-1

I have a Terraform child module for an Azure Function App. This Function App also implements an Azure Monitor Alert (referenced from another child module) and provisions a set of dedicated Action Groups for each environment, i.e. Dev, Test, Staging and Production.

Each Action Group is provisioned with 3 email recipients and requires the corresponding email addresses to be assigned to the variables bmc_email_address, slack_email_address and teams_email_address respectively, as shown below.

module "action-groups" {
source = "../../../modules/monitoring-alert"
environment = var.environment
slack_email_address = var.slack_email_address
teams_email_address = var.teams_email_address
bmc_email_address = var.bmc_email_address

**[[ variables.tf ]]**

variable "db_connection_string" {
type = string
}

variable "bmc_email_address" {
description = "The bmc_email_address for the current environment"
default = null
}
variable "slack_email_address" {
description = "The slack_email_address for the current environment"
default = "[email protected]" # Value must be set conditionally depending on the current environment, i.e. DEV, TEST, STAGING & PRODUCTION
}

variable "teams_email_address" {
description = "The teams_email_address for the current environment"
default = "[email protected]" # Value must be set conditionally depending on the current environment, i.e. DEV, TEST, STAGING & PRODUCTION

The slack and teams email variables are not nullable, meaning if I fail to set a default value, the my child module terraform plan errors on the missing required variable values. Naturally, I cannot and do not wish to set a default value to these variables, as the value differs across all four environments. I would rather prefer some conditional logic based on the current environment which is all handled by my overarching root module and pipeline stage definition.

Any suggestions or ideas?

@ha36d, following on from your feedback and having implemented your proposed solution by:

  1. Setting up the email_by_environment local block.
  2. Updating the 3 email address args for the action-group implementation in the 2nd child module.

I am unfortunately still receiving a Missing required argument error in Terraform as depicted below, as the 2nd child module appears to require default values declared for the two non-nullable email variables, i.e. slack_email_address = var.slack_email_address and teams_email_address = var.teams_email_address

Any suggestions how to get round this?

enter image description here

1 Answer 1

-1

The best solution for this case is terragrunt, but using pure terraform, you can define a map of maps and then reference these local variables inside the module. In the middle module, you will use only one variable email_by_environment and in the child module, you will decouple it.

Function App module (middle module):

# modules/function-app/main.tf
locals {
  email_by_environment = {
    Dev = {
      slack = "[email protected]"
      teams = "[email protected]"
      bmc   = "[email protected]"
    }
    Test = {
      slack = "[email protected]"
      teams = "[email protected]"
      bmc   = "[email protected]"
    }
    Staging = {
      slack = "[email protected]"
      teams = "[email protected]"
      bmc   = "[email protected]"
    }
    Production = {
      slack = "[email protected]"
      teams = "[email protected]"
      bmc   = "[email protected]"
    }
  }
}

module "action-groups" {
  source                = "../monitoring-alert"
  environment           = var.environment
  email_by_environment  = local.email_by_environment
}
# modules/function-app/variables.tf
variable "environment" {
  type = string
}

Monitoring Alert module (child module):

# modules/monitoring-alert/variables.tf
variable "environment" {
  type = string
}

variable "email_by_environment" {
  description = "Map of env => {slack, teams, bmc}"
  type = map(object({
    slack = string
    teams = string
    bmc   = string
  }))
}
# modules/monitoring-alert/main.tf
locals {
  resolved_emails = var.email_by_environment[var.environment]
}

resource "someResource" "example" {

# working with local.resolved_emails.bmc, local.resolved_emails.slack and local.resolved_emails.teams
  ...
}
Sign up to request clarification or add additional context in comments.

5 Comments

Appreciate the feedback @ha36d. I do believe your proposed solution could be near to fulfilling this requirement. However, there appears to be one major sticking point which is causing Terraform to fail, even after implementing your solution. So, as pointed out earlier, the 1st child module that I'm referencing from the 2nd child module (as below), declares three email variables bmc_email_address slack_email_address and teams_email_address , the last two of which cannot be nullable. module "action-groups" { source = "../../../modules/monitoring-alert" [contd below]
Because I am not setting default values for those two non-nullable variables in the 2nd child module, as mentioned in my initial submission, Terraform is now throwing a Missing required argument error when run, and this is even after implementing your solution. I've updated my original post with a screenshot of the error, as it's impossible to do so within a comment. I can set a default value for obvious reasons, as explained previously. Any thoughts?
I added a single variable in middle module which holds are the contacts, and then decouple it where we need it (for example in child module). I updated the answer.
Thanks. So if I understand what you're saying, you've added the below variable to the 2nd (calling) child module which should get round the reported issue, i.e. - email_by_environment = local.email_by_environment. Is this correct? If that is the case, well VSCode has immediately highlighted it as an error, since (I stand to be corrected on this) it appears we're attempting to inherit/instantiate the first child module, but then attempting to introduce an entirely new variable in the 2nd child module, event though it isn't defined in that first child module?
Have reviewed your last update and I'm afraid it's not gotten any clearer. If anything, I'm probably more confused now. Somehow, part of me thinks the proposed solution may be overcomplicating things and that rather than looking to apply all these raft of changes, including to the monitoring alert child module which would impact other consumers of the module, we could perhaps simply set those 3 email variables in the function app module to set a default value conditionally? I'll illustrate this with an example at the bottom of my original post for better clarity and also better formatting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.