From 13e50e11c395bba6b4e51bc1b0719a258ed0811d Mon Sep 17 00:00:00 2001 From: jackofallops Date: Fri, 24 Jan 2020 08:59:24 +0000 Subject: [PATCH 01/26] Adds new resource and datasource for App Serice Environment (v2 support only) Replaces https://github.com/terraform-providers/terraform-provider-azurerm/pull/4956/ Co-authored-by: @justinbarias --- azurerm/internal/services/network/subnet.go | 54 ++++ .../services/network/virtual_network.go | 49 +++ .../services/web/app_service_environment.go | 74 +++++ .../web/app_service_environment_test.go | 103 ++++++ .../internal/services/web/client/client.go | 26 +- .../data_source_app_service_environment.go | 72 +++++ azurerm/internal/services/web/registration.go | 6 +- .../resource_arm_app_service_environment.go | 282 ++++++++++++++++ ...ata_source_app_service_environment_test.go | 39 +++ ...source_arm_app_service_environment_test.go | 302 ++++++++++++++++++ vendor/modules.txt | 1 + .../d/app_service_environment.html.markdown | 43 +++ .../r/app_service_environment.html.markdown | 84 +++++ 13 files changed, 1123 insertions(+), 12 deletions(-) create mode 100644 azurerm/internal/services/network/subnet.go create mode 100644 azurerm/internal/services/network/virtual_network.go create mode 100644 azurerm/internal/services/web/app_service_environment.go create mode 100644 azurerm/internal/services/web/app_service_environment_test.go create mode 100644 azurerm/internal/services/web/data_source_app_service_environment.go create mode 100644 azurerm/internal/services/web/resource_arm_app_service_environment.go create mode 100644 azurerm/internal/services/web/tests/data_source_app_service_environment_test.go create mode 100644 azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go create mode 100644 website/docs/d/app_service_environment.html.markdown create mode 100644 website/docs/r/app_service_environment.html.markdown diff --git a/azurerm/internal/services/network/subnet.go b/azurerm/internal/services/network/subnet.go new file mode 100644 index 000000000000..b6a4994df3f0 --- /dev/null +++ b/azurerm/internal/services/network/subnet.go @@ -0,0 +1,54 @@ +package network + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type SubnetID struct { + ResourceGroup string + VirtualNetworkName string + Name string +} + +func ParseSubnetID(input string) (*SubnetID, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse Subnet ID %q: %+v", input, err) + } + + subnet := SubnetID{ + ResourceGroup: id.ResourceGroup, + } + + if subnet.VirtualNetworkName, err = id.PopSegment("virtualNetworks"); err != nil { + return nil, err + } + + if subnet.Name, err = id.PopSegment("subnets"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &subnet, nil +} + +// ValidateSubnetID validates that the specified ID is a valid App Service ID +func ValidateSubnetID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := ParseSubnetID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} diff --git a/azurerm/internal/services/network/virtual_network.go b/azurerm/internal/services/network/virtual_network.go new file mode 100644 index 000000000000..ffd47239f6ff --- /dev/null +++ b/azurerm/internal/services/network/virtual_network.go @@ -0,0 +1,49 @@ +package network + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type VirtualNetworkID struct { + ResourceGroup string + Name string +} + +func ParseVirtualNetworkID(input string) (*VirtualNetworkID, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse Subnet ID %q: %+v", input, err) + } + + vnet := VirtualNetworkID{ + ResourceGroup: id.ResourceGroup, + } + + if vnet.Name, err = id.PopSegment("virtualNetworks"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &vnet, nil +} + +// ValidateVirtualNetworkID validates that the specified ID is a valid App Service ID +func ValidateVirtualNetworkID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := ParseVirtualNetworkID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} diff --git a/azurerm/internal/services/web/app_service_environment.go b/azurerm/internal/services/web/app_service_environment.go new file mode 100644 index 000000000000..6f4eba92fc6a --- /dev/null +++ b/azurerm/internal/services/web/app_service_environment.go @@ -0,0 +1,74 @@ +package web + +import ( + "fmt" + "regexp" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type AppServiceEnvironmentResourceID struct { + ResourceGroup string + Name string +} + +func ParseAppServiceEnvironmentID(input string) (*AppServiceEnvironmentResourceID, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse App Service Environment ID %q: %+v", input, err) + } + + appServiceEnvironment := AppServiceEnvironmentResourceID{ + ResourceGroup: id.ResourceGroup, + } + + if appServiceEnvironment.Name, err = id.PopSegment("hostingEnvironments"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &appServiceEnvironment, nil +} + +// ValidateAppServiceID validates that the specified ID is a valid App Service ID +func ValidateAppServiceEnvironmentID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := ParseAppServiceEnvironmentID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} + +func validateAppServiceEnvironmentName(v interface{}, k string) (warnings []string, errors []error) { + value := v.(string) + + if matched := regexp.MustCompile(`^[0-9a-zA-Z][-0-9a-zA-Z]{0,61}[0-9a-zA-Z]$`).Match([]byte(value)); !matched { + errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes up to 60 characters in length, and must start and end in an alphanumeric", k)) + } + + return warnings, errors +} + +func validateAppServiceEnvironmentPricingTier(v interface{}, k string) (warnings []string, errors []error) { + tier := v.(string) + + valid := []string{"I1", "I2", "I3"} + + for _, val := range valid { + if val == tier { + return + } + } + errors = append(errors, fmt.Errorf("pricing_tier must be one of %q", valid)) + return warnings, errors +} diff --git a/azurerm/internal/services/web/app_service_environment_test.go b/azurerm/internal/services/web/app_service_environment_test.go new file mode 100644 index 000000000000..942cac22492f --- /dev/null +++ b/azurerm/internal/services/web/app_service_environment_test.go @@ -0,0 +1,103 @@ +package web + +import "testing" + +func TestParseAppServiceEnvironmentID(t *testing.T) { + testData := []struct { + Name string + Input string + Expected *AppServiceEnvironmentResourceID + }{ + { + Name: "Empty", + Input: "", + Expected: nil, + }, + { + Name: "No Resource Groups Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Expected: nil, + }, + { + Name: "No Resource Groups Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + Expected: nil, + }, + { + Name: "Resource Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/", + Expected: nil, + }, + { + Name: "Missing environment name value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/providers/Microsoft.Web/hostingEnvironments/", + Expected: nil, + }, + { + Name: "Valid", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup1/providers/Microsoft.Web/hostingEnvironments/TestASEv2", + Expected: &AppServiceEnvironmentResourceID{ + ResourceGroup: "testGroup1", + Name: "TestASEv2", + }, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := ParseAppServiceEnvironmentID(v.Input) + if err != nil { + if v.Expected == nil { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.Name != v.Expected.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expected.Name, actual.Name) + } + + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for Resource Group", v.Expected.ResourceGroup, actual.ResourceGroup) + } + } +} + +func TestValidateAppServiceEnvironmentID(t *testing.T) { + cases := []struct { + ID string + Valid bool + }{ + { + ID: "", + Valid: false, + }, + { + ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + Valid: false, + }, + { + ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/", + Valid: false, + }, + { + ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/providers/Microsoft.Web/hostingEnvironments/", + Valid: false, + }, + { + ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup1/providers/Microsoft.Web/hostingEnvironments/TestASEv2", + Valid: true, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.ID) + _, errors := ValidateAppServiceEnvironmentID(tc.ID, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/azurerm/internal/services/web/client/client.go b/azurerm/internal/services/web/client/client.go index 696f8b593547..0ff3d10a458c 100644 --- a/azurerm/internal/services/web/client/client.go +++ b/azurerm/internal/services/web/client/client.go @@ -2,18 +2,23 @@ package client import ( "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web" + asev2 "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/common" ) type Client struct { - AppServicePlansClient *web.AppServicePlansClient - AppServicesClient *web.AppsClient - BaseClient *web.BaseClient - CertificatesClient *web.CertificatesClient - CertificatesOrderClient *web.AppServiceCertificateOrdersClient + AppServiceEnvironmentsClient *asev2.AppServiceEnvironmentsClient + AppServicePlansClient *web.AppServicePlansClient + AppServicesClient *web.AppsClient + BaseClient *web.BaseClient + CertificatesClient *web.CertificatesClient + CertificatesOrderClient *web.AppServiceCertificateOrdersClient } func NewClient(o *common.ClientOptions) *Client { + appServiceEnvironmentsClient := asev2.NewAppServiceEnvironmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&appServiceEnvironmentsClient.Client, o.ResourceManagerAuthorizer) + appServicePlansClient := web.NewAppServicePlansClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&appServicePlansClient.Client, o.ResourceManagerAuthorizer) @@ -30,10 +35,11 @@ func NewClient(o *common.ClientOptions) *Client { o.ConfigureClient(&certificatesOrderClient.Client, o.ResourceManagerAuthorizer) return &Client{ - AppServicePlansClient: &appServicePlansClient, - AppServicesClient: &appServicesClient, - BaseClient: &baseClient, - CertificatesClient: &certificatesClient, - CertificatesOrderClient: &certificatesOrderClient, + AppServiceEnvironmentsClient: &appServiceEnvironmentsClient, + AppServicePlansClient: &appServicePlansClient, + AppServicesClient: &appServicesClient, + BaseClient: &baseClient, + CertificatesClient: &certificatesClient, + CertificatesOrderClient: &certificatesOrderClient, } } diff --git a/azurerm/internal/services/web/data_source_app_service_environment.go b/azurerm/internal/services/web/data_source_app_service_environment.go new file mode 100644 index 000000000000..c95e62f39355 --- /dev/null +++ b/azurerm/internal/services/web/data_source_app_service_environment.go @@ -0,0 +1,72 @@ +package web + +import ( + "fmt" + "time" + + "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/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceArmAppServiceEnvironment() *schema.Resource { + return &schema.Resource{ + Read: dataSourceArmAppServiceEnvironmentRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "front_end_scale_factor": { + Type: schema.TypeInt, + Computed: true, + }, + + "pricing_tier": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tags.SchemaDataSource(), + }, + } +} + +func dataSourceArmAppServiceEnvironmentRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Web.AppServiceEnvironmentsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + resourceGroup := d.Get("resource_group_name").(string) + name := d.Get("name").(string) + + resp, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Error: App Service Environment %q (Resource Group %q) was not found", name, resourceGroup) + } + return fmt.Errorf("Error making read request on Azure App Service Environment %q: %+v", name, err) + } + + d.SetId(*resp.ID) + + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + d.Set("front_end_scale_factor", int(*resp.FrontEndScaleFactor)) + d.Set("pricing_tier", convertToIsolatedSKU(*resp.MultiSize)) + d.Set("location", azure.NormalizeLocation(*resp.Location)) + + return tags.FlattenAndSet(d, resp.Tags) +} diff --git a/azurerm/internal/services/web/registration.go b/azurerm/internal/services/web/registration.go index 53fc4553211b..37589d215f5b 100644 --- a/azurerm/internal/services/web/registration.go +++ b/azurerm/internal/services/web/registration.go @@ -21,10 +21,11 @@ func (r Registration) WebsiteCategories() []string { // SupportedDataSources returns the supported Data Sources supported by this Service func (r Registration) SupportedDataSources() map[string]*schema.Resource { return map[string]*schema.Resource{ - "azurerm_app_service_plan": dataSourceAppServicePlan(), - "azurerm_app_service_certificate": dataSourceAppServiceCertificate(), "azurerm_app_service": dataSourceArmAppService(), "azurerm_app_service_certificate_order": dataSourceArmAppServiceCertificateOrder(), + "azurerm_app_service_environment": dataSourceArmAppServiceEnvironment(), + "azurerm_app_service_certificate": dataSourceAppServiceCertificate(), //TODO: rename this for consistency? + "azurerm_app_service_plan": dataSourceAppServicePlan(), //TODO: rename this for consistency? "azurerm_function_app": dataSourceArmFunctionApp(), } } @@ -36,6 +37,7 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "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_plan": resourceArmAppServicePlan(), "azurerm_app_service_slot": resourceArmAppServiceSlot(), "azurerm_app_service_source_control_token": resourceArmAppServiceSourceControlToken(), diff --git a/azurerm/internal/services/web/resource_arm_app_service_environment.go b/azurerm/internal/services/web/resource_arm_app_service_environment.go new file mode 100644 index 000000000000..cfd3e9e8d021 --- /dev/null +++ b/azurerm/internal/services/web/resource_arm_app_service_environment.go @@ -0,0 +1,282 @@ +package web + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web" + "github.com/hashicorp/go-azure-helpers/response" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags" + azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceArmAppServiceEnvironment() *schema.Resource { + return &schema.Resource{ + Create: resourceArmAppServiceEnvironmentCreateOrUpdate, + Read: resourceArmAppServiceEnvironmentRead, + Update: resourceArmAppServiceEnvironmentCreateOrUpdate, + Delete: resourceArmAppServiceEnvironmentDelete, + Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { + _, err := ParseAppServiceEnvironmentID(id) + return err + }), + + // Need to find sane values for below, some operations on this resource can take an exceptionally long time + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(4 * time.Hour), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(4 * time.Hour), + Delete: schema.DefaultTimeout(4 * time.Hour), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateAppServiceEnvironmentName, + }, + + "internal_load_balancing_mode": { + Type: schema.TypeString, + Optional: true, + Default: string(web.InternalLoadBalancingModeNone), + ValidateFunc: validation.StringInSlice([]string{ + string(web.InternalLoadBalancingModeNone), + string(web.InternalLoadBalancingModePublishing), + string(web.InternalLoadBalancingModeWeb), + }, false), + }, + + "subnet_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: network.ValidateSubnetID, + }, + + // Note: This is currently 'multiSize' in the API for historic v1 reasons, may change in future? + "pricing_tier": { + Type: schema.TypeString, + Optional: true, + Default: "I1", + ValidateFunc: validateAppServiceEnvironmentPricingTier, + }, + + "front_end_scale_factor": { + Type: schema.TypeInt, + Optional: true, + Default: 15, + ValidateFunc: validation.IntBetween(5, 15), + }, + + "location": { + Type: schema.TypeString, + Computed: true, + StateFunc: azure.NormalizeLocation, + }, + + "resource_group_name": { + Type: schema.TypeString, + Computed: true, + }, + + "tags": tags.Schema(), + }, + } +} +func resourceArmAppServiceEnvironmentCreateOrUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Web.AppServiceEnvironmentsClient + vnetClient := meta.(*clients.Client).Network.VnetClient + ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + name := d.Get("name").(string) + internalLoadBalancingMode := d.Get("internal_load_balancing_mode").(string) + t := d.Get("tags").(map[string]interface{}) + + subnetId := d.Get("subnet_id").(string) + subnet, err := network.ParseSubnetID(subnetId) + if err != nil { + return fmt.Errorf("Error parsing subnet id %q: %+v", subnetId, err) + } + + resourceGroup := subnet.ResourceGroup + + vnet, err := vnetClient.Get(ctx, resourceGroup, subnet.VirtualNetworkName, "") + if err != nil { + return fmt.Errorf("Error reading Virtual Network %q for App Service Environment %q: %+v", subnet.VirtualNetworkName, name, err) + } + + var location string + if vnetLoc := vnet.Location; vnetLoc != nil { + location = azure.NormalizeLocation(*vnetLoc) + } else { + return fmt.Errorf("Error determining Location from Virtual Network %s", *vnet.Name) + } + + frontEndScaleFactor := d.Get("front_end_scale_factor").(int) + + pricingTier := d.Get("pricing_tier").(string) + + // the SDK is coded primarily for v1, which needs a non-null entry for workerpool, so we construct an empty slice for it + wp := []web.WorkerPool{{}} + + envelope := web.AppServiceEnvironmentResource{ + Location: utils.String(location), + Kind: utils.String("ASEV2"), + AppServiceEnvironment: &web.AppServiceEnvironment{ + FrontEndScaleFactor: utils.Int32(int32(frontEndScaleFactor)), + MultiSize: utils.String(convertFromIsolatedSKU(pricingTier)), + Name: utils.String(name), + Location: utils.String(location), + InternalLoadBalancingMode: web.InternalLoadBalancingMode(internalLoadBalancingMode), + VirtualNetwork: &web.VirtualNetworkProfile{ + ID: utils.String(subnetId), + Subnet: utils.String(subnet.Name), + }, + WorkerPools: &wp, + }, + Tags: tags.Expand(t), + } + + future, err := client.CreateOrUpdate(ctx, resourceGroup, name, envelope) + if err != nil { + return fmt.Errorf("Error creating App Service Environment %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + err = future.WaitForCompletionRef(ctx, client.Client) + if err != nil { + return fmt.Errorf("Error waiting for the creation of App Service Environment %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error retrieving App Service Environment %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.SetId(*read.ID) + + return resourceArmAppServiceEnvironmentRead(d, meta) +} + +func resourceArmAppServiceEnvironmentRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Web.AppServiceEnvironmentsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := ParseAppServiceEnvironmentID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + name := id.Name + + appServiceEnvironment, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if utils.ResponseWasNotFound(appServiceEnvironment.Response) { + log.Printf("[DEBUG] App Service Environmment %q (Resource Group %q) was not found!", name, resourceGroup) + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving App Service Environmment %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + d.Set("name", name) + d.Set("resource_group_name", resourceGroup) + if location := appServiceEnvironment.Location; location != nil { + d.Set("location", azure.NormalizeLocation(*location)) + } + + if err := tags.FlattenAndSet(d, appServiceEnvironment.Tags); err != nil { + return fmt.Errorf("Error flattening and setting tags in App Service Environment %q (resource group %q): %+v", name, resourceGroup, err) + } + + ase := appServiceEnvironment.AppServiceEnvironment + if ase.InternalLoadBalancingMode != "" { + d.Set("internal_load_balancing_mode", ase.InternalLoadBalancingMode) + } + if ase.VirtualNetwork.ID != nil { + d.Set("subnet_id", ase.VirtualNetwork.ID) + } + if ase.FrontEndScaleFactor != nil { + d.Set("front_end_scale_factor", int(*ase.FrontEndScaleFactor)) + } + if ase.MultiSize != nil { + d.Set("pricing_tier", convertToIsolatedSKU(*ase.MultiSize)) + } + + return nil +} + +func resourceArmAppServiceEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Web.AppServiceEnvironmentsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := ParseAppServiceEnvironmentID(d.Id()) + if err != nil { + return err + } + + resGroup := id.ResourceGroup + name := id.Name + + log.Printf("[DEBUG] Deleting App Service Environment %q (Resource Group %q)", name, resGroup) + + // `true` below deletes any child resources (e.g. App Services / Plans / Certificates etc) + // This potentially destroys resources outside of Terraform's state without the user knowing + // It is set to true as this is consistent with other instances of this type of functionality in the provider. + future, err := client.Delete(ctx, resGroup, name, utils.Bool(true)) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + + return err + } + + err = future.WaitForCompletionRef(ctx, client.Client) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + + return err + } + + return nil +} + +func convertFromIsolatedSKU(isolated string) (vmSKU string) { + switch isolated { + case "I1": + vmSKU = "Standard_D1_V2" + case "I2": + vmSKU = "Standard_D2_V2" + case "I3": + vmSKU = "Standard_D3_V2" + } + return vmSKU +} + +func convertToIsolatedSKU(vmSKU string) (isolated string) { + switch vmSKU { + case "Standard_D1_V2": + isolated = "I1" + case "Standard_D2_V2": + isolated = "I2" + case "Standard_D3_V2": + isolated = "I3" + } + return isolated +} diff --git a/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go b/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go new file mode 100644 index 000000000000..a26d0453d801 --- /dev/null +++ b/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go @@ -0,0 +1,39 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" +) + +func TestDataSourceAzureRMAppServiceEnvironment_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_app_service_environment", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + Steps: []resource.TestStep{ + { + Config: testAccDatasourceAppServiceEnvironment_basic(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(data.ResourceName, "front_end_scale_factor"), + resource.TestCheckResourceAttrSet(data.ResourceName, "pricing_tier"), + ), + }, + }, + }) +} + +func testAccDatasourceAppServiceEnvironment_basic(data acceptance.TestData) string { + config := testAccAzureRMAppServiceEnvironment_basic(data) + return fmt.Sprintf(` +%s + +data "azurerm_app_service_environment" "test" { + name = "${azurerm_app_service_environment.test.name}" + resource_group_name = "${azurerm_app_service_environment.test.resource_group_name}" +} +`, config) +} diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go new file mode 100644 index 000000000000..1623cc2d2a6b --- /dev/null +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go @@ -0,0 +1,302 @@ +package tests + +import ( + "fmt" + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func TestAccAzureRMAppServiceEnvironment_basicWindows(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceEnvironment_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceEnvironmentExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "pricing_tier", "I1"), + resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "15"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMAppServiceEnvironment_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceEnvironment_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceEnvironmentExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "pricing_tier", "I1"), + resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "15"), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMAppServiceEnvironment_update(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(data.ResourceName, "pricing_tier", "I2"), + resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "10"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMAppServiceEnvironment_tierAndScaleFactor(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceEnvironmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceEnvironment_tierAndScaleFactor(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceEnvironmentExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "pricing_tier", "I2"), + resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "10"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMAppServiceEnvironment_withAppServicePlan(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") + aspData := acceptance.BuildTestData(t, "azurerm_app_service_plan", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppServiceEnvironment_withAppServicePlan(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceEnvironmentExists(data.ResourceName), + testCheckAppServicePlanMemberOfAppServiceEnvironment(data.ResourceName, aspData.ResourceName), + ), + }, + }, + }) +} + +func testAccAzureRMAppServiceEnvironment_basic(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest-vnet-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + address_space = ["10.0.0.0/16"] + + subnet { + name = "asesubnet" + address_prefix = "10.0.1.0/24" + } + + subnet { + name = "gatewaysubnet" + address_prefix = "10.0.2.0/24" + } +} + +data "azurerm_subnet" "test" { + name = "asesubnet" + virtual_network_name = "${azurerm_virtual_network.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_app_service_environment" "test" { + name = "acctest-ase-%[1]d" + subnet_id = "${data.azurerm_subnet.test.id}" +} +`, data.RandomInteger, data.Locations.Primary) +} + +func testAccAzureRMAppServiceEnvironment_tierAndScaleFactor(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest-vnet-%[1]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + address_space = ["10.0.0.0/16"] + + subnet { + name = "asesubnet" + address_prefix = "10.0.1.0/24" + } + + subnet { + name = "gatewaysubnet" + address_prefix = "10.0.2.0/24" + } +} + +data "azurerm_subnet" "test" { + name = "asesubnet" + virtual_network_name = "${azurerm_virtual_network.test.name}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_app_service_environment" "test" { + name = "acctest-ase-%[1]d" + subnet_id = "${data.azurerm_subnet.test.id}" + pricing_tier = "I2" + front_end_scale_factor = 10 +} +`, data.RandomInteger, data.Locations.Primary) +} + +func testAccAzureRMAppServiceEnvironment_update(data acceptance.TestData) string { + return testAccAzureRMAppServiceEnvironment_tierAndScaleFactor(data) +} + +func testAccAzureRMAppServiceEnvironment_withAppServicePlan(data acceptance.TestData) string { + template := testAccAzureRMAppServiceEnvironment_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_plan" "test"{ + name = "acctest-ASP-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + app_service_environment_id = "${azurerm_app_service_environment.test.id}" + + sku { + tier = "Basic" + size = "B1" + } + +} +`, template, data.RandomInteger) +} + +func testCheckAzureRMAppServiceEnvironmentExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServiceEnvironmentsClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Not found: %s", resourceName) + } + + appServiceEnvironmentName := 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 App Service Environment: %s", appServiceEnvironmentName) + } + + resp, err := client.Get(ctx, resourceGroup, appServiceEnvironmentName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Bad: App Service Environment %q (resource group %q) does not exist", appServiceEnvironmentName, resourceGroup) + } + + return fmt.Errorf("Bad: Get on appServiceEnvironmentClient: %+v", err) + } + + return nil + } +} + +func testCheckAzureRMAppServiceEnvironmentDestroy(s *terraform.State) error { + client := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServiceEnvironmentsClient + + for _, rs := range s.RootModule().Resources { + if rs.Type != "azurerm_app_service_environment" { + continue + } + + name := rs.Primary.Attributes["name"] + resourceGroup := rs.Primary.Attributes["resource_group_name"] + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + resp, err := client.Get(ctx, resourceGroup, name) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return nil + } + + return err + } + + return nil + } + + return nil +} + +func testCheckAppServicePlanMemberOfAppServiceEnvironment(ase string, asp string) resource.TestCheckFunc { + return func(s *terraform.State) error { + aseClient := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServiceEnvironmentsClient + aspClient := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServicePlansClient + ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext + + aseResource, ok := s.RootModule().Resources[ase] + if !ok { + return fmt.Errorf("Not found: %s", ase) + } + + appServiceEnvironmentName := aseResource.Primary.Attributes["name"] + appServiceEnvironmentResourceGroup := aseResource.Primary.Attributes["resource_group_name"] + + aseResp, err := aseClient.Get(ctx, appServiceEnvironmentResourceGroup, appServiceEnvironmentName) + if err != nil { + if utils.ResponseWasNotFound(aseResp.Response) { + return fmt.Errorf("Bad: App Service Environment %q (resource group %q) does not exist: %+v", appServiceEnvironmentName, appServiceEnvironmentResourceGroup, err) + } + } + + aspResource, ok := s.RootModule().Resources[asp] + if !ok { + return fmt.Errorf("Not found: %s", ase) + } + + appServicePlanName := aspResource.Primary.Attributes["name"] + appServicePlanResourceGroup := aspResource.Primary.Attributes["resource_group_name"] + + aspResp, err := aspClient.Get(ctx, appServicePlanResourceGroup, appServicePlanName) + if err != nil { + if utils.ResponseWasNotFound(aseResp.Response) { + return fmt.Errorf("Bad: App Service Plan %q (resource group %q) does not exist: %+v", appServicePlanName, appServicePlanResourceGroup, err) + } + } + if aspResp.HostingEnvironmentProfile.ID != aseResp.ID { + return fmt.Errorf("Bad: App Service Plan %s not a member of App Service Environment %s", appServicePlanName, appServiceEnvironmentName) + } + + return nil + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index ef8827c62e16..21fb930017fc 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -80,6 +80,7 @@ github.com/Azure/azure-sdk-for-go/services/signalr/mgmt/2018-10-01/signalr github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage github.com/Azure/azure-sdk-for-go/services/streamanalytics/mgmt/2016-03-01/streamanalytics github.com/Azure/azure-sdk-for-go/services/trafficmanager/mgmt/2018-04-01/trafficmanager +github.com/Azure/azure-sdk-for-go/services/web/mgmt/2018-02-01/web github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web github.com/Azure/azure-sdk-for-go/version # github.com/Azure/go-autorest/autorest v0.9.3 diff --git a/website/docs/d/app_service_environment.html.markdown b/website/docs/d/app_service_environment.html.markdown new file mode 100644 index 000000000000..7b6b1b89a1ea --- /dev/null +++ b/website/docs/d/app_service_environment.html.markdown @@ -0,0 +1,43 @@ +--- +subcategory: "App Service (Web Apps)" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_app_service_environment" +description: |- + Gets information about an existing App Service Environment. +--- + +# Data Source: azurerm_app_service_environment + +Use this data source to access information about an existing App Service Environment + +## Example Usage + +```hcl +data "azure_app_service_plan" "example" { + name = "example-ase" + resource_group_name = "example-rg" +} + +output "app_service_environment_id" { + value = "${data.azurerm_app_service_environment.id}" +} + +``` + +## Argument Reference + +* `name` - (Required) The name of the App Service Environment. + +* `resource_group_name` - (Required) The Name of the Resource Group where the App Service Environment exists. + +## Attribute Reference + +* `id` - The ID of the App Service Environment. + +* `location` - The Azure location where the App Service Environment exists + +* `front_end_scale_factor` - The number of app instances per App Service Environment Front End + +* `pricing_tier` - The Pricing Tier (Isolated SKU) of the App Service Environment. + +* `tags` - A mapping of tags assigned to the resource. \ No newline at end of file diff --git a/website/docs/r/app_service_environment.html.markdown b/website/docs/r/app_service_environment.html.markdown new file mode 100644 index 000000000000..e863e6df06eb --- /dev/null +++ b/website/docs/r/app_service_environment.html.markdown @@ -0,0 +1,84 @@ +--- +subcategory: "App Service (Web Apps)" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_app_service_environment" +description: |- + Manages an App Service Environment v2. + +--- + +# azurerm_app_service_environment + +Manages a App Service Environment v2 + +*WARNING* Deleting an App Service Environment resource will also delete App Service Plans and App Services associated with it. + +## Example Usage + +```hcl +resource "azurerm_resource_group" "example" { + name = "exampleRG1" + location = "westeurope" +} + +resource "azurerm_virtual_network" "example" { + name = "example-vnet1" + location = "${azurerm_resource_group.example.location}" + resource_group_name = "${azurerm_resource_group.example.name}" + address_space = ["10.0.0.0/16"] + + subnet { + name = "asesubnet" + address_prefix = "10.0.1.0/24" + } + + subnet { + name = "gatewaysubnet" + address_prefix = "10.0.2.0/24" + } +} + +data "azurerm_subnet" "example" { + name = "asesubnet" + virtual_network_name = "${azurerm_virtual_network.example.name}" + resource_group_name = "${azurerm_resource_group.example.name}" +} + +resource "azurerm_app_service_environment" "example" { + name = "example-ase" + subnet_id = "${data.azurerm_subnet.example.id}" + pricing_tier = "I2" + front_end_scale_factor = 10 +} + +``` + +## Argument Reference + +* `name` - (Required) name of the App Service Environment. + +~> *NOTE* Must meet DNS name specification. + +* `subnet_id` - (Required) Resource ID for the ASE subnet. + +~> *NOTE* a /24 or larger CIDR is required. + +* `pricing_tier` - (Optional) Pricing tier for the front end instances. Possible values are `I1` (default), `I2` and `I3`. + +* `front_end_scale_factor` - (Optional) Scale factor for front end instances. Possible values are between `15` (default) and `5`. + +~> *NOTE* Lowering/changing this value has cost implications, see https://docs.microsoft.com/en-us/azure/app-service/environment/using-an-ase#front-end-scaling for details. + +## Attribute Reference + +* `id` - The ID of the App Services Environment. + +* `resource_group_name` - The name of the resource group. + +* `location` - The location the App Service Environment is deployed into. + +## Import + +```shell +terraform import azurerm_app_service_environment.myAppServiceEnv /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroup/providers/Microsoft.Web/hostingEnvironments/myAppServiceEnv +``` \ No newline at end of file From 5beb2d2727de0ccecf4fea38716aa09897e9480b Mon Sep 17 00:00:00 2001 From: jackofallops Date: Fri, 24 Jan 2020 10:06:00 +0000 Subject: [PATCH 02/26] Linter fixes --- .../data_source_app_service_environment_test.go | 2 +- .../resource_arm_app_service_environment_test.go | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go b/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go index a26d0453d801..3d48cbf9ade5 100644 --- a/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go +++ b/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go @@ -8,7 +8,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" ) -func TestDataSourceAzureRMAppServiceEnvironment_basic(t *testing.T) { +func TestAccDataSourceAzureRMAppServiceEnvironment_basic(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service_environment", "test") resource.ParallelTest(t, resource.TestCase{ diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go index 1623cc2d2a6b..b8883c54591a 100644 --- a/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go @@ -108,7 +108,7 @@ resource "azurerm_resource_group" "test" { name = "acctestRG-%[1]d" location = "%[2]s" } - + resource "azurerm_virtual_network" "test" { name = "acctest-vnet-%[1]d" location = "${azurerm_resource_group.test.location}" @@ -118,8 +118,8 @@ resource "azurerm_virtual_network" "test" { subnet { name = "asesubnet" address_prefix = "10.0.1.0/24" - } - + } + subnet { name = "gatewaysubnet" address_prefix = "10.0.2.0/24" @@ -145,7 +145,7 @@ resource "azurerm_resource_group" "test" { name = "acctestRG-%[1]d" location = "%[2]s" } - + resource "azurerm_virtual_network" "test" { name = "acctest-vnet-%[1]d" location = "${azurerm_resource_group.test.location}" @@ -155,8 +155,8 @@ resource "azurerm_virtual_network" "test" { subnet { name = "asesubnet" address_prefix = "10.0.1.0/24" - } - + } + subnet { name = "gatewaysubnet" address_prefix = "10.0.2.0/24" @@ -187,7 +187,7 @@ func testAccAzureRMAppServiceEnvironment_withAppServicePlan(data acceptance.Test return fmt.Sprintf(` %s -resource "azurerm_app_service_plan" "test"{ +resource "azurerm_app_service_plan" "test" { name = "acctest-ASP-%d" location = "${azurerm_resource_group.test.location}" resource_group_name = "${azurerm_resource_group.test.name}" @@ -197,7 +197,6 @@ resource "azurerm_app_service_plan" "test"{ tier = "Basic" size = "B1" } - } `, template, data.RandomInteger) } From e94e186b246f1f48399618f2e3fbe412e1eb4b46 Mon Sep 17 00:00:00 2001 From: jackofallops Date: Fri, 24 Jan 2020 12:55:41 +0000 Subject: [PATCH 03/26] Added forgotten requiresImport test --- ...source_arm_app_service_environment_test.go | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go index b8883c54591a..2f9f816e1782 100644 --- a/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go @@ -4,11 +4,11 @@ import ( "fmt" "testing" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" - "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/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) @@ -33,6 +33,29 @@ func TestAccAzureRMAppServiceEnvironment_basicWindows(t *testing.T) { }) } +func TestAccAzureRMAppServiceEnvironment_requiresImport(t *testing.T) { + if !features.ShouldResourcesBeImported() { + t.Skip("Skipping since resources aren't required to be imported") + return + } + + data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppService_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceEnvironmentExists(data.ResourceName), + ), + }, + data.RequiresImportErrorStep(testAccAzureRMAppServiceEnvironment_requiresImport), + }, + }) +} + func TestAccAzureRMAppServiceEnvironment_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") @@ -49,7 +72,6 @@ func TestAccAzureRMAppServiceEnvironment_update(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "15"), ), }, - data.ImportStep(), { Config: testAccAzureRMAppServiceEnvironment_update(data), Check: resource.ComposeTestCheckFunc( @@ -57,7 +79,6 @@ func TestAccAzureRMAppServiceEnvironment_update(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "10"), ), }, - data.ImportStep(), }, }) } @@ -139,6 +160,19 @@ resource "azurerm_app_service_environment" "test" { `, data.RandomInteger, data.Locations.Primary) } +func testAccAzureRMAppServiceEnvironment_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMAppServiceEnvironment_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_environment" "import" { + name = "${azurerm_app_service_environment.test.name}" + subnet_id = "${azurerm_app_service_environment.test.subnet_id}" + +} +`, template) +} + func testAccAzureRMAppServiceEnvironment_tierAndScaleFactor(data acceptance.TestData) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { From 1a5f5f2216f6228ff7d05a5099cd4365b264eb51 Mon Sep 17 00:00:00 2001 From: jackofallops Date: Wed, 12 Feb 2020 15:10:16 +0000 Subject: [PATCH 04/26] Refactor for 2.0 --- .../services/web/app_service_environment.go | 74 ------------------- ...=> app_service_environment_data_source.go} | 0 ...go => app_service_environment_resource.go} | 13 ++-- .../web/parse/app_service_environment.go | 33 +++++++++ .../app_service_environment_test.go | 41 +--------- .../web/validate/app_service_environment.go | 47 ++++++++++++ .../validate/app_service_environment_test.go | 40 ++++++++++ 7 files changed, 130 insertions(+), 118 deletions(-) delete mode 100644 azurerm/internal/services/web/app_service_environment.go rename azurerm/internal/services/web/{data_source_app_service_environment.go => app_service_environment_data_source.go} (100%) rename azurerm/internal/services/web/{resource_arm_app_service_environment.go => app_service_environment_resource.go} (94%) create mode 100644 azurerm/internal/services/web/parse/app_service_environment.go rename azurerm/internal/services/web/{ => parse}/app_service_environment_test.go (62%) create mode 100644 azurerm/internal/services/web/validate/app_service_environment.go create mode 100644 azurerm/internal/services/web/validate/app_service_environment_test.go diff --git a/azurerm/internal/services/web/app_service_environment.go b/azurerm/internal/services/web/app_service_environment.go deleted file mode 100644 index 6f4eba92fc6a..000000000000 --- a/azurerm/internal/services/web/app_service_environment.go +++ /dev/null @@ -1,74 +0,0 @@ -package web - -import ( - "fmt" - "regexp" - - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" -) - -type AppServiceEnvironmentResourceID struct { - ResourceGroup string - Name string -} - -func ParseAppServiceEnvironmentID(input string) (*AppServiceEnvironmentResourceID, error) { - id, err := azure.ParseAzureResourceID(input) - if err != nil { - return nil, fmt.Errorf("[ERROR] Unable to parse App Service Environment ID %q: %+v", input, err) - } - - appServiceEnvironment := AppServiceEnvironmentResourceID{ - ResourceGroup: id.ResourceGroup, - } - - if appServiceEnvironment.Name, err = id.PopSegment("hostingEnvironments"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &appServiceEnvironment, nil -} - -// ValidateAppServiceID validates that the specified ID is a valid App Service ID -func ValidateAppServiceEnvironmentID(i interface{}, k string) (warnings []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) - return - } - - if _, err := ParseAppServiceEnvironmentID(v); err != nil { - errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) - return - } - - return warnings, errors -} - -func validateAppServiceEnvironmentName(v interface{}, k string) (warnings []string, errors []error) { - value := v.(string) - - if matched := regexp.MustCompile(`^[0-9a-zA-Z][-0-9a-zA-Z]{0,61}[0-9a-zA-Z]$`).Match([]byte(value)); !matched { - errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes up to 60 characters in length, and must start and end in an alphanumeric", k)) - } - - return warnings, errors -} - -func validateAppServiceEnvironmentPricingTier(v interface{}, k string) (warnings []string, errors []error) { - tier := v.(string) - - valid := []string{"I1", "I2", "I3"} - - for _, val := range valid { - if val == tier { - return - } - } - errors = append(errors, fmt.Errorf("pricing_tier must be one of %q", valid)) - return warnings, errors -} diff --git a/azurerm/internal/services/web/data_source_app_service_environment.go b/azurerm/internal/services/web/app_service_environment_data_source.go similarity index 100% rename from azurerm/internal/services/web/data_source_app_service_environment.go rename to azurerm/internal/services/web/app_service_environment_data_source.go diff --git a/azurerm/internal/services/web/resource_arm_app_service_environment.go b/azurerm/internal/services/web/app_service_environment_resource.go similarity index 94% rename from azurerm/internal/services/web/resource_arm_app_service_environment.go rename to azurerm/internal/services/web/app_service_environment_resource.go index cfd3e9e8d021..2057371dda1c 100644 --- a/azurerm/internal/services/web/resource_arm_app_service_environment.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -12,6 +12,8 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" + "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/tags" azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" @@ -25,7 +27,7 @@ func resourceArmAppServiceEnvironment() *schema.Resource { Update: resourceArmAppServiceEnvironmentCreateOrUpdate, Delete: resourceArmAppServiceEnvironmentDelete, Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { - _, err := ParseAppServiceEnvironmentID(id) + _, err := parse.AppServiceEnvironmentID(id) return err }), @@ -42,7 +44,7 @@ func resourceArmAppServiceEnvironment() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: validateAppServiceEnvironmentName, + ValidateFunc: validate.AppServiceEnvironmentName, }, "internal_load_balancing_mode": { @@ -68,7 +70,7 @@ func resourceArmAppServiceEnvironment() *schema.Resource { Type: schema.TypeString, Optional: true, Default: "I1", - ValidateFunc: validateAppServiceEnvironmentPricingTier, + ValidateFunc: validate.AppServiceEnvironmentPricingTier, }, "front_end_scale_factor": { @@ -128,6 +130,7 @@ func resourceArmAppServiceEnvironmentCreateOrUpdate(d *schema.ResourceData, meta pricingTier := d.Get("pricing_tier").(string) // the SDK is coded primarily for v1, which needs a non-null entry for workerpool, so we construct an empty slice for it + // TODO Submit change for SDK? wp := []web.WorkerPool{{}} envelope := web.AppServiceEnvironmentResource{ @@ -173,7 +176,7 @@ func resourceArmAppServiceEnvironmentRead(d *schema.ResourceData, meta interface ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := ParseAppServiceEnvironmentID(d.Id()) + id, err := parse.AppServiceEnvironmentID(d.Id()) if err != nil { return err } @@ -223,7 +226,7 @@ func resourceArmAppServiceEnvironmentDelete(d *schema.ResourceData, meta interfa ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := ParseAppServiceEnvironmentID(d.Id()) + id, err := parse.AppServiceEnvironmentID(d.Id()) if err != nil { return err } diff --git a/azurerm/internal/services/web/parse/app_service_environment.go b/azurerm/internal/services/web/parse/app_service_environment.go new file mode 100644 index 000000000000..7189915717ae --- /dev/null +++ b/azurerm/internal/services/web/parse/app_service_environment.go @@ -0,0 +1,33 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type AppServiceEnvironmentResourceID struct { + ResourceGroup string + Name string +} + +func AppServiceEnvironmentID(input string) (*AppServiceEnvironmentResourceID, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse App Service Environment ID %q: %+v", input, err) + } + + appServiceEnvironment := AppServiceEnvironmentResourceID{ + ResourceGroup: id.ResourceGroup, + } + + if appServiceEnvironment.Name, err = id.PopSegment("hostingEnvironments"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &appServiceEnvironment, nil +} diff --git a/azurerm/internal/services/web/app_service_environment_test.go b/azurerm/internal/services/web/parse/app_service_environment_test.go similarity index 62% rename from azurerm/internal/services/web/app_service_environment_test.go rename to azurerm/internal/services/web/parse/app_service_environment_test.go index 942cac22492f..50c93b544257 100644 --- a/azurerm/internal/services/web/app_service_environment_test.go +++ b/azurerm/internal/services/web/parse/app_service_environment_test.go @@ -1,4 +1,4 @@ -package web +package parse import "testing" @@ -46,7 +46,7 @@ func TestParseAppServiceEnvironmentID(t *testing.T) { for _, v := range testData { t.Logf("[DEBUG] Testing %q", v.Name) - actual, err := ParseAppServiceEnvironmentID(v.Input) + actual, err := AppServiceEnvironmentID(v.Input) if err != nil { if v.Expected == nil { continue @@ -64,40 +64,3 @@ func TestParseAppServiceEnvironmentID(t *testing.T) { } } } - -func TestValidateAppServiceEnvironmentID(t *testing.T) { - cases := []struct { - ID string - Valid bool - }{ - { - ID: "", - Valid: false, - }, - { - ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", - Valid: false, - }, - { - ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/", - Valid: false, - }, - { - ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/providers/Microsoft.Web/hostingEnvironments/", - Valid: false, - }, - { - ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup1/providers/Microsoft.Web/hostingEnvironments/TestASEv2", - Valid: true, - }, - } - for _, tc := range cases { - t.Logf("[DEBUG] Testing Value %s", tc.ID) - _, errors := ValidateAppServiceEnvironmentID(tc.ID, "test") - valid := len(errors) == 0 - - if tc.Valid != valid { - t.Fatalf("Expected %t but got %t", tc.Valid, valid) - } - } -} diff --git a/azurerm/internal/services/web/validate/app_service_environment.go b/azurerm/internal/services/web/validate/app_service_environment.go new file mode 100644 index 000000000000..63d458654577 --- /dev/null +++ b/azurerm/internal/services/web/validate/app_service_environment.go @@ -0,0 +1,47 @@ +package validate + +import ( + "fmt" + "regexp" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/web/parse" +) + +func AppServiceEnvironmentID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := parse.AppServiceEnvironmentID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} + +func AppServiceEnvironmentName(v interface{}, k string) (warnings []string, errors []error) { + value := v.(string) + + if matched := regexp.MustCompile(`^[0-9a-zA-Z][-0-9a-zA-Z]{0,61}[0-9a-zA-Z]$`).Match([]byte(value)); !matched { + errors = append(errors, fmt.Errorf("%q may only contain alphanumeric characters and dashes up to 60 characters in length, and must start and end in an alphanumeric", k)) + } + + return warnings, errors +} + +func AppServiceEnvironmentPricingTier(v interface{}, k string) (warnings []string, errors []error) { + tier := v.(string) + + valid := []string{"I1", "I2", "I3"} + + for _, val := range valid { + if val == tier { + return + } + } + errors = append(errors, fmt.Errorf("pricing_tier must be one of %q", valid)) + return warnings, errors +} diff --git a/azurerm/internal/services/web/validate/app_service_environment_test.go b/azurerm/internal/services/web/validate/app_service_environment_test.go new file mode 100644 index 000000000000..9f6b1d44b4c8 --- /dev/null +++ b/azurerm/internal/services/web/validate/app_service_environment_test.go @@ -0,0 +1,40 @@ +package validate + +import "testing" + +func TestValidateAppServiceEnvironmentID(t *testing.T) { + cases := []struct { + ID string + Valid bool + }{ + { + ID: "", + Valid: false, + }, + { + ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + Valid: false, + }, + { + ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/", + Valid: false, + }, + { + ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/providers/Microsoft.Web/hostingEnvironments/", + Valid: false, + }, + { + ID: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup1/providers/Microsoft.Web/hostingEnvironments/TestASEv2", + Valid: true, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.ID) + _, errors := AppServiceEnvironmentID(tc.ID, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} From 522a17b76f759f8fd567efd3249e812b0e667112 Mon Sep 17 00:00:00 2001 From: jackofallops Date: Wed, 12 Feb 2020 15:30:02 +0000 Subject: [PATCH 05/26] refactor tests, fix tflint issues --- .../services/web/app_service_environment_data_source.go | 1 - .../services/web/app_service_environment_resource.go | 5 ++--- ...ment_test.go => app_service_environment_resource_test.go} | 3 +++ 3 files changed, 5 insertions(+), 4 deletions(-) rename azurerm/internal/services/web/tests/{resource_arm_app_service_environment_test.go => app_service_environment_resource_test.go} (99%) diff --git a/azurerm/internal/services/web/app_service_environment_data_source.go b/azurerm/internal/services/web/app_service_environment_data_source.go index c95e62f39355..de54d73a3684 100644 --- a/azurerm/internal/services/web/app_service_environment_data_source.go +++ b/azurerm/internal/services/web/app_service_environment_data_source.go @@ -24,7 +24,6 @@ func dataSourceArmAppServiceEnvironment() *schema.Resource { "name": { Type: schema.TypeString, Required: true, - ForceNew: true, }, "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index 2057371dda1c..a229098d75b2 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -83,7 +83,6 @@ func resourceArmAppServiceEnvironment() *schema.Resource { "location": { Type: schema.TypeString, Computed: true, - StateFunc: azure.NormalizeLocation, }, "resource_group_name": { @@ -237,8 +236,7 @@ func resourceArmAppServiceEnvironmentDelete(d *schema.ResourceData, meta interfa log.Printf("[DEBUG] Deleting App Service Environment %q (Resource Group %q)", name, resGroup) // `true` below deletes any child resources (e.g. App Services / Plans / Certificates etc) - // This potentially destroys resources outside of Terraform's state without the user knowing - // It is set to true as this is consistent with other instances of this type of functionality in the provider. + // TODO: Add this to the provider 'Features' schema? future, err := client.Delete(ctx, resGroup, name, utils.Bool(true)) if err != nil { if response.WasNotFound(future.Response()) { @@ -260,6 +258,7 @@ func resourceArmAppServiceEnvironmentDelete(d *schema.ResourceData, meta interfa return nil } +// Note: These are abstractions and possibly subject to change if Azure changes the underlying SKU for Isolated instances. func convertFromIsolatedSKU(isolated string) (vmSKU string) { switch isolated { case "I1": diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go similarity index 99% rename from azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go rename to azurerm/internal/services/web/tests/app_service_environment_resource_test.go index 2f9f816e1782..b90e65844a49 100644 --- a/azurerm/internal/services/web/tests/resource_arm_app_service_environment_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go @@ -72,6 +72,7 @@ func TestAccAzureRMAppServiceEnvironment_update(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "15"), ), }, + data.ImportStep(), { Config: testAccAzureRMAppServiceEnvironment_update(data), Check: resource.ComposeTestCheckFunc( @@ -79,6 +80,7 @@ func TestAccAzureRMAppServiceEnvironment_update(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "10"), ), }, + data.ImportStep(), }, }) } @@ -119,6 +121,7 @@ func TestAccAzureRMAppServiceEnvironment_withAppServicePlan(t *testing.T) { testCheckAppServicePlanMemberOfAppServiceEnvironment(data.ResourceName, aspData.ResourceName), ), }, + data.ImportStep(), }, }) } From 260bd86b9d7fbbded5cae753d2b992a88680f76b Mon Sep 17 00:00:00 2001 From: jackofallops Date: Wed, 12 Feb 2020 15:58:11 +0000 Subject: [PATCH 06/26] docs update --- website/azurerm.erb | 12 ++++++++++-- .../docs/r/app_service_environment.html.markdown | 14 ++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/website/azurerm.erb b/website/azurerm.erb index 13e50d7b1078..1045f5dd3d2d 100644 --- a/website/azurerm.erb +++ b/website/azurerm.erb @@ -83,11 +83,15 @@
  • - azurerm_app_service_plan + azurerm_app_service_certificate
  • - azurerm_app_service_certificate + azurerm_app_service_environment +
  • + +
  • + azurerm_app_service_plan
  • @@ -695,6 +699,10 @@ azurerm_app_service_custom_hostname_binding
  • +
  • + azurerm_app_service_environment +
  • +
  • azurerm_app_service_plan
  • diff --git a/website/docs/r/app_service_environment.html.markdown b/website/docs/r/app_service_environment.html.markdown index e863e6df06eb..d82ffca09a4f 100644 --- a/website/docs/r/app_service_environment.html.markdown +++ b/website/docs/r/app_service_environment.html.markdown @@ -3,15 +3,15 @@ subcategory: "App Service (Web Apps)" layout: "azurerm" page_title: "Azure Resource Manager: azurerm_app_service_environment" description: |- - Manages an App Service Environment v2. + Manages an App Service Environment. --- # azurerm_app_service_environment -Manages a App Service Environment v2 +Manages a App Service Environment -*WARNING* Deleting an App Service Environment resource will also delete App Service Plans and App Services associated with it. +**WARNING** Deleting an App Service Environment resource will also delete App Service Plans and App Services associated with it. ## Example Usage @@ -57,17 +57,19 @@ resource "azurerm_app_service_environment" "example" { * `name` - (Required) name of the App Service Environment. -~> *NOTE* Must meet DNS name specification. +~> **NOTE** Must meet DNS name specification. * `subnet_id` - (Required) Resource ID for the ASE subnet. -~> *NOTE* a /24 or larger CIDR is required. +~> **NOTE** a /24 or larger CIDR is required. Once associated with an ASE this size cannot be changed. * `pricing_tier` - (Optional) Pricing tier for the front end instances. Possible values are `I1` (default), `I2` and `I3`. +~> **NOTE** Azure currently utilises Dv2 instances for Isolated SKUs, being `Standard_D1_V2`, `Standard_D2_V2`, and `Standard_D3_V2`. + * `front_end_scale_factor` - (Optional) Scale factor for front end instances. Possible values are between `15` (default) and `5`. -~> *NOTE* Lowering/changing this value has cost implications, see https://docs.microsoft.com/en-us/azure/app-service/environment/using-an-ase#front-end-scaling for details. +~> **NOTE** Lowering/changing this value has cost implications, see https://docs.microsoft.com/en-us/azure/app-service/environment/using-an-ase#front-end-scaling for details. ## Attribute Reference From f2d90670d7bef22c14c6a58b2a0d522015ee88d8 Mon Sep 17 00:00:00 2001 From: jackofallops Date: Thu, 13 Feb 2020 06:56:03 +0000 Subject: [PATCH 07/26] fmt fix --- .../internal/services/web/app_service_environment_resource.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index a229098d75b2..4c0f47b2c0c1 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -81,8 +81,8 @@ func resourceArmAppServiceEnvironment() *schema.Resource { }, "location": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Computed: true, }, "resource_group_name": { From f659142c09521a3ca74b67625fa54db5c131d0f9 Mon Sep 17 00:00:00 2001 From: jackofallops Date: Mon, 17 Feb 2020 07:39:46 +0000 Subject: [PATCH 08/26] refactor validate to correct helper location --- .../web => helpers}/validate/app_service_environment.go | 0 .../web => helpers}/validate/app_service_environment_test.go | 0 .../internal/services/web/app_service_environment_resource.go | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename azurerm/{internal/services/web => helpers}/validate/app_service_environment.go (100%) rename azurerm/{internal/services/web => helpers}/validate/app_service_environment_test.go (100%) diff --git a/azurerm/internal/services/web/validate/app_service_environment.go b/azurerm/helpers/validate/app_service_environment.go similarity index 100% rename from azurerm/internal/services/web/validate/app_service_environment.go rename to azurerm/helpers/validate/app_service_environment.go diff --git a/azurerm/internal/services/web/validate/app_service_environment_test.go b/azurerm/helpers/validate/app_service_environment_test.go similarity index 100% rename from azurerm/internal/services/web/validate/app_service_environment_test.go rename to azurerm/helpers/validate/app_service_environment_test.go diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index 4c0f47b2c0c1..fe43cfff1c25 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -10,10 +10,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "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/services/network" "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/tags" azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" From 3e21fb74a627794b6b64e03c9572652d47ba07d9 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 19 Feb 2020 12:37:18 +0100 Subject: [PATCH 09/26] r/app_service_environment: fixing up the build errors --- .../internal/services/web/app_service_environment_resource.go | 2 +- .../services/web}/validate/app_service_environment.go | 0 .../services/web}/validate/app_service_environment_test.go | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename azurerm/{helpers => internal/services/web}/validate/app_service_environment.go (100%) rename azurerm/{helpers => internal/services/web}/validate/app_service_environment_test.go (100%) diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index fe43cfff1c25..4c0f47b2c0c1 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -10,10 +10,10 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" - "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/services/network" "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/tags" azSchema "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" diff --git a/azurerm/helpers/validate/app_service_environment.go b/azurerm/internal/services/web/validate/app_service_environment.go similarity index 100% rename from azurerm/helpers/validate/app_service_environment.go rename to azurerm/internal/services/web/validate/app_service_environment.go diff --git a/azurerm/helpers/validate/app_service_environment_test.go b/azurerm/internal/services/web/validate/app_service_environment_test.go similarity index 100% rename from azurerm/helpers/validate/app_service_environment_test.go rename to azurerm/internal/services/web/validate/app_service_environment_test.go From 6ab4e1e7f829af2e9924a87822e1ba0bd83c4059 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 19 Feb 2020 12:44:10 +0100 Subject: [PATCH 10/26] r/subnet: moving the subnet parser into the parse package --- .../services/network/{ => parse}/subnet.go | 24 +---- .../services/network/parse/subnet_test.go | 90 +++++++++++++++++++ .../services/network/validate/subnet.go | 23 +++++ .../web/app_service_environment_resource.go | 7 +- 4 files changed, 121 insertions(+), 23 deletions(-) rename azurerm/internal/services/network/{ => parse}/subnet.go (53%) create mode 100644 azurerm/internal/services/network/parse/subnet_test.go create mode 100644 azurerm/internal/services/network/validate/subnet.go diff --git a/azurerm/internal/services/network/subnet.go b/azurerm/internal/services/network/parse/subnet.go similarity index 53% rename from azurerm/internal/services/network/subnet.go rename to azurerm/internal/services/network/parse/subnet.go index b6a4994df3f0..a60ca6a00731 100644 --- a/azurerm/internal/services/network/subnet.go +++ b/azurerm/internal/services/network/parse/subnet.go @@ -1,4 +1,4 @@ -package network +package parse import ( "fmt" @@ -6,19 +6,19 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" ) -type SubnetID struct { +type SubnetId struct { ResourceGroup string VirtualNetworkName string Name string } -func ParseSubnetID(input string) (*SubnetID, error) { +func SubnetID(input string) (*SubnetId, error) { id, err := azure.ParseAzureResourceID(input) if err != nil { return nil, fmt.Errorf("[ERROR] Unable to parse Subnet ID %q: %+v", input, err) } - subnet := SubnetID{ + subnet := SubnetId{ ResourceGroup: id.ResourceGroup, } @@ -36,19 +36,3 @@ func ParseSubnetID(input string) (*SubnetID, error) { return &subnet, nil } - -// ValidateSubnetID validates that the specified ID is a valid App Service ID -func ValidateSubnetID(i interface{}, k string) (warnings []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) - return - } - - if _, err := ParseSubnetID(v); err != nil { - errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) - return - } - - return warnings, errors -} diff --git a/azurerm/internal/services/network/parse/subnet_test.go b/azurerm/internal/services/network/parse/subnet_test.go new file mode 100644 index 000000000000..ef696cba59b8 --- /dev/null +++ b/azurerm/internal/services/network/parse/subnet_test.go @@ -0,0 +1,90 @@ +package parse + +import ( + "testing" +) + +func TestSubnetID(t *testing.T) { + testData := []struct { + Name string + Input string + Error bool + Expect *SubnetId + }{ + { + Name: "Empty", + Input: "", + Error: true, + }, + { + Name: "No Resource Groups Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Error: true, + }, + { + Name: "No Resource Groups Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + Error: true, + }, + { + Name: "Resource Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/", + Error: true, + }, + { + Name: "Missing Virtual Networks Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworks/", + Error: true, + }, + { + Name: "Missing Subnets Key", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworks/network1", + Error: true, + }, + { + Name: "Missing Subnets Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworks/network1/subnets/", + Error: true, + }, + { + Name: "Subnet ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworks/network1/subnets/subnet1", + Error: false, + Expect: &SubnetId{ + ResourceGroup: "resGroup1", + VirtualNetworkName: "network1", + Name: "subnet1", + }, + }, + { + Name: "Wrong Casing", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworks/network1/Subnets/subnet1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := SubnetID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.Name != v.Expect.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expect.Name, actual.Name) + } + + if actual.VirtualNetworkName != v.Expect.VirtualNetworkName { + t.Fatalf("Expected %q but got %q for Virtual Network Name", v.Expect.VirtualNetworkName, actual.VirtualNetworkName) + } + + if actual.ResourceGroup != v.Expect.ResourceGroup { + t.Fatalf("Expected %q but got %q for Resource Group", v.Expect.ResourceGroup, actual.ResourceGroup) + } + } +} diff --git a/azurerm/internal/services/network/validate/subnet.go b/azurerm/internal/services/network/validate/subnet.go new file mode 100644 index 000000000000..625f73014824 --- /dev/null +++ b/azurerm/internal/services/network/validate/subnet.go @@ -0,0 +1,23 @@ +package validate + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +// SubnetID validates that the specified ID is a valid Subnet ID +func SubnetID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := parse.SubnetID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index 4c0f47b2c0c1..3efda382e9df 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -11,7 +11,8 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network" + networkParse "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" + networkValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" "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/tags" @@ -62,7 +63,7 @@ func resourceArmAppServiceEnvironment() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - ValidateFunc: network.ValidateSubnetID, + ValidateFunc: networkValidate.SubnetID, }, // Note: This is currently 'multiSize' in the API for historic v1 reasons, may change in future? @@ -105,7 +106,7 @@ func resourceArmAppServiceEnvironmentCreateOrUpdate(d *schema.ResourceData, meta t := d.Get("tags").(map[string]interface{}) subnetId := d.Get("subnet_id").(string) - subnet, err := network.ParseSubnetID(subnetId) + subnet, err := networkParse.SubnetID(subnetId) if err != nil { return fmt.Errorf("Error parsing subnet id %q: %+v", subnetId, err) } From a6a48978a0009e4a2604bcdde81c365e4384948d Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 19 Feb 2020 14:01:28 +0100 Subject: [PATCH 11/26] network: moving the virtual network parse/validaters into those packages --- .../services/network/parse/virtual_network.go | 33 +++++++++ .../network/parse/virtual_network_test.go | 70 +++++++++++++++++++ .../network/validate/virtual_network.go | 23 ++++++ .../services/network/virtual_network.go | 49 ------------- 4 files changed, 126 insertions(+), 49 deletions(-) create mode 100644 azurerm/internal/services/network/parse/virtual_network.go create mode 100644 azurerm/internal/services/network/parse/virtual_network_test.go create mode 100644 azurerm/internal/services/network/validate/virtual_network.go delete mode 100644 azurerm/internal/services/network/virtual_network.go diff --git a/azurerm/internal/services/network/parse/virtual_network.go b/azurerm/internal/services/network/parse/virtual_network.go new file mode 100644 index 000000000000..b789e8aefb40 --- /dev/null +++ b/azurerm/internal/services/network/parse/virtual_network.go @@ -0,0 +1,33 @@ +package parse + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type VirtualNetworkId struct { + ResourceGroup string + Name string +} + +func VirtualNetworkID(input string) (*VirtualNetworkId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, fmt.Errorf("[ERROR] Unable to parse Virtual Network ID %q: %+v", input, err) + } + + vnet := VirtualNetworkId{ + ResourceGroup: id.ResourceGroup, + } + + if vnet.Name, err = id.PopSegment("virtualNetworks"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &vnet, nil +} diff --git a/azurerm/internal/services/network/parse/virtual_network_test.go b/azurerm/internal/services/network/parse/virtual_network_test.go new file mode 100644 index 000000000000..b9eb6b35d357 --- /dev/null +++ b/azurerm/internal/services/network/parse/virtual_network_test.go @@ -0,0 +1,70 @@ +package parse + +import ( + "testing" +) + +func TestVirtualNetworkID(t *testing.T) { + testData := []struct { + Name string + Input string + Error bool + Expect *VirtualNetworkId + }{ + { + Name: "Empty", + Input: "", + Error: true, + }, + { + Name: "No Resource Groups Segment", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000", + Error: true, + }, + { + Name: "No Resource Groups Value", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/", + Error: true, + }, + { + Name: "Resource Group ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/foo/", + Error: true, + }, + { + Name: "Virtual Network ID", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Network/virtualNetworks/network1", + Error: false, + Expect: &VirtualNetworkId{ + ResourceGroup: "resGroup1", + Name: "network1", + }, + }, + { + Name: "Wrong Casing", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Network/VirtualNetworks/network1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Name) + + actual, err := VirtualNetworkID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expected a value but got an error: %s", err) + } + + if actual.Name != v.Expect.Name { + t.Fatalf("Expected %q but got %q for Name", v.Expect.Name, actual.Name) + } + + if actual.ResourceGroup != v.Expect.ResourceGroup { + t.Fatalf("Expected %q but got %q for Resource Group", v.Expect.ResourceGroup, actual.ResourceGroup) + } + } +} diff --git a/azurerm/internal/services/network/validate/virtual_network.go b/azurerm/internal/services/network/validate/virtual_network.go new file mode 100644 index 000000000000..03b10e31f2ef --- /dev/null +++ b/azurerm/internal/services/network/validate/virtual_network.go @@ -0,0 +1,23 @@ +package validate + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" +) + +// VirtualNetworkID validates that the specified ID is a valid Virtual Network ID +func VirtualNetworkID(i interface{}, k string) (warnings []string, errors []error) { + v, ok := i.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) + return + } + + if _, err := parse.VirtualNetworkID(v); err != nil { + errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) + return + } + + return warnings, errors +} diff --git a/azurerm/internal/services/network/virtual_network.go b/azurerm/internal/services/network/virtual_network.go deleted file mode 100644 index ffd47239f6ff..000000000000 --- a/azurerm/internal/services/network/virtual_network.go +++ /dev/null @@ -1,49 +0,0 @@ -package network - -import ( - "fmt" - - "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" -) - -type VirtualNetworkID struct { - ResourceGroup string - Name string -} - -func ParseVirtualNetworkID(input string) (*VirtualNetworkID, error) { - id, err := azure.ParseAzureResourceID(input) - if err != nil { - return nil, fmt.Errorf("[ERROR] Unable to parse Subnet ID %q: %+v", input, err) - } - - vnet := VirtualNetworkID{ - ResourceGroup: id.ResourceGroup, - } - - if vnet.Name, err = id.PopSegment("virtualNetworks"); err != nil { - return nil, err - } - - if err := id.ValidateNoEmptySegments(input); err != nil { - return nil, err - } - - return &vnet, nil -} - -// ValidateVirtualNetworkID validates that the specified ID is a valid App Service ID -func ValidateVirtualNetworkID(i interface{}, k string) (warnings []string, errors []error) { - v, ok := i.(string) - if !ok { - errors = append(errors, fmt.Errorf("expected type of %q to be string", k)) - return - } - - if _, err := ParseVirtualNetworkID(v); err != nil { - errors = append(errors, fmt.Errorf("Can not parse %q as a resource id: %v", k, err)) - return - } - - return warnings, errors -} From ef7dcaaab5b05cbb15739cab0da4c3997bd8ce11 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 19 Feb 2020 14:02:58 +0100 Subject: [PATCH 12/26] d/app_service_environment: fixing comments from code review --- .../app_service_environment_data_source.go | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/web/app_service_environment_data_source.go b/azurerm/internal/services/web/app_service_environment_data_source.go index de54d73a3684..4e99c9de26c3 100644 --- a/azurerm/internal/services/web/app_service_environment_data_source.go +++ b/azurerm/internal/services/web/app_service_environment_data_source.go @@ -56,16 +56,31 @@ func dataSourceArmAppServiceEnvironmentRead(d *schema.ResourceData, meta interfa if utils.ResponseWasNotFound(resp.Response) { return fmt.Errorf("Error: App Service Environment %q (Resource Group %q) was not found", name, resourceGroup) } - return fmt.Errorf("Error making read request on Azure App Service Environment %q: %+v", name, err) + return fmt.Errorf("Error retrieving App Service Environment %q (Resource Group %q): %+v", name, resourceGroup, err) } d.SetId(*resp.ID) d.Set("name", name) d.Set("resource_group_name", resourceGroup) - d.Set("front_end_scale_factor", int(*resp.FrontEndScaleFactor)) - d.Set("pricing_tier", convertToIsolatedSKU(*resp.MultiSize)) - d.Set("location", azure.NormalizeLocation(*resp.Location)) + + if loc := resp.Location; loc != nil { + d.Set("location", azure.NormalizeLocation(*loc)) + } + + if props := resp.AppServiceEnvironment; props != nil { + frontendScaleFactor := 0 + if props.FrontEndScaleFactor != nil { + frontendScaleFactor = int(*props.FrontEndScaleFactor) + } + d.Set("front_end_scale_factor", frontendScaleFactor) + + pricingTier := "" + if props.MultiSize != nil { + pricingTier = convertFromIsolatedSKU(*props.MultiSize) + } + d.Set("pricing_tier", pricingTier) + } return tags.FlattenAndSet(d, resp.Tags) } From bbdfbcb93894d8b24c3254cda22d3e18d92b868d Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 19 Feb 2020 15:40:30 +0100 Subject: [PATCH 13/26] web: removing todos --- azurerm/internal/services/web/registration.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/web/registration.go b/azurerm/internal/services/web/registration.go index 37589d215f5b..282159c5e36e 100644 --- a/azurerm/internal/services/web/registration.go +++ b/azurerm/internal/services/web/registration.go @@ -24,8 +24,8 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { "azurerm_app_service": dataSourceArmAppService(), "azurerm_app_service_certificate_order": dataSourceArmAppServiceCertificateOrder(), "azurerm_app_service_environment": dataSourceArmAppServiceEnvironment(), - "azurerm_app_service_certificate": dataSourceAppServiceCertificate(), //TODO: rename this for consistency? - "azurerm_app_service_plan": dataSourceAppServicePlan(), //TODO: rename this for consistency? + "azurerm_app_service_certificate": dataSourceAppServiceCertificate(), + "azurerm_app_service_plan": dataSourceAppServicePlan(), "azurerm_function_app": dataSourceArmFunctionApp(), } } From a661838752f2bfbb9fba9d08d1e8aa5fdf7bf152 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 19 Feb 2020 15:56:09 +0100 Subject: [PATCH 14/26] d/app_service_environment: renaming the file to match the convention --- ...est.go => app_service_environment_data_source_test.go} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename azurerm/internal/services/web/tests/{data_source_app_service_environment_test.go => app_service_environment_data_source_test.go} (76%) diff --git a/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go b/azurerm/internal/services/web/tests/app_service_environment_data_source_test.go similarity index 76% rename from azurerm/internal/services/web/tests/data_source_app_service_environment_test.go rename to azurerm/internal/services/web/tests/app_service_environment_data_source_test.go index 3d48cbf9ade5..5b98c25ff79c 100644 --- a/azurerm/internal/services/web/tests/data_source_app_service_environment_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_data_source_test.go @@ -16,7 +16,7 @@ func TestAccDataSourceAzureRMAppServiceEnvironment_basic(t *testing.T) { Providers: acceptance.SupportedProviders, Steps: []resource.TestStep{ { - Config: testAccDatasourceAppServiceEnvironment_basic(data), + Config: testAccDataSourceAppServiceEnvironment_basic(data), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(data.ResourceName, "front_end_scale_factor"), resource.TestCheckResourceAttrSet(data.ResourceName, "pricing_tier"), @@ -26,14 +26,14 @@ func TestAccDataSourceAzureRMAppServiceEnvironment_basic(t *testing.T) { }) } -func testAccDatasourceAppServiceEnvironment_basic(data acceptance.TestData) string { +func testAccDataSourceAppServiceEnvironment_basic(data acceptance.TestData) string { config := testAccAzureRMAppServiceEnvironment_basic(data) return fmt.Sprintf(` %s data "azurerm_app_service_environment" "test" { - name = "${azurerm_app_service_environment.test.name}" - resource_group_name = "${azurerm_app_service_environment.test.resource_group_name}" + name = azurerm_app_service_environment.test.name + resource_group_name = azurerm_app_service_environment.test.resource_group_name } `, config) } From b840fd481b4159caebee88be1bed147583dfb5a8 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 19 Feb 2020 15:56:45 +0100 Subject: [PATCH 15/26] r/app_service_environment: fixing comments from code review --- .../web/parse/app_service_environment_test.go | 5 ++ .../web/validate/app_service_environment.go | 14 ------ .../r/app_service_environment.html.markdown | 50 ++++++++----------- 3 files changed, 25 insertions(+), 44 deletions(-) diff --git a/azurerm/internal/services/web/parse/app_service_environment_test.go b/azurerm/internal/services/web/parse/app_service_environment_test.go index 50c93b544257..5600c8b6efdb 100644 --- a/azurerm/internal/services/web/parse/app_service_environment_test.go +++ b/azurerm/internal/services/web/parse/app_service_environment_test.go @@ -41,6 +41,11 @@ func TestParseAppServiceEnvironmentID(t *testing.T) { Name: "TestASEv2", }, }, + { + Name: "Wrong Case", + Input: "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testGroup1/providers/Microsoft.Web/HostingEnvironments/TestASEv2", + Expected: nil, + }, } for _, v := range testData { diff --git a/azurerm/internal/services/web/validate/app_service_environment.go b/azurerm/internal/services/web/validate/app_service_environment.go index 63d458654577..9e7b63222213 100644 --- a/azurerm/internal/services/web/validate/app_service_environment.go +++ b/azurerm/internal/services/web/validate/app_service_environment.go @@ -31,17 +31,3 @@ func AppServiceEnvironmentName(v interface{}, k string) (warnings []string, erro return warnings, errors } - -func AppServiceEnvironmentPricingTier(v interface{}, k string) (warnings []string, errors []error) { - tier := v.(string) - - valid := []string{"I1", "I2", "I3"} - - for _, val := range valid { - if val == tier { - return - } - } - errors = append(errors, fmt.Errorf("pricing_tier must be one of %q", valid)) - return warnings, errors -} diff --git a/website/docs/r/app_service_environment.html.markdown b/website/docs/r/app_service_environment.html.markdown index d82ffca09a4f..4f9a554b62cc 100644 --- a/website/docs/r/app_service_environment.html.markdown +++ b/website/docs/r/app_service_environment.html.markdown @@ -9,9 +9,7 @@ description: |- # azurerm_app_service_environment -Manages a App Service Environment - -**WARNING** Deleting an App Service Environment resource will also delete App Service Plans and App Services associated with it. +Manages an App Service Environment. ## Example Usage @@ -26,27 +24,25 @@ resource "azurerm_virtual_network" "example" { location = "${azurerm_resource_group.example.location}" resource_group_name = "${azurerm_resource_group.example.name}" address_space = ["10.0.0.0/16"] - - subnet { - name = "asesubnet" - address_prefix = "10.0.1.0/24" - } - - subnet { - name = "gatewaysubnet" - address_prefix = "10.0.2.0/24" - } } -data "azurerm_subnet" "example" { +resource "azurerm_subnet" "ase" { name = "asesubnet" - virtual_network_name = "${azurerm_virtual_network.example.name}" - resource_group_name = "${azurerm_resource_group.example.name}" + resource_group_name = azurerm_resource_group.example.name + virtual_network_name = azurerm_virtual_network.example.name + address_prefix = "10.0.1.0/24" +} + +resource "azurerm_subnet" "gateway" { + name = "gatewaysubnet" + 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_app_service_environment" "example" { name = "example-ase" - subnet_id = "${data.azurerm_subnet.example.id}" + subnet_id = azurerm_subnet.ase.id pricing_tier = "I2" front_end_scale_factor = 10 } @@ -55,29 +51,23 @@ resource "azurerm_app_service_environment" "example" { ## Argument Reference -* `name` - (Required) name of the App Service Environment. - -~> **NOTE** Must meet DNS name specification. +* `name` - (Required) The name of the App Service Environment. Changing this forces a new resource to be created. -* `subnet_id` - (Required) Resource ID for the ASE subnet. +* `subnet_id` - (Required) The ID of the Subnet which the App Service Environment should be connected to. Changing this forces a new resource to be created. ~> **NOTE** a /24 or larger CIDR is required. Once associated with an ASE this size cannot be changed. -* `pricing_tier` - (Optional) Pricing tier for the front end instances. Possible values are `I1` (default), `I2` and `I3`. - -~> **NOTE** Azure currently utilises Dv2 instances for Isolated SKUs, being `Standard_D1_V2`, `Standard_D2_V2`, and `Standard_D3_V2`. - -* `front_end_scale_factor` - (Optional) Scale factor for front end instances. Possible values are between `15` (default) and `5`. +* `pricing_tier` - (Optional) Pricing tier for the front end instances. Possible values are `I1`, `I2` and `I3`. Defaults to `I1`. -~> **NOTE** Lowering/changing this value has cost implications, see https://docs.microsoft.com/en-us/azure/app-service/environment/using-an-ase#front-end-scaling for details. +* `front_end_scale_factor` - (Optional) Scale factor for front end instances. Possible values are between `5` and `15`. Defaults to `15`. ## Attribute Reference -* `id` - The ID of the App Services Environment. +* `id` - The ID of the App Service Environment. -* `resource_group_name` - The name of the resource group. +* `resource_group_name` - The name of the Resource Group where the App Service Environment exists. -* `location` - The location the App Service Environment is deployed into. +* `location` - The location where the App Service Environment exists. ## Import From 5b5241ee7c7b5c5a9c43319e006939c60ee062f1 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Wed, 19 Feb 2020 16:56:07 +0100 Subject: [PATCH 16/26] r/app_service_environment: switching to use a custom update method/poller --- .../web/app_service_environment_resource.go | 222 +++++++++++++----- .../app_service_environment_resource_test.go | 203 +++++++--------- 2 files changed, 246 insertions(+), 179 deletions(-) diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index 3efda382e9df..cdb134e90a4e 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -1,6 +1,7 @@ package web import ( + "context" "fmt" "log" "time" @@ -10,6 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "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" networkParse "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/parse" networkValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/network/validate" @@ -23,9 +25,9 @@ import ( func resourceArmAppServiceEnvironment() *schema.Resource { return &schema.Resource{ - Create: resourceArmAppServiceEnvironmentCreateOrUpdate, + Create: resourceArmAppServiceEnvironmentCreate, Read: resourceArmAppServiceEnvironmentRead, - Update: resourceArmAppServiceEnvironmentCreateOrUpdate, + Update: resourceArmAppServiceEnvironmentUpdate, Delete: resourceArmAppServiceEnvironmentDelete, Importer: azSchema.ValidateResourceIDPriorToImport(func(id string) error { _, err := parse.AppServiceEnvironmentID(id) @@ -48,6 +50,13 @@ func resourceArmAppServiceEnvironment() *schema.Resource { ValidateFunc: validate.AppServiceEnvironmentName, }, + "subnet_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: networkValidate.SubnetID, + }, + "internal_load_balancing_mode": { Type: schema.TypeString, Optional: true, @@ -59,21 +68,6 @@ func resourceArmAppServiceEnvironment() *schema.Resource { }, false), }, - "subnet_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: networkValidate.SubnetID, - }, - - // Note: This is currently 'multiSize' in the API for historic v1 reasons, may change in future? - "pricing_tier": { - Type: schema.TypeString, - Optional: true, - Default: "I1", - ValidateFunc: validate.AppServiceEnvironmentPricingTier, - }, - "front_end_scale_factor": { Type: schema.TypeInt, Optional: true, @@ -81,6 +75,20 @@ func resourceArmAppServiceEnvironment() *schema.Resource { ValidateFunc: validation.IntBetween(5, 15), }, + "pricing_tier": { + Type: schema.TypeString, + Optional: true, + Default: "I1", + ValidateFunc: validation.StringInSlice([]string{ + "I1", + "I2", + "I3", + }, false), + }, + + "tags": tags.ForceNewSchema(), + + // Computed "location": { Type: schema.TypeString, Computed: true, @@ -90,14 +98,13 @@ func resourceArmAppServiceEnvironment() *schema.Resource { Type: schema.TypeString, Computed: true, }, - - "tags": tags.Schema(), }, } } -func resourceArmAppServiceEnvironmentCreateOrUpdate(d *schema.ResourceData, meta interface{}) error { + +func resourceArmAppServiceEnvironmentCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Web.AppServiceEnvironmentsClient - vnetClient := meta.(*clients.Client).Network.VnetClient + networksClient := meta.(*clients.Client).Network.VnetClient ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -108,56 +115,65 @@ func resourceArmAppServiceEnvironmentCreateOrUpdate(d *schema.ResourceData, meta subnetId := d.Get("subnet_id").(string) subnet, err := networkParse.SubnetID(subnetId) if err != nil { - return fmt.Errorf("Error parsing subnet id %q: %+v", subnetId, err) + return err } resourceGroup := subnet.ResourceGroup - - vnet, err := vnetClient.Get(ctx, resourceGroup, subnet.VirtualNetworkName, "") + vnet, err := networksClient.Get(ctx, resourceGroup, subnet.VirtualNetworkName, "") if err != nil { - return fmt.Errorf("Error reading Virtual Network %q for App Service Environment %q: %+v", subnet.VirtualNetworkName, name, err) + return fmt.Errorf("Error retrieving Virtual Network %q (Resource Group %q): %+v", subnet.VirtualNetworkName, resourceGroup, err) } + // the App Service Environment has to be in the same location as the Virtual netowrk - var location string - if vnetLoc := vnet.Location; vnetLoc != nil { - location = azure.NormalizeLocation(*vnetLoc) + if loc := vnet.Location; loc != nil { + location = azure.NormalizeLocation(*loc) } else { - return fmt.Errorf("Error determining Location from Virtual Network %s", *vnet.Name) + return fmt.Errorf("Error determining Location from Virtual Network %q (Resource Group %q): `location` was nil", subnet.VirtualNetworkName, resourceGroup) } - frontEndScaleFactor := d.Get("front_end_scale_factor").(int) + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing App Service Environment %q (Resource Group %q): %s", name, resourceGroup, err) + } + } - pricingTier := d.Get("pricing_tier").(string) + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_app_service_environment", *existing.ID) + } - // the SDK is coded primarily for v1, which needs a non-null entry for workerpool, so we construct an empty slice for it - // TODO Submit change for SDK? - wp := []web.WorkerPool{{}} + frontEndScaleFactor := d.Get("front_end_scale_factor").(int) + pricingTier := d.Get("pricing_tier").(string) envelope := web.AppServiceEnvironmentResource{ Location: utils.String(location), Kind: utils.String("ASEV2"), AppServiceEnvironment: &web.AppServiceEnvironment{ - FrontEndScaleFactor: utils.Int32(int32(frontEndScaleFactor)), - MultiSize: utils.String(convertFromIsolatedSKU(pricingTier)), Name: utils.String(name), Location: utils.String(location), InternalLoadBalancingMode: web.InternalLoadBalancingMode(internalLoadBalancingMode), + FrontEndScaleFactor: utils.Int32(int32(frontEndScaleFactor)), + MultiSize: utils.String(convertFromIsolatedSKU(pricingTier)), VirtualNetwork: &web.VirtualNetworkProfile{ ID: utils.String(subnetId), Subnet: utils.String(subnet.Name), }, - WorkerPools: &wp, + + // the SDK is coded primarily for v1, which needs a non-null entry for workerpool, so we construct an empty slice for it + // TODO: remove this hack once https://github.com/Azure/azure-rest-api-specs/pull/8433 has been merged + WorkerPools: &[]web.WorkerPool{{}}, }, Tags: tags.Expand(t), } - future, err := client.CreateOrUpdate(ctx, resourceGroup, name, envelope) - if err != nil { + // whilst this returns a future go-autorest has a max number of retries + if _, err := client.CreateOrUpdate(ctx, resourceGroup, name, envelope); err != nil { return fmt.Errorf("Error creating App Service Environment %q (Resource Group %q): %+v", name, resourceGroup, err) } - err = future.WaitForCompletionRef(ctx, client.Client) - if err != nil { + // as such we'll ignore it and use a custom poller instead + if err := waitForAppServiceEnvironmentToStabilize(ctx, client, resourceGroup, name); err != nil { return fmt.Errorf("Error waiting for the creation of App Service Environment %q (Resource Group %q): %+v", name, resourceGroup, err) } @@ -171,6 +187,49 @@ func resourceArmAppServiceEnvironmentCreateOrUpdate(d *schema.ResourceData, meta return resourceArmAppServiceEnvironmentRead(d, meta) } +func resourceArmAppServiceEnvironmentUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Web.AppServiceEnvironmentsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.AppServiceEnvironmentID(d.Id()) + if err != nil { + return err + } + + resourceGroup := id.ResourceGroup + name := id.Name + + environment := web.AppServiceEnvironmentPatchResource{ + AppServiceEnvironment: &web.AppServiceEnvironment{}, + } + + if d.HasChange("internal_load_balancing_mode") { + v := d.Get("internal_load_balancing_mode").(string) + environment.AppServiceEnvironment.InternalLoadBalancingMode = web.InternalLoadBalancingMode(v) + } + + if d.HasChange("front_end_scale_factor") { + v := d.Get("front_end_scale_factor").(int) + environment.AppServiceEnvironment.FrontEndScaleFactor = utils.Int32(int32(v)) + } + + if d.HasChange("pricing_tier") { + v := d.Get("pricing_tier").(string) + environment.AppServiceEnvironment.MultiSize = utils.String(v) + } + + if _, err := client.Update(ctx, resourceGroup, name, environment); err != nil { + return fmt.Errorf("Error updating App Service Environment %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + if err := waitForAppServiceEnvironmentToStabilize(ctx, client, resourceGroup, name); err != nil { + return fmt.Errorf("Error waiting for Update of App Service Environment %q (Resource Group %q): %+v", name, resourceGroup, err) + } + + return resourceArmAppServiceEnvironmentRead(d, meta) +} + func resourceArmAppServiceEnvironmentRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*clients.Client).Web.AppServiceEnvironmentsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) @@ -184,10 +243,10 @@ func resourceArmAppServiceEnvironmentRead(d *schema.ResourceData, meta interface resourceGroup := id.ResourceGroup name := id.Name - appServiceEnvironment, err := client.Get(ctx, resourceGroup, name) + existing, err := client.Get(ctx, resourceGroup, name) if err != nil { - if utils.ResponseWasNotFound(appServiceEnvironment.Response) { - log.Printf("[DEBUG] App Service Environmment %q (Resource Group %q) was not found!", name, resourceGroup) + if utils.ResponseWasNotFound(existing.Response) { + log.Printf("[DEBUG] App Service Environmment %q (Resource Group %q) was not found - removing from state!", name, resourceGroup) d.SetId("") return nil } @@ -196,29 +255,34 @@ func resourceArmAppServiceEnvironmentRead(d *schema.ResourceData, meta interface d.Set("name", name) d.Set("resource_group_name", resourceGroup) - if location := appServiceEnvironment.Location; location != nil { + + if location := existing.Location; location != nil { d.Set("location", azure.NormalizeLocation(*location)) } - if err := tags.FlattenAndSet(d, appServiceEnvironment.Tags); err != nil { - return fmt.Errorf("Error flattening and setting tags in App Service Environment %q (resource group %q): %+v", name, resourceGroup, err) - } + if props := existing.AppServiceEnvironment; props != nil { + d.Set("internal_load_balancing_mode", string(props.InternalLoadBalancingMode)) - ase := appServiceEnvironment.AppServiceEnvironment - if ase.InternalLoadBalancingMode != "" { - d.Set("internal_load_balancing_mode", ase.InternalLoadBalancingMode) - } - if ase.VirtualNetwork.ID != nil { - d.Set("subnet_id", ase.VirtualNetwork.ID) - } - if ase.FrontEndScaleFactor != nil { - d.Set("front_end_scale_factor", int(*ase.FrontEndScaleFactor)) - } - if ase.MultiSize != nil { - d.Set("pricing_tier", convertToIsolatedSKU(*ase.MultiSize)) + subnetId := "" + if props.VirtualNetwork != nil && props.VirtualNetwork.ID != nil { + subnetId = *props.VirtualNetwork.ID + } + d.Set("subnet_id", subnetId) + + frontendScaleFactor := 0 + if props.FrontEndScaleFactor != nil { + frontendScaleFactor = int(*props.FrontEndScaleFactor) + } + d.Set("front_end_scale_factor", frontendScaleFactor) + + pricingTier := "" + if props.MultiSize != nil { + pricingTier = convertToIsolatedSKU(*props.MultiSize) + } + d.Set("pricing_tier", pricingTier) } - return nil + return tags.FlattenAndSet(d, existing.Tags) } func resourceArmAppServiceEnvironmentDelete(d *schema.ResourceData, meta interface{}) error { @@ -236,15 +300,15 @@ func resourceArmAppServiceEnvironmentDelete(d *schema.ResourceData, meta interfa log.Printf("[DEBUG] Deleting App Service Environment %q (Resource Group %q)", name, resGroup) - // `true` below deletes any child resources (e.g. App Services / Plans / Certificates etc) - // TODO: Add this to the provider 'Features' schema? - future, err := client.Delete(ctx, resGroup, name, utils.Bool(true)) + // TODO: should this behaviour be added to the `features` block? + forceDeleteAllChildren := utils.Bool(false) + future, err := client.Delete(ctx, resGroup, name, forceDeleteAllChildren) if err != nil { if response.WasNotFound(future.Response()) { return nil } - return err + return fmt.Errorf("Error deleting App Service Environment %q (Resource Group %q): %+v", name, resGroup, err) } err = future.WaitForCompletionRef(ctx, client.Client) @@ -253,7 +317,35 @@ func resourceArmAppServiceEnvironmentDelete(d *schema.ResourceData, meta interfa return nil } - return err + return fmt.Errorf("Error waiting for deletion of App Service Environment %q (Resource Group %q): %+v", name, resGroup, err) + } + + return nil +} + +func waitForAppServiceEnvironmentToStabilize(ctx context.Context, client *web.AppServiceEnvironmentsClient, resourceGroup string, name string) error { + for true { + time.Sleep(1 * time.Minute) + + read, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return err + } + + if read.AppServiceEnvironment == nil { + return fmt.Errorf("`properties` was nil") + } + + state := read.AppServiceEnvironment.ProvisioningState + if state == web.ProvisioningStateSucceeded { + return nil + } + + if state == web.ProvisioningStateInProgress { + continue + } + + return fmt.Errorf("Unexpected ProvisioningState: %q", state) } return nil diff --git a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go index b90e65844a49..b64ed190ae02 100644 --- a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go @@ -12,7 +12,7 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) -func TestAccAzureRMAppServiceEnvironment_basicWindows(t *testing.T) { +func TestAccAzureRMAppServiceEnvironment_basic(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") resource.ParallelTest(t, resource.TestCase{ @@ -74,7 +74,7 @@ func TestAccAzureRMAppServiceEnvironment_update(t *testing.T) { }, data.ImportStep(), { - Config: testAccAzureRMAppServiceEnvironment_update(data), + Config: testAccAzureRMAppServiceEnvironment_tierAndScaleFactor(data), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(data.ResourceName, "pricing_tier", "I2"), resource.TestCheckResourceAttr(data.ResourceName, "front_end_scale_factor", "10"), @@ -126,118 +126,6 @@ func TestAccAzureRMAppServiceEnvironment_withAppServicePlan(t *testing.T) { }) } -func testAccAzureRMAppServiceEnvironment_basic(data acceptance.TestData) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%[1]d" - location = "%[2]s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctest-vnet-%[1]d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - address_space = ["10.0.0.0/16"] - - subnet { - name = "asesubnet" - address_prefix = "10.0.1.0/24" - } - - subnet { - name = "gatewaysubnet" - address_prefix = "10.0.2.0/24" - } -} - -data "azurerm_subnet" "test" { - name = "asesubnet" - virtual_network_name = "${azurerm_virtual_network.test.name}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_app_service_environment" "test" { - name = "acctest-ase-%[1]d" - subnet_id = "${data.azurerm_subnet.test.id}" -} -`, data.RandomInteger, data.Locations.Primary) -} - -func testAccAzureRMAppServiceEnvironment_requiresImport(data acceptance.TestData) string { - template := testAccAzureRMAppServiceEnvironment_basic(data) - return fmt.Sprintf(` -%s - -resource "azurerm_app_service_environment" "import" { - name = "${azurerm_app_service_environment.test.name}" - subnet_id = "${azurerm_app_service_environment.test.subnet_id}" - -} -`, template) -} - -func testAccAzureRMAppServiceEnvironment_tierAndScaleFactor(data acceptance.TestData) string { - return fmt.Sprintf(` -resource "azurerm_resource_group" "test" { - name = "acctestRG-%[1]d" - location = "%[2]s" -} - -resource "azurerm_virtual_network" "test" { - name = "acctest-vnet-%[1]d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - address_space = ["10.0.0.0/16"] - - subnet { - name = "asesubnet" - address_prefix = "10.0.1.0/24" - } - - subnet { - name = "gatewaysubnet" - address_prefix = "10.0.2.0/24" - } -} - -data "azurerm_subnet" "test" { - name = "asesubnet" - virtual_network_name = "${azurerm_virtual_network.test.name}" - resource_group_name = "${azurerm_resource_group.test.name}" -} - -resource "azurerm_app_service_environment" "test" { - name = "acctest-ase-%[1]d" - subnet_id = "${data.azurerm_subnet.test.id}" - pricing_tier = "I2" - front_end_scale_factor = 10 -} -`, data.RandomInteger, data.Locations.Primary) -} - -func testAccAzureRMAppServiceEnvironment_update(data acceptance.TestData) string { - return testAccAzureRMAppServiceEnvironment_tierAndScaleFactor(data) -} - -func testAccAzureRMAppServiceEnvironment_withAppServicePlan(data acceptance.TestData) string { - template := testAccAzureRMAppServiceEnvironment_basic(data) - return fmt.Sprintf(` -%s - -resource "azurerm_app_service_plan" "test" { - name = "acctest-ASP-%d" - location = "${azurerm_resource_group.test.location}" - resource_group_name = "${azurerm_resource_group.test.name}" - app_service_environment_id = "${azurerm_app_service_environment.test.id}" - - sku { - tier = "Basic" - size = "B1" - } -} -`, template, data.RandomInteger) -} - func testCheckAzureRMAppServiceEnvironmentExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { client := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServiceEnvironmentsClient @@ -336,3 +224,90 @@ func testCheckAppServicePlanMemberOfAppServiceEnvironment(ase string, asp string return nil } } + +func testAccAzureRMAppServiceEnvironment_basic(data acceptance.TestData) string { + template := testAccAzureRMAppServiceEnvironment_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_environment" "test" { + name = "acctest-ase-%d" + subnet_id = azurerm_subnet.ase.id +} +`, template, data.RandomInteger) +} + +func testAccAzureRMAppServiceEnvironment_requiresImport(data acceptance.TestData) string { + template := testAccAzureRMAppServiceEnvironment_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_environment" "import" { + name = azurerm_app_service_environment.test.name + subnet_id = azurerm_app_service_environment.test.subnet_id +} +`, template) +} + +func testAccAzureRMAppServiceEnvironment_tierAndScaleFactor(data acceptance.TestData) string { + template := testAccAzureRMAppServiceEnvironment_template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_environment" "test" { + name = "acctest-ase-%d" + subnet_id = azurerm_subnet.ase.id + pricing_tier = "I2" + front_end_scale_factor = 10 +} +`, template, data.RandomInteger) +} + +func testAccAzureRMAppServiceEnvironment_withAppServicePlan(data acceptance.TestData) string { + template := testAccAzureRMAppServiceEnvironment_basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_app_service_plan" "test" { + name = "acctest-ASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_environment_id = azurerm_app_service_environment.test.id + + sku { + tier = "Basic" + size = "B1" + } +} +`, template, data.RandomInteger) +} + +func testAccAzureRMAppServiceEnvironment_template(data acceptance.TestData) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctest-vnet-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + address_space = ["10.0.0.0/16"] +} + +resource "azurerm_subnet" "ase" { + name = "asesubnet" + 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_subnet" "gateway" { + name = "gatewaysubnet" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefix = "10.0.2.0/24" +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger) +} From f5d0c7ce52aa7cbb060b347c48b2307aa483927c Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 21 Feb 2020 15:03:12 +0100 Subject: [PATCH 17/26] tests: adding in missing checkdestroys for the data source tests --- ...pp_service_environment_data_source_test.go | 5 +- .../data_source_app_service_plan_test.go | 20 +++++--- .../web/tests/data_source_app_service_test.go | 50 +++++++++++-------- 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/azurerm/internal/services/web/tests/app_service_environment_data_source_test.go b/azurerm/internal/services/web/tests/app_service_environment_data_source_test.go index 5b98c25ff79c..a38c32a878ed 100644 --- a/azurerm/internal/services/web/tests/app_service_environment_data_source_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_data_source_test.go @@ -12,8 +12,9 @@ func TestAccDataSourceAzureRMAppServiceEnvironment_basic(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service_environment", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceEnvironmentDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppServiceEnvironment_basic(data), diff --git a/azurerm/internal/services/web/tests/data_source_app_service_plan_test.go b/azurerm/internal/services/web/tests/data_source_app_service_plan_test.go index 0b6d291c9d01..83076a2e4399 100644 --- a/azurerm/internal/services/web/tests/data_source_app_service_plan_test.go +++ b/azurerm/internal/services/web/tests/data_source_app_service_plan_test.go @@ -14,8 +14,9 @@ func TestAccDataSourceAzureRMAppServicePlan_basic(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service_plan", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServicePlanDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppServicePlan_basic(data), @@ -35,8 +36,9 @@ func TestAccDataSourceAzureRMAppServicePlan_complete(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service_plan", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServicePlanDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppServicePlan_complete(data), @@ -57,8 +59,9 @@ func TestAccDataSourceAzureRMAppServicePlan_premiumSKU(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service_plan", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServicePlanDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppServicePlan_premiumSKU(data), @@ -78,8 +81,9 @@ func TestAccDataSourceAzureRMAppServicePlan_basicWindowsContainer(t *testing.T) data := acceptance.BuildTestData(t, "data.azurerm_app_service_plan", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServicePlanDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppServicePlan_basicWindowsContainer(data), diff --git a/azurerm/internal/services/web/tests/data_source_app_service_test.go b/azurerm/internal/services/web/tests/data_source_app_service_test.go index b94041087df6..bc4f75c25aba 100644 --- a/azurerm/internal/services/web/tests/data_source_app_service_test.go +++ b/azurerm/internal/services/web/tests/data_source_app_service_test.go @@ -12,8 +12,9 @@ func TestAccDataSourceAzureRMAppService_basic(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_basic(data), @@ -32,8 +33,9 @@ func TestAccDataSourceAzureRMAppService_tags(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_tags(data), @@ -50,8 +52,9 @@ func TestAccDataSourceAzureRMAppService_clientAppAffinityDisabled(t *testing.T) data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_clientAffinityDisabled(data), @@ -67,8 +70,9 @@ func TestAccDataSourceAzureRMAppService_32Bit(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_32Bit(data), @@ -84,8 +88,9 @@ func TestAccDataSourceAzureRMAppService_appSettings(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_appSettings(data), @@ -101,8 +106,9 @@ func TestAccDataSourceAzureRMAppService_connectionString(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_connectionStrings(data), @@ -123,8 +129,9 @@ func TestAccDataSourceAzureRMAppService_ipRestriction(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_ipRestriction(data), @@ -140,8 +147,9 @@ func TestAccDataSourceAzureRMAppService_http2Enabled(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_http2Enabled(data), @@ -157,8 +165,9 @@ func TestAccDataSourceAzureRMAppService_minTls(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_minTls(data), @@ -174,8 +183,9 @@ func TestAccDataSourceAzureRMAppService_basicWindowsContainer(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acceptance.PreCheck(t) }, - Providers: acceptance.SupportedProviders, + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAppService_basicWindowsContainer(data), From b190eff5f5b79964ea12d6ae4003502ba6a71bdc Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 21 Feb 2020 15:05:58 +0100 Subject: [PATCH 18/26] r/app_service_environment: fixing up linting --- .../internal/services/web/app_service_environment_resource.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index cdb134e90a4e..ac1acef6ca6f 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -124,7 +124,7 @@ func resourceArmAppServiceEnvironmentCreate(d *schema.ResourceData, meta interfa return fmt.Errorf("Error retrieving Virtual Network %q (Resource Group %q): %+v", subnet.VirtualNetworkName, resourceGroup, err) } - // the App Service Environment has to be in the same location as the Virtual netowrk - + // the App Service Environment has to be in the same location as the Virtual Network var location string if loc := vnet.Location; loc != nil { location = azure.NormalizeLocation(*loc) @@ -324,7 +324,7 @@ func resourceArmAppServiceEnvironmentDelete(d *schema.ResourceData, meta interfa } func waitForAppServiceEnvironmentToStabilize(ctx context.Context, client *web.AppServiceEnvironmentsClient, resourceGroup string, name string) error { - for true { + for { time.Sleep(1 * time.Minute) read, err := client.Get(ctx, resourceGroup, name) From 8000bba4476615e2473e591b900deee0be642f65 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 21 Feb 2020 15:23:16 +0100 Subject: [PATCH 19/26] r/app_service_env: fixing the import test --- .../services/web/tests/app_service_environment_resource_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go index b64ed190ae02..6db18f88cab4 100644 --- a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go @@ -39,7 +39,7 @@ func TestAccAzureRMAppServiceEnvironment_requiresImport(t *testing.T) { return } - data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") + data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "import") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, From afb1e60f3e4e9ec22a4e94f0612c5985b3b75bb6 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 21 Feb 2020 18:56:18 +0100 Subject: [PATCH 20/26] r/app_service_environment: fixing the requires import test --- .../web/tests/app_service_environment_resource_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go index 6db18f88cab4..05a1ec9792fc 100644 --- a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go @@ -39,14 +39,14 @@ func TestAccAzureRMAppServiceEnvironment_requiresImport(t *testing.T) { return } - data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "import") + data := acceptance.BuildTestData(t, "azurerm_app_service_environment", "test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acceptance.PreCheck(t) }, Providers: acceptance.SupportedProviders, - CheckDestroy: testCheckAzureRMAppServiceDestroy, + CheckDestroy: testCheckAzureRMAppServiceEnvironmentDestroy, Steps: []resource.TestStep{ { - Config: testAccAzureRMAppService_basic(data), + Config: testAccAzureRMAppServiceEnvironment_basic(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceEnvironmentExists(data.ResourceName), ), From 08855d9b8ab32e0f07c504e96dba320a754802e0 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 21 Feb 2020 20:58:57 +0100 Subject: [PATCH 21/26] r/app_service_environment: converting from the display to actual sku --- .../internal/services/web/app_service_environment_resource.go | 1 + 1 file changed, 1 insertion(+) diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index ac1acef6ca6f..78edc473120f 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -216,6 +216,7 @@ func resourceArmAppServiceEnvironmentUpdate(d *schema.ResourceData, meta interfa if d.HasChange("pricing_tier") { v := d.Get("pricing_tier").(string) + v = convertFromIsolatedSKU(v) environment.AppServiceEnvironment.MultiSize = utils.String(v) } From 1c2eb081ae5a1361f87be1c27f6c9080da7a276f Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 21 Feb 2020 21:32:33 +0100 Subject: [PATCH 22/26] r/app_service_environment: fixing the plan test --- .../services/web/app_service_environment_resource.go | 2 -- .../web/tests/app_service_environment_resource_test.go | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/web/app_service_environment_resource.go b/azurerm/internal/services/web/app_service_environment_resource.go index 78edc473120f..bda7acb22fb6 100644 --- a/azurerm/internal/services/web/app_service_environment_resource.go +++ b/azurerm/internal/services/web/app_service_environment_resource.go @@ -348,8 +348,6 @@ func waitForAppServiceEnvironmentToStabilize(ctx context.Context, client *web.Ap return fmt.Errorf("Unexpected ProvisioningState: %q", state) } - - return nil } // Note: These are abstractions and possibly subject to change if Azure changes the underlying SKU for Isolated instances. diff --git a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go index 05a1ec9792fc..0e0ef9687f64 100644 --- a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go @@ -275,8 +275,9 @@ resource "azurerm_app_service_plan" "test" { app_service_environment_id = azurerm_app_service_environment.test.id sku { - tier = "Basic" - size = "B1" + tier = "Isolated" + size = "I1" + capacity = 1 } } `, template, data.RandomInteger) From 9187513738fc4e2dad9faf3949340647148b3606 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 21 Feb 2020 21:46:13 +0100 Subject: [PATCH 23/26] refactor: switching to the same client --- azurerm/internal/services/web/client/client.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/services/web/client/client.go b/azurerm/internal/services/web/client/client.go index 0ff3d10a458c..6c89651665ad 100644 --- a/azurerm/internal/services/web/client/client.go +++ b/azurerm/internal/services/web/client/client.go @@ -2,12 +2,11 @@ package client import ( "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web" - asev2 "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/common" ) type Client struct { - AppServiceEnvironmentsClient *asev2.AppServiceEnvironmentsClient + AppServiceEnvironmentsClient *web.AppServiceEnvironmentsClient AppServicePlansClient *web.AppServicePlansClient AppServicesClient *web.AppsClient BaseClient *web.BaseClient @@ -16,7 +15,7 @@ type Client struct { } func NewClient(o *common.ClientOptions) *Client { - appServiceEnvironmentsClient := asev2.NewAppServiceEnvironmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + appServiceEnvironmentsClient := web.NewAppServiceEnvironmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&appServiceEnvironmentsClient.Client, o.ResourceManagerAuthorizer) appServicePlansClient := web.NewAppServicePlansClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) From 26000c1c11ab7631b0c0097ea7d84c74a46b8f6d Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Fri, 21 Feb 2020 21:46:57 +0100 Subject: [PATCH 24/26] deps: fixing the vendor file --- vendor/modules.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/vendor/modules.txt b/vendor/modules.txt index 21fb930017fc..ef8827c62e16 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -80,7 +80,6 @@ github.com/Azure/azure-sdk-for-go/services/signalr/mgmt/2018-10-01/signalr github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2019-04-01/storage github.com/Azure/azure-sdk-for-go/services/streamanalytics/mgmt/2016-03-01/streamanalytics github.com/Azure/azure-sdk-for-go/services/trafficmanager/mgmt/2018-04-01/trafficmanager -github.com/Azure/azure-sdk-for-go/services/web/mgmt/2018-02-01/web github.com/Azure/azure-sdk-for-go/services/web/mgmt/2019-08-01/web github.com/Azure/azure-sdk-for-go/version # github.com/Azure/go-autorest/autorest v0.9.3 From 8bf7e312ad7294aa5864718ecd53160989a661a4 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Sat, 22 Feb 2020 11:35:50 +0100 Subject: [PATCH 25/26] r/app_service_plan: increasing the timeouts to 60m for ASE's --- .../internal/services/web/resource_arm_app_service_plan.go | 6 +++--- website/docs/r/app_service_plan.html.markdown | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/azurerm/internal/services/web/resource_arm_app_service_plan.go b/azurerm/internal/services/web/resource_arm_app_service_plan.go index 3a40be35b8a1..66ac7d4f8e81 100644 --- a/azurerm/internal/services/web/resource_arm_app_service_plan.go +++ b/azurerm/internal/services/web/resource_arm_app_service_plan.go @@ -33,10 +33,10 @@ func resourceArmAppServicePlan() *schema.Resource { }), Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(30 * time.Minute), + Create: schema.DefaultTimeout(60 * time.Minute), Read: schema.DefaultTimeout(5 * time.Minute), - Update: schema.DefaultTimeout(30 * time.Minute), - Delete: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(60 * time.Minute), }, Schema: map[string]*schema.Schema{ diff --git a/website/docs/r/app_service_plan.html.markdown b/website/docs/r/app_service_plan.html.markdown index 061859390bf0..5a0ce52bd049 100644 --- a/website/docs/r/app_service_plan.html.markdown +++ b/website/docs/r/app_service_plan.html.markdown @@ -143,10 +143,10 @@ The following attributes are exported: 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 Plan. -* `update` - (Defaults to 30 minutes) Used when updating the App Service Plan. +* `create` - (Defaults to 60 minutes) Used when creating the App Service Plan. +* `update` - (Defaults to 60 minutes) Used when updating the App Service Plan. * `read` - (Defaults to 5 minutes) Used when retrieving the App Service Plan. -* `delete` - (Defaults to 30 minutes) Used when deleting the App Service Plan. +* `delete` - (Defaults to 60 minutes) Used when deleting the App Service Plan. ## Import From f9f006e8cfd97aa915aea6db9ff7ebd1b0e56a67 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Sun, 23 Feb 2020 09:51:28 +0100 Subject: [PATCH 26/26] r/app_service_environment: checking the ID's from the state --- .../web/resource_arm_app_service_plan.go | 14 ++++-- .../app_service_environment_resource_test.go | 45 +------------------ 2 files changed, 11 insertions(+), 48 deletions(-) diff --git a/azurerm/internal/services/web/resource_arm_app_service_plan.go b/azurerm/internal/services/web/resource_arm_app_service_plan.go index 66ac7d4f8e81..6e9d7e38421d 100644 --- a/azurerm/internal/services/web/resource_arm_app_service_plan.go +++ b/azurerm/internal/services/web/resource_arm_app_service_plan.go @@ -264,17 +264,23 @@ func resourceArmAppServicePlanRead(d *schema.ResourceData, meta interface{}) err d.Set("kind", resp.Kind) if props := resp.AppServicePlanProperties; props != nil { - if profile := props.HostingEnvironmentProfile; profile != nil { - d.Set("app_service_environment_id", profile.ID) + appServiceEnvironmentId := "" + if props.HostingEnvironmentProfile != nil && props.HostingEnvironmentProfile.ID != nil { + appServiceEnvironmentId = *props.HostingEnvironmentProfile.ID } + d.Set("app_service_environment_id", appServiceEnvironmentId) + maximumNumberOfWorkers := 0 if props.MaximumNumberOfWorkers != nil { - d.Set("maximum_number_of_workers", int(*props.MaximumNumberOfWorkers)) + maximumNumberOfWorkers = int(*props.MaximumNumberOfWorkers) } + d.Set("maximum_number_of_workers", maximumNumberOfWorkers) + maximumElasticWorkerCount := 0 if props.MaximumElasticWorkerCount != nil { - d.Set("maximum_elastic_worker_count", int(*props.MaximumElasticWorkerCount)) + maximumElasticWorkerCount = int(*props.MaximumElasticWorkerCount) } + d.Set("maximum_elastic_worker_count", maximumElasticWorkerCount) d.Set("per_site_scaling", props.PerSiteScaling) d.Set("reserved", props.Reserved) diff --git a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go index 0e0ef9687f64..e70014f11122 100644 --- a/azurerm/internal/services/web/tests/app_service_environment_resource_test.go +++ b/azurerm/internal/services/web/tests/app_service_environment_resource_test.go @@ -118,7 +118,7 @@ func TestAccAzureRMAppServiceEnvironment_withAppServicePlan(t *testing.T) { Config: testAccAzureRMAppServiceEnvironment_withAppServicePlan(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceEnvironmentExists(data.ResourceName), - testCheckAppServicePlanMemberOfAppServiceEnvironment(data.ResourceName, aspData.ResourceName), + resource.TestCheckResourceAttrPair(data.ResourceName, "id", aspData.ResourceName, "app_service_environment_id"), ), }, data.ImportStep(), @@ -182,49 +182,6 @@ func testCheckAzureRMAppServiceEnvironmentDestroy(s *terraform.State) error { return nil } -func testCheckAppServicePlanMemberOfAppServiceEnvironment(ase string, asp string) resource.TestCheckFunc { - return func(s *terraform.State) error { - aseClient := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServiceEnvironmentsClient - aspClient := acceptance.AzureProvider.Meta().(*clients.Client).Web.AppServicePlansClient - ctx := acceptance.AzureProvider.Meta().(*clients.Client).StopContext - - aseResource, ok := s.RootModule().Resources[ase] - if !ok { - return fmt.Errorf("Not found: %s", ase) - } - - appServiceEnvironmentName := aseResource.Primary.Attributes["name"] - appServiceEnvironmentResourceGroup := aseResource.Primary.Attributes["resource_group_name"] - - aseResp, err := aseClient.Get(ctx, appServiceEnvironmentResourceGroup, appServiceEnvironmentName) - if err != nil { - if utils.ResponseWasNotFound(aseResp.Response) { - return fmt.Errorf("Bad: App Service Environment %q (resource group %q) does not exist: %+v", appServiceEnvironmentName, appServiceEnvironmentResourceGroup, err) - } - } - - aspResource, ok := s.RootModule().Resources[asp] - if !ok { - return fmt.Errorf("Not found: %s", ase) - } - - appServicePlanName := aspResource.Primary.Attributes["name"] - appServicePlanResourceGroup := aspResource.Primary.Attributes["resource_group_name"] - - aspResp, err := aspClient.Get(ctx, appServicePlanResourceGroup, appServicePlanName) - if err != nil { - if utils.ResponseWasNotFound(aseResp.Response) { - return fmt.Errorf("Bad: App Service Plan %q (resource group %q) does not exist: %+v", appServicePlanName, appServicePlanResourceGroup, err) - } - } - if aspResp.HostingEnvironmentProfile.ID != aseResp.ID { - return fmt.Errorf("Bad: App Service Plan %s not a member of App Service Environment %s", appServicePlanName, appServiceEnvironmentName) - } - - return nil - } -} - func testAccAzureRMAppServiceEnvironment_basic(data acceptance.TestData) string { template := testAccAzureRMAppServiceEnvironment_template(data) return fmt.Sprintf(`