From 0f40e6db43d1c7cfa90d8a2d7f57da339de6b7bc Mon Sep 17 00:00:00 2001 From: Matthijs Vos Date: Mon, 5 Dec 2022 14:18:21 +0100 Subject: [PATCH 01/19] Typo in sftp_enabled of `azurerm_storage_account` documentation (#19552) --- website/docs/r/storage_account.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/storage_account.html.markdown b/website/docs/r/storage_account.html.markdown index ca2a56948495..c769267eb0db 100644 --- a/website/docs/r/storage_account.html.markdown +++ b/website/docs/r/storage_account.html.markdown @@ -166,7 +166,7 @@ The following arguments are supported: * `sas_policy` - (Optional) A `sas_policy` block as defined below. -* `stfp_enabled` - (Optional) Boolean, enable SFTP for the storage account +* `sftp_enabled` - (Optional) Boolean, enable SFTP for the storage account -> **NOTE:** SFTP support requires `is_hns_enabled` set to `true`. [More information on SFTP support can be found here](https://learn.microsoft.com/azure/storage/blobs/secure-file-transfer-protocol-support). Defaults to `false` From 376be1031861f6302beb9f4ceb66e8e589ba13d7 Mon Sep 17 00:00:00 2001 From: Tom Harvey Date: Mon, 5 Dec 2022 14:26:04 +0100 Subject: [PATCH 02/19] r/media_services_account: fixing the Resource ID segment to match the validation function (#19557) --- website/docs/r/media_services_account.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/media_services_account.html.markdown b/website/docs/r/media_services_account.html.markdown index 1ffdcae1a93f..6b47d708cc94 100644 --- a/website/docs/r/media_services_account.html.markdown +++ b/website/docs/r/media_services_account.html.markdown @@ -114,5 +114,5 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/l Media Services Accounts can be imported using the `resource id`, e.g. ```shell -terraform import azurerm_media_services_account.account /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Media/mediaservices/account1 +terraform import azurerm_media_services_account.account /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Media/mediaServices/account1 ``` From f12d293cb3a6bb9d3058ff205278d010fe7083d7 Mon Sep 17 00:00:00 2001 From: Jonathan Share Date: Mon, 5 Dec 2022 15:01:02 +0100 Subject: [PATCH 03/19] Correct field name from `auth_config` to `authentication` on documentation example for `azurerm_postgresql_flexible_server_active_directory_administrator` (#19555) --- ...flexible_server_active_directory_administrator.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/postgresql_flexible_server_active_directory_administrator.html.markdown b/website/docs/r/postgresql_flexible_server_active_directory_administrator.html.markdown index d35eeae9427d..0230b6fe0124 100644 --- a/website/docs/r/postgresql_flexible_server_active_directory_administrator.html.markdown +++ b/website/docs/r/postgresql_flexible_server_active_directory_administrator.html.markdown @@ -30,7 +30,7 @@ resource "azurerm_postgresql_flexible_server" "example" { sku_name = "GP_Standard_D2s_v3" zone = "2" - auth_config { + authentication { active_directory_auth_enabled = true tenant_id = data.azurerm_client_config.current.tenant_id } From 5894a6835810115dd2cc346992d39c20cf2d9f3a Mon Sep 17 00:00:00 2001 From: Daniel Schniepp Date: Mon, 5 Dec 2022 19:34:02 +0100 Subject: [PATCH 04/19] Fix wrong Azure FrontDoor SP name to `Microsoft.Azure.Cdn` (#19560) --- .../frontdoor/frontdoor-cmk-byoc-custom-domain/README.md | 8 ++++---- .../frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf | 4 ++-- .../cdn/cdn_endpoint_custom_domain_resource_test.go | 2 +- website/docs/r/cdn_frontdoor_secret.html.markdown | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/README.md b/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/README.md index 4cd1a3ed5559..b3ffee18e11d 100644 --- a/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/README.md +++ b/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/README.md @@ -30,11 +30,11 @@ For this example you will need to look up the object IDs of the Frontdoor servic * From the left hand menu select `Azure Active Directory`. -* In the search filter box, near the top of the page, type `Microsoft.AzureFrontDoor-Cdn`. +* In the search filter box, near the top of the page, type `Microsoft.Azure.Cdn`. -* Click on the `Microsoft.AzureFrontDoor-Cdn` entry in the `Enterprise Applications` results view. +* Click on the `Microsoft.Azure.Cdn` entry in the `Enterprise Applications` results view. -* This will open the `Enterprise Applications Properties`, copy the `Object ID` and paste it into the examples `main.tf` file where is says `<- Object Id for the Microsoft.AzureFrontDoor-Cdn Enterprise Application.`. +* This will open the `Enterprise Applications Properties`, copy the `Object ID` and paste it into the examples `main.tf` file where is says `<- Object Id for the Microsoft.Azure.Cdn Enterprise Application.`. Repeat the above steps for all of the object IDs needed for this example. @@ -44,7 +44,7 @@ The following Key Vault permission are granted by this example: | Object ID | Key Permissions | Secret Permissions | Certificate Permissions | |:-----------------------------------------|:---------------:|:--------------------:|:---------------------------------------------:| -| `Microsoft.AzureFrontDoor-Cdn` Object ID | - | **Get** | - | +| `Microsoft.Azure.Cdn` Object ID | - | **Get** | - | | Your Personal AAD Object ID | - | **Get** and **List** | **Get**, **List**, **Purge** and **Recover** | | Terraform Service Principal | - | **Get** | **Get**, **Import**, **Delete** and **Purge** | diff --git a/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf b/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf index 96263508047a..ac2ecf2e098e 100644 --- a/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf +++ b/examples/cdn/frontdoor/frontdoor-cmk-byoc-custom-domain/main.tf @@ -23,10 +23,10 @@ resource "azurerm_key_vault" "example" { ip_rules = ["10.0.1.0/24"] # <- this should be the CIDR for your clients IP to allow it through the Key Vault Firewall Policy } - # Grant access to the Frontdoor Enterprise Application(e.g. Microsoft.AzureFrontDoor-Cdn) to the Key Vaults Certificates + # Grant access to the Frontdoor Enterprise Application(e.g. Microsoft.Azure.Cdn) to the Key Vaults Certificates access_policy { tenant_id = data.azurerm_client_config.current.tenant_id - object_id = "00000000-0000-0000-0000-000000000000" # <- Object Id for the Microsoft.AzureFrontDoor-Cdn Enterprise Application. + object_id = "00000000-0000-0000-0000-000000000000" # <- Object Id for the Microsoft.Azure.Cdn Enterprise Application. secret_permissions = [ "Get", diff --git a/internal/services/cdn/cdn_endpoint_custom_domain_resource_test.go b/internal/services/cdn/cdn_endpoint_custom_domain_resource_test.go index cd85001600ef..1cb01b6bad8c 100644 --- a/internal/services/cdn/cdn_endpoint_custom_domain_resource_test.go +++ b/internal/services/cdn/cdn_endpoint_custom_domain_resource_test.go @@ -292,7 +292,7 @@ data "azurerm_client_config" "test" { } data "azuread_service_principal" "test" { - display_name = "Microsoft.AzureFrontDoor-Cdn" + display_name = "Microsoft.Azure.Cdn" } resource "azurerm_key_vault" "test" { diff --git a/website/docs/r/cdn_frontdoor_secret.html.markdown b/website/docs/r/cdn_frontdoor_secret.html.markdown index f3acfdb16bb0..e51771a7eff2 100644 --- a/website/docs/r/cdn_frontdoor_secret.html.markdown +++ b/website/docs/r/cdn_frontdoor_secret.html.markdown @@ -12,11 +12,11 @@ Manages a Front Door (standard/premium) Secret. ## Required Key Vault Permissions -!>**IMPORTANT:** You must add an `Access Policy` to your `azurerm_key_vault` for the `Microsoft.AzureFrontDoor-Cdn` Enterprise Application Object ID. +!>**IMPORTANT:** You must add an `Access Policy` to your `azurerm_key_vault` for the `Microsoft.Azure.Cdn` Enterprise Application Object ID. | Object ID | Key Permissions | Secret Permissions | Certificate Permissions | |:-----------------------------------------|:---------------:|:--------------------:|:---------------------------------------------:| -| `Microsoft.AzureFrontDoor-Cdn` Object ID | - | **Get** | - | +| `Microsoft.Azure.Cdn` Object ID | - | **Get** | - | | Your Personal AAD Object ID | - | **Get** and **List** | **Get**, **List**, **Purge** and **Recover** | | Terraform Service Principal | - | **Get** | **Get**, **Import**, **Delete** and **Purge** | @@ -27,7 +27,7 @@ Manages a Front Door (standard/premium) Secret. ```hcl data "azurerm_client_config" "current" {} data "azuread_service_principal" "frontdoor" { - display_name = "Microsoft.AzureFrontDoor-Cdn" + display_name = "Microsoft.Azure.Cdn" } resource "azurerm_key_vault" "example" { @@ -44,7 +44,7 @@ resource "azurerm_key_vault" "example" { ip_rules = ["10.0.0.0/24"] } - # CDN Front Door Enterprise Application Object ID(e.g. Microsoft.AzureFrontDoor-Cdn) + # CDN Front Door Enterprise Application Object ID(e.g. Microsoft.Azure.Cdn) access_policy { tenant_id = data.azurerm_client_config.current.tenant_id object_id = data.azuread_service_principal.frontdoor.object_id From e28e81b5c617c6e665d19c2ea36300f366bbb2e6 Mon Sep 17 00:00:00 2001 From: Yichun Ma Date: Tue, 6 Dec 2022 02:35:58 +0800 Subject: [PATCH 05/19] `azurerm_mssql_virtual_machine` - support manual schedule `days_of_week` (#19553) Close https://github.com/hashicorp/terraform-provider-azurerm/issues/17931 --- .../mssql/mssql_virtual_machine_resource.go | 96 ++++++++++++++++--- .../mssql_virtual_machine_resource_test.go | 90 +++++++++++++++++ .../r/mssql_virtual_machine.html.markdown | 4 + 3 files changed, 175 insertions(+), 15 deletions(-) diff --git a/internal/services/mssql/mssql_virtual_machine_resource.go b/internal/services/mssql/mssql_virtual_machine_resource.go index aba79cfb485e..a8bd059aa461 100644 --- a/internal/services/mssql/mssql_virtual_machine_resource.go +++ b/internal/services/mssql/mssql_virtual_machine_resource.go @@ -117,6 +117,24 @@ func resourceMsSqlVirtualMachine() *pluginsdk.Resource { Required: true, ValidateFunc: validation.IntBetween(5, 60), }, + + "days_of_week": { + Type: pluginsdk.TypeSet, + Optional: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(sqlvirtualmachines.AutoBackupDaysOfWeekMonday), + string(sqlvirtualmachines.AutoBackupDaysOfWeekTuesday), + string(sqlvirtualmachines.AutoBackupDaysOfWeekWednesday), + string(sqlvirtualmachines.AutoBackupDaysOfWeekThursday), + string(sqlvirtualmachines.AutoBackupDaysOfWeekFriday), + string(sqlvirtualmachines.AutoBackupDaysOfWeekSaturday), + string(sqlvirtualmachines.AutoBackupDaysOfWeekSunday), + }, false), + }, + }, }, }, }, @@ -478,11 +496,15 @@ func resourceMsSqlVirtualMachineCreateUpdate(d *pluginsdk.ResourceData, meta int connectivityType := sqlvirtualmachines.ConnectivityType(d.Get("sql_connectivity_type").(string)) sqlManagement := sqlvirtualmachines.SqlManagementModeFull sqlServerLicenseType := sqlvirtualmachines.SqlServerLicenseType(d.Get("sql_license_type").(string)) + autoBackupSettings, err := expandSqlVirtualMachineAutoBackupSettings(d.Get("auto_backup").([]interface{})) + if err != nil { + return fmt.Errorf("expanding `auto_backup`: %+v", err) + } parameters := sqlvirtualmachines.SqlVirtualMachine{ Location: *respvm.Location, Properties: &sqlvirtualmachines.SqlVirtualMachineProperties{ - AutoBackupSettings: expandSqlVirtualMachineAutoBackupSettings(d.Get("auto_backup").([]interface{})), + AutoBackupSettings: autoBackupSettings, AutoPatchingSettings: expandSqlVirtualMachineAutoPatchingSettings(d.Get("auto_patching").([]interface{})), AssessmentSettings: expandSqlVirtualMachineAssessmentSettings(d.Get("assessment").([]interface{})), KeyVaultCredentialSettings: expandSqlVirtualMachineKeyVaultCredential(d.Get("key_vault_credential").([]interface{})), @@ -697,6 +719,28 @@ func resourceMsSqlVirtualMachineAutoBackupSettingsRefreshFunc(ctx context.Contex if !strings.EqualFold(v2.(string), val2.(string)) { return resp, "Pending", nil } + case "days_of_week": + daysOfWeekLocal := make(map[string]bool, 0) + if v2 != nil { + for _, item := range v2.(*pluginsdk.Set).List() { + daysOfWeekLocal[item.(string)] = true + } + } + + daysOfWeekRemote := make([]interface{}, 0) + if val2 != nil { + daysOfWeekRemote = val2.([]interface{}) + } + + if len(daysOfWeekRemote) != len(daysOfWeekLocal) { + return resp, "Pending", nil + } + + for _, item := range daysOfWeekRemote { + if _, ok := daysOfWeekLocal[item.(string)]; !ok { + return resp, "Pending", nil + } + } default: if v2 != val2 { return resp, "Pending", nil @@ -722,7 +766,7 @@ func resourceMsSqlVirtualMachineAutoBackupSettingsRefreshFunc(ctx context.Contex } } -func expandSqlVirtualMachineAutoBackupSettings(input []interface{}) *sqlvirtualmachines.AutoBackupSettings { +func expandSqlVirtualMachineAutoBackupSettings(input []interface{}) (*sqlvirtualmachines.AutoBackupSettings, error) { ret := sqlvirtualmachines.AutoBackupSettings{ Enable: utils.Bool(false), } @@ -759,23 +803,24 @@ func expandSqlVirtualMachineAutoBackupSettings(input []interface{}) *sqlvirtualm backupScheduleTypeManual := sqlvirtualmachines.BackupScheduleTypeManual ret.BackupScheduleType = &backupScheduleTypeManual - if v, ok := manualSchedule["full_backup_frequency"]; ok { - fullBackupFrequencyType := sqlvirtualmachines.FullBackupFrequencyType(v.(string)) - ret.FullBackupFrequency = &fullBackupFrequencyType - } - if v, ok := manualSchedule["full_backup_start_hour"]; ok { - ret.FullBackupStartTime = utils.Int64(int64(v.(int))) - } - if v, ok := manualSchedule["full_backup_window_in_hours"]; ok { - ret.FullBackupWindowHours = utils.Int64(int64(v.(int))) - } - if v, ok := manualSchedule["log_backup_frequency_in_minutes"]; ok { - ret.LogBackupFrequency = utils.Int64(int64(v.(int))) + fullBackupFrequency := sqlvirtualmachines.FullBackupFrequencyType(manualSchedule["full_backup_frequency"].(string)) + + daysOfWeek := manualSchedule["days_of_week"].(*pluginsdk.Set).List() + if len(daysOfWeek) > 0 { + if !strings.EqualFold(string(fullBackupFrequency), string(sqlvirtualmachines.FullBackupFrequencyTypeWeekly)) { + return nil, fmt.Errorf("`manual_schedule.0.days_of_week` can only be specified when `manual_schedule.0.full_backup_frequency` is set to `Weekly`") + } + ret.DaysOfWeek = expandSqlVirtualMachineAutoBackupSettingsDaysOfWeek(daysOfWeek) } + + ret.FullBackupFrequency = &fullBackupFrequency + ret.FullBackupStartTime = utils.Int64(int64(manualSchedule["full_backup_start_hour"].(int))) + ret.FullBackupWindowHours = utils.Int64(int64(manualSchedule["full_backup_window_in_hours"].(int))) + ret.LogBackupFrequency = utils.Int64(int64(manualSchedule["log_backup_frequency_in_minutes"].(int))) } } - return &ret + return &ret, nil } func flattenSqlVirtualMachineAutoBackup(autoBackup *sqlvirtualmachines.AutoBackupSettings, d *pluginsdk.ResourceData) []interface{} { @@ -815,6 +860,7 @@ func flattenSqlVirtualMachineAutoBackup(autoBackup *sqlvirtualmachines.AutoBacku "full_backup_start_hour": fullBackupStartHour, "full_backup_window_in_hours": fullBackupWindowHours, "log_backup_frequency_in_minutes": logBackupFrequency, + "days_of_week": flattenSqlVirtualMachineAutoBackupDaysOfWeek(autoBackup.DaysOfWeek), }, } } @@ -843,6 +889,26 @@ func flattenSqlVirtualMachineAutoBackup(autoBackup *sqlvirtualmachines.AutoBacku } } +func expandSqlVirtualMachineAutoBackupSettingsDaysOfWeek(input []interface{}) *[]sqlvirtualmachines.AutoBackupDaysOfWeek { + result := make([]sqlvirtualmachines.AutoBackupDaysOfWeek, 0) + for _, item := range input { + result = append(result, sqlvirtualmachines.AutoBackupDaysOfWeek(item.(string))) + } + return &result +} + +func flattenSqlVirtualMachineAutoBackupDaysOfWeek(daysOfWeek *[]sqlvirtualmachines.AutoBackupDaysOfWeek) []interface{} { + output := make([]interface{}, 0) + + if daysOfWeek != nil { + for _, v := range *daysOfWeek { + output = append(output, string(v)) + } + } + + return output +} + func resourceMsSqlVirtualMachineAutoPatchingSettingsRefreshFunc(ctx context.Context, client *sqlvirtualmachines.SqlVirtualMachinesClient, d *pluginsdk.ResourceData) pluginsdk.StateRefreshFunc { return func() (interface{}, string, error) { id, err := sqlvirtualmachines.ParseSqlVirtualMachineID(d.Id()) diff --git a/internal/services/mssql/mssql_virtual_machine_resource_test.go b/internal/services/mssql/mssql_virtual_machine_resource_test.go index 7f606de3601b..eaeabe0adce7 100644 --- a/internal/services/mssql/mssql_virtual_machine_resource_test.go +++ b/internal/services/mssql/mssql_virtual_machine_resource_test.go @@ -103,6 +103,28 @@ func TestAccMsSqlVirtualMachine_autoBackup(t *testing.T) { }) } +func TestAccMsSqlVirtualMachine_autoBackupDaysOfWeek(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_virtual_machine", "test") + r := MsSqlVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.withAutoBackupManualScheduleDaysOfWeek(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("auto_backup.0.encryption_password", "auto_backup.0.storage_account_access_key", "auto_backup.0.storage_blob_endpoint"), + { + Config: r.withAutoBackupManualScheduleDaysOfWeekUpdated(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("auto_backup.0.encryption_password", "auto_backup.0.storage_account_access_key", "auto_backup.0.storage_blob_endpoint"), + }) +} + func TestAccMsSqlVirtualMachine_autoPatching(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_mssql_virtual_machine", "test") r := MsSqlVirtualMachineResource{} @@ -572,6 +594,74 @@ resource "azurerm_mssql_virtual_machine" "test" { `, r.template(data), data.RandomString) } +func (r MsSqlVirtualMachineResource) withAutoBackupManualScheduleDaysOfWeek(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%[2]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_mssql_virtual_machine" "test" { + virtual_machine_id = azurerm_virtual_machine.test.id + sql_license_type = "PAYG" + + auto_backup { + retention_period_in_days = 14 + storage_blob_endpoint = azurerm_storage_account.test.primary_blob_endpoint + storage_account_access_key = azurerm_storage_account.test.primary_access_key + system_databases_backup_enabled = true + + manual_schedule { + full_backup_frequency = "Weekly" + full_backup_start_hour = 3 + full_backup_window_in_hours = 4 + log_backup_frequency_in_minutes = 60 + days_of_week = ["Monday", "Tuesday"] + } + } +} +`, r.template(data), data.RandomString) +} + +func (r MsSqlVirtualMachineResource) withAutoBackupManualScheduleDaysOfWeekUpdated(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_storage_account" "test" { + name = "unlikely23exst2acct%[2]s" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + account_tier = "Standard" + account_replication_type = "LRS" +} + +resource "azurerm_mssql_virtual_machine" "test" { + virtual_machine_id = azurerm_virtual_machine.test.id + sql_license_type = "PAYG" + + auto_backup { + retention_period_in_days = 14 + storage_blob_endpoint = azurerm_storage_account.test.primary_blob_endpoint + storage_account_access_key = azurerm_storage_account.test.primary_access_key + system_databases_backup_enabled = true + + manual_schedule { + full_backup_frequency = "Weekly" + full_backup_start_hour = 3 + full_backup_window_in_hours = 4 + log_backup_frequency_in_minutes = 60 + days_of_week = ["Friday", "Monday", "Tuesday"] + } + } +} +`, r.template(data), data.RandomString) +} + func (r MsSqlVirtualMachineResource) withKeyVault(data acceptance.TestData) string { return fmt.Sprintf(` %[1]s diff --git a/website/docs/r/mssql_virtual_machine.html.markdown b/website/docs/r/mssql_virtual_machine.html.markdown index 7396c0ab2a63..3f7ba85aeb18 100644 --- a/website/docs/r/mssql_virtual_machine.html.markdown +++ b/website/docs/r/mssql_virtual_machine.html.markdown @@ -99,6 +99,10 @@ The `manual_schedule` block supports the following: * `log_backup_frequency_in_minutes` - (Required) Frequency of log backups, in minutes. Valid values are from `5` to `60`. +* `days_of_week` - (Optional) A list of days on which backup can take place. Possible values are `Monday`, `Tuesday`, `Wednesday`, `Thursday`, `Friday`, `Saturday` and `Sunday` + +* ~> **NOTE:** `days_of_week` can only be specified when `manual_schedule` is set to `Weekly` + --- The `auto_patching` block supports the following: From 93b7015399f7473a859586554f4efdd4e5837f9e Mon Sep 17 00:00:00 2001 From: kt Date: Mon, 5 Dec 2022 10:36:41 -0800 Subject: [PATCH 06/19] CHANGELOG #19553 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fee18a3ed515..d6203d92aa62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ENHANCEMENTS: * `lighthouse`: updating to API version `2022-10-01` [GH-19499] +* `azurerm_mssql_virtual_machine` - support for the `days_of_week` property [GH-19553] BUG FIXES: From a4023a4e79d01d6b726dc5024eb0c5d0037c76c4 Mon Sep 17 00:00:00 2001 From: Elena Xin <39109137+sinbai@users.noreply.github.com> Date: Tue, 6 Dec 2022 02:56:07 +0800 Subject: [PATCH 07/19] `azurerm_lb` - Fix adding/removing a frontend configuration forces recreation of loadbalancer issue (#19548) Fix https://github.com/hashicorp/terraform-provider-azurerm/issues/19260 --- .../loadbalancer/loadbalancer_resource.go | 31 ++++++++- .../loadbalancer_resource_test.go | 63 +++++++++++++++++++ internal/tf/pluginsdk/customize_diff.go | 16 +++++ 3 files changed, 109 insertions(+), 1 deletion(-) diff --git a/internal/services/loadbalancer/loadbalancer_resource.go b/internal/services/loadbalancer/loadbalancer_resource.go index 2d93e0aa5c7c..78f9725326c7 100644 --- a/internal/services/loadbalancer/loadbalancer_resource.go +++ b/internal/services/loadbalancer/loadbalancer_resource.go @@ -1,8 +1,11 @@ package loadbalancer import ( + "context" "fmt" "log" + "reflect" + "strconv" "strings" "time" @@ -10,6 +13,7 @@ import ( "github.com/hashicorp/go-azure-helpers/resourcemanager/edgezones" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" "github.com/hashicorp/go-azure-helpers/resourcemanager/zones" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -45,6 +49,30 @@ func resourceArmLoadBalancer() *pluginsdk.Resource { }, Schema: resourceArmLoadBalancerSchema(), + + CustomizeDiff: pluginsdk.CustomDiffWithAll( + pluginsdk.ForceNewIf("frontend_ip_configuration", func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bool { + old, new := d.GetChange("frontend_ip_configuration") + if len(old.([]interface{})) == 0 && len(new.([]interface{})) > 0 || len(old.([]interface{})) > 0 && len(new.([]interface{})) == 0 { + return false + } else { + for i, nc := range new.([]interface{}) { + dataNew := nc.(map[string]interface{}) + for _, oc := range old.([]interface{}) { + dataOld := oc.(map[string]interface{}) + if dataOld["name"].(string) == dataNew["name"].(string) { + if !reflect.DeepEqual(dataOld["zones"].(*pluginsdk.Set).List(), dataNew["zones"].(*pluginsdk.Set).List()) { + // set ForceNew to true when the `frontend_ip_configuration.#.zones` is changed. + d.ForceNew("frontend_ip_configuration." + strconv.Itoa(i) + ".zones") + break + } + } + } + } + } + return false + }), + ), } } @@ -58,6 +86,7 @@ func resourceArmLoadBalancerCreateUpdate(d *pluginsdk.ResourceData, meta interfa id := parse.NewLoadBalancerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + log.Printf("elena: is new resource : %t", d.IsNewResource()) if d.IsNewResource() { existing, err := client.Get(ctx, id.ResourceGroup, id.Name, "") if err != nil { @@ -495,7 +524,7 @@ func resourceArmLoadBalancerSchema() map[string]*pluginsdk.Schema { Set: pluginsdk.HashString, }, - "zones": commonschema.ZonesMultipleOptionalForceNew(), + "zones": commonschema.ZonesMultipleOptional(), "id": { Type: pluginsdk.TypeString, diff --git a/internal/services/loadbalancer/loadbalancer_resource_test.go b/internal/services/loadbalancer/loadbalancer_resource_test.go index 745907799756..61912e69573c 100644 --- a/internal/services/loadbalancer/loadbalancer_resource_test.go +++ b/internal/services/loadbalancer/loadbalancer_resource_test.go @@ -169,6 +169,13 @@ func TestAccAzureRMLoadBalancer_zonesSingle(t *testing.T) { r := LoadBalancer{} data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.standard(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), { Config: r.zonesSingle(data), Check: acceptance.ComposeTestCheckFunc( @@ -176,6 +183,20 @@ func TestAccAzureRMLoadBalancer_zonesSingle(t *testing.T) { ), }, data.ImportStep(), + { + Config: r.zonesSingleUpdated(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.standard(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), }) } @@ -601,6 +622,48 @@ resource "azurerm_lb" "test" { `, data.RandomInteger, data.Locations.Primary) } +func (r LoadBalancer) zonesSingleUpdated(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-lb-%[1]d" + location = "%[2]s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctvn-%[1]d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "acctsub-%[1]d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.2.0/24"] +} + +resource "azurerm_lb" "test" { + name = "acctestlb-%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard" + + frontend_ip_configuration { + name = "Internal" + private_ip_address_allocation = "Static" + private_ip_address_version = "IPv4" + private_ip_address = "10.0.2.7" + subnet_id = azurerm_subnet.test.id + } +} +`, data.RandomInteger, data.Locations.Primary) +} + func (r LoadBalancer) zonesMultiple(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/internal/tf/pluginsdk/customize_diff.go b/internal/tf/pluginsdk/customize_diff.go index 3e9002b02ee6..3e8c5edae3be 100644 --- a/internal/tf/pluginsdk/customize_diff.go +++ b/internal/tf/pluginsdk/customize_diff.go @@ -10,6 +10,7 @@ import ( type ( CustomizeDiffFunc = func(context.Context, *ResourceDiff, interface{}) error ValueChangeConditionFunc = func(ctx context.Context, old, new, meta interface{}) bool + ResourceConditionFunc = func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bool ) // CustomDiffWithAll returns a CustomizeDiffFunc that runs all of the given @@ -68,3 +69,18 @@ func ForceNewIfChange(key string, f ValueChangeConditionFunc) CustomizeDiffFunc return nil } } + +// ForceNewIf returns a CustomizeDiffFunc that flags the given key as +// requiring a new resource if the given condition function returns true. +// +// The return value of the condition function is ignored if the old and new +// values of the field compare equal, since no attribute diff is generated in +// that case. +func ForceNewIf(key string, f ResourceConditionFunc) CustomizeDiffFunc { + return func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error { + if f(ctx, d, meta) { + d.ForceNew(key) + } + return nil + } +} From b132c32a580595b12afb137eef528643794096cc Mon Sep 17 00:00:00 2001 From: kt Date: Mon, 5 Dec 2022 10:56:52 -0800 Subject: [PATCH 08/19] Update CHANGELOG.md CHANGELOG #19548 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6203d92aa62..316a3545a6a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ BUG FIXES: * `azurerm_frontdoor_rules_engine` - a state migration to work around the previously incorrect id casing [GH-19512] * `azurerm_healthcare_*` - a state migration to work around the previously incorrect id casing [GH-19511] * `azurerm_iothub_x` - a state migration to work around the previously incorrect id casing [GH-19524] +* `azurerm_lb` - adding/removing a frontend configuration will no longer force recreation a new resource to be created [GH-19548] * `azurerm_kusto_*` - a state migration to work around the previously incorrect id casing [GH-19525] * `azurerm_monitor_smart_detector_alert_rule` - a state migration to work around the previously incorrect id casing [GH-19513] From bb226cdddf8beae3b31799294facbda486db885f Mon Sep 17 00:00:00 2001 From: Xiaxin <92154856+xiaxyi@users.noreply.github.com> Date: Tue, 6 Dec 2022 03:15:27 +0800 Subject: [PATCH 09/19] `azurerm_app_service_connection` - fix the secret type issue. (#19519) fix https://github.com/hashicorp/terraform-provider-azurerm/issues/19439 --- internal/services/appservice/helpers/web_app_schema.go | 3 +++ internal/services/serviceconnector/helper.go | 10 ++++++---- .../service_connector_app_service_resource.go | 4 +++- .../service_connector_spring_cloud_resource.go | 3 ++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/internal/services/appservice/helpers/web_app_schema.go b/internal/services/appservice/helpers/web_app_schema.go index fcb14e1ee051..3f068e8cdab1 100644 --- a/internal/services/appservice/helpers/web_app_schema.go +++ b/internal/services/appservice/helpers/web_app_schema.go @@ -3821,6 +3821,9 @@ func FlattenAppSettings(input web.StringDictionary) (map[string]string, *int) { "WEBSITE_HTTPLOGGING_CONTAINER_URL", "WEBSITE_HTTPLOGGING_RETENTION_DAYS", "WEBSITE_VNET_ROUTE_ALL", + "spring.datasource.password", + "spring.datasource.url", + "spring.datasource.username", maxPingFailures, } diff --git a/internal/services/serviceconnector/helper.go b/internal/services/serviceconnector/helper.go index 4af9cca9c8f1..68dbb4029cbc 100644 --- a/internal/services/serviceconnector/helper.go +++ b/internal/services/serviceconnector/helper.go @@ -118,8 +118,10 @@ func expandServiceConnectorAuthInfo(input []AuthInfoModel) (servicelinker.AuthIn return nil, fmt.Errorf("`secret` cannot be set when `name` is empty") } return servicelinker.SecretAuthInfo{ - Name: utils.String(name), - SecretInfo: secret, + Name: utils.String(name), + SecretInfo: servicelinker.ValueSecretInfo{ + Value: utils.String(secret), + }, }, nil case servicelinker.AuthTypeSystemAssignedIdentity: @@ -206,7 +208,7 @@ func expandServiceConnectorAuthInfo(input []AuthInfoModel) (servicelinker.AuthIn return nil, fmt.Errorf("unsupported authentication type %q", authType) } -func flattenServiceConnectorAuthInfo(input servicelinker.AuthInfoBase) []AuthInfoModel { +func flattenServiceConnectorAuthInfo(input servicelinker.AuthInfoBase, pwd string) []AuthInfoModel { var authType string var name string var secret string @@ -220,7 +222,7 @@ func flattenServiceConnectorAuthInfo(input servicelinker.AuthInfoBase) []AuthInf if value.Name != nil { name = *value.Name } - secret = value.SecretInfo.(string) + secret = pwd } if _, ok := input.(servicelinker.SystemAssignedIdentityAuthInfo); ok { diff --git a/internal/services/serviceconnector/service_connector_app_service_resource.go b/internal/services/serviceconnector/service_connector_app_service_resource.go index 1dba7ec26303..8f762449a1b1 100644 --- a/internal/services/serviceconnector/service_connector_app_service_resource.go +++ b/internal/services/serviceconnector/service_connector_app_service_resource.go @@ -183,6 +183,8 @@ func (r AppServiceConnectorResource) Read() sdk.ResourceFunc { return fmt.Errorf("reading %s: %+v", *id, err) } + pwd := metadata.ResourceData.Get("authentication.0.secret").(string) + if model := resp.Model; model != nil { props := model.Properties if props.AuthInfo == nil || props.TargetService == nil { @@ -193,7 +195,7 @@ func (r AppServiceConnectorResource) Read() sdk.ResourceFunc { Name: id.LinkerName, AppServiceId: id.ResourceUri, TargetResourceId: flattenTargetService(props.TargetService), - AuthInfo: flattenServiceConnectorAuthInfo(props.AuthInfo), + AuthInfo: flattenServiceConnectorAuthInfo(props.AuthInfo, pwd), } if props.ClientType != nil { diff --git a/internal/services/serviceconnector/service_connector_spring_cloud_resource.go b/internal/services/serviceconnector/service_connector_spring_cloud_resource.go index 5dbcf824ea97..3fa1dec2a3b1 100644 --- a/internal/services/serviceconnector/service_connector_spring_cloud_resource.go +++ b/internal/services/serviceconnector/service_connector_spring_cloud_resource.go @@ -185,6 +185,7 @@ func (r SpringCloudConnectorResource) Read() sdk.ResourceFunc { return fmt.Errorf("reading %s: %+v", *id, err) } + pwd := metadata.ResourceData.Get("authentication.0.secret").(string) if model := resp.Model; model != nil { props := model.Properties if props.AuthInfo == nil || props.TargetService == nil { @@ -195,7 +196,7 @@ func (r SpringCloudConnectorResource) Read() sdk.ResourceFunc { Name: id.LinkerName, SpringCloudId: id.ResourceUri, TargetResourceId: flattenTargetService(props.TargetService), - AuthInfo: flattenServiceConnectorAuthInfo(props.AuthInfo), + AuthInfo: flattenServiceConnectorAuthInfo(props.AuthInfo, pwd), } if props.ClientType != nil { From 673926918a6879ae86c66b6eb3873479a94efe85 Mon Sep 17 00:00:00 2001 From: kt Date: Mon, 5 Dec 2022 11:16:10 -0800 Subject: [PATCH 10/19] Update CHANGELOG.md CHANGELOG #19519 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 316a3545a6a0..77d5617e35ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ENHANCEMENTS: BUG FIXES: +* `azurerm_app_service_connection` - correctly pass the secret to the service [GH-19519] * `azurerm_automation_software_update_configuration` - fix issue where omitting `tags`and `tag_filter` result in an error [GH-19516] * `azurerm_automation_source_control` - a state migration to work around the previously incorrect id casing [GH-19506] * `azurerm_automation_webhook` - a state migration to work around the previously incorrect id casing [GH-19506] From 9384b027ae6056595471d93fcfe2580daa3ef400 Mon Sep 17 00:00:00 2001 From: Tao <104055472+teowa@users.noreply.github.com> Date: Tue, 6 Dec 2022 04:04:08 +0800 Subject: [PATCH 11/19] `azurerm_key_vault` - fix two kv in different sub issue (#19531) resolves https://github.com/hashicorp/terraform-provider-azurerm/issues/19509 --- internal/services/keyvault/client/helpers.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/services/keyvault/client/helpers.go b/internal/services/keyvault/client/helpers.go index e2f0cd02533f..440be0065ea9 100644 --- a/internal/services/keyvault/client/helpers.go +++ b/internal/services/keyvault/client/helpers.go @@ -45,11 +45,12 @@ func (c *Client) BaseUriForKeyVault(ctx context.Context, keyVaultId parse.VaultI lock[cacheKey].Lock() defer lock[cacheKey].Unlock() + vaultsClient := c.VaultsClient if keyVaultId.SubscriptionId != c.VaultsClient.SubscriptionID { - c.VaultsClient = c.KeyVaultClientForSubscription(keyVaultId.SubscriptionId) + vaultsClient = c.KeyVaultClientForSubscription(keyVaultId.SubscriptionId) } - resp, err := c.VaultsClient.Get(ctx, keyVaultId.ResourceGroup, keyVaultId.Name) + resp, err := vaultsClient.Get(ctx, keyVaultId.ResourceGroup, keyVaultId.Name) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return nil, fmt.Errorf("%s was not found", keyVaultId) From 37f6268c31308d375bd3c23e2792962ce6e62b25 Mon Sep 17 00:00:00 2001 From: kt Date: Mon, 5 Dec 2022 12:05:07 -0800 Subject: [PATCH 12/19] Update CHANGELOG.md CHANGELOG #19531 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77d5617e35ba..32b8b4021a42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ BUG FIXES: * `azurerm_frontdoor_rules_engine` - a state migration to work around the previously incorrect id casing [GH-19512] * `azurerm_healthcare_*` - a state migration to work around the previously incorrect id casing [GH-19511] * `azurerm_iothub_x` - a state migration to work around the previously incorrect id casing [GH-19524] +* `azurerm_key_vault` - allow for keyvaults in two different subscriptions [GH-19531] * `azurerm_lb` - adding/removing a frontend configuration will no longer force recreation a new resource to be created [GH-19548] * `azurerm_kusto_*` - a state migration to work around the previously incorrect id casing [GH-19525] * `azurerm_monitor_smart_detector_alert_rule` - a state migration to work around the previously incorrect id casing [GH-19513] From 5827173391433bd516541700beef5f3ecc0b71b9 Mon Sep 17 00:00:00 2001 From: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Tue, 6 Dec 2022 04:07:11 +0800 Subject: [PATCH 13/19] new resource: `azurerm_spring_cloud_application_live_view` (#19495) --- internal/provider/services.go | 1 + .../services/springcloud/client/client.go | 5 + .../spring_cloud_application_live_view.go | 75 +++++++++ ...spring_cloud_application_live_view_test.go | 128 +++++++++++++++ internal/services/springcloud/registration.go | 15 +- internal/services/springcloud/resourceids.go | 1 + ...ng_cloud_application_live_view_resource.go | 155 ++++++++++++++++++ ...oud_application_live_view_resource_test.go | 105 ++++++++++++ .../spring_cloud_application_live_view_id.go | 23 +++ ...ing_cloud_application_live_view_id_test.go | 88 ++++++++++ ..._cloud_application_live_view.html.markdown | 69 ++++++++ 11 files changed, 664 insertions(+), 1 deletion(-) create mode 100644 internal/services/springcloud/parse/spring_cloud_application_live_view.go create mode 100644 internal/services/springcloud/parse/spring_cloud_application_live_view_test.go create mode 100644 internal/services/springcloud/spring_cloud_application_live_view_resource.go create mode 100644 internal/services/springcloud/spring_cloud_application_live_view_resource_test.go create mode 100644 internal/services/springcloud/validate/spring_cloud_application_live_view_id.go create mode 100644 internal/services/springcloud/validate/spring_cloud_application_live_view_id_test.go create mode 100644 website/docs/r/spring_cloud_application_live_view.html.markdown diff --git a/internal/provider/services.go b/internal/provider/services.go index 3f04cdd0e438..40b1569b06e8 100644 --- a/internal/provider/services.go +++ b/internal/provider/services.go @@ -152,6 +152,7 @@ func SupportedTypedServices() []sdk.TypedServiceRegistration { orbital.Registration{}, streamanalytics.Registration{}, search.Registration{}, + springcloud.Registration{}, web.Registration{}, } services = append(services, autoRegisteredTypedServices()...) diff --git a/internal/services/springcloud/client/client.go b/internal/services/springcloud/client/client.go index 0799235d2227..317d553bf10d 100644 --- a/internal/services/springcloud/client/client.go +++ b/internal/services/springcloud/client/client.go @@ -8,6 +8,7 @@ import ( type Client struct { APIPortalClient *appplatform.APIPortalsClient APIPortalCustomDomainClient *appplatform.APIPortalCustomDomainsClient + ApplicationLiveViewsClient *appplatform.ApplicationLiveViewsClient AppsClient *appplatform.AppsClient BindingsClient *appplatform.BindingsClient BuildPackBindingClient *appplatform.BuildpackBindingClient @@ -34,6 +35,9 @@ func NewClient(o *common.ClientOptions) *Client { apiPortalCustomDomainClient := appplatform.NewAPIPortalCustomDomainsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&apiPortalCustomDomainClient.Client, o.ResourceManagerAuthorizer) + applicationLiveViewsClient := appplatform.NewApplicationLiveViewsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&applicationLiveViewsClient.Client, o.ResourceManagerAuthorizer) + appsClient := appplatform.NewAppsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&appsClient.Client, o.ResourceManagerAuthorizer) @@ -88,6 +92,7 @@ func NewClient(o *common.ClientOptions) *Client { return &Client{ APIPortalClient: &apiPortalClient, APIPortalCustomDomainClient: &apiPortalCustomDomainClient, + ApplicationLiveViewsClient: &applicationLiveViewsClient, AppsClient: &appsClient, BindingsClient: &bindingsClient, BuildPackBindingClient: &buildpackBindingClient, diff --git a/internal/services/springcloud/parse/spring_cloud_application_live_view.go b/internal/services/springcloud/parse/spring_cloud_application_live_view.go new file mode 100644 index 000000000000..a498b4a4de0c --- /dev/null +++ b/internal/services/springcloud/parse/spring_cloud_application_live_view.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +type SpringCloudApplicationLiveViewId struct { + SubscriptionId string + ResourceGroup string + SpringName string + ApplicationLiveViewName string +} + +func NewSpringCloudApplicationLiveViewID(subscriptionId, resourceGroup, springName, applicationLiveViewName string) SpringCloudApplicationLiveViewId { + return SpringCloudApplicationLiveViewId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + SpringName: springName, + ApplicationLiveViewName: applicationLiveViewName, + } +} + +func (id SpringCloudApplicationLiveViewId) String() string { + segments := []string{ + fmt.Sprintf("Application Live View Name %q", id.ApplicationLiveViewName), + fmt.Sprintf("Spring Name %q", id.SpringName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Spring Cloud Application Live View", segmentsStr) +} + +func (id SpringCloudApplicationLiveViewId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.AppPlatform/Spring/%s/applicationLiveViews/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.SpringName, id.ApplicationLiveViewName) +} + +// SpringCloudApplicationLiveViewID parses a SpringCloudApplicationLiveView ID into an SpringCloudApplicationLiveViewId struct +func SpringCloudApplicationLiveViewID(input string) (*SpringCloudApplicationLiveViewId, error) { + id, err := resourceids.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := SpringCloudApplicationLiveViewId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.SpringName, err = id.PopSegment("Spring"); err != nil { + return nil, err + } + if resourceId.ApplicationLiveViewName, err = id.PopSegment("applicationLiveViews"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/internal/services/springcloud/parse/spring_cloud_application_live_view_test.go b/internal/services/springcloud/parse/spring_cloud_application_live_view_test.go new file mode 100644 index 000000000000..9ce33a8927f4 --- /dev/null +++ b/internal/services/springcloud/parse/spring_cloud_application_live_view_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/hashicorp/go-azure-helpers/resourcemanager/resourceids" +) + +var _ resourceids.Id = SpringCloudApplicationLiveViewId{} + +func TestSpringCloudApplicationLiveViewIDFormatter(t *testing.T) { + actual := NewSpringCloudApplicationLiveViewID("12345678-1234-9876-4563-123456789012", "resourceGroup1", "service1", "default").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/applicationLiveViews/default" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestSpringCloudApplicationLiveViewID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *SpringCloudApplicationLiveViewId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/", + Error: true, + }, + + { + // missing value for SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/", + Error: true, + }, + + { + // missing ApplicationLiveViewName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/", + Error: true, + }, + + { + // missing value for ApplicationLiveViewName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/applicationLiveViews/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/applicationLiveViews/default", + Expected: &SpringCloudApplicationLiveViewId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resourceGroup1", + SpringName: "service1", + ApplicationLiveViewName: "default", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.APPPLATFORM/SPRING/SERVICE1/APPLICATIONLIVEVIEWS/DEFAULT", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := SpringCloudApplicationLiveViewID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.SpringName != v.Expected.SpringName { + t.Fatalf("Expected %q but got %q for SpringName", v.Expected.SpringName, actual.SpringName) + } + if actual.ApplicationLiveViewName != v.Expected.ApplicationLiveViewName { + t.Fatalf("Expected %q but got %q for ApplicationLiveViewName", v.Expected.ApplicationLiveViewName, actual.ApplicationLiveViewName) + } + } +} diff --git a/internal/services/springcloud/registration.go b/internal/services/springcloud/registration.go index 44698ffe3484..cbd250765f8d 100644 --- a/internal/services/springcloud/registration.go +++ b/internal/services/springcloud/registration.go @@ -7,7 +7,10 @@ import ( type Registration struct{} -var _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +var ( + _ sdk.TypedServiceRegistrationWithAGitHubLabel = Registration{} + _ sdk.UntypedServiceRegistrationWithAGitHubLabel = Registration{} +) func (r Registration) AssociatedGitHubLabel() string { return "service/spring" @@ -58,3 +61,13 @@ func (r Registration) SupportedResources() map[string]*pluginsdk.Resource { "azurerm_spring_cloud_storage": resourceSpringCloudStorage(), } } + +func (r Registration) DataSources() []sdk.DataSource { + return []sdk.DataSource{} +} + +func (r Registration) Resources() []sdk.Resource { + return []sdk.Resource{ + SpringCloudApplicationLiveViewResource{}, + } +} diff --git a/internal/services/springcloud/resourceids.go b/internal/services/springcloud/resourceids.go index a1d7374156c8..c887b6fa5295 100644 --- a/internal/services/springcloud/resourceids.go +++ b/internal/services/springcloud/resourceids.go @@ -4,6 +4,7 @@ package springcloud //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudAppAssociation -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/bindings/bind1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudAPIPortal -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/apiPortals/apiPortal1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudAPIPortalCustomDomain -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/apiPortals/apiPortal1/domains/domain1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudApplicationLiveView -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/applicationLiveViews/default //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudBuildServiceBuilder -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/buildServices/buildService1/builders/builder1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudBuildPackBinding -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/buildServices/buildService1/builders/builder1/buildPackBindings/buildPackBinding1 -rewrite=true //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=SpringCloudDeployment -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.AppPlatform/Spring/spring1/apps/app1/deployments/deploy1 diff --git a/internal/services/springcloud/spring_cloud_application_live_view_resource.go b/internal/services/springcloud/spring_cloud_application_live_view_resource.go new file mode 100644 index 000000000000..f251460ca403 --- /dev/null +++ b/internal/services/springcloud/spring_cloud_application_live_view_resource.go @@ -0,0 +1,155 @@ +package springcloud + +import ( + "context" + "fmt" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/springcloud/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/springcloud/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" + "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" + "github.com/hashicorp/terraform-provider-azurerm/utils" + "github.com/tombuildsstuff/kermit/sdk/appplatform/2022-11-01-preview/appplatform" +) + +type SpringCloudApplicationLiveViewModel struct { + Name string `tfschema:"name"` + SpringCloudServiceId string `tfschema:"spring_cloud_service_id"` +} + +type SpringCloudApplicationLiveViewResource struct{} + +var _ sdk.Resource = SpringCloudApplicationLiveViewResource{} + +func (s SpringCloudApplicationLiveViewResource) ResourceType() string { + return "azurerm_spring_cloud_application_live_view" +} + +func (s SpringCloudApplicationLiveViewResource) ModelObject() interface{} { + return &SpringCloudApplicationLiveViewModel{} +} + +func (s SpringCloudApplicationLiveViewResource) IDValidationFunc() pluginsdk.SchemaValidateFunc { + return validate.SpringCloudApplicationLiveViewID +} + +func (s SpringCloudApplicationLiveViewResource) Arguments() map[string]*schema.Schema { + return map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"default"}, false), + }, + + "spring_cloud_service_id": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.SpringCloudServiceID, + }, + } +} + +func (s SpringCloudApplicationLiveViewResource) Attributes() map[string]*schema.Schema { + return map[string]*pluginsdk.Schema{} +} + +func (s SpringCloudApplicationLiveViewResource) Create() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + var model SpringCloudApplicationLiveViewModel + if err := metadata.Decode(&model); err != nil { + return fmt.Errorf("decoding: %+v", err) + } + + client := metadata.Client.AppPlatform.ApplicationLiveViewsClient + springId, err := parse.SpringCloudServiceID(model.SpringCloudServiceId) + if err != nil { + return fmt.Errorf("parsing spring service ID: %+v", err) + } + id := parse.NewSpringCloudApplicationLiveViewID(springId.SubscriptionId, springId.ResourceGroup, springId.SpringName, model.Name) + + existing, err := client.Get(ctx, id.ResourceGroup, id.SpringName, id.ApplicationLiveViewName) + if err != nil && !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("checking for existing %s: %+v", id, err) + } + if !utils.ResponseWasNotFound(existing.Response) { + return metadata.ResourceRequiresImport(s.ResourceType(), id) + } + + applicationLiveViewResource := appplatform.ApplicationLiveViewResource{} + future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.SpringName, id.ApplicationLiveViewName, applicationLiveViewResource) + if err != nil { + return fmt.Errorf("creating %s: %+v", id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for creation of %s: %+v", id, err) + } + + metadata.SetID(id) + return nil + }, + } +} + +func (s SpringCloudApplicationLiveViewResource) Read() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 5 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.AppPlatform.ApplicationLiveViewsClient + + id, err := parse.SpringCloudApplicationLiveViewID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.SpringName, id.ApplicationLiveViewName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return metadata.MarkAsGone(id) + } + + return fmt.Errorf("retrieving %s: %+v", *id, err) + } + state := SpringCloudApplicationLiveViewModel{ + Name: id.ApplicationLiveViewName, + SpringCloudServiceId: parse.NewSpringCloudServiceID(id.SubscriptionId, id.ResourceGroup, id.SpringName).ID(), + } + return metadata.Encode(&state) + }, + } +} + +func (s SpringCloudApplicationLiveViewResource) Delete() sdk.ResourceFunc { + return sdk.ResourceFunc{ + Timeout: 30 * time.Minute, + Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { + client := metadata.Client.AppPlatform.ApplicationLiveViewsClient + + id, err := parse.SpringCloudApplicationLiveViewID(metadata.ResourceData.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.SpringName, id.ApplicationLiveViewName) + if err != nil { + return fmt.Errorf("deleting %s: %+v", *id, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if !response.WasNotFound(future.Response()) { + return fmt.Errorf("waiting for deletion of %s: %+v", *id, err) + } + } + + return nil + }, + } +} diff --git a/internal/services/springcloud/spring_cloud_application_live_view_resource_test.go b/internal/services/springcloud/spring_cloud_application_live_view_resource_test.go new file mode 100644 index 000000000000..5e9f302f16d8 --- /dev/null +++ b/internal/services/springcloud/spring_cloud_application_live_view_resource_test.go @@ -0,0 +1,105 @@ +package springcloud_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "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/springcloud/parse" + "github.com/hashicorp/terraform-provider-azurerm/utils" +) + +type SpringCloudApplicationLiveViewResource struct{} + +func TestAccSpringCloudApplicationLiveView_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_application_live_view", "test") + r := SpringCloudApplicationLiveViewResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccSpringCloudApplicationLiveView_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_spring_cloud_application_live_view", "test") + r := SpringCloudApplicationLiveViewResource{} + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.RequiresImportErrorStep(r.requiresImport), + }) +} + +func (r SpringCloudApplicationLiveViewResource) Exists(ctx context.Context, client *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.SpringCloudApplicationLiveViewID(state.ID) + if err != nil { + return nil, err + } + resp, err := client.AppPlatform.ApplicationLiveViewsClient.Get(ctx, id.ResourceGroup, id.SpringName, id.ApplicationLiveViewName) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return utils.Bool(false), nil + } + return nil, fmt.Errorf("retrieving %s: %+v", id, err) + } + return utils.Bool(true), nil +} + +func (r SpringCloudApplicationLiveViewResource) template(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-spring-%[2]d" + location = "%[1]s" +} + +resource "azurerm_spring_cloud_service" "test" { + name = "acctest-sc-%[2]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + sku_name = "E0" +} + +`, data.Locations.Primary, data.RandomInteger) +} + +func (r SpringCloudApplicationLiveViewResource) basic(data acceptance.TestData) string { + template := r.template(data) + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_application_live_view" "test" { + name = "default" + spring_cloud_service_id = azurerm_spring_cloud_service.test.id +} +`, template) +} + +func (r SpringCloudApplicationLiveViewResource) requiresImport(data acceptance.TestData) string { + config := r.basic(data) + return fmt.Sprintf(` +%s + +resource "azurerm_spring_cloud_application_live_view" "import" { + name = azurerm_spring_cloud_application_live_view.test.name + spring_cloud_service_id = azurerm_spring_cloud_application_live_view.test.spring_cloud_service_id +} +`, config) +} diff --git a/internal/services/springcloud/validate/spring_cloud_application_live_view_id.go b/internal/services/springcloud/validate/spring_cloud_application_live_view_id.go new file mode 100644 index 000000000000..d116b50fe0be --- /dev/null +++ b/internal/services/springcloud/validate/spring_cloud_application_live_view_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/hashicorp/terraform-provider-azurerm/internal/services/springcloud/parse" +) + +func SpringCloudApplicationLiveViewID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.SpringCloudApplicationLiveViewID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/internal/services/springcloud/validate/spring_cloud_application_live_view_id_test.go b/internal/services/springcloud/validate/spring_cloud_application_live_view_id_test.go new file mode 100644 index 000000000000..f7805068255d --- /dev/null +++ b/internal/services/springcloud/validate/spring_cloud_application_live_view_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestSpringCloudApplicationLiveViewID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/", + Valid: false, + }, + + { + // missing value for SpringName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/", + Valid: false, + }, + + { + // missing ApplicationLiveViewName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/", + Valid: false, + }, + + { + // missing value for ApplicationLiveViewName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/applicationLiveViews/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/applicationLiveViews/default", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESOURCEGROUP1/PROVIDERS/MICROSOFT.APPPLATFORM/SPRING/SERVICE1/APPLICATIONLIVEVIEWS/DEFAULT", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := SpringCloudApplicationLiveViewID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/website/docs/r/spring_cloud_application_live_view.html.markdown b/website/docs/r/spring_cloud_application_live_view.html.markdown new file mode 100644 index 000000000000..b7734c382214 --- /dev/null +++ b/website/docs/r/spring_cloud_application_live_view.html.markdown @@ -0,0 +1,69 @@ +--- +subcategory: "Spring Cloud" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_spring_cloud_application_live_view" +description: |- + Manages a Spring Cloud Application Live View. +--- + +# azurerm_spring_cloud_application_live_view + +-> **NOTE:** This resource is applicable only for Spring Cloud Service with enterprise tier. + +Manages a Spring Cloud Application Live View. + +## Example Usage + +```hcl +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "example" { + name = "example" + location = "West Europe" +} + +resource "azurerm_spring_cloud_service" "example" { + name = "example" + location = azurerm_resource_group.example.location + resource_group_name = azurerm_resource_group.example.name + sku_name = "E0" +} + +resource "azurerm_spring_cloud_application_live_view" "example" { + name = "default" + spring_cloud_service_id = azurerm_spring_cloud_service.example.id +} +``` + +## Arguments Reference + +The following arguments are supported: + +* `name` - (Required) The name which should be used for this Spring Cloud Application Live View. Changing this forces a new Spring Cloud Application Live View to be created. The only possible value is `default`. + +* `spring_cloud_service_id` - (Required) The ID of the Spring Cloud Service. Changing this forces a new Spring Cloud Application Live View to be created. + +## Attributes Reference + +In addition to the Arguments listed above - the following Attributes are exported: + +* `id` - The ID of the Spring Cloud Application Live View. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Spring Cloud Application Live View. +* `read` - (Defaults to 5 minutes) Used when retrieving the Spring Cloud Application Live View. +* `update` - (Defaults to 30 minutes) Used when updating the Spring Cloud Application Live View. +* `delete` - (Defaults to 30 minutes) Used when deleting the Spring Cloud Application Live View. + +## Import + +Spring Cloud Application Live Views can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_spring_cloud_application_live_view.example /subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resourceGroup1/providers/Microsoft.AppPlatform/Spring/service1/applicationLiveViews/default +``` From 4a30f9bf1f1ad90b8d1551d81b03332643e8925b Mon Sep 17 00:00:00 2001 From: kt Date: Mon, 5 Dec 2022 12:07:54 -0800 Subject: [PATCH 14/19] Update CHANGELOG.md CHANGELOG #19495 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32b8b4021a42..d1db3009e525 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## 3.35.0 (Unreleased) +FEATURES: + +* **New Resource:** `azurerm_spring_cloud_application_live_view` [GH-19495] + ENHANCEMENTS: * `lighthouse`: updating to API version `2022-10-01` [GH-19499] From d7f59ebd7491ce6e7ac37edec9564361891debe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bindewald?= Date: Mon, 5 Dec 2022 21:09:15 +0100 Subject: [PATCH 15/19] azurerm_api_management // New property `security.tls_rsa_with_aes256_gcm_sha384_ciphers_enabled` (#19472) --- .../services/apimanagement/api_management_resource.go | 10 ++++++++++ website/docs/r/api_management.html.markdown | 8 ++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/internal/services/apimanagement/api_management_resource.go b/internal/services/apimanagement/api_management_resource.go index debbd49b24d9..d4949f8c0a4f 100644 --- a/internal/services/apimanagement/api_management_resource.go +++ b/internal/services/apimanagement/api_management_resource.go @@ -45,6 +45,7 @@ var ( apimTlsEcdheRsaWithAes128CbcShaCiphers = "Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA" apimTlsRsaWithAes128GcmSha256Ciphers = "Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_GCM_SHA256" apimTlsRsaWithAes256CbcSha256Ciphers = "Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA256" + apimTlsRsaWithAes256GcmSha384Ciphers = "Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_GCM_SHA384" apimTlsRsaWithAes128CbcSha256Ciphers = "Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA256" apimTlsRsaWithAes256CbcShaCiphers = "Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA" apimTlsRsaWithAes128CbcShaCiphers = "Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA" @@ -381,6 +382,11 @@ func resourceApiManagementSchema() map[string]*pluginsdk.Schema { Optional: true, Default: false, }, + "tls_rsa_with_aes256_gcm_sha384_ciphers_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, "tls_rsa_with_aes256_cbc_sha_ciphers_enabled": { Type: pluginsdk.TypeBool, Optional: true, @@ -1583,6 +1589,7 @@ func expandApiManagementCustomProperties(d *pluginsdk.ResourceData, skuIsConsump tlsEcdheRsaWithAes256CbcShaCiphers := false tlsEcdheRsaWithAes128CbcShaCiphers := false tlsRsaWithAes128GcmSha256Ciphers := false + tlsRsaWithAes256GcmSha384Ciphers := false tlsRsaWithAes256CbcSha256Ciphers := false tlsRsaWithAes128CbcSha256Ciphers := false tlsRsaWithAes256CbcShaCiphers := false @@ -1606,6 +1613,7 @@ func expandApiManagementCustomProperties(d *pluginsdk.ResourceData, skuIsConsump tlsEcdheRsaWithAes256CbcShaCiphers = v["tls_ecdhe_rsa_with_aes256_cbc_sha_ciphers_enabled"].(bool) tlsEcdheRsaWithAes128CbcShaCiphers = v["tls_ecdhe_rsa_with_aes128_cbc_sha_ciphers_enabled"].(bool) tlsRsaWithAes128GcmSha256Ciphers = v["tls_rsa_with_aes128_gcm_sha256_ciphers_enabled"].(bool) + tlsRsaWithAes256GcmSha384Ciphers = v["tls_rsa_with_aes256_gcm_sha384_ciphers_enabled"].(bool) tlsRsaWithAes256CbcSha256Ciphers = v["tls_rsa_with_aes256_cbc_sha256_ciphers_enabled"].(bool) tlsRsaWithAes128CbcSha256Ciphers = v["tls_rsa_with_aes128_cbc_sha256_ciphers_enabled"].(bool) tlsRsaWithAes256CbcShaCiphers = v["tls_rsa_with_aes256_cbc_sha_ciphers_enabled"].(bool) @@ -1672,6 +1680,7 @@ func expandApiManagementCustomProperties(d *pluginsdk.ResourceData, skuIsConsump customProperties[apimTlsEcdheRsaWithAes256CbcShaCiphers] = utils.String(strconv.FormatBool(tlsEcdheRsaWithAes256CbcShaCiphers)) customProperties[apimTlsEcdheRsaWithAes128CbcShaCiphers] = utils.String(strconv.FormatBool(tlsEcdheRsaWithAes128CbcShaCiphers)) customProperties[apimTlsRsaWithAes128GcmSha256Ciphers] = utils.String(strconv.FormatBool(tlsRsaWithAes128GcmSha256Ciphers)) + customProperties[apimTlsRsaWithAes256GcmSha384Ciphers] = utils.String(strconv.FormatBool(tlsRsaWithAes256GcmSha384Ciphers)) customProperties[apimTlsRsaWithAes256CbcSha256Ciphers] = utils.String(strconv.FormatBool(tlsRsaWithAes256CbcSha256Ciphers)) customProperties[apimTlsRsaWithAes128CbcSha256Ciphers] = utils.String(strconv.FormatBool(tlsRsaWithAes128CbcSha256Ciphers)) customProperties[apimTlsRsaWithAes256CbcShaCiphers] = utils.String(strconv.FormatBool(tlsRsaWithAes256CbcShaCiphers)) @@ -1717,6 +1726,7 @@ func flattenApiManagementSecurityCustomProperties(input map[string]*string, skuI output["tls_ecdhe_ecdsa_with_aes128_cbc_sha_ciphers_enabled"] = parseApiManagementNilableDictionary(input, apimTlsEcdheEcdsaWithAes128CbcShaCiphers) output["tls_ecdhe_rsa_with_aes256_cbc_sha_ciphers_enabled"] = parseApiManagementNilableDictionary(input, apimTlsEcdheRsaWithAes256CbcShaCiphers) output["tls_ecdhe_rsa_with_aes128_cbc_sha_ciphers_enabled"] = parseApiManagementNilableDictionary(input, apimTlsEcdheRsaWithAes128CbcShaCiphers) + output["tls_rsa_with_aes256_gcm_sha384_ciphers_enabled"] = parseApiManagementNilableDictionary(input, apimTlsRsaWithAes256GcmSha384Ciphers) output["tls_rsa_with_aes128_gcm_sha256_ciphers_enabled"] = parseApiManagementNilableDictionary(input, apimTlsRsaWithAes128GcmSha256Ciphers) output["tls_rsa_with_aes256_cbc_sha256_ciphers_enabled"] = parseApiManagementNilableDictionary(input, apimTlsRsaWithAes256CbcSha256Ciphers) output["tls_rsa_with_aes128_cbc_sha256_ciphers_enabled"] = parseApiManagementNilableDictionary(input, apimTlsRsaWithAes128CbcSha256Ciphers) diff --git a/website/docs/r/api_management.html.markdown b/website/docs/r/api_management.html.markdown index ec8f70daaa12..abf70bca9689 100644 --- a/website/docs/r/api_management.html.markdown +++ b/website/docs/r/api_management.html.markdown @@ -251,11 +251,11 @@ A `security` block supports the following: -> **info:** This maps to the `Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA` field -* `tls_ecdheRsa_with_aes128_cbc_sha_ciphers_enabled` - (Optional) Should the `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA` cipher be enabled? Defaults to `false`. +* `tls_ecdhe_rsa_with_aes128_cbc_sha_ciphers_enabled` - (Optional) Should the `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA` cipher be enabled? Defaults to `false`. -> **info:** This maps to the `Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA` field -* `tls_ecdheRsa_with_aes256_cbc_sha_ciphers_enabled` - (Optional) Should the `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA` cipher be enabled? Defaults to `false`. +* `tls_ecdhe_rsa_with_aes256_cbc_sha_ciphers_enabled` - (Optional) Should the `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA` cipher be enabled? Defaults to `false`. -> **info:** This maps to the `Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA` field @@ -271,6 +271,10 @@ A `security` block supports the following: -> **info:** This maps to the `Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_GCM_SHA256` field +* `tls_rsa_with_aes256_gcm_sha384_ciphers_enabled` - (Optional) Should the `TLS_RSA_WITH_AES_256_GCM_SHA384` cipher be enabled? Defaults to `false`. + +-> **info:** This maps to the `Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_GCM_SHA384` field + * `tls_rsa_with_aes256_cbc_sha256_ciphers_enabled` - (Optional) Should the `TLS_RSA_WITH_AES_256_CBC_SHA256` cipher be enabled? Defaults to `false`. -> **info:** This maps to the `Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA256` field From ca434ae60e1c782a2d9297f9893677c75711801c Mon Sep 17 00:00:00 2001 From: Heng Lu <79895375+ms-henglu@users.noreply.github.com> Date: Tue, 6 Dec 2022 05:45:48 +0800 Subject: [PATCH 16/19] `azurerm_spring_cloud_gateway_route_config` - support for the `filters`, `predicates` and `sso_validation_enabled` properties (#19493) --- ...ing_cloud_gateway_route_config_resource.go | 34 +++++++++++++++++++ ...loud_gateway_route_config_resource_test.go | 3 ++ ...g_cloud_gateway_route_config.html.markdown | 6 ++++ 3 files changed, 43 insertions(+) diff --git a/internal/services/springcloud/spring_cloud_gateway_route_config_resource.go b/internal/services/springcloud/spring_cloud_gateway_route_config_resource.go index 8a2abadf0d5a..e512e3bf4820 100644 --- a/internal/services/springcloud/spring_cloud_gateway_route_config_resource.go +++ b/internal/services/springcloud/spring_cloud_gateway_route_config_resource.go @@ -87,6 +87,24 @@ func resourceSpringCloudGatewayRouteConfig() *pluginsdk.Resource { ValidateFunc: validate.SpringCloudAppID, }, + "filters": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + + "predicates": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + "route": { Type: pluginsdk.TypeSet, Optional: true, @@ -154,6 +172,11 @@ func resourceSpringCloudGatewayRouteConfig() *pluginsdk.Resource { }, }, }, + + "sso_validation_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + }, }, } } @@ -185,8 +208,11 @@ func resourceSpringCloudGatewayRouteConfigCreateUpdate(d *pluginsdk.ResourceData gatewayRouteConfigResource := appplatform.GatewayRouteConfigResource{ Properties: &appplatform.GatewayRouteConfigProperties{ AppResourceID: utils.String(d.Get("spring_cloud_app_id").(string)), + Filters: utils.ExpandStringSlice(d.Get("filters").(*pluginsdk.Set).List()), + Predicates: utils.ExpandStringSlice(d.Get("predicates").(*pluginsdk.Set).List()), Protocol: appplatform.GatewayRouteConfigProtocol(d.Get("protocol").(string)), Routes: expandGatewayRouteConfigGatewayAPIRouteArray(d.Get("route").(*pluginsdk.Set).List()), + SsoEnabled: utils.Bool(d.Get("sso_validation_enabled").(bool)), OpenAPI: expandGatewayRouteConfigOpenApi(d.Get("open_api").([]interface{})), }, } @@ -234,6 +260,14 @@ func resourceSpringCloudGatewayRouteConfigRead(d *pluginsdk.ResourceData, meta i if err := d.Set("open_api", flattenGatewayRouteConfigOpenApi(props.OpenAPI)); err != nil { return fmt.Errorf("setting `open_api`: %+v", err) } + + if props.Filters != nil { + d.Set("filters", utils.FlattenStringSlice(props.Filters)) + } + if props.Predicates != nil { + d.Set("predicates", utils.FlattenStringSlice(props.Predicates)) + } + d.Set("sso_validation_enabled", props.SsoEnabled) } return nil } diff --git a/internal/services/springcloud/spring_cloud_gateway_route_config_resource_test.go b/internal/services/springcloud/spring_cloud_gateway_route_config_resource_test.go index f53873d6d0b3..3dd36104eb11 100644 --- a/internal/services/springcloud/spring_cloud_gateway_route_config_resource_test.go +++ b/internal/services/springcloud/spring_cloud_gateway_route_config_resource_test.go @@ -167,6 +167,9 @@ resource "azurerm_spring_cloud_gateway_route_config" "test" { name = "acctest-agrc-%d" spring_cloud_gateway_id = azurerm_spring_cloud_gateway.test.id spring_cloud_app_id = azurerm_spring_cloud_app.test.id + filters = ["StripPrefix=7", "RateLimit=2,1s"] + predicates = ["Path=/defaults/customer/**"] + sso_validation_enabled = true protocol = "HTTP" route { description = "test description" diff --git a/website/docs/r/spring_cloud_gateway_route_config.html.markdown b/website/docs/r/spring_cloud_gateway_route_config.html.markdown index f57e595b249d..f665029848c2 100644 --- a/website/docs/r/spring_cloud_gateway_route_config.html.markdown +++ b/website/docs/r/spring_cloud_gateway_route_config.html.markdown @@ -69,6 +69,12 @@ The following arguments are supported: * `spring_cloud_gateway_id` - (Required) The ID of the Spring Cloud Gateway. Changing this forces a new Spring Cloud Gateway Route Config to be created. +* `filters` - (Optional) Specifies a list of filters which are used to modify the request before sending it to the target endpoint, or the received response in app level. + +* `predicates` - (Optional) Specifies a list of conditions to evaluate a route for each request in app level. Each predicate may be evaluated against request headers and parameter values. All of the predicates associated with a route must evaluate to true for the route to be matched to the request. + +* `sso_validation_enabled` - (Optional) Should the sso validation be enabled in app level? + --- * `route` - (Optional) One or more `route` blocks as defined below. From 2c8338499c1ddd91a077616fbc708f1aeaae68b5 Mon Sep 17 00:00:00 2001 From: kt Date: Mon, 5 Dec 2022 13:46:25 -0800 Subject: [PATCH 17/19] Update CHANGELOG.md CHANGELOG #19493 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1db3009e525..aae1dd8bfe94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ENHANCEMENTS: * `lighthouse`: updating to API version `2022-10-01` [GH-19499] * `azurerm_mssql_virtual_machine` - support for the `days_of_week` property [GH-19553] +* `azurerm_spring_cloud_gateway_route_config` - support for the `filters`, `predicates`, and `sso_validation_enabled` properties [GH-19493] BUG FIXES: From 23411a23232ca269f55228b8cbebe553728ac3a7 Mon Sep 17 00:00:00 2001 From: Xu Wu Date: Tue, 6 Dec 2022 06:06:28 +0800 Subject: [PATCH 18/19] `azurerm_firewall_policy` - support for `explicit_proxy` and `auto_learn_private_ranges_mode` properties (#19313) --- .../firewall/firewall_policy_resource.go | 104 ++++++++++++++++++ .../firewall/firewall_policy_resource_test.go | 18 +++ website/docs/r/firewall_policy.html.markdown | 20 ++++ 3 files changed, 142 insertions(+) diff --git a/internal/services/firewall/firewall_policy_resource.go b/internal/services/firewall/firewall_policy_resource.go index dac329f65880..675808375104 100644 --- a/internal/services/firewall/firewall_policy_resource.go +++ b/internal/services/firewall/firewall_policy_resource.go @@ -83,6 +83,7 @@ func resourceFirewallPolicyCreateUpdate(d *pluginsdk.ResourceData, meta interfac IntrusionDetection: expandFirewallPolicyIntrusionDetection(d.Get("intrusion_detection").([]interface{})), TransportSecurity: expandFirewallPolicyTransportSecurity(d.Get("tls_certificate").([]interface{})), Insights: expandFirewallPolicyInsights(d.Get("insights").([]interface{})), + ExplicitProxy: expandFirewallPolicyExplicitProxy(d.Get("explicit_proxy").([]interface{})), }, Identity: expandedIdentity, Location: utils.String(location.Normalize(d.Get("location").(string))), @@ -111,6 +112,15 @@ func resourceFirewallPolicyCreateUpdate(d *pluginsdk.ResourceData, meta interfac } } + if v, ok := d.GetOk("auto_learn_private_ranges_enabled"); ok { + if props.FirewallPolicyPropertiesFormat.Snat == nil { + props.FirewallPolicyPropertiesFormat.Snat = &network.FirewallPolicySNAT{} + } + if v.(bool) { + props.FirewallPolicyPropertiesFormat.Snat.AutoLearnPrivateRanges = network.AutoLearnPrivateRangesModeEnabled + } + } + locks.ByName(id.Name, azureFirewallPolicyResourceName) defer locks.UnlockByName(id.Name, azureFirewallPolicyResourceName) @@ -194,17 +204,28 @@ func resourceFirewallPolicyRead(d *pluginsdk.ResourceData, meta interface{}) err } var privateIPRanges []interface{} + var isAutoLearnPrivateRangeEnabled bool if prop.Snat != nil { privateIPRanges = utils.FlattenStringSlice(prop.Snat.PrivateRanges) + isAutoLearnPrivateRangeEnabled = prop.Snat.AutoLearnPrivateRanges == network.AutoLearnPrivateRangesModeEnabled } if err := d.Set("private_ip_ranges", privateIPRanges); err != nil { return fmt.Errorf("setting `private_ip_ranges`: %+v", err) } + if err := d.Set("auto_learn_private_ranges_enabled", isAutoLearnPrivateRangeEnabled); err != nil { + return fmt.Errorf("setting `auto_learn_private_ranges_enabled`: %+v", err) + } + if err := d.Set("insights", flattenFirewallPolicyInsights(prop.Insights)); err != nil { return fmt.Errorf(`setting "insights": %+v`, err) } + proxySettings := flattenFirewallPolicyExplicitProxy(prop.ExplicitProxy) + if err := d.Set("explicit_proxy", proxySettings); err != nil { + return fmt.Errorf("setting `explicit_proxy`: %+v", err) + } + if prop.SQL != nil && prop.SQL.AllowSQLRedirect != nil { if err := d.Set("sql_redirect_allowed", prop.SQL.AllowSQLRedirect); err != nil { return fmt.Errorf("setting `sql_redirect_allowed`: %+v", err) @@ -381,6 +402,31 @@ func expandFirewallPolicyInsights(input []interface{}) *network.FirewallPolicyIn return output } +func expandFirewallPolicyExplicitProxy(input []interface{}) *network.ExplicitProxy { + if len(input) == 0 || input[0] == nil { + return nil + } + + raw := input[0].(map[string]interface{}) + if raw == nil { + return nil + } + + output := &network.ExplicitProxy{ + EnableExplicitProxy: utils.Bool(raw["enabled"].(bool)), + HTTPPort: utils.Int32(int32(raw["http_port"].(int))), + HTTPSPort: utils.Int32(int32(raw["https_port"].(int))), + PacFilePort: utils.Int32(int32(raw["pac_file_port"].(int))), + PacFile: utils.String(raw["pac_file"].(string)), + } + + if val, ok := raw["enable_pac_file"]; ok { + output.EnablePacFile = utils.Bool(val.(bool)) + } + + return output +} + func expandFirewallPolicyLogAnalyticsResources(defaultWorkspaceId string, workspaces []interface{}) *network.FirewallPolicyLogAnalyticsResources { output := &network.FirewallPolicyLogAnalyticsResources{ DefaultWorkspaceID: &network.SubResource{ @@ -589,6 +635,21 @@ func flattenFirewallPolicyInsights(input *network.FirewallPolicyInsights) []inte } } +func flattenFirewallPolicyExplicitProxy(input *network.ExplicitProxy) (result []interface{}) { + if input == nil { + return + } + output := map[string]interface{}{ + "enabled": input.EnableExplicitProxy, + "http_port": input.HTTPPort, + "https_port": input.HTTPSPort, + "enable_pac_file": input.EnablePacFile, + "pac_file_port": input.PacFilePort, + "pac_file": input.PacFile, + } + return []interface{}{output} +} + func flattenFirewallPolicyLogAnalyticsResources(input *network.FirewallPolicyLogAnalyticsResources) (string, []interface{}) { if input == nil { return "", []interface{}{} @@ -883,6 +944,44 @@ func resourceFirewallPolicySchema() map[string]*pluginsdk.Schema { }, }, + "explicit_proxy": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*schema.Schema{ + "enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "http_port": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 35536), + }, + "https_port": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 35536), + }, + "enable_pac_file": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "pac_file_port": { + Type: pluginsdk.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 35536), + }, + "pac_file": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + }, + "sql_redirect_allowed": { Type: pluginsdk.TypeBool, Optional: true, @@ -925,6 +1024,11 @@ func resourceFirewallPolicySchema() map[string]*pluginsdk.Schema { }, }, + "auto_learn_private_ranges_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "tags": tags.Schema(), } } diff --git a/internal/services/firewall/firewall_policy_resource_test.go b/internal/services/firewall/firewall_policy_resource_test.go index a5cb552b3fc3..3d2003db82e3 100644 --- a/internal/services/firewall/firewall_policy_resource_test.go +++ b/internal/services/firewall/firewall_policy_resource_test.go @@ -248,6 +248,15 @@ resource "azurerm_firewall_policy" "test" { ip_addresses = ["1.1.1.1", "2.2.2.2", "10.0.0.0/16"] fqdns = ["foo.com", "bar.com"] } + explicit_proxy { + enabled = true + http_port = 8087 + https_port = 8088 + enable_pac_file = true + pac_file_port = 8089 + pac_file = "https://tinawstorage.file.core.windows.net/?sv=2020-02-10&ss=bfqt&srt=sco&sp=rwdlacuptfx&se=2021-06-04T07:01:12Z&st=2021-06-03T23:01:12Z&sip=68.65.171.11&spr=https&sig=Plsa0RRVpGbY0IETZZOT6znOHcSro71LLTTbzquYPgs%%3D" + } + auto_learn_private_ranges_enabled = true dns { servers = ["1.1.1.1", "3.3.3.3", "2.2.2.2"] proxy_enabled = true @@ -274,6 +283,15 @@ resource "azurerm_firewall_policy" "test" { ip_addresses = ["1.1.1.1", "2.2.2.2", "10.0.0.0/16"] fqdns = ["foo.com", "bar.com"] } + explicit_proxy { + enabled = true + http_port = 8087 + https_port = 8088 + enable_pac_file = true + pac_file_port = 8089 + pac_file = "https://tinawstorage.file.core.windows.net/?sv=2020-02-10&ss=bfqt&srt=sco&sp=rwdlacuptfx&se=2021-06-04T07:01:12Z&st=2021-06-03T23:01:12Z&sip=68.65.171.11&spr=https&sig=Plsa0RRVpGbY0IETZZOT6znOHcSro71LLTTbzquYPgs%%3D" + } + auto_learn_private_ranges_enabled = true dns { servers = ["1.1.1.1", "2.2.2.2"] proxy_enabled = true diff --git a/website/docs/r/firewall_policy.html.markdown b/website/docs/r/firewall_policy.html.markdown index 738c69f175bd..9f3730f0d6c3 100644 --- a/website/docs/r/firewall_policy.html.markdown +++ b/website/docs/r/firewall_policy.html.markdown @@ -49,6 +49,8 @@ The following arguments are supported: * `private_ip_ranges` - (Optional) A list of private IP ranges to which traffic will not be SNAT. +* `auto_learn_private_ranges_enabled` - (Optional) Whether enable auto learn private ip range. Defaults to `false`. + * `sku` - (Optional) The SKU Tier of the Firewall Policy. Possible values are `Standard`, `Premium` and `Basic`. Changing this forces a new Firewall Policy to be created. * `tags` - (Optional) A mapping of tags which should be assigned to the Firewall Policy. @@ -61,6 +63,8 @@ The following arguments are supported: * `sql_redirect_allowed` - (Optional) Whether SQL Redirect traffic filtering is allowed. Enabling this flag requires no rule using ports between `11000`-`11999`. +* `explicit_proxy` - (Optional) A `explicit_proxy` block as defined below. + --- A `dns` block supports the following: @@ -153,6 +157,22 @@ A `traffic_bypass` block supports the following: * `source_ip_groups` - (Optional) Specifies a list of source IP groups that shall be bypassed by intrusion detection. +--- + +A `explicit_proxy` block supports the following: + +* `enabled` (Optional) Whether the explicit proxy is enabled for this Firewall Policy. + +* `http_port` (Optional) The port number for explicit http protocol. + +* `https_port` (Optional) The port number for explicit proxy https protocol. + +* `enable_pac_file` (Optional) Whether the pac file port and url need to be provided. + +* `pac_file_port` (Optional) Specifies a port number for firewall to serve PAC file. + +* `pac_file` (Optional) Specifies a SAS URL for PAC file. + ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: From 55a2b36c2e8207e2785373dc37bd4a693ae9a6b2 Mon Sep 17 00:00:00 2001 From: kt Date: Mon, 5 Dec 2022 14:07:07 -0800 Subject: [PATCH 19/19] Update CHANGELOG.md CHANGELOG #19313 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aae1dd8bfe94..dcebdaf330c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ FEATURES: ENHANCEMENTS: * `lighthouse`: updating to API version `2022-10-01` [GH-19499] +* `azurerm_firewall_policy` - support for the `explicit_proxy` block and `auto_learn_private_ranges_mode` property [GH-19313] * `azurerm_mssql_virtual_machine` - support for the `days_of_week` property [GH-19553] * `azurerm_spring_cloud_gateway_route_config` - support for the `filters`, `predicates`, and `sso_validation_enabled` properties [GH-19493]