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

[Enhancement] ip_configuration add count support #1002

Closed FrenchBen closed 6 years ago

FrenchBen commented 6 years ago

It's sometimes desirable to assign a few different IPs to a VNIC. On the SDK side, this is done by passing an array; on the terraform side, you need to specify each ip_config entry, which is a bit annoying.

Terraform Version

terraform -v
Terraform v0.11.3
+ provider.azurerm v1.3.0
+ provider.random v1.1.0

Affected Resource(s)

Terraform Configuration Files

Full script from: https://docs.microsoft.com/en-us/azure/virtual-machines/linux/terraform-create-complete-vm#complete-terraform-script

variable "resourcename" {
  default = "myResourceGroup"
}

# Configure the Microsoft Azure Provider
provider "azurerm" {
    subscription_id = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    client_id       = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    client_secret   = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    tenant_id       = "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

# Create a resource group if it doesn’t exist
resource "azurerm_resource_group" "myterraformgroup" {
    name     = "myResourceGroup"
    location = "eastus"

    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_prefix       = "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}"
    public_ip_address_allocation = "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}"
    network_security_group_id = "${azurerm_network_security_group.myterraformnsg.id}"

    ip_configuration {
        name                          = "myNicConfiguration"
        subnet_id                     = "${azurerm_subnet.myterraformsubnet.id}"
        private_ip_address_allocation = "dynamic"
        public_ip_address_id          = "${azurerm_public_ip.myterraformpublicip.id}"
        primary = true
    }

    ip_configuration {
        count    = "20"
        name                          = "${format("myOtherNicConf-%d", count.index)}"
        subnet_id                     = "${azurerm_subnet.myterraformsubnet.id}"
        private_ip_address_allocation = "dynamic"
    }

    tags {
        environment = "Terraform Demo"
    }
}

# 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 virtual machine
resource "azurerm_virtual_machine" "myterraformvm" {
    name                  = "myVM"
    location              = "eastus"
    resource_group_name   = "${azurerm_resource_group.myterraformgroup.name}"
    network_interface_ids = ["${azurerm_network_interface.myterraformnic.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       = "16.04.0-LTS"
        version   = "latest"
    }

    os_profile {
        computer_name  = "myvm"
        admin_username = "azureuser"
    }

    os_profile_linux_config {
        disable_password_authentication = true
        ssh_keys {
            path     = "/home/azureuser/.ssh/authorized_keys"
            key_data = "ssh-rsa AAAAB3Nz{snip}hwhqT9h"
        }
    }

    boot_diagnostics {
        enabled = "true"
        storage_uri = "${azurerm_storage_account.mystorageaccount.primary_blob_endpoint}"
    }

    tags {
        environment = "Terraform Demo"
    }
}

Debug Output

$ terraform validate

Error: azurerm_network_interface.myterraformnic: ip_configuration.1: invalid or unknown key: count

Expected Behavior

I expected terraform to support the count attribute with the ip_configuration attribute

Actual Behavior

It doesn't look like it does.

Steps to Reproduce

Please list the steps required to reproduce the issue, for example:

  1. terraform apply
seanknox commented 6 years ago

To add some priority to this, to use Azure CNI requires setting secondary IPs on NICs. If I wanted a pool of 100 IPs, currently you would have to add 100 ip_configuration blocks. Having a count/looping function would be a big help here.

FrenchBen commented 6 years ago

@seanknox that is precisely the issue I'm trying to fix :P We created a tool that can do this by making a few API calls: src: https://github.com/ddebroy/azip docker image: https://hub.docker.com/r/docker4x/az-nic-ips/

To cross-reference, I also opened an issue on terraform core: https://github.com/hashicorp/terraform/issues/17635#issuecomment-379344568

ddebroy commented 6 years ago

It will be great to also have similar functionality for ip_configuration under azurerm_virtual_machine_scale_set -> network_profile.

For the Azure IPAM scenario referenced above by @seanknox, in a Azure VM Scale Set environment, one needs to specify numerous ip_configuration blocks (similar to regular Azure VMs). What makes things worse in a VM Scale Set environment is that the API based mechanism does not appear to work against the network configuration of VM Scale Sets.

metacpp commented 6 years ago

We need support from HCL level: https://github.com/hashicorp/terraform/issues/7034

tombuildsstuff commented 6 years ago

hi @FrenchBen @seanknox @ddebroy

Thanks for opening this issue :)

Given this behaviour would be an enhancement to Terraform Core (since it's a metaparameter, it'll automatically apply to any provider) - I'm going to close this issue in favour of hashicorp/terraform#7034.

Thanks!

voyera commented 5 years ago

Hi there,

given that https://github.com/hashicorp/terraform/issues/7034 is now closed and part of terraform 0.12 ... would you guys be able to implement this?

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!