AMP workflow lets you define operations as part of your Maeztro configuration.

This reference gives some common patterns and tips for use of workflow in Maeztro. Refer to the AMP documentation for Workflow for full information on workflows, including all the available step types and advanced features like concurrency and locks – which can be very useful when working across multiple children Terraform resources in Maeztro!

Writing Workflow in Maeztro/HCL

Workflow is written as a list of steps, where in the simple case each step is a string; this is written in Maeztro (in HCL) as follows:

  steps = [
    "let x = ${try(self.count_sensor, 0}",
    "set-sensor count_sensor = ${x + 1}"

In more complicated situations, such as setting a map value or invoking a container or using a condition, some steps can be written as maps, with step indicating those attributes which can be set as shorthand:

  steps = [
      step: "let x"
      value: {
        count: "${try(self.count_sensor.count, 0}", 
    "let x.count = ${x.count + 1}",
    "set-sensor count_sensor = ${x}"

Both examples above increment a sensor’s count; however the first one stores it as a number, whereas the second stores it in a map. This can be very useful if storing multiple keys together in a map.

Note the use of HCL syntax to express steps, lists, and maps. This is nice in some cases, but for workflows that aren’t extremely simple, or which are used multiple times, it can be useful to either:

  • write the workflow as YAML (as is done elsewhere in AMP)
  • store the workflow in a separate file and read it using file

Workflow expressions in steps are normally evaluated when the workflow is run, to ensure current values for sensors are used in above. If you want to force resolution of expressions when the workflow is applied, you can use templatefile and pass the specific variables to use.

An example of this syntax in Maeztro HCL is:

  steps = decodeyaml(file("my-workflow.yaml"))

You can then provide workflow as YAML as is done elsewhere in AMP (and as used in the examples in that documentation):

# file "my-workflow.yaml"
- step: let x
    count: ${try(self.count_sensor.count, 0)}
- let x.count = ${x.count + 1}
- set-sensor count_sensor = ${x}

Best Practices with Maeztro Workflows

The HCL expression syntax is extremely powerful, and can replace some of the workflow steps and limitations.

For example, without HCL expressions, workflows might be written as:

  "let x = ${self.count} ?? 0",
  "let x = ${x} + 1",
  "set-sensor count = ${x}"

The first step uses the let ?? operator, and the second one uses the arithmetic operators as known to let. With HCL expressions, these can be replaced with the try function and arithmetic inside an expression:

  "let x = ${try(self.count_sensor.count,0) + 1}",    # preferred`
  "set-sensor count = ${x}"

The richer HCL expressions are normally preferred, but two things should be noted.

  • Combining HCL expressions with complicated shorthand can confuse the step parser, as step shorthand is not aware of some subtleties such as when ${...} interpolated expressions contain spaces or double quotes. The longhand (map) notation for steps may be required for complicated expressions.

  • The workflow idempotency checker assumes that interpolated expressions are idempotent across a step. This may not be the case with HCL expressions: for example, the above steps could be combined as set-sensor count = ${self.count+1}; however if “replayed” from that step, it will increment the sensor twice. By using the let step, the intermediate value is recorded and a replay is guaranteed to be idempotent.


Conditions are often used on workflows to indicate whether steps or policies should be run. HCL expressions can be used inside AMP condition/predicate blocks, and in addition, boolean HCL expressions can be supplied as conditions, e.g. condition: ${is_allowed} (instead of the longer workflow condition { target: ${is_allowed}, equals: true }.

Executing Commands

  • If your organization uses ssh or winrm, these steps can be very powerful in workflows, and Maeztro will automatically configure them according to a Terraform connection block on the resources.
  • The container step is recommended for complicated tasks; this uses the kubectl command on the server where Maeztro is running, so all that is necessary to enable this is to configure kubectl.
  • The shell step will run on the server where Maeztro is running, if that is supported. This is commonly used in development environments for easier debugging, with a switch to a container if on a server where shell steps are disabled (e.g. if AMP/Maeztro is offered as a service).