Creating New Templates

Templates are AS3 declarations that have been parameterized. This page has a short tutorial to help template authors get started creating template sets, and a more detailed explanation of the templates and their syntax.

We recommend template authors read the overview of the FAST Engine to fully understand how templates are processed in the system.

In order to use the FAST CLI, which provides template validation and previewing, Node Package Manager (npm) must be installed. FAST CLI is a community-supported authoring tool that template authors may use. It is installed onto the client PC/laptop, not on BIG-IP, and is used to validate templates as they are being built or modified.
For more information on the npm tool and community, visit https://www.npmjs.com/

Some familiarity with the command line is assumed, and we recommend the FAST npm module is installed globally @f5devcentral/f5-fast-core. This provides the FAST command line tools to validate and render templates during authoring.

Help text is provided and accessed via: fast --help
For more information on a given command use the --help flag combined with a command: fast <command> --help

../_images/NPM-Flow.png

Use the following command to install the npm module: npm install -g @f5devcentral/f5-fast-core
Use the following command to validate your template fast validate <filename>
Use one of the following commands to zip your template zip <zipfile.zip> <sourcefile.mst> or fast packageTemplateSet <templateSetPath>
Upload and install your zip file using steps 8 and 9 from the example below

Hello World example

In this section, we create a simple Hello World template and upload it to FAST. Later sections go into detail about the template specification and its entire feature set.

  1. Start by creating a file named hello.mst and copy the following parameterized AS3 declaration into it:

    {
        "class": "ADC",
        "schemaVersion": "3.11.0",
        "{{tenant_name}}": {
          "class": "Tenant",
          "{{application_name}}": {
            "class": "Application",
            "template": "http",
            "serviceMain": {
              "class": "Service_HTTP",
              "virtualAddresses": ["{{virtual_address}}"],
              "pool": "web_pool_{{port}}",
            },
            "web_pool_{{port}}": {
              "class": "Pool",
              "monitors": [
                "http"
              ],
              "members": [
                {
                  "servicePort": {{port::integer}},
                  "serverAddresses": {{server_addresses::array}}
                }
              ]
            }
          }
        }
      }
    }
    
This is a basic template that creates an HTTP Virtual IP allowing you to specify the Virtual IP, a list of server addresses, and a port to use for both the front and back end. The tenant name and application name are also specified by the user.
  1. Save the file.

  2. If the FAST NPM module is installed globally on your system, we can validate it and try rendering it with the following command: fast validate hello.mst

  3. Create the following file named params.json:

    {
        "tenant_name": "TestTenant",
        "application_name": "MyTestApp",
        "virtual_address": "0.0.0.0",
        "port": 80,
        "serverAddresses": [
            "10.0.0.1",
            "10.0.0.2"
        ]
    }
    

  1. Using this file, the following command will show an example render: fast render hello.mst params.json

  2. To add this to the system, the template can be placed into a zip file. From the command line: zip hello.zip hello.mst

  3. Make note of the file location, and the size of the file (in bytes). Note: file size must be less than 1MB or the transfer fails.

  4. Upload the file to the BIG-IP system using cURL from a Linux shell using the following syntax:

    $ curl -sku <BIG-IP username>:<BIG-IP password> --data-binary @<path to zip file> -H "Content-Type: application/octet-stream" -H "Content-Range: 0-<content-length minus 1>/<content-length>" -H "Content-Length: <file size in bytes>" -H "Connection: keep-alive" https://<IP address of BIG-IP>/mgmt/shared/file-transfer/uploads/<zipfile-name>.zip
    

    For example:

    $ curl -sku admin:Pass1w0rd! --data-binary @example.zip -H "Content-Type: application/octet-stream" -H "Content-Range: 0-1298/1299" -H "Content-Length: 1299" -H "Connection: keep-alive" https://192.0.2.87/mgmt/shared/file-transfer/uploads/example.zip
    

    This example returns the following:

    {"remainingByteCount":0,"usedChunks":{"0":1299},"totalByteCount":1299,"localFilePath":"/var/config/rest/downloads/example.zip","temporaryFilePath":"/var/config/rest/downloads/tmp/example.zip","generation":0,"lastUpdateMicros":1582756171238125}
    
  5. Install the newly uploaded template set using the following syntax:

    curl -sku <BIG-IP username>:<BIG-IP password> -X POST -d '{"name": "<zip file name without .zip extension>"}' -H "Content-Type: application/json" https://<IP address of BIG-IP>/mgmt/shared/fast/templatesets
    

    For example:

    curl -sku admin:Pass1w0rd -X POST -d '{"name": "example"}' -H "Content-Type: application/json" https://192.0.2.87/mgmt/shared/fast/templatesets
    

    Example response: {"code":200,"message":""}


The template will validate and be added to the system. When navigating to the Deploy tab, the new template set should be available, with the Hello World template ready for use.

The rest of this page explains more about what the templating system can do. By using JSON schema alongside the templates, FAST provides a powerful system for validating template parameters ensuring applications get deployed as expected.

Template Specification

Templates abide by the following rules:

  • Templates are text files with sections marked off called variables
  • Variables will be marked for replacement at render time.
  • Variables are surrounded with double curly braces, {{ and }}.
  • Variables can specify a type: name::type
  • Primitive Types
    • string (default)
    • text (for strings with new lines and escape characters)
    • number
    • integer
    • boolean
    • array

Example

The following is an example of a simple FAST template that will render an AS3 declaration:

{
    "class": "ADC",
    "schemaVersion": "3.11.0",
    "{{tenant_name}}": {
      "class": "Tenant",
      "{{application_name}}": {
        "class": "Application",
        "template": "http",
        "serviceMain": {
          "class": "Service_HTTP",
          "virtualAddresses": ["{{virtual_address}}"],
          "pool": "web_pool_{{port}}",
        },
        "web_pool_{{port}}": {
          "class": "Pool",
          "monitors": [
            "http"
          ],
          "members": [
            {
              "servicePort": {{port::integer}},
              "serverAddresses": {{server_addresses::array}}
            }
          ]
        }
      }
    }
  }
}

In the example template, we have some variables: tenant_name, application_name, virtual_address, port, and server_addreses. Some have annotations, like port::integer. The integer annotation signifies the value of port must be an integer.

Variables may be used in multiple places, if a variable is annotated somewhere in the file, an unannotated version of that variable will respect the annotation.

From the variables, a schema is generated. This schema describes the parameters that must be provided to render the template. These parameters will show up in the form representation of the template in the GUI.

The following schema will get auto-generated from the example:

{
  "properties": {
    "tenant_name" : {
      "type": "string"
    },
    "application_name" : {
      "type": "string"
    },
    "virtual_address" : {
      "type": "string"
    },
    "server_addresses" : {
      "type": "array"
    },
    "port" : {
      "type": "integer"
    },
  }
}

This example ‘view’ passes validation using the schema:

{
  "tenant_name" : "myTenant",
  "application_name" : "simple_http_1",
  "virtual_address" : "10.0.0.1",
  "server_addresses" : [ "10.0.1.1", "10.0.2.2" ],
  "port" : 80
}

This information is collected in the form UI and compiled into a parameter object like the example. The information is passed along to the template renderer, and the variable names are replaced with their parameter values.

The final declaration is generated by providing the previous view with the provided template:

{
    "class": "ADC",
    "schemaVersion": "3.11.0",
    "myTenant": {
      "class": "Tenant",
      "simple_http_1": {
        "class": "Application",
        "template": "http",
        "serviceMain": {
          "class": "Service_HTTP",
          "virtualAddresses": ["10.0.0.1"],
          "pool": "web_pool_80",
        },
        "web_pool_80": {
          "class": "Pool",
          "monitors": [
            "http"
          ],
          "members": [
            {
              "servicePort": 80,
              "serverAddresses": [ "10.0.1.1", "10.0.2.2" ]
            }
          ]
        }
      }
    }
  }
}

Extended Types

Typestache also allows specification of custom types using JSON schema. Schema files can be placed into /var/config/rest/iapps/as3-forms-lx/schemas. Each file must have a .json extension and contain valid JSON schema. Schemas listed in the definitions will be made available to templates using the following syntax:

name:schema_name:type

  • name is the name of the variable, as before
  • schema_name is the name of the JSON schema file, excluding the extension
  • type is the property name of the definition being referenced

for example:

...
{
  "class": {{service_type:f5:service}}
  ...
}
...

AFL has support for enums and custom formats can be applied to the primitive types outlined in the previous section. The variable in the example is a service type from the f5 schema named service_type. The service schema is an enum containing the AS3 basic services, Service_HTTP, Service_HTTPS, Service_L4, Service_UDP, and Service_TCP.

The definition from f5.json:

"service": {
  "type": "string",
  "enum": [
    "Service_HTTP",
    "Service_HTTPS",
    "Service_TCP",
    "Service_UDP",
    "Service_L4"
  ],
  "default": "Service_HTTP"
},

Arrays of primitives should work fine but have not been extensively tested.

Objects are not yet supported.

Up-front validation using the schema will help to prevent failed deployments by notifying the user prior to deployment when a value has an invalid format. Therefore, when designing a template, the appropriate schema definition should be used for each variable.
For example, if the virtual IP address is a variable, use schema to validate the input is an IPv4 or IPv6 address.
For more information on writing schema, see https://json-schema.org/

Important

When authoring a template, be cautious when entering sensitive data into your template such as passwords, certificates and monitor information to name a few. FAST does not encrypt the data and it will remain as plain text. Careful consideration should be made when adding this type of data onto the template.

AS3 Secrets

Secrets are things such as passphrases, ssl certificate/keys, etc. AS3 declarations made for FAST templates should follow best practices for AS3 secrets outside of FAST.

Keeping a Variable Hidden

In order to keep a template variable secret, identify it as type: string, format: password. This will cause the UI to hide characters as they are typed. When the application is re-deployed, the secret value will return to the same field in the UI, where it can be altered, but not seen.

A schema example showing hidden password text in the gui:

definitions:
  secret_var:
    title: Secret
    description: This will show up as a password field
    format: password
template: |
  {{secret_var}}

Keeping Template Text Secret

The template may be viewed from the FAST UI via the View Template button located on the Deploy tab. If there is a static, plain text passphrase in the template, it will be displayed. For cases where the passphrase is part of an AS3 declaration, the template author may wish to substitute an encrypted passphrase to prevent leaking the password when sharing or backing up the template files. To obtain the encrypted value, submit the declaration directly to AS3, and retrieve the passphrase object that is returned by AS3 into the FAST template.

For example, if the template contains the following certificate definition:

  "webcert": {
  "class": "Certificate",
  "remark": "in practice we recommend using a passphrase",
  "certificate": "-----BEGIN CERTIFICATE-----\nMIICnDCCAgWgAwIBAgIJAJ5n2b0OCEjwMA0GCSqGSIb3DQEBCwUAMGcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRQwEgYDVQQKDAtmNV9OZXR3b3JrczEbMBkGA1UEAwwSc2FtcGxlLmV4YW1wbGUubmV0MB4XDTE3MTEyNjE5NTAyNFoXDTE4MDIyNTE5NTAyNFowZzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxFDASBgNVBAoMC2Y1X05ldHdvcmtzMRswGQYDVQQDDBJzYW1wbGUuZXhhbXBsZS5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALEsuXmSXVQpYjrZPW+WiTBjn491mwZYT7Q92V1HlSBtM6WdWlK1aZN5sovfKtOX7Yrm8xa+e4o/zJ2QYLyyv5O+t2EGN/4qUEjEAPY9mwJdfzRQy6Hyzm84J0QkTuUJ/EjNuPji3D0QJRALUTzu1UqqDCEtiN9OGyXEkh7uvb7BAgMBAAGjUDBOMB0GA1UdDgQWBBSVHPNrGWrjWyZvckQxFYWO59FRFjAfBgNVHSMEGDAWgBSVHPNrGWrjWyZvckQxFYWO59FRFjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4GBAJeJ9SEckEwPhkXOm+IuqfbUS/RcziifBCTmVyE+Fa/j9pKSYTgiEBNdbJeBEa+gPMlQtbV7Y2dy8TKx/8axVBHiXC5geDML7caxOrAyHYBpnx690xJTh5OIORBBM/a/NvaR+P3CoVebr/NPRh9oRNxnntnqvqD7SW0U3ZPe3tJc\n-----END CERTIFICATE-----",
  "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nProc-Type: 4,ENCRYPTED\nDEK-Info: AES-256-CBC,D8FFCE6B255601587CB54EC29B737D31\n\nkv4Fc3Jn0Ujkj0yRjt+gQQfBLSNF2aRLUENXnlr7Xpzqu0Ahr3jS1bAAnd8IWnsR\nyILqVmKsYF2DoHh0tWiEAQ7/y/fe5DTFhK7N4Wml6kp2yVMkP6KC4ssyYPw27kjK\nDBwBZ5O8Ioej08A5sgsLCmglbmtSPHJUn14pQnMTmLOpEtOsu6S+2ibPgSNpdg0b\nCAJNG/KHe+Vkx59qNDyDeKb7FZOlsX30+y67zUq9GQqJEDuysPJ2BUNP0IJXAjst\nFIt1qNoZew+5KDYs7u/lPxcMGTirUhgI84Jy4WcDvSOsP/tKlxj04TbIE3epmSKy\n+TihHkwY7ngIGtcm3Sfqk5jz2RXoj1/Ac3SW8kVTYaOUogBhn7zAq4Wju6Et4hQG\nRGapsJp1aCeZ/a4RCDTxspcKoMaRa97/URQb0hBRGx3DGUhzpmX9zl7JI2Xa5D3R\nmdBXtjLKYJTdIMdd27prBEKhMUpae2rz5Mw4J907wZeBq/wu+zp8LAnecfTe2nGY\nE32x1U7gSEdYOGqnwxsOexb1jKgCa67Nw9TmcMPV8zmH7R9qdvgxAbAtwBl1F9OS\nfcGaC7epf1AjJLtaX7krWmzgASHl28Ynh9lmGMdv+5QYMZvKG0LOg/n3m8uJ6sKy\nIzzvaJswwn0j5P5+czyoV5CvvdCfKnNb+3jUEN8I0PPwjBGKr4B1ojwhogTM248V\nHR69D6TxFVMfGpyJhCPkbGEGbpEpcffpgKuC/mEtMqyDQXJNaV5HO6HgAJ9F1P6v\n5ehHHTMRvzCCFiwndHdlMXUjqSNjww6me6dr6LiAPbejdzhL2vWx1YqebOcwQx3G\n-----END RSA PRIVATE KEY-----",
  "passphrase": {
    "ciphertext": "ZjVmNQ==",
    "protected": "eyJhbGciOiJkaXIiLCJlbmMiOiJub25lIn0"
  }
}

The “protected” field (in base64) indicates that the value of “ciphertext” is in plain text. Literal translation to {“alg”:”dir”,”enc”:”none”}. Submit a declaration containing this definition to AS3.
In the body of the response, you will find:

"passphrase": {
   "ciphertext": "JE0kbGkkOFpmMi9oMnpYb1VkVjJpbFpHd28vUT09",
    "protected": "eyJhbGciOiJkaXIiLCJlbmMiOiJmNXN2In0="
    "miniJWE": true
 }

In the response, the value of “protected” has changed to indicate SecureVault encryption (literally {“alg”:”dir”,”enc”:”f5sv”}), and “ciphertext” is the encrypted secret. These examples are directly tied to AS3, and works only for protected ciphertext elements in a declaration.

See Secrets in AS3 Declarations for a more expanded definition of AS3 secrets.