Skip to content

Commit

Permalink
New data source azurerm_mssql_server and new block `restorable_drop…
Browse files Browse the repository at this point in the history
…ped_databases` in `azuerrm_mssql_server` (#7917)

Fix #6502
#7594

=== RUN TestAccAzureRMMsSqlDatabase_createRestoreMode
=== PAUSE TestAccAzureRMMsSqlDatabase_createRestoreMode
=== CONT TestAccAzureRMMsSqlDatabase_createRestoreMode
--- PASS: TestAccAzureRMMsSqlDatabase_createRestoreMode (2016.02s)

Sql server listing recoverableDatabases Api has problems, thus it's excluded in the PR: Azure/azure-rest-api-specs#10162
  • Loading branch information
yupwei68 committed Sep 21, 2020
1 parent 8f5bac1 commit 690ab63
Show file tree
Hide file tree
Showing 14 changed files with 766 additions and 6 deletions.
5 changes: 5 additions & 0 deletions azurerm/internal/services/mssql/client/client.go
Expand Up @@ -12,6 +12,7 @@ type Client struct {
DatabaseThreatDetectionPoliciesClient *sql.DatabaseThreatDetectionPoliciesClient
ElasticPoolsClient *sql.ElasticPoolsClient
DatabaseVulnerabilityAssessmentRuleBaselinesClient *sql.DatabaseVulnerabilityAssessmentRuleBaselinesClient
RestorableDroppedDatabasesClient *sql.RestorableDroppedDatabasesClient
ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient
ServersClient *sql.ServersClient
ServerExtendedBlobAuditingPoliciesClient *sql.ExtendedServerBlobAuditingPoliciesClient
Expand All @@ -37,6 +38,9 @@ func NewClient(o *common.ClientOptions) *Client {
elasticPoolsClient := sql.NewElasticPoolsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&elasticPoolsClient.Client, o.ResourceManagerAuthorizer)

restorableDroppedDatabasesClient := sql.NewRestorableDroppedDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&restorableDroppedDatabasesClient.Client, o.ResourceManagerAuthorizer)

serverSecurityAlertPoliciesClient := sql.NewServerSecurityAlertPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId)
o.ConfigureClient(&serverSecurityAlertPoliciesClient.Client, o.ResourceManagerAuthorizer)

Expand Down Expand Up @@ -64,6 +68,7 @@ func NewClient(o *common.ClientOptions) *Client {
DatabaseThreatDetectionPoliciesClient: &databaseThreatDetectionPoliciesClient,
DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient,
ElasticPoolsClient: &elasticPoolsClient,
RestorableDroppedDatabasesClient: &restorableDroppedDatabasesClient,
ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient,
ServersClient: &serversClient,
ServerExtendedBlobAuditingPoliciesClient: &serverExtendedBlobAuditingPoliciesClient,
Expand Down
31 changes: 29 additions & 2 deletions azurerm/internal/services/mssql/mssql_database_resource.go
Expand Up @@ -66,7 +66,6 @@ func resourceArmMsSqlDatabase() *schema.Resource {
ValidateFunc: validate.MsSqlDatabaseAutoPauseDelay,
},

// recovery is not support in version 2017-10-01-preview
"create_mode": {
Type: schema.TypeString,
Optional: true,
Expand All @@ -78,6 +77,7 @@ func resourceArmMsSqlDatabase() *schema.Resource {
string(sql.CreateModeOnlineSecondary),
string(sql.CreateModePointInTimeRestore),
string(sql.CreateModeRestore),
string(sql.CreateModeRecovery),
string(sql.CreateModeRestoreExternalBackup),
string(sql.CreateModeRestoreExternalBackupSecondary),
string(sql.CreateModeRestoreLongTermRetentionBackup),
Expand Down Expand Up @@ -133,6 +133,18 @@ func resourceArmMsSqlDatabase() *schema.Resource {
ValidateFunc: validation.IsRFC3339Time,
},

"recover_database_id": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validate.MsSqlRecoverableDatabaseID,
},

"restore_dropped_database_id": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validate.MsSqlRestorableDatabaseID,
},

"read_replica_count": {
Type: schema.TypeInt,
Optional: true,
Expand Down Expand Up @@ -338,9 +350,16 @@ func resourceArmMsSqlDatabaseCreateUpdate(d *schema.ResourceData, meta interface
}

createMode, ok := d.GetOk("create_mode")
if _, dbok := d.GetOk("creation_source_database_id"); ok && (createMode.(string) == string(sql.CreateModeCopy) || createMode.(string) == string(sql.CreateModePointInTimeRestore) || createMode.(string) == string(sql.CreateModeRestore) || createMode.(string) == string(sql.CreateModeSecondary)) && !dbok {
if _, dbok := d.GetOk("creation_source_database_id"); ok && (createMode.(string) == string(sql.CreateModeCopy) || createMode.(string) == string(sql.CreateModePointInTimeRestore) || createMode.(string) == string(sql.CreateModeSecondary)) && !dbok {
return fmt.Errorf("'creation_source_database_id' is required for create_mode %s", createMode.(string))
}
if _, dbok := d.GetOk("recover_database_id"); ok && createMode.(string) == string(sql.CreateModeRecovery) && !dbok {
return fmt.Errorf("'recover_database_id' is required for create_mode %s", createMode.(string))
}
if _, dbok := d.GetOk("restore_dropped_database_id"); ok && createMode.(string) == string(sql.CreateModeRestore) && !dbok {
return fmt.Errorf("'restore_dropped_database_id' is required for create_mode %s", createMode.(string))
}

params.DatabaseProperties.CreateMode = sql.CreateMode(createMode.(string))

auditingPolicies := d.Get("extended_auditing_policy").([]interface{})
Expand Down Expand Up @@ -376,6 +395,14 @@ func resourceArmMsSqlDatabaseCreateUpdate(d *schema.ResourceData, meta interface
params.DatabaseProperties.SourceDatabaseID = utils.String(v.(string))
}

if v, ok := d.GetOk("recover_database_id"); ok {
params.DatabaseProperties.RecoverableDatabaseID = utils.String(v.(string))
}

if v, ok := d.GetOk("restore_dropped_database_id"); ok {
params.DatabaseProperties.RestorableDroppedDatabaseID = utils.String(v.(string))
}

future, err := client.CreateOrUpdate(ctx, serverId.ResourceGroup, serverId.Name, name, params)
if err != nil {
return fmt.Errorf("creating MsSql Database %q (Sql Server %q / Resource Group %q): %+v", name, serverId.Name, serverId.ResourceGroup, err)
Expand Down
126 changes: 126 additions & 0 deletions azurerm/internal/services/mssql/mssql_server_data_source.go
@@ -0,0 +1,126 @@
package mssql

import (
"fmt"
"time"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/location"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tags"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts"
"github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils"
)

func dataSourceMsSqlServer() *schema.Resource {
return &schema.Resource{
Read: dataSourceArmMsSqlServerRead,

Timeouts: &schema.ResourceTimeout{
Read: schema.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},

"resource_group_name": azure.SchemaResourceGroupNameForDataSource(),

"location": azure.SchemaLocationForDataSource(),

"version": {
Type: schema.TypeString,
Computed: true,
},

"administrator_login": {
Type: schema.TypeString,
Computed: true,
},

"fully_qualified_domain_name": {
Type: schema.TypeString,
Computed: true,
},

"identity": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"type": {
Type: schema.TypeString,
Computed: true,
},
"principal_id": {
Type: schema.TypeString,
Computed: true,
},
"tenant_id": {
Type: schema.TypeString,
Computed: true,
},
},
},
},

"restorable_dropped_database_ids": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},

"tags": tags.SchemaDataSource(),
},
}
}

func dataSourceArmMsSqlServerRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*clients.Client).MSSQL.ServersClient
restorableDroppedDatabasesClient := meta.(*clients.Client).MSSQL.RestorableDroppedDatabasesClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

name := d.Get("name").(string)
resourceGroup := d.Get("resource_group_name").(string)

resp, err := client.Get(ctx, resourceGroup, name)
if err != nil {
if utils.ResponseWasNotFound(resp.Response) {
return fmt.Errorf("sql Server %q was not found in Resource Group %q", name, resourceGroup)
}

return fmt.Errorf("retrieving Sql Server %q (Resource Group %q): %s", name, resourceGroup, err)
}

if resp.ID == nil || *resp.ID == "" {
return fmt.Errorf("reading Ms Sql Server %q (Resource Group %q) ID is empty or nil", name, resourceGroup)
}
d.SetId(*resp.ID)
d.Set("location", location.NormalizeNilable(resp.Location))

if props := resp.ServerProperties; props != nil {
d.Set("version", props.Version)
d.Set("administrator_login", props.AdministratorLogin)
d.Set("fully_qualified_domain_name", props.FullyQualifiedDomainName)
}

if err := d.Set("identity", flattenAzureRmSqlServerIdentity(resp.Identity)); err != nil {
return fmt.Errorf("setting `identity`: %+v", err)
}

restorableResp, err := restorableDroppedDatabasesClient.ListByServer(ctx, resourceGroup, name)
if err != nil {
return fmt.Errorf("listing SQL Server %s Restorable Dropped Databases: %v", name, err)
}
if err := d.Set("restorable_dropped_database_ids", flattenAzureRmSqlServerRestorableDatabases(restorableResp)); err != nil {
return fmt.Errorf("setting `restorable_dropped_database_ids`: %+v", err)
}

return tags.FlattenAndSet(d, resp.Tags)
}
32 changes: 32 additions & 0 deletions azurerm/internal/services/mssql/mssql_server_resource.go
Expand Up @@ -149,6 +149,14 @@ func resourceArmMsSqlServer() *schema.Resource {
Computed: true,
},

"restorable_dropped_database_ids": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},

"tags": tags.Schema(),
},
}
Expand Down Expand Up @@ -280,6 +288,7 @@ func resourceArmMsSqlServerRead(d *schema.ResourceData, meta interface{}) error
auditingClient := meta.(*clients.Client).MSSQL.ServerExtendedBlobAuditingPoliciesClient
connectionClient := meta.(*clients.Client).MSSQL.ServerConnectionPoliciesClient
adminClient := meta.(*clients.Client).MSSQL.ServerAzureADAdministratorsClient
restorableDroppedDatabasesClient := meta.(*clients.Client).MSSQL.RestorableDroppedDatabasesClient
ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d)
defer cancel()

Expand Down Expand Up @@ -348,6 +357,14 @@ func resourceArmMsSqlServerRead(d *schema.ResourceData, meta interface{}) error
return fmt.Errorf("Error setting `extended_auditing_policy`: %+v", err)
}

restorableResp, err := restorableDroppedDatabasesClient.ListByServer(ctx, resGroup, name)
if err != nil {
return fmt.Errorf("listing SQL Server %s Restorable Dropped Databases: %v", name, err)
}
if err := d.Set("restorable_dropped_database_ids", flattenAzureRmSqlServerRestorableDatabases(restorableResp)); err != nil {
return fmt.Errorf("setting `restorable_dropped_database_ids`: %+v", err)
}

return tags.FlattenAndSet(d, resp.Tags)
}

Expand Down Expand Up @@ -445,3 +462,18 @@ func flatternAzureRmMsSqlServerAdministrator(admin sql.ServerAzureADAdministrato
},
}
}

func flattenAzureRmSqlServerRestorableDatabases(resp sql.RestorableDroppedDatabaseListResult) []string {
if resp.Value == nil || len(*resp.Value) == 0 {
return []string{}
}
res := make([]string, 0)
for _, r := range *resp.Value {
var id string
if r.ID != nil {
id = *r.ID
}
res = append(res, id)
}
return res
}
72 changes: 72 additions & 0 deletions azurerm/internal/services/mssql/parse/mssql.go
Expand Up @@ -2,6 +2,7 @@ package parse

import (
"fmt"
"strings"

"github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure"
)
Expand Down Expand Up @@ -34,6 +35,19 @@ type MsSqlServerExtendedAuditingPolicyId struct {
ResourceGroup string
}

type MsSqlRestorableDBId struct {
Name string
MsSqlServer string
ResourceGroup string
RestoreName string
}

type MsSqlRecoverableDBId struct {
Name string
MsSqlServer string
ResourceGroup string
}

func NewMsSqlDatabaseID(resourceGroup, msSqlServer, name string) MsSqlDatabaseId {
return MsSqlDatabaseId{
ResourceGroup: resourceGroup,
Expand Down Expand Up @@ -196,3 +210,61 @@ func MssqlServerExtendedAuditingPolicyID(input string) (*MsSqlServerExtendedAudi

return &sqlServerExtendedAuditingPolicyId, nil
}

func MssqlRestorableDBID(input string) (*MsSqlRestorableDBId, error) {
inputList := strings.Split(input, ",")

if len(inputList) != 2 {
return nil, fmt.Errorf("[ERROR] Unable to parse Microsoft Sql Restorable DB ID %q, please refer to '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/resGroup1/providers/Microsoft.Sql/servers/sqlServer1/restorableDroppedDatabases/sqlDB1,000000000000000000'", input)
}

restorableDBId := MsSqlRestorableDBId{
RestoreName: inputList[1],
}

id, err := azure.ParseAzureResourceID(inputList[0])
if err != nil {
return nil, fmt.Errorf("[ERROR] Unable to parse Microsoft Sql Restorable DB ID %q: %+v", input, err)
}

restorableDBId.ResourceGroup = id.ResourceGroup

if restorableDBId.MsSqlServer, err = id.PopSegment("servers"); err != nil {
return nil, err
}

if restorableDBId.Name, err = id.PopSegment("restorableDroppedDatabases"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(inputList[0]); err != nil {
return nil, err
}

return &restorableDBId, nil
}

func MssqlRecoverableDBID(input string) (*MsSqlRecoverableDBId, error) {
id, err := azure.ParseAzureResourceID(input)
if err != nil {
return nil, fmt.Errorf("[ERROR] Unable to parse Microsoft Sql Recoverable DB ID %q: %+v", input, err)
}

recoverableDBId := MsSqlRecoverableDBId{
ResourceGroup: id.ResourceGroup,
}

if recoverableDBId.MsSqlServer, err = id.PopSegment("servers"); err != nil {
return nil, err
}

if recoverableDBId.Name, err = id.PopSegment("recoverabledatabases"); err != nil {
return nil, err
}

if err := id.ValidateNoEmptySegments(input); err != nil {
return nil, err
}

return &recoverableDBId, nil
}

0 comments on commit 690ab63

Please sign in to comment.