The expression syntax exposes all of the available capabilities of expressions in Cloud Assembly templates.

Note: Cloud Assembly expressions aren't the same as regular expressions.

The following syntax is only partly represented in the examples shown in Cloud Assembly expressions.

Literals

The following literals are supported:

  • Boolean (true or false)
  • Integer
  • Floating point
  • String

    Backslash escapes double quote, single quote, and backslash itself:

    " is escaped as \"

    ' is escaped as \'

    \ is escaped as \\

    Quotes only need to be escaped inside a string enclosed with the same type of quote, as shown in the following example.

    "I am a \"double quoted\" string inside \"double quotes\"."

  • Null

Environment variables

Environment names:

  • orgId
  • projectId
  • projectName
  • deploymentId
  • deploymentName
  • blueprintId
  • blueprintVersion
  • blueprintName
  • requestedBy (user)
  • requestedAt (time)

Syntax:

env.ENV_NAME

Example:

${env.blueprintId}

Resource variables

Resource variables let you bind to resource properties from other resources.

Syntax:

resource.RESOURCE_NAME.PROPERTY_NAME

Resource names cannot contain dashes or dots. Underscores are allowed.

Examples:

  • ${resource.db.id}
  • ${resource.db.networks[0].address}
  • ${resource.app.id} (Return the string for non-clustered resources, where count isn't specified. Return the array for clustered resources.)
  • ${resource.app[0].id} (Return the first entry for clustered resources.)

Resource self variables

Resource self variables are allowed only for resources supporting the allocation phase. Resource self variables are only available (or only have a value set) after the allocation phase is complete.

Syntax:

self.property_name

Example:

${self.address} (Return the address assigned during the allocation phase.)

Note that for a resource named resource_x, self.property_name and resource.resource_x.property_name are the same and are both considered self-references.

Conditions

Syntax:

  • Equality operators are == and !=.
  • Relational operators are < > <= and >=.
  • Logical operators are && || and !.
  • Conditionals use the pattern:

    condition-expression ? true-expression :false-expression

Examples:

${input.count < 5 && input.size == 'small'}

${input.count < 2 ? "small":"large"}

Cluster count index

Syntax:

count.index

Examples:

  • Return the node type for clustered resources:

    ${count.index == 0 ? "primary":"secondary"}

  • Set the size of each disk during allocation:
    inputs:
      disks:
        type: array
        minItems: 0
        maxItems: 12
        items:
          type: object
          properties:
            size:
              type: integer
              title: Size (GB)
              minSize: 1
              maxSize: 2048
    resources:
      Cloud_vSphere_Disk_1:
        type: Cloud.vSphere.Disk
        allocatePerInstance: true
        properties:
          capacityGb: '${input.disks[count.index].size}'
          count: '${length(input.disks)}'
    
  • For more examples, see Machine and disk clusters in Cloud Assembly.

Arithmetic operators

Syntax:

Operators are + / * and %.

Example:

${(input.count + 5) * 2}

String concatenation

Syntax:

${'ABC' + 'DEF'} evaluates to ABCDEF.

Operators [ ] and .

The expression follows ECMAScript in unifying the treatment of the [ ] and . operators.

So, expr.identifier is equivalent to expr["identifier"]. The identifier is used to construct a literal whose value is the identifier, and then the [ ] operator is used with that value.

Example:

${resource.app.networks[0].address}

In addition, when a property includes a space, delimit with square brackets and double quotes instead of using dot notation.

Incorrect:

input.operating system

Correct:

input["operating system"]

Construction of map

Syntax:

${{'key1':'value1', 'key2':input.key2}}

Construction of array

Syntax:

${['key1','key2']}

Example:

${[1,2,3]}

Functions

Syntax:

${function(arguments...)}

Example:

${to_lower(resource.app.name)}

Table 1. Functions
Function Description
abs(number) Absolute number value
avg(array) Return average of all values from array of numbers
base64_decode(string) Return decoded base64 value
base64_encode(string) Return base64 encoded value
ceil(number) Returns the smallest (closest to negative infinity) value that is greater than or equal to the argument and is equal to a mathematical integer
contains(array, value) Check if array contains a value
contains(string, value) Check if string contains a value
digest(value, type) Return digest of value using supported type (md5, sha1, sha256, sha384, sha512)
ends_with(subject, suffix) Check if subject string ends with suffix string
filter_by(array, filter)

Return only the array entries that pass the filter operation

filter_by([1,2,3,4], x => x >= 2 && x <= 3)

returns [2, 3]

filter_by({'key1':1, 'key2':2}, (k,v) => v != 1)

returns [{"key2": 2}]

floor(number) Returns the largest (closest to positive infinity) value that is less than or equal to the argument and is equal to a mathematical integer
format(format, values...) Return a formatted string using Java Class Formatter format and values.
from_json(string) Parse json string
join(array, delim) Join array of strings with a delimiter and return a string
json_path(value, path) Evaluate path against value using XPath for JSON.
keys(map) Return keys of map
length(array) Return array length
length(string) Return string length
map_by(array, operation)

Return each array entry with an operation applied to it

map_by([1,2], x => x * 10)

returns [10, 20]

map_by([1,2], x => to_string(x))

returns ["1", "2"]

map_by({'key1':1, 'key2':2}, (k,v) => {k:v*10})

returns [{"key1":10},{"key2":20}]

map_to_object(array, keyname)

Return an array of key:value pairs of the specified key name paired with values from another array

map_to_object(resource.Disk[*].id, "source")

returns an array of key:value pairs that has a key field called source paired with disk ID strings

Note that

map_by(resource.Disk[*].id, id => {'source':id})

returns the same result

matches(string, regex) Check if string matches a regex expression
max(array) Return maximum value from array of numbers
merge(map, map) Return a merged map
min(array) Return minimum value from array of numbers
not_null(array) Return the first entry which is not null
now() Return current time in ISO-8601 format
range(start, stop) Return a series of numbers in increments of 1 that begins with the start number and ends just before the stop number
replace(string, target, replacement) Replace string containing target string with target string
reverse(array) Reverse entries of array
slice(array, begin, end) Return slice of array from begin index to end index
split(string, delim) Split string with a delimiter and return array of strings
starts_with(subject, prefix) Check if subject string starts with prefix string
substring(string, begin, end) Return substring of string from begin index until end index
sum(array) Return sum of all values from array of numbers
to_json(value) Serialize value as json string
to_lower(str) Convert string to lower case
to_number(string) Parse string as number
to_string(value) Return string representation of the value
to_upper(str) Convert string to upper case
trim(string) Remove leading and trailing spaces
url_encode(string) Encode string using url encoding specification
uuid() Return randomly generated UUID
values(map) Return values of map

Nested ternary operators

When using nested ternary operators with parameterized strings, consider the following.
  • The expression must be wrapped inside a dollar sign and curly brackets, like ${...}.
  • Avoid dollar signs ($) in the middle of the expression because this might prevent the evalutation of the whole outer ${...} expression.
  • Follow the ternary operator structure, like A ? B :C, regardless of how many levels of nesting you have. Use round brackets () to support this nesting. For example, A ? (B1 ? B2 :(B3 ? B4 :B5)) :C.
Example without parameterized string:
${input.backup == "Yes" ? (input.region == "Region1" ? "Hello1" :"No-Backup") :"Test"}
Example with parameterized string:
${input.backup == "Yes" ? (input.region == "Region1" ? (env.projectName + "DataCenter1") :(input.region == "Region2" ? (env.projectName + "DataCenter2") :(input.region == "Region3" ? (env.projectName + "DataCenter3") :"No-Backup"))) :"Test"}
Example in a resource in a yaml:
Cloud_Machine_1:
    type: Cloud.Machine
    properties:
      image: imageName
      count: ${input.machineCount}
      flavor: small
      snapshotLimit: 1
      tags:
        - key: key1
          value: ${env.projectName}
        - key: key2
          value: ${input.backup == "Yes" ? (input.region == "Region1" ? (env.projectName + "DataCenter1") :(input.region == "Region2" ? (env.projectName + "DataCenter2") :(input.region == "Region3" ? (env.projectName + "DataCenter3") :"No-Backup"))) :"Test"}

Troubleshooting

The YAML language uses a colon and space (": ") as the separator between key and value in key-value pairs. Expression syntax depends on YAML, so a space after a colon can sometimes cause an expression to fail.

For example, the space between "win" : and "lin" in the following expression causes a failure.

${contains(input.image,"(Windows") == true ? "win" : "lin"}

The working expression omits the space.

${contains(input.image,"(Windows") == true ? "win" :"lin"}

If an expression continues to fail, try enclosing the entire expression in tick marks as shown.

ezOS: '${contains(input.image,"(Windows") == true ? "win" :"lin"}'