Overview

Your containerized app will be deployed multiple times (in various datacenters, for various customers with individual settings) - the goal is to

  • make possible a proper configuration of the application in an automated mode
  • make the process of converting your containerized app (successfully running locally) into an auto-deployable app (cloud, Kubernetes and Helm) having as little stress (for you and DevOps) as possible

Application Parameters - definition

Your application needs to have some fundamental parameters, e.g. on which port does it listen to or what is the domain name it displays to the user. These parameters

  • need to be defined in the application config schema (so they can be configured via UI by the user / admin when deploying)
  • your code has to use values, passed during the deployment, instead of hard-coded ones

Schema File

Each schema contains attributes (AKA options or parameters). For convenience of presenting/editing these options on auto-generated UI, the attributes are placed into one (or more) "groups". This does not affect the values of the attributes, simply allows showing arguments on different tabs/screens.

So the main element of the schema is "groups" list (array), each element of it is another array, that contains "group" objects, with an optional "name" attribute and the "settings" property, which contains a list of "option" objects (each describes an individual parameter and its presentation & validation on UI.

  • Schema
    • Group "ABC
      • Option A
      • Option B
    • Group "XYZ"
      • Option X

FieldTypeMandatoryDescriptionPossible valuesDefaultExample
groupsarray[group]yesContains groups of the options


group.namestringyesThe option group nameany
App info
group.providerenumnoWhether these are options to be visible to the user for editing on UI (APP_OWNER), or options to be filled out by the deployment engine (PRODUCT_OWNER, DEVOPS; e.g. port on which the service is provided)APP_OWNER, PRODUCT_OWNER, DEVOPSAPP_OWNERAPP_OWNER
groups[].settingsarrayyesContains a list of the options by the group


groups[].settings[].idstringyesThe unique "id" of the optionany
domain
groups[].settings[].labelstringyesThe label of the UI widget or Front-end config portalany
Web domain
groups[].settings[].typestringyesThe field type. Used as an enum value (check available types below)text, file, url, textarea, integer,
float, boolean, date, datetime,
time, timedelta, ipaddress, 
email, identifier, hostname

text
groups[].settings[].mandatorybool
"true" if the field is required or "false" otherwisetrue, falsefalsetrue
groups[].settings[].infostring
The additional help textanynullAddress of the website your users will go to
groups[].settings[].placeholderstring
The placeholderanynull...
groups[].settings[].defaultany
The default value for the optionanynull...

For the current moment, the next types of fields are supported:

textA single-line text
fileFull contents of a file (can be binary) that is uploaded to the system
urlA valid URL (HTTP or HTTPS)
textareaA multiline text
integerAn integer value
floatA float value
booleanA boolean value (checkbox)
dateA date
datetimeDate and time (the Unix time or string in the format `YYYY-MM-DD[T]HH:MM[:SS[.ffffff]][Z or [±]HH[:]MM]]]`).
timeA time
timedelta

A time delta (string in the format `HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]`).

ipaddressIP address (v4 or v6)
emailAn e-mail
identifierLetters, numbers and underscores. A number may not be first
hostnameA hostname, with regexp "^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"
passwordA single-line text
colorA colour, with regexp "^#([a-fA-F\d]{1,2}){3,4}$"
{
  "name":"MYApp",
  "groups":[
    {
      "name":"App info",
      "settings":[
        {
          "id":"company_name",
          "type":"text",
          "mandatory":true,
          "label":"Custom company name"
        },
        {
          "id":"company_url",
          "type":"url",
          "label":"Custom company URL",
          "mandatory":true
        },
        {
          "id":"company_logo",
          "type":"file",
          "mandatory":true,
          "label":"Company logo"
        },
        {
          "id":"company_description",
          "type":"textarea",
          "mandatory":true,
          "label":"Company description"
        },
        {
          "id":"company_rating",
          "type":"float",
          "mandatory":true,
          "label":"Company rating"
        },
        {
          "id":"app_id",
          "type":"identifier",
          "label":"App ID",
          "mandatory":true
        },
        {
          "id":"custom_colors",
          "type":"boolean",
          "label":"Custom colors",
          "mandatory":true,
          "default":false
        },
        {
          "id":"maintainer",
          "type":"email",
          "label":"Maintainer"
        },
        {
          "id":"created_at",
          "type":"datetime",
          "mandatory":true,
          "label":"Created at"
        },
        {
          "id":"updated_at",
          "type":"date",
          "mandatory":true,
          "label":"Updated at"
        },
        {
          "id":"scheduled_deploy_time",
          "type":"time",
          "mandatory":true,
          "label":"Scheduled deploy time"
        },
        {
          "id":"average_deploy_time",
          "type":"timedelta",
          "mandatory":true,
          "label":"Average deploy time"
        },
        {
          "id":"core_domain",
          "type":"hostname",
          "mandatory":true,
          "label":"Core domain"
        },
        {
          "id":"dialer_domain",
          "type":"hostname",
          "label":"Dialer domain"
        },
        {
          "id":"app_ip",
          "type":"ipaddress",
          "mandatory":true,
          "label":"App IP address"
        },
        {
          "id":"app_port",
          "type":"integer",
          "mandatory":true,
          "label":"App port"
        }
      ]
    },
    {
      "name":"Deployment settings",
      "provider":"PRODUCT_OWNER",
      "settings":[
        {
          "id":"is_specific_service_enabled",
          "type":"boolean",
          "default":false,
          "mandatory":true,
          "label":"Custom company name"
        }
      ]
    }
  ]
}

Advanced schema settings

Hide/Show an option by condition

We can add a condition to show or hide some fields based on the value of another field. For example, you want to display a color selection field box if the option for a Custom color appearance is selected.

{
    "groups":[
        {
            "name":"Branding",
            "settings":[
                {
                    "id":"custom_colors",
                    "type":"boolean",
                    "label":"Appearance: Use custom colors",
                    "mandatory":true,
                    "default":false
                },
                {
                    "id":"color_accent",
                    "type":"color",
                    "label":"Choose colors for 'Accent'",
                    "mandatory":false,
                    "default":"#F5841F",
                    "validator":[
                        {
                            "name":"MANDATORY",
                            "relates":{
                                "is_disabled":{
                                    "custom_colors":false
                                }
                            }
                        }
                    ]
                },
                {
                    "id":"color_anchor",
                    "type":"color",
                    "label":"Choose colors for 'Anchor'",
                    "mandatory":false,
                    "default":"#F5841F",
                    "validator":[
                        {
                            "name":"MANDATORY",
                            "relates":{
                                "is_disabled":{
                                    "custom_colors":false
                                }
                            }
                        }
                    ]
                }
            ]
        }
    ]
}

Drop-down option with list of values

 {
    "groups":[
        {
            "name":"PortaSwitch connection",
            "settings":[
                {
                    "id":"portabilling_signin_credentials",
                    "type":"text",
                    "mandatory":false,
                    "default":"self-care",
                    "label":"PortaBilling sign in Credentials",
                    "info":"Defines the type of account properties used for login\n\nself-care - login for request and password from the response (default value)\nsip - id for request and h323_password from response",
                    "validator":[
                        {
                            "name":"OPTIONS",
                            "options":[
                                {
                                    "name":"Self-care",
                                    "value":"self-care"
                                },
                                {
                                    "name":"SIP",
                                    "value":"sip"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    ]
}


Application development using "addon-mart" tool

In order to configure, run, and send a module to the PortaOne registry it can be used a new CLI tool addon-mart.

This tool allows to do the following actions:

  • validate configuration values according to the configuration schema (that can be created with Module schema generator UI)
  • generate configuration files from Jinja2 templates
  • build and run the application with provisioned paramters as environment variables or/and configuration files using Dockerfile or compose file
  • push a built image and Helm charts to the PortaOne registry

The detailed instruction on how to use addon-mart tool can be found here.

References