diff --git a/azurerm/internal/services/web/parse/slot_virtual_network_swift_connection.go b/azurerm/internal/services/web/parse/slot_virtual_network_swift_connection.go new file mode 100644 index 000000000000..39c9096fba05 --- /dev/null +++ b/azurerm/internal/services/web/parse/slot_virtual_network_swift_connection.go @@ -0,0 +1,34 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type SlotVirtualNetworkSwiftConnectionId struct { + VirtualNetworkSwiftConnectionId + SlotName string +} + +func SlotVirtualNetworkSwiftConnectionID(resourceId string) (*SlotVirtualNetworkSwiftConnectionId, error) { + id, err := azure.ParseAzureResourceID(resourceId) + if err != nil { + return nil, fmt.Errorf("Error parsing Azure Resource ID %q", id) + } + + virtualNetworkId, err := VirtualNetworkSwiftConnectionID(resourceId) + if err != nil { + return nil, err + } + + slotVirtualNetworkId := &SlotVirtualNetworkSwiftConnectionId{ + VirtualNetworkSwiftConnectionId: *virtualNetworkId, + } + + if slotVirtualNetworkId.SlotName, err = id.PopSegment("slots"); err != nil { + return nil, err + } + + return slotVirtualNetworkId, nil +} diff --git a/azurerm/internal/services/web/parse/slot_virtual_network_swift_connection_test.go b/azurerm/internal/services/web/parse/slot_virtual_network_swift_connection_test.go new file mode 100644 index 000000000000..68abdbba617f --- /dev/null +++ b/azurerm/internal/services/web/parse/slot_virtual_network_swift_connection_test.go @@ -0,0 +1,73 @@ +package parse + +import ( + "testing" +) + +func TestSlotVirtualNetworkSwiftConnectionID(t *testing.T) { + testData := []struct { + Name string + Input string + Expected *SlotVirtualNetworkSwiftConnectionId + }{ + { + Name: "Empty", + Input: "", + Expected: nil, + }, + { + Name: "No Resource Groups Segemt", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Expected: nil, + }, + { + Name: "No Sites Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Web", + Expected: nil, + }, + { + Name: "No Slot Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Web/sites/instance1", + Expected: nil, + }, + { + Name: "Valid Network Association But No Slot Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Web/sites/instance1/networkconfig/virtualNetwork", + Expected: nil, + }, + { + Name: "Slot Virtual Network Association", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Web/sites/instance1/slots/stageing/networkconfig/virtualNetwork", + Expected: &SlotVirtualNetworkSwiftConnectionId{ + VirtualNetworkSwiftConnectionId: VirtualNetworkSwiftConnectionId{ + SiteName: "instance1", + ResourceGroup: "mygroup1", + }, + SlotName: "stageing", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := SlotVirtualNetworkSwiftConnectionID(v.Input) + if err != nil { + if v.Expected == nil { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.SiteName != v.Expected.SiteName { + t.Fatalf("Expected %q but got %q for Name", v.Expected.SiteName, actual.SiteName) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.SlotName != v.Expected.SlotName { + t.Fatalf("Expected %q but got %q for SlotName", v.Expected.SlotName, actual.SlotName) + } + } +} diff --git a/azurerm/internal/services/web/parse/virtual_network_swift_connection.go b/azurerm/internal/services/web/parse/virtual_network_swift_connection.go new file mode 100644 index 000000000000..f8e0bc854b99 --- /dev/null +++ b/azurerm/internal/services/web/parse/virtual_network_swift_connection.go @@ -0,0 +1,29 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type VirtualNetworkSwiftConnectionId struct { + SiteName string + ResourceGroup string +} + +func VirtualNetworkSwiftConnectionID(resourceId string) (*VirtualNetworkSwiftConnectionId, error) { + id, err := azure.ParseAzureResourceID(resourceId) + if err != nil { + return nil, fmt.Errorf("Error parsing Azure Resource ID %q", id) + } + + virtualNetworkId := &VirtualNetworkSwiftConnectionId{ + ResourceGroup: id.ResourceGroup, + } + + if virtualNetworkId.SiteName, err = id.PopSegment("sites"); err != nil { + return nil, err + } + + return virtualNetworkId, nil +} diff --git a/azurerm/internal/services/web/parse/virtual_network_swift_connection_test.go b/azurerm/internal/services/web/parse/virtual_network_swift_connection_test.go new file mode 100644 index 000000000000..f1b7abe14e7d --- /dev/null +++ b/azurerm/internal/services/web/parse/virtual_network_swift_connection_test.go @@ -0,0 +1,57 @@ +package parse + +import ( + "testing" +) + +func TestVirtualNetworkSwiftConnectionID(t *testing.T) { + testData := []struct { + Name string + Input string + Expected *VirtualNetworkSwiftConnectionId + }{ + { + Name: "Empty", + Input: "", + Expected: nil, + }, + { + Name: "No Resource Groups Segemt", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Expected: nil, + }, + { + Name: "No Sites Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Web/", + Expected: nil, + }, + { + Name: "Virtual Network Association", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Web/sites/instance1/networkconfig/virtualNetwork", + Expected: &VirtualNetworkSwiftConnectionId{ + SiteName: "instance1", + ResourceGroup: "mygroup1", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := VirtualNetworkSwiftConnectionID(v.Input) + if err != nil { + if v.Expected == nil { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.SiteName != v.Expected.SiteName { + t.Fatalf("Expected %q but got %q for Name", v.Expected.SiteName, actual.SiteName) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + } +} diff --git a/azurerm/internal/services/web/registration.go b/azurerm/internal/services/web/registration.go index fbfabf656b54..496a3972595c 100644 --- a/azurerm/internal/services/web/registration.go +++ b/azurerm/internal/services/web/registration.go @@ -33,18 +33,19 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { // SupportedResources returns the supported Resources supported by this Service func (r Registration) SupportedResources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_app_service_active_slot": resourceArmAppServiceActiveSlot(), - "azurerm_app_service_certificate": resourceArmAppServiceCertificate(), - "azurerm_app_service_certificate_order": resourceArmAppServiceCertificateOrder(), - "azurerm_app_service_custom_hostname_binding": resourceArmAppServiceCustomHostnameBinding(), - "azurerm_app_service_environment": resourceArmAppServiceEnvironment(), - "azurerm_app_service_hybrid_connection": resourceArmAppServiceHybridConnection(), - "azurerm_app_service_plan": resourceArmAppServicePlan(), - "azurerm_app_service_slot": resourceArmAppServiceSlot(), - "azurerm_app_service_source_control_token": resourceArmAppServiceSourceControlToken(), - "azurerm_app_service_virtual_network_swift_connection": resourceArmAppServiceVirtualNetworkSwiftConnection(), - "azurerm_app_service": resourceArmAppService(), - "azurerm_function_app": resourceArmFunctionApp(), - "azurerm_function_app_slot": resourceArmFunctionAppSlot(), + "azurerm_app_service_active_slot": resourceArmAppServiceActiveSlot(), + "azurerm_app_service_certificate": resourceArmAppServiceCertificate(), + "azurerm_app_service_certificate_order": resourceArmAppServiceCertificateOrder(), + "azurerm_app_service_custom_hostname_binding": resourceArmAppServiceCustomHostnameBinding(), + "azurerm_app_service_environment": resourceArmAppServiceEnvironment(), + "azurerm_app_service_hybrid_connection": resourceArmAppServiceHybridConnection(), + "azurerm_app_service_plan": resourceArmAppServicePlan(), + "azurerm_app_service_slot": resourceArmAppServiceSlot(), + "azurerm_app_service_source_control_token": resourceArmAppServiceSourceControlToken(), + "azurerm_app_service_virtual_network_swift_connection": resourceArmAppServiceVirtualNetworkSwiftConnection(), + "azurerm_app_service_slot_virtual_network_swift_connection": resourceArmAppServiceSlotVirtualNetworkSwiftConnection(), + "azurerm_app_service": resourceArmAppService(), + "azurerm_function_app": resourceArmFunctionApp(), + "azurerm_function_app_slot": resourceArmFunctionAppSlot(), } } diff --git a/azurerm/internal/services/web/resource_arm_app_service_slot_virtual_network_swift_connection.go b/azurerm/internal/services/web/resource_arm_app_service_slot_virtual_network_swift_connection.go new file mode 100644 index 000000000000..2a453dd36e73 --- /dev/null +++ b/azurerm/internal/services/web/resource_arm_app_service_slot_virtual_network_swift_connection.go @@ -0,0 +1,229 @@ +package web + +import ( + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web" + "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/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" + subnetParse "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmAppServiceSlotVirtualNetworkSwiftConnection() *schema.Resource { + return &schema.Resource{ + Create: resourceArmAppServiceSlotVirtualNetworkSwiftConnectionCreateUpdate, + Read: resourceArmAppServiceSlotVirtualNetworkSwiftConnectionRead, + Update: resourceArmAppServiceSlotVirtualNetworkSwiftConnectionCreateUpdate, + Delete: resourceArmAppServiceSlotVirtualNetworkSwiftConnectionDelete, + 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{ + "app_service_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: azure.ValidateResourceID, + }, + "subnet_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: azure.ValidateResourceID, + }, + "slot_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.AppServiceName, + }, + }, + } +} + +func resourceArmAppServiceSlotVirtualNetworkSwiftConnectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Web.AppServicesClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + appID, err := ParseAppServiceID(d.Get("app_service_id").(string)) + if err != nil { + return fmt.Errorf("Error parsing Azure Resource ID %q", appID) + } + + subnetID, err := subnetParse.SubnetID(d.Get("subnet_id").(string)) + if err != nil { + return fmt.Errorf("Error parsing Azure Resource ID %q", subnetID) + } + + resourceGroup := appID.ResourceGroup + name := appID.Name + subnetName := subnetID.Name + virtualNetworkName := subnetID.VirtualNetworkName + slotName := d.Get("slot_name").(string) + + if d.IsNewResource() { + existing, err := client.GetSwiftVirtualNetworkConnectionSlot(ctx, resourceGroup, name, slotName) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("failed checking for presence of existing App Service Slot Swift Network Connection %q (Resource Group %q)", name, resourceGroup) + } + } + + if existing.SwiftVirtualNetworkProperties.SubnetResourceID != nil && *existing.SwiftVirtualNetworkProperties.SubnetResourceID != "" { + return tf.ImportAsExistsError("azurerm_app_service_slot_virtual_network_swift_connection", *existing.ID) + } + } + + locks.ByName(virtualNetworkName, network.VirtualNetworkResourceName) + defer locks.UnlockByName(virtualNetworkName, network.VirtualNetworkResourceName) + + locks.ByName(subnetName, network.SubnetResourceName) + defer locks.UnlockByName(subnetName, network.SubnetResourceName) + + appServiceExists, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(appServiceExists.Response) { + return fmt.Errorf("Error retrieving existing App Service %q (Resource Group %q): App Service not found in resource group", name, resourceGroup) + } + return fmt.Errorf("Error retrieving existing App Service %q (Resource Group %q): %s", name, resourceGroup, err) + } + + slotExists, err := client.GetSlot(ctx, resourceGroup, name, slotName) + if err != nil { + if utils.ResponseWasNotFound(slotExists.Response) { + return fmt.Errorf("Error retrieving existing App Service Slot %q (App Service %q / Resource Group %q): App Service not found in resource group", slotName, name, resourceGroup) + } + return fmt.Errorf("Error retrieving existing App Service Slot %q (App Service %q / Resource Group %q): %s", slotName, name, resourceGroup, err) + } + + connectionEnvelope := web.SwiftVirtualNetwork{ + SwiftVirtualNetworkProperties: &web.SwiftVirtualNetworkProperties{ + SubnetResourceID: utils.String(d.Get("subnet_id").(string)), + }, + } + if _, err = client.CreateOrUpdateSwiftVirtualNetworkConnectionSlot(ctx, resourceGroup, name, connectionEnvelope, slotName); err != nil { + return fmt.Errorf("Error creating/updating App Service Slot VNet association between %q (App Service %q / Resource Group %q) and Virtual Network %q: %s", slotName, name, resourceGroup, virtualNetworkName, err) + } + + read, err := client.GetSwiftVirtualNetworkConnectionSlot(ctx, resourceGroup, name, slotName) + if err != nil { + return fmt.Errorf("Error retrieving App Service Slot VNet association between %q (App Service %q / Resource Group %q) and Virtual Network %q: %s", slotName, name, resourceGroup, virtualNetworkName, err) + } + d.SetId(*read.ID) + + return resourceArmAppServiceSlotVirtualNetworkSwiftConnectionRead(d, meta) +} + +func resourceArmAppServiceSlotVirtualNetworkSwiftConnectionRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Web.AppServicesClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SlotVirtualNetworkSwiftConnectionID(d.Id()) + if err != nil { + return err + } + + slot, err := client.GetSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) + if err != nil { + if utils.ResponseWasNotFound(slot.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving existing App Service Slot %q (App Service %q / Resource Group %q): %s", id.SlotName, id.SiteName, id.ResourceGroup, err) + } + appService, err := client.Get(ctx, id.ResourceGroup, id.SiteName) + if err != nil { + if utils.ResponseWasNotFound(appService.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving existing App Service %q (Resource Group %q): %s", id.SiteName, id.ResourceGroup, err) + } + swiftVnet, err := client.GetSwiftVirtualNetworkConnectionSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) + if err != nil { + if utils.ResponseWasNotFound(swiftVnet.Response) { + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving App Service Slot VNet association for %q (App Service %q / Resource Group %q): %s", id.SlotName, id.SiteName, id.ResourceGroup, err) + } + + if swiftVnet.SwiftVirtualNetworkProperties == nil { + return fmt.Errorf("Error retrieving virtual network properties (Slot Name %q / App Service %q / Resource Group %q): `properties` was nil", id.SlotName, id.SiteName, id.ResourceGroup) + } + props := *swiftVnet.SwiftVirtualNetworkProperties + subnetID := props.SubnetResourceID + if subnetID == nil || *subnetID == "" { + d.SetId("") + return nil + } + d.Set("subnet_id", subnetID) + d.Set("app_service_id", appService.ID) + d.Set("slot_name", id.SlotName) + return nil +} + +func resourceArmAppServiceSlotVirtualNetworkSwiftConnectionDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Web.AppServicesClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.SlotVirtualNetworkSwiftConnectionID(d.Id()) + if err != nil { + return err + } + + subnetID, err := subnetParse.SubnetID(d.Get("subnet_id").(string)) + if err != nil { + return fmt.Errorf("Error parsing Subnet Resource ID %q", subnetID) + } + subnetName := subnetID.Name + virtualNetworkName := subnetID.VirtualNetworkName + + locks.ByName(virtualNetworkName, network.VirtualNetworkResourceName) + defer locks.UnlockByName(virtualNetworkName, network.VirtualNetworkResourceName) + + locks.ByName(subnetName, network.SubnetResourceName) + defer locks.UnlockByName(subnetName, network.SubnetResourceName) + + read, err := client.GetSwiftVirtualNetworkConnectionSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) + if err != nil { + return fmt.Errorf("Error making read request on virtual network properties (Slot Name %q / App Service %q / Resource Group %q): %+v", id.SlotName, id.SiteName, id.ResourceGroup, err) + } + if read.SwiftVirtualNetworkProperties == nil { + return fmt.Errorf("Error retrieving virtual network properties (Slot Name %q / App Service %q / Resource Group %q): `properties` was nil", id.SlotName, id.SiteName, id.ResourceGroup) + } + props := *read.SwiftVirtualNetworkProperties + subnet := props.SubnetResourceID + if subnet == nil || *subnet == "" { + // assume deleted + return nil + } + + resp, err := client.DeleteSwiftVirtualNetworkSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) + if err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("Error deleting virtual network properties (Slot Name %q / App Service %q / Resource Group %q): %+v", id.SlotName, id.SiteName, id.ResourceGroup, err) + } + } + + return nil +} diff --git a/azurerm/internal/services/web/resource_arm_app_service_virtual_network_swift_connection.go b/azurerm/internal/services/web/resource_arm_app_service_virtual_network_swift_connection.go index 47c6963be53b..a50b9827ec09 100644 --- a/azurerm/internal/services/web/resource_arm_app_service_virtual_network_swift_connection.go +++ b/azurerm/internal/services/web/resource_arm_app_service_virtual_network_swift_connection.go @@ -4,13 +4,15 @@ import ( "fmt" "time" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" - "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web" "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/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/locks" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" + subnetParse "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -42,7 +44,6 @@ func resourceArmAppServiceVirtualNetworkSwiftConnection() *schema.Resource { "subnet_id": { Type: schema.TypeString, Required: true, - ForceNew: false, ValidateFunc: azure.ValidateResourceID, }, }, @@ -51,21 +52,36 @@ func resourceArmAppServiceVirtualNetworkSwiftConnection() *schema.Resource { func resourceArmAppServiceVirtualNetworkSwiftConnectionCreateUpdate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Web.AppServicesClient - ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Get("app_service_id").(string)) + appID, err := ParseAppServiceID(d.Get("app_service_id").(string)) if err != nil { - return fmt.Errorf("Error parsing Azure Resource ID %q", id) + return fmt.Errorf("Error parsing App Service Resource ID %q", appID) } - subnetID, err := azure.ParseAzureResourceID(d.Get("subnet_id").(string)) + + subnetID, err := subnetParse.SubnetID(d.Get("subnet_id").(string)) if err != nil { - return fmt.Errorf("Error parsing Azure Resource ID %q", id) + return fmt.Errorf("Error parsing Subnet Resource ID %q", subnetID) + } + + resourceGroup := appID.ResourceGroup + name := appID.Name + subnetName := subnetID.Name + virtualNetworkName := subnetID.VirtualNetworkName + + if d.IsNewResource() { + existing, err := client.GetSwiftVirtualNetworkConnection(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("failed checking for presence of existing App Service Swift Network Connection %q (Resource Group %q)", name, resourceGroup) + } + } + + if existing.SwiftVirtualNetworkProperties.SubnetResourceID != nil && *existing.SwiftVirtualNetworkProperties.SubnetResourceID != "" { + return tf.ImportAsExistsError("azurerm_app_service_virtual_network_swift_connection", *existing.ID) + } } - resourceGroup := id.ResourceGroup - name := id.Path["sites"] - subnetName := subnetID.Path["subnets"] - virtualNetworkName := subnetID.Path["virtualNetworks"] locks.ByName(virtualNetworkName, network.VirtualNetworkResourceName) defer locks.UnlockByName(virtualNetworkName, network.VirtualNetworkResourceName) @@ -104,34 +120,32 @@ func resourceArmAppServiceVirtualNetworkSwiftConnectionRead(d *schema.ResourceDa ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Id()) + id, err := parse.VirtualNetworkSwiftConnectionID(d.Id()) if err != nil { - return fmt.Errorf("Error parsing Azure Resource ID %q", id) + return err } - resourceGroup := id.ResourceGroup - name := id.Path["sites"] - appService, err := client.Get(ctx, resourceGroup, name) + appService, err := client.Get(ctx, id.ResourceGroup, id.SiteName) if err != nil { if utils.ResponseWasNotFound(appService.Response) { d.SetId("") return nil } - return fmt.Errorf("Error retrieving existing App Service %q (Resource Group %q): %s", name, resourceGroup, err) + return fmt.Errorf("Error retrieving existing App Service %q (Resource Group %q): %s", id.SiteName, id.ResourceGroup, err) } - resp, err := client.GetSwiftVirtualNetworkConnection(ctx, resourceGroup, name) + swiftVnet, err := client.GetSwiftVirtualNetworkConnection(ctx, id.ResourceGroup, id.SiteName) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if utils.ResponseWasNotFound(swiftVnet.Response) { d.SetId("") return nil } - return fmt.Errorf("Error retrieving App Service VNet association for %q (Resource Group %q): %s", name, resourceGroup, err) + return fmt.Errorf("Error retrieving App Service VNet association for %q (Resource Group %q): %s", id.SiteName, id.ResourceGroup, err) } - if resp.SwiftVirtualNetworkProperties == nil { - return fmt.Errorf("Error retrieving virtual network properties (App Service %q / Resource Group %q): `properties` was nil", name, resourceGroup) + if swiftVnet.SwiftVirtualNetworkProperties == nil { + return fmt.Errorf("Error retrieving virtual network properties (App Service %q / Resource Group %q): `properties` was nil", id.SiteName, id.ResourceGroup) } - props := *resp.SwiftVirtualNetworkProperties + props := *swiftVnet.SwiftVirtualNetworkProperties subnetID := props.SubnetResourceID if subnetID == nil || *subnetID == "" { d.SetId("") @@ -147,18 +161,17 @@ func resourceArmAppServiceVirtualNetworkSwiftConnectionDelete(d *schema.Resource ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := azure.ParseAzureResourceID(d.Get("app_service_id").(string)) + id, err := parse.VirtualNetworkSwiftConnectionID(d.Id()) if err != nil { - return fmt.Errorf("Error parsing Azure Resource ID %q", id) + return err } - subnetID, err := azure.ParseAzureResourceID(d.Get("subnet_id").(string)) + + subnetID, err := subnetParse.SubnetID(d.Get("subnet_id").(string)) if err != nil { - return fmt.Errorf("Error parsing Azure Resource ID %q", id) + return fmt.Errorf("Error parsing Subnet Resource ID %q", subnetID) } - resourceGroup := id.ResourceGroup - name := id.Path["sites"] - subnetName := subnetID.Path["subnets"] - virtualNetworkName := subnetID.Path["virtualNetworks"] + subnetName := subnetID.Name + virtualNetworkName := subnetID.VirtualNetworkName locks.ByName(virtualNetworkName, network.VirtualNetworkResourceName) defer locks.UnlockByName(virtualNetworkName, network.VirtualNetworkResourceName) @@ -166,12 +179,12 @@ func resourceArmAppServiceVirtualNetworkSwiftConnectionDelete(d *schema.Resource locks.ByName(subnetName, network.SubnetResourceName) defer locks.UnlockByName(subnetName, network.SubnetResourceName) - read, err := client.GetSwiftVirtualNetworkConnection(ctx, resourceGroup, name) + read, err := client.GetSwiftVirtualNetworkConnection(ctx, id.ResourceGroup, id.SiteName) if err != nil { - return fmt.Errorf("Error making read request on virtual network properties (App Service %q / Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("Error making read request on virtual network properties (App Service %q / Resource Group %q): %+v", id.SiteName, id.ResourceGroup, err) } if read.SwiftVirtualNetworkProperties == nil { - return fmt.Errorf("Error retrieving virtual network properties (App Service %q / Resource Group %q): `properties` was nil", name, resourceGroup) + return fmt.Errorf("Error retrieving virtual network properties (App Service %q / Resource Group %q): `properties` was nil", id.SiteName, id.ResourceGroup) } props := *read.SwiftVirtualNetworkProperties subnet := props.SubnetResourceID @@ -180,10 +193,10 @@ func resourceArmAppServiceVirtualNetworkSwiftConnectionDelete(d *schema.Resource return nil } - resp, err := client.DeleteSwiftVirtualNetwork(ctx, resourceGroup, name) + resp, err := client.DeleteSwiftVirtualNetwork(ctx, id.ResourceGroup, id.SiteName) if err != nil { if !utils.ResponseWasNotFound(resp) { - return fmt.Errorf("Error deleting virtual network properties (App Service %q / Resource Group %q): %+v", name, resourceGroup, err) + return fmt.Errorf("Error deleting virtual network properties (App Service %q / Resource Group %q): %+v", id.SiteName, id.ResourceGroup, err) } } diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_slot_virtual_network_association_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_slot_virtual_network_association_test.go new file mode 100644 index 000000000000..2bcdc3f4aefd --- /dev/null +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_slot_virtual_network_association_test.go @@ -0,0 +1,300 @@ +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/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_slot_virtual_network_swift_connection", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionExists(data.ResourceName), + resource.TestCheckResourceAttrSet(data.ResourceName, "subnet_id"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_slot_virtual_network_swift_connection", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceVirtualNetworkSwiftConnectionExists(data.ResourceName), + ), + }, + data.RequiresImportErrorStep(testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_requiresImport), + }, + }) +} + +func TestAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_slot_virtual_network_swift_connection", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionExists(data.ResourceName), + resource.TestCheckResourceAttrSet(data.ResourceName, "subnet_id"), + ), + }, + { + Config: testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_update(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionExists(data.ResourceName), + resource.TestCheckResourceAttrSet(data.ResourceName, "subnet_id"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_disappears(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_slot_virtual_network_swift_connection", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionExists(data.ResourceName), + resource.TestCheckResourceAttrSet(data.ResourceName, "subnet_id"), + testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionDisappears(data.ResourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServicesClient + 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) + } + + id, err := parse.SlotVirtualNetworkSwiftConnectionID(rs.Primary.ID) + if err != nil { + return err + } + + resp, err := client.GetSwiftVirtualNetworkConnectionSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: App Service Slot Virtual Network Association %q (Site: %q, Resource Group: %q) does not exist", id.SlotName, id.SiteName, id.ResourceGroup) + } + + return fmt.Errorf("Bad: Get on appServicesClient: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionDisappears(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServicesClient + 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) + } + + id, err := parse.SlotVirtualNetworkSwiftConnectionID(rs.Primary.ID) + if err != nil { + return err + } + + resp, err := client.DeleteSwiftVirtualNetworkSlot(ctx, id.ResourceGroup, id.SiteName, id.SlotName) + if err != nil { + if !utils.ResponseWasNotFound(resp) { + return fmt.Errorf("Bad: Delete on appServicesClient: %+v", err) + } + } + + return nil + } +} + +func testCheckAzureRMAppServiceSlotVirtualNetworkSwiftConnectionDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServicesClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_app_service_slot_virtual_network_swift_connection" { + continue + } + + id, err := parse.SlotVirtualNetworkSwiftConnectionID(rs.Primary.ID) + if err != nil { + return err + } + + resp, err := client.GetSwiftVirtualNetworkConnectionSlot(ctx, id.ResourceGroup, id.SiteName, id.SiteName) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + return err + } + + return nil + } + + return nil +} + +func testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_base(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-appservice-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest-VNET-%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + lifecycle { + ignore_changes = ["ddos_protection_plan"] + } +} + +resource "azurerm_subnet" "test1" { + name = "acctestSubnet1" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefix = "10.0.1.0/24" + + delegation { + name = "acctestdelegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_subnet" "test2" { + name = "acctestSubnet2" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefix = "10.0.2.0/24" + + delegation { + name = "acctestdelegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_app_service_plan" "test" { + name = "acctest-ASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctest-AS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id +} + +resource "azurerm_app_service_slot" "test-staging" { + name = "acctest-AS-%d-staging" + app_service_name = azurerm_app_service.test.name + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_basic(data acceptance.TestData) string { + template := testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_base(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_slot_virtual_network_swift_connection" "test" { + slot_name = azurerm_app_service_slot.test-staging.name + app_service_id = azurerm_app_service.test.id + subnet_id = azurerm_subnet.test1.id +} +`, template) +} + +func testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_update(data acceptance.TestData) string { + template := testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_base(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_slot_virtual_network_swift_connection" "test" { + slot_name = azurerm_app_service_slot.test-staging.name + app_service_id = azurerm_app_service.test.id + subnet_id = azurerm_subnet.test2.id +} +`, template) +} + +func testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMAppServiceSlotVirtualNetworkSwiftConnection_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_slot_virtual_network_swift_connection" "import" { + slot_name = azurerm_app_service_slot_virtual_network_swift_connection.test.slot_name + app_service_id = azurerm_app_service_slot_virtual_network_swift_connection.test.app_service_id + subnet_id = azurerm_app_service_slot_virtual_network_swift_connection.test.subnet_id +} +`, template) +} diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_virtual_network_association_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_virtual_network_association_test.go index 3ea415bb12d5..3883bb55cb7f 100644 --- a/azurerm/internal/services/web/tests/resource_arm_app_service_virtual_network_association_test.go +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_virtual_network_association_test.go @@ -6,14 +6,12 @@ import ( "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/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web/parse" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -// TODO: requires import - func TestAccAzureRMAppServiceVirtualNetworkSwiftConnection_basic(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_service_virtual_network_swift_connection", "test") @@ -34,6 +32,25 @@ func TestAccAzureRMAppServiceVirtualNetworkSwiftConnection_basic(t *testing.T) { }) } +func TestAccAzureRMAppServiceVirtualNetworkSwiftConnection_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_virtual_network_swift_connection", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceVirtualNetworkSwiftConnectionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceVirtualNetworkSwiftConnection_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceVirtualNetworkSwiftConnectionExists(data.ResourceName), + ), + }, + data.RequiresImportErrorStep(testAccAzureRMAppServiceVirtualNetworkSwiftConnection_requiresImport), + }, + }) +} + func TestAccAzureRMAppServiceVirtualNetworkSwiftConnection_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_service_virtual_network_swift_connection", "test") @@ -92,18 +109,15 @@ func testCheckAzureRMAppServiceVirtualNetworkSwiftConnectionExists(resourceName return fmt.Errorf("Not found: %s", resourceName) } - id := rs.Primary.Attributes["id"] - parsedID, err := azure.ParseAzureResourceID(id) + id, err := parse.VirtualNetworkSwiftConnectionID(rs.Primary.Attributes["id"]) if err != nil { return fmt.Errorf("Error parsing Azure Resource ID %q", id) } - name := parsedID.Path["sites"] - resourceGroup := parsedID.ResourceGroup - resp, err := client.GetSwiftVirtualNetworkConnection(ctx, resourceGroup, name) + resp, err := client.GetSwiftVirtualNetworkConnection(ctx, id.ResourceGroup, id.SiteName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Bad: App Service Virtual Network Association %q (Resource Group: %q) does not exist", name, resourceGroup) + return fmt.Errorf("Bad: App Service Virtual Network Association %q (Resource Group: %q) does not exist", id.SiteName, id.ResourceGroup) } return fmt.Errorf("Bad: Get on appServicesClient: %+v", err) @@ -124,15 +138,12 @@ func testCheckAzureRMAppServiceVirtualNetworkSwiftConnectionDisappears(resourceN return fmt.Errorf("Not found: %s", resourceName) } - id := rs.Primary.Attributes["id"] - parsedID, err := azure.ParseAzureResourceID(id) + id, err := parse.VirtualNetworkSwiftConnectionID(rs.Primary.Attributes["id"]) if err != nil { return fmt.Errorf("Error parsing Azure Resource ID %q", id) } - name := parsedID.Path["sites"] - resourceGroup := parsedID.ResourceGroup - resp, err := client.DeleteSwiftVirtualNetwork(ctx, resourceGroup, name) + resp, err := client.DeleteSwiftVirtualNetwork(ctx, id.ResourceGroup, id.SiteName) if err != nil { if !utils.ResponseWasNotFound(resp) { return fmt.Errorf("Bad: Delete on appServicesClient: %+v", err) @@ -152,15 +163,12 @@ func testCheckAzureRMAppServiceVirtualNetworkSwiftConnectionDestroy(s *terraform continue } - id := rs.Primary.Attributes["id"] - parsedID, err := azure.ParseAzureResourceID(id) + id, err := parse.VirtualNetworkSwiftConnectionID(rs.Primary.Attributes["id"]) if err != nil { return fmt.Errorf("Error parsing Azure Resource ID %q", id) } - name := parsedID.Path["sites"] - resourceGroup := parsedID.ResourceGroup - resp, err := client.GetSwiftVirtualNetworkConnection(ctx, resourceGroup, name) + resp, err := client.GetSwiftVirtualNetworkConnection(ctx, id.ResourceGroup, id.SiteName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { @@ -271,3 +279,15 @@ resource "azurerm_app_service_virtual_network_swift_connection" "test" { } `, template) } + +func testAccAzureRMAppServiceVirtualNetworkSwiftConnection_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMAppServiceVirtualNetworkSwiftConnection_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_virtual_network_swift_connection" "import" { + app_service_id = azurerm_app_service_virtual_network_swift_connection.test.app_service_id + subnet_id = azurerm_app_service_virtual_network_swift_connection.test.subnet_id +} +`, template) +} diff --git a/website/azurerm.erb b/website/azurerm.erb index 833df21d6457..a27c0675e1e3 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -830,6 +830,10 @@ azurerm_app_service_virtual_network_swift_connection +
  • + azurerm_app_service_slot_virtual_network_swift_connection +
  • +
  • azurerm_function_app
  • diff --git a/website/docs/r/app_service_slot_virtual_network_swift_connection.html.markdown b/website/docs/r/app_service_slot_virtual_network_swift_connection.html.markdown new file mode 100644 index 000000000000..253fde4ebb53 --- /dev/null +++ b/website/docs/r/app_service_slot_virtual_network_swift_connection.html.markdown @@ -0,0 +1,109 @@ +--- +subcategory: "App Service (Web Apps)" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_app_service_slot_virtual_network_swift_connection" +description: |- + Manages an App Service's Slot Virtual Network Association. + +--- + +# azurerm_app_service_slot_virtual_network_swift_connection + +Manages an App Service Slot's Virtual Network Association (this is for the [Regional VNet Integration](https://docs.microsoft.com/en-us/azure/app-service/web-sites-integrate-with-vnet#regional-vnet-integration) which is still in preview). + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resources" + location = "uksouth" +} + +resource "azurerm_virtual_network" "example" { + name = "example-virtual-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 = "example-subnet" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name + address_prefix = "10.0.1.0/24" + + delegation { + name = "example-delegation" + + service_delegation { + name = "Microsoft.Web/serverFarms" + actions = ["Microsoft.Network/virtualNetworks/subnets/action"] + } + } +} + +resource "azurerm_app_service_plan" "example" { + name = "example-service-plan" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "example" { + name = "example-app-service" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id +} + +resource "azurerm_app_service_slot" "example-staging" { + name = "staging" + app_service_name = azurerm_app_service.example.name + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id +} + +resource "azurerm_app_service_slot_virtual_network_swift_connection" "example" { + slot_name = azurerm_app_service_slot.example-staging.name + app_service_id = azurerm_app_service.example.id + subnet_id = azurerm_subnet.example.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `app_service_id` - (Required) The ID of the App Service to associate to the VNet. Changing this forces a new resource to be created. + +* `slot_name` - (Required) The name of the App Service Slot. Changing this forces a new resource to be created. + +* `subnet_id` - (Required) The ID of the subnet the app service will be associated to (the subnet must have a `service_delegation` configured for `Microsoft.Web/serverFarms`). + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the App Service Slot Virtual Network Association + +## 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 App Service Virtual Network Association. +* `update` - (Defaults to 30 minutes) Used when updating the App Service Virtual Network Association. +* `read` - (Defaults to 5 minutes) Used when retrieving the App Service Virtual Network Association. +* `delete` - (Defaults to 30 minutes) Used when deleting the App Service Virtual Network Association. + +## Import + +App Service Slot Virtual Network Associations can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_app_service_slot_virtual_network_swift_connection.myassociation /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Web/sites/instance1/slots/stageing/networkconfig/virtualNetwork +``` diff --git a/website/docs/r/app_service_virtual_network_swift_connection.html.markdown b/website/docs/r/app_service_virtual_network_swift_connection.html.markdown index 4450494cef1a..e20cf5c4104d 100644 --- a/website/docs/r/app_service_virtual_network_swift_connection.html.markdown +++ b/website/docs/r/app_service_virtual_network_swift_connection.html.markdown @@ -14,26 +14,26 @@ Manages an App Service Virtual Network Association (this is for the [Regional VN ## Example Usage ```hcl -resource "azurerm_resource_group" "test" { +resource "azurerm_resource_group" "example" { name = "example-resources" location = "uksouth" } -resource "azurerm_virtual_network" "test" { - name = "acctestvnet" +resource "azurerm_virtual_network" "example" { + name = "example-virtual-network" address_space = ["10.0.0.0/16"] - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name } -resource "azurerm_subnet" "test1" { - name = "acctestsubnet1" - resource_group_name = azurerm_resource_group.test.name - virtual_network_name = azurerm_virtual_network.test.name +resource "azurerm_subnet" "example" { + name = "example-subnet" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name address_prefix = "10.0.1.0/24" delegation { - name = "acctestdelegation" + name = "example-delegation" service_delegation { name = "Microsoft.Web/serverFarms" @@ -42,10 +42,10 @@ resource "azurerm_subnet" "test1" { } } -resource "azurerm_app_service_plan" "test" { - name = "acctestasp" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name +resource "azurerm_app_service_plan" "example" { + name = "example-app-service-plan" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name sku { tier = "Standard" @@ -53,16 +53,16 @@ resource "azurerm_app_service_plan" "test" { } } -resource "azurerm_app_service" "test" { - name = "acctestas" - location = azurerm_resource_group.test.location - resource_group_name = azurerm_resource_group.test.name - app_service_plan_id = azurerm_app_service_plan.test.id +resource "azurerm_app_service" "example" { + name = "example-app-service" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + app_service_plan_id = azurerm_app_service_plan.example.id } -resource "azurerm_app_service_virtual_network_swift_connection" "test" { - app_service_id = azurerm_app_service.test.id - subnet_id = azurerm_subnet.test1.id +resource "azurerm_app_service_virtual_network_swift_connection" "example" { + app_service_id = azurerm_app_service.example.id + subnet_id = azurerm_subnet.example.id } ```