Create Application

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.
  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=="

Archives

Download Document Archives

Back to Top

Download

Already filled the basic info?Click here.

Enter at least 2 characters.
Invalid mobile number.
Enter at least 4 characters.
Invalid email address.
Wrong code. Try again. Send Code Resend Code (60s)

An email with a verification code will be sent to you. Make sure the address you provided is valid and correct.

同意 不同意

I have read and concur with the Site TermsPrivacy PolicyRules and Conventions on User Management of ZStack Cloud

Download

Not filled the basic info yet? Click here.

Invalid email address or mobile number.
同意 不同意

I have read and concur with the Site TermsPrivacy PolicyRules and Conventions on User Management of ZStack Cloud

Email Us

contact@zstack.io
ZStack Training and Certification
Enter at least 2 characters.
Invalid mobile number.
Enter at least 4 characters.
Invalid email address.
Wrong code. Try again. Send Code Resend Code (60s)

同意 不同意

I have read and concur with the Site TermsPrivacy PolicyRules and Conventions on User Management of ZStack Cloud

Email Us

contact@zstack.io
Request Trial
Enter at least 2 characters.
Invalid mobile number.
Enter at least 4 characters.
Invalid email address.
Wrong code. Try again. Send Code Resend Code (60s)

同意 不同意

I have read and concur with the Site TermsPrivacy PolicyRules and Conventions on User Management of ZStack Cloud

Email Us

contact@zstack.io

The download link is sent to your email address.

If you don't see it, check your spam folder, subscription folder, or AD folder. After receiving the email, click the URL to download the documentation.

The download link is sent to your email address.

If you don't see it, check your spam folder, subscription folder, or AD folder.
Or click on the URL below. (For Internet Explorer, right-click the URL and save it.)

Thank you for using ZStack products and services.

Submit successfully.

We'll connect soon.

Thank you for using ZStack products and services.