skip to Main Content

I’d like to use something as below to create/manage common tags for all resources in projects. For the common_var_tag, I’d like it to be applied only there are any other changes. So the sources are tagged with last-modified by who and when.

Is there any way to do it?

Thanks in advance!

locals { 
    common_var_tags = { 
        ChangedBy = data.aws_caller_identity.current.arn
        ChangedAt = timestamp() 
    } 

    common_fix_tags = { 
        Project.  = "Project" 
        Owner     = "Tiger Peng" 
        Team      = "DevOps" 
        CreatedAt = "2021-06-08" 
     } 
} 

For example, right now, I have to comment out the "local.common_var_tags" as each time when I run terraform plan or terrafomr apply without changing any attribute, the resource nginx is marked/changed due to ChangedAt = timestamp(). I’d like to find the way that only when other attributes changed, this tag changing will be applied.

resource "aws_instance" "nginx" {
  count                  = 1
  ami                    = var.nginx-ami
  instance_type          = var.nginx-instance-type
  subnet_id              = var.frontend-subnets[count.index]
  key_name               = aws_key_pair.key-pair.key_name
  vpc_security_group_ids = [aws_security_group.nginx-sg.id]

  root_block_device {
    delete_on_termination = false
    encrypted             = true
    volume_size           = var.nginx-root-volume-size
    volume_type           = var.default-ebs-type
    tags = merge(
      local.common_fix_tags,
      #local.common_var_tags,
      map(
        "Name", "${var.project}-${var.env}-nginx-${var.zones[count.index]}"
      )
    )
  }

  tags = merge(
    local.common_fix_tags,
    #local.common_var_tags,
    map(
      "Name", "${var.project}-${var.env}-nginx-${var.zones[count.index]}",
      "Role", "Nginx"
    )
  )
}

2

Answers


  1. I had the same problem and I found a workaround. It is not a clean solution but it works in some way.

    First of all, you have to create a lifecycle block on your resource and ignore changes on your "ChangedAt" tag:

    resource "aws_instance" "nginx" {
      ...
    
      lifecycle {
        ignore_changes = [tags["ChangedAt"]]
      }
    }
    

    Then create a local variable. Its value must be a md5 hash with the value of all the resource attributes whose changes should provoke and update on "ChangedAt" tag:

    locals{
      hash = md5(join(",",[var.nginx-ami,var.nginx-instance-type, etc]))
    }
    

    Finally create a null resource that triggers on the change of that local variable, with a local-exec that updates "ChangedAt" tag:

    resource "null_resource" "nginx_tags" {
      triggers = {
        instance = local.hash
      }
    
      provisioner "local-exec" {
        command = "aws resourcegroupstaggingapi tag-resources --resource-arn-list ${aws_instance.nginx.arn} --tags ChangedAt=${timestamp()}"
      }
    }
    

    With that configuration any change in the variables included in the md5 has will update your tag

    Login or Signup to reply.
  2. That’s defeating a bit the purpose of immutable infrastructure. You shouldn’t have any change between 2 successive tf apply. BUT because this is a quite common pattern when you work in K8S clusters, Terraforn AWS provider 2.6 allows you to globally ignore changes on tags

    provider "aws" {
      # ... potentially other configuration ...
    
      ignore_tags {
        # specific tag
        keys = ["ChangedAt"]
        # or by prefix to ignore ChangedBy too
        key_prefixes = ["Changed"]
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search