skip to Main Content

I keep getting error "host for provisioner cannot be empty"

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region  = var.region
  profile = "whatsnxt"
}

resource "tls_private_key" "rsa_4096" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

#  create key pair for connecting to EC2 via SSH
resource "aws_key_pair" "key_pair" {
  key_name   = var.key_pair_name
  public_key = tls_private_key.rsa_4096.public_key_openssh
}

resource "local_file" "private_key" {
  content  = tls_private_key.rsa_4096.private_key_openssh
  filename = pathexpand("~/.ssh/${var.private_key}")

  provisioner "local-exec" {
    command = "chmod 400 ${self.filename}"
  }
}

# update docker image when var.image_version changes
resource "null_resource" "image_updater" {
  depends_on = [ null_resource.node_provisioner, module.ec2_instance ]
  triggers = {
    image_version = var.image_version
  }

  connection {
    host = module.ec2_instance.public_ip
    user = "ec2-user"
    type = "ssh"
    private_key = local_file.private_key.content
  }

  provisioner "file" {
    source      = "run-image.sh"
    destination = "run-image.sh"
  }
  provisioner "file" {
    source      = "../.env"
    destination = ".env"
  }  
  provisioner "remote-exec" {
    inline = [
      "chmod +x run-image.sh",
      "./run-image.sh ${var.image_version}"
    ]
  }
}

module "ec2_instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"

  ami                    = var.ami
  name                   = var.instance_name
  instance_type          = var.instance_type
  key_name               = aws_key_pair.key_pair.key_name
  monitoring             = true
  subnet_id              = aws_subnet.blog_public_subnet.id
  vpc_security_group_ids = [aws_security_group.blogSG.id]
  user_data = <<-EOF
                    #!/bin/bash -xe
                    sudo yum update -y
                    sudo yum install docker -y
                    sudo systemctl enable docker.service
                    sudo systemctl start docker.service
                    sleep 15
                  EOF  

  tags = {
    Terraform   = "true"
    Environment = "dev"
    Name        = var.instance_name
  }

}

resource "null_resource" "node_provisioner" {
  depends_on = [ module.ec2_instance ]
  
  triggers = {
    instance_id = module.ec2_instance.id
  }

  connection {
    host = module.ec2_instance.public_ip
    user = "ec2-user"
    type = "ssh"
    private_key = local_file.private_key.content
  }

  provisioner "file" {
    source      = ".credentials"
    destination = "credentials"
  }

  provisioner "remote-exec" {
    inline = [
      "mkdir -p .aws",
      "mv credentials .aws/credentials"
    ]
  }

}
# resource "aws_default_vpc" "default" {
#   tags = {
#     Name = "Default blog webserver VPC"
#   }
# }

resource "aws_vpc" "blog_vpc" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "Custom Blog VPC"
  }
}

resource "aws_subnet" "blog_public_subnet" {
  vpc_id            = aws_vpc.blog_vpc.id
  cidr_block        = "10.0.1.0/24"
  availability_zone = var.availability_zone

  tags = {
    Name = "Blog Public Subnet"
  }
}

resource "aws_subnet" "blog_private_subnet" {
  vpc_id            = aws_vpc.blog_vpc.id
  cidr_block        = "10.0.2.0/24"
  availability_zone = var.availability_zone

  tags = {
    Name = "Blog Private Subnet"
  }
}

resource "aws_internet_gateway" "blog_ig" {
  vpc_id = aws_vpc.blog_vpc.id

  tags = {
    Name = "Blog Internet Gateway"
  }
}

resource "aws_route_table" "public_rt" {
  vpc_id = aws_vpc.blog_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.blog_ig.id
  }

  route {
    ipv6_cidr_block = "::/0"
    gateway_id      = aws_internet_gateway.blog_ig.id
  }

  tags = {
    Name = "Public Route Table"
  }
}

resource "aws_route_table_association" "public_1_rt_a" {
  subnet_id      = aws_subnet.blog_public_subnet.id
  route_table_id = aws_route_table.public_rt.id
}

resource "aws_security_group" "blogSG" {
  name        = "Blog Webserver SG"
  description = "Blog Webserver Security Group"
  vpc_id      = aws_vpc.blog_vpc.id

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

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

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

}

2

Answers


  1. In

    resource "null_resource" "image_updater" {
    

    you have set

    connection {
      host = module.ec2_instance.public_ip
    

    but in the actual ec2 instance you don’t create a public IP. Either use module.ec2_instance.private_ip instead or in the ec2 instance associate a public IP with the "associate_public_ip_address" parameter

    Login or Signup to reply.
  2. In order to have a public IP attached to an instance, you have to specify it when calling the module:

    module "ec2_instance" {
      source  = "terraform-aws-modules/ec2-instance/aws"
    
      ami                         = var.ami
      name                        = var.instance_name
      instance_type               = var.instance_type
      key_name                    = aws_key_pair.key_pair.key_name
      monitoring                  = true
      subnet_id                   = aws_subnet.blog_public_subnet.id
      vpc_security_group_ids      = [aws_security_group.blogSG.id]
      associate_public_ip_address = true # <---- add this line
      user_data = <<-EOF
                        #!/bin/bash -xe
                        sudo yum update -y
                        sudo yum install docker -y
                        sudo systemctl enable docker.service
                        sudo systemctl start docker.service
                        sleep 15
                      EOF  
    
      tags = {
        Terraform   = "true"
        Environment = "dev"
        Name        = var.instance_name
      }
    
    }
    

    By adding associate_public_ip_address = true, the module will produce the requested output which you can then reference in the host argument.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search