From 094d87c0870b51ba5291863920efef55c516726d Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:42:36 -0600 Subject: [PATCH 1/6] Initial Check-in... --- internal/services/mssql/helper/database.go | 6 +- .../services/mssql/mssql_database_resource.go | 59 ++++++++++--------- .../mssql/mssql_elasticpool_resource.go | 20 +++---- website/docs/r/mssql_database.html.markdown | 2 +- .../docs/r/mssql_elasticpool.html.markdown | 2 +- 5 files changed, 46 insertions(+), 43 deletions(-) diff --git a/internal/services/mssql/helper/database.go b/internal/services/mssql/helper/database.go index a8d02585097b..ff9555cd7560 100644 --- a/internal/services/mssql/helper/database.go +++ b/internal/services/mssql/helper/database.go @@ -20,7 +20,7 @@ import ( // FindDatabaseReplicationPartners looks for partner databases having one of the specified replication roles, by // reading any replication links then attempting to discover and match the corresponding server/database resources for // the other end of the link. -func FindDatabaseReplicationPartners(ctx context.Context, databasesClient *databases.DatabasesClient, replicationLinksClient *sql.ReplicationLinksClient, resourcesClient *resources.Client, id commonids.SqlDatabaseId, primaryEnclaveType databases.AlwaysEncryptedEnclaveType, rolesToFind []sql.ReplicationRole) ([]databases.Database, error) { +func FindDatabaseReplicationPartners(ctx context.Context, databasesClient *databases.DatabasesClient, replicationLinksClient *sql.ReplicationLinksClient, resourcesClient *resources.Client, id commonids.SqlDatabaseId, primaryEnclaveType string, rolesToFind []sql.ReplicationRole) ([]databases.Database, error) { var partnerDatabases []databases.Database matchesRole := func(role sql.ReplicationRole) bool { @@ -108,11 +108,11 @@ func FindDatabaseReplicationPartners(ctx context.Context, databasesClient *datab } if partnerDatabase.Id != nil && partnerDatabase.Properties != nil && partnerDatabase.Properties.PreferredEnclaveType != nil { - if primaryEnclaveType == *partnerDatabase.Properties.PreferredEnclaveType { + if primaryEnclaveType != "" && databases.AlwaysEncryptedEnclaveType(primaryEnclaveType) == *partnerDatabase.Properties.PreferredEnclaveType { log.Printf("[INFO] Found Partner %s", partnerDatabaseId) partnerDatabases = append(partnerDatabases, *partnerDatabase) } else { - log.Printf("[INFO] Mismatch of possible Partner Database based on enclave type (%s vs %s) for %s", string(primaryEnclaveType), string(*partnerDatabase.Properties.PreferredEnclaveType), id) + log.Printf("[INFO] Mismatch of possible Partner Database based on enclave type (%q vs %q) for %s", primaryEnclaveType, string(*partnerDatabase.Properties.PreferredEnclaveType), id) } } } diff --git a/internal/services/mssql/mssql_database_resource.go b/internal/services/mssql/mssql_database_resource.go index 565b51bf1445..0bb58182e9b1 100644 --- a/internal/services/mssql/mssql_database_resource.go +++ b/internal/services/mssql/mssql_database_resource.go @@ -102,10 +102,14 @@ func resourceMsSqlDatabaseImporter(ctx context.Context, d *pluginsdk.ResourceDat return nil, err } - enclaveType := databases.AlwaysEncryptedEnclaveTypeDefault - if v := d.Get("enclave_type").(string); v != "" { - enclaveType = databases.AlwaysEncryptedEnclaveTypeVBS + // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' + // field it shouldn’t be passed as part of the ARM API request for database or + // elastic pool, as it is an optional parameter and not a required one. + enclaveType := "" + if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { + enclaveType = v.(string) } + d.Set("enclave_type", enclaveType) partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, client, legacyreplicationLinksClient, resourcesClient, *id, enclaveType, []sql.ReplicationRole{sql.ReplicationRolePrimary}) if err != nil { @@ -200,11 +204,12 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er locks.ByID(id.ID()) defer locks.UnlockByID(id.ID()) - // NOTE: Set the default value, if the field exists in the config the only value - // that it could be is 'VBS'... - enclaveType := databases.AlwaysEncryptedEnclaveTypeDefault - if _, ok := d.GetOk("enclave_type"); ok { - enclaveType = databases.AlwaysEncryptedEnclaveTypeVBS + // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' + // field it shouldn’t be passed as part of the ARM API request for database or + // elastic pool, as it is an optional parameter and not a required one. + enclaveType := "" + if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { + enclaveType = v.(string) } skuName := d.Get("sku_name").(string) @@ -247,7 +252,7 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er } // NOTE: If the database is being added to an elastic pool, we need to GET the elastic pool and check - // if the 'enclave_type' match. If they don't we need to raise an error stating that they must match. + // if the 'enclave_type' matches. If they don't we need to raise an error stating that they must match. elasticPoolId := d.Get("elastic_pool_id").(string) if elasticPoolId != "" { elasticId, err := commonids.ParseSqlElasticPoolID(elasticPoolId) @@ -262,10 +267,9 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er if elasticPool.Model != nil && elasticPool.Model.Properties != nil && elasticPool.Model.Properties.PreferredEnclaveType != nil { elasticEnclaveType := string(pointer.From(elasticPool.Model.Properties.PreferredEnclaveType)) - databaseEnclaveType := string(enclaveType) - if !strings.EqualFold(elasticEnclaveType, databaseEnclaveType) { - return fmt.Errorf("adding the %s with enclave type %q to the %s with enclave type %q is not supported. Before adding a database to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, databaseEnclaveType, elasticId, elasticEnclaveType) + if !strings.EqualFold(elasticEnclaveType, enclaveType) { + return fmt.Errorf("adding the %s with enclave type %q to the %s with enclave type %q is not supported. Before adding a database to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, enclaveType, elasticId, elasticEnclaveType) } } } @@ -291,8 +295,8 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er } // NOTE: The 'PreferredEnclaveType' field cannot be passed to the APIs Create if the 'sku_name' is a DW or DC-series SKU... - if !strings.HasPrefix(strings.ToLower(skuName), "dw") && !strings.Contains(strings.ToLower(skuName), "_dc_") { - input.Properties.PreferredEnclaveType = pointer.To(enclaveType) + if !strings.HasPrefix(strings.ToLower(skuName), "dw") && !strings.Contains(strings.ToLower(skuName), "_dc_") && enclaveType != "" { + input.Properties.PreferredEnclaveType = pointer.To(databases.AlwaysEncryptedEnclaveType(enclaveType)) } createMode := d.Get("create_mode").(string) @@ -313,7 +317,7 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("retrieving creation source %s: %+v", primaryDatabaseId, err) } - if model := primaryDatabase.Model; model != nil && model.Properties != nil && model.Properties.PreferredEnclaveType != nil && enclaveType != *model.Properties.PreferredEnclaveType { + if model := primaryDatabase.Model; model != nil && model.Properties != nil && model.Properties.PreferredEnclaveType != nil && enclaveType != string(*model.Properties.PreferredEnclaveType) { return fmt.Errorf("specifying different 'enclave_type' properties for 'create_mode' %q is not supported, primary 'enclave_type' %q does not match current 'enclave_type' %q. please ensure that the 'enclave_type' is the same for both databases", createMode, string(*model.Properties.PreferredEnclaveType), string(enclaveType)) } } @@ -687,15 +691,15 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er } if d.HasChange("enclave_type") { - enclaveType := databases.AlwaysEncryptedEnclaveTypeDefault - if v := d.Get("enclave_type").(string); v != "" { - enclaveType = databases.AlwaysEncryptedEnclaveTypeVBS + enclaveType := "" + if v, ok := d.GetOk("enclave_type"); ok { + enclaveType = v.(string) } // The 'PreferredEnclaveType' field cannot be passed to the APIs Update if the // 'sku_name' is a DW or DC-series SKU... - if !strings.HasPrefix(strings.ToLower(skuName), "dw") && !strings.Contains(strings.ToLower(skuName), "_dc_") { - props.PreferredEnclaveType = pointer.To(enclaveType) + if !strings.HasPrefix(strings.ToLower(skuName), "dw") && !strings.Contains(strings.ToLower(skuName), "_dc_") && enclaveType != "" { + props.PreferredEnclaveType = pointer.To(databases.AlwaysEncryptedEnclaveType(enclaveType)) } // If the database belongs to an elastic pool, we need to GET the elastic pool and check @@ -714,10 +718,9 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er if elasticPool.Model != nil && elasticPool.Model.Properties != nil && elasticPool.Model.Properties.PreferredEnclaveType != nil { elasticEnclaveType := string(pointer.From(elasticPool.Model.Properties.PreferredEnclaveType)) - databaseEnclaveType := string(enclaveType) - if !strings.EqualFold(elasticEnclaveType, databaseEnclaveType) { - return fmt.Errorf("updating the %s with enclave type %q to the %s with enclave type %q is not supported. Before updating a database that belongs to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, databaseEnclaveType, elasticId, elasticEnclaveType) + if !strings.EqualFold(elasticEnclaveType, enclaveType) { + return fmt.Errorf("updating the %s with enclave type %q to the %s with enclave type %q is not supported. Before updating a database that belongs to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, enclaveType, elasticId, elasticEnclaveType) } } } @@ -776,9 +779,9 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er // Place a lock for the current database so any partner resources can't bump its SKU out of band if skuName != "" { - existingEnclaveType := databases.AlwaysEncryptedEnclaveTypeDefault + existingEnclaveType := "" if model := existing.Model; model != nil && model.Properties != nil && model.Properties.PreferredEnclaveType != nil { - existingEnclaveType = *model.Properties.PreferredEnclaveType + existingEnclaveType = string(*model.Properties.PreferredEnclaveType) } partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, client, legacyReplicationLinksClient, resourcesClient, id, existingEnclaveType, []sql.ReplicationRole{sql.ReplicationRoleSecondary, sql.ReplicationRoleNonReadableSecondary}) @@ -1128,8 +1131,9 @@ func resourceMsSqlDatabaseRead(d *pluginsdk.ResourceData, meta interface{}) erro ledgerEnabled = *props.IsLedgerOn } - // NOTE: Always set the PreferredEnclaveType to an empty string unless it isn't 'Default'... - if v := props.PreferredEnclaveType; v != nil && pointer.From(v) != databases.AlwaysEncryptedEnclaveTypeDefault { + // NOTE: Always set the PreferredEnclaveType to an empty string + // if not in the properties that were returned from Azure... + if v := props.PreferredEnclaveType; v != nil { enclaveType = string(pointer.From(v)) } @@ -1508,6 +1512,7 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { Optional: true, ValidateFunc: validation.StringInSlice([]string{ string(databases.AlwaysEncryptedEnclaveTypeVBS), + string(databases.AlwaysEncryptedEnclaveTypeDefault), }, false), }, diff --git a/internal/services/mssql/mssql_elasticpool_resource.go b/internal/services/mssql/mssql_elasticpool_resource.go index bd25127e48d7..6b3064b0a8b4 100644 --- a/internal/services/mssql/mssql_elasticpool_resource.go +++ b/internal/services/mssql/mssql_elasticpool_resource.go @@ -184,6 +184,7 @@ func resourceMsSqlElasticPool() *pluginsdk.Resource { Optional: true, ValidateFunc: validation.StringInSlice([]string{ string(databases.AlwaysEncryptedEnclaveTypeVBS), + string(databases.AlwaysEncryptedEnclaveTypeDefault), }, false), }, @@ -236,13 +237,6 @@ func resourceMsSqlElasticPoolCreateUpdate(d *pluginsdk.ResourceData, meta interf location := azure.NormalizeLocation(d.Get("location").(string)) sku := expandMsSqlElasticPoolSku(d) - // NOTE: Set the default value, if the field exists in the config the only value - // that it could be is 'VBS'... - enclaveType := elasticpools.AlwaysEncryptedEnclaveTypeDefault - if v, ok := d.GetOk("enclave_type"); ok { - enclaveType = elasticpools.AlwaysEncryptedEnclaveType(v.(string)) - } - maintenanceConfigId := publicmaintenanceconfigurations.NewPublicMaintenanceConfigurationID(subscriptionId, d.Get("maintenance_configuration_name").(string)) elasticPool := elasticpools.ElasticPool{ Name: pointer.To(id.ElasticPoolName), @@ -252,12 +246,18 @@ func resourceMsSqlElasticPoolCreateUpdate(d *pluginsdk.ResourceData, meta interf Properties: &elasticpools.ElasticPoolProperties{ LicenseType: pointer.To(elasticpools.ElasticPoolLicenseType(d.Get("license_type").(string))), PerDatabaseSettings: expandMsSqlElasticPoolPerDatabaseSettings(d), - PreferredEnclaveType: pointer.To(enclaveType), ZoneRedundant: pointer.To(d.Get("zone_redundant").(bool)), MaintenanceConfigurationId: pointer.To(maintenanceConfigId.ID()), }, } + // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' + // field it shouldn’t be passed as part of the ARM API request for database or + // elastic pool, as it is an optional parameter and not a required one. + if v, ok := d.GetOk("enclave_type"); ok { + elasticPool.Properties.PreferredEnclaveType = pointer.To(elasticpools.AlwaysEncryptedEnclaveType(v.(string))) + } + if d.HasChange("max_size_gb") { if v, ok := d.GetOk("max_size_gb"); ok { maxSizeBytes := v.(float64) * 1073741824 @@ -308,9 +308,7 @@ func resourceMsSqlElasticPoolRead(d *pluginsdk.ResourceData, meta interface{}) e if props := model.Properties; props != nil { enclaveType := "" - - // NOTE: Always set the PreferredEnclaveType to an empty string unless it isn't 'Default'... - if v := props.PreferredEnclaveType; v != nil && pointer.From(v) != elasticpools.AlwaysEncryptedEnclaveTypeDefault { + if v := props.PreferredEnclaveType; v != nil { enclaveType = string(pointer.From(v)) } d.Set("enclave_type", enclaveType) diff --git a/website/docs/r/mssql_database.html.markdown b/website/docs/r/mssql_database.html.markdown index 14e45f6a8c2b..f3bf789588d1 100644 --- a/website/docs/r/mssql_database.html.markdown +++ b/website/docs/r/mssql_database.html.markdown @@ -190,7 +190,7 @@ The following arguments are supported: * `elastic_pool_id` - (Optional) Specifies the ID of the elastic pool containing this database. -* `enclave_type` - (Optional) Specifies the type of enclave to be used by the database. Possible value `VBS`. +* `enclave_type` - (Optional) Specifies the type of enclave to be used by the database. Possible values are `Default` or `VBS`. ~> **NOTE:** `enclave_type` is currently not supported for DW (e.g, DataWarehouse) and DC-series SKUs. diff --git a/website/docs/r/mssql_elasticpool.html.markdown b/website/docs/r/mssql_elasticpool.html.markdown index aa7fef12a8b0..7d77574dc308 100644 --- a/website/docs/r/mssql_elasticpool.html.markdown +++ b/website/docs/r/mssql_elasticpool.html.markdown @@ -73,7 +73,7 @@ The following arguments are supported: -> **NOTE:** One of either `max_size_gb` or `max_size_bytes` must be specified. -* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. Possible value `VBS`. +* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. Possible values are `Default` or `VBS`. ~> **NOTE:** All databases that are added to the elastic pool must have the same `enclave_type` as the elastic pool. From fa9465bd21144aa33b824e686c9fb8abcbb53afe Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 4 Apr 2024 15:57:21 -0600 Subject: [PATCH 2/6] Slight tweak to behavior... --- internal/services/mssql/helper/database.go | 2 +- .../services/mssql/mssql_database_resource.go | 46 +++++++++++++------ .../mssql/mssql_database_resource_test.go | 15 ++++-- .../mssql/mssql_elasticpool_resource.go | 30 +++++++++--- .../mssql/mssql_elasticpool_resource_test.go | 13 +++++- website/docs/r/mssql_database.html.markdown | 8 ++-- .../docs/r/mssql_elasticpool.html.markdown | 2 +- 7 files changed, 83 insertions(+), 33 deletions(-) diff --git a/internal/services/mssql/helper/database.go b/internal/services/mssql/helper/database.go index ff9555cd7560..533e6d275cb2 100644 --- a/internal/services/mssql/helper/database.go +++ b/internal/services/mssql/helper/database.go @@ -20,7 +20,7 @@ import ( // FindDatabaseReplicationPartners looks for partner databases having one of the specified replication roles, by // reading any replication links then attempting to discover and match the corresponding server/database resources for // the other end of the link. -func FindDatabaseReplicationPartners(ctx context.Context, databasesClient *databases.DatabasesClient, replicationLinksClient *sql.ReplicationLinksClient, resourcesClient *resources.Client, id commonids.SqlDatabaseId, primaryEnclaveType string, rolesToFind []sql.ReplicationRole) ([]databases.Database, error) { +func FindDatabaseReplicationPartners(ctx context.Context, databasesClient *databases.DatabasesClient, replicationLinksClient *sql.ReplicationLinksClient, resourcesClient *resources.Client, id commonids.SqlDatabaseId, primaryEnclaveType databases.AlwaysEncryptedEnclaveType, rolesToFind []sql.ReplicationRole) ([]databases.Database, error) { var partnerDatabases []databases.Database matchesRole := func(role sql.ReplicationRole) bool { diff --git a/internal/services/mssql/mssql_database_resource.go b/internal/services/mssql/mssql_database_resource.go index 0bb58182e9b1..0bdf393b46fd 100644 --- a/internal/services/mssql/mssql_database_resource.go +++ b/internal/services/mssql/mssql_database_resource.go @@ -69,9 +69,20 @@ func resourceMsSqlDatabase() *pluginsdk.Resource { CustomizeDiff: pluginsdk.CustomDiffWithAll( pluginsdk.ForceNewIfChange("sku_name", func(ctx context.Context, old, new, _ interface{}) bool { - // "hyperscale can not change to other sku + // hyperscale can not be changed to another sku return strings.HasPrefix(old.(string), "HS") && !strings.HasPrefix(new.(string), "HS") }), + pluginsdk.ForceNewIfChange("enclave_type", func(ctx context.Context, old, new, _ interface{}) bool { + // enclave_type cannot be removed once it has been set + // but can be changed between VBS and Default... + // this Diff will not work until 4.0 when we remove + // the computed property from the field scheam. + if old.(string) != "" && new.(string) == "" { + return true + } + + return false + }), func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error { transparentDataEncryption := d.Get("transparent_data_encryption_enabled").(bool) skuName := d.Get("sku_name").(string) @@ -105,9 +116,9 @@ func resourceMsSqlDatabaseImporter(ctx context.Context, d *pluginsdk.ResourceDat // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' // field it shouldn’t be passed as part of the ARM API request for database or // elastic pool, as it is an optional parameter and not a required one. - enclaveType := "" + var enclaveType databases.AlwaysEncryptedEnclaveType if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { - enclaveType = v.(string) + enclaveType = databases.AlwaysEncryptedEnclaveType(v.(string)) } d.Set("enclave_type", enclaveType) @@ -207,9 +218,9 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' // field it shouldn’t be passed as part of the ARM API request for database or // elastic pool, as it is an optional parameter and not a required one. - enclaveType := "" + var enclaveType databases.AlwaysEncryptedEnclaveType if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { - enclaveType = v.(string) + enclaveType = databases.AlwaysEncryptedEnclaveType(v.(string)) } skuName := d.Get("sku_name").(string) @@ -267,9 +278,10 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er if elasticPool.Model != nil && elasticPool.Model.Properties != nil && elasticPool.Model.Properties.PreferredEnclaveType != nil { elasticEnclaveType := string(pointer.From(elasticPool.Model.Properties.PreferredEnclaveType)) + databaseEnclaveType := string(enclaveType) - if !strings.EqualFold(elasticEnclaveType, enclaveType) { - return fmt.Errorf("adding the %s with enclave type %q to the %s with enclave type %q is not supported. Before adding a database to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, enclaveType, elasticId, elasticEnclaveType) + if !strings.EqualFold(elasticEnclaveType, databaseEnclaveType) { + return fmt.Errorf("adding the %s with enclave type %q to the %s with enclave type %q is not supported. Before adding a database to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, databaseEnclaveType, elasticId, elasticEnclaveType) } } } @@ -317,7 +329,7 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("retrieving creation source %s: %+v", primaryDatabaseId, err) } - if model := primaryDatabase.Model; model != nil && model.Properties != nil && model.Properties.PreferredEnclaveType != nil && enclaveType != string(*model.Properties.PreferredEnclaveType) { + if model := primaryDatabase.Model; model != nil && model.Properties != nil && model.Properties.PreferredEnclaveType != nil && enclaveType != *model.Properties.PreferredEnclaveType { return fmt.Errorf("specifying different 'enclave_type' properties for 'create_mode' %q is not supported, primary 'enclave_type' %q does not match current 'enclave_type' %q. please ensure that the 'enclave_type' is the same for both databases", createMode, string(*model.Properties.PreferredEnclaveType), string(enclaveType)) } } @@ -691,15 +703,17 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er } if d.HasChange("enclave_type") { - enclaveType := "" - if v, ok := d.GetOk("enclave_type"); ok { - enclaveType = v.(string) + var enclaveType databases.AlwaysEncryptedEnclaveType + if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { + enclaveType = databases.AlwaysEncryptedEnclaveType(v.(string)) } // The 'PreferredEnclaveType' field cannot be passed to the APIs Update if the // 'sku_name' is a DW or DC-series SKU... if !strings.HasPrefix(strings.ToLower(skuName), "dw") && !strings.Contains(strings.ToLower(skuName), "_dc_") && enclaveType != "" { props.PreferredEnclaveType = pointer.To(databases.AlwaysEncryptedEnclaveType(enclaveType)) + } else { + props.PreferredEnclaveType = nil } // If the database belongs to an elastic pool, we need to GET the elastic pool and check @@ -718,9 +732,10 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er if elasticPool.Model != nil && elasticPool.Model.Properties != nil && elasticPool.Model.Properties.PreferredEnclaveType != nil { elasticEnclaveType := string(pointer.From(elasticPool.Model.Properties.PreferredEnclaveType)) + databaseEnclaveType := string(enclaveType) - if !strings.EqualFold(elasticEnclaveType, enclaveType) { - return fmt.Errorf("updating the %s with enclave type %q to the %s with enclave type %q is not supported. Before updating a database that belongs to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, enclaveType, elasticId, elasticEnclaveType) + if !strings.EqualFold(elasticEnclaveType, databaseEnclaveType) { + return fmt.Errorf("updating the %s with enclave type %q to the %s with enclave type %q is not supported. Before updating a database that belongs to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, databaseEnclaveType, elasticId, elasticEnclaveType) } } } @@ -779,9 +794,9 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er // Place a lock for the current database so any partner resources can't bump its SKU out of band if skuName != "" { - existingEnclaveType := "" + var existingEnclaveType databases.AlwaysEncryptedEnclaveType if model := existing.Model; model != nil && model.Properties != nil && model.Properties.PreferredEnclaveType != nil { - existingEnclaveType = string(*model.Properties.PreferredEnclaveType) + existingEnclaveType = *model.Properties.PreferredEnclaveType } partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, client, legacyReplicationLinksClient, resourcesClient, id, existingEnclaveType, []sql.ReplicationRole{sql.ReplicationRoleSecondary, sql.ReplicationRoleNonReadableSecondary}) @@ -1510,6 +1525,7 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { "enclave_type": { Type: pluginsdk.TypeString, Optional: true, + Computed: true, // TODO: Remove Computed in 4.0 ValidateFunc: validation.StringInSlice([]string{ string(databases.AlwaysEncryptedEnclaveTypeVBS), string(databases.AlwaysEncryptedEnclaveTypeDefault), diff --git a/internal/services/mssql/mssql_database_resource_test.go b/internal/services/mssql/mssql_database_resource_test.go index 73134aebdfda..c7fdc08871af 100644 --- a/internal/services/mssql/mssql_database_resource_test.go +++ b/internal/services/mssql/mssql_database_resource_test.go @@ -844,12 +844,13 @@ func TestAccMsSqlDatabase_enclaveType(t *testing.T) { } func TestAccMsSqlDatabase_enclaveTypeUpdate(t *testing.T) { + // NOTE: Once the enclave_type field has be set it cannot be changed... data := acceptance.BuildTestData(t, "azurerm_mssql_database", "test") r := MsSqlDatabaseResource{} data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.enclaveType(data, ""), + Config: r.basic(data), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("enclave_type").IsEmpty(), @@ -865,10 +866,18 @@ func TestAccMsSqlDatabase_enclaveTypeUpdate(t *testing.T) { }, data.ImportStep(), { - Config: r.enclaveType(data, ""), + Config: r.enclaveType(data, ` enclave_type = "Default"`), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("enclave_type").IsEmpty(), + check.That(data.ResourceName).Key("enclave_type").HasValue("Default"), + ), + }, + data.ImportStep(), + { + Config: r.enclaveType(data, ` enclave_type = "VBS"`), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enclave_type").HasValue("VBS"), ), }, data.ImportStep(), diff --git a/internal/services/mssql/mssql_elasticpool_resource.go b/internal/services/mssql/mssql_elasticpool_resource.go index 6b3064b0a8b4..d06d490a4bfe 100644 --- a/internal/services/mssql/mssql_elasticpool_resource.go +++ b/internal/services/mssql/mssql_elasticpool_resource.go @@ -182,6 +182,7 @@ func resourceMsSqlElasticPool() *pluginsdk.Resource { "enclave_type": { Type: pluginsdk.TypeString, Optional: true, + Computed: true, // TODO: Remove Computed in 4.0 ValidateFunc: validation.StringInSlice([]string{ string(databases.AlwaysEncryptedEnclaveTypeVBS), string(databases.AlwaysEncryptedEnclaveTypeDefault), @@ -201,13 +202,27 @@ func resourceMsSqlElasticPool() *pluginsdk.Resource { "tags": commonschema.Tags(), }, - CustomizeDiff: pluginsdk.CustomizeDiffShim(func(ctx context.Context, diff *pluginsdk.ResourceDiff, v interface{}) error { - if err := helper.MSSQLElasticPoolValidateSKU(diff); err != nil { - return err - } + CustomizeDiff: pluginsdk.CustomDiffWithAll( + func(ctx context.Context, diff *pluginsdk.ResourceDiff, v interface{}) error { + if err := helper.MSSQLElasticPoolValidateSKU(diff); err != nil { + return err + } - return nil - }), + return nil + }, + + pluginsdk.ForceNewIfChange("enclave_type", func(ctx context.Context, old, new, _ interface{}) bool { + // enclave_type cannot be removed once it has been set + // but can be changed between VBS and Default... + // this Diff will not work until 4.0 when we remove + // the computed property from the field scheam. + if old.(string) != "" && new.(string) == "" { + return true + } + + return false + }), + ), } } @@ -248,13 +263,14 @@ func resourceMsSqlElasticPoolCreateUpdate(d *pluginsdk.ResourceData, meta interf PerDatabaseSettings: expandMsSqlElasticPoolPerDatabaseSettings(d), ZoneRedundant: pointer.To(d.Get("zone_redundant").(bool)), MaintenanceConfigurationId: pointer.To(maintenanceConfigId.ID()), + PreferredEnclaveType: nil, }, } // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' // field it shouldn’t be passed as part of the ARM API request for database or // elastic pool, as it is an optional parameter and not a required one. - if v, ok := d.GetOk("enclave_type"); ok { + if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { elasticPool.Properties.PreferredEnclaveType = pointer.To(elasticpools.AlwaysEncryptedEnclaveType(v.(string))) } diff --git a/internal/services/mssql/mssql_elasticpool_resource_test.go b/internal/services/mssql/mssql_elasticpool_resource_test.go index b375d506dd16..a8684ae06c1f 100644 --- a/internal/services/mssql/mssql_elasticpool_resource_test.go +++ b/internal/services/mssql/mssql_elasticpool_resource_test.go @@ -369,6 +369,7 @@ func TestAccMsSqlElasticPool_vCoreToStandardDTU(t *testing.T) { } func TestAccMsSqlElasticPool_enclaveTypeUpdate(t *testing.T) { + // NOTE: Once the enclave_type has be set it cannot be removed... data := acceptance.BuildTestData(t, "azurerm_mssql_elasticpool", "test") r := MsSqlElasticPoolResource{} @@ -390,10 +391,18 @@ func TestAccMsSqlElasticPool_enclaveTypeUpdate(t *testing.T) { }, data.ImportStep("max_size_gb"), { - Config: r.basicDTU(data, ""), + Config: r.basicDTU(data, `enclave_type = "Default"`), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), - check.That(data.ResourceName).Key("enclave_type").IsEmpty(), + check.That(data.ResourceName).Key("enclave_type").HasValue("Default"), + ), + }, + data.ImportStep("max_size_gb"), + { + Config: r.basicDTU(data, `enclave_type = "VBS"`), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enclave_type").HasValue("VBS"), ), }, data.ImportStep("max_size_gb"), diff --git a/website/docs/r/mssql_database.html.markdown b/website/docs/r/mssql_database.html.markdown index f3bf789588d1..d07af4770f55 100644 --- a/website/docs/r/mssql_database.html.markdown +++ b/website/docs/r/mssql_database.html.markdown @@ -190,11 +190,11 @@ The following arguments are supported: * `elastic_pool_id` - (Optional) Specifies the ID of the elastic pool containing this database. -* `enclave_type` - (Optional) Specifies the type of enclave to be used by the database. Possible values are `Default` or `VBS`. +* `enclave_type` - (Optional) Specifies the type of enclave to be used by the database. Possible values are `Default` or `VBS`. Removing `enclave_type` from the configuration file after it has been set will cause a new resource to be created. -~> **NOTE:** `enclave_type` is currently not supported for DW (e.g, DataWarehouse) and DC-series SKUs. +-> **NOTE:** `enclave_type` is currently not supported for DW (e.g, DataWarehouse) and DC-series SKUs. -~> **NOTE:** Geo Replicated and Failover databases must have the same `enclave_type`. +-> **NOTE:** Geo Replicated and Failover databases must have the same `enclave_type`. * `geo_backup_enabled` - (Optional) A boolean that specifies if the Geo Backup Policy is enabled. Defaults to `true`. @@ -236,7 +236,7 @@ The following arguments are supported: * `sku_name` - (Optional) Specifies the name of the SKU used by the database. For example, `GP_S_Gen5_2`,`HS_Gen4_1`,`BC_Gen5_2`, `ElasticPool`, `Basic`,`S0`, `P2` ,`DW100c`, `DS100`. Changing this from the HyperScale service tier to another service tier will create a new resource. -~> **NOTE:** The default `sku_name` value may differ between Azure locations depending on local availability of Gen4/Gen5 capacity. When databases are replicated using the `creation_source_database_id` property, the source (primary) database cannot have a higher SKU service tier than any secondary databases. When changing the `sku_name` of a database having one or more secondary databases, this resource will first update any secondary databases as necessary. In such cases it's recommended to use the same `sku_name` in your configuration for all related databases, as not doing so may cause an unresolvable diff during subsequent plans. +-> **NOTE:** The default `sku_name` value may differ between Azure locations depending on local availability of Gen4/Gen5 capacity. When databases are replicated using the `creation_source_database_id` property, the source (primary) database cannot have a higher SKU service tier than any secondary databases. When changing the `sku_name` of a database having one or more secondary databases, this resource will first update any secondary databases as necessary. In such cases it's recommended to use the same `sku_name` in your configuration for all related databases, as not doing so may cause an unresolvable diff during subsequent plans. * `storage_account_type` - (Optional) Specifies the storage account type used to store backups for this database. Possible values are `Geo`, `GeoZone`, `Local` and `Zone`. Defaults to `Geo`. diff --git a/website/docs/r/mssql_elasticpool.html.markdown b/website/docs/r/mssql_elasticpool.html.markdown index 7d77574dc308..73aaddaae3a6 100644 --- a/website/docs/r/mssql_elasticpool.html.markdown +++ b/website/docs/r/mssql_elasticpool.html.markdown @@ -73,7 +73,7 @@ The following arguments are supported: -> **NOTE:** One of either `max_size_gb` or `max_size_bytes` must be specified. -* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. Possible values are `Default` or `VBS`. +* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. Possible values are `Default` or `VBS`. Removing `enclave_type` from the configuration file after it has been set will cause a new resource to be created. ~> **NOTE:** All databases that are added to the elastic pool must have the same `enclave_type` as the elastic pool. From 044a45cf66f7c24a5f35ff8574e30ada80948f14 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 4 Apr 2024 16:58:44 -0600 Subject: [PATCH 3/6] Fix lint errors... --- internal/services/mssql/helper/database.go | 2 +- internal/services/mssql/mssql_database_resource.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/services/mssql/helper/database.go b/internal/services/mssql/helper/database.go index 533e6d275cb2..9bbba8c6822b 100644 --- a/internal/services/mssql/helper/database.go +++ b/internal/services/mssql/helper/database.go @@ -108,7 +108,7 @@ func FindDatabaseReplicationPartners(ctx context.Context, databasesClient *datab } if partnerDatabase.Id != nil && partnerDatabase.Properties != nil && partnerDatabase.Properties.PreferredEnclaveType != nil { - if primaryEnclaveType != "" && databases.AlwaysEncryptedEnclaveType(primaryEnclaveType) == *partnerDatabase.Properties.PreferredEnclaveType { + if primaryEnclaveType != "" && primaryEnclaveType == *partnerDatabase.Properties.PreferredEnclaveType { log.Printf("[INFO] Found Partner %s", partnerDatabaseId) partnerDatabases = append(partnerDatabases, *partnerDatabase) } else { diff --git a/internal/services/mssql/mssql_database_resource.go b/internal/services/mssql/mssql_database_resource.go index 0bdf393b46fd..176cda7586c8 100644 --- a/internal/services/mssql/mssql_database_resource.go +++ b/internal/services/mssql/mssql_database_resource.go @@ -308,7 +308,7 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er // NOTE: The 'PreferredEnclaveType' field cannot be passed to the APIs Create if the 'sku_name' is a DW or DC-series SKU... if !strings.HasPrefix(strings.ToLower(skuName), "dw") && !strings.Contains(strings.ToLower(skuName), "_dc_") && enclaveType != "" { - input.Properties.PreferredEnclaveType = pointer.To(databases.AlwaysEncryptedEnclaveType(enclaveType)) + input.Properties.PreferredEnclaveType = pointer.To(enclaveType) } createMode := d.Get("create_mode").(string) @@ -711,7 +711,7 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er // The 'PreferredEnclaveType' field cannot be passed to the APIs Update if the // 'sku_name' is a DW or DC-series SKU... if !strings.HasPrefix(strings.ToLower(skuName), "dw") && !strings.Contains(strings.ToLower(skuName), "_dc_") && enclaveType != "" { - props.PreferredEnclaveType = pointer.To(databases.AlwaysEncryptedEnclaveType(enclaveType)) + props.PreferredEnclaveType = pointer.To(enclaveType) } else { props.PreferredEnclaveType = nil } From 450f9805c09f9c75908195e4db526bcee5481016 Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 4 Apr 2024 17:52:34 -0600 Subject: [PATCH 4/6] Update documentation, comments and test case... --- internal/services/mssql/mssql_database_resource.go | 4 +--- internal/services/mssql/mssql_database_resource_test.go | 3 ++- internal/services/mssql/mssql_elasticpool_resource.go | 4 +--- website/docs/r/mssql_database.html.markdown | 2 +- website/docs/r/mssql_elasticpool.html.markdown | 6 +++--- 5 files changed, 8 insertions(+), 11 deletions(-) diff --git a/internal/services/mssql/mssql_database_resource.go b/internal/services/mssql/mssql_database_resource.go index 176cda7586c8..85c5966e8b35 100644 --- a/internal/services/mssql/mssql_database_resource.go +++ b/internal/services/mssql/mssql_database_resource.go @@ -113,9 +113,7 @@ func resourceMsSqlDatabaseImporter(ctx context.Context, d *pluginsdk.ResourceDat return nil, err } - // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' - // field it shouldn’t be passed as part of the ARM API request for database or - // elastic pool, as it is an optional parameter and not a required one. + // NOTE: The service default is actually nil/empty which indicates enclave is disabled. the value `Default` is NOT the default. var enclaveType databases.AlwaysEncryptedEnclaveType if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { enclaveType = databases.AlwaysEncryptedEnclaveType(v.(string)) diff --git a/internal/services/mssql/mssql_database_resource_test.go b/internal/services/mssql/mssql_database_resource_test.go index c7fdc08871af..56620a9bf40d 100644 --- a/internal/services/mssql/mssql_database_resource_test.go +++ b/internal/services/mssql/mssql_database_resource_test.go @@ -90,7 +90,7 @@ func TestAccMsSqlDatabase_complete(t *testing.T) { check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("license_type").HasValue("LicenseIncluded"), check.That(data.ResourceName).Key("max_size_gb").HasValue("2"), - check.That(data.ResourceName).Key("enclave_type").IsEmpty(), + check.That(data.ResourceName).Key("enclave_type").HasValue("Default"), check.That(data.ResourceName).Key("tags.%").HasValue("1"), check.That(data.ResourceName).Key("tags.ENV").HasValue("Staging"), ), @@ -1076,6 +1076,7 @@ resource "azurerm_mssql_database" "test" { license_type = "LicenseIncluded" max_size_gb = 2 sku_name = "GP_Gen5_2" + enclave_type = "Default" storage_account_type = "Zone" diff --git a/internal/services/mssql/mssql_elasticpool_resource.go b/internal/services/mssql/mssql_elasticpool_resource.go index d06d490a4bfe..a78b061fe01e 100644 --- a/internal/services/mssql/mssql_elasticpool_resource.go +++ b/internal/services/mssql/mssql_elasticpool_resource.go @@ -267,9 +267,7 @@ func resourceMsSqlElasticPoolCreateUpdate(d *pluginsdk.ResourceData, meta interf }, } - // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' - // field it shouldn’t be passed as part of the ARM API request for database or - // elastic pool, as it is an optional parameter and not a required one. + // NOTE: The service default is actually nil/empty which indicates enclave is disabled. the value `Default` is NOT the default. if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { elasticPool.Properties.PreferredEnclaveType = pointer.To(elasticpools.AlwaysEncryptedEnclaveType(v.(string))) } diff --git a/website/docs/r/mssql_database.html.markdown b/website/docs/r/mssql_database.html.markdown index d07af4770f55..caf5fe9bf399 100644 --- a/website/docs/r/mssql_database.html.markdown +++ b/website/docs/r/mssql_database.html.markdown @@ -190,7 +190,7 @@ The following arguments are supported: * `elastic_pool_id` - (Optional) Specifies the ID of the elastic pool containing this database. -* `enclave_type` - (Optional) Specifies the type of enclave to be used by the database. Possible values are `Default` or `VBS`. Removing `enclave_type` from the configuration file after it has been set will cause a new resource to be created. +* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. When `enclave_type` is not specified in the configuration file (e.g., the default) enclaves are not enabled on the database. Once enabled, by specifying `Default` or `VBS`, removing the `enclave_type` field from the configuration file will force the creation of a new resource. Possible values are `Default` or `VBS`. -> **NOTE:** `enclave_type` is currently not supported for DW (e.g, DataWarehouse) and DC-series SKUs. diff --git a/website/docs/r/mssql_elasticpool.html.markdown b/website/docs/r/mssql_elasticpool.html.markdown index 73aaddaae3a6..361bbfa63b39 100644 --- a/website/docs/r/mssql_elasticpool.html.markdown +++ b/website/docs/r/mssql_elasticpool.html.markdown @@ -73,11 +73,11 @@ The following arguments are supported: -> **NOTE:** One of either `max_size_gb` or `max_size_bytes` must be specified. -* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. Possible values are `Default` or `VBS`. Removing `enclave_type` from the configuration file after it has been set will cause a new resource to be created. +* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. When `enclave_type` is not specified in the configuration file (e.g., the default) enclaves are not enabled on the elastic pool. Once enabled, by specifying `Default` or `VBS`, removing the `enclave_type` field from the configuration file will force the creation of a new resource. Possible values are `Default` or `VBS`. -~> **NOTE:** All databases that are added to the elastic pool must have the same `enclave_type` as the elastic pool. +-> **NOTE:** All databases that are added to the elastic pool must have the same `enclave_type` as the elastic pool. -~> **NOTE:** `enclave_type` is not supported for DC-series SKUs. +-> **NOTE:** `enclave_type` is not supported for DC-series SKUs. * `tags` - (Optional) A mapping of tags to assign to the resource. From a94244a41cce0690066249417f12dc680ab4be4c Mon Sep 17 00:00:00 2001 From: Jeffrey Cline <20408400+WodansSon@users.noreply.github.com> Date: Thu, 4 Apr 2024 18:50:37 -0600 Subject: [PATCH 5/6] Update documentation and fix test case... --- internal/services/mssql/mssql_database_resource.go | 11 +++++++---- website/docs/r/mssql_database.html.markdown | 4 +++- website/docs/r/mssql_elasticpool.html.markdown | 4 +++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/internal/services/mssql/mssql_database_resource.go b/internal/services/mssql/mssql_database_resource.go index 85c5966e8b35..d1a896197446 100644 --- a/internal/services/mssql/mssql_database_resource.go +++ b/internal/services/mssql/mssql_database_resource.go @@ -21,6 +21,7 @@ import ( "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/backupshorttermretentionpolicies" "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/databases" "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/databasesecurityalertpolicies" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/elasticpools" "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/geobackuppolicies" "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/longtermretentionpolicies" "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/servers" @@ -728,12 +729,14 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("retrieving %s: %s", elasticId, err) } + var elasticEnclaveType elasticpools.AlwaysEncryptedEnclaveType if elasticPool.Model != nil && elasticPool.Model.Properties != nil && elasticPool.Model.Properties.PreferredEnclaveType != nil { - elasticEnclaveType := string(pointer.From(elasticPool.Model.Properties.PreferredEnclaveType)) - databaseEnclaveType := string(enclaveType) + elasticEnclaveType = pointer.From(elasticPool.Model.Properties.PreferredEnclaveType) + } - if !strings.EqualFold(elasticEnclaveType, databaseEnclaveType) { - return fmt.Errorf("updating the %s with enclave type %q to the %s with enclave type %q is not supported. Before updating a database that belongs to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, databaseEnclaveType, elasticId, elasticEnclaveType) + if elasticEnclaveType != "" || enclaveType != "" { + if !strings.EqualFold(string(elasticEnclaveType), string(enclaveType)) { + return fmt.Errorf("updating the %s with enclave type %q to the %s with enclave type %q is not supported. Before updating a database that belongs to an elastic pool please ensure that the 'enclave_type' is the same for both the database and the elastic pool", id, enclaveType, elasticId, elasticEnclaveType) } } } diff --git a/website/docs/r/mssql_database.html.markdown b/website/docs/r/mssql_database.html.markdown index caf5fe9bf399..2dcf25a18613 100644 --- a/website/docs/r/mssql_database.html.markdown +++ b/website/docs/r/mssql_database.html.markdown @@ -190,12 +190,14 @@ The following arguments are supported: * `elastic_pool_id` - (Optional) Specifies the ID of the elastic pool containing this database. -* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. When `enclave_type` is not specified in the configuration file (e.g., the default) enclaves are not enabled on the database. Once enabled, by specifying `Default` or `VBS`, removing the `enclave_type` field from the configuration file will force the creation of a new resource. Possible values are `Default` or `VBS`. +* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. When `enclave_type` is not specified (e.g., the default) enclaves are not enabled on the database. Possible values are `Default` or `VBS`. -> **NOTE:** `enclave_type` is currently not supported for DW (e.g, DataWarehouse) and DC-series SKUs. -> **NOTE:** Geo Replicated and Failover databases must have the same `enclave_type`. +~> **NOTE:** The default value for the `enclave_type` field is unset not `Default`. + * `geo_backup_enabled` - (Optional) A boolean that specifies if the Geo Backup Policy is enabled. Defaults to `true`. ~> **NOTE:** `geo_backup_enabled` is only applicable for DataWarehouse SKUs (DW*). This setting is ignored for all other SKUs. diff --git a/website/docs/r/mssql_elasticpool.html.markdown b/website/docs/r/mssql_elasticpool.html.markdown index 361bbfa63b39..a29e003a1fae 100644 --- a/website/docs/r/mssql_elasticpool.html.markdown +++ b/website/docs/r/mssql_elasticpool.html.markdown @@ -73,12 +73,14 @@ The following arguments are supported: -> **NOTE:** One of either `max_size_gb` or `max_size_bytes` must be specified. -* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. When `enclave_type` is not specified in the configuration file (e.g., the default) enclaves are not enabled on the elastic pool. Once enabled, by specifying `Default` or `VBS`, removing the `enclave_type` field from the configuration file will force the creation of a new resource. Possible values are `Default` or `VBS`. +* `enclave_type` - (Optional) Specifies the type of enclave to be used by the elastic pool. When `enclave_type` is not specified (e.g., the default) enclaves are not enabled on the elastic pool. Possible values are `Default` or `VBS`. -> **NOTE:** All databases that are added to the elastic pool must have the same `enclave_type` as the elastic pool. -> **NOTE:** `enclave_type` is not supported for DC-series SKUs. +~> **NOTE:** The default value for `enclave_type` field is unset not `Default`. + * `tags` - (Optional) A mapping of tags to assign to the resource. * `zone_redundant` - (Optional) Whether or not this elastic pool is zone redundant. `tier` needs to be `Premium` for `DTU` based or `BusinessCritical` for `vCore` based `sku`. From 5727e50ec7cd50136aa9a179d97dee36c60d063c Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 4 Apr 2024 19:33:16 -0700 Subject: [PATCH 6/6] Update internal/services/mssql/mssql_database_resource.go --- internal/services/mssql/mssql_database_resource.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/services/mssql/mssql_database_resource.go b/internal/services/mssql/mssql_database_resource.go index d1a896197446..bf746a51b7c4 100644 --- a/internal/services/mssql/mssql_database_resource.go +++ b/internal/services/mssql/mssql_database_resource.go @@ -214,9 +214,7 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er locks.ByID(id.ID()) defer locks.UnlockByID(id.ID()) - // PER THE SERVICE TEAM: If the config doesn’t specify any value for the 'enclave_type' - // field it shouldn’t be passed as part of the ARM API request for database or - // elastic pool, as it is an optional parameter and not a required one. + // NOTE: The service default is actually nil/empty which indicates enclave is disabled. the value `Default` is NOT the default. var enclaveType databases.AlwaysEncryptedEnclaveType if v, ok := d.GetOk("enclave_type"); ok && v.(string) != "" { enclaveType = databases.AlwaysEncryptedEnclaveType(v.(string))