hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.62k stars 4.66k forks source link

Host is empty in the remote-exec provision part #3927

Closed immae1 closed 5 years ago

immae1 commented 5 years ago

Community Note

Terraform (and AzureRM Provider) Version

Terraform v0.12.5 provider "azurerm" { version = "1.31.0" }

Affected Resource(s)

Terraform Configuration Files


variable "admin_username" {
    default = "thisisausernamemyfriend"
}
variable "admin_password" {
    default = "**************"
}

# Configure the Microsoft Azure Provider.
provider "azurerm" {
    version = "1.31.0"
}

# Create a resource group
resource "azurerm_resource_group" "iha-TF-Cloudacademy" {
    name     = "ihaTFResourceGroup" #TODO change!
    location = "westeurope"
}
# Create virtual network
resource "azurerm_virtual_network" "vnet" {
    name                = "ihaTFVnet"
    address_space       = ["10.0.0.0/16"]
    location            = "westeurope"
    resource_group_name = "${azurerm_resource_group.iha-TF-Cloudacademy.name}"
}

# Create subnet
resource "azurerm_subnet" "subnet" {
    name                 = "myTFSubnet"
    resource_group_name  = "${azurerm_resource_group.iha-TF-Cloudacademy.name}"
    virtual_network_name = "${azurerm_virtual_network.vnet.name}"
    address_prefix       = "10.0.1.0/24"
}

# Create public IP
resource "azurerm_public_ip" "publicip" {
    name                         = "ihaTFPublicIP"
    location                     = "westeurope"
    resource_group_name          = "${azurerm_resource_group.iha-TF-Cloudacademy.name}"
    allocation_method            = "Dynamic"
}

# Create Network Security Group and rule
resource "azurerm_network_security_group" "iha-Cloudacdamey-nsg" {
    name                = "ihaTFNSG"
    location            = "westeurope"
    resource_group_name = "${azurerm_resource_group.iha-TF-Cloudacademy.name}"

    security_rule {
        name                       = "SSH"
        priority                   = 1001
        direction                  = "Inbound"
        access                     = "Allow"
        protocol                   = "Tcp"
        source_port_range          = "*"
        destination_port_range     = "22"
        source_address_prefix      = "*"
        destination_address_prefix = "*"
    }
}

# Create network interface
resource "azurerm_network_interface" "nic" {
    name                      = "ihaNIC"
    location                  = "westeurope"
    resource_group_name       = "${azurerm_resource_group.iha-TF-Cloudacademy.name}"
    network_security_group_id = "${azurerm_network_security_group.iha-Cloudacdamey-nsg.id}"

    ip_configuration {
        name                          = "ihaNICConfg"
        subnet_id                     = "${azurerm_subnet.subnet.id}"
        private_ip_address_allocation = "Dynamic"
        public_ip_address_id          = "${azurerm_public_ip.publicip.id}"
    }
}

# Create a Linux virtual machine
resource "azurerm_virtual_machine" "vm" {
    name                  = "ihaTFVM"
    location              = "westeurope"
    resource_group_name   = "${azurerm_resource_group.iha-TF-Cloudacademy.name}"
    network_interface_ids = ["${azurerm_network_interface.nic.id}"]
    vm_size               = "Standard_DS1_v2"

    storage_os_disk {
        name              = "myOsDisk"
        caching           = "ReadWrite"
        create_option     = "FromImage"
        managed_disk_type = "Premium_LRS"
    }

    storage_image_reference {
        publisher = "Canonical"
        offer     = "UbuntuServer"
        sku       = "18.04-LTS"
        version   = "latest"
    }

    os_profile {
        computer_name  = "ihaTFVM"
    admin_username = "${var.admin_username}"
        admin_password = "${var.admin_password}"

    }

    os_profile_linux_config {
        disable_password_authentication = false
    }
  # Here you can see how terraform is able to provision a instance

    provisioner "remote-exec" {
    # Install Python for Ansible
    inline = ["while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done; sudo rm /var/lib/apt/lists/* ; sudo apt-get update ; sudo apt-get install -y python python-pip "]
    connection {
      user     = "${var.admin_username}"
      password = "${var.admin_password}"
      host = "${azurerm_public_ip.publicip.ip_address}"
    }
  }

  # Here we run provision from local disc to VM-instance with the help of Ansible
    provisioner "local-exec" {
      #we dont want host-key-check because we don't knew the assigned eip
    command = "ANSIBLE_HOST_KEY_CHECKING=False Ansible-playbook -u ${var.admin_username} -i '${azurerm_public_ip.publicip.ip_address}' -T 300 ../provision/playbook.yml"
    }

}

   data "azurerm_public_ip" "test" {
       name                = "${azurerm_public_ip.publicip.name}"
       resource_group_name = "${azurerm_virtual_machine.vm.resource_group_name}"
   }
   output "public_ip_address" {
       value = "${data.azurerm_public_ip.test.ip_address}"
   }

Debug Output

azurerm_virtual_machine.vm (remote-exec): Connecting to remote host via SSH...
azurerm_virtual_machine.vm (remote-exec):   Host:       <<--- this is empty! 
azurerm_virtual_machine.vm (remote-exec):   User: thisisausernamemyfriend
azurerm_virtual_machine.vm (remote-exec):   Password: true
azurerm_virtual_machine.vm (remote-exec):   Private key: false
azurerm_virtual_machine.vm (remote-exec):   Certificate: false
azurerm_virtual_machine.vm (remote-exec):   SSH Agent: false
azurerm_virtual_machine.vm (remote-exec):   Checking Host Key: false

-snip-

Error: timeout - last error: dial tcp :22: connectex: No connection could be made because the target machine actively refused it.

Panic Output


Expected Behavior

host = "${azurerm_public_ip.publicip.ip_address}" should have an ip-address for connecting to the generated vm.

Actual Behavior

The host is empty - so no connection could established to the new vm. The funny thing is - if i comment the provision part. i get an ip-address outputed to the cli.

Steps to Reproduce

  1. terraform apply

Important Factoids


References

rukawata commented 5 years ago

Same issue here. Even add explicit depends_on won't change the behavior.

eesprit commented 5 years ago

Same issue there, I found several workaround (like using a null_resource + data to get the IP and do the provision step in another block) but that just looks wrong and is not intuitive at all. Morever, I am actually hitting this issue as I am going through the Terraform Azure Getting start guide (https://learn.hashicorp.com/terraform/azure/provision_az). So if it is not the way it works actually, it should be updated.

By the way, examples (https://github.com/terraform-providers/terraform-provider-azurerm/blob/master/examples/virtual-machines/provisioners/linux/main.tf) are wrong to, because they don't define an host value on the connection, and when doing so, Terrafor will fail because host is not defined. The Azure Getting Start guide is also wrong on that subject (no host is defined).

tombuildsstuff commented 5 years ago

hi @immae1 @rukawata @eesprit

Thanks for opening this issue.

Taking a look at the example configuration posted above - unfortunately Azure doesn't assign an IP Address to Dynamic Public IP Addresses until they're attached to a booted device (in this case a Virtual Machine), which is why this value is empty from the azurerm_public_ip Data Source. Instead you should be able to use the null_resource to retrieve the IP Address using the Data Source once the Virtual Machine has booted, for example:

resource "azurerm_public_ip" "test" { ... }
resource "azurerm_virtual_machine" "test" { ... }

data "azurerm_public_ip" "test" {
  name                = "${azurerm_public_ip.test.name}"
  resource_group_name = "${azurerm_virtual_machine.test.resource_group_name}"
}

resource "null_resource" "ansible" {
  provisioner "remote-exec" {
    # Install Python for Ansible
    inline = ["while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done; sudo rm /var/lib/apt/lists/* ; sudo apt-get update ; sudo apt-get install -y python python-pip "]
    connection {
      user     = "${var.admin_username}"
      password = "${var.admin_password}"
      host = "${data.azurerm_public_ip.test.ip_address}" # <-- note here we're using the Data Source rather than the Resource for a Public IP
    }
  }
}

Would you be able to take a look and see if that works for you?

This forum is intended to be used for feature enhancements and bugs in the Azure Provider - so that we can keep this forum focused on that we instead ask that broader questions are raised using one of the Community Resources. As such I'm going to close this issue for the moment, but if that doesn't work for you I believe you should be able to get an answer for this using one of the Community Resources.

Thanks!

ghost commented 5 years ago

I'm going to lock this issue because it has been closed for 30 days ā³. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. If you feel I made an error šŸ¤– šŸ™‰ , please reach out to my human friends šŸ‘‰ hashibot-feedback@hashicorp.com. Thanks!