amazon-web-servicesterraformamazon-lightsail

How do I force terraform to recreate a resource?


I have two resources:

resource "aws_lightsail_instance" "myserver-sig" {
  name              = "myserver-Sig"
  availability_zone = "eu-west-2a"
  blueprint_id      = "ubuntu_20_04"
  bundle_id         = "nano_2_0"
  key_pair_name     = "LightsailDefaultKeyPair"
}

and

resource "aws_lightsail_instance_public_ports" "myserver-sig-public-ports" {
  instance_name = aws_lightsail_instance.myserver-sig.name
  port_info {
    protocol  = "tcp"
    from_port = 443
    to_port   = 443
  }
  port_info {
    protocol  = "tcp"
    from_port = 80
    to_port   = 80
  }
  depends_on = [
    aws_lightsail_instance.myserver-sig,
  ]
}

When I first run terraform apply both resources are created.

If I want to replace the aws_lightsail_instance with a new version then the aws_lightsail_instance will redeploy, but the aws_lightsail_instance_public_ports will not because the ports haven't changed.

However as part of the deploy of aws_lightsail_instance it changes the public ports to close 443 and open 22. This means that the end state of the redeploy of the aws_lightsail_instance is that port 443 is closed.

If I run terraform apply again then it will correctly replace aws_lightsail_instance_public_ports opening port 443

How do I force a recreation of the aws_lightsail_instance_public_ports resource so that I only have to run terraform apply once?


Solution

  • You can use the lifecycle replace_triggered_by attribute to do this. This was introduced in Terraform 1.2.0 (released May 2022).

    In your case to trigger the replace of aws_lightsail_instance_public_ports.myserver-sig-public-ports whenever aws_lightsail_instance.myserver-sig is replaced, add the following code to the aws_lightsail_instance_public_ports.myserver-sig-public-ports configuration:

    resource "aws_lightsail_instance_public_ports" "myserver-sig-public-ports" {
      # ...
    
      lifecycle {
        replace_triggered_by = [
          aws_lightsail_instance.myserver-sig.id
        ]
      }
    }
    

    Thus, whenever the Lightsail instance is replaced, the public ports will automatically be triggered to be replaced.

    If you want to always replace the public ports, even when the Lightsail instance has not been, replaced add this configuration:

    resource "null_resource" "always_run" {
      triggers = {
        timestamp = "${timestamp()}"
      }
    }
    
    resource "aws_lightsail_instance_public_ports" "myserver-sig-public-ports" {
      # ...
    
      lifecycle {
        replace_triggered_by = [
          null_resource.always_run
        ]
      }
    }