From a42d5d1ce71a65ab52b33e7c1ceded891ae60ae2 Mon Sep 17 00:00:00 2001 From: Yichun Ma Date: Mon, 7 Nov 2022 06:00:21 +0800 Subject: [PATCH] `azurerm_mssql_virtual_machine` - support `sql_instance_setting` (#19123) Fix https://github.com/hashicorp/terraform-provider-azurerm/issues/15824 --- .../mssql/mssql_virtual_machine_resource.go | 141 ++++++++++++++++ .../mssql_virtual_machine_resource_test.go | 150 ++++++++++++++++++ .../r/mssql_virtual_machine.html.markdown | 22 +++ 3 files changed, 313 insertions(+) diff --git a/internal/services/mssql/mssql_virtual_machine_resource.go b/internal/services/mssql/mssql_virtual_machine_resource.go index 14d9ac4c92f2..aba79cfb485e 100644 --- a/internal/services/mssql/mssql_virtual_machine_resource.go +++ b/internal/services/mssql/mssql_virtual_machine_resource.go @@ -315,6 +315,64 @@ func resourceMsSqlVirtualMachine() *pluginsdk.Resource { ValidateFunc: validate.SqlVirtualMachineLoginUserName, }, + "sql_instance": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "adhoc_workloads_optimization_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Default: false, + }, + + "collation": { + Type: pluginsdk.TypeString, + Optional: true, + ForceNew: true, + Default: "SQL_Latin1_General_CP1_CI_AS", + ValidateFunc: validate.DatabaseCollation(), + }, + + "instant_file_initialization_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + }, + + "lock_pages_in_memory_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + }, + + "max_dop": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntBetween(0, 32767), + }, + + "max_server_memory_mb": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 2147483647, + ValidateFunc: validation.IntBetween(128, 2147483647), + }, + + "min_server_memory_mb": { + Type: pluginsdk.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntBetween(0, 2147483647), + }, + }, + }, + }, + "storage_configuration": { Type: pluginsdk.TypeList, Optional: true, @@ -412,6 +470,11 @@ func resourceMsSqlVirtualMachineCreateUpdate(d *pluginsdk.ResourceData, meta int return fmt.Errorf("location is empty from making Read request on Azure Virtual Machine %s: %+v", id.SqlVirtualMachineName, err) } + sqlInstance, err := expandSqlVirtualMachineSQLInstance(d.Get("sql_instance").([]interface{})) + if err != nil { + return fmt.Errorf("expanding `sql_instance`: %+v", err) + } + connectivityType := sqlvirtualmachines.ConnectivityType(d.Get("sql_connectivity_type").(string)) sqlManagement := sqlvirtualmachines.SqlManagementModeFull sqlServerLicenseType := sqlvirtualmachines.SqlServerLicenseType(d.Get("sql_license_type").(string)) @@ -433,6 +496,7 @@ func resourceMsSqlVirtualMachineCreateUpdate(d *pluginsdk.ResourceData, meta int SqlAuthUpdatePassword: utils.String(d.Get("sql_connectivity_update_password").(string)), SqlAuthUpdateUserName: utils.String(d.Get("sql_connectivity_update_username").(string)), }, + SqlInstanceSettings: sqlInstance, }, SqlManagement: &sqlManagement, SqlServerLicenseType: &sqlServerLicenseType, @@ -546,6 +610,8 @@ func resourceMsSqlVirtualMachineRead(d *pluginsdk.ResourceData, meta interface{} d.Set("sql_connectivity_port", mgmtSettings.SqlConnectivityUpdateSettings.Port) d.Set("sql_connectivity_type", mgmtSettings.SqlConnectivityUpdateSettings.ConnectivityType) } + + d.Set("sql_instance", flattenSqlVirtualMachineSQLInstance(mgmtSettings.SqlInstanceSettings)) } // `storage_configuration.0.storage_workload_type` is in a different spot than the rest of the `storage_configuration` @@ -1166,3 +1232,78 @@ func flattenSqlVirtualMachineTempDbSettings(input *sqlvirtualmachines.SQLTempDbS return []interface{}{attrs} } +func expandSqlVirtualMachineSQLInstance(input []interface{}) (*sqlvirtualmachines.SQLInstanceSettings, error) { + if len(input) == 0 || input[0] == nil { + return &sqlvirtualmachines.SQLInstanceSettings{}, nil + } + + settings := input[0].(map[string]interface{}) + maxServerMemoryMB := settings["max_server_memory_mb"].(int) + minServerMemoryMB := settings["min_server_memory_mb"].(int) + + if maxServerMemoryMB < minServerMemoryMB { + return nil, fmt.Errorf("`max_server_memory_mb` must be greater than or equal to `min_server_memory_mb`") + } + + result := sqlvirtualmachines.SQLInstanceSettings{ + Collation: utils.String(settings["collation"].(string)), + IsIfiEnabled: utils.Bool(settings["instant_file_initialization_enabled"].(bool)), + IsLpimEnabled: utils.Bool(settings["lock_pages_in_memory_enabled"].(bool)), + IsOptimizeForAdHocWorkloadsEnabled: utils.Bool(settings["adhoc_workloads_optimization_enabled"].(bool)), + MaxDop: utils.Int64(int64(settings["max_dop"].(int))), + MaxServerMemoryMB: utils.Int64(int64(maxServerMemoryMB)), + MinServerMemoryMB: utils.Int64(int64(minServerMemoryMB)), + } + + return &result, nil +} + +func flattenSqlVirtualMachineSQLInstance(input *sqlvirtualmachines.SQLInstanceSettings) []interface{} { + if input == nil || input.Collation == nil { + return []interface{}{} + } + + collation := *input.Collation + + isIfiEnabled := false + if input.IsIfiEnabled != nil { + isIfiEnabled = *input.IsIfiEnabled + } + + isLpimEnabled := false + if input.IsLpimEnabled != nil { + isLpimEnabled = *input.IsLpimEnabled + } + + isOptimizeForAdhocWorkloadsEnabled := false + if input.IsOptimizeForAdHocWorkloadsEnabled != nil { + isOptimizeForAdhocWorkloadsEnabled = *input.IsOptimizeForAdHocWorkloadsEnabled + } + + var maxDop int64 = 0 + if input.MaxDop != nil { + maxDop = *input.MaxDop + } + + var maxServerMemoryMB int64 = 2147483647 + if input.MaxServerMemoryMB != nil { + maxServerMemoryMB = *input.MaxServerMemoryMB + } + + var minServerMemoryMB int64 = 0 + if input.MinServerMemoryMB != nil { + minServerMemoryMB = *input.MinServerMemoryMB + } + + return []interface{}{ + map[string]interface{}{ + "adhoc_workloads_optimization_enabled": isOptimizeForAdhocWorkloadsEnabled, + "collation": collation, + "instant_file_initialization_enabled": isIfiEnabled, + "lock_pages_in_memory_enabled": isLpimEnabled, + "max_dop": maxDop, + "max_server_memory_mb": maxServerMemoryMB, + "min_server_memory_mb": minServerMemoryMB, + }, + } +} diff --git a/internal/services/mssql/mssql_virtual_machine_resource_test.go b/internal/services/mssql/mssql_virtual_machine_resource_test.go index 83282bf14813..7f606de3601b 100644 --- a/internal/services/mssql/mssql_virtual_machine_resource_test.go +++ b/internal/services/mssql/mssql_virtual_machine_resource_test.go @@ -148,6 +148,80 @@ func TestAccMsSqlVirtualMachine_keyVault(t *testing.T) { }) } +func TestAccMsSqlVirtualMachine_sqlInstance(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_virtual_machine", "test") + r := MsSqlVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.sqlInstanceDefault(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("sql_instance.0.adhoc_workloads_optimization_enabled").HasValue("false"), + check.That(data.ResourceName).Key("sql_instance.0.collation").HasValue("SQL_Latin1_General_CP1_CI_AS"), + check.That(data.ResourceName).Key("sql_instance.0.instant_file_initialization_enabled").HasValue("false"), + check.That(data.ResourceName).Key("sql_instance.0.lock_pages_in_memory_enabled").HasValue("false"), + check.That(data.ResourceName).Key("sql_instance.0.max_dop").HasValue("0"), + check.That(data.ResourceName).Key("sql_instance.0.max_server_memory_mb").HasValue("2147483647"), + check.That(data.ResourceName).Key("sql_instance.0.min_server_memory_mb").HasValue("0"), + ), + }, + data.ImportStep(), + { + Config: r.sqlInstanceUpdated(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMsSqlVirtualMachine_sqlInstanceCollation(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_virtual_machine", "test") + r := MsSqlVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.sqlInstanceCollation(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMsSqlVirtualMachine_sqlInstanceInstantFileInitializationEnabled(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_virtual_machine", "test") + r := MsSqlVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.sqlInstanceInstantFileInitializationEnabled(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccMsSqlVirtualMachine_sqlInstanceLockPagesInMemoryEnabled(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_virtual_machine", "test") + r := MsSqlVirtualMachineResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.sqlInstanceLockPagesInMemoryEnabled(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccMsSqlVirtualMachine_storageConfiguration(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_mssql_virtual_machine", "test") r := MsSqlVirtualMachineResource{} @@ -654,6 +728,82 @@ resource "azurerm_mssql_virtual_machine" "test" { `, r.template(data), data.RandomInteger) } +func (r MsSqlVirtualMachineResource) sqlInstanceDefault(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_mssql_virtual_machine" "test" { + virtual_machine_id = azurerm_virtual_machine.test.id + sql_license_type = "PAYG" + + sql_instance {} +} +`, r.template(data)) +} + +func (r MsSqlVirtualMachineResource) sqlInstanceUpdated(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_mssql_virtual_machine" "test" { + virtual_machine_id = azurerm_virtual_machine.test.id + sql_license_type = "PAYG" + + sql_instance { + adhoc_workloads_optimization_enabled = true + max_dop = 3 + max_server_memory_mb = 2048 + min_server_memory_mb = 2 + } +} +`, r.template(data)) +} + +func (r MsSqlVirtualMachineResource) sqlInstanceCollation(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_mssql_virtual_machine" "test" { + virtual_machine_id = azurerm_virtual_machine.test.id + sql_license_type = "PAYG" + + sql_instance { + collation = "SQL_AltDiction_CP850_CI_AI" + } +} +`, r.template(data)) +} + +func (r MsSqlVirtualMachineResource) sqlInstanceInstantFileInitializationEnabled(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_mssql_virtual_machine" "test" { + virtual_machine_id = azurerm_virtual_machine.test.id + sql_license_type = "PAYG" + + sql_instance { + instant_file_initialization_enabled = true + } +} +`, r.template(data)) +} + +func (r MsSqlVirtualMachineResource) sqlInstanceLockPagesInMemoryEnabled(data acceptance.TestData) string { + return fmt.Sprintf(` +%[1]s + +resource "azurerm_mssql_virtual_machine" "test" { + virtual_machine_id = azurerm_virtual_machine.test.id + sql_license_type = "PAYG" + + sql_instance { + lock_pages_in_memory_enabled = true + } +} +`, r.template(data)) +} + func (r MsSqlVirtualMachineResource) storageConfiguration(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 dc59cae6bbef..498a5beb0298 100644 --- a/website/docs/r/mssql_virtual_machine.html.markdown +++ b/website/docs/r/mssql_virtual_machine.html.markdown @@ -61,6 +61,8 @@ The following arguments are supported: * `sql_connectivity_update_username` - (Optional) The SQL Server sysadmin login to create. +* `sql_instance` - (Optional) A `sql_instance` block as defined below. + * `storage_configuration` - (Optional) An `storage_configuration` block as defined below. * `assessment` - (Optional) An `assessment` block as defined below. @@ -121,6 +123,26 @@ The `key_vault_credential` block supports the following: --- +The `sql_instance` block supports the following: + +* `adhoc_workloads_optimization_enabled` - (Optional) Specifies if the SQL Server is optimized for adhoc workloads. Possible values are `true` and `false`. Defaults to `false`. + +* `collation` - (Optional) Collation of the SQL Server. Defaults to `SQL_Latin1_General_CP1_CI_AS`. Changing this forces a new resource to be created. + +* `instant_file_initialization_enabled` - (Optional) Specifies if Instant File Initialization is enabled for the SQL Server. Possible values are `true` and `false`. Defaults to `false`. Changing this forces a new resource to be created. + +* `lock_pages_in_memory_enabled` - (Optional) Specifies if Lock Pages in Memory is enabled for the SQL Server. Possible values are `true` and `false`. Defaults to `false`. Changing this forces a new resource to be created. + +* `max_dop` - (Optional) Maximum Degree of Parallelism of the SQL Server. Possible values are between `0` and `32767`. Defaults to `0`. + +* `max_server_memory_mb` - (Optional) Maximum amount memory that SQL Server Memory Manager can allocate to the SQL Server process. Possible values are between `128` and `2147483647` Defaults to `2147483647`. + +* `min_server_memory_mb` - (Optional) Minimum amount memory that SQL Server Memory Manager can allocate to the SQL Server process. Possible values are between `0` and `2147483647` Defaults to `0`. + +~> **NOTE:** `max_server_memory_mb` must be greater than or equal to `min_server_memory_mb` + +--- + The `storage_configuration` block supports the following: * `disk_type` - (Required) The type of disk configuration to apply to the SQL Server. Valid values include `NEW`, `EXTEND`, or `ADD`.