Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will resources definition moving to a different module make 'terraform apply' to delete and recreate these resources?

Tags:

terraform

I have created some VMs with a main.tf, and terraform generates a cluster.tfstate file.

Now because of refactoring, I move the VM resource definitions into a module, and refer to this module in main.tf. When I run terraform apply --state=./cluster.tfstate, will terraform destroy and recreate these VMs?

I would expect it will not. Is my understanding correct?

like image 968
Jun Avatar asked Apr 03 '18 09:04

Jun


People also ask

Does Terraform recreate resources?

During planning, by default Terraform retrieves the latest state of each existing object and compares it with the current configuration, planning actions only against objects whose current state does not match the configuration.

Does Terraform apply delete resource?

Terraform works to keep the resources on the server in sync with what's in your configuration. If you delete a resource, it will be removed on the next apply.

Does Terraform recreate resource every time?

my_meta_data, Terraform picks it up as a value change on the description field, which forcefully destroys and then recreates the development-workstation resource.

Is the Terraform destroy command the only way to destroy resources?

Currently, there is no way to specify the resources NOT to be destroyed using Terraform.


1 Answers

Let's try this using the example given in the aws_instance documentation:

# Create a new instance of the latest Ubuntu 14.04 on an
# t2.micro node with an AWS Tag naming it "HelloWorld"
provider "aws" {
  region = "us-west-2"
}

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
  ami           = "${data.aws_ami.ubuntu.id}"
  instance_type = "t2.micro"

  tags {
    Name = "HelloWorld"
  }
}

If we terraform apply this, we get an instance that is referenced within Terraform as aws_instance.web:

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

If we move this definition to a module ubuntu_instance, the directory structure might look like this with the above code in instance.tf:

.
├── main.tf
└── ubuntu_instance
    └── instance.tf

Now you intend to create the same instance as before, but internally Terraform now names this resource module.ubuntu_instance.aws_instance.web

If you attempt to apply this, you would get the following:

Plan: 1 to add, 0 to change, 1 to destroy.

The reason this happens is that Terraform has no idea that the old and new code reference the same instance. When you refactor in a module, you are removing a resource, and thus Terraform deletes that resource.

Terraform maps your code to real resources in the state file. When you create an instance, you can only know that instance maps to your aws_instance because of the state file. So the proper way (as mentioned by Jun) is to refactor your code, then tell Terraform to move the mapping to the real instance from aws_instance.web to module.ubuntu_instance.aws_instance.web Then when you apply, Terraform will leave the instance alone because it matches what your code says. The article Jun linked to is a good discussion of this.

like image 193
Eric M. Johnson Avatar answered Jan 03 '23 15:01

Eric M. Johnson