Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

terraform: how do you make a resource idempotent - i.e. create if not exists but do nothing if it does exist

Tags:

terraform

I have a bit of sample code that:

  1. creates an EC2 instance
  2. creates and adds my public key

but I'd like it to be idempotent. i.e. if the key exists then it will still run and not fail with an error.

Not sure how to do that. Any suggestions?

Sample code:

provider "aws" {
  region = "eu-west-1"
}

module ec2 {
  source = "./ec2_instance"
  name = "EC2 Instance"
} 

resource "aws_key_pair" "my_key" {
  key_name   = "my_key"
  public_key = "<string>"
}

and it's aws_key_pair.my_key that I'm trying to make idempotent.

At the moment I get errors like:

Error: Error applying plan:

1 error(s) occurred:

* aws_key_pair.my_key: 1 error(s) occurred:

* aws_key_pair.my_key: Error import KeyPair: InvalidKeyPair.Duplicate: The keypair 'my_key' already exists.
    status code: 400, request id: <request id>
like image 233
Snowcrash Avatar asked Jul 24 '18 10:07

Snowcrash


2 Answers

This is exactly the behaviour of Terraform as long as all the resources in the provider have been created by or are managed by Terraform.

If you have a blank AWS account and apply Terraform against the code in the question then it will create an AWS key pair and whatever is included in your ec2 module.

If you then run a plan after this it will show no changes.

Where this falls down is where the AWS API only allows a single version of a resource by something that is configurable and it already exists outside of what Terraform knows. This applies to the AWS key pair where each AWS account/region combination can only have a single key pair named by the same thing.

At this point you have two options: you can make Terraform manage the AWS key pair directly or you can simply refer to it with a data source instead of trying to create a new one.

To make Terraform manage the AWS key pair you can import it by running:

terraform import aws_key_pair.my_key my_key

If instead you just want to refer to it you could normally use a data source but in this case it would be unnecessary (and as such there is no aws_key_pair data source) as you simply refer to the key pair by name such as in this example:

resource "aws_instance" "web" {
  ami           = "am-123456"
  instance_type = "t2.micro"
  key_pair      = "my_key"
}
like image 149
ydaetskcoR Avatar answered Oct 05 '22 12:10

ydaetskcoR


Looks like you need to import the existing my_key keypair in to your terraform state. Once you import the resource, terraform will not try to create the keypair that exists.

terraform import aws_key_pair.my_key my_key

https://www.terraform.io/docs/import/index.html

like image 20
manojlds Avatar answered Oct 05 '22 11:10

manojlds