Home > Software engineering >  remote-exec provisioner in terraform gives timeout
remote-exec provisioner in terraform gives timeout

Time:02-10

I am trying to spin up an EC2 instance using an ubuntu image. I want to provide ssh access to the instance, install and run the apache server, and open up port 80, all through terraform.

I have the following code for remote-exec for my EC2

provisioner "remote-exec" {
  inline = [
    "sudo apt update -y",
    "sudo apt upgrade -y",
    "sudo apt install apache2 -y",
    "sudo systemctl status apache2"
  ]
}

however, after all commands are executed successfully i.e. systemctl shows the correct response, my prompt hangs at aws_instance.web_server_instance: Still creating...

console output

my full code

terraform {
  required_version = "~> 1.1.5"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.74.1"
    }

    local = {
      source  = "hashicorp/local"
      version = "2.1.0"
    }

    tls = {
      source  = "hashicorp/tls"
      version = "3.1.0"
    }
  }
}

provider "aws" {
  profile = "terraform"
  region  = "us-east-1"
}

locals {
  application_name = "web_server"
}



# ssh key

resource "tls_private_key" "web_server_key_pair_gen" {
  algorithm = "RSA"
}

resource "local_file" "web_server_private_key" {
  content  = tls_private_key.web_server_key_pair_gen.private_key_pem
  filename = "${local.application_name}_private_key.pem"
}

resource "aws_key_pair" "web_server_public_key" {
  key_name   = "${local.application_name}_public_key"
  public_key = tls_private_key.web_server_key_pair_gen.public_key_openssh
}



# security group

resource "aws_security_group" "web_server_security_group" {
  name = "${local.application_name}_security_group"

  dynamic "ingress" {
    for_each = [
      { port = 22, description = "ssh" },
      { port = 80, description = "http" },
    ]
    content {
      description      = ingress.value.description
      from_port        = ingress.value.port
      to_port          = ingress.value.port
      protocol         = "tcp"
      cidr_blocks      = ["0.0.0.0/0"]
      ipv6_cidr_blocks = []
      prefix_list_ids  = []
      security_groups  = []
      self             = false
    }
  }

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

  tags = {
    Name = "${local.application_name}_security_group"
  }
}



# ami lookup

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"]
}



# ec2 instance

resource "aws_instance" "web_server_instance" {
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = "t2.micro"
  vpc_security_group_ids      = [aws_security_group.web_server_security_group.id]
  key_name                    = aws_key_pair.web_server_public_key.key_name
  associate_public_ip_address = true

  connection {
    user        = "ubuntu"
    private_key = tls_private_key.web_server_key_pair_gen.private_key_pem
    host        = self.public_ip
  }

  provisioner "local-exec" {
    command = "chmod 600 ${local_file.web_server_private_key.filename}"
  }

  provisioner "remote-exec" {
    inline = [
      "sudo apt update -y",
      "sudo apt upgrade -y",
      "sudo apt install apache2 -y",
      "sudo systemctl status apache2"
    ]
  }

  tags = {
    Name = "${local.application_name}_instance"
  }
}

output "server_public_ip" {
  value = aws_instance.web_server_instance.public_ip
}

CodePudding user response:

While you probably should follow advice given in comments, your specific case is probably due to systemctl output being piped through the pager (less), so it waits to receive q to quit.

https://man7.org/linux/man-pages/man1/systemctl.1.html:

   $SYSTEMD_PAGER
       Pager to use when --no-pager is not given; overrides $PAGER.
       If neither $SYSTEMD_PAGER nor $PAGER are set, a set of
       well-known pager implementations are tried in turn, including
       less(1) and more(1), until one is found. If no pager
       implementation is discovered no pager is invoked. Setting
       this environment variable to an empty string or the value
       "cat" is equivalent to passing --no-pager.

Using --no-pager option should help here.

  • Related