首页 > 解决方案 > Set Public IP information using remote-exec for a set of instances

问题描述

I am planning to create puppet infrastructure on AWS with a server node and agent nodes. To be able to install the puppet server and puppet agent packages, it is required to add the IP's to the hosts file on each of the nodes as below

[puppet master ip] puppetmaster puppet
[puppet client ip] puppetclient

I understand that remote-exec runs after the resource is created. But i want it to run after all the resources are created so that i can get the information about the master and client IP's together. So, i used a null resource to execute the remote-exec provisioner after the instances are created. But I am running into an issue

  1. it says This object does not have an attribute named "public_ip"

I have tried using id instead of public_ip and it complains that this object does not have an attribute named "id"

  1. I keep master IP constant and loop over only the agent IP's to be able to put them both into the /etc/hosts file for each of the instance. Is my approach correct in the remote-exec part?

here is the full code

provision_ec2.tf

resource "aws_key_pair" "puppet" {
  key_name   = "puppet"
  public_key = file("puppet.pub")
}

# Provision Puppet Server
resource "aws_instance" "puppet_instances" {
for_each = toset(local.expanded_names)
  ami             = var.ami
  instance_type   = var.instance_type
  key_name        = aws_key_pair.puppet.key_name
  security_groups = ["${aws_security_group.puppet-server.name}"] 
  
tags = {
    Name        = each.value
  } 
}

resource "null_resource" "provisioner" {
  count = "${var.total_count}"

  triggers = {
    master_ip = "${element(aws_instance.puppet_instances.*.public_ip, count.index)}"
  }

  connection {
    host        = "${element(aws_instance.puppet_instances.*.public_ip, count.index)}"
    type        = "ssh"
    user        = "ubuntu"
    private_key = file("puppet")
  }

  # set hostname
  provisioner "remote-exec" {
        inline = [
      "sudo echo ${element(aws_instance.puppet_instances.*.public_ip,0)} puppetmaster puppet>>/etc/hosts",
      "sudo echo ${element(aws_instance.puppet_instances.*.public_ip, count.index)} puppetclient>>/etc/hosts"
    ]
  }
}

locals {
  expanded_names = flatten([
    for name, count in var.host_name : [
      for i in range(count) : format("%s-%02d", name, i+1)
    ]
  ])
}

variables.tf

# Set the instances type. For puppet, choose instance with minimum 2GB RAM
variable "instance_type" {
  default = "t2.small"
}
# Set the region in which the instances will be provisioned. Default region is N.Virgina
variable "aws_region" {
  default = "us-east-1"
}
# Sepcify the AMI to be used
variable "ami" {
  default = "ami-09e67e426f25ce0d7"
}
# Set the hostnames for the instances as per the count
variable "host_name" {
  type = map(number)
  default = {
    "Puppet-Server" = 1
    "Puppet-Agent"  = 3
  }
}
variable "total_count" {
  default = 4
}

security_groups.tf

# Create Security Groups
resource "aws_security_group" "puppet-server" {
  name        = "puppet-server-SG"
  description = "Security Group for puppet master instance"

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

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

  tags = {
    Name        = "puppet-server-SG"
  }
}

I am out of ideas on how to achieve this.

标签: amazon-web-servicesterraformterraform-provider-awsterraform0.12+

解决方案


Since you are using for_each, you should use values first. So it should be:

master_ip = element(values(aws_instance.puppet_instances)[*].public_ip, count.index)

推荐阅读