Warm tip: This article is reproduced from serverfault.com, please click

terraform overwrite tag value in sub modules

发布于 2020-11-30 12:40:52

I'm using terraform modules and passing a set of default_tags to sub-modules for consistent tagging. This is shown below, and has the advantage that sub-modules inherit their parent's tags, but can also add their own.

However what I'd also like to do is to be able to overwrite some of the inherited tags values, especially "Name". But I can't seem to make this work.

In the example below (terraform 13.5 with AWS) the first value specified for any tag, e.g. "scratch-test" in the root module is cascaded down to the sub-modules, and cannot be changed. So both the VPC Name tag and the subnet Name tag = "scratch-test".

How can I overwrite a tag value in a sub-module?

# root variables.tf
variable "default_tags" {
    type = map
    default = {
        environment_type = "Dev Environment"
    }
} 


# root main.tf
provider "aws" {
    region = var.region
}

module "vpc" {
    source = "../../../../scratch/tags-pattern"
    vpc_name                = "scratch-test"
    public_subnets          = ["10.0.0.0/26"]

    default_tags = merge(map(
        "Name", "scratch-test"
    ), var.default_tags)
}

# ../../../../scratch/tags-pattern/main.tf
module "the_vpc" {
    source = "../../terraform/tf-lib/network/vpc"

    vpc_name = var.vpc_name
    vpc_cidr = "10.0.0.0/24"

    default_tags = merge(map(
        "Name", "scratch-test-vpc",
        "vpc_tag", "vpc"
    ), var.default_tags)
}

# Add a subnet
module "public_subnets" {
    source = "../../terraform/tf-lib/network/subnet"
    vpc_id                  = module.the_vpc.output_vpc_id
    subnets                 = var.public_subnets
    default_tags = merge(map(
        "Name", "scratch-test-subnet",
        "subnet_tag", "public"
    ), var.default_tags)
}
# tf-lib/network/vpc/main.tf
resource "aws_vpc" "vpc" {
    cidr_block = var.vpc_cidr
    enable_dns_support = true
    enable_dns_hostnames = true
    tags = merge(map(
        "module", "tf-lib/network/vpc"
    ), var.default_tags)
} 

The variable.tf file for each module contains the statement:

variable "default_tags" {}
Questioner
P Burke
Viewed
1
ydaetskcoR 2020-11-30 21:46:04

The merge function sets precedence by overwriting with the latter maps defined in the argument sequence:

merge takes an arbitrary number of maps or objects, and returns a single map or object that contains a merged set of elements from all arguments.

If more than one given map or object defines the same key or attribute, then the one that is later in the argument sequence takes precedence. If the argument types do not match, the resulting type will be an object matching the type structure of the attributes after the merging rules have been applied.

So to allow for you to override the default tags you can specify the default tags first like this:

# root variables.tf
variable "default_tags" {
    type = map
    default = {
        environment_type = "Dev Environment"
    }
} 


# root main.tf
provider "aws" {
    region = var.region
}

module "vpc" {
    source = "../../../../scratch/tags-pattern"
    vpc_name                = "scratch-test"
    public_subnets          = ["10.0.0.0/26"]

    default_tags = merge(var.default_tags, map(
        "Name", "scratch-test"
    ))
}

The above might also look clearer using the {} map syntax rather than the map function too:

# root main.tf
provider "aws" {
    region = var.region
}

module "vpc" {
    source = "../../../../scratch/tags-pattern"
    vpc_name                = "scratch-test"
    public_subnets          = ["10.0.0.0/26"]

    default_tags = merge(var.default_tags, {
      Name = "scratch-test",
    })
}

As mentioned in the map function documentation this function is deprecated and will eventually be removed:

This function is deprecated. From Terraform v0.12, the Terraform language has built-in syntax for creating maps using the { and } delimiters. Use the built-in syntax instead. The map function will be removed in a future version of Terraform.