Prevent modules to be deployed in one environment

Hello,
I’m currently trying to migrate a quite big Terraform project to TerraSpace (Thanks for your great work BTW !!!)
In the current project, the environments are folders containing functional modules instances (web-app, db , video-generator, etc…)

In the dev environment, there is only video-generator (no web-app and db since they are run locally).

How would you replicate this using TerraSpace ?
I started created stacks (web-app, db…) with base.tfvars, dev.tfvars…etc.
Am I forced to play with the count attributes of the web-app and db-modules ?

Thanks in advance !

Thanks for the kind words. Unsure if this is exactly what you’re looking for, but here are some thoughts.

You can deploy only the specific stacks with terraspace up. Examples:

TS_ENV=dev  terraspace up video-generator
TS_ENV=prod terraspace up db
TS_ENV=prod terraspace up video-generator
TS_ENV=prod terraspace up web-app

So don’t deploy for the other web-app and video-generator for TS_ENV=dev.

If you’re leveraging terraspace all up, then you can specify the stacks to use.

TS_ENV=dev  terraspace all up video-generator
TS_ENV=prod terraspace all up db video-generator web-app 

If you would like to just call terraspace all up without worrying about specifying the stacks. Maybe use the all.ignore_stacks settings. Docs: https://terraspace.cloud/docs/config/reference/ Something like:

config/app.rb

Terraspace.configure do |config|
  ignore_stacks = Terraspace.env == "dev" ? ["db", "web-app"] : []
  config.all.ignore_stacks = ignore_stacks
end

Then terraspace all can be blindly called:

TS_ENV=dev  terraspace all up # only deploy video-generator
TS_ENV=prod terraspace all up # will deploy all stacks

In looking at this, added an all.include_stacks option also. See: https://github.com/boltops-tools/terraspace/pull/85

Maybe a wrapper script also is simpler and more straightforward. Something like:

ts.sh

#!/bin/bash
if [ "$TS_ENV" == "dev" ]; then
  terraspace all up video-generator
else
  terraspace all up db video-generator web-app 
fi

Also, if you want an additional safeguard to ensure that the wrong stack doesn’t get called an env, you can always add a snippet of ERB at the top of your stack main.tf. Something like:

app/stacks/db/main.tf

<% raise "shouldnt be called in this env: #{Terraspace.env} if Terraspace.env == "dev" %>
... 
rest of your terraform HCL code

This prevents the db stack from ever deploying in the TS_ENV=dev env. You can also play with count as you noted, those are some options though.

Thank you for those great insights !

Indeed I’d like to be able to blindly run terraspace all up.

It would be great if we could decide the instantiation of a stack at the stack level.
For instance:
stacks/db/base.tfvars contains count = 0
stacks/db/prod.tfvars contains count = 1

This way, at a glance, you can see that there is no db instance in dev environment, since no dev/tfvars file :wink:
Since Terraform 0.13, count metadata is available in modules and could solve this, but at first sight, it cannot be set with tfvars.
In my current setup, in the dev module, there is no instantiation of the db module (no db module declaration).

Another issue I’m facing is that, sometimes, there is a stack common for all environments. Let’s say I have an ElasticSearch cluster (a quite expensive service !) and I want to instantiate this stack only once.

Could it be solved by creating an all or common environment, instantiating ES in this environment, and access it this from the other environments with remote_state data sources ?

When I use the output helper, say output('vpc.vpc_id'), I understand this as fetch the vpc_id output value in the vpc stack belonging to the same environment i’m running the output helper, is this correct ?
Perhaps it would make sense to have an option like this:
output('vpc.vpc_id', environment: 'common')

Sorry for all those questions !

RE: count in tfvars

Had a thought, though count is not supported in tfvars files, could pass a variable like create_resource = true and then use that to set count = 0 or count = 1 in the db/main.tf. A tfvars file would still be generated, but the db module would not be instantiated.

RE: all or common environment output references

Yes. Would like this. Dug into it a while back and it’s a bit complex. Will consider PRs. Again, no sweat either way :+1:

There are also Terraspace Custom Helpers. So you can extend Terraspace and add your own methods. In this case, could add a method that provides the common stack outputs info.

The remote_state is another approach. When used it, it feels a little too coupled, but that’s may just be a matter of opinion.

Maybe deploy the common stack first. And then just manually assign the values to the tfvars. It’s probably the simplest approach and allows the stack code to be a little more decoupled.

Hello,
About the count method, the (not so big) problem is that every stacks outputs become an array, so you have to to do my_resource[0].my_attributes on all outputs.

What would you think of another hook, which could be triggered earlier in the compiler process (in mod_names listing for instance) and let the user rule out a module before it is generated ? I’ll fork the project to make some tests and propose a PR if this feature is not too specific to my use case :wink:

About the common environment, thank for the suggestion, indeed Custom Helpers will help ! I totally agree that remote_state is not a panacea, the manual approach will be a better fit for now.

I started Terraspace conversion, and it is a very smooth process :wink: