Many of you manage environments with Terramate by using one Stack per environment. While this works for most use cases, sometimes you might want to use Terraform CLI Workspaces instead, which require you to manage multiple Workspaces in the same Stack.
To support Workspaces and any other approach that enables managing different environments within the same Stack, we just added experimental support for a new feature: Deployment Targets. This allows to keep separate Stack information when the same Stacks are deployed to multiple environments, i.e., production and staging.
Since Deployment Targets are an experimental feature, it needs to be explicitly enabled in your terramate.tm.hcl
with terramate.config.experiments = ["targets"]
and terramate.config.cloud.targets.enabled = true
.
terramate {
required_version = ">= 0.9.0"
config {
cloud {
# Configure the namespace of your Terramate Cloud organization
organization = "terramate-demo"
# Opt in for the deployment targets feature
targets {
enabled = true
}
}
# Enable experiments
experiments = [
"targets",
]
}
}
Once enabled, commands that synchronize or read stack information to Terramate Cloud require a -target <target_id>
parameter. These include:
terramate run --sync-deployment/--sync-drift-status/--sync-preview
terramate script run
terramate run --status
terramate list --status
terramate cloud drift show
The following example demonstrates pushing a Terraform CLI Workspace as a Deployment Target to Terramate Cloud.
# Create a new Terraform CLI Workspace called 'prod'
terramate run \
-- \
terraform workspace new prod
# Sync the Workspace in all Stacks as a Deployment Target 'prd' to Terramate Cloud using a Drift Detection Run
terramate run \
--sync-drift-status \
--terraform-plan-file plan.tfplan \
--target prod \
-- \
terraform plan -out plan.tfplan -detailed-exitcode
Please look at our example repository for a complete example of using Terraform CLI Workspaces with Deployment Targets.
Sometimes, it’s helpful to declare a variable that can be reused within the same Terramate Script to keep your workflow as DRY as possible. For that, we just added support for Lets variables to Terramate Scripts.
workflows.tm.hcl
script "deploy" {
description = "Run a Terraform/Tofu deployment"
lets {
provisioner = "terraform" # another option: "tofu"
}
job {
name = "deploy"
description = "Initialize, validate and deploy Terraform stacks"
commands = [
[let.provisioner, "init"],
[let.provisioner, "validate"],
["tfsec", "."],
[let.provisioner, "apply", "-auto-approve"],
]
}
}
This allows you to configure repetitive values, such as commands used in Scripts, to keep your workflows even more DRY .
Trigger enables you to forcibly mark a stack as changed even if it doesn't contain any code changes according to Change Detection. This is particularly helpful for triggering stacks to be run when, e.g., a deployment fails on apply-after-merge workflows for Terraform and OpenTofu.
Some of our customers asked for a way to enforce exactly the inverted behavior of normal triggers. For that, we just added Ignore Triggers to Terramate CLI.
terramate experimental trigger /path/to/stack --ignore-change
This can be helpful when you make cosmetic changes to one or more stacks that don't affect the managed resources and can now be done by using the --ignore-change
flag to trigger Stacks to remain unchanged. This flag configures the change detection to ignore these stacks in the next Pull Request and Deployment.
One of Terramate's most powerful features is the native Code Generation for Terraform, OpenTofu, YAML, JSON and other common configuration languages.
However, before Terramate CLI v0.9.0, the code generation didn’t allow for partial evaluation which made it unsuitable for specific use cases such as assigning Data Sources to Globals .
To overcome this, we finally added support for [for ...]
and {for ...}
expressions containing Terramate variables and functions inside the generate_hcl.content
block.
This now finally allows you to configure more dynamic code generation configurations such as the following:
config.tm.hcl
globals "terraform" "providers" "cloudflare" {
source = "cloudflare/cloudflare"
version = "~> 4.29"
enabled = true
config = {
some_config = true
}
config_partial = {
api_key = "data.sops_file.secrets.data.CLOUDFLARE_API_KEY"
email = "data.sops_file.secrets.data.CLOUDFLARE_EMAIL"
}
}
generate_providers.tm.hcl
generate_hcl "providers.tf" {
lets {
required_providers = { for k, v in tm_try(global.terraform.providers, {}) :
k => {
source = v.source
version = v.version
} if tm_alltrue([
tm_try(v.enabled, true),
tm_length(tm_split(".", k)) == 1,
])
}
providers = { for k, v in tm_try(global.terraform.providers, {}) :
k => {config = tm_try(v.config, {}), config_partial = tm_try(v.config_partial, {})} if tm_alltrue([
tm_length(tm_split(".", k)) == 1,
tm_try(v.enabled, true),
tm_can(v.config) || tm_can(v.config_partial)
])
}
}
content {
# terraform version constraints
terraform {
required_version = tm_try(global.terraform.version, "~> 1.8")
}
# Provider version constraints
terraform {
tm_dynamic "required_providers" {
attributes = let.required_providers
}
}
# Provider configs
tm_dynamic "provider" {
for_each = let.providers
labels = [provider.key]
attributes = tm_merge(
tm_try(provider.value.config, {}),
tm_try({for k, v in provider.value.config_partial : k => tm_hcl_expression(v)}, {}),
)
}
}
}
Which will generate the following providers.tf
file, allowing you to bring your code generation configuration to the next level.
providers.tf
provider "cloudflare" {
api_key = data.sops_file.secrets.data.CLOUDFLARE_API_KEY
email = data.sops_file.secrets.data.CLOUDFLARE_EMAIL
some_config = true
}
Other than adding support for GitLab CI/CD , Terraform CLI Workspaces , Partial Evaluation , Ignore Triggers and Lets Variables in Scripts, we also fixed a variety of bugs and added a bunch of minor improvements. For a complete overview of all changes please take a look at the release notes.
With the 0.9.0 release of Terramate CLI, we added a bunch of great improvements requested by our community that significantly improved the Developer Experience when working with Terramate CLI and Cloud
If you don’t use Terramate yet, we recommend you take it for a spin . A feedback we frequently hear from the community is that Terramate CLI makes using Terraform (and OpenTofu) “so much simpler and easier to use”.
If you have any questions or feature requests - or if you need help, feel free to join our Discord Community .
We’d love to hear from you!