0
votes

I am using the below code with terraform:

#-----Workernodes-----

resource "aws_instance" "nodes-opt-us1-k8s" {
  instance_type = "${var.k8s-node_instance_type}"
  ami           = "${var.k8s-node_ami}"
  count         = "${var.NodeCount}"

  tags {
    Name = "nodes-opt-us1-k8s"
  }

  key_name               = "${aws_key_pair.k8s-node_auth.id}"
  vpc_security_group_ids = ["${aws_security_group.opt-us1-k8s_sg.id}"]
  subnet_id              = "${aws_subnet.opt-us1-k8s.id}"

#-----Link Terraform worker nodes to Ansible playbooks-----

  provisioner "local-exec" {
    command = <<EOD
cat <<EOF > aws_worker_nodes_IP
[workers]
${aws_instance.nodes-opt-us1-k8s.*.public_ip[count.index]}
EOF
EOD
  }
}

My node count has two ec2 instances being created. Everything works with just one instance so the error has to be with count.index syntax or it missing somewhere, but unable to work through it.

But I get this error returned:

Error: aws_instance.nodes-opt-us1-k8s: connection info cannot contain splat variable referencing itself

I have asked Linux Academy mentors and they are unable to see the error without deeper looking into. I am fairly new with terraform and wanted to reach out here to see if this problem has been seen before...I have googled many options but see nothing of the like.

2

2 Answers

0
votes

You need to use the self.ATTRIBUTE syntax when using provisioners for a resource and referring to itself.

So instead your resource and provisioner should look like:

resource "aws_instance" "nodes-opt-us1-k8s" {
  instance_type = "${var.k8s-node_instance_type}"
  ami           = "${var.k8s-node_ami}"
  count         = "${var.NodeCount}"

  tags {
    Name = "nodes-opt-us1-k8s"
  }

  key_name               = "${aws_key_pair.k8s-node_auth.id}"
  vpc_security_group_ids = ["${aws_security_group.opt-us1-k8s_sg.id}"]
  subnet_id              = "${aws_subnet.opt-us1-k8s.id}"

#-----Link Terraform worker nodes to Ansible playbooks-----

  provisioner "local-exec" {
    command = <<EOD
cat <<EOF > aws_worker_nodes_IP
[workers]
${self.public_ip}
EOF
EOD
  }
}

This is also given as examples in the provisioner docs.

Note that the provisioner block above will overwrite your aws_worker_nodes_IP file on each run which will mean it will only show you the output of the last instance to be created in AWS (no guarantee on order).

If you want to append the IPs to the file you could use cat <<EOF >> aws_worker_nodes_IP to append the whole body of your heredoc each time or you might want to think about using a separate provisioner that can gather the IP addresses of all of the instances you are creating by using the null_resource pattern:

resource "aws_instance" "nodes-opt-us1-k8s" {
  instance_type = "${var.k8s-node_instance_type}"
  ami           = "${var.k8s-node_ami}"
  count         = "${var.NodeCount}"

  tags {
    Name = "nodes-opt-us1-k8s"
  }

  key_name               = "${aws_key_pair.k8s-node_auth.id}"
  vpc_security_group_ids = ["${aws_security_group.opt-us1-k8s_sg.id}"]
  subnet_id              = "${aws_subnet.opt-us1-k8s.id}"
}

resource "null_resource" "cluster" {
  # If any instance IPs change we need to change the list of IPs
  triggers {
    cluster_instance_ips = "${join(",", aws_instance.nodes-opt-us1-k8s.*.public_ip)}"
  }

  provisioner "local-exec" {
    command = <<EOD
cat <<EOF > aws_worker_nodes_IP
[workers]
${aws_instance.nodes-opt-us1-k8s.*.public_ip}
EOF
EOD
  }
}
0
votes

I can't test this myself, have you tried interpolating ${self.private_ip} ? instead of ${aws_instance.nodes-opt-us1-k8s.*.public_ip[count.index]}

Regards,