Ported from Garden’s documentation: features/variables-and-templating.md, gliss-cli at
3bc62a036 (Garden 0.14). Gliss runs Garden under the hood; the notes on this page say where Gliss differs.In Gliss, template strings and variables work as in Garden, with three differences: the project uses the
gliss provider, so provider outputs from kubernetes or Terraform don’t exist; Garden Cloud secrets and remote variables aren’t available; and secret values never go in variables or varfiles. You set secret values through Gliss secret requests, and your configuration refers to secrets by name only.Template string overview
String configuration values in Garden config files can be templated to inject variables, information about the user’s environment, references to other actions and more. The basic syntax for templated strings is${some.key}. The key is looked up from the template context available when resolving the string. The available context depends on what is being resolved, i.e. a project, action, provider etc.
For example, in one action you might want to reference something from another action and expose it as an environment variable:
Literals
In addition to referencing variables from template contexts, you can include a variety of literals in template strings:- Strings, including concatenated ones, enclosed with either double or single quotes:
${"foo"},${'bar'},${'bar' + 'foo}. - Numbers:
${123} - Booleans:
${true},${false} - Null:
${null} - Arrays:
${[1, 2, 3]},${["foo", "bar"]},${[var.someKey, var.someOtherKey]},${concat(["foo", "bar"], ["baz"])},${join(["foo", "bar"], ",")}
Operators
You can use a variety of operators in template string expressions:- Arithmetic:
*,/,%,+,- - Numeric comparison:
>=,<=,>,< - Equality:
==,!= - Logical:
&&,||, ternary (<test> ? <value if true> : <value if false>) - Unary:
!(negation),typeof(returns the type of the following value as a string, e.g."boolean"or"number") - Relational:
contains(to see if an array contains a value, an object contains a key, or a string contains a substring) - Arrays:
+ - Strings:
+
+ operator which can be used to concatenate two strings or array references. The equality and logical operators work with any term (but be warned that arrays and complex objects aren’t currently compared in-depth).
Clauses are evaluated in standard precedence order, but you can also use parentheses to control evaluation order (e.g. ${(1 + 2) * (3 + 4)} evaluates to 21).
These operators can be very handy, and allow you to tailor your configuration depending on different environments and other contextual variables.
Below are some examples of usage:
The || operator allows you to set default values:
== and != operators allow you to set boolean flags based on other variables:
contains operator can be used in several ways:
${var.some-array contains "some-value"}checks if thevar.some-arrayarray includes the string"some-value".${var.some-string contains "some"}checks if thevar.some-stringstring includes the substring"some".${var.some-object contains "some-key"}checks if thevar.some-objectobject includes the key"some-key".
+ operator can also be used to concatenate two arrays or strings:
Helper functions
You can use a variety of helper functions in template strings, for things like string processing, parsing, conversions etc. You find a full list in the reference docs, but here are a couple of examples:${base64Encode('my value')}encodes the'my value'string as base64.${base64Decode('bXkgdmFsdWU=')}decodes the given base64 string.${replace(var.someVariable, "_", "-")}returns thesomeVariablevariable with all underscores replaced with dashes.
If/else conditional objects
You can conditionally set values by specifying an object with$if, $then and (optionally) $else keys. This can in many cases be clearer and easier to work with, compared to specifying values within conditional template strings.
Here’s an example:
spec.command to [npm, run, watch] in the dev environment, otherwise to [npm, start].
You can also skip the $else key to default the conditional to no value (i.e. undefined).
Multi-line if/else blocks in strings
You can use if/else blocks in strings. These are particularly handy when templating multi-line strings and generated files in action templates. The syntax is${if <expression>}<content>[${else}]<alternative content>${endif}, where <expression> is any expression you’d put in a normal template string.
Here’s a basic example:
Nested lookups and maps
In addition to dot-notation for key lookups, we also support bracketed lookups, e.g.${some["key"]} and ${some-array[0]}.
This style offer nested template resolution, which is quite powerful, because you can use the output of one expression to choose a key in a parent expression.
For example, you can declare a mapping variable for your project, and look up values by another variable such as the current environment name. To illustrate, here’s an excerpt from a project config with a mapping variable:
${var.replicas[environment.name]}.
You can even use one variable to index another variable, e.g. ${var.a[var.b]}.
Concatenating lists
Any list/array value supports a special kind of value, which is an object with a single$concat key. This allows you to easily concatenate multiple arrays.
Here’s an example where we concatenate the same templated value into the commands of two tests:
For loops
You can map through a list of values by using the special$forEach/$return object.
You specify an object with two keys, $forEach: <some list or object> and $return: <any value>. You can also optionally add a $filter: <expression> key, which if evaluates to false for a particular value, it will be omitted.
Template strings in the $return and $filter fields are resolved with the same template context as what’s available when resolving the for-loop, in addition to ${item.value} which resolves to the list item being processed, and ${item.key}.
You can loop over lists as well as mapping objects. When looping over lists, ${item.key} resolves to the index number (starting with 0) of the item in the list. When looping over mapping objects, ${item.key} is simply the key name of the key value pair.
Here’s an example where we kebab-case a list of string values:
Merging maps
Any object or mapping field supports a special$merge key, which allows you to merge two objects together. This can be used to avoid repeating a set of commonly repeated values.
Here’s an example where we share a common set of environment variables for two services:
$merge key matters. If the keys being merged overlap between the two objects, the value that’s defined later is chosen.
Optional values
In some cases, you may want to provide configuration values only for certain cases, e.g. only for specific environments. By default, an error is thrown when a template string resolves to an undefined value, but you can explicitly allow that by adding a? after the template.
Example:
Project variables
A common use case for templating is to define variables in the project/environment configuration, and to use template strings to propagate values to actions in the project. You can define them in your project configuration using thevariables key, as well as the environment[].variables key for environment-specific values.
You might, for example, define project defaults using the variables key, and then provide environment-specific overrides in the environment[].variables key for each environment. When merging the environment-specific variables and project-wide variables, we use a JSON Merge Patch.
The variables can then be referenced via ${var.<key>} template string keys. For example:
${var.my.nested.key}.
You can also output objects or arrays from template strings. For example:
Variable files (varfiles)
You can also provide variables using “variable files” or varfiles. These work mostly like “dotenv” files or envfiles. However, they don’t implicitly affect the environment of the Garden process and the configured services, but rather are added on top of thevariables you define in your project configuration (or action variables defined in the variables of your individual action configurations).
This is useful for contextual values that differ per environment.
By default, Garden will look for a garden.env file in your project root for project-wide variables, and a garden.<env-name>.env file for environment-specific variables. You can override the filename for each as well.
To use a action-level varfile, simply configure the varfile field to be the relative path (from action root) to the varfile you want to use for that action. For example:
.env- Standard “dotenv” format, as supported by dotenv..yaml/.yml- YAML. Must be a single document in the file, and must be a key/value map (but keys may contain any value types)..json- JSON. Must contain a single JSON object (not an array).
varfile and environments[].varfile fields.
You can also set variables on the command line, with --var flags. To override a nested variable, you can use dot notation. Note that while this is handy for ad-hoc invocations, we don’t generally recommend relying on this for normal operations, since you lose a bit of visibility within your configuration. But here’s one practical example:
Variable precedence order
The order of precedence is as follows (from highest to lowest):- Individual variables set with
--varCLI flags. - The action-level varfiles (if configured).
- Action variables set in the action’s
variablesfield. - The environment-specific varfile (defaults to
garden.<env-name>.env). - The environment-specific variables set in
environment[].variables. - Configured project-wide varfile (defaults to
garden.env). - The project-wide
variablesfield.
Provider outputs
Providers can expose outputs that other provider configs and actions reference, under${providers.<name>.outputs.<key>}.
In Gliss, the project uses the
gliss provider, so outputs of Garden’s kubernetes and Terraform providers don’t exist. The gliss provider’s outputs will be documented when it ships.Action outputs
Actions often output useful information, that other actions can reference (provider and project configs cannot reference action outputs). Every action also exposes certain keys, like the action version. For example, you may want to reference the image name and version of a container Build:Action runtime outputs
Some actions (namely Runs) expose template keys prefixed withactions.<kind>.<name>.outputs. with some special semantics. They are used to expose runtime outputs from actions and therefore are resolved later than other template strings. This means that you cannot use them for some fields, such as most identifiers, because those need to be resolved before validating the configuration.
That caveat aside, they can be very handy for passing information between actions. For example, you can pass log outputs from one task to another:
prep-run is copied to an environment variable for my-deploy. Note that you currently need to explicitly declare prep-run as a dependency for this to work.
For a practical use case, you might make a Run that prepares some data and passes information about it to a Deploy.
Different action types expose different outputs. Please refer to the action type reference docs for details.