Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New data source azurerm_mssql_server and new block restorable_dropped_databases in azuerrm_mssql_server #7917

Merged
merged 13 commits into from Sep 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
}