Adding an EIP to an existing resource does not cause other aws terraform resources to appropriately update to reflect this change.
If I add an aws_eip to an existing ec2 instance and that instance has a corresponding route53 cname that uses the ec2 public_dns it will NOT update those route53 entries till a subsequent apply is performed.
Particularly nasty bug since unless you have the sense to run "terraform plan" again after doing a successful apply you wouldn't be aware of the fact that your r53 entries are now borked. :(
Thanks for the report @rbowlby – do you possibly have an example config that demonstrates this? I'd like to try it out and work on a patch.
Thanks!
Encountered same thing. Example config taking from the Getting Started pages, I added this from http://www.terraform.io/intro/getting-started/dependencies.html:
resource "aws_eip" "ip" {
instance = "${aws_instance.example.id}"
}
then went on to http://www.terraform.io/intro/getting-started/provision.html and added this:
resource "aws_instance" "example" {
ami = "ami-aa7ab6c2"
instance_type = "t1.micro"
provisioner "local-exec" {
command = "echo ${aws_instance.example.public_ip} > file.txt"
}
}
after running terraform destroy and then terraform apply the output in file.txt does not contain the correct public ip
the output in file.txt does not contain the correct public ip
I also encountered this when I first walked through the provisioning page of the getting started guide.
bwestover$ terraform show
aws_eip.ip:
...
public_ip = 52.71.80.96 <---*** The elastic IP that was assigned
aws_instance.example:
...
public_ip = 52.71.80.96 <---*** Also shows up as the public_ip of the instance
...
bwestover$ cat file.txt
54.88.60.48 <--The file created by my provisioner has this OTHER ip in it
My config is right out of the getting started guide.
example.tf:
provider "aws" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
region = "${var.region}"
}
resource "aws_instance" "example" {
ami = "${lookup(var.amis, var.region)}"
instance_type = "t2.micro"
provisioner "local-exec" {
command = "echo ${aws_instance.example.public_ip} > file.txt"
}
}
resource "aws_eip" "ip" {
instance = "${aws_instance.example.id}"
}
variables.tf:
variable "access_key" {}
variable "secret_key" {}
variable "region" {
default = "us-east-1"
}
variable "amis" {
default = {
us-east-1 = "ami-8eb061e6"
us-west-2 = "ami-ef5e24df"
}
}
I can run terraform destroy and then terraform apply and this will reproduce every time.
It seems to me that since there is a dependency on the instance being created before the eip, the provisioner is running before the elastic IP is being applied. This means I get the public ip that is initially assigned in my file.txt and then it is changed to the EIP in the last step.
Another interesting thing is that this workflow:
1) terraform destroy
2) terraform apply
3) terraform show
... will produce an IP in file.txt that matches the public IP on the instance. That IP will NOT match the elastic IP from terraform show or the actual IP on the instance.
However this workflow:
1) terraform destroy
2) terraform apply
3) terraform plan
4) terraform show
...will produce an IP in file.txt that doesn't match the public IP on the instance OR the elastic IP.
_Note_: The output shown above is from this second workflow.
I think step 3 in the second workflow is getting the ACTUAL final state of the resources. Skipping that step in the first workflow returns an ephemeral state that existed while the instance was building (and also the state where the provisioner ran).
This seems like it could lead some surprises.
To get the provisioner to output the correct IP address, I added the provisioner to the aws_eip resource instead of the aws_instance:
resource "aws_eip" "ip" {
instance = "${aws_instance.sshgateway.id}"
vpc = true
provisioner "local-exec" {
command = "echo ${aws_eip.ip.public_ip} > inventory"
}
}
I encountered the same problem as originally posted.
To reproduce:
aws_instanceaws_eipaws_instance.my_instance.public_dnspublic_dnspublic_dnsLooking to add an EIP to an instance and the problem appears to be that the EIP trigger things like aws_route53_record to realize that public_dns will change, so they precompute values based on their current state, ultimately resulting in an incorrect value. I'm guessing during initial apply the public_dns also gets pulled before waiting for the EIP to fully attach to the instance.
+ aws_eip.eip
allocation_id: "<computed>"
association_id: "<computed>"
domain: "<computed>"
instance: "i-397a302f"
network_interface: "<computed>"
private_ip: "<computed>"
public_ip: "<computed>"
vpc: "true"
~ aws_route53_record.http-proxy-cname
records.2502117172: "ec2-52-45-24-144.compute-1.amazonaws.com" => ""
records.3398562927: "" => "ec2-54-161-157-54.compute-1.amazonaws.com"
The current public_dns of i-397a302f is ec2-54-161-157-54.compute-1.amazonaws.com, however once the EIP has been added this value will change.
I’ve encountered this issue as well, though in the case of creating a bastion host in a module, then attempting to use that host as the bastion for my other instances:
# bastion.tf
resource "aws_eip" "bastion_eip" {
vpc = true
instance = "${aws_instance.bastion.id}"
associate_with_private_ip = "${aws_instance.bastion.private_ip}"
}
resource "aws_instance" "bastion" {
ami = "${var.current_ami}"
instance_type = "t2.small"
key_name = "${var.key_pair_id}"
subnet_id = "${aws_subnet.public.0.id}"
source_dest_check = false
associate_public_ip_address = true
vpc_security_group_ids = [
"${aws_security_group.default.id}",
"${aws_security_group.bastion.id}",
]
tags {
Name = "${var.env}-bastion"
Env = "${var.env}"
}
}
output "bastion_public_ip" {
value = "${aws_eip.bastion_eip.public_ip}"
}
# api.tf
resource "aws_instance" "api" {
count = "${var.instance_count}"
provisioner "chef" {
node_name = "${var.env}-api-${count.index}"
environment = "${var.env}"
run_list = ["ds_base", "ds_api"]
secret_key = "${file("~/.chef/ds_encrypted_data_bag_secret")}"
server_url = "https://api.chef.io/organizations/darksky"
user_name = "${var.user_name}"
user_key = "${file(var.user_key)}"
recreate_client = true
connection {
user = "ubuntu"
private_key = "${file("~/.ssh/ds_aws_dev")}"
bastion_host = "${data.terraform_remote_state.vpc.bastion_public_ip}"
}
}
ami = "${var.current_ami}"
instance_type = "${var.instance_type}"
key_name = "${var.key_pair_id}"
subnet_id = "${data.terraform_remote_state.vpc.private_subnet_ids.0}"
}
any better luck here?
I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
Most helpful comment
I encountered the same problem as originally posted.
To reproduce:
aws_instanceaws_eipaws_instance.my_instance.public_dnspublic_dnspublic_dns