From b8c1825da546583007b510f61cd846c70238bda6 Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 5 Nov 2024 16:54:16 +0100 Subject: [PATCH 1/8] migrate logic app standard to go-azure-sdk --- .../logic/logic_app_standard_data_source.go | 351 ++++----- .../logic/logic_app_standard_resource.go | 726 ++++++++---------- .../logic/logic_app_standard_resource_test.go | 21 +- 3 files changed, 457 insertions(+), 641 deletions(-) diff --git a/internal/services/logic/logic_app_standard_data_source.go b/internal/services/logic/logic_app_standard_data_source.go index d37967283aed..3d87d9865437 100644 --- a/internal/services/logic/logic_app_standard_data_source.go +++ b/internal/services/logic/logic_app_standard_data_source.go @@ -9,16 +9,18 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2021-02-01/web" // nolint: staticcheck + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-12-01/webapps" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceLogicAppStandard() *pluginsdk.Resource { @@ -132,7 +134,7 @@ func dataSourceLogicAppStandard() *pluginsdk.Resource { Computed: true, }, - "tags": tags.Schema(), + "tags": commonschema.TagsDataSource(), "custom_domain_verification_id": { Type: pluginsdk.TypeString, @@ -186,196 +188,189 @@ func dataSourceLogicAppStandard() *pluginsdk.Resource { } func dataSourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Web.AppServicesClient + client := meta.(*clients.Client).AppService.WebAppsClient subscriptionId := meta.(*clients.Client).Web.AppServicesClient.SubscriptionID ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewLogicAppStandardID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + id := commonids.NewAppServiceID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.SiteName) + resp, err := client.Get(ctx, id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Logic App Standard %s was not found", id) + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", id) } - return fmt.Errorf("[ERROR] Error making Read request on Logic App Standard %s: %+v", id, err) + return fmt.Errorf("retrieving %s: %+v", id, err) } d.SetId(id.ID()) - appSettingsResp, err := client.ListApplicationSettings(ctx, id.ResourceGroup, id.SiteName) - if err != nil { - return fmt.Errorf("[ERROR] Listing application settings for %s: %+v", id, err) - } - - connectionStringsResp, err := client.ListConnectionStrings(ctx, id.ResourceGroup, id.SiteName) - if err != nil { - return fmt.Errorf("[ERROR] Listing connection strings for %s: %+v", id, err) - } + if model := resp.Model; model != nil { + d.Set("kind", pointer.From(model.Kind)) + d.Set("location", location.Normalize(model.Location)) - siteCredFuture, err := client.ListPublishingCredentials(ctx, id.ResourceGroup, id.SiteName) - if err != nil { - return fmt.Errorf("[ERROR] Listing publishing credentials for %s: %+v", id, err) - } - if err = siteCredFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("[ERROR] Waiting to list the publishing credentials for %s: %+v", id, err) - } - siteCredResp, err := siteCredFuture.Result(*client) - if err != nil { - return fmt.Errorf("[ERROR] Retrieving the publishing credentials for %s: %+v", id, err) - } - - d.Set("kind", resp.Kind) - - d.Set("location", location.NormalizeNilable(resp.Location)) - - if props := resp.SiteProperties; props != nil { - d.Set("app_service_plan_id", props.ServerFarmID) - d.Set("enabled", props.Enabled) - d.Set("default_hostname", props.DefaultHostName) - d.Set("https_only", props.HTTPSOnly) - d.Set("outbound_ip_addresses", props.OutboundIPAddresses) - d.Set("possible_outbound_ip_addresses", props.PossibleOutboundIPAddresses) - d.Set("client_affinity_enabled", props.ClientAffinityEnabled) - d.Set("custom_domain_verification_id", props.CustomDomainVerificationID) + identityFlattened, err := identity.FlattenSystemAndUserAssignedMap(model.Identity) + if err != nil { + return fmt.Errorf("flattening `identity`: %+v", err) + } + if err := d.Set("identity", identityFlattened); err != nil { + return fmt.Errorf("setting `identity`: %s", err) + } - clientCertMode := "" - if props.ClientCertEnabled != nil && *props.ClientCertEnabled { - clientCertMode = string(props.ClientCertMode) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return fmt.Errorf("setting `tags`: %+v", err) } - d.Set("client_certificate_mode", clientCertMode) - } - appSettings := flattenLogicAppStandardDataSourceAppSettings(appSettingsResp.Properties) + if props := model.Properties; props != nil { + d.Set("app_service_plan_id", pointer.From(props.ServerFarmId)) + d.Set("enabled", props.Enabled) + d.Set("default_hostname", props.DefaultHostName) + d.Set("https_only", props.HTTPSOnly) + d.Set("outbound_ip_addresses", props.OutboundIPAddresses) + d.Set("possible_outbound_ip_addresses", props.PossibleOutboundIPAddresses) + d.Set("client_affinity_enabled", props.ClientAffinityEnabled) + d.Set("custom_domain_verification_id", props.CustomDomainVerificationId) + + clientCertMode := "" + if props.ClientCertEnabled != nil && *props.ClientCertEnabled { + clientCertMode = string(pointer.From(props.ClientCertMode)) + } + d.Set("client_certificate_mode", clientCertMode) - if err = d.Set("virtual_network_subnet_id", resp.SiteProperties.VirtualNetworkSubnetID); err != nil { - return err + d.Set("virtual_network_subnet_id", props.VirtualNetworkSubnetId) + } } - if err = d.Set("connection_string", flattenLogicAppStandardDataSourceConnectionStrings(connectionStringsResp.Properties)); err != nil { - return err + appSettingsResp, err := client.ListApplicationSettings(ctx, id) + if err != nil { + return fmt.Errorf("listing application settings for %s: %+v", id, err) } + if model := appSettingsResp.Model; model != nil { + appSettings := flattenLogicAppStandardDataSourceAppSettings(model.Properties) - connectionString := appSettings["AzureWebJobsStorage"] + connectionString := appSettings["AzureWebJobsStorage"] - // This teases out the necessary attributes from the storage connection string - connectionStringParts := strings.Split(connectionString, ";") - for _, part := range connectionStringParts { - if strings.HasPrefix(part, "AccountName") { - accountNameParts := strings.Split(part, "AccountName=") - if len(accountNameParts) > 1 { - d.Set("storage_account_name", accountNameParts[1]) + // This teases out the necessary attributes from the storage connection string + connectionStringParts := strings.Split(connectionString, ";") + for _, part := range connectionStringParts { + if strings.HasPrefix(part, "AccountName") { + accountNameParts := strings.Split(part, "AccountName=") + if len(accountNameParts) > 1 { + d.Set("storage_account_name", accountNameParts[1]) + } } - } - if strings.HasPrefix(part, "AccountKey") { - accountKeyParts := strings.Split(part, "AccountKey=") - if len(accountKeyParts) > 1 { - d.Set("storage_account_access_key", accountKeyParts[1]) + if strings.HasPrefix(part, "AccountKey") { + accountKeyParts := strings.Split(part, "AccountKey=") + if len(accountKeyParts) > 1 { + d.Set("storage_account_access_key", accountKeyParts[1]) + } } } - } - d.Set("version", appSettings["FUNCTIONS_EXTENSION_VERSION"]) + d.Set("version", appSettings["FUNCTIONS_EXTENSION_VERSION"]) - if _, ok := appSettings["AzureFunctionsJobHost__extensionBundle__id"]; ok { - d.Set("use_extension_bundle", true) - if val, ok := appSettings["AzureFunctionsJobHost__extensionBundle__version"]; ok { - d.Set("bundle_version", val) + if _, ok := appSettings["AzureFunctionsJobHost__extensionBundle__id"]; ok { + d.Set("use_extension_bundle", true) + if val, ok := appSettings["AzureFunctionsJobHost__extensionBundle__version"]; ok { + d.Set("bundle_version", val) + } + } else { + d.Set("use_extension_bundle", false) + d.Set("bundle_version", "[1.*, 2.0.0)") } - } else { - d.Set("use_extension_bundle", false) - d.Set("bundle_version", "[1.*, 2.0.0)") - } - d.Set("storage_account_share_name", appSettings["WEBSITE_CONTENTSHARE"]) - - // Remove all the settings that are created by this resource so we don't to have to specify in app_settings - // block whenever we use azurerm_logic_app_standard. - delete(appSettings, "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING") - delete(appSettings, "APP_KIND") - delete(appSettings, "AzureFunctionsJobHost__extensionBundle__id") - delete(appSettings, "AzureFunctionsJobHost__extensionBundle__version") - delete(appSettings, "AzureWebJobsDashboard") - delete(appSettings, "AzureWebJobsStorage") - delete(appSettings, "FUNCTIONS_EXTENSION_VERSION") - delete(appSettings, "WEBSITE_CONTENTSHARE") - - if err = d.Set("app_settings", appSettings); err != nil { - return err + d.Set("storage_account_share_name", appSettings["WEBSITE_CONTENTSHARE"]) + + // Remove all the settings that are created by this resource so we don't to have to specify in app_settings + // block whenever we use azurerm_logic_app_standard. + delete(appSettings, "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING") + delete(appSettings, "APP_KIND") + delete(appSettings, "AzureFunctionsJobHost__extensionBundle__id") + delete(appSettings, "AzureFunctionsJobHost__extensionBundle__version") + delete(appSettings, "AzureWebJobsDashboard") + delete(appSettings, "AzureWebJobsStorage") + delete(appSettings, "FUNCTIONS_EXTENSION_VERSION") + delete(appSettings, "WEBSITE_CONTENTSHARE") + + if err = d.Set("app_settings", appSettings); err != nil { + return err + } } - identity := flattenLogicAppStandardDataSourceIdentity(resp.Identity) - if err := d.Set("identity", identity); err != nil { - return fmt.Errorf("setting `identity`: %s", err) + connectionStringsResp, err := client.ListConnectionStrings(ctx, id) + if err != nil { + return fmt.Errorf("listing connection strings for %s: %+v", id, err) + } + if model := connectionStringsResp.Model; model != nil { + if err = d.Set("connection_string", flattenLogicAppStandardDataSourceConnectionStrings(model.Properties)); err != nil { + return err + } } - configResp, err := client.GetConfiguration(ctx, id.ResourceGroup, id.SiteName) + configResp, err := client.GetConfiguration(ctx, id) if err != nil { return fmt.Errorf("retrieving the configuration for %s: %+v", id, err) } + if model := configResp.Model; model != nil { + siteConfig := flattenLogicAppStandardDataSourceSiteConfig(model.Properties) + if err = d.Set("site_config", siteConfig); err != nil { + return err + } + } - siteConfig := flattenLogicAppStandardDataSourceSiteConfig(configResp.SiteConfig) - if err = d.Set("site_config", siteConfig); err != nil { - return err + siteCredFuture, err := client.ListPublishingCredentials(ctx, id) + if err != nil { + return fmt.Errorf("listing publishing credentials for %s: %+v", id, err) } - siteCred := flattenLogicAppStandardDataSourceSiteCredential(siteCredResp.UserProperties) - if err = d.Set("site_credential", siteCred); err != nil { - return err + if err = siteCredFuture.Poller.PollUntilDone(ctx); err != nil { + return fmt.Errorf("waiting to list the publishing credentials for %s: %+v", id, err) } - return tags.FlattenAndSet(d, resp.Tags) + if model := siteCredFuture.Model; model != nil { + siteCred := flattenLogicAppStandardDataSourceSiteCredential(model.Properties) + if err = d.Set("site_credential", siteCred); err != nil { + return err + } + } + + return nil } -func flattenLogicAppStandardDataSourceAppSettings(input map[string]*string) map[string]string { +func flattenLogicAppStandardDataSourceAppSettings(input *map[string]string) map[string]string { output := make(map[string]string) - for k, v := range input { - output[k] = *v + + if input == nil || len(*input) == 0 { + return output + } + + for k, v := range *input { + output[k] = v } return output } -func flattenLogicAppStandardDataSourceConnectionStrings(input map[string]*web.ConnStringValueTypePair) interface{} { +func flattenLogicAppStandardDataSourceConnectionStrings(input *map[string]webapps.ConnStringValueTypePair) interface{} { results := make([]interface{}, 0) - for k, v := range input { + if input == nil || len(*input) == 0 { + return results + } + + for k, v := range *input { result := make(map[string]interface{}) result["name"] = k result["type"] = string(v.Type) - result["value"] = *v.Value + result["value"] = v.Value results = append(results, result) } return results } -func flattenLogicAppStandardDataSourceIdentity(identity *web.ManagedServiceIdentity) []interface{} { - if identity == nil { - return make([]interface{}, 0) - } - - principalId := "" - if identity.PrincipalID != nil { - principalId = *identity.PrincipalID - } - - tenantId := "" - if identity.TenantID != nil { - tenantId = *identity.TenantID - } - - return []interface{}{ - map[string]interface{}{ - "principal_id": principalId, - "tenant_id": tenantId, - "type": string(identity.Type), - }, - } -} - -func flattenLogicAppStandardDataSourceSiteConfig(input *web.SiteConfig) []interface{} { +func flattenLogicAppStandardDataSourceSiteConfig(input *webapps.SiteConfig) []interface{} { results := make([]interface{}, 0) result := make(map[string]interface{}) @@ -384,80 +379,41 @@ func flattenLogicAppStandardDataSourceSiteConfig(input *web.SiteConfig) []interf return results } - if input.AlwaysOn != nil { - result["always_on"] = *input.AlwaysOn - } - - if input.Use32BitWorkerProcess != nil { - result["use_32_bit_worker_process"] = *input.Use32BitWorkerProcess - } - - if input.WebSocketsEnabled != nil { - result["websockets_enabled"] = *input.WebSocketsEnabled - } - - if input.LinuxFxVersion != nil { - result["linux_fx_version"] = *input.LinuxFxVersion - } - - if input.HTTP20Enabled != nil { - result["http2_enabled"] = *input.HTTP20Enabled - } - - if input.PreWarmedInstanceCount != nil { - result["pre_warmed_instance_count"] = *input.PreWarmedInstanceCount - } + result["always_on"] = pointer.From(input.AlwaysOn) + result["use_32_bit_worker_process"] = pointer.From(input.Use32BitWorkerProcess) + result["websockets_enabled"] = pointer.From(input.WebSocketsEnabled) + result["linux_fx_version"] = pointer.From(input.LinuxFxVersion) + result["http2_enabled"] = pointer.From(input.HTTP20Enabled) + result["pre_warmed_instance_count"] = pointer.From(input.PreWarmedInstanceCount) result["ip_restriction"] = flattenLogicAppStandardIpRestriction(input.IPSecurityRestrictions) - result["scm_type"] = string(input.ScmType) - result["scm_min_tls_version"] = string(input.ScmMinTLSVersion) + result["scm_type"] = string(pointer.From(input.ScmType)) + result["scm_min_tls_version"] = string(pointer.From(input.ScmMinTlsVersion)) result["scm_ip_restriction"] = flattenLogicAppStandardIpRestriction(input.ScmIPSecurityRestrictions) - if input.ScmIPSecurityRestrictionsUseMain != nil { - result["scm_use_main_ip_restriction"] = *input.ScmIPSecurityRestrictionsUseMain - } + result["scm_use_main_ip_restriction"] = pointer.From(input.ScmIPSecurityRestrictionsUseMain) - result["min_tls_version"] = string(input.MinTLSVersion) - result["ftps_state"] = string(input.FtpsState) + result["min_tls_version"] = string(pointer.From(input.MinTlsVersion)) + result["ftps_state"] = string(pointer.From(input.FtpsState)) result["cors"] = flattenLogicAppStandardCorsSettings(input.Cors) - if input.AutoSwapSlotName != nil { - result["auto_swap_slot_name"] = *input.AutoSwapSlotName - } - - if input.HealthCheckPath != nil { - result["health_check_path"] = *input.HealthCheckPath - } - - if input.MinimumElasticInstanceCount != nil { - result["elastic_instance_minimum"] = *input.MinimumElasticInstanceCount - } - - if input.FunctionAppScaleLimit != nil { - result["app_scale_limit"] = *input.FunctionAppScaleLimit - } + result["auto_swap_slot_name"] = pointer.From(input.AutoSwapSlotName) + result["health_check_path"] = pointer.From(input.HealthCheckPath) + result["elastic_instance_minimum"] = pointer.From(input.MinimumElasticInstanceCount) + result["app_scale_limit"] = pointer.From(input.FunctionAppScaleLimit) + result["runtime_scale_monitoring_enabled"] = pointer.From(input.FunctionsRuntimeScaleMonitoringEnabled) - if input.FunctionsRuntimeScaleMonitoringEnabled != nil { - result["runtime_scale_monitoring_enabled"] = *input.FunctionsRuntimeScaleMonitoringEnabled - } + result["dotnet_framework_version"] = pointer.From(input.NetFrameworkVersion) - if input.NetFrameworkVersion != nil { - result["dotnet_framework_version"] = *input.NetFrameworkVersion - } - - vnetRouteAllEnabled := false - if input.VnetRouteAllEnabled != nil { - vnetRouteAllEnabled = *input.VnetRouteAllEnabled - } - result["vnet_route_all_enabled"] = vnetRouteAllEnabled + result["vnet_route_all_enabled"] = pointer.From(input.VnetRouteAllEnabled) results = append(results, result) return results } -func flattenLogicAppStandardDataSourceSiteCredential(input *web.UserProperties) []interface{} { +func flattenLogicAppStandardDataSourceSiteCredential(input *webapps.UserProperties) []interface{} { results := make([]interface{}, 0) result := make(map[string]interface{}) @@ -466,13 +422,8 @@ func flattenLogicAppStandardDataSourceSiteCredential(input *web.UserProperties) return results } - if input.PublishingUserName != nil { - result["username"] = *input.PublishingUserName - } - - if input.PublishingPassword != nil { - result["password"] = *input.PublishingPassword - } + result["username"] = input.PublishingUserName + result["password"] = pointer.From(input.PublishingPassword) return append(results, result) } diff --git a/internal/services/logic/logic_app_standard_resource.go b/internal/services/logic/logic_app_standard_resource.go index 835c0877b742..2d078cac9174 100644 --- a/internal/services/logic/logic_app_standard_resource.go +++ b/internal/services/logic/logic_app_standard_resource.go @@ -10,19 +10,21 @@ import ( "strings" "time" - "github.com/Azure/azure-sdk-for-go/services/web/mgmt/2021-02-01/web" // nolint: staticcheck "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" - "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-01-01/resourceproviders" + "github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-12-01/webapps" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/validate" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -131,17 +133,17 @@ func resourceLogicAppStandard() *pluginsdk.Resource { Type: pluginsdk.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - string(web.ConnectionStringTypeAPIHub), - string(web.ConnectionStringTypeCustom), - string(web.ConnectionStringTypeDocDb), - string(web.ConnectionStringTypeEventHub), - string(web.ConnectionStringTypeMySQL), - string(web.ConnectionStringTypeNotificationHub), - string(web.ConnectionStringTypePostgreSQL), - string(web.ConnectionStringTypeRedisCache), - string(web.ConnectionStringTypeServiceBus), - string(web.ConnectionStringTypeSQLAzure), - string(web.ConnectionStringTypeSQLServer), + string(webapps.ConnectionStringTypeApiHub), + string(webapps.ConnectionStringTypeCustom), + string(webapps.ConnectionStringTypeDocDb), + string(webapps.ConnectionStringTypeEventHub), + string(webapps.ConnectionStringTypeMySql), + string(webapps.ConnectionStringTypeNotificationHub), + string(webapps.ConnectionStringTypePostgreSQL), + string(webapps.ConnectionStringTypeRedisCache), + string(webapps.ConnectionStringTypeServiceBus), + string(webapps.ConnectionStringTypeSQLAzure), + string(webapps.ConnectionStringTypeSQLServer), }, false), }, @@ -180,7 +182,7 @@ func resourceLogicAppStandard() *pluginsdk.Resource { Default: "~4", }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), // Computed Only "custom_domain_verification_id": { @@ -236,11 +238,13 @@ func resourceLogicAppStandard() *pluginsdk.Resource { } func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Web.AppServicesClient + clientNew := meta.(*clients.Client).AppService.WebAppsClient subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() + resourcesClient := meta.(*clients.Client).AppService.ResourceProvidersClient + env := meta.(*clients.Client).Account.Environment storageAccountDomainSuffix, ok := env.Storage.DomainSuffix() if !ok { @@ -249,48 +253,38 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) log.Printf("[INFO] preparing arguments for AzureRM Logic App Standard creation.") - id := parse.NewLogicAppStandardID( - subscriptionId, - d.Get("resource_group_name").(string), - d.Get("name").(string), - ) - existing, err := client.Get(ctx, id.ResourceGroup, id.SiteName) + id := commonids.NewAppServiceID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + existing, err := clientNew.Get(ctx, id) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_logic_app_standard", id.ID()) } - availabilityRequest := web.ResourceNameAvailabilityRequest{ - Name: utils.String(id.SiteName), - Type: web.CheckNameResourceTypesMicrosoftWebsites, + availabilityRequest := resourceproviders.ResourceNameAvailabilityRequest{ + Name: id.SiteName, + Type: resourceproviders.CheckNameResourceTypesMicrosoftPointWebSites, } - available, err := client.CheckNameAvailability(ctx, availabilityRequest) + + available, err := resourcesClient.CheckNameAvailability(ctx, commonids.NewSubscriptionID(subscriptionId), availabilityRequest) if err != nil { - return fmt.Errorf("checking if the name %q was available: %+v", id.SiteName, err) + return fmt.Errorf("checking if name %q was available: %+v", id.SiteName, err) + } + + if available.Model == nil || available.Model.NameAvailable == nil { + return fmt.Errorf("") } - if !*available.NameAvailable { - return fmt.Errorf( - "the name %q used for the Logic App Standard needs to be globally unique and isn't available: %+v", - id.SiteName, - *available.Message, - ) + if !*available.Model.NameAvailable { + return fmt.Errorf("the name %q used for the Logic App Standard needs to be globally unique and isn't available: %+v", id.SiteName, pointer.From(available.Model.Message)) } - appServicePlanID := d.Get("app_service_plan_id").(string) - enabled := d.Get("enabled").(bool) - clientAffinityEnabled := d.Get("client_affinity_enabled").(bool) clientCertMode := d.Get("client_certificate_mode").(string) clientCertEnabled := clientCertMode != "" - httpsOnly := d.Get("https_only").(bool) - location := azure.NormalizeLocation(d.Get("location").(string)) - VirtualNetworkSubnetID := d.Get("virtual_network_subnet_id").(string) - t := d.Get("tags").(map[string]interface{}) basicAppSettings, err := getBasicLogicAppSettings(d, *storageAccountDomainSuffix) if err != nil { @@ -313,52 +307,46 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) siteConfig.AppSettings = &appSettings - siteEnvelope := web.Site{ + siteEnvelope := webapps.Site{ Kind: &kind, - Location: &location, - Tags: tags.Expand(t), - SiteProperties: &web.SiteProperties{ - ServerFarmID: utils.String(appServicePlanID), - Enabled: utils.Bool(enabled), - ClientAffinityEnabled: utils.Bool(clientAffinityEnabled), - ClientCertEnabled: utils.Bool(clientCertEnabled), - HTTPSOnly: utils.Bool(httpsOnly), + Location: location.Normalize(d.Get("location").(string)), + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + Properties: &webapps.SiteProperties{ + ServerFarmId: pointer.To(d.Get("app_service_plan_id").(string)), + Enabled: pointer.To(d.Get("enabled").(bool)), + ClientAffinityEnabled: pointer.To(d.Get("client_affinity_enabled").(bool)), + ClientCertEnabled: pointer.To(clientCertEnabled), + HTTPSOnly: pointer.To(d.Get("https_only").(bool)), SiteConfig: &siteConfig, }, } - if clientCertMode != "" { - siteEnvelope.SiteProperties.ClientCertMode = web.ClientCertMode(clientCertMode) + if clientCertEnabled { + siteEnvelope.Properties.ClientCertMode = pointer.To(webapps.ClientCertMode(clientCertMode)) } - if VirtualNetworkSubnetID != "" { - siteEnvelope.SiteProperties.VirtualNetworkSubnetID = utils.String(VirtualNetworkSubnetID) + if v := d.Get("virtual_network_subnet_id").(string); v != "" { + siteEnvelope.Properties.VirtualNetworkSubnetId = pointer.To(v) } if _, ok := d.GetOk("identity"); ok { - appServiceIdentity, err := expandLogicAppStandardIdentity(d.Get("identity").([]interface{})) + expandedIdentity, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) } - siteEnvelope.Identity = appServiceIdentity + siteEnvelope.Identity = expandedIdentity } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SiteName, siteEnvelope) - if err != nil { + if err := clientNew.CreateOrUpdateThenPoll(ctx, id, siteEnvelope); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } - err = future.WaitForCompletionRef(ctx, client.Client) - if err != nil { - return fmt.Errorf("waiting for the creation of %s: %+v", id, err) - } - d.SetId(id.ID()) return resourceLogicAppStandardUpdate(d, meta) } func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Web.AppServicesClient + clientNew := meta.(*clients.Client).AppService.WebAppsClient ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -368,19 +356,13 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("could not determine the domain suffix for storage accounts in environment %q: %+v", env.Name, env.Storage) } - id, err := parse.LogicAppStandardID(d.Id()) + id, err := commonids.ParseLogicAppId(d.Id()) if err != nil { return err } - location := azure.NormalizeLocation(d.Get("location").(string)) - appServicePlanID := d.Get("app_service_plan_id").(string) - enabled := d.Get("enabled").(bool) - clientAffinityEnabled := d.Get("client_affinity_enabled").(bool) clientCertMode := d.Get("client_certificate_mode").(string) clientCertEnabled := clientCertMode != "" - httpsOnly := d.Get("https_only").(bool) - t := d.Get("tags").(map[string]interface{}) basicAppSettings, err := getBasicLogicAppSettings(d, *storageAccountDomainSuffix) if err != nil { @@ -406,84 +388,79 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) } if vnetRouteAll, ok := appSettings["WEBSITE_VNET_ROUTE_ALL"]; ok { if !d.HasChange("site_config.0.vnet_route_all_enabled") { - vnetRouteAllEnabled, _ := strconv.ParseBool(*vnetRouteAll) + vnetRouteAllEnabled, _ := strconv.ParseBool(vnetRouteAll) siteConfig.VnetRouteAllEnabled = &vnetRouteAllEnabled } } - siteEnvelope := web.Site{ + siteEnvelope := webapps.Site{ Kind: &kind, - Location: &location, - Tags: tags.Expand(t), - SiteProperties: &web.SiteProperties{ - ServerFarmID: utils.String(appServicePlanID), - Enabled: utils.Bool(enabled), - ClientAffinityEnabled: utils.Bool(clientAffinityEnabled), - ClientCertEnabled: utils.Bool(clientCertEnabled), - HTTPSOnly: utils.Bool(httpsOnly), + Location: location.Normalize(d.Get("location").(string)), + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + Properties: &webapps.SiteProperties{ + ServerFarmId: pointer.To(d.Get("app_service_plan_id").(string)), + Enabled: pointer.To(d.Get("enabled").(bool)), + ClientAffinityEnabled: pointer.To(d.Get("client_affinity_enabled").(bool)), + ClientCertEnabled: pointer.To(clientCertEnabled), + HTTPSOnly: pointer.To(d.Get("https_only").(bool)), SiteConfig: &siteConfig, }, } - if clientCertMode != "" { - siteEnvelope.SiteProperties.ClientCertMode = web.ClientCertMode(clientCertMode) + if clientCertEnabled { + siteEnvelope.Properties.ClientCertMode = pointer.To(webapps.ClientCertMode(clientCertMode)) } if d.HasChange("virtual_network_subnet_id") { subnetId := d.Get("virtual_network_subnet_id").(string) if subnetId == "" { - if _, err := client.DeleteSwiftVirtualNetwork(ctx, id.ResourceGroup, id.SiteName); err != nil { + if _, err := clientNew.DeleteSwiftVirtualNetwork(ctx, *id); err != nil { return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) } var empty *string - siteEnvelope.SiteProperties.VirtualNetworkSubnetID = empty + siteEnvelope.Properties.VirtualNetworkSubnetId = empty } else { - siteEnvelope.SiteProperties.VirtualNetworkSubnetID = utils.String(subnetId) + siteEnvelope.Properties.VirtualNetworkSubnetId = pointer.To(subnetId) } } if _, ok := d.GetOk("identity"); ok { - appServiceIdentity, err := expandLogicAppStandardIdentity(d.Get("identity").([]interface{})) + expandedIdentity, err := identity.ExpandSystemAndUserAssignedMap(d.Get("identity").([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) } - siteEnvelope.Identity = appServiceIdentity + siteEnvelope.Identity = expandedIdentity } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SiteName, siteEnvelope) - if err != nil { + if err := clientNew.CreateOrUpdateThenPoll(ctx, *id, siteEnvelope); err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for the update of %s: %+v", id, err) - } - if d.HasChange("site_config") { // update siteConfig before appSettings in case the appSettings get covered by basicAppSettings - siteConfigResource := web.SiteConfigResource{ - SiteConfig: &siteConfig, + siteConfigResource := webapps.SiteConfigResource{ + Properties: &siteConfig, } - if _, err := client.CreateOrUpdateConfiguration(ctx, id.ResourceGroup, id.SiteName, siteConfigResource); err != nil { + if _, err := clientNew.CreateOrUpdateConfiguration(ctx, *id, siteConfigResource); err != nil { return fmt.Errorf("updating Configuration for %s: %+v", *id, err) } } - settings := web.StringDictionary{ - Properties: appSettings, + settings := webapps.StringDictionary{ + Properties: pointer.To(appSettings), } - if _, err = client.UpdateApplicationSettings(ctx, id.ResourceGroup, id.SiteName, settings); err != nil { + if _, err = clientNew.UpdateApplicationSettings(ctx, *id, settings); err != nil { return fmt.Errorf("updating Application Settings for %s: %+v", *id, err) } if d.HasChange("connection_string") { connectionStrings := expandLogicAppStandardConnectionStrings(d) - properties := web.ConnectionStringDictionary{ - Properties: connectionStrings, + properties := webapps.ConnectionStringDictionary{ + Properties: pointer.To(connectionStrings), } - if _, err := client.UpdateConnectionStrings(ctx, id.ResourceGroup, id.SiteName, properties); err != nil { + if _, err := clientNew.UpdateConnectionStrings(ctx, *id, properties); err != nil { return fmt.Errorf("updating Connection Strings for %s: %+v", *id, err) } } @@ -492,18 +469,18 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) } func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Web.AppServicesClient + clientNew := meta.(*clients.Client).AppService.WebAppsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.LogicAppStandardID(d.Id()) + id, err := commonids.ParseLogicAppId(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.SiteName) + resp, err := clientNew.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { log.Printf("[DEBUG] %s was not found - removing from state", *id) d.SetId("") return nil @@ -511,161 +488,159 @@ func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) e return fmt.Errorf("retrieving %s: %+v", *id, err) } - appSettingsResp, err := client.ListApplicationSettings(ctx, id.ResourceGroup, id.SiteName) - if err != nil { - return fmt.Errorf("listing application settings for %s: %+v", *id, err) - } - - connectionStringsResp, err := client.ListConnectionStrings(ctx, id.ResourceGroup, id.SiteName) - if err != nil { - return fmt.Errorf("listing connection strings for %s: %+v", *id, err) - } - - siteCredFuture, err := client.ListPublishingCredentials(ctx, id.ResourceGroup, id.SiteName) - if err != nil { - return fmt.Errorf("listing publishing credentials for %s: %+v", *id, err) - } - if err = siteCredFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting to list the publishing credentials for %s: %+v", *id, err) - } - siteCredResp, err := siteCredFuture.Result(*client) - if err != nil { - return fmt.Errorf("retrieving the publishing credentials for %s: %+v", *id, err) - } - d.Set("name", id.SiteName) - d.Set("resource_group_name", id.ResourceGroup) - d.Set("kind", resp.Kind) + d.Set("resource_group_name", id.ResourceGroupName) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } + if model := resp.Model; model != nil { + d.Set("kind", pointer.From(model.Kind)) + d.Set("location", location.Normalize(model.Location)) - if props := resp.SiteProperties; props != nil { - servicePlanId, err := commonids.ParseAppServicePlanIDInsensitively(*props.ServerFarmID) + flattenedIdentity, err := identity.FlattenSystemAndUserAssignedMap(model.Identity) if err != nil { - return err + return fmt.Errorf("flattening `identity`: %+v", err) } - d.Set("app_service_plan_id", servicePlanId.ID()) - d.Set("enabled", props.Enabled) - d.Set("default_hostname", props.DefaultHostName) - d.Set("https_only", props.HTTPSOnly) - d.Set("outbound_ip_addresses", props.OutboundIPAddresses) - d.Set("possible_outbound_ip_addresses", props.PossibleOutboundIPAddresses) - d.Set("client_affinity_enabled", props.ClientAffinityEnabled) - d.Set("custom_domain_verification_id", props.CustomDomainVerificationID) - d.Set("virtual_network_subnet_id", props.VirtualNetworkSubnetID) - - clientCertMode := "" - if props.ClientCertEnabled != nil && *props.ClientCertEnabled { - clientCertMode = string(props.ClientCertMode) + if err := d.Set("identity", flattenedIdentity); err != nil { + return fmt.Errorf("setting `identity`: %s", err) } - d.Set("client_certificate_mode", clientCertMode) - } - appSettings := flattenLogicAppStandardAppSettings(appSettingsResp.Properties) + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return fmt.Errorf("setting `tags`: %+v", err) + } - if err = d.Set("connection_string", flattenLogicAppStandardConnectionStrings(connectionStringsResp.Properties)); err != nil { - return err + if props := model.Properties; props != nil { + servicePlanId, err := commonids.ParseAppServicePlanIDInsensitively(*props.ServerFarmId) + if err != nil { + return err + } + d.Set("app_service_plan_id", servicePlanId.ID()) + d.Set("enabled", props.Enabled) + d.Set("default_hostname", props.DefaultHostName) + d.Set("https_only", props.HTTPSOnly) + d.Set("outbound_ip_addresses", props.OutboundIPAddresses) + d.Set("possible_outbound_ip_addresses", props.PossibleOutboundIPAddresses) + d.Set("client_affinity_enabled", props.ClientAffinityEnabled) + d.Set("custom_domain_verification_id", props.CustomDomainVerificationId) + d.Set("virtual_network_subnet_id", props.VirtualNetworkSubnetId) + + clientCertMode := "" + if props.ClientCertEnabled != nil && *props.ClientCertEnabled { + clientCertMode = string(pointer.From(props.ClientCertMode)) + } + d.Set("client_certificate_mode", clientCertMode) + } + + } + + appSettingsResp, err := clientNew.ListApplicationSettings(ctx, *id) + if err != nil { + return fmt.Errorf("listing application settings for %s: %+v", *id, err) } + if model := appSettingsResp.Model; model != nil { + appSettings := flattenLogicAppStandardAppSettings(model.Properties) - connectionString := appSettings["AzureWebJobsStorage"] + connectionString := appSettings["AzureWebJobsStorage"] - // This teases out the necessary attributes from the storage connection string - connectionStringParts := strings.Split(connectionString, ";") - for _, part := range connectionStringParts { - if strings.HasPrefix(part, "AccountName") { - accountNameParts := strings.Split(part, "AccountName=") - if len(accountNameParts) > 1 { - d.Set("storage_account_name", accountNameParts[1]) + // This teases out the necessary attributes from the storage connection string + connectionStringParts := strings.Split(connectionString, ";") + for _, part := range connectionStringParts { + if strings.HasPrefix(part, "AccountName") { + accountNameParts := strings.Split(part, "AccountName=") + if len(accountNameParts) > 1 { + d.Set("storage_account_name", accountNameParts[1]) + } } - } - if strings.HasPrefix(part, "AccountKey") { - accountKeyParts := strings.Split(part, "AccountKey=") - if len(accountKeyParts) > 1 { - d.Set("storage_account_access_key", accountKeyParts[1]) + if strings.HasPrefix(part, "AccountKey") { + accountKeyParts := strings.Split(part, "AccountKey=") + if len(accountKeyParts) > 1 { + d.Set("storage_account_access_key", accountKeyParts[1]) + } } } - } - d.Set("version", appSettings["FUNCTIONS_EXTENSION_VERSION"]) + d.Set("version", appSettings["FUNCTIONS_EXTENSION_VERSION"]) - if _, ok := appSettings["AzureFunctionsJobHost__extensionBundle__id"]; ok { - d.Set("use_extension_bundle", true) - if val, ok := appSettings["AzureFunctionsJobHost__extensionBundle__version"]; ok { - d.Set("bundle_version", val) + if _, ok := appSettings["AzureFunctionsJobHost__extensionBundle__id"]; ok { + d.Set("use_extension_bundle", true) + if val, ok := appSettings["AzureFunctionsJobHost__extensionBundle__version"]; ok { + d.Set("bundle_version", val) + } + } else { + d.Set("use_extension_bundle", false) + d.Set("bundle_version", "[1.*, 2.0.0)") } - } else { - d.Set("use_extension_bundle", false) - d.Set("bundle_version", "[1.*, 2.0.0)") - } - d.Set("storage_account_share_name", appSettings["WEBSITE_CONTENTSHARE"]) + d.Set("storage_account_share_name", appSettings["WEBSITE_CONTENTSHARE"]) - // Remove all the settings that are created by this resource so we don't to have to specify in app_settings - // block whenever we use azurerm_logic_app_standard. - delete(appSettings, "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING") - delete(appSettings, "APP_KIND") - delete(appSettings, "AzureFunctionsJobHost__extensionBundle__id") - delete(appSettings, "AzureFunctionsJobHost__extensionBundle__version") - delete(appSettings, "AzureWebJobsDashboard") - delete(appSettings, "AzureWebJobsStorage") - delete(appSettings, "FUNCTIONS_EXTENSION_VERSION") - delete(appSettings, "WEBSITE_CONTENTSHARE") + // Remove all the settings that are created by this resource so we don't to have to specify in app_settings + // block whenever we use azurerm_logic_app_standard. + delete(appSettings, "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING") + delete(appSettings, "APP_KIND") + delete(appSettings, "AzureFunctionsJobHost__extensionBundle__id") + delete(appSettings, "AzureFunctionsJobHost__extensionBundle__version") + delete(appSettings, "AzureWebJobsDashboard") + delete(appSettings, "AzureWebJobsStorage") + delete(appSettings, "FUNCTIONS_EXTENSION_VERSION") + delete(appSettings, "WEBSITE_CONTENTSHARE") - if err = d.Set("app_settings", appSettings); err != nil { - return err + if err = d.Set("app_settings", appSettings); err != nil { + return err + } } - identity, err := flattenLogicAppStandardIdentity(resp.Identity) + connectionStringsResp, err := clientNew.ListConnectionStrings(ctx, *id) if err != nil { - return fmt.Errorf("flattening `identity`: %+v", err) + return fmt.Errorf("listing connection strings for %s: %+v", *id, err) } - if err := d.Set("identity", identity); err != nil { - return fmt.Errorf("setting `identity`: %s", err) + if model := connectionStringsResp.Model; model != nil { + if err = d.Set("connection_string", flattenLogicAppStandardConnectionStrings(model.Properties)); err != nil { + return err + } } - configResp, err := client.GetConfiguration(ctx, id.ResourceGroup, id.SiteName) + siteCredentials, err := helpers.ListPublishingCredentials(ctx, clientNew, *id) if err != nil { - return fmt.Errorf("retrieving the configuration for %s: %+v", *id, err) + return fmt.Errorf("listing publishing credentials for %s: %+v", *id, err) } - - siteConfig := flattenLogicAppStandardSiteConfig(configResp.SiteConfig) - if err = d.Set("site_config", siteConfig); err != nil { + if err = d.Set("site_credential", flattenLogicAppStandardSiteCredential(siteCredentials)); err != nil { return err } - siteCred := flattenLogicAppStandardSiteCredential(siteCredResp.UserProperties) - if err = d.Set("site_credential", siteCred); err != nil { - return err + configResp, err := clientNew.GetConfiguration(ctx, *id) + if err != nil { + return fmt.Errorf("retrieving the configuration for %s: %+v", *id, err) + } + if model := configResp.Model; model != nil { + siteConfig := flattenLogicAppStandardSiteConfig(model.Properties) + if err = d.Set("site_config", siteConfig); err != nil { + return err + } } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourceLogicAppStandardDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).Web.AppServicesClient + clientNew := meta.(*clients.Client).AppService.WebAppsClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.LogicAppStandardID(d.Id()) + id, err := commonids.ParseLogicAppId(d.Id()) if err != nil { return err } - deleteMetrics := true - deleteEmptyServerFarm := false - if _, err := client.Delete(ctx, id.ResourceGroup, id.SiteName, &deleteMetrics, &deleteEmptyServerFarm); err != nil { + opts := webapps.DefaultDeleteOperationOptions() + opts.DeleteMetrics = pointer.To(true) + opts.DeleteEmptyServerFarm = pointer.To(false) + + if _, err := clientNew.Delete(ctx, *id, opts); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } return nil } -func getBasicLogicAppSettings( - d *pluginsdk.ResourceData, - endpointSuffix string, -) ([]web.NameValuePair, error) { +func getBasicLogicAppSettings(d *pluginsdk.ResourceData, endpointSuffix string) ([]webapps.NameValuePair, error) { storagePropName := "AzureWebJobsStorage" functionVersionPropName := "FUNCTIONS_EXTENSION_VERSION" contentSharePropName := "WEBSITE_CONTENTSHARE" @@ -688,7 +663,7 @@ func getBasicLogicAppSettings( contentShare = d.Get("storage_account_share_name").(string) } - basicSettings := []web.NameValuePair{ + basicSettings := []webapps.NameValuePair{ {Name: &storagePropName, Value: &storageConnection}, {Name: &functionVersionPropName, Value: &functionVersion}, {Name: &appKindPropName, Value: &appKindPropValue}, @@ -709,7 +684,7 @@ func getBasicLogicAppSettings( ) } - bundleSettings := []web.NameValuePair{ + bundleSettings := []webapps.NameValuePair{ {Name: &extensionBundlePropName, Value: &extensionBundleName}, {Name: &extensionBundleVersionPropName, Value: &extensionBundleVersion}, } @@ -741,9 +716,9 @@ func schemaLogicAppStandardSiteConfig() *pluginsdk.Schema { Optional: true, Computed: true, ValidateFunc: validation.StringInSlice([]string{ - string(web.FtpsStateAllAllowed), - string(web.FtpsStateDisabled), - string(web.FtpsStateFtpsOnly), + string(webapps.FtpsStateAllAllowed), + string(webapps.FtpsStateDisabled), + string(webapps.FtpsStateFtpsOnly), }, false), }, @@ -766,9 +741,9 @@ func schemaLogicAppStandardSiteConfig() *pluginsdk.Schema { Optional: true, Computed: true, ValidateFunc: validation.StringInSlice([]string{ - string(web.SupportedTLSVersionsOneFullStopZero), - string(web.SupportedTLSVersionsOneFullStopOne), - string(web.SupportedTLSVersionsOneFullStopTwo), + string(webapps.SupportedTlsVersionsOnePointZero), + string(webapps.SupportedTlsVersionsOnePointOne), + string(webapps.SupportedTlsVersionsOnePointTwo), }, false), }, @@ -792,9 +767,9 @@ func schemaLogicAppStandardSiteConfig() *pluginsdk.Schema { Optional: true, Computed: true, ValidateFunc: validation.StringInSlice([]string{ - string(web.SupportedTLSVersionsOneFullStopZero), - string(web.SupportedTLSVersionsOneFullStopOne), - string(web.SupportedTLSVersionsOneFullStopTwo), + string(webapps.SupportedTlsVersionsOnePointZero), + string(webapps.SupportedTlsVersionsOnePointOne), + string(webapps.SupportedTlsVersionsOnePointTwo), }, false), }, @@ -803,20 +778,20 @@ func schemaLogicAppStandardSiteConfig() *pluginsdk.Schema { Optional: true, Computed: true, ValidateFunc: validation.StringInSlice([]string{ - string(web.ScmTypeBitbucketGit), - string(web.ScmTypeBitbucketHg), - string(web.ScmTypeCodePlexGit), - string(web.ScmTypeCodePlexHg), - string(web.ScmTypeDropbox), - string(web.ScmTypeExternalGit), - string(web.ScmTypeExternalHg), - string(web.ScmTypeGitHub), - string(web.ScmTypeLocalGit), - string(web.ScmTypeNone), - string(web.ScmTypeOneDrive), - string(web.ScmTypeTfs), - string(web.ScmTypeVSO), - string(web.ScmTypeVSTSRM), + string(webapps.ScmTypeBitbucketGit), + string(webapps.ScmTypeBitbucketHg), + string(webapps.ScmTypeCodePlexGit), + string(webapps.ScmTypeCodePlexHg), + string(webapps.ScmTypeDropbox), + string(webapps.ScmTypeExternalGit), + string(webapps.ScmTypeExternalHg), + string(webapps.ScmTypeGitHub), + string(webapps.ScmTypeLocalGit), + string(webapps.ScmTypeNone), + string(webapps.ScmTypeOneDrive), + string(webapps.ScmTypeTfs), + string(webapps.ScmTypeVSO), + string(webapps.ScmTypeVSTSRM), }, false), }, @@ -1024,32 +999,38 @@ func schemaLogicAppStandardIpRestriction() *pluginsdk.Schema { } } -func flattenLogicAppStandardAppSettings(input map[string]*string) map[string]string { +func flattenLogicAppStandardAppSettings(input *map[string]string) map[string]string { output := make(map[string]string) - for k, v := range input { - output[k] = *v + if input == nil || len(*input) == 0 { + return output + } + + for k, v := range *input { + output[k] = v } return output } -func flattenLogicAppStandardConnectionStrings( - input map[string]*web.ConnStringValueTypePair, -) interface{} { +func flattenLogicAppStandardConnectionStrings(input *map[string]webapps.ConnStringValueTypePair) interface{} { results := make([]interface{}, 0) - for k, v := range input { + if input == nil || len(*input) == 0 { + return results + } + + for k, v := range *input { result := make(map[string]interface{}) result["name"] = k result["type"] = string(v.Type) - result["value"] = *v.Value + result["value"] = v.Value results = append(results, result) } return results } -func flattenLogicAppStandardSiteConfig(input *web.SiteConfig) []interface{} { +func flattenLogicAppStandardSiteConfig(input *webapps.SiteConfig) []interface{} { results := make([]interface{}, 0) result := make(map[string]interface{}) @@ -1058,75 +1039,40 @@ func flattenLogicAppStandardSiteConfig(input *web.SiteConfig) []interface{} { return results } - if input.AlwaysOn != nil { - result["always_on"] = *input.AlwaysOn - } - - if input.Use32BitWorkerProcess != nil { - result["use_32_bit_worker_process"] = *input.Use32BitWorkerProcess - } - - if input.WebSocketsEnabled != nil { - result["websockets_enabled"] = *input.WebSocketsEnabled - } - - if input.LinuxFxVersion != nil { - result["linux_fx_version"] = *input.LinuxFxVersion - } - - if input.HTTP20Enabled != nil { - result["http2_enabled"] = *input.HTTP20Enabled - } - - if input.PreWarmedInstanceCount != nil { - result["pre_warmed_instance_count"] = *input.PreWarmedInstanceCount - } + result["always_on"] = pointer.From(input.AlwaysOn) + result["use_32_bit_worker_process"] = pointer.From(input.Use32BitWorkerProcess) + result["websockets_enabled"] = pointer.From(input.WebSocketsEnabled) + result["linux_fx_version"] = pointer.From(input.LinuxFxVersion) + result["http2_enabled"] = pointer.From(input.HTTP20Enabled) + result["pre_warmed_instance_count"] = pointer.From(input.PreWarmedInstanceCount) result["ip_restriction"] = flattenLogicAppStandardIpRestriction(input.IPSecurityRestrictions) result["scm_ip_restriction"] = flattenLogicAppStandardIpRestriction(input.ScmIPSecurityRestrictions) - if input.ScmIPSecurityRestrictionsUseMain != nil { - result["scm_use_main_ip_restriction"] = *input.ScmIPSecurityRestrictionsUseMain - } + result["scm_use_main_ip_restriction"] = pointer.From(input.ScmIPSecurityRestrictionsUseMain) - result["scm_type"] = string(input.ScmType) - result["scm_min_tls_version"] = string(input.ScmMinTLSVersion) + result["scm_type"] = string(pointer.From(input.ScmType)) + result["scm_min_tls_version"] = string(pointer.From(input.ScmMinTlsVersion)) - result["min_tls_version"] = string(input.MinTLSVersion) - result["ftps_state"] = string(input.FtpsState) + result["min_tls_version"] = string(pointer.From(input.MinTlsVersion)) + result["ftps_state"] = string(pointer.From(input.FtpsState)) result["cors"] = flattenLogicAppStandardCorsSettings(input.Cors) - if input.AutoSwapSlotName != nil { - result["auto_swap_slot_name"] = *input.AutoSwapSlotName - } + result["auto_swap_slot_name"] = pointer.From(input.AutoSwapSlotName) - if input.HealthCheckPath != nil { - result["health_check_path"] = *input.HealthCheckPath - } + result["health_check_path"] = pointer.From(input.HealthCheckPath) - if input.MinimumElasticInstanceCount != nil { - result["elastic_instance_minimum"] = *input.MinimumElasticInstanceCount - } + result["elastic_instance_minimum"] = pointer.From(input.MinimumElasticInstanceCount) - if input.FunctionAppScaleLimit != nil { - result["app_scale_limit"] = *input.FunctionAppScaleLimit - } + result["app_scale_limit"] = pointer.From(input.FunctionAppScaleLimit) - if input.FunctionsRuntimeScaleMonitoringEnabled != nil { - result["runtime_scale_monitoring_enabled"] = *input.FunctionsRuntimeScaleMonitoringEnabled - } + result["runtime_scale_monitoring_enabled"] = pointer.From(input.FunctionsRuntimeScaleMonitoringEnabled) - if input.NetFrameworkVersion != nil { - result["dotnet_framework_version"] = *input.NetFrameworkVersion - } + result["dotnet_framework_version"] = pointer.From(input.NetFrameworkVersion) - vnetRouteAllEnabled := false - if input.VnetRouteAllEnabled != nil { - vnetRouteAllEnabled = *input.VnetRouteAllEnabled - } - result["vnet_route_all_enabled"] = vnetRouteAllEnabled + result["vnet_route_all_enabled"] = pointer.From(input.VnetRouteAllEnabled) publicNetworkAccessEnabled := true if input.PublicNetworkAccess != nil { @@ -1138,27 +1084,23 @@ func flattenLogicAppStandardSiteConfig(input *web.SiteConfig) []interface{} { return results } -func flattenLogicAppStandardSiteCredential(input *web.UserProperties) []interface{} { +func flattenLogicAppStandardSiteCredential(input *webapps.User) []interface{} { results := make([]interface{}, 0) result := make(map[string]interface{}) - if input == nil { + if input == nil || input.Properties == nil { log.Printf("[DEBUG] UserProperties is nil") return results } - if input.PublishingUserName != nil { - result["username"] = *input.PublishingUserName - } + result["username"] = input.Properties.PublishingUserName - if input.PublishingPassword != nil { - result["password"] = *input.PublishingPassword - } + result["password"] = pointer.From(input.Properties.PublishingPassword) return append(results, result) } -func flattenLogicAppStandardIpRestriction(input *[]web.IPSecurityRestriction) []interface{} { +func flattenLogicAppStandardIpRestriction(input *[]webapps.IPSecurityRestriction) []interface{} { restrictions := make([]interface{}, 0) if input == nil { @@ -1171,8 +1113,8 @@ func flattenLogicAppStandardIpRestriction(input *[]web.IPSecurityRestriction) [] if *ip == "Any" { continue } else { - switch v.Tag { - case web.IPFilterTagServiceTag: + switch pointer.From(v.Tag) { + case webapps.IPFilterTagServiceTag: restriction["service_tag"] = *ip default: restriction["ip_address"] = *ip @@ -1181,7 +1123,7 @@ func flattenLogicAppStandardIpRestriction(input *[]web.IPSecurityRestriction) [] } subnetId := "" - if subnetIdRaw := v.VnetSubnetResourceID; subnetIdRaw != nil { + if subnetIdRaw := v.VnetSubnetResourceId; subnetIdRaw != nil { subnetId = *subnetIdRaw } restriction["virtual_network_subnet_id"] = subnetId @@ -1205,7 +1147,7 @@ func flattenLogicAppStandardIpRestriction(input *[]web.IPSecurityRestriction) [] restriction["action"] = action if headers := v.Headers; headers != nil { - restriction["headers"] = flattenHeaders(headers) + restriction["headers"] = flattenHeaders(*headers) } restrictions = append(restrictions, restriction) @@ -1214,7 +1156,7 @@ func flattenLogicAppStandardIpRestriction(input *[]web.IPSecurityRestriction) [] return restrictions } -func flattenLogicAppStandardCorsSettings(input *web.CorsSettings) []interface{} { +func flattenLogicAppStandardCorsSettings(input *webapps.CorsSettings) []interface{} { results := make([]interface{}, 0) if input == nil { return results @@ -1260,9 +1202,9 @@ func flattenHeaders(input map[string][]string) []interface{} { return append(output, headers) } -func expandLogicAppStandardSiteConfig(d *pluginsdk.ResourceData) (web.SiteConfig, error) { +func expandLogicAppStandardSiteConfig(d *pluginsdk.ResourceData) (webapps.SiteConfig, error) { configs := d.Get("site_config").([]interface{}) - siteConfig := web.SiteConfig{} + siteConfig := webapps.SiteConfig{} if len(configs) == 0 { return siteConfig, nil @@ -1271,19 +1213,19 @@ func expandLogicAppStandardSiteConfig(d *pluginsdk.ResourceData) (web.SiteConfig config := configs[0].(map[string]interface{}) if v, ok := config["always_on"]; ok { - siteConfig.AlwaysOn = utils.Bool(v.(bool)) + siteConfig.AlwaysOn = pointer.To(v.(bool)) } if v, ok := config["use_32_bit_worker_process"]; ok { - siteConfig.Use32BitWorkerProcess = utils.Bool(v.(bool)) + siteConfig.Use32BitWorkerProcess = pointer.To(v.(bool)) } if v, ok := config["websockets_enabled"]; ok { - siteConfig.WebSocketsEnabled = utils.Bool(v.(bool)) + siteConfig.WebSocketsEnabled = pointer.To(v.(bool)) } if v, ok := config["linux_fx_version"]; ok { - siteConfig.LinuxFxVersion = utils.String(v.(string)) + siteConfig.LinuxFxVersion = pointer.To(v.(string)) } if v, ok := config["cors"]; ok { @@ -1292,7 +1234,7 @@ func expandLogicAppStandardSiteConfig(d *pluginsdk.ResourceData) (web.SiteConfig } if v, ok := config["http2_enabled"]; ok { - siteConfig.HTTP20Enabled = utils.Bool(v.(bool)) + siteConfig.HTTP20Enabled = pointer.To(v.(bool)) } if v, ok := config["ip_restriction"]; ok { @@ -1313,52 +1255,52 @@ func expandLogicAppStandardSiteConfig(d *pluginsdk.ResourceData) (web.SiteConfig } if v, ok := config["scm_use_main_ip_restriction"]; ok { - siteConfig.ScmIPSecurityRestrictionsUseMain = utils.Bool(v.(bool)) + siteConfig.ScmIPSecurityRestrictionsUseMain = pointer.To(v.(bool)) } if v, ok := config["scm_min_tls_version"]; ok { - siteConfig.ScmMinTLSVersion = web.SupportedTLSVersions(v.(string)) + siteConfig.ScmMinTlsVersion = pointer.To(webapps.SupportedTlsVersions(v.(string))) } if v, ok := config["scm_type"]; ok { - siteConfig.ScmType = web.ScmType(v.(string)) + siteConfig.ScmType = pointer.To(webapps.ScmType(v.(string))) } if v, ok := config["min_tls_version"]; ok { - siteConfig.MinTLSVersion = web.SupportedTLSVersions(v.(string)) + siteConfig.MinTlsVersion = pointer.To(webapps.SupportedTlsVersions(v.(string))) } if v, ok := config["ftps_state"]; ok { - siteConfig.FtpsState = web.FtpsState(v.(string)) + siteConfig.FtpsState = pointer.To(webapps.FtpsState(v.(string))) } // get value from `d` rather than the `config` map, or it will be covered by the zero-value "0" instead of nil. if v, ok := d.GetOk("site_config.0.pre_warmed_instance_count"); ok { - siteConfig.PreWarmedInstanceCount = utils.Int32(int32(v.(int))) + siteConfig.PreWarmedInstanceCount = pointer.To(int64(v.(int))) } if v, ok := config["health_check_path"]; ok { - siteConfig.HealthCheckPath = utils.String(v.(string)) + siteConfig.HealthCheckPath = pointer.To(v.(string)) } if v, ok := d.GetOk("site_config.0.elastic_instance_minimum"); ok { - siteConfig.MinimumElasticInstanceCount = utils.Int32(int32(v.(int))) + siteConfig.MinimumElasticInstanceCount = pointer.To(int64(v.(int))) } if v, ok := d.GetOk("site_config.0.app_scale_limit"); ok { - siteConfig.FunctionAppScaleLimit = utils.Int32(int32(v.(int))) + siteConfig.FunctionAppScaleLimit = pointer.To(int64(v.(int))) } if v, ok := config["runtime_scale_monitoring_enabled"]; ok { - siteConfig.FunctionsRuntimeScaleMonitoringEnabled = utils.Bool(v.(bool)) + siteConfig.FunctionsRuntimeScaleMonitoringEnabled = pointer.To(v.(bool)) } if v, ok := config["dotnet_framework_version"]; ok { - siteConfig.NetFrameworkVersion = utils.String(v.(string)) + siteConfig.NetFrameworkVersion = pointer.To(v.(string)) } if v, ok := config["vnet_route_all_enabled"]; ok { - siteConfig.VnetRouteAllEnabled = utils.Bool(v.(bool)) + siteConfig.VnetRouteAllEnabled = pointer.To(v.(bool)) } if v, ok := config["public_network_access_enabled"]; ok { @@ -1372,96 +1314,28 @@ func expandLogicAppStandardSiteConfig(d *pluginsdk.ResourceData) (web.SiteConfig return siteConfig, nil } -func expandLogicAppStandardIdentity(input []interface{}) (*web.ManagedServiceIdentity, error) { - expanded, err := identity.ExpandSystemAndUserAssignedMap(input) - if err != nil { - return nil, err - } - - output := web.ManagedServiceIdentity{ - Type: web.ManagedServiceIdentityType(expanded.Type), - } - - if expanded.Type == identity.TypeUserAssigned || expanded.Type == identity.TypeSystemAssignedUserAssigned { - output.UserAssignedIdentities = expandLogicAppStandardUserAssignedIdentity(expanded.IdentityIds) - } - - return &output, nil -} - -func expandLogicAppStandardUserAssignedIdentity(input map[string]identity.UserAssignedIdentityDetails) map[string]*web.UserAssignedIdentity { - output := make(map[string]*web.UserAssignedIdentity) - for k := range input { - output[k] = &web.UserAssignedIdentity{} - } - return output -} - -func flattenLogicAppStandardIdentity(input *web.ManagedServiceIdentity) ([]interface{}, error) { - var transform *identity.SystemAndUserAssignedMap - - if input != nil { - transform = &identity.SystemAndUserAssignedMap{ - Type: identity.Type(string(input.Type)), - } - if input.PrincipalID != nil { - transform.PrincipalId = *input.PrincipalID - } - if input.TenantID != nil { - transform.TenantId = *input.TenantID - } - if input.UserAssignedIdentities != nil { - transform.IdentityIds = flattenLogicAppStandardUserAssignedIdentity(input.UserAssignedIdentities) - } - } - - output, err := identity.FlattenSystemAndUserAssignedMap(transform) - if err != nil { - return nil, err - } - return *output, nil -} - -func flattenLogicAppStandardUserAssignedIdentity(input map[string]*web.UserAssignedIdentity) map[string]identity.UserAssignedIdentityDetails { - expanded := make(map[string]identity.UserAssignedIdentityDetails) - for k, v := range input { - identityDetail := identity.UserAssignedIdentityDetails{} - if v.PrincipalID != nil { - identityDetail.PrincipalId = v.PrincipalID - } - if v.ClientID != nil { - identityDetail.ClientId = v.ClientID - } - expanded[k] = identityDetail - } - return expanded -} - -func expandLogicAppStandardSettings( - d *pluginsdk.ResourceData, - endpointSuffix string, -) (map[string]*string, error) { - output := make(map[string]*string) +func expandLogicAppStandardSettings(d *pluginsdk.ResourceData, endpointSuffix string) (map[string]string, error) { + output := make(map[string]string) appSettings := expandAppSettings(d) basicAppSettings, err := getBasicLogicAppSettings(d, endpointSuffix) if err != nil { return nil, err } for _, p := range append(basicAppSettings, appSettings...) { - output[*p.Name] = p.Value + output[*p.Name] = pointer.From(p.Value) } return output, nil } -func expandAppSettings(d *pluginsdk.ResourceData) []web.NameValuePair { +func expandAppSettings(d *pluginsdk.ResourceData) []webapps.NameValuePair { input := d.Get("app_settings").(map[string]interface{}) - output := make([]web.NameValuePair, 0) + output := make([]webapps.NameValuePair, 0) for k, v := range input { - nameValue := web.NameValuePair{ - Name: utils.String(k), - Value: utils.String(v.(string)), + nameValue := webapps.NameValuePair{ + Name: pointer.To(k), + Value: pointer.To(v.(string)), } output = append(output, nameValue) } @@ -1469,11 +1343,9 @@ func expandAppSettings(d *pluginsdk.ResourceData) []web.NameValuePair { return output } -func expandLogicAppStandardConnectionStrings( - d *pluginsdk.ResourceData, -) map[string]*web.ConnStringValueTypePair { +func expandLogicAppStandardConnectionStrings(d *pluginsdk.ResourceData) map[string]webapps.ConnStringValueTypePair { input := d.Get("connection_string").(*pluginsdk.Set).List() - output := make(map[string]*web.ConnStringValueTypePair, len(input)) + output := make(map[string]webapps.ConnStringValueTypePair, len(input)) for _, v := range input { vals := v.(map[string]interface{}) @@ -1482,18 +1354,18 @@ func expandLogicAppStandardConnectionStrings( csType := vals["type"].(string) csValue := vals["value"].(string) - output[csName] = &web.ConnStringValueTypePair{ - Value: utils.String(csValue), - Type: web.ConnectionStringType(csType), + output[csName] = webapps.ConnStringValueTypePair{ + Value: csValue, + Type: webapps.ConnectionStringType(csType), } } return output } -func expandLogicAppStandardCorsSettings(input interface{}) web.CorsSettings { +func expandLogicAppStandardCorsSettings(input interface{}) webapps.CorsSettings { settings := input.([]interface{}) - corsSettings := web.CorsSettings{} + corsSettings := webapps.CorsSettings{} if len(settings) == 0 { return corsSettings @@ -1513,14 +1385,14 @@ func expandLogicAppStandardCorsSettings(input interface{}) web.CorsSettings { } if v, ok := setting["support_credentials"]; ok { - corsSettings.SupportCredentials = utils.Bool(v.(bool)) + corsSettings.SupportCredentials = pointer.To(v.(bool)) } return corsSettings } -func expandLogicAppStandardIpRestriction(input interface{}) ([]web.IPSecurityRestriction, error) { - restrictions := make([]web.IPSecurityRestriction, 0) +func expandLogicAppStandardIpRestriction(input interface{}) ([]webapps.IPSecurityRestriction, error) { + restrictions := make([]webapps.IPSecurityRestriction, 0) for _, r := range input.([]interface{}) { if r == nil { @@ -1554,7 +1426,7 @@ func expandLogicAppStandardIpRestriction(input interface{}) ([]web.IPSecurityRes ) } - ipSecurityRestriction := web.IPSecurityRestriction{} + ipSecurityRestriction := webapps.IPSecurityRestriction{} if ipAddress == "Any" { continue } @@ -1565,11 +1437,11 @@ func expandLogicAppStandardIpRestriction(input interface{}) ([]web.IPSecurityRes if serviceTag != "" { ipSecurityRestriction.IPAddress = &serviceTag - ipSecurityRestriction.Tag = web.IPFilterTagServiceTag + ipSecurityRestriction.Tag = pointer.To(webapps.IPFilterTagServiceTag) } if vNetSubnetID != "" { - ipSecurityRestriction.VnetSubnetResourceID = &vNetSubnetID + ipSecurityRestriction.VnetSubnetResourceId = &vNetSubnetID } if name != "" { @@ -1577,14 +1449,14 @@ func expandLogicAppStandardIpRestriction(input interface{}) ([]web.IPSecurityRes } if priority != 0 { - ipSecurityRestriction.Priority = utils.Int32(int32(priority)) + ipSecurityRestriction.Priority = pointer.To(int64(priority)) } if action != "" { ipSecurityRestriction.Action = &action } if headers, ok := restriction["headers"]; ok { - ipSecurityRestriction.Headers = expandHeaders(headers.([]interface{})) + ipSecurityRestriction.Headers = pointer.To(expandHeaders(headers.([]interface{}))) } restrictions = append(restrictions, ipSecurityRestriction) diff --git a/internal/services/logic/logic_app_standard_resource_test.go b/internal/services/logic/logic_app_standard_resource_test.go index 5c0dd46fc59f..d7d44aff34a9 100644 --- a/internal/services/logic/logic_app_standard_resource_test.go +++ b/internal/services/logic/logic_app_standard_resource_test.go @@ -9,12 +9,13 @@ import ( "strings" "testing" + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) type LogicAppStandardResource struct{} @@ -35,7 +36,7 @@ func TestAccLogicAppStandard_basic(t *testing.T) { check.That(data.ResourceName).Key("custom_domain_verification_id").Exists(), ), }, - data.ImportStep(), + data.ImportStep("site_credential"), }) } @@ -946,25 +947,17 @@ func TestAccLogicAppStandard_publicNetworkAccessEnabled(t *testing.T) { } func (r LogicAppStandardResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.LogicAppStandardID(state.ID) + id, err := commonids.ParseLogicAppId(state.ID) if err != nil { return nil, err } - resp, err := clients.Web.AppServicesClient.Get(ctx, id.ResourceGroup, id.SiteName) + resp, err := clients.AppService.WebAppsClient.Get(ctx, *id) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return utils.Bool(false), nil - } - return nil, fmt.Errorf("retrieving Function App %q (Resource Group %q): %+v", id.SiteName, id.ResourceGroup, err) - } - - // The SDK defines 404 as an "ok" status code.. - if utils.ResponseWasNotFound(resp.Response) { - return utils.Bool(false), nil + return nil, fmt.Errorf("retrieving %s: %+v", id, err) } - return utils.Bool(true), nil + return pointer.To(resp.Model != nil), nil } func (r LogicAppStandardResource) hasExtensionBundleAppSetting(shouldExist bool) func(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) error { From 95b77630b4c8c97959474d8060bf46b3a2a5760e Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 6 Nov 2024 11:11:17 +0100 Subject: [PATCH 2/8] add public_network_access --- .../logic/logic_app_standard_data_source.go | 22 +++-- .../logic/logic_app_standard_resource.go | 84 +++++++++++-------- .../logic/logic_app_standard_resource_test.go | 43 +++++++++- 3 files changed, 104 insertions(+), 45 deletions(-) diff --git a/internal/services/logic/logic_app_standard_data_source.go b/internal/services/logic/logic_app_standard_data_source.go index 3d87d9865437..070fd80672d9 100644 --- a/internal/services/logic/logic_app_standard_data_source.go +++ b/internal/services/logic/logic_app_standard_data_source.go @@ -161,6 +161,11 @@ func dataSourceLogicAppStandard() *pluginsdk.Resource { Computed: true, }, + "public_network_access": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "virtual_network_subnet_id": { Type: pluginsdk.TypeString, Computed: true, @@ -224,13 +229,14 @@ func dataSourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) if props := model.Properties; props != nil { d.Set("app_service_plan_id", pointer.From(props.ServerFarmId)) - d.Set("enabled", props.Enabled) - d.Set("default_hostname", props.DefaultHostName) - d.Set("https_only", props.HTTPSOnly) - d.Set("outbound_ip_addresses", props.OutboundIPAddresses) - d.Set("possible_outbound_ip_addresses", props.PossibleOutboundIPAddresses) - d.Set("client_affinity_enabled", props.ClientAffinityEnabled) - d.Set("custom_domain_verification_id", props.CustomDomainVerificationId) + d.Set("enabled", pointer.From(props.Enabled)) + d.Set("default_hostname", pointer.From(props.DefaultHostName)) + d.Set("https_only", pointer.From(props.HTTPSOnly)) + d.Set("outbound_ip_addresses", pointer.From(props.OutboundIPAddresses)) + d.Set("possible_outbound_ip_addresses", pointer.From(props.PossibleOutboundIPAddresses)) + d.Set("client_affinity_enabled", pointer.From(props.ClientAffinityEnabled)) + d.Set("custom_domain_verification_id", pointer.From(props.CustomDomainVerificationId)) + d.Set("public_network_access", pointer.From(props.PublicNetworkAccess)) clientCertMode := "" if props.ClientCertEnabled != nil && *props.ClientCertEnabled { @@ -302,6 +308,7 @@ func dataSourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("listing connection strings for %s: %+v", id, err) } + if model := connectionStringsResp.Model; model != nil { if err = d.Set("connection_string", flattenLogicAppStandardDataSourceConnectionStrings(model.Properties)); err != nil { return err @@ -312,6 +319,7 @@ func dataSourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("retrieving the configuration for %s: %+v", id, err) } + if model := configResp.Model; model != nil { siteConfig := flattenLogicAppStandardDataSourceSiteConfig(model.Properties) if err = d.Set("site_config", siteConfig); err != nil { diff --git a/internal/services/logic/logic_app_standard_resource.go b/internal/services/logic/logic_app_standard_resource.go index 2d078cac9174..8e5385184605 100644 --- a/internal/services/logic/logic_app_standard_resource.go +++ b/internal/services/logic/logic_app_standard_resource.go @@ -22,7 +22,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/validate" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" @@ -38,7 +37,7 @@ func resourceLogicAppStandard() *pluginsdk.Resource { Update: resourceLogicAppStandardUpdate, Delete: resourceLogicAppStandardDelete, Importer: pluginsdk.ImporterValidatingResourceId(func(id string) error { - _, err := parse.LogicAppStandardID(id) + _, err := commonids.ParseLogicAppId(id) return err }), @@ -170,6 +169,17 @@ func resourceLogicAppStandard() *pluginsdk.Resource { ValidateFunc: validation.NoZeroValues, }, + "public_network_access": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + Default: helpers.PublicNetworkAccessEnabled, + ValidateFunc: validation.StringInSlice([]string{ + helpers.PublicNetworkAccessEnabled, + helpers.PublicNetworkAccessDisabled, + }, false), + }, + "storage_account_share_name": { Type: pluginsdk.TypeString, Optional: true, @@ -182,6 +192,12 @@ func resourceLogicAppStandard() *pluginsdk.Resource { Default: "~4", }, + "virtual_network_subnet_id": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: commonids.ValidateSubnetID, + }, + "tags": commonschema.Tags(), // Computed Only @@ -227,18 +243,12 @@ func resourceLogicAppStandard() *pluginsdk.Resource { }, }, }, - - "virtual_network_subnet_id": { - Type: pluginsdk.TypeString, - Optional: true, - ValidateFunc: commonids.ValidateSubnetID, - }, }, } } func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) error { - clientNew := meta.(*clients.Client).AppService.WebAppsClient + client := meta.(*clients.Client).AppService.WebAppsClient subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -254,7 +264,7 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) log.Printf("[INFO] preparing arguments for AzureRM Logic App Standard creation.") id := commonids.NewAppServiceID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - existing, err := clientNew.Get(ctx, id) + existing, err := client.Get(ctx, id) if err != nil { if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) @@ -317,6 +327,7 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) ClientAffinityEnabled: pointer.To(d.Get("client_affinity_enabled").(bool)), ClientCertEnabled: pointer.To(clientCertEnabled), HTTPSOnly: pointer.To(d.Get("https_only").(bool)), + PublicNetworkAccess: pointer.To(d.Get("public_network_access").(string)), SiteConfig: &siteConfig, }, } @@ -337,7 +348,7 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) siteEnvelope.Identity = expandedIdentity } - if err := clientNew.CreateOrUpdateThenPoll(ctx, id, siteEnvelope); err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, id, siteEnvelope); err != nil { return fmt.Errorf("creating %s: %+v", id, err) } @@ -346,7 +357,7 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) } func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - clientNew := meta.(*clients.Client).AppService.WebAppsClient + client := meta.(*clients.Client).AppService.WebAppsClient ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -403,6 +414,7 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) ClientAffinityEnabled: pointer.To(d.Get("client_affinity_enabled").(bool)), ClientCertEnabled: pointer.To(clientCertEnabled), HTTPSOnly: pointer.To(d.Get("https_only").(bool)), + PublicNetworkAccess: pointer.To(d.Get("public_network_access").(string)), SiteConfig: &siteConfig, }, } @@ -414,7 +426,7 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) if d.HasChange("virtual_network_subnet_id") { subnetId := d.Get("virtual_network_subnet_id").(string) if subnetId == "" { - if _, err := clientNew.DeleteSwiftVirtualNetwork(ctx, *id); err != nil { + if _, err := client.DeleteSwiftVirtualNetwork(ctx, *id); err != nil { return fmt.Errorf("removing `virtual_network_subnet_id` association for %s: %+v", *id, err) } var empty *string @@ -432,7 +444,7 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) siteEnvelope.Identity = expandedIdentity } - if err := clientNew.CreateOrUpdateThenPoll(ctx, *id, siteEnvelope); err != nil { + if err := client.CreateOrUpdateThenPoll(ctx, *id, siteEnvelope); err != nil { return fmt.Errorf("updating %s: %+v", *id, err) } @@ -441,7 +453,7 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) Properties: &siteConfig, } - if _, err := clientNew.CreateOrUpdateConfiguration(ctx, *id, siteConfigResource); err != nil { + if _, err := client.CreateOrUpdateConfiguration(ctx, *id, siteConfigResource); err != nil { return fmt.Errorf("updating Configuration for %s: %+v", *id, err) } } @@ -450,7 +462,7 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) Properties: pointer.To(appSettings), } - if _, err = clientNew.UpdateApplicationSettings(ctx, *id, settings); err != nil { + if _, err = client.UpdateApplicationSettings(ctx, *id, settings); err != nil { return fmt.Errorf("updating Application Settings for %s: %+v", *id, err) } @@ -460,7 +472,7 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) Properties: pointer.To(connectionStrings), } - if _, err := clientNew.UpdateConnectionStrings(ctx, *id, properties); err != nil { + if _, err := client.UpdateConnectionStrings(ctx, *id, properties); err != nil { return fmt.Errorf("updating Connection Strings for %s: %+v", *id, err) } } @@ -469,7 +481,7 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) } func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) error { - clientNew := meta.(*clients.Client).AppService.WebAppsClient + client := meta.(*clients.Client).AppService.WebAppsClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -478,7 +490,7 @@ func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) e return err } - resp, err := clientNew.Get(ctx, *id) + resp, err := client.Get(ctx, *id) if err != nil { if response.WasNotFound(resp.HttpResponse) { log.Printf("[DEBUG] %s was not found - removing from state", *id) @@ -513,14 +525,15 @@ func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) e return err } d.Set("app_service_plan_id", servicePlanId.ID()) - d.Set("enabled", props.Enabled) - d.Set("default_hostname", props.DefaultHostName) - d.Set("https_only", props.HTTPSOnly) - d.Set("outbound_ip_addresses", props.OutboundIPAddresses) - d.Set("possible_outbound_ip_addresses", props.PossibleOutboundIPAddresses) - d.Set("client_affinity_enabled", props.ClientAffinityEnabled) - d.Set("custom_domain_verification_id", props.CustomDomainVerificationId) - d.Set("virtual_network_subnet_id", props.VirtualNetworkSubnetId) + d.Set("enabled", pointer.From(props.Enabled)) + d.Set("default_hostname", pointer.From(props.DefaultHostName)) + d.Set("https_only", pointer.From(props.HTTPSOnly)) + d.Set("outbound_ip_addresses", pointer.From(props.OutboundIPAddresses)) + d.Set("possible_outbound_ip_addresses", pointer.From(props.PossibleOutboundIPAddresses)) + d.Set("client_affinity_enabled", pointer.From(props.ClientAffinityEnabled)) + d.Set("custom_domain_verification_id", pointer.From(props.CustomDomainVerificationId)) + d.Set("virtual_network_subnet_id", pointer.From(props.VirtualNetworkSubnetId)) + d.Set("public_network_access", pointer.From(props.PublicNetworkAccess)) clientCertMode := "" if props.ClientCertEnabled != nil && *props.ClientCertEnabled { @@ -528,13 +541,13 @@ func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) e } d.Set("client_certificate_mode", clientCertMode) } - } - appSettingsResp, err := clientNew.ListApplicationSettings(ctx, *id) + appSettingsResp, err := client.ListApplicationSettings(ctx, *id) if err != nil { return fmt.Errorf("listing application settings for %s: %+v", *id, err) } + if model := appSettingsResp.Model; model != nil { appSettings := flattenLogicAppStandardAppSettings(model.Properties) @@ -587,28 +600,31 @@ func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) e } } - connectionStringsResp, err := clientNew.ListConnectionStrings(ctx, *id) + connectionStringsResp, err := client.ListConnectionStrings(ctx, *id) if err != nil { return fmt.Errorf("listing connection strings for %s: %+v", *id, err) } + if model := connectionStringsResp.Model; model != nil { if err = d.Set("connection_string", flattenLogicAppStandardConnectionStrings(model.Properties)); err != nil { return err } } - siteCredentials, err := helpers.ListPublishingCredentials(ctx, clientNew, *id) + siteCredentials, err := helpers.ListPublishingCredentials(ctx, client, *id) if err != nil { return fmt.Errorf("listing publishing credentials for %s: %+v", *id, err) } + if err = d.Set("site_credential", flattenLogicAppStandardSiteCredential(siteCredentials)); err != nil { return err } - configResp, err := clientNew.GetConfiguration(ctx, *id) + configResp, err := client.GetConfiguration(ctx, *id) if err != nil { return fmt.Errorf("retrieving the configuration for %s: %+v", *id, err) } + if model := configResp.Model; model != nil { siteConfig := flattenLogicAppStandardSiteConfig(model.Properties) if err = d.Set("site_config", siteConfig); err != nil { @@ -620,7 +636,7 @@ func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) e } func resourceLogicAppStandardDelete(d *pluginsdk.ResourceData, meta interface{}) error { - clientNew := meta.(*clients.Client).AppService.WebAppsClient + client := meta.(*clients.Client).AppService.WebAppsClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() @@ -633,7 +649,7 @@ func resourceLogicAppStandardDelete(d *pluginsdk.ResourceData, meta interface{}) opts.DeleteMetrics = pointer.To(true) opts.DeleteEmptyServerFarm = pointer.To(false) - if _, err := clientNew.Delete(ctx, *id, opts); err != nil { + if _, err := client.Delete(ctx, *id, opts); err != nil { return fmt.Errorf("deleting %s: %+v", *id, err) } diff --git a/internal/services/logic/logic_app_standard_resource_test.go b/internal/services/logic/logic_app_standard_resource_test.go index d7d44aff34a9..cc2ee0953356 100644 --- a/internal/services/logic/logic_app_standard_resource_test.go +++ b/internal/services/logic/logic_app_standard_resource_test.go @@ -36,7 +36,22 @@ func TestAccLogicAppStandard_basic(t *testing.T) { check.That(data.ResourceName).Key("custom_domain_verification_id").Exists(), ), }, - data.ImportStep("site_credential"), + data.ImportStep(), + }) +} + +func TestAccLogicAppStandard_publicNetworkAccessDisabled(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_logic_app_standard", "test") + r := LogicAppStandardResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.publicNetworkAccess(data, "Disabled"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), }) } @@ -928,7 +943,7 @@ func TestAccLogicAppStandard_publicNetworkAccessEnabled(t *testing.T) { data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.publicNetworkAccessEnabled(data, false), + Config: r.siteConfigPublicNetworkAccessEnabled(data, false), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("site_config.0.public_network_access_enabled").HasValue("false"), @@ -936,7 +951,7 @@ func TestAccLogicAppStandard_publicNetworkAccessEnabled(t *testing.T) { }, data.ImportStep(), { - Config: r.publicNetworkAccessEnabled(data, true), + Config: r.siteConfigPublicNetworkAccessEnabled(data, true), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("site_config.0.public_network_access_enabled").HasValue("true"), @@ -1006,6 +1021,26 @@ resource "azurerm_logic_app_standard" "test" { `, r.template(data), data.RandomInteger) } +func (r LogicAppStandardResource) publicNetworkAccess(data acceptance.TestData, status string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +%s + +resource "azurerm_logic_app_standard" "test" { + name = "acctest-%d-func" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + storage_account_name = azurerm_storage_account.test.name + storage_account_access_key = azurerm_storage_account.test.primary_access_key + public_network_access = "%s" +} +`, r.template(data), data.RandomInteger, status) +} + func (r LogicAppStandardResource) containerized(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { @@ -2280,7 +2315,7 @@ resource "azurerm_logic_app_standard" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomString) } -func (r LogicAppStandardResource) publicNetworkAccessEnabled(data acceptance.TestData, enabled bool) string { +func (r LogicAppStandardResource) siteConfigPublicNetworkAccessEnabled(data acceptance.TestData, enabled bool) string { return fmt.Sprintf(` provider "azurerm" { features {} From a13e52bb69a7f2e022441c8828f3905b111ff84f Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 6 Nov 2024 11:44:41 +0100 Subject: [PATCH 3/8] finish half baked logic app resource and data source documentation --- .../docs/d/logic_app_standard.html.markdown | 158 ++++++++++++++++++ .../docs/r/logic_app_standard.html.markdown | 41 +++-- 2 files changed, 178 insertions(+), 21 deletions(-) diff --git a/website/docs/d/logic_app_standard.html.markdown b/website/docs/d/logic_app_standard.html.markdown index d54e9d415f73..e885620eef68 100644 --- a/website/docs/d/logic_app_standard.html.markdown +++ b/website/docs/d/logic_app_standard.html.markdown @@ -41,6 +41,52 @@ The following attributes are exported: * `identity` - An `identity` block as defined below. +* `app_service_plan_id` - The ID of the App Service Plan. + +* `app_settings` - A map of key-value pairs for [App Settings](https://docs.microsoft.com/azure/azure-functions/functions-app-settings) and custom values. + +* `use_extension_bundle` - Whether the logic app should use the bundled extension package. + +* `bundle_version` - Controls the allowed range for bundle versions. + +* `client_affinity_enabled` - Should the Logic App send session affinity cookies, which route client requests in the same session to the same instance. + +* `client_certificate_mode` - The mode of the Logic App's client certificates requirement for incoming requests. + +* `connection_string` - A `connection_string` block as defined below. + +* `custom_domain_verification_id` - The custom domain verification of the Logic App. + +* `default_hostname` - The default hostname of the Logic App. + +* `enabled` - Whether the Logic App is enabled. + +* `https_only` - Whether the Logic App can only be accessed via HTTPS. + +* `kind` - The kind of the Logic App. + +* `outbound_ip_addresses` - The outbound IP addresses of the Logic App. + +* `possible_outbound_ip_addresses` - The possible outbound IP addresses of the Logic App. + +* `public_network_access` - Whether Public Network Access should be enabled or not. + +* `site_config` - A `site_config` object as defined below. + +* `site_credential` - A `site_credential` block as defined below, which contains the site-level credentials used to publish to this Logic App. + +* `storage_account_name` - The backend storage account name which will be used by this Logic App (e.g. for Stateful workflows data). + +* `storage_account_access_key` - The access key which will be used to access the backend storage account for the Logic App. + +* `storage_account_share_name` - The name of the share used by the logic app. + +* `tags` - A mapping of tags assigned to the resource. + +* `version` - The runtime version associated with the Logic App. + +* `virtual_network_subnet_id` - The subnet ID for the Logic App. + --- The `identity` block exports the following: @@ -51,6 +97,118 @@ The `identity` block exports the following: * `principal_id` - The Principal ID for the Service Principal associated with the Managed Service Identity of this Logic App Workflow. +--- + +he `site_credential` block exports the following: + +* `username` - The username which can be used to publish to this Logic App. + +* `password` - The password associated with the username, which can be used to publish to this Logic App. + +--- + +The `site_config` block exports the following: + +* `always_on` - Should the Logic App be loaded at all times? + +* `app_scale_limit` - The number of workers this Logic App can scale out to. Only applicable to apps on the Consumption and Premium plan. + +* `auto_swap_slot_name` - The Auto-swap slot name. + +* `cors` - A `cors` block as defined below. + +* `dotnet_framework_version` - The version of the .NET framework's CLR used in this Logic App. + +* `elastic_instance_minimum` - The number of minimum instances for this Logic App Only affects apps on the Premium plan. + +* `ftps_state` - The state of FTP / FTPS service for this Logic App. + +* `health_check_path` - Path which will be checked for this Logic App health. + +* `http2_enabled` - Specifies whether the HTTP2 protocol should be enabled. + +* `ip_restriction` - A list of `ip_restriction` objects representing IP restrictions as defined below. + +* `scm_ip_restriction` - A list of `scm_ip_restriction` objects representing SCM IP restrictions as defined below. + +* `scm_use_main_ip_restriction` - Should the Logic App `ip_restriction` configuration be used for the SCM too. + +* `scm_min_tls_version` - The minimum version of TLS required for SSL requests to the SCM site. + +* `scm_type` - The type of Source Control used by the Logic App in use by the Windows Function App. + +* `linux_fx_version` - Linux App Framework and version for the Logic App. + +* `min_tls_version` - The minimum supported TLS version for the Logic App. + +* `pre_warmed_instance_count` - The number of pre-warmed instances for this Logic App Only affects apps on the Premium plan. + +* `public_network_access_enabled` - Is public network access enabled? + +* `runtime_scale_monitoring_enabled` - Should Runtime Scale Monitoring be enabled?. Only applicable to apps on the Premium plan. + +* `use_32_bit_worker_process` - Should the Logic App run in 32 bit mode, rather than 64 bit mode? + +* `vnet_route_all_enabled` - Should all outbound traffic to have Virtual Network Security Groups and User Defined Routes applied. + +* `websockets_enabled` - Should WebSockets be enabled? + +--- + +A `cors` block supports the following: + +* `allowed_origins` - A list of origins which should be able to make cross-origin calls. + +* `support_credentials` - Are credentials supported? + +--- + +A `ip_restriction` block supports the following: + +* `ip_address` - The IP Address used for this IP Restriction in CIDR notation. + +* `service_tag` - The Service Tag used for this IP Restriction. + +* `virtual_network_subnet_id` - The Virtual Network Subnet ID used for this IP Restriction. + +* `name` - The name for this IP Restriction. + +* `priority` - The priority for this IP Restriction. Restrictions are enforced in priority order. + +* `action` - Does this restriction `Allow` or `Deny` access for this IP range. + +* `headers` - The `headers` block for this specific as a `ip_restriction` block as defined below. + +--- + +A `scm_ip_restriction` block supports the following: + +* `ip_address` - The IP Address used for this IP Restriction in CIDR notation. + +* `service_tag` - The Service Tag used for this IP Restriction. + +* `virtual_network_subnet_id` - The Virtual Network Subnet ID used for this IP Restriction. + +* `name` - The name for this IP Restriction. + +* `priority` - The priority for this IP Restriction. Restrictions are enforced in priority order. + +* `action` - Does this restriction `Allow` or `Deny` access for this IP range. + +* `headers` - The `headers` block for this specific `ip_restriction` as defined below. + +--- + +A `headers` block supports the following: + +* `x_azure_fdid` - A list of allowed Azure FrontDoor IDs in UUID notation. + +* `x_fd_health_probe` - A list to allow the Azure FrontDoor health probe header. + +* `x_forwarded_for` - A list of allowed 'X-Forwarded-For' IPs in CIDR notation. + +* `x_forwarded_host` - A list of allowed 'X-Forwarded-Host' domains. + ## Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: diff --git a/website/docs/r/logic_app_standard.html.markdown b/website/docs/r/logic_app_standard.html.markdown index f3343f2d5bd1..0e1153e6e52d 100644 --- a/website/docs/r/logic_app_standard.html.markdown +++ b/website/docs/r/logic_app_standard.html.markdown @@ -117,7 +117,11 @@ The following arguments are supported: * `location` - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. -* `app_service_plan_id` - (Required) The ID of the App Service Plan within which to create this Logic App +* `app_service_plan_id` - (Required) The ID of the App Service Plan within which to create this Logic App. + +* `storage_account_name` - (Required) The backend storage account name which will be used by this Logic App (e.g. for Stateful workflows data). Changing this forces a new resource to be created. + +* `storage_account_access_key` - (Required) The access key which will be used to access the backend storage account for the Logic App. * `app_settings` - (Optional) A map of key-value pairs for [App Settings](https://docs.microsoft.com/azure/azure-functions/functions-app-settings) and custom values. @@ -127,7 +131,7 @@ The following arguments are supported: * `bundle_version` - (Optional) If `use_extension_bundle` then controls the allowed range for bundle versions. Defaults to `[1.*, 2.0.0)`. -* `connection_string` - (Optional) An `connection_string` block as defined below. +* `connection_string` - (Optional) A `connection_string` block as defined below. * `client_affinity_enabled` - (Optional) Should the Logic App send session affinity cookies, which route client requests in the same session to the same instance? @@ -139,11 +143,9 @@ The following arguments are supported: * `identity` - (Optional) An `identity` block as defined below. -* `site_config` - (Optional) A `site_config` object as defined below. - -* `storage_account_name` - (Required) The backend storage account name which will be used by this Logic App (e.g. for Stateful workflows data). Changing this forces a new resource to be created. +* `public_network_access` - (Optional) Whether Public Network Access should be enabled or not. Possible values are `Enabled` and `Disabled`. Defaults to `Enabled`. Changing this forces a new resource to be created. -* `storage_account_access_key` - (Required) The access key which will be used to access the backend storage account for the Logic App +* `site_config` - (Optional) A `site_config` object as defined below. * `storage_account_share_name` - (Optional) The name of the share used by the logic app, if you want to use a custom name. This corresponds to the WEBSITE_CONTENTSHARE appsetting, which this resource will create for you. If you don't specify a name, then this resource will generate a dynamic name. This setting is useful if you want to provision a storage account and create a share using azurerm_storage_share @@ -155,7 +157,7 @@ The following arguments are supported: ~> **Note:** Logic App version `3.x` will be out of support from December 3 2022. For more details refer [Logic Apps Standard Support for Functions Runtime V4](https://azure.microsoft.com/en-us/updates/logic-apps-standard-support-for-functions-runtime-v4/) -* `virtual_network_subnet_id` - (Optional) The subnet id which will be used by this resource for [regional virtual network integration](https://docs.microsoft.com/en-us/azure/app-service/overview-vnet-integration#regional-virtual-network-integration). +* `virtual_network_subnet_id` - (Optional) The subnet ID which will be used by this resource for [regional virtual network integration](https://docs.microsoft.com/en-us/azure/app-service/overview-vnet-integration#regional-virtual-network-integration). ~> **NOTE on regional virtual network integration:** The AzureRM Terraform provider provides regional virtual network integration via the standalone resource [app_service_virtual_network_swift_connection](app_service_virtual_network_swift_connection.html) and in-line within this resource using the `virtual_network_subnet_id` property. You cannot use both methods simutaneously. @@ -181,17 +183,19 @@ The `site_config` block supports the following: * `app_scale_limit` - (Optional) The number of workers this Logic App can scale out to. Only applicable to apps on the Consumption and Premium plan. +* `auto_swap_slot_name` - The Auto-swap slot name. + * `cors` - (Optional) A `cors` block as defined below. * `dotnet_framework_version` - (Optional) The version of the .NET framework's CLR used in this Logic App Possible values are `v4.0` (including .NET Core 2.1 and 3.1), `v5.0`, `v6.0` and `v8.0`. [For more information on which .NET Framework version to use based on the runtime version you're targeting - please see this table](https://docs.microsoft.com/azure/azure-functions/functions-dotnet-class-library#supported-versions). Defaults to `v4.0`. * `elastic_instance_minimum` - (Optional) The number of minimum instances for this Logic App Only affects apps on the Premium plan. -* `ftps_state` - (Optional) State of FTP / FTPS service for this Logic App Possible values include: `AllAllowed`, `FtpsOnly` and `Disabled`. Defaults to `AllAllowed`. +* `ftps_state` - (Optional) State of FTP / FTPS service for this Logic App. Possible values include: `AllAllowed`, `FtpsOnly` and `Disabled`. Defaults to `AllAllowed`. * `health_check_path` - (Optional) Path which will be checked for this Logic App health. -* `http2_enabled` - (Optional) Specifies whether or not the HTTP2 protocol should be enabled. Defaults to `false`. +* `http2_enabled` - (Optional) Specifies whether the HTTP2 protocol should be enabled. Defaults to `false`. * `ip_restriction` - (Optional) A list of `ip_restriction` objects representing IP restrictions as defined below. @@ -207,9 +211,9 @@ The `site_config` block supports the following: * `scm_type` - (Optional) The type of Source Control used by the Logic App in use by the Windows Function App. Defaults to `None`. Possible values are: `BitbucketGit`, `BitbucketHg`, `CodePlexGit`, `CodePlexHg`, `Dropbox`, `ExternalGit`, `ExternalHg`, `GitHub`, `LocalGit`, `None`, `OneDrive`, `Tfs`, `VSO`, and `VSTSRM` -* `linux_fx_version` - (Optional) Linux App Framework and version for the AppService, e.g. `DOCKER|(golang:latest)`. Setting this value will also set the `kind` of application deployed to `functionapp,linux,container,workflowapp` +* `linux_fx_version` - (Optional) Linux App Framework and version for the App Service, e.g. `DOCKER|(golang:latest)`. Setting this value will also set the `kind` of application deployed to `functionapp,linux,container,workflowapp` -* `min_tls_version` - (Optional) The minimum supported TLS version for the Logic App Possible values are `1.0`, `1.1`, and `1.2`. Defaults to `1.2` for new Logic Apps. +* `min_tls_version` - (Optional) The minimum supported TLS version for the Logic App. Possible values are `1.0`, `1.1`, and `1.2`. Defaults to `1.2` for new Logic Apps. * `pre_warmed_instance_count` - (Optional) The number of pre-warmed instances for this Logic App Only affects apps on the Premium plan. @@ -238,6 +242,7 @@ A `cors` block supports the following: An `identity` block supports the following: * `type` - (Required) Specifies the type of Managed Service Identity that should be configured on this Logic App Standard. Possible values are `SystemAssigned`, `UserAssigned` and `SystemAssigned, UserAssigned` (to enable both). + * `identity_ids` - (Optional) Specifies a list of User Assigned Managed Identity IDs to be assigned to this Logic App Standard. ~> **NOTE:** When `type` is set to `SystemAssigned`, The assigned `principal_id` and `tenant_id` can be retrieved after the Logic App has been created. More details are available below. @@ -278,7 +283,7 @@ A `scm_ip_restriction` block supports the following: * `name` - (Optional) The name for this IP Restriction. -* `priority` - (Optional) The priority for this IP Restriction. Restrictions are enforced in priority order. By default, the priority is set to 65000 if not specified. +* `priority` - (Optional) The priority for this IP Restriction. Restrictions are enforced in priority order. By default, the priority is set to `65000` if not specified. * `action` - (Optional) Does this restriction `Allow` or `Deny` access for this IP range. Defaults to `Allow`. @@ -290,9 +295,9 @@ A `headers` block supports the following: * `x_azure_fdid` - (Optional) A list of allowed Azure FrontDoor IDs in UUID notation with a maximum of 8. -* `x_fd_health_probe` - (Optional) A list to allow the Azure FrontDoor health probe header. Only allowed value is "1". +* `x_fd_health_probe` - (Optional) A list to allow the Azure FrontDoor health probe header. Only allowed value is `1`. -* `x_forwarded_for` - (Optional) A list of allowed 'X-Forwarded-For' IPs in CIDR notation with a maximum of 8 +* `x_forwarded_for` - (Optional) A list of allowed 'X-Forwarded-For' IPs in CIDR notation with a maximum of 8. * `x_forwarded_host` - (Optional) A list of allowed 'X-Forwarded-Host' domains with a maximum of 8. @@ -330,16 +335,10 @@ The `identity` block exports the following: The `site_credential` block exports the following: -* `username` - The username which can be used to publish to this App Service +* `username` - The username which can be used to publish to this App Service. * `password` - The password associated with the username, which can be used to publish to this App Service. ---- - -The `site_config` block exports the following: - -* `auto_swap_slot_name` - The Auto-swap slot name. - ## Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: From db19d28b52ba4cb2acfb72200bd95a3921608a54 Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 6 Nov 2024 14:25:05 +0100 Subject: [PATCH 4/8] use helper to get and set site_credential --- .../logic/logic_app_standard_data_source.go | 29 +++---------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/internal/services/logic/logic_app_standard_data_source.go b/internal/services/logic/logic_app_standard_data_source.go index 070fd80672d9..cd458c627deb 100644 --- a/internal/services/logic/logic_app_standard_data_source.go +++ b/internal/services/logic/logic_app_standard_data_source.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" "github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-12-01/webapps" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -327,20 +328,13 @@ func dataSourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) } } - siteCredFuture, err := client.ListPublishingCredentials(ctx, id) + siteCredentials, err := helpers.ListPublishingCredentials(ctx, client, id) if err != nil { return fmt.Errorf("listing publishing credentials for %s: %+v", id, err) } - if err = siteCredFuture.Poller.PollUntilDone(ctx); err != nil { - return fmt.Errorf("waiting to list the publishing credentials for %s: %+v", id, err) - } - - if model := siteCredFuture.Model; model != nil { - siteCred := flattenLogicAppStandardDataSourceSiteCredential(model.Properties) - if err = d.Set("site_credential", siteCred); err != nil { - return err - } + if err = d.Set("site_credential", flattenLogicAppStandardSiteCredential(siteCredentials)); err != nil { + return err } return nil @@ -420,18 +414,3 @@ func flattenLogicAppStandardDataSourceSiteConfig(input *webapps.SiteConfig) []in results = append(results, result) return results } - -func flattenLogicAppStandardDataSourceSiteCredential(input *webapps.UserProperties) []interface{} { - results := make([]interface{}, 0) - result := make(map[string]interface{}) - - if input == nil { - log.Printf("[DEBUG] UserProperties is nil") - return results - } - - result["username"] = input.PublishingUserName - result["password"] = pointer.From(input.PublishingPassword) - - return append(results, result) -} From 1bd282950d0d9c9a34a251ff46ac18a0b0fc85b5 Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 19 Nov 2024 16:01:03 +0100 Subject: [PATCH 5/8] deprecate site_config.public_network_access_enabled --- .../logic/logic_app_standard_resource.go | 78 +++++++++++++++---- .../logic/logic_app_standard_resource_test.go | 11 +++ website/docs/5.0-upgrade-guide.html.markdown | 8 ++ .../docs/d/logic_app_standard.html.markdown | 2 - .../docs/r/logic_app_standard.html.markdown | 6 +- 5 files changed, 84 insertions(+), 21 deletions(-) diff --git a/internal/services/logic/logic_app_standard_resource.go b/internal/services/logic/logic_app_standard_resource.go index 8e5385184605..2be979d28868 100644 --- a/internal/services/logic/logic_app_standard_resource.go +++ b/internal/services/logic/logic_app_standard_resource.go @@ -21,6 +21,7 @@ import ( "github.com/hashicorp/go-azure-sdk/resource-manager/web/2023-12-01/webapps" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/appservice/helpers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/validate" storageValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/storage/validate" @@ -31,7 +32,7 @@ import ( ) func resourceLogicAppStandard() *pluginsdk.Resource { - return &pluginsdk.Resource{ + resource := &pluginsdk.Resource{ Create: resourceLogicAppStandardCreate, Read: resourceLogicAppStandardRead, Update: resourceLogicAppStandardUpdate, @@ -172,7 +173,6 @@ func resourceLogicAppStandard() *pluginsdk.Resource { "public_network_access": { Type: pluginsdk.TypeString, Optional: true, - ForceNew: true, Default: helpers.PublicNetworkAccessEnabled, ValidateFunc: validation.StringInSlice([]string{ helpers.PublicNetworkAccessEnabled, @@ -245,6 +245,15 @@ func resourceLogicAppStandard() *pluginsdk.Resource { }, }, } + + if !features.FivePointOhBeta() { + // Due to the way the `site_config.public_network_access_enabled` property and the `public_network_access` property + // influence each other, the default needs to be handled in the Create for now until `site_config.public_network_access_enabled` + // is removed in v5.0 + resource.Schema["public_network_access"].Default = nil + resource.Schema["public_network_access"].Computed = true + } + return resource } func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) error { @@ -327,11 +336,28 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) ClientAffinityEnabled: pointer.To(d.Get("client_affinity_enabled").(bool)), ClientCertEnabled: pointer.To(clientCertEnabled), HTTPSOnly: pointer.To(d.Get("https_only").(bool)), - PublicNetworkAccess: pointer.To(d.Get("public_network_access").(string)), SiteConfig: &siteConfig, }, } + publicNetworkAccess := d.Get("public_network_access").(string) + if !features.FivePointOhBeta() && publicNetworkAccess == "" { + // if a user is still using `site_config.public_network_access_enabled` we should be setting `public_network_access` for them + publicNetworkAccess = helpers.PublicNetworkAccessEnabled + if *siteEnvelope.Properties.SiteConfig.PublicNetworkAccess == helpers.PublicNetworkAccessDisabled { + publicNetworkAccess = helpers.PublicNetworkAccessDisabled + } + } + + // conversely if `public_network_access` has been set it should take precedence, and we should be propagating the value for that to `site_config.public_network_access_enabled` + if publicNetworkAccess == helpers.PublicNetworkAccessDisabled { + siteEnvelope.Properties.SiteConfig.PublicNetworkAccess = pointer.To(helpers.PublicNetworkAccessDisabled) + } else if publicNetworkAccess == helpers.PublicNetworkAccessEnabled { + siteEnvelope.Properties.SiteConfig.PublicNetworkAccess = pointer.To(helpers.PublicNetworkAccessEnabled) + } + + siteEnvelope.Properties.PublicNetworkAccess = pointer.To(publicNetworkAccess) + if clientCertEnabled { siteEnvelope.Properties.ClientCertMode = pointer.To(webapps.ClientCertMode(clientCertMode)) } @@ -419,6 +445,16 @@ func resourceLogicAppStandardUpdate(d *pluginsdk.ResourceData, meta interface{}) }, } + if d.HasChange("public_network_access") { + publicNetworkAccess := d.Get("public_network_access").(string) + siteEnvelope.Properties.PublicNetworkAccess = pointer.To(publicNetworkAccess) + if publicNetworkAccess == helpers.PublicNetworkAccessEnabled { + siteEnvelope.Properties.SiteConfig.PublicNetworkAccess = pointer.To(helpers.PublicNetworkAccessEnabled) + } else { + siteEnvelope.Properties.SiteConfig.PublicNetworkAccess = pointer.To(helpers.PublicNetworkAccessDisabled) + } + } + if clientCertEnabled { siteEnvelope.Properties.ClientCertMode = pointer.To(webapps.ClientCertMode(clientCertMode)) } @@ -712,7 +748,7 @@ func getBasicLogicAppSettings(d *pluginsdk.ResourceData, endpointSuffix string) } func schemaLogicAppStandardSiteConfig() *pluginsdk.Schema { - return &pluginsdk.Schema{ + schema := &pluginsdk.Schema{ Type: pluginsdk.TypeList, Optional: true, Computed: true, @@ -866,12 +902,6 @@ func schemaLogicAppStandardSiteConfig() *pluginsdk.Schema { Computed: true, }, - "public_network_access_enabled": { - Type: pluginsdk.TypeBool, - Optional: true, - Default: true, - }, - "auto_swap_slot_name": { Type: pluginsdk.TypeString, Computed: true, @@ -879,6 +909,17 @@ func schemaLogicAppStandardSiteConfig() *pluginsdk.Schema { }, }, } + + if !features.FivePointOhBeta() { + schema.Elem.(*pluginsdk.Resource).Schema["public_network_access_enabled"] = &pluginsdk.Schema{ + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + Deprecated: "the `site_config.public_network_access_enabled` property has been superseded by the `public_network_access` property and will be removed in v5.0 of the AzureRM Provider.", + } + } + + return schema } func schemaLogicAppCorsSettings() *pluginsdk.Schema { @@ -1094,7 +1135,10 @@ func flattenLogicAppStandardSiteConfig(input *webapps.SiteConfig) []interface{} if input.PublicNetworkAccess != nil { publicNetworkAccessEnabled = !strings.EqualFold(pointer.From(input.PublicNetworkAccess), helpers.PublicNetworkAccessDisabled) } - result["public_network_access_enabled"] = publicNetworkAccessEnabled + + if !features.FivePointOhBeta() { + result["public_network_access_enabled"] = publicNetworkAccessEnabled + } results = append(results, result) return results @@ -1319,12 +1363,14 @@ func expandLogicAppStandardSiteConfig(d *pluginsdk.ResourceData) (webapps.SiteCo siteConfig.VnetRouteAllEnabled = pointer.To(v.(bool)) } - if v, ok := config["public_network_access_enabled"]; ok { - pna := helpers.PublicNetworkAccessEnabled - if !v.(bool) { - pna = helpers.PublicNetworkAccessDisabled + if !features.FivePointOhBeta() { + if v, ok := config["public_network_access_enabled"]; ok { + pna := helpers.PublicNetworkAccessEnabled + if !v.(bool) { + pna = helpers.PublicNetworkAccessDisabled + } + siteConfig.PublicNetworkAccess = pointer.To(pna) } - siteConfig.PublicNetworkAccess = pointer.To(pna) } return siteConfig, nil diff --git a/internal/services/logic/logic_app_standard_resource_test.go b/internal/services/logic/logic_app_standard_resource_test.go index cc2ee0953356..b9167e2b9cc9 100644 --- a/internal/services/logic/logic_app_standard_resource_test.go +++ b/internal/services/logic/logic_app_standard_resource_test.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" + "github.com/hashicorp/terraform-provider-azurerm/internal/features" "github.com/hashicorp/terraform-provider-azurerm/internal/services/logic/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" ) @@ -52,6 +53,13 @@ func TestAccLogicAppStandard_publicNetworkAccessDisabled(t *testing.T) { ), }, data.ImportStep(), + { + Config: r.publicNetworkAccess(data, "Enabled"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), }) } @@ -938,6 +946,9 @@ func TestAccLogicAppStandard_vNetIntegrationUpdate(t *testing.T) { } func TestAccLogicAppStandard_publicNetworkAccessEnabled(t *testing.T) { + if features.FivePointOhBeta() { + t.Skip("skipping since `site_config.public_network_access_enabled` is removed in v5.0") + } data := acceptance.BuildTestData(t, "azurerm_logic_app_standard", "test") r := LogicAppStandardResource{} diff --git a/website/docs/5.0-upgrade-guide.html.markdown b/website/docs/5.0-upgrade-guide.html.markdown index bd8de5a1253a..82060a1d8eaf 100644 --- a/website/docs/5.0-upgrade-guide.html.markdown +++ b/website/docs/5.0-upgrade-guide.html.markdown @@ -77,6 +77,10 @@ Please follow the format in the example below for listing breaking changes in re * The `minimum_tls_version` property no longer accepts `1.0` and `1.1` as a value. +### `azurerm_logic_app_standard` + +* The deprecated `site_config.public_network_access_enabled` property has been removed and superseded by the `public_network_access` property. + ### `azurerm_monitor_aad_diagnostic_setting` * The deprecated `enabled_log.retention_policy` block has been removed. @@ -123,6 +127,10 @@ Please follow the format in the example below for listing breaking changes in da * The deprecated `example_property_with_no_replacement` property has been removed. ``` +### `azurerm_logic_app_standard` + +* The deprecated `site_config.public_network_access_enabled` property has been removed and superseded by the `public_network_access` property. + ### `azurerm_storage_container` * The deprecated `storage_account_name` property has been removed in favour of the `storage_account_id` property. diff --git a/website/docs/d/logic_app_standard.html.markdown b/website/docs/d/logic_app_standard.html.markdown index e885620eef68..00ec35134dee 100644 --- a/website/docs/d/logic_app_standard.html.markdown +++ b/website/docs/d/logic_app_standard.html.markdown @@ -143,8 +143,6 @@ The `site_config` block exports the following: * `pre_warmed_instance_count` - The number of pre-warmed instances for this Logic App Only affects apps on the Premium plan. -* `public_network_access_enabled` - Is public network access enabled? - * `runtime_scale_monitoring_enabled` - Should Runtime Scale Monitoring be enabled?. Only applicable to apps on the Premium plan. * `use_32_bit_worker_process` - Should the Logic App run in 32 bit mode, rather than 64 bit mode? diff --git a/website/docs/r/logic_app_standard.html.markdown b/website/docs/r/logic_app_standard.html.markdown index 0e1153e6e52d..a973fe29e49c 100644 --- a/website/docs/r/logic_app_standard.html.markdown +++ b/website/docs/r/logic_app_standard.html.markdown @@ -143,7 +143,9 @@ The following arguments are supported: * `identity` - (Optional) An `identity` block as defined below. -* `public_network_access` - (Optional) Whether Public Network Access should be enabled or not. Possible values are `Enabled` and `Disabled`. Defaults to `Enabled`. Changing this forces a new resource to be created. +* `public_network_access` - (Optional) Whether Public Network Access should be enabled or not. Possible values are `Enabled` and `Disabled`. Defaults to `Enabled`. + +~> **Note:** Setting this property will also set it in the Site Config. * `site_config` - (Optional) A `site_config` object as defined below. @@ -217,8 +219,6 @@ The `site_config` block supports the following: * `pre_warmed_instance_count` - (Optional) The number of pre-warmed instances for this Logic App Only affects apps on the Premium plan. -* `public_network_access_enabled` - (Optional) Is public network access enabled? Defaults to `true`. - * `runtime_scale_monitoring_enabled` - (Optional) Should Runtime Scale Monitoring be enabled?. Only applicable to apps on the Premium plan. Defaults to `false`. * `use_32_bit_worker_process` - (Optional) Should the Logic App run in 32 bit mode, rather than 64 bit mode? Defaults to `true`. From 7f854f987282ee851d7a9ea9bfcca56d0161b061 Mon Sep 17 00:00:00 2001 From: Steph Date: Tue, 19 Nov 2024 16:29:46 +0100 Subject: [PATCH 6/8] fix panic when site_config.public_network_access_enabled isn't set and add data source deprecation to upgrade guide --- internal/services/logic/logic_app_standard_resource.go | 2 +- website/docs/5.0-upgrade-guide.html.markdown | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/services/logic/logic_app_standard_resource.go b/internal/services/logic/logic_app_standard_resource.go index 2be979d28868..3adedac82694 100644 --- a/internal/services/logic/logic_app_standard_resource.go +++ b/internal/services/logic/logic_app_standard_resource.go @@ -344,7 +344,7 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) if !features.FivePointOhBeta() && publicNetworkAccess == "" { // if a user is still using `site_config.public_network_access_enabled` we should be setting `public_network_access` for them publicNetworkAccess = helpers.PublicNetworkAccessEnabled - if *siteEnvelope.Properties.SiteConfig.PublicNetworkAccess == helpers.PublicNetworkAccessDisabled { + if v := siteEnvelope.Properties.SiteConfig.PublicNetworkAccess; v != nil && *v == helpers.PublicNetworkAccessDisabled { publicNetworkAccess = helpers.PublicNetworkAccessDisabled } } diff --git a/website/docs/5.0-upgrade-guide.html.markdown b/website/docs/5.0-upgrade-guide.html.markdown index 82060a1d8eaf..c0a95d04096d 100644 --- a/website/docs/5.0-upgrade-guide.html.markdown +++ b/website/docs/5.0-upgrade-guide.html.markdown @@ -48,6 +48,10 @@ Please follow the format in the example below for adding removed data sources: This deprecated data source has been superseded/retired and has been removed from the Azure Provider. ``` +### `azurerm_logic_app_standard` + +* The deprecated `site_config.public_network_access_enabled` property has been removed and superseded by the `public_network_access` property. + ## Breaking Changes in Resources Please follow the format in the example below for listing breaking changes in resources: From 7fad0b17d27b219d87079fc31369da324f623976 Mon Sep 17 00:00:00 2001 From: Steph Date: Wed, 20 Nov 2024 08:36:08 +0100 Subject: [PATCH 7/8] use storage_account_id for storage share resource --- internal/services/logic/logic_app_standard_resource_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/services/logic/logic_app_standard_resource_test.go b/internal/services/logic/logic_app_standard_resource_test.go index b9167e2b9cc9..d163f15597db 100644 --- a/internal/services/logic/logic_app_standard_resource_test.go +++ b/internal/services/logic/logic_app_standard_resource_test.go @@ -1260,9 +1260,9 @@ provider "azurerm" { %s resource "azurerm_storage_share" "custom" { - name = "customshare" - storage_account_name = azurerm_storage_account.test.name - quota = 1 + name = "customshare" + storage_account_id = azurerm_storage_account.test.id + quota = 1 } resource "azurerm_logic_app_standard" "test" { From 98f28c3249510007f3e334c490fee0c5292d04bb Mon Sep 17 00:00:00 2001 From: Steph Date: Mon, 25 Nov 2024 09:38:43 +0100 Subject: [PATCH 8/8] review comments --- .../logic/logic_app_standard_data_source.go | 16 +--------------- .../logic/logic_app_standard_resource.go | 17 ++--------------- website/docs/r/logic_app_standard.html.markdown | 2 +- 3 files changed, 4 insertions(+), 31 deletions(-) diff --git a/internal/services/logic/logic_app_standard_data_source.go b/internal/services/logic/logic_app_standard_data_source.go index cd458c627deb..b862dd9926ee 100644 --- a/internal/services/logic/logic_app_standard_data_source.go +++ b/internal/services/logic/logic_app_standard_data_source.go @@ -254,7 +254,7 @@ func dataSourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("listing application settings for %s: %+v", id, err) } if model := appSettingsResp.Model; model != nil { - appSettings := flattenLogicAppStandardDataSourceAppSettings(model.Properties) + appSettings := pointer.From(model.Properties) connectionString := appSettings["AzureWebJobsStorage"] @@ -340,20 +340,6 @@ func dataSourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) return nil } -func flattenLogicAppStandardDataSourceAppSettings(input *map[string]string) map[string]string { - output := make(map[string]string) - - if input == nil || len(*input) == 0 { - return output - } - - for k, v := range *input { - output[k] = v - } - - return output -} - func flattenLogicAppStandardDataSourceConnectionStrings(input *map[string]webapps.ConnStringValueTypePair) interface{} { results := make([]interface{}, 0) diff --git a/internal/services/logic/logic_app_standard_resource.go b/internal/services/logic/logic_app_standard_resource.go index 3adedac82694..6d3ff8b855c6 100644 --- a/internal/services/logic/logic_app_standard_resource.go +++ b/internal/services/logic/logic_app_standard_resource.go @@ -295,7 +295,7 @@ func resourceLogicAppStandardCreate(d *pluginsdk.ResourceData, meta interface{}) } if available.Model == nil || available.Model.NameAvailable == nil { - return fmt.Errorf("") + return fmt.Errorf("checking if name %q was available: `model` was nil", id.SiteName) } if !*available.Model.NameAvailable { @@ -585,7 +585,7 @@ func resourceLogicAppStandardRead(d *pluginsdk.ResourceData, meta interface{}) e } if model := appSettingsResp.Model; model != nil { - appSettings := flattenLogicAppStandardAppSettings(model.Properties) + appSettings := pointer.From(model.Properties) connectionString := appSettings["AzureWebJobsStorage"] @@ -1056,19 +1056,6 @@ func schemaLogicAppStandardIpRestriction() *pluginsdk.Schema { } } -func flattenLogicAppStandardAppSettings(input *map[string]string) map[string]string { - output := make(map[string]string) - if input == nil || len(*input) == 0 { - return output - } - - for k, v := range *input { - output[k] = v - } - - return output -} - func flattenLogicAppStandardConnectionStrings(input *map[string]webapps.ConnStringValueTypePair) interface{} { results := make([]interface{}, 0) diff --git a/website/docs/r/logic_app_standard.html.markdown b/website/docs/r/logic_app_standard.html.markdown index a973fe29e49c..e255b162bb4d 100644 --- a/website/docs/r/logic_app_standard.html.markdown +++ b/website/docs/r/logic_app_standard.html.markdown @@ -185,7 +185,7 @@ The `site_config` block supports the following: * `app_scale_limit` - (Optional) The number of workers this Logic App can scale out to. Only applicable to apps on the Consumption and Premium plan. -* `auto_swap_slot_name` - The Auto-swap slot name. +* `auto_swap_slot_name` - (Optional) The Auto-swap slot name. * `cors` - (Optional) A `cors` block as defined below.