When using Terramate CLI, you often encounter scenarios where you want to execute a sequence of commands in stacks. Either locally or in CI/CD pipelines.
For example, a typical sequence for a Terraform pipeline could look like this:
terraform init
terraform validate
tfsec .
terraform apply -auto-approve
This requires you to invoke multiple terramate run
commands. The following will execute each step in our defined workflow in stacks:
terramate run terraform init
terramate run terraform validate
terramate run tfsec .
terraform run terraform apply -auto-approve
Terramate CLI would first invoke terraform init
in all stacks, then continue with terraform validate
, and so on. To run the full sequence of commands in each stack, they could be executed in a shell:
terramate run -- sh -c 'terraform init && terraform validate && tfsec . && terraform apply -auto-approve'
The example above would execute the sequence of commands in the first stack before moving on to the next (sequential execution of commands in stacks).
To simplify this, we added a new feature to Terramate called Terramate Scripts, allowing developers to create and execute such sequences of commands conveniently.
Defining scripts
A script in Terramate CLI is defined in a script block placed in any Terramate configuration file on any level of your project hierarchy. The script
block has the following syntax:
script "command" "subcommand" { # any level of subcommands is supported
description = "Execute commands"
job {
commands = [
["echo", "-n", "Hello"],
["echo", " World!"],
]
}
}
The list of labels of the script
block defines the arguments you need to provide to the terramate script run
command to execute the script: terramate script run command subcommand
. You can define any number of labels.
Attributes and Blocks Reference of the script
block
description
(optional) - A description of the jobs being executedjob
(required) - One or more blocks, each defining a sequence of commands to be executed in the script. Jobs are executed in the order of definition.
Each job can have the following attributes:
commands
(required) - A list of commands. Each item is a list has the form[ command, arg1, arg2, ...]
that will be executed accordingly. Terramate Functions and variable interpolation of the following namespaces are supported:global
,terramate
, andenv
To run a Terraform deployment, a script can be defined as:
script "deploy" {
description = "Run a Terraform deployment"
job {
commands = [
["terraform", "init"],
["terraform", "validate"],
["tfsec", "."],
["terraform", "apply", "-auto-approve"],
]
}
}
Running Scripts
Terramate scripts are run with terramate script run <command...>
, which will execute the defined job commands in the context of each stack directory.
Scripts can be defined on any hierarchy level and follow the inheritance rules of Globals and other Terramate features. When calling a script, it will only be executed on stacks that define or inherit the script definition. They are reachable from the current working directory and unaffected by filters. Scripts can be redefined on any hierarchy level and replace the previous definition.
Note: No error or warning will be issued for stacks not selected for script execution.
A more detailed explanation is covered in the Scope and Visibility sections, where
- Scope defines where a script will be executed in
- Visibility describes where a script can be called from
Scope
In general, the scope of a script definition includes the directory it is defined in and all nested sub-directories. A script can be run on stacks within its scope.
Figure A shows an example by highlighting the scope of a script named cmd:
Which stacks are selected further depends on additional criteria. Most importantly, the directory terramate script run
is executed from limits the selected stacks to those contained within. This works just like terramate run
.
A useful property of scripts is that they allow multiple definitions with the same name at different locations, yet all can be run with a single terramate script run
invocation. For example, as shown in Figure B, terramate script run cmd
at the root level, each of the two script definitions on stacks within their respective scopes.
As shown in Figure C, a script that is re-defined in a sub-directory overriding its previous definition will only be executed in stacks contained within the sub-directory, while the other stacks execute the original definition of the script.
This behavior enables scenarios where a single terramate script run deploy
could execute different scripts for different parts of the infrastructure, based on directory grouping.
Visibility
To call a script, it needs to be visible to the current working directory.
Scripts are generally visible within their scope, as defined in the last section, but additionally, they are also visible to all their parent directories.
This enables us to call a script from the project root without knowing where it is actually defined, as shown in Figure D.
Inspecting scripts
To inspect the behavior of a script, a dry-run can be started with script run --dry-run <command...>
. This will print out the commands executed per stack without actually executing them.
Besides this, there are additional experimental commands that can be used to inspect and debug script behavior:
terramate script list
Shows a list of all uniquely named scripts visible in the current directory, their description, and the root directory of their scope. If multiple definitions have the same name, a parent is selected over a child or a first sibling over a later sibling (ordered by directory name).terramate script info <scriptname>
Shows a detailed list of definitions for a given script name. This list includes the jobs and the stacks within the scope of each definition. As with the command, this information is always relative to the current directory.terramate script tree
Shows a tree view of all scripts relative to the current directory. The tree expands all sub-directories and the parent path to the project root, showing script definitions per directory.
Summary
Terramate scripts allow you to specify a recurring sequence of commands to execute, e.g., a deployment, specifying specific options for the cloud. Scripts are especially useful for defining custom commands in Terramate that can be reused among environments and platforms without repeating expressive logic.
Join our Community
Your feedback is very valuable for us and the future development of Terramate. We’d love you to join our Discord Community, which is the best way to give us feedback or ask questions regarding Terramate.