Terraspace All: Including and Excluding Stacks
The terraspace all
command allows you to deploy multiple stacks simultaneously. You can configure Terraspace to include or exclude specific stacks that terraspace all
will deploy.
Important: See Including and Excluding Stacks Inference at the bottom. In general, it’s recommendeded to have terraspace all
infer which stacks are allowed be deployed from config.allow.stacks
and config.deny.stacks
instead of configuring config.all.include_stacks
explicitly. Though config.all.include_stacks
can be used if you need the control.
Example 1: Simple Include
Let’s say we have 3 stacks:
$ terraspace list
app/stacks/stack1
app/stacks/stack2
app/stacks/stack3
config/app.rb
Terraspace.configure do |config|
config.all.include_stacks = ["stack1"]
end
This means that terraspace all
will only consider stack1. Example:
$ terraspace all up
terraspace up stack1 # batch 1
You can still deploy stack2 and stack3 directly with terraspace up
terraspace up stack2
terraspace up stack3
Example 2: Simple Exclude
Let’s say we have 3 stacks:
$ terraspace list
app/stacks/stack1
app/stacks/stack2
app/stacks/stack3
config/app.rb
Terraspace.configure do |config|
config.all.exclude_stacks = ["stack1"]
end
This means that terraspace all
will not consider stack1. Example:
$ terraspace all up
terraspace up stack2 # batch 1
terraspace up stack3 # batch 1
You can still deploy stack1
directly with terraspace up
terraspace up stack1
Example 3: Exclude Stacks for Specific Environments with Multiple Files
An interesting example is if you want terraspace all
to deploy specific stacks only for certain environments.
Let’s say we have 3 stacks:
$ terraspace list
app/stacks/route53
app/stacks/stack1
app/stacks/stack2
Route53 resources are global and may not always make sense to deploy on a per env basis. Here are the terraspace up
commands to explain how we only want these stacks to deploy with specific environments.
TS_ENV=global terraspace up route53
TS_ENV=dev terraspace up stack1
TS_ENV=prod terraspace up stack1
TS_ENV=dev terraspace up stack2
TS_ENV=prod terraspace up stack2
To configure terraspace all
so that it will only deploy based on the environment, we can do this:
config/app.rb
Terraspace.configure do |config|
config.all.exclude_stacks = ["route53"]
end
So we generally exclude the route53
stack from all environments. Then we override the config include it in the global
environment like so:
config/envs/global.rb
Terraspace.configure do |config|
config.all.exclude_stacks = nil # important to override and reset this
config.all.include_stacks = ["route53"]
end
Running terraspace all
results in something like this:
$ TS_ENV=dev terraspace all up
Will run:
terraspace up stack1 # batch 1
terraspace up stack2 # batch 1
$ TS_ENV=prod terraspace all up
Will run:
terraspace up stack1 # batch 1
terraspace up stack2 # batch 1
And for TS_ENV=global
$ TS_ENV=global terraspace all up
Will run:
terraspace up route53 # batch 1
Example 4: Exclude Stacks for Specific Environments with One File
Some folks may prefer or feel it’s easier not to have the configuration in multiple files. To use one file instead.
config/app.rb
Terraspace.configure do |config|
if Terraspace.env == "global"
config.all.include_stacks = ["route53"]
else
config.all.exclude_stacks = ["route53"]
end
end
This is one of the benefits that come with the way Terraspace handles configurations. You have access to the power of a full programming language, Ruby, when you need it. Of course, with great power comes great responsibility.
Question: Should you use multiple files or one file?
It depends. If the configurations are small, it’s clearer to have them in one file. If the configurations get complex, separating them into multiple files makes sense. It also depends a lot on personal preference.
Example 5: Complete Customization with Object That Implements Call
For even more control over which stacks are included or excluded you can assign an object that implements call
and returns an Array
. This is an advanced technique. Example:
class Includer
def call(stack)
["route53"] if Terraspace.env == "global"
end
end
class Excluder
def call(stack)
["route53"] unless Terraspace.env == "global"
end
end
Terraspace.configure do |config|
config.all.include_stacks = Includer
config.all.exclude_stacks = Excluder
end
The Excluder
class defines the call
method and takes in the stack
argument. It’s value is the name of current stack being deployed. The Includer
and Excluder
classes should return an Array or nil. Returning nil
is the same as not setting the option at all.
Including and Excluding Stacks Inference
If you are using config.allow.stacks
and config.deny.stacks
, then config.all.include_stacks
and config.all.exclude_stacks
are inferred from those settings. For example:
Let’s say we have 3 stacks:
$ terraspace list
app/stacks/route53
app/stacks/stack1
app/stacks/stack2
If you want to only allow terraspace up
to deploy the route53
stack for TS_ENV=global
environment. Configure:
config/app.rb
Terraspace.configure do |config|
if Terraspace.env == "global"
config.allow.stacks = ["route53"]
else
config.deny.stacks = ["route53"]
end
end
Then the route53
stack will only be allowed to be deployed with TS_ENV=global
. If TS_ENV=dev
, then the route53
stack will be prevented from deploying. Example:
$ TS_ENV=global terraspace up route53
...
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
...
$ TS_ENV=dev terraspace up route53
Building .terraspace-cache/dev/stacks/route53
ERROR: The configs do not allow this.
This stack is not allowed to be used for TS_ENV=dev
Deny stacks: route53
By default, terraspace set the options like this:
config.all.include_stacks = config.allow.stacks
config.all.exclude_stacks = config.deny.stacks
This means:
$ TS_ENV=global terraspace all up
Will run:
terraspace up route53 # batch 1
And
$ TS_ENV=dev terraspace all up
Will run:
terraspace up stack1 # batch 1
terraspace up stack2 # batch 1
The the route53
stack will only be deployed when TS_ENV=global
by inference. You only have to set the config.allow.stacks
and config.deny.stacks
and terraspace all
automatically knew what to do.
You can change this default behavior with config.all.consider_allow_deny_stacks = false
. You would then need to set config.all.include_stacks
and config.all.exclude_stacks
explicitly.
More docs: Config Restricting Stacks.