From adb6f592e49249dd5092dca1b7095a382e671ee2 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 14 Feb 2020 13:49:10 +0100 Subject: [PATCH 01/17] r/network_interface: introducing a separate update method --- azurerm/helpers/azure/contains.go | 11 + .../keyvault/resource_arm_key_vault.go | 4 +- .../network/network_interface_locking.go | 61 ++ .../resource_arm_ddos_protection_plan.go | 2 +- .../services/network/resource_arm_firewall.go | 8 +- ...source_arm_network_ddos_protection_plan.go | 2 +- .../network/resource_arm_network_interface.go | 639 ++++++++++-------- .../network/resource_arm_network_profile.go | 4 +- .../network/resource_arm_virtual_network.go | 4 +- 9 files changed, 446 insertions(+), 289 deletions(-) create mode 100644 azurerm/helpers/azure/contains.go create mode 100644 azurerm/internal/services/network/network_interface_locking.go diff --git a/azurerm/helpers/azure/contains.go b/azurerm/helpers/azure/contains.go new file mode 100644 index 000000000000..d6357dc3cc5b --- /dev/null +++ b/azurerm/helpers/azure/contains.go @@ -0,0 +1,11 @@ +package azure + +func SliceContainsValue(input []string, value string) bool { + for _, v := range input { + if v == value { + return true + } + } + + return false +} diff --git a/azurerm/internal/services/keyvault/resource_arm_key_vault.go b/azurerm/internal/services/keyvault/resource_arm_key_vault.go index 62d559c4d2f1..b8794993e092 100644 --- a/azurerm/internal/services/keyvault/resource_arm_key_vault.go +++ b/azurerm/internal/services/keyvault/resource_arm_key_vault.go @@ -290,7 +290,7 @@ func resourceArmKeyVaultCreateUpdate(d *schema.ResourceData, meta interface{}) e } virtualNetworkName := id.Path["virtualNetworks"] - if !network.SliceContainsValue(virtualNetworkNames, virtualNetworkName) { + if !azure.SliceContainsValue(virtualNetworkNames, virtualNetworkName) { virtualNetworkNames = append(virtualNetworkNames, virtualNetworkName) } } @@ -437,7 +437,7 @@ func resourceArmKeyVaultDelete(d *schema.ResourceData, meta interface{}) error { } virtualNetworkName := id.Path["virtualNetworks"] - if !network.SliceContainsValue(virtualNetworkNames, virtualNetworkName) { + if !azure.SliceContainsValue(virtualNetworkNames, virtualNetworkName) { virtualNetworkNames = append(virtualNetworkNames, virtualNetworkName) } } diff --git a/azurerm/internal/services/network/network_interface_locking.go b/azurerm/internal/services/network/network_interface_locking.go new file mode 100644 index 000000000000..9e599ce482b8 --- /dev/null +++ b/azurerm/internal/services/network/network_interface_locking.go @@ -0,0 +1,61 @@ +package network + +import ( + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-09-01/network" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" +) + +type networkInterfaceIPConfigurationLockingDetails struct { + subnetNamesToLock []string + virtualNetworkNamesToLock []string +} + +func (details networkInterfaceIPConfigurationLockingDetails) lock() { + locks.MultipleByName(&details.subnetNamesToLock, SubnetResourceName) + locks.MultipleByName(&details.virtualNetworkNamesToLock, VirtualNetworkResourceName) +} + +func (details networkInterfaceIPConfigurationLockingDetails) unlock() { + locks.UnlockMultipleByName(&details.subnetNamesToLock, SubnetResourceName) + locks.UnlockMultipleByName(&details.virtualNetworkNamesToLock, VirtualNetworkResourceName) +} + +func determineResourcesToLockFromIPConfiguration(input *[]network.InterfaceIPConfiguration) (*networkInterfaceIPConfigurationLockingDetails, error) { + if input == nil { + return &networkInterfaceIPConfigurationLockingDetails{ + subnetNamesToLock: []string{}, + virtualNetworkNamesToLock: []string{}, + }, nil + } + + subnetNamesToLock := make([]string, 0) + virtualNetworkNamesToLock := make([]string, 0) + + for _, config := range *input { + if config.Subnet == nil || config.Subnet.ID == nil { + continue + } + + id, err := azure.ParseAzureResourceID(*config.Subnet.ID) + if err != nil { + return nil, err + } + + virtualNetworkName := id.Path["virtualNetworks"] + subnetName := id.Path["subnets"] + + if !azure.SliceContainsValue(virtualNetworkNamesToLock, virtualNetworkName) { + virtualNetworkNamesToLock = append(virtualNetworkNamesToLock, virtualNetworkName) + } + + if !azure.SliceContainsValue(subnetNamesToLock, subnetName) { + subnetNamesToLock = append(subnetNamesToLock, subnetName) + } + } + + return &networkInterfaceIPConfigurationLockingDetails{ + subnetNamesToLock: subnetNamesToLock, + virtualNetworkNamesToLock: virtualNetworkNamesToLock, + }, nil +} diff --git a/azurerm/internal/services/network/resource_arm_ddos_protection_plan.go b/azurerm/internal/services/network/resource_arm_ddos_protection_plan.go index 29edffb05e50..10c5377ba10e 100644 --- a/azurerm/internal/services/network/resource_arm_ddos_protection_plan.go +++ b/azurerm/internal/services/network/resource_arm_ddos_protection_plan.go @@ -229,7 +229,7 @@ func extractVnetNames(d *schema.ResourceData) (*[]string, error) { vnetName := vnetResourceID.Path["virtualNetworks"] - if !SliceContainsValue(vnetNames, vnetName) { + if !azure.SliceContainsValue(vnetNames, vnetName) { vnetNames = append(vnetNames, vnetName) } } diff --git a/azurerm/internal/services/network/resource_arm_firewall.go b/azurerm/internal/services/network/resource_arm_firewall.go index 9b4ac25596ad..c825d2e914d8 100644 --- a/azurerm/internal/services/network/resource_arm_firewall.go +++ b/azurerm/internal/services/network/resource_arm_firewall.go @@ -267,12 +267,12 @@ func resourceArmFirewallDelete(d *schema.ResourceData, meta interface{}) error { } subnetName := parsedSubnetId.Path["subnets"] - if !SliceContainsValue(subnetNamesToLock, subnetName) { + if !azure.SliceContainsValue(subnetNamesToLock, subnetName) { subnetNamesToLock = append(subnetNamesToLock, subnetName) } virtualNetworkName := parsedSubnetId.Path["virtualNetworks"] - if !SliceContainsValue(virtualNetworkNamesToLock, virtualNetworkName) { + if !azure.SliceContainsValue(virtualNetworkNamesToLock, virtualNetworkName) { virtualNetworkNamesToLock = append(virtualNetworkNamesToLock, virtualNetworkName) } } @@ -338,11 +338,11 @@ func expandArmFirewallIPConfigurations(d *schema.ResourceData) (*[]network.Azure subnetName := subnetID.Path["subnets"] virtualNetworkName := subnetID.Path["virtualNetworks"] - if !SliceContainsValue(subnetNamesToLock, subnetName) { + if !azure.SliceContainsValue(subnetNamesToLock, subnetName) { subnetNamesToLock = append(subnetNamesToLock, subnetName) } - if !SliceContainsValue(virtualNetworkNamesToLock, virtualNetworkName) { + if !azure.SliceContainsValue(virtualNetworkNamesToLock, virtualNetworkName) { virtualNetworkNamesToLock = append(virtualNetworkNamesToLock, virtualNetworkName) } diff --git a/azurerm/internal/services/network/resource_arm_network_ddos_protection_plan.go b/azurerm/internal/services/network/resource_arm_network_ddos_protection_plan.go index f8c8b7131d43..3f8f2f8dfb53 100644 --- a/azurerm/internal/services/network/resource_arm_network_ddos_protection_plan.go +++ b/azurerm/internal/services/network/resource_arm_network_ddos_protection_plan.go @@ -223,7 +223,7 @@ func expandArmNetworkDDoSProtectionPlanVnetNames(d *schema.ResourceData) (*[]str vnetName := vnetResourceID.Path["virtualNetworks"] - if !SliceContainsValue(vnetNames, vnetName) { + if !azure.SliceContainsValue(vnetNames, vnetName) { vnetNames = append(vnetNames, vnetName) } } diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index 67d9a448b7fb..108413b84da7 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -3,7 +3,6 @@ package network import ( "fmt" "log" - "strings" "time" "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-09-01/network" @@ -12,7 +11,6 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/suppress" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/validate" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" @@ -26,9 +24,9 @@ var networkInterfaceResourceName = "azurerm_network_interface" func resourceArmNetworkInterface() *schema.Resource { return &schema.Resource{ - Create: resourceArmNetworkInterfaceCreateUpdate, + Create: resourceArmNetworkInterfaceCreate, Read: resourceArmNetworkInterfaceRead, - Update: resourceArmNetworkInterfaceCreateUpdate, + Update: resourceArmNetworkInterfaceUpdate, Delete: resourceArmNetworkInterfaceDelete, Importer: &schema.ResourceImporter{ @@ -53,26 +51,13 @@ func resourceArmNetworkInterface() *schema.Resource { "resource_group_name": azure.SchemaResourceGroupName(), + // NOTE: does this want it's own association resource? "network_security_group_id": { Type: schema.TypeString, Optional: true, ValidateFunc: azure.ValidateResourceIDOrEmpty, }, - "mac_address": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: validate.MACAddress, - }, - - "virtual_machine_id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - ValidateFunc: azure.ValidateResourceID, - }, - "ip_configuration": { Type: schema.TypeList, Required: true, @@ -107,7 +92,6 @@ func resourceArmNetworkInterface() *schema.Resource { }, false), }, - //TODO: should this be renamed to private_ip_address_allocation_method or private_ip_allocation_method ? "private_ip_address_allocation": { Type: schema.TypeString, Required: true, @@ -193,6 +177,18 @@ func resourceArmNetworkInterface() *schema.Resource { Set: schema.HashString, }, + "enable_accelerated_networking": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "enable_ip_forwarding": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "internal_dns_name_label": { Type: schema.TypeString, Optional: true, @@ -200,45 +196,22 @@ func resourceArmNetworkInterface() *schema.Resource { ValidateFunc: validation.StringIsNotEmpty, }, + "tags": tags.Schema(), + + // Computed "applied_dns_servers": { - Type: schema.TypeSet, - Optional: true, + Type: schema.TypeList, Computed: true, Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringIsNotEmpty, + Type: schema.TypeString, }, - Set: schema.HashString, }, - "internal_fqdn": { - Type: schema.TypeString, - Optional: true, - Computed: true, - Deprecated: "This field has been removed by Azure", - }, - - /** - * As of 2018-01-06: AN (aka. SR-IOV) on Azure is GA on Windows and Linux. - * - * Refer to: https://azure.microsoft.com/en-us/blog/maximize-your-vm-s-performance-with-accelerated-networking-now-generally-available-for-both-windows-and-linux/ - * - * Refer to: https://docs.microsoft.com/en-us/azure/virtual-network/create-vm-accelerated-networking-cli - * For details, VM configuration and caveats. - */ - "enable_accelerated_networking": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - - "enable_ip_forwarding": { - Type: schema.TypeBool, - Optional: true, - Default: false, + "mac_address": { + Type: schema.TypeString, + Computed: true, }, - // todo consider removing this one day as it is exposed in `private_ip_addresses.0` "private_ip_address": { Type: schema.TypeString, Computed: true, @@ -252,26 +225,27 @@ func resourceArmNetworkInterface() *schema.Resource { }, }, - "tags": tags.Schema(), + "virtual_machine_id": { + Type: schema.TypeString, + Computed: true, + }, }, } } -func resourceArmNetworkInterfaceCreateUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.InterfacesClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - log.Printf("[INFO] preparing arguments for AzureRM Network Interface creation.") - name := d.Get("name").(string) - resGroup := d.Get("resource_group_name").(string) + resourceGroup := d.Get("resource_group_name").(string) if features.ShouldResourcesBeImported() && d.IsNewResource() { - existing, err := client.Get(ctx, resGroup, name, "") + existing, err := client.Get(ctx, resourceGroup, name, "") if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("Error checking for presence of existing Network Interface %q (Resource Group %q): %s", name, resGroup, err) + return fmt.Errorf("Error checking for presence of existing Network Interface %q (Resource Group %q): %s", name, resourceGroup, err) } } @@ -313,70 +287,176 @@ func resourceArmNetworkInterfaceCreateUpdate(d *schema.ResourceData, meta interf dns, hasDns := d.GetOk("dns_servers") nameLabel, hasNameLabel := d.GetOk("internal_dns_name_label") if hasDns || hasNameLabel { - ifaceDnsSettings := network.InterfaceDNSSettings{} + dnsSettings := network.InterfaceDNSSettings{} if hasDns { - var dnsServers []string - dns := dns.(*schema.Set).List() - for _, v := range dns { - str := v.(string) - dnsServers = append(dnsServers, str) - } - ifaceDnsSettings.DNSServers = &dnsServers + dnsRaw := dns.(*schema.Set).List() + dns := expandNetworkInterfaceDnsServers(dnsRaw) + dnsSettings.DNSServers = &dns } if hasNameLabel { name_label := nameLabel.(string) - ifaceDnsSettings.InternalDNSNameLabel = &name_label + dnsSettings.InternalDNSNameLabel = &name_label } - properties.DNSSettings = &ifaceDnsSettings + properties.DNSSettings = &dnsSettings } - ipConfigs, subnetnToLock, vnnToLock, sgErr := expandAzureRmNetworkInterfaceIpConfigurations(d) - if sgErr != nil { - return fmt.Errorf("Error Building list of Network Interface IP Configurations: %+v", sgErr) + ipConfigsRaw := d.Get("ip_configuration").([]interface{}) + ipConfigs, err := expandNetworkInterfaceIPConfigurations(ipConfigsRaw) + if err != nil { + return fmt.Errorf("Error expanding `ip_configuration`: %+v", err) + } + lockingDetails, err := determineResourcesToLockFromIPConfiguration(&ipConfigs) + if err != nil { + return fmt.Errorf("Error determing locking details: %+v", err) } - locks.MultipleByName(subnetnToLock, SubnetResourceName) - defer locks.UnlockMultipleByName(subnetnToLock, SubnetResourceName) - - locks.MultipleByName(vnnToLock, VirtualNetworkResourceName) - defer locks.UnlockMultipleByName(vnnToLock, VirtualNetworkResourceName) + lockingDetails.lock() + defer lockingDetails.unlock() if len(ipConfigs) > 0 { properties.IPConfigurations = &ipConfigs } iface := network.Interface{ - Name: &name, - Location: &location, + Name: utils.String(name), + Location: utils.String(location), InterfacePropertiesFormat: &properties, Tags: tags.Expand(t), } - future, err := client.CreateOrUpdate(ctx, resGroup, name, iface) + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, iface) if err != nil { - return err + return fmt.Errorf("Error creating Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return err + return fmt.Errorf("Error waiting for creation of Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) } - read, err := client.Get(ctx, resGroup, name, "") + read, err := client.Get(ctx, resourceGroup, name, "") if err != nil { - return err + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) } if read.ID == nil { - return fmt.Errorf("Cannot read NIC %q (resource group %q) ID", name, resGroup) + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): ID was nil", name, resourceGroup) } - d.SetId(*read.ID) return resourceArmNetworkInterfaceRead(d, meta) } +func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.InterfacesClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := azure.ParseAzureResourceID(d.Id()) + if err != nil { + return err + } + resourceGroup := id.ResourceGroup + name := id.Path["networkInterfaces"] + + locks.ByName(name, networkInterfaceResourceName) + defer locks.UnlockByName(name, networkInterfaceResourceName) + + location := azure.NormalizeLocation(d.Get("location").(string)) + update := network.Interface{ + Name: utils.String(name), + Location: utils.String(location), + } + + if d.HasChange("dns_servers") { + if update.InterfacePropertiesFormat == nil { + update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} + } + if update.InterfacePropertiesFormat.DNSSettings == nil { + update.InterfacePropertiesFormat.DNSSettings = &network.InterfaceDNSSettings{} + } + + dnsServersRaw := d.Get("dns_servers").(*schema.Set).List() + dnsServers := expandNetworkInterfaceDnsServers(dnsServersRaw) + + update.InterfacePropertiesFormat.DNSSettings.DNSServers = &dnsServers + } + + if d.HasChange("enable_accelerated_networking") { + if update.InterfacePropertiesFormat == nil { + update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} + } + + update.InterfacePropertiesFormat.EnableAcceleratedNetworking = utils.Bool(d.Get("enable_accelerated_networking").(bool)) + } + + if d.HasChange("enable_ip_forwarding") { + if update.InterfacePropertiesFormat == nil { + update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} + } + + update.InterfacePropertiesFormat.EnableIPForwarding = utils.Bool(d.Get("enable_ip_forwarding").(bool)) + } + + if d.HasChange("internal_dns_name_label") { + if update.InterfacePropertiesFormat == nil { + update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} + } + if update.InterfacePropertiesFormat.DNSSettings == nil { + update.InterfacePropertiesFormat.DNSSettings = &network.InterfaceDNSSettings{} + } + + update.InterfacePropertiesFormat.DNSSettings.InternalDNSNameLabel = utils.String(d.Get("internal_dns_name_label").(string)) + } + + if d.HasChange("ip_configuration") { + if update.InterfacePropertiesFormat == nil { + update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} + } + + ipConfigsRaw := d.Get("ip_configuration").([]interface{}) + ipConfigs, err := expandNetworkInterfaceIPConfigurations(ipConfigsRaw) + if err != nil { + return fmt.Errorf("Error expanding `ip_configuration`: %+v", err) + } + lockingDetails, err := determineResourcesToLockFromIPConfiguration(&ipConfigs) + if err != nil { + return fmt.Errorf("Error determing locking details: %+v", err) + } + + lockingDetails.lock() + defer lockingDetails.unlock() + + update.InterfacePropertiesFormat.IPConfigurations = &ipConfigs + } + + if d.HasChange("network_security_group_id") { + if update.InterfacePropertiesFormat == nil { + update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} + } + + update.InterfacePropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{ + ID: utils.String(d.Get("network_security_group_id").(string)), + } + } + + if d.HasChange("tags") { + tagsRaw := d.Get("tags").(map[string]interface{}) + update.Tags = tags.Expand(tagsRaw) + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, update) + if err != nil { + return fmt.Errorf("Error updating Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for update of Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + return nil +} + func resourceArmNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Network.InterfacesClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) @@ -386,80 +466,88 @@ func resourceArmNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) e if err != nil { return err } - resGroup := id.ResourceGroup + resourceGroup := id.ResourceGroup name := id.Path["networkInterfaces"] - resp, err := client.Get(ctx, resGroup, name, "") + resp, err := client.Get(ctx, resourceGroup, name, "") if err != nil { if utils.ResponseWasNotFound(resp.Response) { d.SetId("") return nil } - return fmt.Errorf("Error making Read request on Azure Network Interface %q (Resource Group %q): %+v", name, resGroup, err) + return fmt.Errorf("Error making Read request on Azure Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) } d.Set("name", resp.Name) - d.Set("resource_group_name", resGroup) + d.Set("resource_group_name", resourceGroup) if location := resp.Location; location != nil { d.Set("location", azure.NormalizeLocation(*location)) } if props := resp.InterfacePropertiesFormat; props != nil { - d.Set("mac_address", props.MacAddress) - addresses := make([]interface{}, 0) + primaryPrivateIPAddress := "" + privateIPAddresses := make([]interface{}, 0) if configs := props.IPConfigurations; configs != nil { for i, config := range *props.IPConfigurations { if ipProps := config.InterfaceIPConfigurationPropertiesFormat; ipProps != nil { - if v := ipProps.PrivateIPAddress; v != nil { - if i == 0 { - d.Set("private_ip_address", v) - } - addresses = append(addresses, *v) + v := ipProps.PrivateIPAddress + if v == nil { + continue } - } - } - } - if err := d.Set("private_ip_addresses", addresses); err != nil { - return err - } - if props.IPConfigurations != nil { - configs := flattenNetworkInterfaceIPConfigurations(props.IPConfigurations) - if err := d.Set("ip_configuration", configs); err != nil { - return fmt.Errorf("Error setting `ip_configuration`: %+v", err) - } - } + if i == 0 { + primaryPrivateIPAddress = *v + } - if vm := props.VirtualMachine; vm != nil { - d.Set("virtual_machine_id", vm.ID) + privateIPAddresses = append(privateIPAddresses, *v) + } + } } - var appliedDNSServers []string - var dnsServers []string + appliedDNSServers := make([]string, 0) + dnsServers := make([]string, 0) + internalDnsNameLabel := "" if dnsSettings := props.DNSSettings; dnsSettings != nil { - if s := dnsSettings.AppliedDNSServers; s != nil { - appliedDNSServers = *s - } + appliedDNSServers = flattenNetworkInterfaceDnsServers(dnsSettings.AppliedDNSServers) + dnsServers = flattenNetworkInterfaceDnsServers(dnsSettings.DNSServers) - if s := dnsSettings.DNSServers; s != nil { - dnsServers = *s + if dnsSettings.InternalDNSNameLabel != nil { + internalDnsNameLabel = *dnsSettings.InternalDNSNameLabel } + } - d.Set("internal_fqdn", dnsSettings.InternalFqdn) - d.Set("internal_dns_name_label", dnsSettings.InternalDNSNameLabel) + networkSecurityGroupId := "" + if props.NetworkSecurityGroup != nil && props.NetworkSecurityGroup.ID != nil { + networkSecurityGroupId = *props.NetworkSecurityGroup.ID + } + virtualMachineId := "" + if props.VirtualMachine != nil && props.VirtualMachine.ID != nil { + virtualMachineId = *props.VirtualMachine.ID } - d.Set("applied_dns_servers", appliedDNSServers) - d.Set("dns_servers", dnsServers) + if err := d.Set("applied_dns_servers", appliedDNSServers); err != nil { + return fmt.Errorf("Error setting `applied_dns_servers`: %+v", err) + } - if nsg := props.NetworkSecurityGroup; nsg != nil { - d.Set("network_security_group_id", nsg.ID) - } else { - d.Set("network_security_group_id", "") + if err := d.Set("dns_servers", dnsServers); err != nil { + return fmt.Errorf("Error setting `applied_dns_servers`: %+v", err) } d.Set("enable_ip_forwarding", resp.EnableIPForwarding) d.Set("enable_accelerated_networking", resp.EnableAcceleratedNetworking) + d.Set("internal_dns_name_label", internalDnsNameLabel) + d.Set("mac_address", props.MacAddress) + d.Set("network_security_group_id", networkSecurityGroupId) + d.Set("private_ip_address", primaryPrivateIPAddress) + d.Set("virtual_machine_id", virtualMachineId) + + if err := d.Set("ip_configuration", flattenNetworkInterfaceIPConfigurations(props.IPConfigurations)); err != nil { + return fmt.Errorf("Error setting `ip_configuration`: %+v", err) + } + + if err := d.Set("private_ip_addresses", privateIPAddresses); err != nil { + return fmt.Errorf("Error setting `private_ip_addresses`: %+v", err) + } } return tags.FlattenAndSet(d, resp.Tags) @@ -474,14 +562,30 @@ func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) if err != nil { return err } - resGroup := id.ResourceGroup + resourceGroup := id.ResourceGroup name := id.Path["networkInterfaces"] locks.ByName(name, networkInterfaceResourceName) defer locks.UnlockByName(name, networkInterfaceResourceName) - if v, ok := d.GetOk("network_security_group_id"); ok { - networkSecurityGroupId := v.(string) + existing, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + if utils.ResponseWasNotFound(existing.Response) { + log.Printf("[DEBUG] Network Interface %q was not found in Resource Group %q - removing from state", name, resourceGroup) + d.SetId("") + return nil + } + + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + if existing.InterfacePropertiesFormat == nil { + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): `properties` was nil", name, resourceGroup) + } + props := *existing.InterfacePropertiesFormat + + if props.NetworkSecurityGroup != nil && props.NetworkSecurityGroup.ID != nil { + networkSecurityGroupId := *props.NetworkSecurityGroup.ID parsedNsgID, err := azure.ParseAzureResourceID(networkSecurityGroupId) if err != nil { return fmt.Errorf("Error parsing Network Security Group ID %q: %+v", networkSecurityGroupId, err) @@ -493,159 +597,49 @@ func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) defer locks.UnlockByName(networkSecurityGroupName, networkSecurityGroupResourceName) } - configs := d.Get("ip_configuration").([]interface{}) - subnetNamesToLock := make([]string, 0) - virtualNetworkNamesToLock := make([]string, 0) - - for _, configRaw := range configs { - data := configRaw.(map[string]interface{}) - - subnet_id := data["subnet_id"].(string) - if subnet_id != "" { - subnetId, err2 := azure.ParseAzureResourceID(subnet_id) - if err2 != nil { - return err2 - } - subnetName := subnetId.Path["subnets"] - if !SliceContainsValue(subnetNamesToLock, subnetName) { - subnetNamesToLock = append(subnetNamesToLock, subnetName) - } - - virtualNetworkName := subnetId.Path["virtualNetworks"] - if !SliceContainsValue(virtualNetworkNamesToLock, virtualNetworkName) { - virtualNetworkNamesToLock = append(virtualNetworkNamesToLock, virtualNetworkName) - } - } + lockingDetails, err := determineResourcesToLockFromIPConfiguration(props.IPConfigurations) + if err != nil { + return fmt.Errorf("Error determing locking details: %+v", err) } - locks.MultipleByName(&subnetNamesToLock, SubnetResourceName) - defer locks.UnlockMultipleByName(&subnetNamesToLock, SubnetResourceName) - - locks.MultipleByName(&virtualNetworkNamesToLock, VirtualNetworkResourceName) - defer locks.UnlockMultipleByName(&virtualNetworkNamesToLock, VirtualNetworkResourceName) + lockingDetails.lock() + defer lockingDetails.unlock() - future, err := client.Delete(ctx, resGroup, name) + future, err := client.Delete(ctx, resourceGroup, name) if err != nil { - return fmt.Errorf("Error deleting Network Interface %q (Resource Group %q): %+v", name, resGroup, err) + return fmt.Errorf("Error deleting Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("Error waiting for the deletion of Network Interface %q (Resource Group %q): %+v", name, resGroup, err) + return fmt.Errorf("Error waiting for the deletion of Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) } - return err -} - -func flattenNetworkInterfaceIPConfigurations(ipConfigs *[]network.InterfaceIPConfiguration) []interface{} { - result := make([]interface{}, 0, len(*ipConfigs)) - for _, ipConfig := range *ipConfigs { - niIPConfig := make(map[string]interface{}) - - props := ipConfig.InterfaceIPConfigurationPropertiesFormat - - niIPConfig["name"] = *ipConfig.Name - - if props.Subnet != nil && props.Subnet.ID != nil { - niIPConfig["subnet_id"] = *props.Subnet.ID - } - - niIPConfig["private_ip_address_allocation"] = strings.ToLower(string(props.PrivateIPAllocationMethod)) - - if props.PrivateIPAddress != nil { - niIPConfig["private_ip_address"] = *props.PrivateIPAddress - } - - if props.PrivateIPAddressVersion != "" { - niIPConfig["private_ip_address_version"] = string(props.PrivateIPAddressVersion) - } - - if props.PublicIPAddress != nil { - niIPConfig["public_ip_address_id"] = *props.PublicIPAddress.ID - } - - if props.Primary != nil { - niIPConfig["primary"] = *props.Primary - } - - var poolsAG []interface{} - if props.ApplicationGatewayBackendAddressPools != nil { - for _, pool := range *props.ApplicationGatewayBackendAddressPools { - poolsAG = append(poolsAG, *pool.ID) - } - } - niIPConfig["application_gateway_backend_address_pools_ids"] = schema.NewSet(schema.HashString, poolsAG) - - var pools []interface{} - if props.LoadBalancerBackendAddressPools != nil { - for _, pool := range *props.LoadBalancerBackendAddressPools { - pools = append(pools, *pool.ID) - } - } - niIPConfig["load_balancer_backend_address_pools_ids"] = schema.NewSet(schema.HashString, pools) - - var rules []interface{} - if props.LoadBalancerInboundNatRules != nil { - for _, rule := range *props.LoadBalancerInboundNatRules { - rules = append(rules, *rule.ID) - } - } - niIPConfig["load_balancer_inbound_nat_rules_ids"] = schema.NewSet(schema.HashString, rules) - - securityGroups := make([]interface{}, 0) - if sgs := props.ApplicationSecurityGroups; sgs != nil { - for _, sg := range *sgs { - securityGroups = append(securityGroups, *sg.ID) - } - } - niIPConfig["application_security_group_ids"] = schema.NewSet(schema.HashString, securityGroups) - - result = append(result, niIPConfig) - } - return result + return nil } -func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]network.InterfaceIPConfiguration, *[]string, *[]string, error) { - configs := d.Get("ip_configuration").([]interface{}) - ipConfigs := make([]network.InterfaceIPConfiguration, 0, len(configs)) - subnetNamesToLock := make([]string, 0) - virtualNetworkNamesToLock := make([]string, 0) +func expandNetworkInterfaceIPConfigurations(input []interface{}) ([]network.InterfaceIPConfiguration, error) { + ipConfigs := make([]network.InterfaceIPConfiguration, 0) - for _, configRaw := range configs { + for _, configRaw := range input { data := configRaw.(map[string]interface{}) - subnet_id := data["subnet_id"].(string) - private_ip_allocation_method := data["private_ip_address_allocation"].(string) - private_ip_address_version := network.IPVersion(data["private_ip_address_version"].(string)) + subnetId := data["subnet_id"].(string) + privateIpAllocationMethod := data["private_ip_address_allocation"].(string) + privateIpAddressVersion := network.IPVersion(data["private_ip_address_version"].(string)) - allocationMethod := network.IPAllocationMethod(private_ip_allocation_method) + allocationMethod := network.IPAllocationMethod(privateIpAllocationMethod) properties := network.InterfaceIPConfigurationPropertiesFormat{ PrivateIPAllocationMethod: allocationMethod, - PrivateIPAddressVersion: private_ip_address_version, + PrivateIPAddressVersion: privateIpAddressVersion, } - if private_ip_address_version == network.IPv4 && subnet_id == "" { - return nil, nil, nil, fmt.Errorf("A Subnet ID must be specified for an IPv4 Network Interface.") + if privateIpAddressVersion == network.IPv4 && subnetId == "" { + return nil, fmt.Errorf("A Subnet ID must be specified for an IPv4 Network Interface.") } - if subnet_id != "" { + if subnetId != "" { properties.Subnet = &network.Subnet{ - ID: &subnet_id, - } - - subnetId, err := azure.ParseAzureResourceID(subnet_id) - if err != nil { - return []network.InterfaceIPConfiguration{}, nil, nil, err - } - - subnetName := subnetId.Path["subnets"] - virtualNetworkName := subnetId.Path["virtualNetworks"] - - if !SliceContainsValue(subnetNamesToLock, subnetName) { - subnetNamesToLock = append(subnetNamesToLock, subnetName) - } - - if !SliceContainsValue(virtualNetworkNamesToLock, virtualNetworkName) { - virtualNetworkNamesToLock = append(virtualNetworkNamesToLock, virtualNetworkName) + ID: &subnetId, } } @@ -660,17 +654,16 @@ func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]ne } if v, ok := data["primary"]; ok { - b := v.(bool) - properties.Primary = &b + properties.Primary = utils.Bool(v.(bool)) } if v, ok := data["application_gateway_backend_address_pools_ids"]; ok { var ids []network.ApplicationGatewayBackendAddressPool pools := v.(*schema.Set).List() for _, p := range pools { - pool_id := p.(string) + poolId := p.(string) id := network.ApplicationGatewayBackendAddressPool{ - ID: &pool_id, + ID: &poolId, } ids = append(ids, id) @@ -683,9 +676,9 @@ func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]ne var ids []network.BackendAddressPool pools := v.(*schema.Set).List() for _, p := range pools { - pool_id := p.(string) + poolId := p.(string) id := network.BackendAddressPool{ - ID: &pool_id, + ID: &poolId, } ids = append(ids, id) @@ -698,9 +691,9 @@ func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]ne var natRules []network.InboundNatRule rules := v.(*schema.Set).List() for _, r := range rules { - rule_id := r.(string) + ruleId := r.(string) rule := network.InboundNatRule{ - ID: &rule_id, + ID: &ruleId, } natRules = append(natRules, rule) @@ -725,12 +718,10 @@ func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]ne } name := data["name"].(string) - ipConfig := network.InterfaceIPConfiguration{ + ipConfigs = append(ipConfigs, network.InterfaceIPConfiguration{ Name: &name, InterfaceIPConfigurationPropertiesFormat: &properties, - } - - ipConfigs = append(ipConfigs, ipConfig) + }) } // if we've got multiple IP Configurations - one must be designated Primary @@ -744,19 +735,113 @@ func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]ne } if !hasPrimary { - return nil, nil, nil, fmt.Errorf("If multiple `ip_configurations` are specified - one must be designated as `primary`.") + return nil, fmt.Errorf("If multiple `ip_configurations` are specified - one must be designated as `primary`.") } } - return ipConfigs, &subnetNamesToLock, &virtualNetworkNamesToLock, nil + return ipConfigs, nil } -func SliceContainsValue(input []string, value string) bool { - for _, v := range input { - if v == value { - return true +func flattenNetworkInterfaceIPConfigurations(input *[]network.InterfaceIPConfiguration) []interface{} { + if input == nil { + return []interface{}{} + } + + result := make([]interface{}, 0) + for _, ipConfig := range *input { + props := ipConfig.InterfaceIPConfigurationPropertiesFormat + + name := "" + if ipConfig.Name != nil { + name = *ipConfig.Name + } + + subnetId := "" + if props.Subnet != nil && props.Subnet.ID != nil { + subnetId = *props.Subnet.ID + } + + privateIPAddress := "" + if props.PrivateIPAddress != nil { + privateIPAddress = *props.PrivateIPAddress + } + + privateIPAddressVersion := "" + if props.PrivateIPAddressVersion != "" { + privateIPAddressVersion = string(props.PrivateIPAddressVersion) + } + + publicIPAddressId := "" + if props.PublicIPAddress != nil && props.PublicIPAddress.ID != nil { + publicIPAddressId = *props.PublicIPAddress.ID + } + + var appGatewayBackendPools []interface{} + if props.ApplicationGatewayBackendAddressPools != nil { + for _, pool := range *props.ApplicationGatewayBackendAddressPools { + appGatewayBackendPools = append(appGatewayBackendPools, *pool.ID) + } } + + var lbBackendAddressPools []interface{} + if props.LoadBalancerBackendAddressPools != nil { + for _, pool := range *props.LoadBalancerBackendAddressPools { + lbBackendAddressPools = append(lbBackendAddressPools, *pool.ID) + } + } + + var lbInboundNatRules []interface{} + if props.LoadBalancerInboundNatRules != nil { + for _, rule := range *props.LoadBalancerInboundNatRules { + lbInboundNatRules = append(lbInboundNatRules, *rule.ID) + } + } + + primary := false + if props.Primary != nil { + primary = *props.Primary + } + + securityGroups := make([]interface{}, 0) + if sgs := props.ApplicationSecurityGroups; sgs != nil { + for _, sg := range *sgs { + securityGroups = append(securityGroups, *sg.ID) + } + } + + result = append(result, map[string]interface{}{ + "application_gateway_backend_address_pools_ids": schema.NewSet(schema.HashString, appGatewayBackendPools), + "application_security_group_ids": schema.NewSet(schema.HashString, securityGroups), + "load_balancer_backend_address_pools_ids": schema.NewSet(schema.HashString, lbBackendAddressPools), + "load_balancer_inbound_nat_rules_ids": schema.NewSet(schema.HashString, lbInboundNatRules), + "name": name, + "primary": primary, + "private_ip_address": privateIPAddress, + "private_ip_address_allocation": string(props.PrivateIPAllocationMethod), + "private_ip_address_version": privateIPAddressVersion, + "public_ip_address_id": publicIPAddressId, + "subnet_id": subnetId, + }) + } + return result +} + +func expandNetworkInterfaceDnsServers(input []interface{}) []string { + dnsServers := make([]string, 0) + for _, v := range input { + dnsServers = append(dnsServers, v.(string)) + } + return dnsServers +} + +func flattenNetworkInterfaceDnsServers(input *[]string) []string { + output := make([]string, 0) + if input == nil { + return output } - return false + for _, v := range *input { + output = append(output, v) + } + return output } diff --git a/azurerm/internal/services/network/resource_arm_network_profile.go b/azurerm/internal/services/network/resource_arm_network_profile.go index 40c8bd3593e0..f3338e0dc972 100644 --- a/azurerm/internal/services/network/resource_arm_network_profile.go +++ b/azurerm/internal/services/network/resource_arm_network_profile.go @@ -315,11 +315,11 @@ func expandNetworkProfileVirtualNetworkSubnetNames(d *schema.ResourceData) (*[]s subnetName := subnetResourceID.Path["subnets"] vnetName := subnetResourceID.Path["virtualNetworks"] - if !SliceContainsValue(subnetNames, subnetName) { + if !azure.SliceContainsValue(subnetNames, subnetName) { subnetNames = append(subnetNames, subnetName) } - if !SliceContainsValue(vnetNames, vnetName) { + if !azure.SliceContainsValue(vnetNames, vnetName) { vnetNames = append(vnetNames, vnetName) } } diff --git a/azurerm/internal/services/network/resource_arm_virtual_network.go b/azurerm/internal/services/network/resource_arm_virtual_network.go index 3bc5e0080567..3b7ce65bf664 100644 --- a/azurerm/internal/services/network/resource_arm_virtual_network.go +++ b/azurerm/internal/services/network/resource_arm_virtual_network.go @@ -178,7 +178,7 @@ func resourceArmVirtualNetworkCreateUpdate(d *schema.ResourceData, meta interfac networkSecurityGroupName := parsedNsgID.Path["networkSecurityGroups"] - if !SliceContainsValue(networkSecurityGroupNames, networkSecurityGroupName) { + if !azure.SliceContainsValue(networkSecurityGroupNames, networkSecurityGroupName) { networkSecurityGroupNames = append(networkSecurityGroupNames, networkSecurityGroupName) } } @@ -480,7 +480,7 @@ func expandAzureRmVirtualNetworkVirtualNetworkSecurityGroupNames(d *schema.Resou networkSecurityGroupName := parsedNsgID.Path["networkSecurityGroups"] - if !SliceContainsValue(nsgNames, networkSecurityGroupName) { + if !azure.SliceContainsValue(nsgNames, networkSecurityGroupName) { nsgNames = append(nsgNames, networkSecurityGroupName) } } From 9ea66209d490b0ac5c6e7192c6a51a6a28a04695 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 14 Feb 2020 14:43:15 +0100 Subject: [PATCH 02/17] r/network_interface: removing the `application_gateway_backend_address_pool_ids` field --- .../network/resource_arm_network_interface.go | 55 ++------ ...ce_application_gateway_association_test.go | 130 +++++++++++++----- .../resource_arm_network_interface_test.go | 130 ------------------ .../docs/r/network_interface.html.markdown | 4 - 4 files changed, 108 insertions(+), 211 deletions(-) diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index 108413b84da7..d137973c4c67 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -109,18 +109,6 @@ func resourceArmNetworkInterface() *schema.Resource { ValidateFunc: azure.ValidateResourceIDOrEmpty, }, - "application_gateway_backend_address_pools_ids": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Deprecated: "This field has been deprecated in favour of the `azurerm_network_interface_application_gateway_backend_address_pool_association` resource.", - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: azure.ValidateResourceID, - }, - Set: schema.HashString, - }, - "load_balancer_backend_address_pools_ids": { Type: schema.TypeSet, Optional: true, @@ -657,21 +645,6 @@ func expandNetworkInterfaceIPConfigurations(input []interface{}) ([]network.Inte properties.Primary = utils.Bool(v.(bool)) } - if v, ok := data["application_gateway_backend_address_pools_ids"]; ok { - var ids []network.ApplicationGatewayBackendAddressPool - pools := v.(*schema.Set).List() - for _, p := range pools { - poolId := p.(string) - id := network.ApplicationGatewayBackendAddressPool{ - ID: &poolId, - } - - ids = append(ids, id) - } - - properties.ApplicationGatewayBackendAddressPools = &ids - } - if v, ok := data["load_balancer_backend_address_pools_ids"]; ok { var ids []network.BackendAddressPool pools := v.(*schema.Set).List() @@ -776,13 +749,6 @@ func flattenNetworkInterfaceIPConfigurations(input *[]network.InterfaceIPConfigu publicIPAddressId = *props.PublicIPAddress.ID } - var appGatewayBackendPools []interface{} - if props.ApplicationGatewayBackendAddressPools != nil { - for _, pool := range *props.ApplicationGatewayBackendAddressPools { - appGatewayBackendPools = append(appGatewayBackendPools, *pool.ID) - } - } - var lbBackendAddressPools []interface{} if props.LoadBalancerBackendAddressPools != nil { for _, pool := range *props.LoadBalancerBackendAddressPools { @@ -810,17 +776,16 @@ func flattenNetworkInterfaceIPConfigurations(input *[]network.InterfaceIPConfigu } result = append(result, map[string]interface{}{ - "application_gateway_backend_address_pools_ids": schema.NewSet(schema.HashString, appGatewayBackendPools), - "application_security_group_ids": schema.NewSet(schema.HashString, securityGroups), - "load_balancer_backend_address_pools_ids": schema.NewSet(schema.HashString, lbBackendAddressPools), - "load_balancer_inbound_nat_rules_ids": schema.NewSet(schema.HashString, lbInboundNatRules), - "name": name, - "primary": primary, - "private_ip_address": privateIPAddress, - "private_ip_address_allocation": string(props.PrivateIPAllocationMethod), - "private_ip_address_version": privateIPAddressVersion, - "public_ip_address_id": publicIPAddressId, - "subnet_id": subnetId, + "application_security_group_ids": schema.NewSet(schema.HashString, securityGroups), + "load_balancer_backend_address_pools_ids": schema.NewSet(schema.HashString, lbBackendAddressPools), + "load_balancer_inbound_nat_rules_ids": schema.NewSet(schema.HashString, lbInboundNatRules), + "name": name, + "primary": primary, + "private_ip_address": privateIPAddress, + "private_ip_address_allocation": string(props.PrivateIPAllocationMethod), + "private_ip_address_version": privateIPAddressVersion, + "public_ip_address_id": publicIPAddressId, + "subnet_id": subnetId, }) } return result diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_application_gateway_association_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_application_gateway_association_test.go index 3fc2b0d855eb..f2dad35421cd 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_application_gateway_association_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_application_gateway_association_test.go @@ -27,6 +27,7 @@ func TestAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociati testCheckAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociationExists(data.ResourceName), ), }, + data.ImportStep(), }, }) } @@ -79,6 +80,32 @@ func TestAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociati }) } +func TestAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_updateNIC(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface_application_gateway_backend_address_pool_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_updateNIC(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + func testCheckAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociationExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Network.InterfacesClient @@ -185,6 +212,76 @@ func testCheckAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssocia } func testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_basic(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + ip_configuration { + name = "testconfiguration1" + subnet_id = "${azurerm_subnet.frontend.id}" + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "test" { + network_interface_id = azurerm_network_interface.test.id + ip_configuration_name = "testconfiguration1" + backend_address_pool_id = azurerm_application_gateway.test.backend_address_pool.0.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "import" { + network_interface_id = "${azurerm_network_interface_application_gateway_backend_address_pool_association.test.network_interface_id}" + ip_configuration_name = "${azurerm_network_interface_application_gateway_backend_address_pool_association.test.ip_configuration_name}" + backend_address_pool_id = "${azurerm_network_interface_application_gateway_backend_address_pool_association.test.backend_address_pool_id}" +} +`, template) +} + +func testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_updateNIC(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + ip_configuration { + name = "testconfiguration1" + subnet_id = "${azurerm_subnet.frontend.id}" + private_ip_address_allocation = "Dynamic" + primary = true + } + + ip_configuration { + name = "testconfiguration2" + private_ip_address_version = "IPv6" + private_ip_address_allocation = "dynamic" + } +} + +resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "test" { + network_interface_id = azurerm_network_interface.test.id + ip_configuration_name = "testconfiguration1" + backend_address_pool_id = azurerm_application_gateway.test.backend_address_pool.0.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_template(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" @@ -282,36 +379,5 @@ resource "azurerm_application_gateway" "test" { backend_http_settings_name = "${local.http_setting_name}" } } - -resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.frontend.id}" - private_ip_address_allocation = "Dynamic" - } -} - -resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "test" { - network_interface_id = "${azurerm_network_interface.test.id}" - ip_configuration_name = "testconfiguration1" - backend_address_pool_id = "${azurerm_application_gateway.test.backend_address_pool.0.id}" -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) -} - -func testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_requiresImport(data acceptance.TestData) string { - template := testAccAzureRMNetworkInterfaceApplicationGatewayBackendAddressPoolAssociation_basic(data) - return fmt.Sprintf(` -%s - -resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "import" { - network_interface_id = "${azurerm_network_interface_application_gateway_backend_address_pool_association.test.network_interface_id}" - ip_configuration_name = "${azurerm_network_interface_application_gateway_backend_address_pool_association.test.ip_configuration_name}" - backend_address_pool_id = "${azurerm_network_interface_application_gateway_backend_address_pool_association.test.backend_address_pool_id}" -} -`, template) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go index 468f031e3237..8d35f133cbac 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go @@ -231,24 +231,6 @@ func TestAccAzureRMNetworkInterface_multipleLoadBalancers(t *testing.T) { }) } -func TestAccAzureRMNetworkInterface_applicationGateway(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAzureRMNetworkInterface_applicationGatewayBackendPool(data), - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.application_gateway_backend_address_pools_ids.#", "1"), - ), - }, - }, - }) -} - func TestAccAzureRMNetworkInterface_withTags(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ @@ -1067,118 +1049,6 @@ resource "azurerm_network_interface" "test2" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) } -func testAccAzureRMNetworkInterface_applicationGatewayBackendPool(data acceptance.TestData) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctest-vnet-%d" - resource_group_name = "${azurerm_resource_group.test.name}" - address_space = ["10.254.0.0/16"] - location = "${azurerm_resource_group.test.location}" -} - -resource "azurerm_subnet" "gateway" { - name = "subnet-gateway-%d" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.254.0.0/24" -} - -resource "azurerm_subnet" "test" { - name = "subnet-%d" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.254.1.0/24" -} - -resource "azurerm_public_ip" "test" { - name = "acctest-pubip-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - allocation_method = "Dynamic" -} - -resource "azurerm_application_gateway" "test" { - name = "acctestgw-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - sku { - name = "Standard_Medium" - tier = "Standard" - capacity = 1 - } - - gateway_ip_configuration { - name = "gw-ip-config1" - subnet_id = "${azurerm_subnet.gateway.id}" - } - - frontend_port { - name = "port-8080" - port = 8080 - } - - frontend_ip_configuration { - name = "ip-config-public" - public_ip_address_id = "${azurerm_public_ip.test.id}" - } - - backend_address_pool { - name = "pool-1" - } - - backend_http_settings { - name = "backend-http-1" - port = 8080 - protocol = "Http" - cookie_based_affinity = "Enabled" - request_timeout = 30 - } - - http_listener { - name = "listener-1" - frontend_ip_configuration_name = "ip-config-public" - frontend_port_name = "port-8080" - protocol = "Http" - } - - request_routing_rule { - name = "rule-basic-1" - rule_type = "Basic" - http_listener_name = "listener-1" - backend_address_pool_name = "pool-1" - backend_http_settings_name = "backend-http-1" - } - - tags = { - environment = "tf01" - } -} - -resource "azurerm_network_interface" "test" { - name = "acctestnic-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - enable_ip_forwarding = true - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - - application_gateway_backend_address_pools_ids = [ - "${azurerm_application_gateway.test.backend_address_pool.0.id}", - ] - } -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) -} - func testAccAzureRMNetworkInterface_bug7986(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/website/docs/r/network_interface.html.markdown b/website/docs/r/network_interface.html.markdown index 45f5f6bfddce..ccd50c546012 100644 --- a/website/docs/r/network_interface.html.markdown +++ b/website/docs/r/network_interface.html.markdown @@ -90,10 +90,6 @@ The `ip_configuration` block supports: * `public_ip_address_id` - (Optional) Reference to a Public IP Address to associate with this NIC -* `application_gateway_backend_address_pools_ids` - (Optional / **Deprecated**) List of Application Gateway Backend Address Pool IDs references to which this NIC belongs - --> **NOTE:** At this time Network Interface <-> Application Gateway Backend Address Pool associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_application_gateway_backend_address_pool_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. - * `load_balancer_backend_address_pools_ids` - (Optional / **Deprecated**) List of Load Balancer Backend Address Pool IDs references to which this NIC belongs -> **NOTE:** At this time Network Interface <-> Load Balancer Backend Address Pool associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_backend_address_pool_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. From bf5cf315c9fe54f65f245213a561c69ec48bb88f Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 14 Feb 2020 14:55:32 +0100 Subject: [PATCH 03/17] r/network_interface: removing the deprecated `application_security_group_ids` field --- .../network/resource_arm_network_interface.go | 35 ----- ...ication_security_group_association_test.go | 131 +++++++++++++----- .../resource_arm_network_interface_test.go | 60 -------- .../docs/r/network_interface.html.markdown | 4 - 4 files changed, 98 insertions(+), 132 deletions(-) diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index d137973c4c67..1c9ebd3dd106 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -133,18 +133,6 @@ func resourceArmNetworkInterface() *schema.Resource { Set: schema.HashString, }, - "application_security_group_ids": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Deprecated: "This field has been deprecated in favour of the `azurerm_network_interface_application_security_group_association` resource.", - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: azure.ValidateResourceID, - }, - Set: schema.HashString, - }, - "primary": { Type: schema.TypeBool, Optional: true, @@ -675,21 +663,6 @@ func expandNetworkInterfaceIPConfigurations(input []interface{}) ([]network.Inte properties.LoadBalancerInboundNatRules = &natRules } - if v, ok := data["application_security_group_ids"]; ok { - var securityGroups []network.ApplicationSecurityGroup - rules := v.(*schema.Set).List() - for _, r := range rules { - groupId := r.(string) - group := network.ApplicationSecurityGroup{ - ID: &groupId, - } - - securityGroups = append(securityGroups, group) - } - - properties.ApplicationSecurityGroups = &securityGroups - } - name := data["name"].(string) ipConfigs = append(ipConfigs, network.InterfaceIPConfiguration{ Name: &name, @@ -768,15 +741,7 @@ func flattenNetworkInterfaceIPConfigurations(input *[]network.InterfaceIPConfigu primary = *props.Primary } - securityGroups := make([]interface{}, 0) - if sgs := props.ApplicationSecurityGroups; sgs != nil { - for _, sg := range *sgs { - securityGroups = append(securityGroups, *sg.ID) - } - } - result = append(result, map[string]interface{}{ - "application_security_group_ids": schema.NewSet(schema.HashString, securityGroups), "load_balancer_backend_address_pools_ids": schema.NewSet(schema.HashString, lbBackendAddressPools), "load_balancer_inbound_nat_rules_ids": schema.NewSet(schema.HashString, lbInboundNatRules), "name": name, diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_application_security_group_association_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_application_security_group_association_test.go index 563976476bbf..bd544711f3e1 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_application_security_group_association_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_application_security_group_association_test.go @@ -27,6 +27,7 @@ func TestAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_basic(t * testCheckAzureRMNetworkInterfaceApplicationSecurityGroupAssociationExists(data.ResourceName), ), }, + data.ImportStep(), }, }) } @@ -79,6 +80,32 @@ func TestAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_deleted(t }) } +func TestAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_updateNIC(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface_application_security_group_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceApplicationSecurityGroupAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_updateNIC(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceApplicationSecurityGroupAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + func testCheckAzureRMNetworkInterfaceApplicationSecurityGroupAssociationExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Network.InterfacesClient @@ -185,51 +212,28 @@ func testCheckAzureRMNetworkInterfaceApplicationSecurityGroupAssociationDisappea } func testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_basic(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "internal" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.1.0/24" -} - -resource "azurerm_application_security_group" "test" { - name = "acctest-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} +%s resource "azurerm_network_interface" "test" { name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - application_security_group_ids = ["${azurerm_application_security_group.test.id}"] + name = "testconfiguration1" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" } } resource "azurerm_network_interface_application_security_group_association" "test" { - network_interface_id = "${azurerm_network_interface.test.id}" + network_interface_id = azurerm_network_interface.test.id ip_configuration_name = "testconfiguration1" - application_security_group_id = "${azurerm_application_security_group.test.id}" + application_security_group_id = azurerm_application_security_group.test.id } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } func testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_requiresImport(data acceptance.TestData) string { @@ -244,3 +248,64 @@ resource "azurerm_network_interface_application_security_group_association" "imp } `, template) } + +func testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_updateNIC(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + primary = true + } + + ip_configuration { + name = "testconfiguration2" + private_ip_address_version = "IPv6" + private_ip_address_allocation = "dynamic" + } +} + +resource "azurerm_network_interface_application_security_group_association" "test" { + network_interface_id = azurerm_network_interface.test.id + ip_configuration_name = "testconfiguration1" + application_security_group_id = azurerm_application_security_group.test.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNetworkInterfaceApplicationSecurityGroupAssociation_template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvn-%d" + address_space = ["10.0.0.0/16"] + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = "${azurerm_resource_group.test.name}" + virtual_network_name = "${azurerm_virtual_network.test.name}" + address_prefix = "10.0.1.0/24" +} + +resource "azurerm_application_security_group" "test" { + name = "acctest-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go index 8d35f133cbac..3dfa3f73ea01 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go @@ -326,24 +326,6 @@ func TestAccAzureRMNetworkInterface_bug7986(t *testing.T) { }) } -func TestAccAzureRMNetworkInterface_applicationSecurityGroups(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAzureRMNetworkInterface_applicationSecurityGroup(data), - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.application_security_group_ids.#", "1"), - ), - }, - }, - }) -} - func TestAccAzureRMNetworkInterface_importPublicIP(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") @@ -1195,45 +1177,3 @@ resource "azurerm_network_interface" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } - -func testAccAzureRMNetworkInterface_applicationSecurityGroup(data acceptance.TestData) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} - -resource "azurerm_application_security_group" "test" { - name = "acctest-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_network_interface" "test" { - name = "acctestnic-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - application_security_group_ids = ["${azurerm_application_security_group.test.id}"] - } -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) -} diff --git a/website/docs/r/network_interface.html.markdown b/website/docs/r/network_interface.html.markdown index ccd50c546012..25af5192cf89 100644 --- a/website/docs/r/network_interface.html.markdown +++ b/website/docs/r/network_interface.html.markdown @@ -98,10 +98,6 @@ The `ip_configuration` block supports: -> **NOTE:** At this time Network Interface <-> Load Balancer Inbound NAT Rule associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_nat_rule_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. -* `application_security_group_ids` - (Optional / **Deprecated**) List of Application Security Group IDs which should be attached to this NIC - --> **NOTE:** At this time Network Interface <-> Application Security Group associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_application_security_group_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. - * `primary` - (Optional) Is this the Primary Network Interface? If set to `true` this should be the first `ip_configuration` in the array. ## Attributes Reference From a024810d55ab9030b489d7f1b467bfe27f6917f9 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 14 Feb 2020 15:16:52 +0100 Subject: [PATCH 04/17] r/network_interface: removing the deprecated `load_balancer_inbound_nat_rules_ids` field --- .../network/resource_arm_network_interface.go | 49 ++-------- ...ork_interface_nat_rule_association_test.go | 98 +++++++++++++------ .../docs/r/network_interface.html.markdown | 4 - 3 files changed, 73 insertions(+), 78 deletions(-) diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index 1c9ebd3dd106..70f7246ead85 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -121,18 +121,6 @@ func resourceArmNetworkInterface() *schema.Resource { Set: schema.HashString, }, - "load_balancer_inbound_nat_rules_ids": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Deprecated: "This field has been deprecated in favour of the `azurerm_network_interface_nat_rule_association` resource.", - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: azure.ValidateResourceID, - }, - Set: schema.HashString, - }, - "primary": { Type: schema.TypeBool, Optional: true, @@ -648,21 +636,6 @@ func expandNetworkInterfaceIPConfigurations(input []interface{}) ([]network.Inte properties.LoadBalancerBackendAddressPools = &ids } - if v, ok := data["load_balancer_inbound_nat_rules_ids"]; ok { - var natRules []network.InboundNatRule - rules := v.(*schema.Set).List() - for _, r := range rules { - ruleId := r.(string) - rule := network.InboundNatRule{ - ID: &ruleId, - } - - natRules = append(natRules, rule) - } - - properties.LoadBalancerInboundNatRules = &natRules - } - name := data["name"].(string) ipConfigs = append(ipConfigs, network.InterfaceIPConfiguration{ Name: &name, @@ -729,13 +702,6 @@ func flattenNetworkInterfaceIPConfigurations(input *[]network.InterfaceIPConfigu } } - var lbInboundNatRules []interface{} - if props.LoadBalancerInboundNatRules != nil { - for _, rule := range *props.LoadBalancerInboundNatRules { - lbInboundNatRules = append(lbInboundNatRules, *rule.ID) - } - } - primary := false if props.Primary != nil { primary = *props.Primary @@ -743,14 +709,13 @@ func flattenNetworkInterfaceIPConfigurations(input *[]network.InterfaceIPConfigu result = append(result, map[string]interface{}{ "load_balancer_backend_address_pools_ids": schema.NewSet(schema.HashString, lbBackendAddressPools), - "load_balancer_inbound_nat_rules_ids": schema.NewSet(schema.HashString, lbInboundNatRules), - "name": name, - "primary": primary, - "private_ip_address": privateIPAddress, - "private_ip_address_allocation": string(props.PrivateIPAllocationMethod), - "private_ip_address_version": privateIPAddressVersion, - "public_ip_address_id": publicIPAddressId, - "subnet_id": subnetId, + "name": name, + "primary": primary, + "private_ip_address": privateIPAddress, + "private_ip_address_allocation": string(props.PrivateIPAllocationMethod), + "private_ip_address_version": privateIPAddressVersion, + "public_ip_address_id": publicIPAddressId, + "subnet_id": subnetId, }) } return result diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go index e10f617bfe01..2585bea6c433 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go @@ -27,6 +27,7 @@ func TestAccAzureRMNetworkInterfaceNATRuleAssociation_basic(t *testing.T) { testCheckAzureRMNetworkInterfaceNATRuleAssociationExists(data.ResourceName), ), }, + data.ImportStep(), }, }) } @@ -79,6 +80,32 @@ func TestAccAzureRMNetworkInterfaceNATRuleAssociation_deleted(t *testing.T) { }) } +func TestAccAzureRMNetworkInterfaceNATRuleAssociation_updateNIC(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface_nat_rule_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkInterfaceNATRuleAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceNATRuleAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterfaceNATRuleAssociation_updateNIC(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceNATRuleAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + func testCheckAzureRMNetworkInterfaceNATRuleAssociationExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Network.InterfacesClient @@ -185,6 +212,44 @@ func testCheckAzureRMNetworkInterfaceNATRuleAssociationDisappears(resourceName s } func testAccAzureRMNetworkInterfaceNATRuleAssociation_basic(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceNATRuleAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_network_interface_nat_rule_association" "test" { + network_interface_id = azurerm_network_interface.test.id + ip_configuration_name = "testconfiguration1" + nat_rule_id = azurerm_lb_nat_rule.test.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNetworkInterfaceNATRuleAssociation_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceNATRuleAssociation_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface_nat_rule_association" "import" { + network_interface_id = "${azurerm_network_interface_nat_rule_association.test.network_interface_id}" + ip_configuration_name = "${azurerm_network_interface_nat_rule_association.test.ip_configuration_name}" + nat_rule_id = "${azurerm_network_interface_nat_rule_association.test.nat_rule_id}" +} +`, template) +} + +func testAccAzureRMNetworkInterfaceNATRuleAssociation_template(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" @@ -232,36 +297,5 @@ resource "azurerm_lb_nat_rule" "test" { backend_port = 3389 frontend_ip_configuration_name = "primary" } - -resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - } -} - -resource "azurerm_network_interface_nat_rule_association" "test" { - network_interface_id = "${azurerm_network_interface.test.id}" - ip_configuration_name = "testconfiguration1" - nat_rule_id = "${azurerm_lb_nat_rule.test.id}" -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) -} - -func testAccAzureRMNetworkInterfaceNATRuleAssociation_requiresImport(data acceptance.TestData) string { - template := testAccAzureRMNetworkInterfaceNATRuleAssociation_basic(data) - return fmt.Sprintf(` -%s - -resource "azurerm_network_interface_nat_rule_association" "import" { - network_interface_id = "${azurerm_network_interface_nat_rule_association.test.network_interface_id}" - ip_configuration_name = "${azurerm_network_interface_nat_rule_association.test.ip_configuration_name}" - nat_rule_id = "${azurerm_network_interface_nat_rule_association.test.nat_rule_id}" -} -`, template) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } diff --git a/website/docs/r/network_interface.html.markdown b/website/docs/r/network_interface.html.markdown index 25af5192cf89..8c7d9542c57a 100644 --- a/website/docs/r/network_interface.html.markdown +++ b/website/docs/r/network_interface.html.markdown @@ -94,10 +94,6 @@ The `ip_configuration` block supports: -> **NOTE:** At this time Network Interface <-> Load Balancer Backend Address Pool associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_backend_address_pool_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. -* `load_balancer_inbound_nat_rules_ids` - (Optional / **Deprecated**) List of Load Balancer Inbound Nat Rules IDs involving this NIC - --> **NOTE:** At this time Network Interface <-> Load Balancer Inbound NAT Rule associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_nat_rule_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. - * `primary` - (Optional) Is this the Primary Network Interface? If set to `true` this should be the first `ip_configuration` in the array. ## Attributes Reference From 380f32c3cba42124866000e55492e642056483f5 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 14 Feb 2020 15:19:32 +0100 Subject: [PATCH 05/17] r/network_interface: removing the deprecated `load_balancer_backend_address_pools_ids` field --- .../network/resource_arm_network_interface.go | 35 ---- ...e_backend_address_pool_association_test.go | 130 +++++++++++---- .../resource_arm_network_interface_test.go | 151 ------------------ .../docs/r/network_interface.html.markdown | 4 - 4 files changed, 98 insertions(+), 222 deletions(-) diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index 70f7246ead85..135ed6669a65 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -109,18 +109,6 @@ func resourceArmNetworkInterface() *schema.Resource { ValidateFunc: azure.ValidateResourceIDOrEmpty, }, - "load_balancer_backend_address_pools_ids": { - Type: schema.TypeSet, - Optional: true, - Computed: true, - Deprecated: "This field has been deprecated in favour of the `azurerm_network_interface_backend_address_pool_association` resource.", - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: azure.ValidateResourceID, - }, - Set: schema.HashString, - }, - "primary": { Type: schema.TypeBool, Optional: true, @@ -621,21 +609,6 @@ func expandNetworkInterfaceIPConfigurations(input []interface{}) ([]network.Inte properties.Primary = utils.Bool(v.(bool)) } - if v, ok := data["load_balancer_backend_address_pools_ids"]; ok { - var ids []network.BackendAddressPool - pools := v.(*schema.Set).List() - for _, p := range pools { - poolId := p.(string) - id := network.BackendAddressPool{ - ID: &poolId, - } - - ids = append(ids, id) - } - - properties.LoadBalancerBackendAddressPools = &ids - } - name := data["name"].(string) ipConfigs = append(ipConfigs, network.InterfaceIPConfiguration{ Name: &name, @@ -695,20 +668,12 @@ func flattenNetworkInterfaceIPConfigurations(input *[]network.InterfaceIPConfigu publicIPAddressId = *props.PublicIPAddress.ID } - var lbBackendAddressPools []interface{} - if props.LoadBalancerBackendAddressPools != nil { - for _, pool := range *props.LoadBalancerBackendAddressPools { - lbBackendAddressPools = append(lbBackendAddressPools, *pool.ID) - } - } - primary := false if props.Primary != nil { primary = *props.Primary } result = append(result, map[string]interface{}{ - "load_balancer_backend_address_pools_ids": schema.NewSet(schema.HashString, lbBackendAddressPools), "name": name, "primary": primary, "private_ip_address": privateIPAddress, diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_backend_address_pool_association_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_backend_address_pool_association_test.go index 635796cfc426..ae067fb3fb8c 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_backend_address_pool_association_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_backend_address_pool_association_test.go @@ -27,6 +27,7 @@ func TestAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_basic(t *testin testCheckAzureRMNetworkInterfaceBackendAddressPoolAssociationExists(data.ResourceName), ), }, + data.ImportStep(), }, }) } @@ -79,6 +80,32 @@ func TestAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_deleted(t *test }) } +func TestAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_updateNIC(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface_backend_address_pool_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceBackendAddressPoolAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_updateNIC(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceBackendAddressPoolAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + func testCheckAzureRMNetworkInterfaceBackendAddressPoolAssociationExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Network.InterfacesClient @@ -185,6 +212,76 @@ func testCheckAzureRMNetworkInterfaceBackendAddressPoolAssociationDisappears(res } func testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_basic(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_network_interface_backend_address_pool_association" "test" { + network_interface_id = azurerm_network_interface.test.id + ip_configuration_name = "testconfiguration1" + backend_address_pool_id = azurerm_lb_backend_address_pool.test.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface_backend_address_pool_association" "import" { + network_interface_id = "${azurerm_network_interface_backend_address_pool_association.test.network_interface_id}" + ip_configuration_name = "${azurerm_network_interface_backend_address_pool_association.test.ip_configuration_name}" + backend_address_pool_id = "${azurerm_network_interface_backend_address_pool_association.test.backend_address_pool_id}" +} +`, template) +} + +func testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_updateNIC(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + primary = true + } + + ip_configuration { + name = "testconfiguration2" + private_ip_address_version = "IPv6" + private_ip_address_allocation = "dynamic" + } +} + +resource "azurerm_network_interface_backend_address_pool_association" "test" { + network_interface_id = azurerm_network_interface.test.id + ip_configuration_name = "testconfiguration1" + backend_address_pool_id = azurerm_lb_backend_address_pool.test.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_template(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" @@ -229,36 +326,5 @@ resource "azurerm_lb_backend_address_pool" "test" { loadbalancer_id = "${azurerm_lb.test.id}" name = "acctestpool" } - -resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - } -} - -resource "azurerm_network_interface_backend_address_pool_association" "test" { - network_interface_id = "${azurerm_network_interface.test.id}" - ip_configuration_name = "testconfiguration1" - backend_address_pool_id = "${azurerm_lb_backend_address_pool.test.id}" -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) -} - -func testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_requiresImport(data acceptance.TestData) string { - template := testAccAzureRMNetworkInterfaceBackendAddressPoolAssociation_basic(data) - return fmt.Sprintf(` -%s - -resource "azurerm_network_interface_backend_address_pool_association" "import" { - network_interface_id = "${azurerm_network_interface_backend_address_pool_association.test.network_interface_id}" - ip_configuration_name = "${azurerm_network_interface_backend_address_pool_association.test.ip_configuration_name}" - backend_address_pool_id = "${azurerm_network_interface_backend_address_pool_association.test.backend_address_pool_id}" -} -`, template) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go index 3dfa3f73ea01..05170566f5b4 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go @@ -212,25 +212,6 @@ func TestAccAzureRMNetworkInterface_enableAcceleratedNetworking(t *testing.T) { }) } -func TestAccAzureRMNetworkInterface_multipleLoadBalancers(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_network_interface", "test1") - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, - Steps: []resource.TestStep{ - { - Config: testAccAzureRMNetworkInterface_multipleLoadBalancers(data), - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test1"), - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test2"), - ), - }, - }, - }) -} - func TestAccAzureRMNetworkInterface_withTags(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ @@ -899,138 +880,6 @@ resource "azurerm_network_interface" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } -func testAccAzureRMNetworkInterface_multipleLoadBalancers(data acceptance.TestData) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} - -resource "azurerm_public_ip" "testext" { - name = "acctestpip-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - allocation_method = "Static" -} - -resource "azurerm_lb" "testext" { - name = "acctestlb-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - frontend_ip_configuration { - name = "publicipext" - public_ip_address_id = "${azurerm_public_ip.testext.id}" - } -} - -resource "azurerm_lb_backend_address_pool" "testext" { - name = "testbackendpoolext" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - loadbalancer_id = "${azurerm_lb.testext.id}" -} - -resource "azurerm_lb_nat_rule" "testext" { - name = "testnatruleext" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - loadbalancer_id = "${azurerm_lb.testext.id}" - protocol = "Tcp" - frontend_port = 3389 - backend_port = 3390 - frontend_ip_configuration_name = "publicipext" -} - -resource "azurerm_public_ip" "testint" { - name = "testpublicipint" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - allocation_method = "Static" -} - -resource "azurerm_lb" "testint" { - name = "testlbint" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - frontend_ip_configuration { - name = "publicipint" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - } -} - -resource "azurerm_lb_backend_address_pool" "testint" { - name = "testbackendpoolint" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - loadbalancer_id = "${azurerm_lb.testint.id}" -} - -resource "azurerm_lb_nat_rule" "testint" { - name = "testnatruleint" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - loadbalancer_id = "${azurerm_lb.testint.id}" - protocol = "Tcp" - frontend_port = 3389 - backend_port = 3391 - frontend_ip_configuration_name = "publicipint" -} - -resource "azurerm_network_interface" "test1" { - name = "acctestnic1-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - enable_ip_forwarding = true - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - - load_balancer_backend_address_pools_ids = [ - "${azurerm_lb_backend_address_pool.testext.id}", - "${azurerm_lb_backend_address_pool.testint.id}", - ] - } -} - -resource "azurerm_network_interface" "test2" { - name = "acctestnic2-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - enable_ip_forwarding = true - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - - load_balancer_inbound_nat_rules_ids = [ - "${azurerm_lb_nat_rule.testext.id}", - "${azurerm_lb_nat_rule.testint.id}", - ] - } -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) -} - func testAccAzureRMNetworkInterface_bug7986(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/website/docs/r/network_interface.html.markdown b/website/docs/r/network_interface.html.markdown index 8c7d9542c57a..d2045d5c50d6 100644 --- a/website/docs/r/network_interface.html.markdown +++ b/website/docs/r/network_interface.html.markdown @@ -90,10 +90,6 @@ The `ip_configuration` block supports: * `public_ip_address_id` - (Optional) Reference to a Public IP Address to associate with this NIC -* `load_balancer_backend_address_pools_ids` - (Optional / **Deprecated**) List of Load Balancer Backend Address Pool IDs references to which this NIC belongs - --> **NOTE:** At this time Network Interface <-> Load Balancer Backend Address Pool associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_backend_address_pool_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. - * `primary` - (Optional) Is this the Primary Network Interface? If set to `true` this should be the first `ip_configuration` in the array. ## Attributes Reference From 367ca5b1a04d938b021c5147cd1f677499aa2893 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 14 Feb 2020 15:26:05 +0100 Subject: [PATCH 06/17] r/network_interface_nat_rule_association: commiting the missing method --- ...ork_interface_nat_rule_association_test.go | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go index 2585bea6c433..57c369aa6ce7 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go @@ -249,6 +249,38 @@ resource "azurerm_network_interface_nat_rule_association" "import" { `, template) } +func testAccAzureRMNetworkInterfaceNATRuleAssociation_updateNIC(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceNATRuleAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + primary = true + } + + ip_configuration { + name = "testconfiguration2" + private_ip_address_version = "IPv6" + private_ip_address_allocation = "dynamic" + } +} + +resource "azurerm_network_interface_nat_rule_association" "test" { + network_interface_id = azurerm_network_interface.test.id + ip_configuration_name = "testconfiguration1" + nat_rule_id = azurerm_lb_nat_rule.test.id +} +`, template, data.RandomInteger) +} + func testAccAzureRMNetworkInterfaceNATRuleAssociation_template(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { From f50eb8d9341deeb7c57d3bd3b591960d78304ebd Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 14 Feb 2020 17:59:29 +0100 Subject: [PATCH 07/17] r/network_interface: loading the existing nic details during a delta update --- .../network/resource_arm_network_interface.go | 47 ++++++++----------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index 135ed6669a65..0789e212bfea 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -51,7 +51,6 @@ func resourceArmNetworkInterface() *schema.Resource { "resource_group_name": azure.SchemaResourceGroupName(), - // NOTE: does this want it's own association resource? "network_security_group_id": { Type: schema.TypeString, Optional: true, @@ -315,16 +314,20 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) locks.ByName(name, networkInterfaceResourceName) defer locks.UnlockByName(name, networkInterfaceResourceName) + // first get the existing one so that we can pull things as needed + existing, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) + } + location := azure.NormalizeLocation(d.Get("location").(string)) update := network.Interface{ - Name: utils.String(name), - Location: utils.String(location), + Name: utils.String(name), + Location: utils.String(location), + InterfacePropertiesFormat: &network.InterfacePropertiesFormat{}, } if d.HasChange("dns_servers") { - if update.InterfacePropertiesFormat == nil { - update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} - } if update.InterfacePropertiesFormat.DNSSettings == nil { update.InterfacePropertiesFormat.DNSSettings = &network.InterfaceDNSSettings{} } @@ -336,25 +339,14 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) } if d.HasChange("enable_accelerated_networking") { - if update.InterfacePropertiesFormat == nil { - update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} - } - update.InterfacePropertiesFormat.EnableAcceleratedNetworking = utils.Bool(d.Get("enable_accelerated_networking").(bool)) } if d.HasChange("enable_ip_forwarding") { - if update.InterfacePropertiesFormat == nil { - update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} - } - update.InterfacePropertiesFormat.EnableIPForwarding = utils.Bool(d.Get("enable_ip_forwarding").(bool)) } if d.HasChange("internal_dns_name_label") { - if update.InterfacePropertiesFormat == nil { - update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} - } if update.InterfacePropertiesFormat.DNSSettings == nil { update.InterfacePropertiesFormat.DNSSettings = &network.InterfaceDNSSettings{} } @@ -363,10 +355,6 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) } if d.HasChange("ip_configuration") { - if update.InterfacePropertiesFormat == nil { - update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} - } - ipConfigsRaw := d.Get("ip_configuration").([]interface{}) ipConfigs, err := expandNetworkInterfaceIPConfigurations(ipConfigsRaw) if err != nil { @@ -381,16 +369,19 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) defer lockingDetails.unlock() update.InterfacePropertiesFormat.IPConfigurations = &ipConfigs + } else { + update.InterfacePropertiesFormat.IPConfigurations = existing.InterfacePropertiesFormat.IPConfigurations } if d.HasChange("network_security_group_id") { - if update.InterfacePropertiesFormat == nil { - update.InterfacePropertiesFormat = &network.InterfacePropertiesFormat{} - } - - update.InterfacePropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{ - ID: utils.String(d.Get("network_security_group_id").(string)), - } + update.InterfacePropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{} + if networkSecurityGroupId := d.Get("network_security_group_id").(string); networkSecurityGroupId != "" { + update.InterfacePropertiesFormat.NetworkSecurityGroup.ID = utils.String(networkSecurityGroupId) + } else { + update.InterfacePropertiesFormat.NetworkSecurityGroup = nil + } + } else { + update.InterfacePropertiesFormat.NetworkSecurityGroup = existing.InterfacePropertiesFormat.NetworkSecurityGroup } if d.HasChange("tags") { From 34340db17924ea5709f2d174ca5a1f1240496cf3 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Feb 2020 08:37:55 +0100 Subject: [PATCH 08/17] New Resource: `azurerm_network_interface_security_group_association` This commit introduces a new resource for linking a Network Interface and a Network Security Group which is required to work around a dependency issue in the Azure API where the NSG must be detached in order to be able to delete dependent resources. --- .../azuresdkhacks/network_interface.go | 105 +++++++ azurerm/internal/azuresdkhacks/notes.go | 15 + ...ork_security_group_association_resource.go | 218 ++++++++++++++ .../internal/services/network/registration.go | 1 + ...ecurity_group_association_resource_test.go | 281 ++++++++++++++++++ ...e_security_group_association.html.markdown | 91 ++++++ 6 files changed, 711 insertions(+) create mode 100644 azurerm/internal/azuresdkhacks/network_interface.go create mode 100644 azurerm/internal/azuresdkhacks/notes.go create mode 100644 azurerm/internal/services/network/network_interface_network_security_group_association_resource.go create mode 100644 azurerm/internal/services/network/tests/network_interface_network_security_group_association_resource_test.go create mode 100644 website/docs/r/network_interface_security_group_association.html.markdown diff --git a/azurerm/internal/azuresdkhacks/network_interface.go b/azurerm/internal/azuresdkhacks/network_interface.go new file mode 100644 index 000000000000..8f4c849d71de --- /dev/null +++ b/azurerm/internal/azuresdkhacks/network_interface.go @@ -0,0 +1,105 @@ +package azuresdkhacks + +import ( + "bytes" + "context" + "encoding/json" + "io/ioutil" + "net/http" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-09-01/network" + "github.com/Azure/go-autorest/autorest" +) + +// UpdateNetworkInterfaceAllowingRemovalOfNSG patches our way around a design flaw in the Azure +// Resource Manager API <-> Azure SDK for Go where it's not possible to remove a Network Security Group +func UpdateNetworkInterfaceAllowingRemovalOfNSG(ctx context.Context, client *network.InterfacesClient, resourceGroupName string, networkInterfaceName string, parameters network.Interface) (result network.InterfacesCreateOrUpdateFuture, err error) { + req, err := updateNetworkInterfaceAllowingRemovalOfNSGPreparer(ctx, client, resourceGroupName, networkInterfaceName, parameters) + if err != nil { + err = autorest.NewErrorWithError(err, "network.InterfacesClient", "CreateOrUpdate", nil, "Failure preparing request") + return + } + + result, err = client.CreateOrUpdateSender(req) + if err != nil { + err = autorest.NewErrorWithError(err, "network.InterfacesClient", "CreateOrUpdate", result.Response(), "Failure sending request") + return + } + + return +} + +// updateNetworkInterfaceAllowingRemovalOfNSGPreparer prepares the CreateOrUpdate request but applies the +// necessary patches to be able to remove the NSG if required +func updateNetworkInterfaceAllowingRemovalOfNSGPreparer(ctx context.Context, client *network.InterfacesClient, resourceGroupName string, networkInterfaceName string, parameters network.Interface) (*http.Request, error) { + pathParameters := map[string]interface{}{ + "networkInterfaceName": autorest.Encode("path", networkInterfaceName), + "resourceGroupName": autorest.Encode("path", resourceGroupName), + "subscriptionId": autorest.Encode("path", client.SubscriptionID), + } + + const APIVersion = "2019-09-01" + queryParameters := map[string]interface{}{ + "api-version": APIVersion, + } + + parameters.Etag = nil + preparer := autorest.CreatePreparer( + autorest.AsContentType("application/json; charset=utf-8"), + autorest.AsPut(), + autorest.WithBaseURL(client.BaseURI), + autorest.WithPathParameters("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/networkInterfaces/{networkInterfaceName}", pathParameters), + withJsonWorkingAroundTheBrokenNetworkAPI(parameters), + autorest.WithQueryParameters(queryParameters)) + return preparer.Prepare((&http.Request{}).WithContext(ctx)) +} + +func withJsonWorkingAroundTheBrokenNetworkAPI(v network.Interface) autorest.PrepareDecorator { + return func(p autorest.Preparer) autorest.Preparer { + return autorest.PreparerFunc(func(r *http.Request) (*http.Request, error) { + r, err := p.Prepare(r) + if err == nil { + b, err := json.Marshal(v) + if err == nil { + // there's a few fields which can be intentionally set to nil - as such here we need to check if they should be nil and force them to be nil + var out map[string]interface{} + if err := json.Unmarshal(b, &out); err != nil { + return r, err + } + + // apply the hack + out = patchNICUpdateAPIIssue(v, out) + + // then reserialize it as needed + b, err = json.Marshal(out) + if err == nil { + r.ContentLength = int64(len(b)) + r.Body = ioutil.NopCloser(bytes.NewReader(b)) + } + } + } + return r, err + }) + } +} + +func patchNICUpdateAPIIssue(nic network.Interface, input map[string]interface{}) map[string]interface{} { + if nic.InterfacePropertiesFormat == nil { + return input + } + + output := input + + if v, ok := output["properties"]; ok { + props := v.(map[string]interface{}) + + if nic.InterfacePropertiesFormat.NetworkSecurityGroup == nil { + var hack *string // a nil-pointered string + props["networkSecurityGroup"] = hack + } + + output["properties"] = props + } + + return output +} diff --git a/azurerm/internal/azuresdkhacks/notes.go b/azurerm/internal/azuresdkhacks/notes.go new file mode 100644 index 000000000000..a1612ed8dad8 --- /dev/null +++ b/azurerm/internal/azuresdkhacks/notes.go @@ -0,0 +1,15 @@ +package azuresdkhacks + +// There's a functional difference that exists between the Azure SDK for Go and Azure Resource Manager API +// where when performing a delta update unchanged fields are omited from the response when they could +// also have a legitimate value of `null` (to remove/disable a sub-block). +// +// Ultimately the Azure SDK for Go has opted to serialise structs with `json:"name,omitempty"` which +// means that this value will be omited if nil to allow for delta updates - however this means there's +// no means of removing/resetting a value of a nested object once provided since a `nil` object will be +// reset +// +// As such this set of well intentioned hacks is intended to force this behaviour where necessary. +// +// It's worth noting that these hacks are a last resort and the Swagger/API/SDK should almost always be +// fixed instead. diff --git a/azurerm/internal/services/network/network_interface_network_security_group_association_resource.go b/azurerm/internal/services/network/network_interface_network_security_group_association_resource.go new file mode 100644 index 000000000000..b71f335adb04 --- /dev/null +++ b/azurerm/internal/services/network/network_interface_network_security_group_association_resource.go @@ -0,0 +1,218 @@ +package network + +import ( + "fmt" + "log" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-09-01/network" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/azuresdkhacks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmNetworkInterfaceSecurityGroupAssociation() *schema.Resource { + return &schema.Resource{ + Create: resourceArmNetworkInterfaceSecurityGroupAssociationCreate, + Read: resourceArmNetworkInterfaceSecurityGroupAssociationRead, + Delete: resourceArmNetworkInterfaceSecurityGroupAssociationDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "network_interface_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: azure.ValidateResourceID, + }, + + "network_security_group_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: azure.ValidateResourceID, + }, + }, + } +} + +func resourceArmNetworkInterfaceSecurityGroupAssociationCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.InterfacesClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for Network Interface <-> Network Security Group Association creation.") + + networkInterfaceId := d.Get("network_interface_id").(string) + networkSecurityGroupId := d.Get("network_security_group_id").(string) + + nicId, err := azure.ParseAzureResourceID(networkInterfaceId) + if err != nil { + return err + } + + networkInterfaceName := nicId.Path["networkInterfaces"] + resourceGroup := nicId.ResourceGroup + + locks.ByName(networkInterfaceName, networkInterfaceResourceName) + defer locks.UnlockByName(networkInterfaceName, networkInterfaceResourceName) + + nsgId, err := azure.ParseAzureResourceID(networkSecurityGroupId) + if err != nil { + return err + } + nsgName := nsgId.Path["networkSecurityGroups"] + + locks.ByName(nsgName, networkSecurityGroupResourceName) + defer locks.UnlockByName(nsgName, networkSecurityGroupResourceName) + + read, err := client.Get(ctx, resourceGroup, networkInterfaceName, "") + if err != nil { + if utils.ResponseWasNotFound(read.Response) { + return fmt.Errorf("Network Interface %q (Resource Group %q) was not found!", networkInterfaceName, resourceGroup) + } + + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err) + } + + props := read.InterfacePropertiesFormat + if props == nil { + return fmt.Errorf("Error: `properties` was nil for Network Interface %q (Resource Group %q)", networkInterfaceName, resourceGroup) + } + + // first double-check it doesn't exist + resourceId := fmt.Sprintf("%s|%s", networkInterfaceId, networkSecurityGroupId) + if features.ShouldResourcesBeImported() { + if props.NetworkSecurityGroup != nil { + return tf.ImportAsExistsError("azurerm_network_interface_security_group_association", resourceGroup) + } + } + + props.NetworkSecurityGroup = &network.SecurityGroup{ + ID: utils.String(networkSecurityGroupId), + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, networkInterfaceName, read) + if err != nil { + return fmt.Errorf("Error updating Security Group Association for Network Interface %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for completion of Security Group Association for NIC %q (Resource Group %q): %+v", networkInterfaceName, resourceGroup, err) + } + + d.SetId(resourceId) + + return resourceArmNetworkInterfaceSecurityGroupAssociationRead(d, meta) +} + +func resourceArmNetworkInterfaceSecurityGroupAssociationRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.InterfacesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + splitId := strings.Split(d.Id(), "|") + if len(splitId) != 2 { + return fmt.Errorf("Expected ID to be in the format {networkInterfaceId}|{networkSecurityGroupId} but got %q", d.Id()) + } + + nicID, err := azure.ParseAzureResourceID(splitId[0]) + if err != nil { + return err + } + + name := nicID.Path["networkInterfaces"] + resourceGroup := nicID.ResourceGroup + + read, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + if utils.ResponseWasNotFound(read.Response) { + return fmt.Errorf("Network Interface %q (Resource Group %q) was not found!", name, resourceGroup) + } + + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + props := read.InterfacePropertiesFormat + if props == nil { + return fmt.Errorf("Error: `properties` was nil for Network Interface %q (Resource Group %q)", name, resourceGroup) + } + + if props.NetworkSecurityGroup == nil || props.NetworkSecurityGroup.ID == nil { + log.Printf("Network Interface %q (Resource Group %q) doesn't have a Security Group attached - removing from state!", name, resourceGroup) + d.SetId("") + return nil + } + + d.Set("network_interface_id", read.ID) + + // nil-checked above + d.Set("network_security_group_id", props.NetworkSecurityGroup.ID) + + return nil +} + +func resourceArmNetworkInterfaceSecurityGroupAssociationDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Network.InterfacesClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + splitId := strings.Split(d.Id(), "|") + if len(splitId) != 2 { + return fmt.Errorf("Expected ID to be in the format {networkInterfaceId}/{networkSecurityGroup} but got %q", d.Id()) + } + + nicID, err := azure.ParseAzureResourceID(splitId[0]) + if err != nil { + return err + } + + name := nicID.Path["networkInterfaces"] + resourceGroup := nicID.ResourceGroup + + locks.ByName(name, networkInterfaceResourceName) + defer locks.UnlockByName(name, networkInterfaceResourceName) + + read, err := client.Get(ctx, resourceGroup, name, "") + if err != nil { + if utils.ResponseWasNotFound(read.Response) { + return fmt.Errorf("Network Interface %q (Resource Group %q) was not found!", name, resourceGroup) + } + + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + props := read.InterfacePropertiesFormat + if props == nil { + return fmt.Errorf("Error: `properties` was nil for Network Interface %q (Resource Group %q)", name, resourceGroup) + } + + props.NetworkSecurityGroup = nil + read.InterfacePropertiesFormat = props + + future, err := azuresdkhacks.UpdateNetworkInterfaceAllowingRemovalOfNSG(ctx, client, resourceGroup, name, read) + if err != nil { + return fmt.Errorf("Error updating Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if err := future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for update of Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + return nil +} diff --git a/azurerm/internal/services/network/registration.go b/azurerm/internal/services/network/registration.go index fc30e925d99b..3209c66a5d48 100644 --- a/azurerm/internal/services/network/registration.go +++ b/azurerm/internal/services/network/registration.go @@ -71,6 +71,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_network_interface_application_security_group_association": resourceArmNetworkInterfaceApplicationSecurityGroupAssociation(), "azurerm_network_interface_backend_address_pool_association": resourceArmNetworkInterfaceBackendAddressPoolAssociation(), "azurerm_network_interface_nat_rule_association": resourceArmNetworkInterfaceNatRuleAssociation(), + "azurerm_network_interface_security_group_association": resourceArmNetworkInterfaceSecurityGroupAssociation(), "azurerm_network_packet_capture": resourceArmNetworkPacketCapture(), "azurerm_network_profile": resourceArmNetworkProfile(), "azurerm_packet_capture": resourceArmPacketCapture(), diff --git a/azurerm/internal/services/network/tests/network_interface_network_security_group_association_resource_test.go b/azurerm/internal/services/network/tests/network_interface_network_security_group_association_resource_test.go new file mode 100644 index 000000000000..1ad3e382435b --- /dev/null +++ b/azurerm/internal/services/network/tests/network_interface_network_security_group_association_resource_test.go @@ -0,0 +1,281 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/azuresdkhacks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" +) + +func TestAccAzureRMNetworkInterfaceSecurityGroupAssociation_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface_security_group_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkInterfaceSecurityGroupAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceSecurityGroupAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMNetworkInterfaceSecurityGroupAssociation_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + data := acceptance.BuildTestData(t, "azurerm_network_interface_security_group_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkInterfaceSecurityGroupAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceSecurityGroupAssociationExists(data.ResourceName), + ), + }, + { + Config: testAccAzureRMNetworkInterfaceSecurityGroupAssociation_requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_network_interface_security_group_association"), + }, + }, + }) +} + +func TestAccAzureRMNetworkInterfaceSecurityGroupAssociation_deleted(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface_security_group_association", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkInterfaceSecurityGroupAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceSecurityGroupAssociationExists(data.ResourceName), + testCheckAzureRMNetworkInterfaceSecurityGroupAssociationDisappears(data.ResourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAzureRMNetworkInterfaceSecurityGroupAssociation_updateNIC(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface_security_group_association", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + // intentional as this is a Virtual Resource + CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkInterfaceSecurityGroupAssociation_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceSecurityGroupAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterfaceSecurityGroupAssociation_updateNIC(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceSecurityGroupAssociationExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func testCheckAzureRMNetworkInterfaceSecurityGroupAssociationExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Network.InterfacesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + nicID, err := azure.ParseAzureResourceID(rs.Primary.Attributes["network_interface_id"]) + if err != nil { + return err + } + + nicName := nicID.Path["networkInterfaces"] + resourceGroup := nicID.ResourceGroup + networkSecurityGroupId := rs.Primary.Attributes["network_security_group_id"] + + read, err := client.Get(ctx, resourceGroup, nicName, "") + if err != nil { + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", nicName, resourceGroup, err) + } + + found := false + if read.InterfacePropertiesFormat != nil { + if read.InterfacePropertiesFormat.NetworkSecurityGroup != nil && read.InterfacePropertiesFormat.NetworkSecurityGroup.ID != nil { + found = *read.InterfacePropertiesFormat.NetworkSecurityGroup.ID == networkSecurityGroupId + } + } + if !found { + return fmt.Errorf("Association between NIC %q and Network Security Group %q was not found!", nicName, networkSecurityGroupId) + } + + return nil + } +} + +func testCheckAzureRMNetworkInterfaceSecurityGroupAssociationDisappears(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Network.InterfacesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + nicID, err := azure.ParseAzureResourceID(rs.Primary.Attributes["network_interface_id"]) + if err != nil { + return err + } + + nicName := nicID.Path["networkInterfaces"] + resourceGroup := nicID.ResourceGroup + + read, err := client.Get(ctx, resourceGroup, nicName, "") + if err != nil { + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", nicName, resourceGroup, err) + } + + read.InterfacePropertiesFormat.NetworkSecurityGroup = nil + + future, err := azuresdkhacks.UpdateNetworkInterfaceAllowingRemovalOfNSG(ctx, client, resourceGroup, nicName, read) + if err != nil { + return fmt.Errorf("Error removing Network Security Group Association for Network Interface %q (Resource Group %q): %+v", nicName, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for removal of Network Security Group Association for NIC %q (Resource Group %q): %+v", nicName, resourceGroup, err) + } + + return nil + } +} + +func testAccAzureRMNetworkInterfaceSecurityGroupAssociation_basic(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceSecurityGroupAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_network_interface_security_group_association" "test" { + network_interface_id = azurerm_network_interface.test.id + network_security_group_id = azurerm_network_security_group.test.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNetworkInterfaceSecurityGroupAssociation_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceSecurityGroupAssociation_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface_security_group_association" "import" { + network_interface_id = azurerm_network_interface_security_group_association.test.network_interface_id + network_security_group_id = azurerm_network_interface_security_group_association.test.network_security_group_id +} +`, template) +} + +func testAccAzureRMNetworkInterfaceSecurityGroupAssociation_updateNIC(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterfaceSecurityGroupAssociation_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + primary = true + } + + ip_configuration { + name = "testconfiguration2" + private_ip_address_version = "IPv6" + private_ip_address_allocation = "dynamic" + } +} + +resource "azurerm_network_interface_security_group_association" "test" { + network_interface_id = azurerm_network_interface.test.id + network_security_group_id = azurerm_network_security_group.test.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMNetworkInterfaceSecurityGroupAssociation_template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvn-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefix = "10.0.1.0/24" +} + +resource "azurerm_network_security_group" "test" { + name = "acctestnsg-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/website/docs/r/network_interface_security_group_association.html.markdown b/website/docs/r/network_interface_security_group_association.html.markdown new file mode 100644 index 000000000000..3bc138982a77 --- /dev/null +++ b/website/docs/r/network_interface_security_group_association.html.markdown @@ -0,0 +1,91 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_network_interface_security_group_association" +description: |- + Manages the association between a Network Interface and a Network Security Group. + +--- + +# azurerm_network_interface_security_group_association + +Manages the association between a Network Interface and a Network Security Group. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_virtual_network" "example" { + name = "example-network" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_subnet" "example" { + name = "internal" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name + address_prefix = "10.0.2.0/24" +} + +resource "azurerm_network_security_group" "example" { + name = "example-nsg" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_network_interface" "example" { + name = "example-nic" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.example.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_network_interface_security_group_association" "example" { + network_interface_id = azurerm_network_interface.example.id + network_security_group_id = azurerm_network_security_group.example.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `network_interface_id` - (Required) The ID of the Network Interface. Changing this forces a new resource to be created. + +* `network_security_group_id` - (Required) The ID of the Network Security Group which should be attached to the Network Interface. Changing this forces a new resource to be created. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The (Terraform specific) ID of the Association between the Network Interface and the Network Interface. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the association between the Network Interface and the Network Security Group. +* `update` - (Defaults to 30 minutes) Used when updating the association between the Network Interface and the Network Security Group. +* `read` - (Defaults to 5 minutes) Used when retrieving the association between the Network Interface and the Network Security Group. +* `delete` - (Defaults to 30 minutes) Used when deleting the association between the Network Interface and the Network Security Group. + +## Import + +Associations between Network Interfaces and Network Security Group can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_network_interface_security_group_association.association1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/microsoft.network/networkInterfaces/nic1/ipConfigurations/example|/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/networkSecurityGroups/group1 +``` + +-> **NOTE:** This ID is specific to Terraform - and is of the format `{networkInterfaceId}/|{networkSecurityGroupId}`. From 1a18b602c780be2853356b258a62176b46d85672 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Feb 2020 08:38:26 +0100 Subject: [PATCH 09/17] r/network_interface: applying properties managed in other resources to this resource --- .../network/resource_arm_network_interface.go | 203 +++++++++++++----- 1 file changed, 144 insertions(+), 59 deletions(-) diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index 0789e212bfea..a6b1bd6d987c 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -51,12 +51,6 @@ func resourceArmNetworkInterface() *schema.Resource { "resource_group_name": azure.SchemaResourceGroupName(), - "network_security_group_id": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: azure.ValidateResourceIDOrEmpty, - }, - "ip_configuration": { Type: schema.TypeList, Required: true, @@ -218,23 +212,6 @@ func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) locks.ByName(name, networkInterfaceResourceName) defer locks.UnlockByName(name, networkInterfaceResourceName) - if v, ok := d.GetOk("network_security_group_id"); ok { - nsgId := v.(string) - properties.NetworkSecurityGroup = &network.SecurityGroup{ - ID: &nsgId, - } - - parsedNsgID, err := azure.ParseAzureResourceID(nsgId) - if err != nil { - return fmt.Errorf("Error parsing Network Security Group ID %q: %+v", nsgId, err) - } - - networkSecurityGroupName := parsedNsgID.Path["networkSecurityGroups"] - - locks.ByName(networkSecurityGroupName, networkSecurityGroupResourceName) - defer locks.UnlockByName(networkSecurityGroupName, networkSecurityGroupResourceName) - } - dns, hasDns := d.GetOk("dns_servers") nameLabel, hasNameLabel := d.GetOk("internal_dns_name_label") if hasDns || hasNameLabel { @@ -259,7 +236,7 @@ func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("Error expanding `ip_configuration`: %+v", err) } - lockingDetails, err := determineResourcesToLockFromIPConfiguration(&ipConfigs) + lockingDetails, err := determineResourcesToLockFromIPConfiguration(ipConfigs) if err != nil { return fmt.Errorf("Error determing locking details: %+v", err) } @@ -267,8 +244,8 @@ func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) lockingDetails.lock() defer lockingDetails.unlock() - if len(ipConfigs) > 0 { - properties.IPConfigurations = &ipConfigs + if len(*ipConfigs) > 0 { + properties.IPConfigurations = ipConfigs } iface := network.Interface{ @@ -320,6 +297,13 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) } + if existing.InterfacePropertiesFormat == nil { + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): `properties` was nil", name, resourceGroup) + } + + // then pull out things we need to lock on + info := parseFieldsFromNetworkInterface(*existing.InterfacePropertiesFormat) + location := azure.NormalizeLocation(d.Get("location").(string)) update := network.Interface{ Name: utils.String(name), @@ -360,7 +344,7 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("Error expanding `ip_configuration`: %+v", err) } - lockingDetails, err := determineResourcesToLockFromIPConfiguration(&ipConfigs) + lockingDetails, err := determineResourcesToLockFromIPConfiguration(ipConfigs) if err != nil { return fmt.Errorf("Error determing locking details: %+v", err) } @@ -368,20 +352,12 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) lockingDetails.lock() defer lockingDetails.unlock() - update.InterfacePropertiesFormat.IPConfigurations = &ipConfigs - } else { - update.InterfacePropertiesFormat.IPConfigurations = existing.InterfacePropertiesFormat.IPConfigurations - } + // then map the fields managed in other resources back + ipConfigs = mapFieldsToNetworkInterface(ipConfigs, info) - if d.HasChange("network_security_group_id") { - update.InterfacePropertiesFormat.NetworkSecurityGroup = &network.SecurityGroup{} - if networkSecurityGroupId := d.Get("network_security_group_id").(string); networkSecurityGroupId != "" { - update.InterfacePropertiesFormat.NetworkSecurityGroup.ID = utils.String(networkSecurityGroupId) - } else { - update.InterfacePropertiesFormat.NetworkSecurityGroup = nil - } + update.InterfacePropertiesFormat.IPConfigurations = ipConfigs } else { - update.InterfacePropertiesFormat.NetworkSecurityGroup = existing.InterfacePropertiesFormat.NetworkSecurityGroup + update.InterfacePropertiesFormat.IPConfigurations = existing.InterfacePropertiesFormat.IPConfigurations } if d.HasChange("tags") { @@ -389,6 +365,9 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) update.Tags = tags.Expand(tagsRaw) } + // this can be managed in another resource, so just port it over + update.InterfacePropertiesFormat.NetworkSecurityGroup = existing.InterfacePropertiesFormat.NetworkSecurityGroup + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, update) if err != nil { return fmt.Errorf("Error updating Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) @@ -459,10 +438,6 @@ func resourceArmNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) e } } - networkSecurityGroupId := "" - if props.NetworkSecurityGroup != nil && props.NetworkSecurityGroup.ID != nil { - networkSecurityGroupId = *props.NetworkSecurityGroup.ID - } virtualMachineId := "" if props.VirtualMachine != nil && props.VirtualMachine.ID != nil { virtualMachineId = *props.VirtualMachine.ID @@ -480,7 +455,6 @@ func resourceArmNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) e d.Set("enable_accelerated_networking", resp.EnableAcceleratedNetworking) d.Set("internal_dns_name_label", internalDnsNameLabel) d.Set("mac_address", props.MacAddress) - d.Set("network_security_group_id", networkSecurityGroupId) d.Set("private_ip_address", primaryPrivateIPAddress) d.Set("virtual_machine_id", virtualMachineId) @@ -527,19 +501,6 @@ func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) } props := *existing.InterfacePropertiesFormat - if props.NetworkSecurityGroup != nil && props.NetworkSecurityGroup.ID != nil { - networkSecurityGroupId := *props.NetworkSecurityGroup.ID - parsedNsgID, err := azure.ParseAzureResourceID(networkSecurityGroupId) - if err != nil { - return fmt.Errorf("Error parsing Network Security Group ID %q: %+v", networkSecurityGroupId, err) - } - - networkSecurityGroupName := parsedNsgID.Path["networkSecurityGroups"] - - locks.ByName(networkSecurityGroupName, networkSecurityGroupResourceName) - defer locks.UnlockByName(networkSecurityGroupName, networkSecurityGroupResourceName) - } - lockingDetails, err := determineResourcesToLockFromIPConfiguration(props.IPConfigurations) if err != nil { return fmt.Errorf("Error determing locking details: %+v", err) @@ -560,7 +521,7 @@ func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) return nil } -func expandNetworkInterfaceIPConfigurations(input []interface{}) ([]network.InterfaceIPConfiguration, error) { +func expandNetworkInterfaceIPConfigurations(input []interface{}) (*[]network.InterfaceIPConfiguration, error) { ipConfigs := make([]network.InterfaceIPConfiguration, 0) for _, configRaw := range input { @@ -622,7 +583,7 @@ func expandNetworkInterfaceIPConfigurations(input []interface{}) ([]network.Inte } } - return ipConfigs, nil + return &ipConfigs, nil } func flattenNetworkInterfaceIPConfigurations(input *[]network.InterfaceIPConfiguration) []interface{} { @@ -696,3 +657,127 @@ func flattenNetworkInterfaceDnsServers(input *[]string) []string { } return output } + +type networkInterfaceUpdateInformation struct { + applicationGatewayBackendAddressPoolIDs []string + applicationSecurityGroupIDs []string + loadBalancerBackendAddressPoolIDs []string + loadBalancerInboundNatRuleIDs []string + networkSecurityGroupID string +} + +func parseFieldsFromNetworkInterface(input network.InterfacePropertiesFormat) networkInterfaceUpdateInformation { + networkSecurityGroupId := "" + if input.NetworkSecurityGroup != nil && input.NetworkSecurityGroup.ID != nil { + networkSecurityGroupId = *input.NetworkSecurityGroup.ID + } + + var mapToSlice = func(input map[string]struct{}) []string { + output := make([]string, 0) + + for id, _ := range input { + output = append(output, id) + } + + return output + } + + applicationSecurityGroupIds := make(map[string]struct{}, 0) + applicationGatewayBackendAddressPoolIds := make(map[string]struct{}, 0) + loadBalancerBackendAddressPoolIds := make(map[string]struct{}, 0) + loadBalancerInboundNatRuleIds := make(map[string]struct{}, 0) + + if input.IPConfigurations != nil { + for _, v := range *input.IPConfigurations { + if v.InterfaceIPConfigurationPropertiesFormat == nil { + continue + } + + props := *v.InterfaceIPConfigurationPropertiesFormat + if props.ApplicationSecurityGroups != nil { + for _, asg := range *props.ApplicationSecurityGroups { + if asg.ID != nil { + applicationSecurityGroupIds[*asg.ID] = struct{}{} + } + } + } + + if props.ApplicationGatewayBackendAddressPools != nil { + for _, pool := range *props.ApplicationGatewayBackendAddressPools { + if pool.ID != nil { + applicationGatewayBackendAddressPoolIds[*pool.ID] = struct{}{} + } + } + } + + if props.LoadBalancerBackendAddressPools != nil { + for _, pool := range *props.LoadBalancerBackendAddressPools { + if pool.ID != nil { + loadBalancerBackendAddressPoolIds[*pool.ID] = struct{}{} + } + } + } + + if props.LoadBalancerInboundNatRules != nil { + for _, rule := range *props.LoadBalancerInboundNatRules { + if rule.ID != nil { + loadBalancerInboundNatRuleIds[*rule.ID] = struct{}{} + } + } + } + } + } + + return networkInterfaceUpdateInformation{ + applicationGatewayBackendAddressPoolIDs: mapToSlice(applicationGatewayBackendAddressPoolIds), + applicationSecurityGroupIDs: mapToSlice(applicationSecurityGroupIds), + loadBalancerBackendAddressPoolIDs: mapToSlice(loadBalancerBackendAddressPoolIds), + loadBalancerInboundNatRuleIDs: mapToSlice(loadBalancerInboundNatRuleIds), + networkSecurityGroupID: networkSecurityGroupId, + } +} + +func mapFieldsToNetworkInterface(input *[]network.InterfaceIPConfiguration, info networkInterfaceUpdateInformation) *[]network.InterfaceIPConfiguration { + output := input + + applicationSecurityGroups := make([]network.ApplicationSecurityGroup, 0) + for _, id := range info.applicationSecurityGroupIDs { + applicationSecurityGroups = append(applicationSecurityGroups, network.ApplicationSecurityGroup{ + ID: utils.String(id), + }) + } + + applicationGatewayBackendAddressPools := make([]network.ApplicationGatewayBackendAddressPool, 0) + for _, id := range info.applicationGatewayBackendAddressPoolIDs { + applicationGatewayBackendAddressPools = append(applicationGatewayBackendAddressPools, network.ApplicationGatewayBackendAddressPool{ + ID: utils.String(id), + }) + } + + loadBalancerBackendAddressPools := make([]network.BackendAddressPool, 0) + for _, id := range info.loadBalancerBackendAddressPoolIDs { + loadBalancerBackendAddressPools = append(loadBalancerBackendAddressPools, network.BackendAddressPool{ + ID: utils.String(id), + }) + } + + loadBalancerInboundNatRules := make([]network.InboundNatRule, 0) + for _, id := range info.loadBalancerInboundNatRuleIDs { + loadBalancerInboundNatRules = append(loadBalancerInboundNatRules, network.InboundNatRule{ + ID: utils.String(id), + }) + } + + for _, config := range *output { + if config.InterfaceIPConfigurationPropertiesFormat == nil { + continue + } + + config.ApplicationSecurityGroups = &applicationSecurityGroups + config.ApplicationGatewayBackendAddressPools = &applicationGatewayBackendAddressPools + config.LoadBalancerBackendAddressPools = &loadBalancerBackendAddressPools + config.LoadBalancerInboundNatRules = &loadBalancerInboundNatRules + } + + return output +} From a99d908e20a083d33262a217e65d20b77ec44f70 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Feb 2020 08:40:41 +0100 Subject: [PATCH 10/17] spelling --- azurerm/internal/azuresdkhacks/notes.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/azuresdkhacks/notes.go b/azurerm/internal/azuresdkhacks/notes.go index a1612ed8dad8..f75c0ac1c827 100644 --- a/azurerm/internal/azuresdkhacks/notes.go +++ b/azurerm/internal/azuresdkhacks/notes.go @@ -1,11 +1,11 @@ package azuresdkhacks // There's a functional difference that exists between the Azure SDK for Go and Azure Resource Manager API -// where when performing a delta update unchanged fields are omited from the response when they could +// where when performing a delta update unchanged fields are omitted from the response when they could // also have a legitimate value of `null` (to remove/disable a sub-block). // // Ultimately the Azure SDK for Go has opted to serialise structs with `json:"name,omitempty"` which -// means that this value will be omited if nil to allow for delta updates - however this means there's +// means that this value will be omitted if nil to allow for delta updates - however this means there's // no means of removing/resetting a value of a nested object once provided since a `nil` object will be // reset // From cad4978e7f7bd6b670778660dff325a81d84e9b4 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Feb 2020 11:15:27 +0100 Subject: [PATCH 11/17] r/network_interface: updating the tests / rewriting the docs --- .../network/resource_arm_network_interface.go | 10 +- .../resource_arm_network_interface_test.go | 839 +++++++----------- .../docs/r/network_interface.html.markdown | 83 +- 3 files changed, 361 insertions(+), 571 deletions(-) diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index a6b1bd6d987c..899d4bbfba60 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -112,14 +112,13 @@ func resourceArmNetworkInterface() *schema.Resource { }, "dns_servers": { - Type: schema.TypeSet, + Type: schema.TypeList, Optional: true, Computed: true, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringIsNotEmpty, }, - Set: schema.HashString, }, "enable_accelerated_networking": { @@ -218,14 +217,13 @@ func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) dnsSettings := network.InterfaceDNSSettings{} if hasDns { - dnsRaw := dns.(*schema.Set).List() + dnsRaw := dns.([]interface{}) dns := expandNetworkInterfaceDnsServers(dnsRaw) dnsSettings.DNSServers = &dns } if hasNameLabel { - name_label := nameLabel.(string) - dnsSettings.InternalDNSNameLabel = &name_label + dnsSettings.InternalDNSNameLabel = utils.String(nameLabel.(string)) } properties.DNSSettings = &dnsSettings @@ -316,7 +314,7 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) update.InterfacePropertiesFormat.DNSSettings = &network.InterfaceDNSSettings{} } - dnsServersRaw := d.Get("dns_servers").(*schema.Set).List() + dnsServersRaw := d.Get("dns_servers").([]interface{}) dnsServers := expandNetworkInterfaceDnsServers(dnsServersRaw) update.InterfacePropertiesFormat.DNSSettings.DNSServers = &dnsServers diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go index 05170566f5b4..3ec528f8615a 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go @@ -12,7 +12,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func TestAccAzureRMNetworkInterface_disappears(t *testing.T) { +func TestAccAzureRMNetworkInterface_basic(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, @@ -23,20 +23,14 @@ func TestAccAzureRMNetworkInterface_disappears(t *testing.T) { Config: testAccAzureRMNetworkInterface_basic(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - testCheckAzureRMNetworkInterfaceDisappears(data.ResourceName), ), - ExpectNonEmptyPlan: true, }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_requiresImport(t *testing.T) { - if !features.ShouldResourcesBeImported() { - t.Skip("Skipping since resources aren't required to be imported") - return - } - +func TestAccAzureRMNetworkInterface_disappears(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, @@ -47,17 +41,15 @@ func TestAccAzureRMNetworkInterface_requiresImport(t *testing.T) { Config: testAccAzureRMNetworkInterface_basic(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + testCheckAzureRMNetworkInterfaceDisappears(data.ResourceName), ), - }, - { - Config: testAccAzureRMNetworkInterface_requiresImport(data), - ExpectError: acceptance.RequiresImportError("azurerm_network_interface"), + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccAzureRMNetworkInterface_basic(t *testing.T) { +func TestAccAzureRMNetworkInterface_dnsServers(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, @@ -65,7 +57,14 @@ func TestAccAzureRMNetworkInterface_basic(t *testing.T) { CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_basic(data), + Config: testAccAzureRMNetworkInterface_dnsServers(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterface_dnsServersUpdated(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), ), @@ -75,108 +74,122 @@ func TestAccAzureRMNetworkInterface_basic(t *testing.T) { }) } -func TestAccAzureRMNetworkInterface_setNetworkSecurityGroupId(t *testing.T) { +func TestAccAzureRMNetworkInterface_enableAcceleratedNetworking(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_basic(data), + // Enabled + Config: testAccAzureRMNetworkInterface_enableAcceleratedNetworking(data, true), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), ), }, + data.ImportStep(), + { + // Disabled + Config: testAccAzureRMNetworkInterface_enableAcceleratedNetworking(data, false), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + ), + }, + data.ImportStep(), { - Config: testAccAzureRMNetworkInterface_basicWithNetworkSecurityGroup(data), + // Enabled + Config: testAccAzureRMNetworkInterface_enableAcceleratedNetworking(data, true), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttrSet(data.ResourceName, "network_security_group_id"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_removeNetworkSecurityGroupId(t *testing.T) { +func TestAccAzureRMNetworkInterface_enableIPForwarding(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_basicWithNetworkSecurityGroup(data), + // Enabled + Config: testAccAzureRMNetworkInterface_enableIPForwarding(data, true), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), ), }, + data.ImportStep(), { - Config: testAccAzureRMNetworkInterface_basic(data), + // Disabled + Config: testAccAzureRMNetworkInterface_enableIPForwarding(data, false), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + // Enabled + Config: testAccAzureRMNetworkInterface_enableIPForwarding(data, true), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "network_security_group_id", ""), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_multipleSubnets(t *testing.T) { +func TestAccAzureRMNetworkInterface_internalDomainNameLabel(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_multipleSubnets(data), + Config: testAccAzureRMNetworkInterface_internalDomainNameLabel(data, "1"), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterface_internalDomainNameLabel(data, "2"), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.#", "2"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_multipleSubnetsPrimary(t *testing.T) { +func TestAccAzureRMNetworkInterface_ipv6(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_multipleSubnets(data), + Config: testAccAzureRMNetworkInterface_ipv6(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.primary", "true"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.name", "testconfiguration1"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.1.primary", "false"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.1.name", "testconfiguration2"), - ), - }, - { - Config: testAccAzureRMNetworkInterface_multipleSubnetsUpdatedPrimary(data), - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.primary", "true"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.name", "testconfiguration2"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.1.primary", "false"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.1.name", "testconfiguration1"), + resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.private_ip_address_version", "IPv4"), + resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.1.private_ip_address_version", "IPv6"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_enableIPForwarding(t *testing.T) { +func TestAccAzureRMNetworkInterface_multipleIPConfigurations(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, @@ -184,17 +197,17 @@ func TestAccAzureRMNetworkInterface_enableIPForwarding(t *testing.T) { CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_ipForwarding(data), + Config: testAccAzureRMNetworkInterface_multipleIPConfigurations(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "enable_ip_forwarding", "true"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_enableAcceleratedNetworking(t *testing.T) { +func TestAccAzureRMNetworkInterface_multipleIPConfigurationsSecondaryAsPrimary(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, @@ -202,17 +215,17 @@ func TestAccAzureRMNetworkInterface_enableAcceleratedNetworking(t *testing.T) { CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_acceleratedNetworking(data), + Config: testAccAzureRMNetworkInterface_multipleIPConfigurationsSecondaryAsPrimary(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "enable_accelerated_networking", "true"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_withTags(t *testing.T) { +func TestAccAzureRMNetworkInterface_publicIP(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, @@ -220,27 +233,36 @@ func TestAccAzureRMNetworkInterface_withTags(t *testing.T) { CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_withTags(data), + Config: testAccAzureRMNetworkInterface_publicIP(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterface_publicIPRemoved(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(data.ResourceName, "tags.environment", "Production"), - resource.TestCheckResourceAttr(data.ResourceName, "tags.cost_center", "MSFT"), ), }, + data.ImportStep(), { - Config: testAccAzureRMNetworkInterface_withTagsUpdate(data), + Config: testAccAzureRMNetworkInterface_publicIP(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "tags.%", "1"), - resource.TestCheckResourceAttr(data.ResourceName, "tags.environment", "staging"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_IPAddressesBug1286(t *testing.T) { +func TestAccAzureRMNetworkInterface_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, @@ -248,75 +270,81 @@ func TestAccAzureRMNetworkInterface_IPAddressesBug1286(t *testing.T) { CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_withIPAddresses(data), + Config: testAccAzureRMNetworkInterface_basic(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttrSet(data.ResourceName, "ip_configuration.0.private_ip_address"), - resource.TestCheckResourceAttrSet(data.ResourceName, "ip_configuration.0.public_ip_address_id"), ), }, { - Config: testAccAzureRMNetworkInterface_withIPAddressesUpdate(data), - Check: resource.ComposeTestCheckFunc( - testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttrSet(data.ResourceName, "ip_configuration.0.private_ip_address"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.public_ip_address_id", ""), - ), + Config: testAccAzureRMNetworkInterface_requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_network_interface"), }, }, }) } -func TestAccAzureRMNetworkInterface_IPAddressesFeature2543(t *testing.T) { +func TestAccAzureRMNetworkInterface_static(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_withIPv6Addresses(data), + Config: testAccAzureRMNetworkInterface_static(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.private_ip_address_version", "IPv4"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.1.private_ip_address_version", "IPv6"), - resource.TestCheckResourceAttrSet(data.ResourceName, "private_ip_address"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_bug7986(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_network_interface", "test1") - +func TestAccAzureRMNetworkInterface_tags(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_bug7986(data), + Config: testAccAzureRMNetworkInterface_tags(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterface_tagsUpdated(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test1"), - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test2"), + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_importPublicIP(t *testing.T) { +func TestAccAzureRMNetworkInterface_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_network_interface", "test") - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_publicIP(data), + Config: testAccAzureRMNetworkInterface_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMNetworkInterface_multipleIPConfigurations(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), + ), }, data.ImportStep(), }, @@ -335,11 +363,7 @@ func testCheckAzureRMNetworkInterfaceExists(resourceName string) resource.TestCh } name := rs.Primary.Attributes["name"] - resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] - if !hasResourceGroup { - return fmt.Errorf("Bad: no resource group found in state for availability set: %q", name) - } - + resourceGroup := rs.Primary.Attributes["resource_group_name"] resp, err := client.Get(ctx, resourceGroup, name, "") if err != nil { if utils.ResponseWasNotFound(resp.Response) { @@ -365,10 +389,7 @@ func testCheckAzureRMNetworkInterfaceDisappears(resourceName string) resource.Te } name := rs.Primary.Attributes["name"] - resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] - if !hasResourceGroup { - return fmt.Errorf("Bad: no resource group found in state for availability set: %q", name) - } + resourceGroup := rs.Primary.Attributes["resource_group_name"] future, err := client.Delete(ctx, resourceGroup, name) if err != nil { @@ -411,580 +432,350 @@ func testCheckAzureRMNetworkInterfaceDestroy(s *terraform.State) error { } func testAccAzureRMNetworkInterface_basic(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +%s resource "azurerm_network_interface" "test" { name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_requiresImport(data acceptance.TestData) string { - template := testAccAzureRMNetworkInterface_basic(data) +func testAccAzureRMNetworkInterface_dnsServers(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` %s -resource "azurerm_network_interface" "import" { - name = "${azurerm_network_interface.test.name}" - location = "${azurerm_network_interface.test.location}" - resource_group_name = "${azurerm_network_interface.test.resource_group_name}" +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + dns_servers = [ + "10.0.0.5", + "10.0.0.6" + ] ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } } -`, template) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_basicWithNetworkSecurityGroup(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_dnsServersUpdated(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} - -resource "azurerm_network_security_group" "test" { - name = "acctestnsg-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} +%s resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - network_security_group_id = "${azurerm_network_security_group.test.id}" + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + dns_servers = [ + "10.0.0.6", + "10.0.0.5" + ] ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_multipleSubnets(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_enableAcceleratedNetworking(data acceptance.TestData, enabled bool) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +%s resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - primary = true - } + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + enable_accelerated_networking = %t ip_configuration { - name = "testconfiguration2" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger, enabled) } -func testAccAzureRMNetworkInterface_multipleSubnetsUpdatedPrimary(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_enableIPForwarding(data acceptance.TestData, enabled bool) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +%s resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - ip_configuration { - name = "testconfiguration2" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - primary = true - } + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + enable_ip_forwarding = %t ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger, enabled) } -func testAccAzureRMNetworkInterface_ipForwarding(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_internalDomainNameLabel(data acceptance.TestData, suffix string) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +%s resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - enable_ip_forwarding = true + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + internal_dns_name_label = "acctestni-%s-%s" ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger, suffix, data.RandomString) } -func testAccAzureRMNetworkInterface_acceleratedNetworking(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_ipv6(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +%s resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - enable_ip_forwarding = false - enable_accelerated_networking = true + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" + primary = true } -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) -} -func testAccAzureRMNetworkInterface_withTags(data acceptance.TestData) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" + ip_configuration { + name = "secondary" + private_ip_address_allocation = "Dynamic" + private_ip_address_version = "IPv6" + } } - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" +`, template, data.RandomInteger) } -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +func testAccAzureRMNetworkInterface_multipleIPConfigurations(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) + return fmt.Sprintf(` +%s resource "azurerm_network_interface" "test" { name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" + primary = true } - tags = { - environment = "Production" - cost_center = "MSFT" + ip_configuration { + name = "secondary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_withTagsUpdate(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_multipleIPConfigurationsSecondaryAsPrimary(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +%s resource "azurerm_network_interface" "test" { name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } - tags = { - environment = "staging" + ip_configuration { + name = "secondary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + primary = true } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_withIPAddresses(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_publicIP(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_publicIPTemplate(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} - -resource "azurerm_public_ip" "test" { - name = "test-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - allocation_method = "Static" - domain_name_label = "${azurerm_resource_group.test.name}" -} +%s resource "azurerm_network_interface" "test" { name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Static" - private_ip_address = "10.0.2.9" - public_ip_address_id = "${azurerm_public_ip.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + public_ip_address_id = azurerm_public_ip.test.id } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_withIPAddressesUpdate(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_publicIPRemoved(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_publicIPTemplate(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} - -resource "azurerm_public_ip" "test" { - name = "test-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - allocation_method = "Static" - domain_name_label = "${azurerm_resource_group.test.name}" -} +%s resource "azurerm_network_interface" "test" { name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_withIPv6Addresses(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_publicIPTemplate(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%d" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctestvn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +%s resource "azurerm_public_ip" "test" { - name = "test-%d" + name = "acctestpublicip-%d" location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" allocation_method = "Static" - domain_name_label = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_network_interface" "test" { - name = "acctestni-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "dynamic" - primary = true - } - - ip_configuration { - name = "testconfiguration2" - private_ip_address_version = "IPv6" - private_ip_address_allocation = "dynamic" - } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_bug7986(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_basic(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctest-%d" - location = "%s" -} +%s -resource "azurerm_network_security_group" "test" { - name = "acctest-%d-nsg" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" +resource "azurerm_network_interface" "import" { + name = azurerm_network_interface.test.name + location = azurerm_network_interface.test.location + resource_group_name = azurerm_network_interface.test.resource_group_name - tags = { - environment = "Production" + ip_configuration { + name = "primary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" } } - -resource "azurerm_network_security_rule" "test1" { - name = "test1" - priority = 101 - direction = "Outbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "*" - source_address_prefix = "*" - destination_address_prefix = "*" - resource_group_name = "${azurerm_resource_group.test.name}" - network_security_group_name = "${azurerm_network_security_group.test.name}" +`, template) } -resource "azurerm_network_security_rule" "test2" { - name = "test2" - priority = 102 - direction = "Outbound" - access = "Allow" - protocol = "Tcp" - source_port_range = "*" - destination_port_range = "*" - source_address_prefix = "*" - destination_address_prefix = "*" - resource_group_name = "${azurerm_resource_group.test.name}" - network_security_group_name = "${azurerm_network_security_group.test.name}" -} +func testAccAzureRMNetworkInterface_static(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) + return fmt.Sprintf(` +%s -resource "azurerm_public_ip" "test" { - name = "acctest-%d-pip" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - allocation_method = "Dynamic" +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name - tags = { - environment = "Production" + ip_configuration { + name = "primary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Static" + private_ip_address = "10.0.2.15" } } - -resource "azurerm_virtual_network" "test" { - name = "acctest-%d-vn" - address_space = ["10.0.0.0/16"] - resource_group_name = "${azurerm_resource_group.test.name}" - location = "${azurerm_resource_group.test.location}" +`, template, data.RandomInteger) } -resource "azurerm_subnet" "test" { - name = "first" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.2.0/24" -} +func testAccAzureRMNetworkInterface_tags(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) + return fmt.Sprintf(` +%s -resource "azurerm_network_interface" "test1" { - name = "acctest-%d-nic1" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } tags = { - environment = "staging" + Hello = "World" } } +`, template, data.RandomInteger) +} -resource "azurerm_network_interface" "test2" { - name = "acctest-%d-nic2" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" +func testAccAzureRMNetworkInterface_tagsUpdated(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" } tags = { - environment = "staging" + Hello = "World" + Elephants = "Five" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_publicIP(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_template(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { name = "acctestRG-%d" @@ -993,36 +784,16 @@ resource "azurerm_resource_group" "test" { resource "azurerm_virtual_network" "test" { name = "acctestvn-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" } resource "azurerm_subnet" "test" { - name = "testsubnet" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" + name = "internal" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name address_prefix = "10.0.2.0/24" } - -resource "azurerm_public_ip" "testext" { - name = "acctestip-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - allocation_method = "Static" -} - -resource "azurerm_network_interface" "test" { - name = "acctestnic-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - public_ip_address_id = "${azurerm_public_ip.testext.id}" - } -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } diff --git a/website/docs/r/network_interface.html.markdown b/website/docs/r/network_interface.html.markdown index d2045d5c50d6..97e05d62d827 100644 --- a/website/docs/r/network_interface.html.markdown +++ b/website/docs/r/network_interface.html.markdown @@ -3,50 +3,46 @@ subcategory: "Network" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_network_interface" description: |- - Manages a Network Interface located in a Virtual Network, usually attached to a Virtual Machine. + Manages a Network Interface. --- # azurerm_network_interface -Manages a Network Interface located in a Virtual Network, usually attached to a Virtual Machine. +Manages a Network Interface. ## Example Usage ```hcl resource "azurerm_resource_group" "example" { - name = "acceptanceTestResourceGroup1" - location = "West US" + name = "example-resources" + location = "West Europe" } resource "azurerm_virtual_network" "example" { - name = "acceptanceTestVirtualNetwork1" + name = "example-network" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.example.location resource_group_name = azurerm_resource_group.example.name } resource "azurerm_subnet" "example" { - name = "testsubnet" + name = "internal" resource_group_name = azurerm_resource_group.example.name virtual_network_name = azurerm_virtual_network.example.name address_prefix = "10.0.2.0/24" } resource "azurerm_network_interface" "example" { - name = "acceptanceTestNetworkInterface1" + name = "example-nic" location = azurerm_resource_group.example.location resource_group_name = azurerm_resource_group.example.name ip_configuration { - name = "testconfiguration1" + name = "internal" subnet_id = azurerm_subnet.example.id private_ip_address_allocation = "Dynamic" } - - tags = { - environment = "staging" - } } ``` @@ -54,54 +50,79 @@ resource "azurerm_network_interface" "example" { The following arguments are supported: -* `name` - (Required) The name of the network interface. Changing this forces a new resource to be created. +* `ip_configuration` - (Required) One or more `ip_configuration` blocks as defined below. + +* `location` - (Required) The location where the Network Interface should exist. Changing this forces a new resource to be created. -* `resource_group_name` - (Required) The name of the resource group in which to create the network interface. Changing this forces a new resource to be created. +* `name` - (Required) The name of the Network Interface. Changing this forces a new resource to be created. -* `location` - (Required) The location/region where the network interface is created. Changing this forces a new resource to be created. +* `resource_group_name` - (Required) The name of the Resource Group in which to create the Network Interface. Changing this forces a new resource to be created. + +--- -* `network_security_group_id` - (Optional) The ID of the Network Security Group to associate with the network interface. +* `dns_servers` - (Optional) A list of IP Addresses defining the DNS Servers which should be used for this Network Interface. -* `internal_dns_name_label` - (Optional) Relative DNS name for this NIC used for internal communications between VMs in the same VNet +-> **Note:** Configuring DNS Servers on the Network Interface will override the DNS Servers defined on the Virtual Network. -* `enable_ip_forwarding` - (Optional) Enables IP Forwarding on the NIC. Defaults to `false`. +* `enable_ip_forwarding` - (Optional) Should IP Forwarding be enabled? Defaults to `false`. -* `enable_accelerated_networking` - (Optional) Enables Azure Accelerated Networking using SR-IOV. Only certain VM instance sizes are supported. Refer to [Create a Virtual Machine with Accelerated Networking](https://docs.microsoft.com/en-us/azure/virtual-network/create-vm-accelerated-networking-cli). Defaults to `false`. +* `enable_accelerated_networking` - (Optional) Should Accelerated Networking be enabled? Defaults to `false`. -~> **NOTE:** when using Accelerated Networking in an Availability Set - the Availability Set must be deployed on an Accelerated Networking enabled cluster. +-> **Note:** Only certain Virtual Machine sizes are supported for Accelerated Networking - [more information can be found in this document](https://docs.microsoft.com/en-us/azure/virtual-network/create-vm-accelerated-networking-cli). -* `dns_servers` - (Optional) List of DNS servers IP addresses to use for this NIC, overrides the VNet-level server list +-> **Note:** To use Accelerated Networking in an Availability Set, the Availability Set must be deployed onto an Accelerated Networking enabled cluster. -* `ip_configuration` - (Required) One or more `ip_configuration` associated with this NIC as documented below. +* `internal_dns_name_label` - (Optional) The (relative) DNS Name used for internal communications between Virtual Machines in the same Virtual Network. * `tags` - (Optional) A mapping of tags to assign to the resource. -The `ip_configuration` block supports: +--- -* `name` - (Required) User-defined name of the IP. +The `ip_configuration` block supports the following: -* `subnet_id` - (Optional) Reference to a subnet in which this NIC has been created. Required when `private_ip_address_version` is IPv4. +* `name` - (Required) A name used for this IP Configuration. -* `private_ip_address` - (Optional) Static IP Address. +* `subnet_id` - (Optional) The ID of the Subnet where this Network Interface should be located in. -* `private_ip_address_allocation` - (Required) Defines how a private IP address is assigned. Options are Static or Dynamic. +-> **Note:** This is required when `private_ip_address_version` is set to `IPv4`. * `private_ip_address_version` - (Optional) The IP Version to use. Possible values are `IPv4` or `IPv6`. Defaults to `IPv4`. +* `private_ip_address_allocation` - (Required) The allocation method used for the Private IP Address. Possible values are `Dynamic` and `Static`. + +~> **Note:** Azure does not assign a Dynamic IP Address until the Network Interface is attached to a running Virtual Machine (or other resource) + * `public_ip_address_id` - (Optional) Reference to a Public IP Address to associate with this NIC -* `primary` - (Optional) Is this the Primary Network Interface? If set to `true` this should be the first `ip_configuration` in the array. +* `primary` - (Optional) Is this the Primary IP Configuration? Must be `true` for the first `ip_configuration` when multiple are specified. Defaults to `false`. + +When `private_ip_address_allocation` is set to `Static` the following fields can be configured: + +* `private_ip_address` - (Optional) The Static IP Address which should be used. + +When `private_ip_address_version` is set to `IPv4` the following fields can be configured: + +* `subnet_id` - (Required) The ID of the Subnet where this Network Interface should be located in. ## Attributes Reference The following attributes are exported: +* `applied_dns_servers` - If the Virtual Machine using this Network Interface is part of an Availability Set, then this list will have the union of all DNS servers from all Network Interfaces that are part of the Availability Set. + * `id` - The ID of the Network Interface. -* `mac_address` - The media access control (MAC) address of the network interface. + +* `mac_address` - The Media Access Control (MAC) Address of the Network Interface. + * `private_ip_address` - The first private IP address of the network interface. + +~> **Note:** If a `Dynamic` allocation method is used Azure will not allocate an IP Address until the Network Interface is attached to a running resource (such as a Virtual Machine). + * `private_ip_addresses` - The private IP addresses of the network interface. -* `virtual_machine_id` - Reference to a VM with which this NIC has been associated. -* `applied_dns_servers` - If the VM that uses this NIC is part of an Availability Set, then this list will have the union of all DNS servers from all NICs that are part of the Availability Set + +~> **Note:** If a `Dynamic` allocation method is used Azure will not allocate an IP Address until the Network Interface is attached to a running resource (such as a Virtual Machine). + +* `virtual_machine_id` - The ID of the Virtual Machine which this Network Interface is connected to. ## Timeouts From 3ececb9672b0033770c6b19c7a7ea985bbab8839 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Feb 2020 11:18:02 +0100 Subject: [PATCH 12/17] r/network_interface: conditionally updating the nics only for ipv4 configurations --- .../services/network/network_interface.go | 134 ++++++++++++++++++ .../network/resource_arm_network_interface.go | 124 ---------------- 2 files changed, 134 insertions(+), 124 deletions(-) create mode 100644 azurerm/internal/services/network/network_interface.go diff --git a/azurerm/internal/services/network/network_interface.go b/azurerm/internal/services/network/network_interface.go new file mode 100644 index 000000000000..dd29bb6aa188 --- /dev/null +++ b/azurerm/internal/services/network/network_interface.go @@ -0,0 +1,134 @@ +package network + +import ( + "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-09-01/network" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type networkInterfaceUpdateInformation struct { + applicationGatewayBackendAddressPoolIDs []string + applicationSecurityGroupIDs []string + loadBalancerBackendAddressPoolIDs []string + loadBalancerInboundNatRuleIDs []string + networkSecurityGroupID string +} + +func parseFieldsFromNetworkInterface(input network.InterfacePropertiesFormat) networkInterfaceUpdateInformation { + networkSecurityGroupId := "" + if input.NetworkSecurityGroup != nil && input.NetworkSecurityGroup.ID != nil { + networkSecurityGroupId = *input.NetworkSecurityGroup.ID + } + + var mapToSlice = func(input map[string]struct{}) []string { + output := make([]string, 0) + + for id, _ := range input { + output = append(output, id) + } + + return output + } + + applicationSecurityGroupIds := make(map[string]struct{}, 0) + applicationGatewayBackendAddressPoolIds := make(map[string]struct{}, 0) + loadBalancerBackendAddressPoolIds := make(map[string]struct{}, 0) + loadBalancerInboundNatRuleIds := make(map[string]struct{}, 0) + + if input.IPConfigurations != nil { + for _, v := range *input.IPConfigurations { + if v.InterfaceIPConfigurationPropertiesFormat == nil { + continue + } + + props := *v.InterfaceIPConfigurationPropertiesFormat + if props.ApplicationSecurityGroups != nil { + for _, asg := range *props.ApplicationSecurityGroups { + if asg.ID != nil { + applicationSecurityGroupIds[*asg.ID] = struct{}{} + } + } + } + + if props.ApplicationGatewayBackendAddressPools != nil { + for _, pool := range *props.ApplicationGatewayBackendAddressPools { + if pool.ID != nil { + applicationGatewayBackendAddressPoolIds[*pool.ID] = struct{}{} + } + } + } + + if props.LoadBalancerBackendAddressPools != nil { + for _, pool := range *props.LoadBalancerBackendAddressPools { + if pool.ID != nil { + loadBalancerBackendAddressPoolIds[*pool.ID] = struct{}{} + } + } + } + + if props.LoadBalancerInboundNatRules != nil { + for _, rule := range *props.LoadBalancerInboundNatRules { + if rule.ID != nil { + loadBalancerInboundNatRuleIds[*rule.ID] = struct{}{} + } + } + } + } + } + + return networkInterfaceUpdateInformation{ + applicationGatewayBackendAddressPoolIDs: mapToSlice(applicationGatewayBackendAddressPoolIds), + applicationSecurityGroupIDs: mapToSlice(applicationSecurityGroupIds), + loadBalancerBackendAddressPoolIDs: mapToSlice(loadBalancerBackendAddressPoolIds), + loadBalancerInboundNatRuleIDs: mapToSlice(loadBalancerInboundNatRuleIds), + networkSecurityGroupID: networkSecurityGroupId, + } +} + +func mapFieldsToNetworkInterface(input *[]network.InterfaceIPConfiguration, info networkInterfaceUpdateInformation) *[]network.InterfaceIPConfiguration { + output := input + + applicationSecurityGroups := make([]network.ApplicationSecurityGroup, 0) + for _, id := range info.applicationSecurityGroupIDs { + applicationSecurityGroups = append(applicationSecurityGroups, network.ApplicationSecurityGroup{ + ID: utils.String(id), + }) + } + + applicationGatewayBackendAddressPools := make([]network.ApplicationGatewayBackendAddressPool, 0) + for _, id := range info.applicationGatewayBackendAddressPoolIDs { + applicationGatewayBackendAddressPools = append(applicationGatewayBackendAddressPools, network.ApplicationGatewayBackendAddressPool{ + ID: utils.String(id), + }) + } + + loadBalancerBackendAddressPools := make([]network.BackendAddressPool, 0) + for _, id := range info.loadBalancerBackendAddressPoolIDs { + loadBalancerBackendAddressPools = append(loadBalancerBackendAddressPools, network.BackendAddressPool{ + ID: utils.String(id), + }) + } + + loadBalancerInboundNatRules := make([]network.InboundNatRule, 0) + for _, id := range info.loadBalancerInboundNatRuleIDs { + loadBalancerInboundNatRules = append(loadBalancerInboundNatRules, network.InboundNatRule{ + ID: utils.String(id), + }) + } + + for _, config := range *output { + if config.InterfaceIPConfigurationPropertiesFormat == nil { + continue + } + + if config.InterfaceIPConfigurationPropertiesFormat.PrivateIPAddressVersion != network.IPv4 { + continue + } + + config.ApplicationSecurityGroups = &applicationSecurityGroups + config.ApplicationGatewayBackendAddressPools = &applicationGatewayBackendAddressPools + config.LoadBalancerBackendAddressPools = &loadBalancerBackendAddressPools + config.LoadBalancerInboundNatRules = &loadBalancerInboundNatRules + } + + return output +} diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index 899d4bbfba60..92f606503b84 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -655,127 +655,3 @@ func flattenNetworkInterfaceDnsServers(input *[]string) []string { } return output } - -type networkInterfaceUpdateInformation struct { - applicationGatewayBackendAddressPoolIDs []string - applicationSecurityGroupIDs []string - loadBalancerBackendAddressPoolIDs []string - loadBalancerInboundNatRuleIDs []string - networkSecurityGroupID string -} - -func parseFieldsFromNetworkInterface(input network.InterfacePropertiesFormat) networkInterfaceUpdateInformation { - networkSecurityGroupId := "" - if input.NetworkSecurityGroup != nil && input.NetworkSecurityGroup.ID != nil { - networkSecurityGroupId = *input.NetworkSecurityGroup.ID - } - - var mapToSlice = func(input map[string]struct{}) []string { - output := make([]string, 0) - - for id, _ := range input { - output = append(output, id) - } - - return output - } - - applicationSecurityGroupIds := make(map[string]struct{}, 0) - applicationGatewayBackendAddressPoolIds := make(map[string]struct{}, 0) - loadBalancerBackendAddressPoolIds := make(map[string]struct{}, 0) - loadBalancerInboundNatRuleIds := make(map[string]struct{}, 0) - - if input.IPConfigurations != nil { - for _, v := range *input.IPConfigurations { - if v.InterfaceIPConfigurationPropertiesFormat == nil { - continue - } - - props := *v.InterfaceIPConfigurationPropertiesFormat - if props.ApplicationSecurityGroups != nil { - for _, asg := range *props.ApplicationSecurityGroups { - if asg.ID != nil { - applicationSecurityGroupIds[*asg.ID] = struct{}{} - } - } - } - - if props.ApplicationGatewayBackendAddressPools != nil { - for _, pool := range *props.ApplicationGatewayBackendAddressPools { - if pool.ID != nil { - applicationGatewayBackendAddressPoolIds[*pool.ID] = struct{}{} - } - } - } - - if props.LoadBalancerBackendAddressPools != nil { - for _, pool := range *props.LoadBalancerBackendAddressPools { - if pool.ID != nil { - loadBalancerBackendAddressPoolIds[*pool.ID] = struct{}{} - } - } - } - - if props.LoadBalancerInboundNatRules != nil { - for _, rule := range *props.LoadBalancerInboundNatRules { - if rule.ID != nil { - loadBalancerInboundNatRuleIds[*rule.ID] = struct{}{} - } - } - } - } - } - - return networkInterfaceUpdateInformation{ - applicationGatewayBackendAddressPoolIDs: mapToSlice(applicationGatewayBackendAddressPoolIds), - applicationSecurityGroupIDs: mapToSlice(applicationSecurityGroupIds), - loadBalancerBackendAddressPoolIDs: mapToSlice(loadBalancerBackendAddressPoolIds), - loadBalancerInboundNatRuleIDs: mapToSlice(loadBalancerInboundNatRuleIds), - networkSecurityGroupID: networkSecurityGroupId, - } -} - -func mapFieldsToNetworkInterface(input *[]network.InterfaceIPConfiguration, info networkInterfaceUpdateInformation) *[]network.InterfaceIPConfiguration { - output := input - - applicationSecurityGroups := make([]network.ApplicationSecurityGroup, 0) - for _, id := range info.applicationSecurityGroupIDs { - applicationSecurityGroups = append(applicationSecurityGroups, network.ApplicationSecurityGroup{ - ID: utils.String(id), - }) - } - - applicationGatewayBackendAddressPools := make([]network.ApplicationGatewayBackendAddressPool, 0) - for _, id := range info.applicationGatewayBackendAddressPoolIDs { - applicationGatewayBackendAddressPools = append(applicationGatewayBackendAddressPools, network.ApplicationGatewayBackendAddressPool{ - ID: utils.String(id), - }) - } - - loadBalancerBackendAddressPools := make([]network.BackendAddressPool, 0) - for _, id := range info.loadBalancerBackendAddressPoolIDs { - loadBalancerBackendAddressPools = append(loadBalancerBackendAddressPools, network.BackendAddressPool{ - ID: utils.String(id), - }) - } - - loadBalancerInboundNatRules := make([]network.InboundNatRule, 0) - for _, id := range info.loadBalancerInboundNatRuleIDs { - loadBalancerInboundNatRules = append(loadBalancerInboundNatRules, network.InboundNatRule{ - ID: utils.String(id), - }) - } - - for _, config := range *output { - if config.InterfaceIPConfigurationPropertiesFormat == nil { - continue - } - - config.ApplicationSecurityGroups = &applicationSecurityGroups - config.ApplicationGatewayBackendAddressPools = &applicationGatewayBackendAddressPools - config.LoadBalancerBackendAddressPools = &loadBalancerBackendAddressPools - config.LoadBalancerInboundNatRules = &loadBalancerInboundNatRules - } - - return output -} From f22151a876a5de465164acf5b291d7104de7d866 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Feb 2020 11:22:02 +0100 Subject: [PATCH 13/17] r/network_interface_application_gateway_association: fixing the tests --- ..._network_interface_application_gateway_association_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_application_gateway_association_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_application_gateway_association_test.go index f2dad35421cd..2c02e8476030 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_application_gateway_association_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_application_gateway_association_test.go @@ -223,7 +223,7 @@ resource "azurerm_network_interface" "test" { ip_configuration { name = "testconfiguration1" - subnet_id = "${azurerm_subnet.frontend.id}" + subnet_id = "${azurerm_subnet.backend.id}" private_ip_address_allocation = "Dynamic" } } @@ -261,7 +261,7 @@ resource "azurerm_network_interface" "test" { ip_configuration { name = "testconfiguration1" - subnet_id = "${azurerm_subnet.frontend.id}" + subnet_id = "${azurerm_subnet.backend.id}" private_ip_address_allocation = "Dynamic" primary = true } From 44868cb05d0f323aaf79c3a817ea48c29f8e53ba Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Feb 2020 12:26:53 +0100 Subject: [PATCH 14/17] d/network_interface: updating the tests --- .../network/data_source_network_interface.go | 9 -- .../data_source_network_interface_test.go | 110 ++---------------- 2 files changed, 10 insertions(+), 109 deletions(-) diff --git a/azurerm/internal/services/network/data_source_network_interface.go b/azurerm/internal/services/network/data_source_network_interface.go index 7e934893da4e..aac805452193 100644 --- a/azurerm/internal/services/network/data_source_network_interface.go +++ b/azurerm/internal/services/network/data_source_network_interface.go @@ -73,7 +73,6 @@ func dataSourceArmNetworkInterface() *schema.Resource { Computed: true, }, - //TODO: should this be renamed to private_ip_address_allocation_method or private_ip_allocation_method ? "private_ip_address_allocation": { Type: schema.TypeString, Computed: true, @@ -145,14 +144,6 @@ func dataSourceArmNetworkInterface() *schema.Resource { Computed: true, }, - /** - * As of 2018-01-06: AN (aka. SR-IOV) on Azure is GA on Windows and Linux. - * - * Refer to: https://azure.microsoft.com/en-us/blog/maximize-your-vm-s-performance-with-accelerated-networking-now-generally-available-for-both-windows-and-linux/ - * - * Refer to: https://docs.microsoft.com/en-us/azure/virtual-network/create-vm-accelerated-networking-cli - * For details, VM configuration and caveats. - */ "enable_accelerated_networking": { Type: schema.TypeBool, Computed: true, diff --git a/azurerm/internal/services/network/tests/data_source_network_interface_test.go b/azurerm/internal/services/network/tests/data_source_network_interface_test.go index e4c0bd02235e..c40a91de9e18 100644 --- a/azurerm/internal/services/network/tests/data_source_network_interface_test.go +++ b/azurerm/internal/services/network/tests/data_source_network_interface_test.go @@ -8,124 +8,34 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" ) -func TestAccDataSourceArmVirtualNetworkInterface_basic(t *testing.T) { +func TestAccDataSourceArmNetworkInterface_basic(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_network_interface", "test") - name := fmt.Sprintf("acctest-nic-%d", data.RandomInteger) - resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceArmVirtualNetworkInterface_basic(data), + Config: testAccAzureRMNetworkInterface_static(data), }, { - Config: testAccDataSourceArmVirtualNetworkInterface_withDataSource(data), + Config: testAccDataSourceNetworkInterface_basic(data), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(data.ResourceName, "name", name), - resource.TestCheckResourceAttrSet(data.ResourceName, "id"), - resource.TestCheckResourceAttr(data.ResourceName, "private_ip_address", "10.0.1.4"), - resource.TestCheckResourceAttrSet(data.ResourceName, "network_security_group_id"), + resource.TestCheckResourceAttr(data.ResourceName, "private_ip_address", "10.0.2.15"), ), }, }, }) } -func testAccDataSourceArmVirtualNetworkInterface_basic(data acceptance.TestData) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctest-%d-rg" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctest-vn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_network_security_group" "test" { - name = "acctest-nsg-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "subnet1" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.1.0/24" -} - -resource "azurerm_network_interface" "test" { - name = "acctest-nic-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - network_security_group_id = "${azurerm_network_security_group.test.id}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - } - - tags = { - environment = "staging" - } -} -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) -} - -func testAccDataSourceArmVirtualNetworkInterface_withDataSource(data acceptance.TestData) string { +func testAccDataSourceNetworkInterface_basic(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_static(data) return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctest-%d-rg" - location = "%s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctest-vn-%d" - address_space = ["10.0.0.0/16"] - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_network_security_group" "test" { - name = "acctest-nsg-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_subnet" "test" { - name = "subnet1" - resource_group_name = "${azurerm_resource_group.test.name}" - virtual_network_name = "${azurerm_virtual_network.test.name}" - address_prefix = "10.0.1.0/24" -} - -resource "azurerm_network_interface" "test" { - name = "acctest-nic-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - network_security_group_id = "${azurerm_network_security_group.test.id}" - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - } - - tags = { - environment = "staging" - } -} +%s data "azurerm_network_interface" "test" { - name = "acctest-nic-%d" - resource_group_name = "${azurerm_resource_group.test.name}" + name = azurerm_network_interface.test.name + resource_group_name = azurerm_network_interface.test.resource_group_name } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, template) } From 8e874af34c2025ba406dc0da9944c8e256a73caf Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Mon, 17 Feb 2020 15:10:52 +0100 Subject: [PATCH 15/17] docs: adding the `azurerm_network_interface_security_group_association` to the sidebar --- website/azurerm.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/website/azurerm.erb b/website/azurerm.erb index 0ea9b471ad15..ac91bdd26944 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -1803,6 +1803,10 @@ azurerm_network_interface_nat_rule_association +
  • + azurerm_network_interface_security_group_association +
  • +
  • azurerm_network_packet_capture
  • From 1310177ce5c98469fc3d7ece4d305acce21215b0 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 18 Feb 2020 12:11:29 +0100 Subject: [PATCH 16/17] linting --- .../internal/services/network/network_interface.go | 8 ++++---- .../network/resource_arm_network_interface.go | 14 +++++--------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/azurerm/internal/services/network/network_interface.go b/azurerm/internal/services/network/network_interface.go index dd29bb6aa188..0f5c25a97bd4 100644 --- a/azurerm/internal/services/network/network_interface.go +++ b/azurerm/internal/services/network/network_interface.go @@ -29,10 +29,10 @@ func parseFieldsFromNetworkInterface(input network.InterfacePropertiesFormat) ne return output } - applicationSecurityGroupIds := make(map[string]struct{}, 0) - applicationGatewayBackendAddressPoolIds := make(map[string]struct{}, 0) - loadBalancerBackendAddressPoolIds := make(map[string]struct{}, 0) - loadBalancerInboundNatRuleIds := make(map[string]struct{}, 0) + applicationSecurityGroupIds := make(map[string]struct{}) + applicationGatewayBackendAddressPoolIds := make(map[string]struct{}) + loadBalancerBackendAddressPoolIds := make(map[string]struct{}) + loadBalancerInboundNatRuleIds := make(map[string]struct{}) if input.IPConfigurations != nil { for _, v := range *input.IPConfigurations { diff --git a/azurerm/internal/services/network/resource_arm_network_interface.go b/azurerm/internal/services/network/resource_arm_network_interface.go index 92f606503b84..4b4c388d5499 100644 --- a/azurerm/internal/services/network/resource_arm_network_interface.go +++ b/azurerm/internal/services/network/resource_arm_network_interface.go @@ -236,7 +236,7 @@ func resourceArmNetworkInterfaceCreate(d *schema.ResourceData, meta interface{}) } lockingDetails, err := determineResourcesToLockFromIPConfiguration(ipConfigs) if err != nil { - return fmt.Errorf("Error determing locking details: %+v", err) + return fmt.Errorf("Error determining locking details: %+v", err) } lockingDetails.lock() @@ -344,7 +344,7 @@ func resourceArmNetworkInterfaceUpdate(d *schema.ResourceData, meta interface{}) } lockingDetails, err := determineResourcesToLockFromIPConfiguration(ipConfigs) if err != nil { - return fmt.Errorf("Error determing locking details: %+v", err) + return fmt.Errorf("Error determining locking details: %+v", err) } lockingDetails.lock() @@ -501,7 +501,7 @@ func resourceArmNetworkInterfaceDelete(d *schema.ResourceData, meta interface{}) lockingDetails, err := determineResourcesToLockFromIPConfiguration(props.IPConfigurations) if err != nil { - return fmt.Errorf("Error determing locking details: %+v", err) + return fmt.Errorf("Error determining locking details: %+v", err) } lockingDetails.lock() @@ -645,13 +645,9 @@ func expandNetworkInterfaceDnsServers(input []interface{}) []string { } func flattenNetworkInterfaceDnsServers(input *[]string) []string { - output := make([]string, 0) if input == nil { - return output + return make([]string, 0) } - for _, v := range *input { - output = append(output, v) - } - return output + return *input } From 065ef3172b00e0ca78d323464334948c6480dd0b Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 18 Feb 2020 13:29:10 +0100 Subject: [PATCH 17/17] linting --- azurerm/internal/services/network/network_interface.go | 2 +- .../network/tests/resource_arm_network_interface_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/network/network_interface.go b/azurerm/internal/services/network/network_interface.go index 0f5c25a97bd4..798b38580bb4 100644 --- a/azurerm/internal/services/network/network_interface.go +++ b/azurerm/internal/services/network/network_interface.go @@ -22,7 +22,7 @@ func parseFieldsFromNetworkInterface(input network.InterfacePropertiesFormat) ne var mapToSlice = func(input map[string]struct{}) []string { output := make([]string, 0) - for id, _ := range input { + for id := range input { output = append(output, id) } diff --git a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go index 3ec528f8615a..47ccf8ca5d29 100644 --- a/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go +++ b/azurerm/internal/services/network/tests/resource_arm_network_interface_test.go @@ -547,7 +547,7 @@ resource "azurerm_network_interface" "test" { name = "acctestni-%d" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name - internal_dns_name_label = "acctestni-%s-%s" + internal_dns_name_label = "acctestni-%s-%s" ip_configuration { name = "primary"