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 +
  • + azurerm_network_interface_security_group_association +
  • +
  • azurerm_network_packet_capture
  • diff --git a/website/docs/r/network_interface.html.markdown b/website/docs/r/network_interface.html.markdown index 45f5f6bfddce..97e05d62d827 100644 --- a/website/docs/r/network_interface.html.markdown +++ b/website/docs/r/network_interface.html.markdown @@ -3,50 +3,46 @@ subcategory: "Network" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_network_interface" description: |- - Manages a Network Interface located in a Virtual Network, usually attached to a Virtual Machine. + Manages a Network Interface. --- # azurerm_network_interface -Manages a Network Interface located in a Virtual Network, usually attached to a Virtual Machine. +Manages a Network Interface. ## Example Usage ```hcl resource "azurerm_resource_group" "example" { - name = "acceptanceTestResourceGroup1" - location = "West US" + name = "example-resources" + location = "West Europe" } resource "azurerm_virtual_network" "example" { - name = "acceptanceTestVirtualNetwork1" + name = "example-network" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.example.location resource_group_name = azurerm_resource_group.example.name } resource "azurerm_subnet" "example" { - name = "testsubnet" + name = "internal" resource_group_name = azurerm_resource_group.example.name virtual_network_name = azurerm_virtual_network.example.name address_prefix = "10.0.2.0/24" } resource "azurerm_network_interface" "example" { - name = "acceptanceTestNetworkInterface1" + name = "example-nic" location = azurerm_resource_group.example.location resource_group_name = azurerm_resource_group.example.name ip_configuration { - name = "testconfiguration1" + name = "internal" subnet_id = azurerm_subnet.example.id private_ip_address_allocation = "Dynamic" } - - tags = { - environment = "staging" - } } ``` @@ -54,70 +50,79 @@ resource "azurerm_network_interface" "example" { The following arguments are supported: -* `name` - (Required) The name of the network interface. Changing this forces a new resource to be created. +* `ip_configuration` - (Required) One or more `ip_configuration` blocks as defined below. -* `resource_group_name` - (Required) The name of the resource group in which to create the network interface. Changing this forces a new resource to be created. +* `location` - (Required) The location where the Network Interface should exist. Changing this forces a new resource to be created. -* `location` - (Required) The location/region where the network interface is created. Changing this forces a new resource to be created. +* `name` - (Required) The name of the Network Interface. Changing this forces a new resource to be created. -* `network_security_group_id` - (Optional) The ID of the Network Security Group to associate with the network interface. +* `resource_group_name` - (Required) The name of the Resource Group in which to create the Network Interface. Changing this forces a new resource to be created. -* `internal_dns_name_label` - (Optional) Relative DNS name for this NIC used for internal communications between VMs in the same VNet +--- -* `enable_ip_forwarding` - (Optional) Enables IP Forwarding on the NIC. Defaults to `false`. +* `dns_servers` - (Optional) A list of IP Addresses defining the DNS Servers which should be used for this Network Interface. -* `enable_accelerated_networking` - (Optional) Enables Azure Accelerated Networking using SR-IOV. Only certain VM instance sizes are supported. Refer to [Create a Virtual Machine with Accelerated Networking](https://docs.microsoft.com/en-us/azure/virtual-network/create-vm-accelerated-networking-cli). Defaults to `false`. +-> **Note:** Configuring DNS Servers on the Network Interface will override the DNS Servers defined on the Virtual Network. -~> **NOTE:** when using Accelerated Networking in an Availability Set - the Availability Set must be deployed on an Accelerated Networking enabled cluster. +* `enable_ip_forwarding` - (Optional) Should IP Forwarding be enabled? Defaults to `false`. -* `dns_servers` - (Optional) List of DNS servers IP addresses to use for this NIC, overrides the VNet-level server list +* `enable_accelerated_networking` - (Optional) Should Accelerated Networking be enabled? Defaults to `false`. -* `ip_configuration` - (Required) One or more `ip_configuration` associated with this NIC as documented below. +-> **Note:** Only certain Virtual Machine sizes are supported for Accelerated Networking - [more information can be found in this document](https://docs.microsoft.com/en-us/azure/virtual-network/create-vm-accelerated-networking-cli). -* `tags` - (Optional) A mapping of tags to assign to the resource. +-> **Note:** To use Accelerated Networking in an Availability Set, the Availability Set must be deployed onto an Accelerated Networking enabled cluster. -The `ip_configuration` block supports: +* `internal_dns_name_label` - (Optional) The (relative) DNS Name used for internal communications between Virtual Machines in the same Virtual Network. -* `name` - (Required) User-defined name of the IP. +* `tags` - (Optional) A mapping of tags to assign to the resource. -* `subnet_id` - (Optional) Reference to a subnet in which this NIC has been created. Required when `private_ip_address_version` is IPv4. +--- -* `private_ip_address` - (Optional) Static IP Address. +The `ip_configuration` block supports the following: -* `private_ip_address_allocation` - (Required) Defines how a private IP address is assigned. Options are Static or Dynamic. +* `name` - (Required) A name used for this IP Configuration. -* `private_ip_address_version` - (Optional) The IP Version to use. Possible values are `IPv4` or `IPv6`. Defaults to `IPv4`. +* `subnet_id` - (Optional) The ID of the Subnet where this Network Interface should be located in. -* `public_ip_address_id` - (Optional) Reference to a Public IP Address to associate with this NIC +-> **Note:** This is required when `private_ip_address_version` is set to `IPv4`. -* `application_gateway_backend_address_pools_ids` - (Optional / **Deprecated**) List of Application Gateway Backend Address Pool IDs references to which this NIC belongs +* `private_ip_address_version` - (Optional) The IP Version to use. Possible values are `IPv4` or `IPv6`. Defaults to `IPv4`. --> **NOTE:** At this time Network Interface <-> Application Gateway Backend Address Pool associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_application_gateway_backend_address_pool_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. +* `private_ip_address_allocation` - (Required) The allocation method used for the Private IP Address. Possible values are `Dynamic` and `Static`. -* `load_balancer_backend_address_pools_ids` - (Optional / **Deprecated**) List of Load Balancer Backend Address Pool IDs references to which this NIC belongs +~> **Note:** Azure does not assign a Dynamic IP Address until the Network Interface is attached to a running Virtual Machine (or other resource) --> **NOTE:** At this time Network Interface <-> Load Balancer Backend Address Pool associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_backend_address_pool_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. +* `public_ip_address_id` - (Optional) Reference to a Public IP Address to associate with this NIC -* `load_balancer_inbound_nat_rules_ids` - (Optional / **Deprecated**) List of Load Balancer Inbound Nat Rules IDs involving this NIC +* `primary` - (Optional) Is this the Primary IP Configuration? Must be `true` for the first `ip_configuration` when multiple are specified. Defaults to `false`. --> **NOTE:** At this time Network Interface <-> Load Balancer Inbound NAT Rule associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_nat_rule_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. +When `private_ip_address_allocation` is set to `Static` the following fields can be configured: -* `application_security_group_ids` - (Optional / **Deprecated**) List of Application Security Group IDs which should be attached to this NIC +* `private_ip_address` - (Optional) The Static IP Address which should be used. --> **NOTE:** At this time Network Interface <-> Application Security Group associations need to be configured both using this field (which is now Deprecated) and using the `azurerm_network_interface_application_security_group_association` resource. This field is deprecated and will be removed in favour of that resource in the next major version (2.0) of the AzureRM Provider. +When `private_ip_address_version` is set to `IPv4` the following fields can be configured: -* `primary` - (Optional) Is this the Primary Network Interface? If set to `true` this should be the first `ip_configuration` in the array. +* `subnet_id` - (Required) The ID of the Subnet where this Network Interface should be located in. ## Attributes Reference The following attributes are exported: +* `applied_dns_servers` - If the Virtual Machine using this Network Interface is part of an Availability Set, then this list will have the union of all DNS servers from all Network Interfaces that are part of the Availability Set. + * `id` - The ID of the Network Interface. -* `mac_address` - The media access control (MAC) address of the network interface. + +* `mac_address` - The Media Access Control (MAC) Address of the Network Interface. + * `private_ip_address` - The first private IP address of the network interface. + +~> **Note:** If a `Dynamic` allocation method is used Azure will not allocate an IP Address until the Network Interface is attached to a running resource (such as a Virtual Machine). + * `private_ip_addresses` - The private IP addresses of the network interface. -* `virtual_machine_id` - Reference to a VM with which this NIC has been associated. -* `applied_dns_servers` - If the VM that uses this NIC is part of an Availability Set, then this list will have the union of all DNS servers from all NICs that are part of the Availability Set + +~> **Note:** If a `Dynamic` allocation method is used Azure will not allocate an IP Address until the Network Interface is attached to a running resource (such as a Virtual Machine). + +* `virtual_machine_id` - The ID of the Virtual Machine which this Network Interface is connected to. ## Timeouts diff --git a/website/docs/r/network_interface_security_group_association.html.markdown b/website/docs/r/network_interface_security_group_association.html.markdown new file mode 100644 index 000000000000..3bc138982a77 --- /dev/null +++ b/website/docs/r/network_interface_security_group_association.html.markdown @@ -0,0 +1,91 @@ +--- +subcategory: "Network" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_network_interface_security_group_association" +description: |- + Manages the association between a Network Interface and a Network Security Group. + +--- + +# azurerm_network_interface_security_group_association + +Manages the association between a Network Interface and a Network Security Group. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "West Europe" +} + +resource "azurerm_virtual_network" "example" { + name = "example-network" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_subnet" "example" { + name = "internal" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name + address_prefix = "10.0.2.0/24" +} + +resource "azurerm_network_security_group" "example" { + name = "example-nsg" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name +} + +resource "azurerm_network_interface" "example" { + name = "example-nic" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + + ip_configuration { + name = "testconfiguration1" + subnet_id = azurerm_subnet.example.id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_network_interface_security_group_association" "example" { + network_interface_id = azurerm_network_interface.example.id + network_security_group_id = azurerm_network_security_group.example.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `network_interface_id` - (Required) The ID of the Network Interface. Changing this forces a new resource to be created. + +* `network_security_group_id` - (Required) The ID of the Network Security Group which should be attached to the Network Interface. Changing this forces a new resource to be created. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The (Terraform specific) ID of the Association between the Network Interface and the Network Interface. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the association between the Network Interface and the Network Security Group. +* `update` - (Defaults to 30 minutes) Used when updating the association between the Network Interface and the Network Security Group. +* `read` - (Defaults to 5 minutes) Used when retrieving the association between the Network Interface and the Network Security Group. +* `delete` - (Defaults to 30 minutes) Used when deleting the association between the Network Interface and the Network Security Group. + +## Import + +Associations between Network Interfaces and Network Security Group can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_network_interface_security_group_association.association1 /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/microsoft.network/networkInterfaces/nic1/ipConfigurations/example|/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Network/networkSecurityGroups/group1 +``` + +-> **NOTE:** This ID is specific to Terraform - and is of the format `{networkInterfaceId}/|{networkSecurityGroupId}`.