Creating more than one server with Terraform count funtion

   @derekm1215    this is the error I am getting

aws_instance.nodes-opt-us1-k8s[0]: 1 error occured:

Resource 'aws_instance.nodes-opt-us1-k8s' not found for variable 'aws_instance.nodes-opt-us1-k8s.public_ip'

here is my main.tf file shorten to error area:

#-----key pair for Workernodes-----

resource "aws_key_pair" "k8s-node_auth" {

key_name = "${var.key_name2}"

public_key = "${file(var.public_key_path2)}"

}

#-----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} <---DO I NEED MORE?

EOF

EOD

}

}

and the other files with the count variable linked:

NodeCount = "2"

variable "NodeCount" {}



When I change the count to just one in the other file it runs right, but not when I place more than one in the vars file

This did not work:



provisioner "local-exec" {

command = <<EOD

cat <<EOF > aws_worker_nodes_IP

[workers]

${aws_instance.nodes-opt-us1-k8s.public_ip[0]}

${aws_instance.nodes-opt-us1-k8s.public_ip[1]}

EOF

EOD


  • post-author-pic
    Derek M
    10-16-2018

    I'm pretty sure the syntax here:

    ${aws_instance.nodes-opt-us1-k8s.public_ip}  <---DO I NEED MORE?
    Should be more like:
    ${aws_instance.nodes-opt-us1-k8s.*.public_ip[count.index]}
    See if that helps. If not, I'd have to see more of the deployment as there are a lot of places something like that can go wrong. 

    You can also check here for my snippets to see if anything helps: 

    https://github.com/linuxacademy/content-terraform/


    https://github.com/linuxacademy/content-terraform/blob/master/course/terraform-aws/networking/main.tf

    Has some examples of count. 


    I hope this helps!

  • post-author-pic
    Chase M
    10-16-2018

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

    -----MAIN.TF


    provider "aws" {
    region = "${var.aws_region}"
    profile = "${var.aws_profile}"
    }

    #--------------------------------------------VPC-----------------------------------------------------
    resource "aws_vpc" "opt-us1-k8s" {
    cidr_block = "${var.vpc_cidr}"
    enable_dns_hostnames = true
    enable_dns_support = true

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

    #-----Internet gateway-----

    resource "aws_internet_gateway" "opt-us1-k8s_internet_gateway" {
    vpc_id = "${aws_vpc.opt-us1-k8s.id}"

    tags {
    Name = "opt-us1-k8s_igw"
    }
    }

    #-----Route table-----

    resource "aws_route_table" "opt-us1-k8s_routetable" {
    vpc_id = "${aws_vpc.opt-us1-k8s.id}"

    route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "${aws_internet_gateway.opt-us1-k8s_internet_gateway.id}"
    }

    tags {
    Name = "opt-us1-k8s_routetable"
    }
    }

    #-----Subnets-----

    resource "aws_subnet" "opt-us1-k8s" {
    vpc_id = "${aws_vpc.opt-us1-k8s.id}"
    cidr_block = "${var.cidrs["us1-k8s"]}"
    map_public_ip_on_launch = true
    availability_zone = "${data.aws_availability_zones.available.names[0]}"

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

    #-----Subnet associations to route tables-----

    resource "aws_route_table_association" "opt-us1-k8s_assoc" {
    subnet_id = "${aws_subnet.opt-us1-k8s.id}"
    route_table_id = "${aws_route_table.opt-us1-k8s_routetable.id}"
    }

    #-----Security Groups-----

    resource "aws_security_group" "opt-us1-k8s_sg" {
    name = "opt-us1-k8s_sg"
    description = "Used for access to the Kubernetes instances"
    vpc_id = "${aws_vpc.opt-us1-k8s.id}"

    #SSH

    ingress {
    from_port = 22
    to_port = 22
    protocol = "tcp"
    cidr_blocks = ["${var.localip}"]
    }

    #HTTP

    ingress {
    from_port = 80
    to_port = 80
    protocol = "tcp"
    }
    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }
    }

    #-----Public Security Group--------

    resource "aws_security_group" "api-elb-opt-us1-k8s_sg" {
    name = "api-elb-opt-us1-k8s_sg"
    description = "Used for the elastic load balancer for HTTP/HTTPS access"
    vpc_id = "${aws_vpc.opt-us1-k8s.id}"

    #HTTP

    ingress {
    from_port = 80
    to_port = 80
    protocol = "tcp"
    cidr_blocks = ["${var.localip}"]
    }

    #HTTPS

    ingress {
    from_port = 443
    to_port = 443
    protocol = "tcp"
    cidr_blocks = ["${var.localip}"]
    }

    #Outbound internet access

    egress {
    from_port = 0
    to_port = 0
    protocol = "-1"
    cidr_blocks = ["0.0.0.0/0"]
    }
    }

    #-----------------------------Kubernetes Master & Worker Node Server Creations----------------------------

    #-----key pair for Workernodes-----

    resource "aws_key_pair" "k8s-node_auth" {
    key_name = "${var.key_name2}"
    public_key = "${file(var.public_key_path2)}"
    }

    #-----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
    }
    }

    #-----key pair for Masternodes-----

    #key pair

    resource "aws_key_pair" "k8s-master_auth" {
    key_name = "${var.key_name}"
    public_key = "${file(var.public_key_path)}"
    }

    #-----Masternodes-----

    resource "aws_instance" "master-opt-us1-k8s" {
    instance_type = "${var.k8s-master_instance_type}"
    ami = "${var.k8s-master_ami}"
    count = "${var.MasterCount}"

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

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

    #-----Link Terraform Master to Ansible playbooks

    provisioner "local-exec" {
    command = <<EOD
    cat <<EOF > aws_master_node_IP
    [master]
    ${aws_instance.master-opt-us1-k8s.public_ip}
    EOF
    EOD
    }
    }

    Variables.tf


    variable "aws_region" {}

    variable "aws_profile" {}

    data "aws_availability_zones" "available" {}

    variable "vpc_cidr" {}

    variable "cidrs" {
    type = "map"
    }

    variable "localip" {}

    variable "domain_name" {}

    variable "k8s-master_instance_type" {}

    variable "k8s-master_ami" {}

    variable "k8s-node_instance_type" {}

    variable "k8s-node_ami" {}

    variable "public_key_path" {}

    variable "key_name" {}

    variable "public_key_path2" {}

    variable "key_name2" {}

    variable "MasterCount" {}

    variable "NodeCount" {}

    Terraform.tfvars


    aws_profile = "Terraform"
    aws_region = "us-east-1"
    vpc_cidr = "172.41.0.0/16"
    cidrs = {
    us1-k8s = "172.41.32.0/19"
    }

    localip = "0.0.0.0/0"
    domain_name = "tangoe"

    k8s-master_instance_type = "m4.xlarge"
    k8s-master_ami = "ami-0ac019f4fcb7cb7e6"

    k8s-node_instance_type = "m4.xlarge"
    k8s-node_ami = "ami-0ac019f4fcb7cb7e6"

    public_key_path = "/root/.ssh/xxxxxx.pub"
    key_name = "Kubernetes"

    public_key_path2 = "/root/.ssh/xxxxxxx.pub"
    key_name2 = "Kubernetes2"

    MasterCount = "1"
    NodeCount = "2"


  • post-author-pic
    Chase M
    10-16-2018

     @derekm1215  when I remove the provisioner code, it works fine I might add.

  • post-author-pic
    Derek M
    10-17-2018

    Hmmm, I'm really not sure. Sometimes,  these issues take a good bit of troubleshooting to find the culprit. My code worked properly, so perhaps take a look at that and work backwards from there. There's a lot here to go over, I'll try to take a more indepth look to see, but hopefully someone in the community has encountered this. I think Terraform has had several revisions since my course, so things may have changed a bit. If 0.12 would hurry up and get released, a lot of this stuff will be a thing of the past thanks to the improvements in looping. 

  • post-author-pic
    Chase M
    10-19-2018

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

  • post-author-pic
    Chase M
    10-19-2018

     @derekm1215 

  • post-author-pic
    Chase M
    10-22-2018

    Like so....

    provisioner "local-exec" {

    command = <<EOD

    cat <<EOF >> aws_worker_nodes_IP

    [workers]

    ${self.public_ip}

    EOF

    EOD

    }

    }  

Looking For Team Training?

Learn More