Overview

ZStack Cloud Application Market is an IaC (Infrastructure as Code)-based development platform that offers standardized IaC orchestration and a user-friendly development framework. It features strong compatibility, scalability, and hybrid cloud deployment. This helps ISV partners, channels, and customers quickly integrate complex enterprise applications to ZStack Cloud and deploy them with one click, allowing for flexible scaling of cloud capabilities based on business needs and the easy application of best practices to production environments.

This document describes how to create, release, and install an application on ZStack Cloud.

Create Application

About this task

This topic describes how to create an application image and package. Follow these steps:
  1. Get the application template.
  2. Configure application files.
  3. Create the application image.

Procedure

  1. Get the application template.
    1. Log in to https://github.com/ZStack-Robot/marketplace-apps
    2. On the upper right corner or the displayed page, click Use this template > Create a new repository to clone the application template to your own repository.
      Figure 1. Clone Application Template to Your Repository


    The source directory structure of the application package is as follow:
    ├── applications
    │   ├── index.json
    │   ├── zstack_io_grafana
    │   │   └── aarch64
    │   │       └── 11.2.0
    │   │           ├── application.json
    │   │           ├── input.json
    │   │           ├── logo.png
    │   │           ├── output.json
    │   │           └── src
    │   │                 ├── main.tf
    │   │                 ├── output.tf
    │   │                 ├── scripts
    │   │                 │     └── check-health.sh
    │   │                 ├── variables.tf
    │   │                 └── version.tf
    │   │   └── x86_64
    │   │       └── 11.2.0
    │   │           ├── application.json
    │   │           ├── input.json
    │   │           ├── logo.png
    │   │           ├── output.json
    │   │           └── src
    │   │                 ├── main.tf
    │   │                 ├── output.tf
    │   │                 ├── scripts
    │   │                 │     └── check-health.sh
    │   │                 ├── variables.tf
    │   │                 └── version.tf
    Directory Explanation
    • zstack_io_grafana: Application ID. Use the real Application ID to rename this path. This name must be consistent with the appId value in the file application.json.
    • aarch64/x86_64: Application architecture. If your application supports only one architecture, delete the path corresponding to another architecture.
    • 11.2.0: Application version. Use the real version number to rename this path.
    • application.json: A file defining the application name, application description, appId, application type, and connection type.
    • input.json: A file used for the UI rendering, which defines the form parameters that users need to set when installing this application on the Application Market UI page.
    • logo.png: The application Logo picture.
    • output.json: A file defining the application fields displayed on the UI after it is installed.
    • src: A directory contains IaC files with Terraform (OpenTofu). The files must follow the Terraform syntax. See https://developer.hashicorp.com/terraform/language
    • main.tf: The entry point for the OpenTofu execution file.
    • output.tf: The output after executing main.
    • script: A directory contains execution scripts. These scripts can import data using data and execute commands on the VM instances running this application.
    • variables.tf: The variables in OpenTofu format.
    • version.tf: The provider information.
  2. Configure application files.
    1. Use the real application ID, application architecture, and application version to rename the path zstack_io_grafana, aarch64/x86_64, and 11.2.0 respectively.
    2. Configure application.json.
      Template
      {
        "name": "Grafana 是一款开源指标分析和可视化套件",
        "description": "Grafana 是一款开源指标分析和可视化套件,用于可视化支持各种数据源的时间序列数据,应用市场也提供对应ZStack监控模板",
        "details": "Grafana 是一款开源指标分析和可视化套件,用于可视化支持各种数据源的时间序列数据。 本应用由ZStack打包。产品中提及的相应商标归相应公司所有",
        "appId": "zstack.io.grafana",
        "category": "cloud",
        "connector_type": "zstack"
      }
      Note:
      • Use the default value provided by the template for the parameter category and connector_type.
      • Modify other parameters according to your real conditions.
    3. Configure input.json.
      Template
      [
        {
          "name": "root_disk_size",
          "required": true,
          "default_value": 107374182400,
          "min": 107374182400,
          "tag": "ZStack::rootDiskSize"
        },
        {
          "name": "memory_size",
          "required": true,
          "default_value": 4294967296,
          "min": 2147483648,
          "tag": "ZStack::memorySize"
        },
        {
          "name": "l3_network_uuids",
          "en_label": "l3_network_uuids",
          "zh_label": "网络",
          "required": true,
          "tag": "ZStack::l3NetworkUuids"
        },
        {
          "name": "cpu_num",
          "required": true,
          "default_value": 2,
          "min": 1,
          "tag": "ZStack::cpuNumber"
        },
        {
          "name": "backup_storage_uuid",
          "required": true,
          "tag": "ZStack::backupStorageUuid"
        }
      ]
      Note:
      • name: The parameter need to configure when users install this application on the Application Market UI.
      • required: Whether the parameter is mandatory during the application installation.
      • en_lable: The English name of the parameter displayed on the UI.
      • zh_lable:The Chinese name of the parameter displayed on the UI.
      • default_value: The default value of the parameter.
      • min: The minimum value of the parameter.
      • tag: The tag with ZStack prefix is used for UI rendering. Only parameters with such tags can be displayed on the UI.
      The parameters defined in input.json are displayed on the UI in the following order:
      Parameter Description Whether the parameter must be included in input.json
      ZStack::cpuNumber The CPU cores. Yes
      ZStack::memorySize The memory size. Yes
      ZStack::imageStoreUuid The image storage UUID. No. This parameter is generated and displayed automatically.
      ZStack::rootDiskSize The root volume size. Yes
      ZStack::dataDiskSize The data volume size. No. If need, you can include one or more this parameter in input.json. The number of this parameters included in input.json is the number of data volumes user can configure on the UI when installing the application.
      ZStack::l3NetworkUuid The L3 network UUID. Yes. You must include at least one this parameter in input.json. The number of this parameters included in input.json is the number of NICs user can configure on the UI when installing the application.
      ZStack::l3NetworkIp The specified IP address for the NIC. No. If you include this parameter, you must include a ZStack::l3NetworkUuid first. One ZStack::l3NetworkUuid corresponds to one ZStack::l3NetworkIp.
      ZStack::clusterUuid The cluster UUID. Yes
      ZStack::hostUuid The host UUID. Yes
      ZStack::rootDiskPrimaryStorageUuid The UUID of the primary storage for the root volume. Yes
      ZStack::rootDiskPrimaryStorageCephPoolUuid The UUID of the storage pool for the root volume. If the root volume use a Ceph primary storage, you must include this parameter. This parameter is configured together with rootDiskPrimaryStorageUuid.
      ZStack::dataDiskPrimaryStorageUuid The UUID of the primary storage for data volumes. If you include ZStack::dataDiskSize, you must include this parameter.
      ZStack::dataDiskPrimaryStorageCephPoolUuid The UUID of the storage pool for data volumes. If you include ZStack::dataDiskSize and the data volumes use a Ceph primary storage, you must include this parameter. This parameter is configured together with ZStack::dataDiskPrimaryStorageUuid.
      ZStack::gpuDeviceUuid The GPU device UUID. No. If you include this parameter, you must include ZStack::gpuSpecsUuid and ZStack::gpuDeviceType.
      ZStack::gpuSpecsUuid The GPU specification UUID. No. If you include this parameter, you must include ZStack::gpuDeviceUuid and ZStack::gpuDeviceType.
      ZStack::gpuDeviceType The GPU device type. No. If you include this parameter, you must include ZStack::gpuDeviceUuid and ZStack::gpuSpecsUuid.
    4. Configure output.json.
      Template
      [
          {
              "name": "vm_uuids",
              "en_label": "vm_uuids",
              "zh_label": "vm_uuids",
              "type":"array",
              "tag":"ZStack:vmInstanceUuid"
          },
          {
              "name": "application_protocol",
              "en_label": "Application Protocol",
              "zh_label": "应用协议",
              "type": "string",
              "tag": "Application:protocol"
          },
          {
              "name": "application_ip",
              "en_label": "Application IP",
              "zh_label": "应用IP",
              "type":"string",
              "tag":"Application:ip"
          },
          {
              "name": "application_port",
              "en_label": "Application Port",
              "zh_label": "应用端口",
              "type":"number",
              "tag":"Application:port"
          },
          {
              "name": "default_account",
              "en_label": "Default User Name",
              "zh_label": "默认账号",
              "type":"string"
          },
          {
              "name": "default_password",
              "en_label": "Default Password",
              "zh_label": "默认密码",
              "type":"password"
          }
      ]
      Note:
      • name: The application field displayed on the UI after the installation.
      • en_lable: The English name of the field displayed on the UI.
      • zh_lable: The Chinese name of the field displayed on the UI.
    5. Configure src-main.tf.
      Template
      resource "zstack_vm" "vm" {
        name = "Grafana"
        description = "应用市场-Grafana-可视化"
        root_disk = {
          size = {{.root_disk_size}}
        }
      
        l3_network_uuids = {{.l3_network_uuids}}
        memory_size = {{.memory_size}}
        cpu_num = {{.cpu_num}}
        marketplace = true
        never_stop = true
      }
      
      variable "l3Uuids" {
        type = list(string)
        default = {{.l3_network_uuids}}
      }
      
      data "zstack_l3network" "network" {
          depends_on = [zstack_vm.vm]
          uuid = var.l3Uuids[0]
      }
      
      resource "terraform_data" "healthy_check" {
        depends_on = [zstack_vm.vm]
      
        provisioner "local-exec" {
           command     = var.wait_for_migrate_health_cmd
           environment = {
             ENDPOINT =  "http://${zstack_vm.vm.ip}:3000/"
           }
         }
      }
      Note:

      The variable values within {{}} are passed from the corresponding fields in input.json, which are also the values that users set on the UI when installing the application.

    6. Configure src-output.tf.
      Template
      output "vm_uuids" {
         value = zstack_vm.vm.uuid
      }
      
      output "application_protocol" {
         value = "http"
      }
      
      output "application_ip" {
         value = zstack_vm.vm.ip
      }
      
      output "application_port" {
         value = 3000
      }
      
      output "default_account" {
         value = "admin"
      }
      
      output "default_password" {
         value = "password"
      }
      
      output "default_host_root_password" {
         value = "password"
      }
    7. Configure src-variables.tf.
      Template
      variable "wait_for_migrate_health_cmd" {
         description = "local-exec command to execute for determining if the Grafana url is healthy. Grafana endpoint will be available as an environment variable called ENDPOINT"
         type        = string
         default     = "start=$(date +%s); until curl -k -s $ENDPOINT >/dev/null; do sleep 4; now=$(date +%s); if [ $((now - start)) -ge 600 ]; then echo 'Timeout reached'; exit 1; fi; done"
       } 
    8. Configure src-version.tf.
      Template
      terraform {
        required_providers {
          zstack = {
            source = "zstack.io/terraform-provider-zstack/zstack"
          }
        }
      }
      Note:
      • If the user's environment can connect to the Internet, you can use providers provided on https://registry.terraform.io/browse/providers
      • If the user's environment cannot connect to the Internet, you can use the following providers only. For detailed information see https://registry.terraform.io/browse/providers
         template = {
              source  = "hashicorp/template"
              version = "2.2.0"
            }
            external = {
              source = "hashicorp/external"
              version = "2.3.3"
            }
            grafana = {
              source = "grafana/grafana"
              version = "3.2.1"
            }
            local = {
              source = "hashicorp/local"
              version = "2.5.1"
            }
            null = {
              source = "hashicorp/null"
              version = "3.2.3"
            }
  3. Create the application image.
    The application image must be based on an instance image of the KVM qcow2 format. You can use the Packer Qemu Plugin to create the image. If the image includes QGA, you can pass User Data. The User Data passed must be encoded based on Base64.

    The following example shows the User Data for formatting a data disk. You can write your own User Data according to your specific requirements.

    Original User Data:
    #cloud-config
    runcmd:
      - |
        pv_list=$(pvs --noheadings -o pv_name)
        pv_count=$(echo "$pv_list" | wc -l)
        pv_name=$(echo "$pv_list" | tr -d ' ')
    
        vg_name=$(pvs --noheadings -o vg_name $pv_name | tr -d ' ')
    
        growpart $(echo $pv_name | sed 's/[0-9]*$//') $(echo $pv_name | grep -o '[0-9]*$')
        pvresize $pv_name
    
        lv_name=$(lvs --noheadings -o lv_name --sort -size | tail -1 | tr -d ' ')
    
        lvextend -l +100%FREE /dev/$vg_name/$lv_name
    
        lv_path="/dev/$vg_name/$lv_name"
        mapper_name=$(readlink -f $lv_path | awk -F '/' '{print $3}')
    
        lv_mapper_name=$(ls -l /dev/mapper/ | grep "$mapper_name" | awk '{print $9}')
    
        blkid | grep "/dev/mapper/$lv_mapper_name" | grep -q xfs
    
        if [ $? -eq 0 ]; then
            xfs_growfs /dev/mapper/$lv_mapper_name
        else
            resize2fs /dev/mapper/$lv_mapper_name
        fi
        partprobe
    Encoded User Data:
     user_data = "I2Nsb3VkLWNvbmZpZwpydW5jbWQ6CiAgLSB8CiAgICBwdl9saXN0PSQocHZzIC0tbm9oZWFkaW5ncyAtbyBwdl9u \
    YW1lKQogICAgcHZfY291bnQ9JChlY2hvICIkcHZfbGlzdCIgfCB3YyAtbCkKICAgIHB2X25hbWU9JChlY2hvICIkcHZfbGlzdCIgfCB0ciAtZCAnI \
    CcpCgogICAgdmdfbmFtZT0kKHB2cyAtLW5vaGVhZGluZ3MgLW8gdmdfbmFtZSAkcHZfbmFtZSB8IHRyIC1kICcgJykKCiAgICBncm93cGFydCAkKG \
    VjaG8gJHB2X25hbWUgfCBzZWQgJ3MvWzAtOV0qJC8vJykgJChlY2hvICRwdl9uYW1lIHwgZ3JlcCAtbyAnWzAtOV0qJCcpCiAgICBwdnJlc2l6ZSA \
    kcHZfbmFtZQoKICAgIGx2X25hbWU9JChsdnMgLS1ub2hlYWRpbmdzIC1vIGx2X25hbWUgLS1zb3J0IC1zaXplIHwgdGFpbCAtMSB8IHRyIC1kICcg \
    JykKCiAgICBsdmV4dGVuZCAtbCArMTAwJUZSRUUgL2Rldi8kdmdfbmFtZS8kbHZfbmFtZQoKICAgIGx2X3BhdGg9Ii9kZXYvJHZnX25hbWUvJGx2X \
    25hbWUiCiAgICBtYXBwZXJfbmFtZT0kKHJlYWRsaW5rIC1mICRsdl9wYXRoIHwgYXdrIC1GICcvJyAne3ByaW50ICQzfScpCgogICAgbHZfbWFwcG \
    VyX25hbWU9JChscyAtbCAvZGV2L21hcHBlci8gfCBncmVwICIkbWFwcGVyX25hbWUiIHwgYXdrICd7cHJpbnQgJDl9JykKCiAgICBibGtpZCB8IGd \
    yZXAgIi9kZXYvbWFwcGVyLyRsdl9tYXBwZXJfbmFtZSIgfCBncmVwIC1xIHhmcwoKICAgIGlmIFsgJD8gLWVxIDAgXTsgdGhlbgogICAgICAgIHhm \
    c19ncm93ZnMgL2Rldi9tYXBwZXIvJGx2X21hcHBlcl9uYW1lCiAgICBlbHNlCiAgICAgICAgcmVzaXplMmZzIC9kZXYvbWFwcGVyLyRsdl9tYXBwZ \
    XJfbmFtZQogICAgZmkKICAgIHBhcnRwcm9iZQ=="

Release Application

This topic describes how to release your application package and image to ZStack Cloud Application Market.
  • Private Release: Upload your application package and image to your local cloud. Only you can use this application.
  • Specified Shared Release: Upload your application package and image to your CDN. You and your partners can use this application.
  • Shared Release: Upload your application package and image to the official CDN of ZStack Cloud. All ZStack Cloud users can use this application.

Private Release

  1. Execute the python package_repo.py script to generate the directory images.
  2. Rename your application image to image.qcow2 and upload it to the directory images.
  3. Run the following command to generate a .bin package:
    python package_bin --${AppId} --${Version} --${Arch} --include_images
  4. Check the .bin package in the following path: target/application_bins/${AppID}/${Arch}/${Version}/${PackageName}.bin
  5. Upload the .bin package to the management node of ZStack Cloud and run the following command:
    [root@localhost~] bash ${PackageName}.bin
    Note: If you use dual-management node. Upload the .bin package to and run the bash command on the two management nodes respectively.
  6. On the main menu of ZStack Cloud, choose Operational Management > Application Market > Default Application. On the Default Application page, click Sync Application. Then, you can view the application you release.

Specified Shared Release

  1. Execute the python package_repo.py script to generate application.tar.gz and the new index.json
  2. Check application.tar.gz in the following path: target/application_bins/${app_id}/${arch}/${version}/xxx.bin
  3. Rename your application image as image.qcow2
  4. Upload application.tar.gz and image.qcow2 to your CDN according to the following directory structure:
    ├── index.json
    ├── ${AppId}
    │   └── ${Arch}
    │       └── ${Version}
    │           └── application.tar.gz
    │           └── image.qcow2    
  5. Log in to the management node of ZStack Cloud and run the following command to write your CDN into repositories:
    [root@localhost~]zstack-cli    # Enter CLI command line.
    - >>>LogInByAccount accountName=admin password=${AdminPassword}    # Log the admin account.
    admin >>>UpdateGlobalConfig name=repositories category=marketplace value="file:///opt/zstack-marketplace-repo;${CustomCDNAddress}"    # Write your CDN into repositories.
    admin >>>exit    # Exit the CLI command line.
  6. Run the following command to restart the management node:
    [root@localhost~] zstack-ctl restart_node
  7. Check whether the repositories in the marketplace-server/config/config.yaml is consistent with the sample shown below:
    repositories:
    - file:///opt/zstack-marketplace-repo
    - ${CustomCDNAddress}
  8. On the main menu of ZStack Cloud, choose Operational Management > Application Market > Default Application. On the Default Application page, click Sync Application. Then, you can view the application you release.

Shared Release

  1. Execute the python package_repo.py script to generate application.tar.gz and the new index.json
  2. Check application.tar.gz in the following path: target/application_bins/${app_id}/${arch}/${version}/xxx.bin
  3. Rename your application image as image.qcow2
  4. Send application.tar.gz and image.qcow2 to ZStack Cloud technical support. The technical support will upload the files to the official CND.
  5. On the main menu of ZStack Cloud, choose Operational Management > Application Market > Default Application. On the Default Application page, click Sync Application. Then, you can view the application you release.

Install Application

About this task

This topic describes how to install an application released on Application Market. Follow these steps:
  1. Upload the application image. (Optional)
  2. Install the application.
  3. Access the application.
  4. Application debug tips.

Procedure

  1. Upload the application image. (Optional)
    When installing the application. The system downloads the application image from the CDN automatically, which consumes certain time. If your Cloud cannot visit the CDN or you want to accelerate the installation, you can maually upload the image to the specified path in advance.
    • Download Address
      • ZStack Cloud CDN: Click here
      • To download applications that are not officially released on ZStack Cloud, contact the corresponding developers.
    • Upload Image
      • Rename the image to image.qcow2 and upload it to the following path on your management node and ImageStore (create the path if it does not exist)): /opt/zstack-marketplace-repo/{appName}/{Architecture}/{version}. For example, /opt/zstack-marketplace-repo/zstack_io_zaku/x86_64/3.1.0/image.qcow2
      • To ensure the correctness of the path and file name, we recommend that you contact the official technical support to execute this step.
  2. Install the application.

    On the main menu of ZStack Cloud, choose Operational Management > Application Market > Default Application. Locate the application you need to install and click Install. Then, the Install Application page is displayed.

    On the displayed page, set the required parameters and confirm to install.

  3. Access the application.

    On the main menu of ZStack Cloud, choose Operational Management > Application Market > Default Application > Installed. Locate the application and click the access address. Then, you can access the application.

  4. Application debug tips.
    If you need to debug, you can find the information you need with the following tips:
    • View the application UUID: Click Task on the main menu of ZStack Cloud, and locate the task corresponding to the application installation. You can find the application UUID in this task details.
    • View the application logs: See /var/lib/zstack/marketplace-server/server.log on the management node.
    • View the application directory: Enter /var/lib/zstack/marketplace-server/apps/${application_uuid}/instance/${instance_uuid} on the management node. You can see the terraform.tfstate here. If you need to debug manually, run the following command:
      ```bash
      export TF_CLI_CONFIG_FILE=/var/lib/zstack/marketplace-server/.terraformrc && /var/lib/zstack/marketplace-server/tools/tofu apply -var "host=cloud api endpoint" -var "port=8080" -var "session_id=xxxxx"
      ​```
Application Market Development and Using Tutorial | 5.5.30 | ZStack Cloud · ZCF | ZStack Resource Center