Provisioner "remote-exec"

Hi,
I’m having trouble with “remote-exec” provisioner . I followed documenation but for some reason “host” in “connection block” is not resolved. After the very first apply I’m getting:

null_resource.testinstance (remote-exec): Connecting to remote host via SSH...
null_resource.testinstance (remote-exec):   Host:
null_resource.testinstance (remote-exec):   User: ubuntu
null_resource.testinstance (remote-exec):   Password: false
null_resource.testinstance (remote-exec):   Private key: true
null_resource.testinstance (remote-exec):   Certificate: false
null_resource.testinstance (remote-exec):   SSH Agent: true
null_resource.testinstance (remote-exec):   Checking Host Key: false

The part of my terraform config loooks like:

resource "aws_eip" "ip-test-env" {
  instance = aws_instance.testinstance.id
  vpc      = true
  tags = {
    Name        = "test eip"
    Creator     = var.deployer
    Environment = var.environment
  }
}
resource "aws_instance" "testinstance" {
  ami                    = data.aws_ami.instance_store_ami.id
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.SSH.id, aws_security_group.PING.id]
  tags = {
    Name        = "testinstance"
    Creator     = var.deployer
    Environment = var.environment
  }
  subnet_id = aws_subnet.SUBNET1.id
  key_name  = aws_key_pair.ssh-access-key.id
}
resource "null_resource" "testinstance" {
  depends_on = [aws_eip.ip-test-env, aws_instance.testinstance]
  connection {
    type        = "ssh"
    host        = aws_instance.testinstance.public_ip
    private_key = file(var.private_key)
    user        = var.ansible_user
  }
  provisioner "remote-exec" {
    inline     = ["sudo apt-get -qq install python -y"]
    on_failure = continue
  }
}

Any ideas?

Thanks, Janusz

I might be jumping ahead, but I assume the machine is being launched in a public subnet, right? (and not in a private subnet)

other than that there could be a timing possibility?! could it be taking time to assign a public IP. (I am guessing this one)

It might help to show us the actual remote-exec resource.

Thanks @shantanugadgil @grimm26
remote-exec I shown in my first mail.
I tested two ways:

  1. I did put provisioner block inside instance resource:
resource "aws_instance" "testinstance" {
  ami                    = data.aws_ami.instance_store_ami.id
  instance_type          = "t2.micro"
  vpc_security_group_ids = [aws_security_group.SSH.id, aws_security_group.PING.id]
  subnet_id = aws_subnet.SUBNET1.id
  key_name  = aws_key_pair.ssh-access-key.id
  provisioner "remote-exec" {
    connection {
      type        = "ssh"
      host        = self.public_ip
      private_key = file(var.private_key)
      user        = var.ansible_user
      timeout = "30"
    }
    inline     = ["sudo apt-get -qq install python -y"]
    on_failure = continue
  }
}

That provisioner obviously failed because terraform initiated creating that resource before elastic IP instance which references to above one:

resource "aws_eip" "ip-test-env" {
  instance = aws_instance.testinstance.id
  vpc      = true
 }
  1. So I tried to use resource “null_resource” “testinstance” and set to depend on those instances.
resource "null_resource" "testinstance" {
  depends_on = [aws_eip.ip-test-env, aws_instance.testinstance]
  provisioner "remote-exec" {
    connection {
      type        = "ssh"
      host        = aws_instance.testinstance.public_ip
      private_key = file(var.private_key)
      user        = var.ansible_user
    }
    inline     = ["sudo apt-get -qq install python -y"]
    on_failure = continue
  }
}

But it also failing with empty Host for 5 mins even if after couple of seconds public ip was assigned.

To me is strange that “host” is required in “connection” block and in the same time is trying SSH connection with Host: null
Shouldn’t it try to check again for referenced values if null ?

And obviously when I run again: terraform apply
works well because both aws_instance and eip_instance are already provisioned

Is any work around for it?

Thanks, Janusz

Have you verified the .public_ip value is being populated. I would try to apply your configuration without the provisioner. Then launch the terraform shell locally and type “aws_instance.testinstance.public_ip”. This should output the value of the ip address if it has one.

Thanks @castironclay,
Actually I hadn’t check that with terraform console.
After apply (without provisioner):

> aws_instance.testinstance.id
  i-0af1625021e141dcb
> aws_instance.testinstance.public_ip
 /*empty result*/

>aws_eip.ip-test-env.public_ip
 XX.XX.XXX.XX
>aws_eip.ip-test-env.instance
 i-0af1625021e141dcb

So yes public_ip is missing in that instance from the tfstate
When I typed “terraform refresh” and run console again I got expected result:

>aws_instance.testinstance.public_ip
XX.XX.XXX.XX

I wonder if that expected or a bug in core/aws plugin ?
Thank you,
Janusz

No I think it’s an error in your implementation. Trying to find it though. I do basically the same thing but don’t run in to that problem. I’ll post what I use below. Hope it helps. I am using multiple modules but I think you can follow the interpolation

**main.tf**
resource "aws_instance" "host" {
  vpc_security_group_ids      = [var.aws_sg]
  associate_public_ip_address = true
  subnet_id                   = var.subnet
  ami                         = var.ami
  instance_type               = var.size
  key_name                    = aws_key_pair.host_key.key_name
  availability_zone           = var.a_zone
  depends_on                  = [aws_key_pair.host_key]
  root_block_device {
    delete_on_termination = var.delete_root_volume
  }
  tags = {
    Status = var.dev_or_prod
    Name   = var.instance_name
  }
  provisioner "remote-exec" {
    inline = ["echo 'Im alive!'"]

    connection {
      type        = "ssh"
      user        = "ubuntu"
      private_key = file("~/.ssh/id_rsa")
      host        = aws_instance.host.public_ip
    }
  }
}
1 Like

ah. You are missing one line in your aws_instance resource I think.

  associate_public_ip_address = true

If you want to ssh to the instance using the eip IP address you need to change your line in your provisioner to host = aws_eip.ip-test-env.public_ip

@castironclay , thanks very much.
yes, referrencing to aws_eip.ip-test-env.public_ip fixed the issue !!!
btw. interesting side effect when used associate_public_ip_address = true and left eip untouched:

> aws_instance.testinstance.public_ip
XX.XX.XX.XX
> aws_eip.ip-test-env.public_ip
YY.YY.YY.YY

Again, thanks for you help in fixing it !
Janusz

The default behavior is to not assign a public IP to your instance so setting it to true fixing that’s. So you could actually target the instance via either the dynamically assigned public ip or the eip.

Happy to help! Glad it worked.