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/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..f75c0ac1c827 --- /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 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 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 +// +// 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/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/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/network_interface.go b/azurerm/internal/services/network/network_interface.go new file mode 100644 index 000000000000..798b38580bb4 --- /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{}) + applicationGatewayBackendAddressPoolIds := make(map[string]struct{}) + loadBalancerBackendAddressPoolIds := make(map[string]struct{}) + loadBalancerInboundNatRuleIds := make(map[string]struct{}) + + 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/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/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/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..4b4c388d5499 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,6 @@ func resourceArmNetworkInterface() *schema.Resource { "resource_group_name": azure.SchemaResourceGroupName(), - "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 +85,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, @@ -125,54 +102,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, - 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, - }, - - "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, - }, - - "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, @@ -183,14 +112,25 @@ 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": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "enable_ip_forwarding": { + Type: schema.TypeBool, + Optional: true, + Default: false, }, "internal_dns_name_label": { @@ -200,45 +140,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 +169,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) } } @@ -293,90 +211,172 @@ func resourceArmNetworkInterfaceCreateUpdate(d *schema.ResourceData, meta interf 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 { - 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.([]interface{}) + dns := expandNetworkInterfaceDnsServers(dnsRaw) + dnsSettings.DNSServers = &dns } if hasNameLabel { - name_label := nameLabel.(string) - ifaceDnsSettings.InternalDNSNameLabel = &name_label + dnsSettings.InternalDNSNameLabel = utils.String(nameLabel.(string)) } - 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 determining 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 + 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) + + // 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) + } + + 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), + Location: utils.String(location), + InterfacePropertiesFormat: &network.InterfacePropertiesFormat{}, + } + + if d.HasChange("dns_servers") { + if update.InterfacePropertiesFormat.DNSSettings == nil { + update.InterfacePropertiesFormat.DNSSettings = &network.InterfaceDNSSettings{} + } + + dnsServersRaw := d.Get("dns_servers").([]interface{}) + dnsServers := expandNetworkInterfaceDnsServers(dnsServersRaw) + + update.InterfacePropertiesFormat.DNSSettings.DNSServers = &dnsServers + } + + if d.HasChange("enable_accelerated_networking") { + update.InterfacePropertiesFormat.EnableAcceleratedNetworking = utils.Bool(d.Get("enable_accelerated_networking").(bool)) + } + + if d.HasChange("enable_ip_forwarding") { + update.InterfacePropertiesFormat.EnableIPForwarding = utils.Bool(d.Get("enable_ip_forwarding").(bool)) + } + + if d.HasChange("internal_dns_name_label") { + 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") { + 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 determining locking details: %+v", err) + } + + lockingDetails.lock() + defer lockingDetails.unlock() + + // then map the fields managed in other resources back + ipConfigs = mapFieldsToNetworkInterface(ipConfigs, info) + + update.InterfacePropertiesFormat.IPConfigurations = ipConfigs + } else { + update.InterfacePropertiesFormat.IPConfigurations = existing.InterfacePropertiesFormat.IPConfigurations + } + + if d.HasChange("tags") { + tagsRaw := d.Get("tags").(map[string]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) + } + 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 +386,83 @@ 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) + 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("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,178 +477,71 @@ 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) - parsedNsgID, err := azure.ParseAzureResourceID(networkSecurityGroupId) - if err != nil { - return fmt.Errorf("Error parsing Network Security Group ID %q: %+v", networkSecurityGroupId, err) + 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 } - networkSecurityGroupName := parsedNsgID.Path["networkSecurityGroups"] - - locks.ByName(networkSecurityGroupName, networkSecurityGroupResourceName) - defer locks.UnlockByName(networkSecurityGroupName, networkSecurityGroupResourceName) + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): %+v", name, resourceGroup, err) } - 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) - } - } + if existing.InterfacePropertiesFormat == nil { + return fmt.Errorf("Error retrieving Network Interface %q (Resource Group %q): `properties` was nil", name, resourceGroup) } + props := *existing.InterfacePropertiesFormat - locks.MultipleByName(&subnetNamesToLock, SubnetResourceName) - defer locks.UnlockMultipleByName(&subnetNamesToLock, SubnetResourceName) + lockingDetails, err := determineResourcesToLockFromIPConfiguration(props.IPConfigurations) + if err != nil { + return fmt.Errorf("Error determining locking details: %+v", err) + } - 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,77 +556,14 @@ func expandAzureRmNetworkInterfaceIpConfigurations(d *schema.ResourceData) ([]ne } if v, ok := data["primary"]; ok { - b := v.(bool) - properties.Primary = &b - } - - 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) - id := network.ApplicationGatewayBackendAddressPool{ - ID: &pool_id, - } - - 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() - for _, p := range pools { - pool_id := p.(string) - id := network.BackendAddressPool{ - ID: &pool_id, - } - - ids = append(ids, id) - } - - 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 { - rule_id := r.(string) - rule := network.InboundNatRule{ - ID: &rule_id, - } - - natRules = append(natRules, rule) - } - - 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 + properties.Primary = utils.Bool(v.(bool)) } 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 +577,77 @@ 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 + } + + primary := false + if props.Primary != nil { + primary = *props.Primary + } + + result = append(result, map[string]interface{}{ + "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 { + if input == nil { + return make([]string, 0) } - return false + return *input } 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) } } 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) } 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/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..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 @@ -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.backend.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.backend.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_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_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_nat_rule_association_test.go b/azurerm/internal/services/network/tests/resource_arm_network_interface_nat_rule_association_test.go index e10f617bfe01..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 @@ -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,76 @@ 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_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" { name = "acctestRG-%d" @@ -232,36 +329,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/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..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 @@ -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,102 @@ 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), - resource.TestCheckResourceAttr(data.ResourceName, "network_security_group_id", ""), ), }, - }, - }) -} - -func TestAccAzureRMNetworkInterface_multipleSubnets(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{ + data.ImportStep(), { - Config: testAccAzureRMNetworkInterface_multipleSubnets(data), + // Enabled + Config: testAccAzureRMNetworkInterface_enableIPForwarding(data, true), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.#", "2"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_multipleSubnetsPrimary(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), - 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"), ), }, + data.ImportStep(), { - Config: testAccAzureRMNetworkInterface_multipleSubnetsUpdatedPrimary(data), + Config: testAccAzureRMNetworkInterface_internalDomainNameLabel(data, "2"), 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"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_enableIPForwarding(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) }, @@ -184,17 +177,19 @@ func TestAccAzureRMNetworkInterface_enableIPForwarding(t *testing.T) { CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_ipForwarding(data), + Config: testAccAzureRMNetworkInterface_ipv6(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "enable_ip_forwarding", "true"), + 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_enableAcceleratedNetworking(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) }, @@ -202,36 +197,35 @@ func TestAccAzureRMNetworkInterface_enableAcceleratedNetworking(t *testing.T) { CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_acceleratedNetworking(data), + Config: testAccAzureRMNetworkInterface_multipleIPConfigurations(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "enable_accelerated_networking", "true"), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_multipleLoadBalancers(t *testing.T) { - data := acceptance.BuildTestData(t, "azurerm_network_interface", "test1") - +func TestAccAzureRMNetworkInterface_multipleIPConfigurationsSecondaryAsPrimary(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_multipleLoadBalancers(data), + Config: testAccAzureRMNetworkInterface_multipleIPConfigurationsSecondaryAsPrimary(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test1"), - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test2"), + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), ), }, + data.ImportStep(), }, }) } -func TestAccAzureRMNetworkInterface_applicationGateway(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) }, @@ -239,45 +233,36 @@ func TestAccAzureRMNetworkInterface_applicationGateway(t *testing.T) { CheckDestroy: testCheckAzureRMNetworkInterfaceDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMNetworkInterface_applicationGatewayBackendPool(data), + Config: testAccAzureRMNetworkInterface_publicIP(data), Check: resource.ComposeTestCheckFunc( - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test"), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.application_gateway_backend_address_pools_ids.#", "1"), + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), ), }, - }, - }) -} - -func TestAccAzureRMNetworkInterface_withTags(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{ + data.ImportStep(), { - Config: testAccAzureRMNetworkInterface_withTags(data), + 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) }, @@ -285,93 +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("azurerm_network_interface.test1"), - testCheckAzureRMNetworkInterfaceExists("azurerm_network_interface.test2"), + testCheckAzureRMNetworkInterfaceExists(data.ResourceName), ), }, - }, - }) -} - -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{ + data.ImportStep(), { - Config: testAccAzureRMNetworkInterface_applicationSecurityGroup(data), + Config: testAccAzureRMNetworkInterface_tagsUpdated(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMNetworkInterfaceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "ip_configuration.0.application_security_group_ids.#", "1"), ), }, + 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(), }, @@ -390,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) { @@ -420,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 { @@ -466,824 +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" -} +%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_network_interface" "test" { + name = "acctestni-%d" + 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" + ip_configuration { + name = "primary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} +`, template, data.RandomInteger) } +func testAccAzureRMNetworkInterface_dnsServers(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 + + 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" } } -`, 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_dnsServersUpdated(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.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" } } -`, template) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_basicWithNetworkSecurityGroup(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" -} +%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_network_interface" "test" { + name = "acctestni-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + enable_accelerated_networking = %t -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" + ip_configuration { + name = "primary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } } - -resource "azurerm_network_security_group" "test" { - name = "acctestnsg-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" +`, template, data.RandomInteger, enabled) } +func testAccAzureRMNetworkInterface_enableIPForwarding(data acceptance.TestData, enabled bool) 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}" - 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 + 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, data.RandomInteger) +`, template, data.RandomInteger, enabled) } -func testAccAzureRMNetworkInterface_multipleSubnets(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" -} +%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_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" -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" + ip_configuration { + name = "primary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Dynamic" + } +} +`, template, data.RandomInteger, suffix, data.RandomString) } +func testAccAzureRMNetworkInterface_ipv6(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 } ip_configuration { - name = "testconfiguration2" - subnet_id = "${azurerm_subnet.test.id}" + name = "secondary" private_ip_address_allocation = "Dynamic" + private_ip_address_version = "IPv6" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_multipleSubnetsUpdatedPrimary(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_multipleIPConfigurations(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 = "testconfiguration2" - subnet_id = "${azurerm_subnet.test.id}" + name = "primary" + subnet_id = azurerm_subnet.test.id private_ip_address_allocation = "Dynamic" primary = true } ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" + 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_ipForwarding(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}" - enable_ip_forwarding = 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" } + + 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_acceleratedNetworking(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_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 - - ip_configuration { - name = "testconfiguration1" - subnet_id = "${azurerm_subnet.test.id}" - private_ip_address_allocation = "Dynamic" - } -} -`, 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" -} - -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 = "Production" - cost_center = "MSFT" + public_ip_address_id = azurerm_public_ip.test.id } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_withTagsUpdate(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" -} +%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" - } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_withIPAddresses(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 = "Static" - private_ip_address = "10.0.2.9" - 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_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_basic(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}" +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 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) } -func testAccAzureRMNetworkInterface_withIPv6Addresses(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_static(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_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}" - - 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) -} - -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 + 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" - - load_balancer_inbound_nat_rules_ids = [ - "${azurerm_lb_nat_rule.testext.id}", - "${azurerm_lb_nat_rule.testint.id}", - ] + name = "primary" + subnet_id = azurerm_subnet.test.id + private_ip_address_allocation = "Static" + private_ip_address = "10.0.2.15" } } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +`, template, data.RandomInteger) } -func testAccAzureRMNetworkInterface_applicationGatewayBackendPool(data acceptance.TestData) string { +func testAccAzureRMNetworkInterface_tags(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 = "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" - } -} +%s 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 + 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" - - 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" { - name = "acctest-%d" - location = "%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}" tags = { - environment = "Production" + Hello = "World" } } - -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}" -} - -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}" +`, template, data.RandomInteger) } -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" - - tags = { - environment = "Production" - } -} - -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}" -} - -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" -} - -resource "azurerm_network_interface" "test1" { - name = "acctest-%d-nic1" - 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" - } - - tags = { - environment = "staging" - } -} +func testAccAzureRMNetworkInterface_tagsUpdated(data acceptance.TestData) string { + template := testAccAzureRMNetworkInterface_template(data) + return fmt.Sprintf(` +%s -resource "azurerm_network_interface" "test2" { - name = "acctest-%d-nic2" - 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" + 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" @@ -1292,78 +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) -} - -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) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) } 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 +