【问题标题】:Error: host for provisioner cannot be empty错误:provisioner 的主机不能为空
【发布时间】:2022-03-01 15:16:57
【问题描述】:

我正在处理 main.tf 文件,用于在 azure 中创建具有远程执行功能的虚拟机,并且我想在此文件中创建和下载 SSH 密钥 .pem 文件以访问 Linux VM。

主要。 tf文件

# Configure the Microsoft Azure Provider
terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "~>2.0"
    }
  }
}
provider "azurerm" {
  features {}
  subscription_id = var.subscription_id
  client_id       = var.client_id
  client_secret   = var.client_secret
  tenant_id =       var.tenant_id
 
}
# Create a resource group if it doesn't exist
resource "azurerm_resource_group" "myterraformgroup" {
    name     = var.resource_group
    location = var.resource_group_location

    tags = {
        environment = "Terraform Demo"
    }
}
# Create virtual network
resource "azurerm_virtual_network" "myterraformnetwork" {
    name                = "myVnet"
    address_space       = ["10.0.0.0/16"]
    location            = "eastus"
    resource_group_name = azurerm_resource_group.myterraformgroup.name

    tags = {
        environment = "Terraform Demo"
    }
}

# Create subnet
resource "azurerm_subnet" "myterraformsubnet" {
    name                 = "mySubnet"
    resource_group_name  = azurerm_resource_group.myterraformgroup.name
    virtual_network_name = azurerm_virtual_network.myterraformnetwork.name
    address_prefixes       = ["10.0.1.0/24"]
}

# Create public IPs
resource "azurerm_public_ip" "myterraformpublicip" {
    name                         = "myPublicIP"
    location                     = "eastus"
    resource_group_name          = azurerm_resource_group.myterraformgroup.name
    allocation_method            = "Dynamic"

    tags = {
        environment = "Terraform Demo"
    }
}

# Create Network Security Group and rule
resource "azurerm_network_security_group" "myterraformnsg" {
    name                = "myNetworkSecurityGroup"
    location            = "eastus"
    resource_group_name = azurerm_resource_group.myterraformgroup.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 = "*"
    }

    tags = {
        environment = "Terraform Demo"
    }
}

# Create network interface
resource "azurerm_network_interface" "myterraformnic" {
    name                      = "myNIC"
    location                  = "eastus"
    resource_group_name       = azurerm_resource_group.myterraformgroup.name

    ip_configuration {
        name                          = "myNicConfiguration"
        subnet_id                     = azurerm_subnet.myterraformsubnet.id
        private_ip_address_allocation = "Dynamic"
        public_ip_address_id          = azurerm_public_ip.myterraformpublicip.id
    }

    tags = {
        environment = "Terraform Demo"
    }
}

# Connect the security group to the network interface
resource "azurerm_network_interface_security_group_association" "example" {
    network_interface_id      = azurerm_network_interface.myterraformnic.id
    network_security_group_id = azurerm_network_security_group.myterraformnsg.id
}

# Generate random text for a unique storage account name
resource "random_id" "randomId" {
    keepers = {
        # Generate a new ID only when a new resource group is defined
        resource_group = azurerm_resource_group.myterraformgroup.name
    }

    byte_length = 8
}

# Create storage account for boot diagnostics
resource "azurerm_storage_account" "mystorageaccount" {
    name                        = "diag${random_id.randomId.hex}"
    resource_group_name         = azurerm_resource_group.myterraformgroup.name
    location                    = "eastus"
    account_tier                = "Standard"
    account_replication_type    = "LRS"

    tags = {
        environment = "Terraform Demo"
    }
}
# Create (and display) an SSH key
resource "tls_private_key" "example_ssh" {
  algorithm = "RSA"
  rsa_bits = 2048
    }
    output "tls_private_key" { 
    value = tls_private_key.example_ssh.private_key_pem 
    sensitive = true
}

# Create virtual machine
resource "azurerm_linux_virtual_machine" "myterraformvm" {
    name                  = "myVM"
    location              = "eastus"
    resource_group_name   = azurerm_resource_group.myterraformgroup.name
    network_interface_ids = [azurerm_network_interface.myterraformnic.id]
    size                  = "Standard_DS1_v2"

    os_disk {
        name              = "myOsDisk"
        caching           = "ReadWrite"
        storage_account_type = "Premium_LRS"
    }

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

    computer_name  = "myvm"
    admin_username = "azureuser"
    disable_password_authentication = true

    admin_ssh_key {
    username = "azureuser"
    public_key     = tls_private_key.example_ssh.public_key_openssh
    }

    boot_diagnostics {
        storage_account_uri = azurerm_storage_account.mystorageaccount.primary_blob_endpoint
    }

    tags = {
        environment = "Terraform Demo"
    }
}
resource "null_resource" "execute" {
connection {
    type        =   "ssh"
    agent       =   false
    user        =   "azureuser"
    host        =   azurerm_public_ip.myterraformpublicip.ip_address
    private_key =   tls_private_key.example_ssh.private_key_pem
}
provisioner "file" {
  source    =   "./config"
  destination   =   "~/"
}
provisioner "remote-exec" {
 inline     = [
   "chmod 755 ~/scripts/*",
   "sudo sh ~/scripts/foreman_prerequisite_config.sh",
   ]
}
depends_on = [azurerm_linux_virtual_machine.myterraformvm]
}

使用命令 terraform apply时遇到以下错误

[0m[1mnull_resource.execute: Provisioning with 'file'...[0m[0m
[31m╷[0m[0m
[31m│[0m [0m[1m[31mError: [0m[0m[1mfile provisioner error[0m
[31m│[0m [0m
[31m│[0m [0m[0m  with null_resource.execute,
[31m│[0m [0m  on main.tf line 184, in resource "null_resource" "execute":
[31m│[0m [0m 184: provisioner "file" [4m{[0m[0m
[31m│[0m [0m
[31m│[0m [0mhost for provisioner cannot be empty

请帮我解决这个问题。提前致谢!

【问题讨论】:

  • 我在文档中看到的只是有一条注释说公共 IP 地址资源是动态的,并且它的属性在连接到 NIC 之前不可用。即使我看到您将其附加到 NIC 并将该 NIC 附加到 VM,我仍会尝试使用数据源:registry.terraform.io/providers/hashicorp/azurerm/latest/docs/…。
  • 感谢您的回复。我需要根据您的参考链接更改代码中的任何内容吗?另外,如果你能帮我弄清楚就好了。

标签: linux azure terraform terraform-provider-azure terraform-template-file


【解决方案1】:

根据Azure提供者文档[1],当公共IP分配类型为Dynamic时,应使用data源获取IP地址:

data "azurerm_public_ip" "myterraformpublicip" {
  name                = azurerm_public_ip.myterraformpublicip.name
  resource_group_name = azurerm_linux_virtual_machine.myterraformvm.resource_group_name
}

然后,在null_resource 的host 参数中,您应该设置以下内容:

host = data.azurerm_public_ip.myterraformpublicip.ip_address

但是,这可能无法解决您遇到的问题,因为此版本的适用于 Linux VM 的 Azure 提供程序 [2] 似乎存在问题:

在此版本中存在一个已知问题,即动态公共 IP 的 public_ip_address 和 public_ip_addresses 字段可能没有完全填充。

问题的第二部分与生成 SSH 密钥有关,以后可以使用该密钥访问虚拟机。在您的问题中,您有以下代码:

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

output "tls_private_key" { 
    value = tls_private_key.example_ssh.private_key_pem 
    sensitive = true
}

根据您在 cmets [3] 中链接的答案,不需要 output。这可用于在同一目录中创建私钥:

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

resource "local_file" "private_key_file" {
  content  = tls_private_key.example_ssh.private_key_pem
  filename = "${path.root}/private-key.pem"
}

然后,在null_resource 中,您应该添加以下内容:

resource "null_resource" "execute" {
  connection {
    type        =   "ssh"
    agent       =   false
    user        =   "azureuser"
    host        =   data.azurerm_public_ip.myterraformpublicip.ip_address
    private_key =   "${path.root}/private-key.pem"
  }

  provisioner "file" {
    source      =  "./config"
    destination =  "~/"
  }

  provisioner "remote-exec" {
   inline     = [
     "chmod 755 ~/scripts/*",
     "sudo sh ~/scripts/foreman_prerequisite_config.sh",
   ]
  }
}
depends_on = [azurerm_linux_virtual_machine.myterraformvm]
}

请注意,您可能不应该将 tls_private_key 资源用于生产环境 [4]:

此资源生成的私钥将不加密地存储在您的 Terraform 状态文件中。不建议将此资源用于生产部署。相反,在 Terraform 之外生成一个私钥文件并将其安全地分发到将运行 Terraform 的系统。


[1]https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/public_ip#example-usage-retrieve-the-dynamic-public-ip-of-a-new-vm

[2]https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_virtual_machine#:~:text=In%20this%20release%20there%27s%20a%20known%20issue%20where%20the%20public_ip_address%20and%20public_ip_addresses%20fields%20may%20not%20be%20fully%20populated%20for%20Dynamic%20Public%20IP%27s.

[3]https://stackoverflow.com/a/67379867/8343484

[4]https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key

【讨论】:

  • 如果可行,我将不胜感激接受这个答案。
  • 感谢您的回答。这个对我有用。我想下载 Terraform 在模块的帮助下生成的 tls_private_key_pem (.pem) 密钥文件。 [1] (github.com/hashicorp-modules/tls-private-key/blob/master/…) 和 [2] (stackoverflow.com/questions/49743220/…)
  • 你能帮我解决上面提到的问题吗?
  • 如果我没记错的话,这是一个与原始问题无关的不同问题。
  • 是的,但是我也和原来的问题一起问了这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-19
  • 2020-09-19
  • 1970-01-01
  • 2014-06-27
  • 1970-01-01
  • 2013-08-07
  • 1970-01-01
相关资源
最近更新 更多