Conditional Lookups

Is there any way to perform a conditional data lookup with the equivalent of something like a try / catch block. For example (this is pseudo-code)
data aws_kms_alias trysomekey {name=“xxx”} // try looking up resource
catch error:
resource aws_kms_key some_key {name=“xxx”, …} … // create resource if not found

data aws_kms_somekey {name=“xxx”} // can rely on this working now

The problem I am trying to address is we have written a module for CloudWatch logs which gets used by lots of other modules & it would be great to be able to rely on the fact that we can safely create a global KMS key & alias for encrypting logs if one does not already exist in the account or use the one that does exist… I’ve been looking at external data source using a script to wrap the AWS CLI I don’t know if that could work ? I

The alternative is passing key aliases around all of our modules which isn’t great.

Hi @fergoid,

Since Terraform is a desired-state system rather than an imperative system there isn’t any way to express statements like “create this unless it already exists”. Instead, the closest we can do is to declare that something should exist if it doesn’t exist, which is contradictory and will therefore cause Terraform to fail to converge that configuration because it will cycle between creating and destroying the object each time you run terraform apply. (Because that non-converging situation is very confusing, most singular data sources are designed to make it impossible to make such a statement, and thus you get an explicit error rather than non-convergence.)

Instead, you must design your system so that each object is managed by one specific configuration, and then the other configurations consume that object in a read-only way. In your case it sounds like you would need a separate configuration that sets up all of the common infrastructure that would be shared across all instances of your CloudWatch Logs module (rather than each module instance having its own object), and then write your CloudWatch Logs module to discover those shared objects using data sources.

In that model, you’d apply the “shared infrastructure” configuration first, and then you could call your CloudWatch Logs module from as many other configurations as you need. If you try to apply the CloudWatch Logs module into an environment where the shared infrastructure wasn’t already applied then it would return an error saying that those necessary objects aren’t present.

This does of course assume that there’s some suitable convention for discovering the necessary objects via data sources. That can either be an informal convention using particular tag values, or something more explicit such as storing necessary ids/names/ARNs under well-known names in SSM Parameter Store. The main thing though is that the shared infrastructure configuration and the CloudWatch Logs module both agree on that convention and so instances of the module can find it with little to no extra configuration.