diff --git a/internal/services/mssql/client/client.go b/internal/services/mssql/client/client.go index 97073be5ca0c..40ef04667a36 100644 --- a/internal/services/mssql/client/client.go +++ b/internal/services/mssql/client/client.go @@ -4,58 +4,59 @@ package client import ( + "fmt" + "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck + "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/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/replicationlinks" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/restorabledroppeddatabases" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverazureadadministrators" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverazureadonlyauthentications" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverconnectionpolicies" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/servers" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serversecurityalertpolicies" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/transparentdataencryptions" "github.com/hashicorp/go-azure-sdk/resource-manager/sqlvirtualmachine/2022-02-01/availabilitygrouplisteners" "github.com/hashicorp/go-azure-sdk/resource-manager/sqlvirtualmachine/2022-02-01/sqlvirtualmachinegroups" "github.com/hashicorp/go-azure-sdk/resource-manager/sqlvirtualmachine/2022-02-01/sqlvirtualmachines" "github.com/hashicorp/terraform-provider-azurerm/internal/common" - - // @tombuildsstuff: force-importing these packages to vendor them to reduce the size of - // https://github.com/hashicorp/terraform-provider-azurerm/pull/23721, meaning that - // @WodansSon can remove the underscore as these are used to make these regular imports - _ "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/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/replicationlinks" - _ "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/restorabledroppeddatabases" - _ "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverazureadadministrators" - _ "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverazureadonlyauthentications" - _ "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverconnectionpolicies" - _ "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/servers" - _ "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serversecurityalertpolicies" - _ "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/transparentdataencryptions" ) type Client struct { - BackupShortTermRetentionPoliciesClient *sql.BackupShortTermRetentionPoliciesClient + BackupShortTermRetentionPoliciesClient *backupshorttermretentionpolicies.BackupShortTermRetentionPoliciesClient DatabaseExtendedBlobAuditingPoliciesClient *sql.ExtendedDatabaseBlobAuditingPoliciesClient - DatabaseSecurityAlertPoliciesClient *sql.DatabaseSecurityAlertPoliciesClient + DatabaseSecurityAlertPoliciesClient *databasesecurityalertpolicies.DatabaseSecurityAlertPoliciesClient DatabaseVulnerabilityAssessmentRuleBaselinesClient *sql.DatabaseVulnerabilityAssessmentRuleBaselinesClient - DatabasesClient *sql.DatabasesClient + DatabasesClient *databases.DatabasesClient + LegacyDatabasesClient *sql.DatabasesClient ElasticPoolsClient *sql.ElasticPoolsClient EncryptionProtectorClient *sql.EncryptionProtectorsClient FailoverGroupsClient *sql.FailoverGroupsClient FirewallRulesClient *sql.FirewallRulesClient - GeoBackupPoliciesClient *sql.GeoBackupPoliciesClient + GeoBackupPoliciesClient *geobackuppolicies.GeoBackupPoliciesClient JobAgentsClient *sql.JobAgentsClient JobCredentialsClient *sql.JobCredentialsClient - LongTermRetentionPoliciesClient *sql.LongTermRetentionPoliciesClient + LongTermRetentionPoliciesClient *longtermretentionpolicies.LongTermRetentionPoliciesClient OutboundFirewallRulesClient *sql.OutboundFirewallRulesClient - ReplicationLinksClient *sql.ReplicationLinksClient - RestorableDroppedDatabasesClient *sql.RestorableDroppedDatabasesClient - ServerAzureADAdministratorsClient *sql.ServerAzureADAdministratorsClient - ServerAzureADOnlyAuthenticationsClient *sql.ServerAzureADOnlyAuthenticationsClient - ServerConnectionPoliciesClient *sql.ServerConnectionPoliciesClient + ReplicationLinksClient *replicationlinks.ReplicationLinksClient + LegacyReplicationLinksClient *sql.ReplicationLinksClient + RestorableDroppedDatabasesClient *restorabledroppeddatabases.RestorableDroppedDatabasesClient + ServerAzureADAdministratorsClient *serverazureadadministrators.ServerAzureADAdministratorsClient + ServerAzureADOnlyAuthenticationsClient *serverazureadonlyauthentications.ServerAzureADOnlyAuthenticationsClient + ServerConnectionPoliciesClient *serverconnectionpolicies.ServerConnectionPoliciesClient ServerDNSAliasClient *sql.ServerDNSAliasesClient ServerExtendedBlobAuditingPoliciesClient *sql.ExtendedServerBlobAuditingPoliciesClient ServerDevOpsAuditSettingsClient *sql.ServerDevOpsAuditSettingsClient ServerKeysClient *sql.ServerKeysClient - ServerSecurityAlertPoliciesClient *sql.ServerSecurityAlertPoliciesClient + ServerSecurityAlertPoliciesClient *serversecurityalertpolicies.ServerSecurityAlertPoliciesClient + LegacyServerSecurityAlertPoliciesClient *sql.ServerSecurityAlertPoliciesClient ServerVulnerabilityAssessmentsClient *sql.ServerVulnerabilityAssessmentsClient - ServersClient *sql.ServersClient - TransparentDataEncryptionsClient *sql.TransparentDataEncryptionsClient + ServersClient *servers.ServersClient + TransparentDataEncryptionsClient *transparentdataencryptions.TransparentDataEncryptionsClient VirtualMachinesAvailabilityGroupListenersClient *availabilitygrouplisteners.AvailabilityGroupListenersClient VirtualMachinesClient *sqlvirtualmachines.SqlVirtualMachinesClient VirtualMachineGroupsClient *sqlvirtualmachinegroups.SqlVirtualMachineGroupsClient @@ -63,20 +64,33 @@ type Client struct { } func NewClient(o *common.ClientOptions) (*Client, error) { - backupShortTermRetentionPoliciesClient := sql.NewBackupShortTermRetentionPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&backupShortTermRetentionPoliciesClient.Client, o.ResourceManagerAuthorizer) + backupShortTermRetentionPoliciesClient, err := backupshorttermretentionpolicies.NewBackupShortTermRetentionPoliciesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Backup Short Term Retention Policies Client: %+v", err) + } + o.Configure(backupShortTermRetentionPoliciesClient.Client, o.Authorizers.ResourceManager) databaseExtendedBlobAuditingPoliciesClient := sql.NewExtendedDatabaseBlobAuditingPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&databaseExtendedBlobAuditingPoliciesClient.Client, o.ResourceManagerAuthorizer) - databaseSecurityAlertPoliciesClient := sql.NewDatabaseSecurityAlertPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&databaseSecurityAlertPoliciesClient.Client, o.ResourceManagerAuthorizer) + databaseSecurityAlertPoliciesClient, err := databasesecurityalertpolicies.NewDatabaseSecurityAlertPoliciesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Databases Security Alert Policies Client: %+v", err) + } + o.Configure(databaseSecurityAlertPoliciesClient.Client, o.Authorizers.ResourceManager) databaseVulnerabilityAssessmentRuleBaselinesClient := sql.NewDatabaseVulnerabilityAssessmentRuleBaselinesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&databaseVulnerabilityAssessmentRuleBaselinesClient.Client, o.ResourceManagerAuthorizer) - databasesClient := sql.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&databasesClient.Client, o.ResourceManagerAuthorizer) + databasesClient, err := databases.NewDatabasesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Databases Client: %+v", err) + } + o.Configure(databasesClient.Client, o.Authorizers.ResourceManager) + + // NOTE: Remove once Azure Bug 2805551 ReplicationLink API ListByDatabase missed subsubcriptionId in partnerDatabaseId in response body has been released + legacyDatabasesClient := sql.NewDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&legacyDatabasesClient.Client, o.ResourceManagerAuthorizer) elasticPoolsClient := sql.NewElasticPoolsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&elasticPoolsClient.Client, o.ResourceManagerAuthorizer) @@ -90,8 +104,11 @@ func NewClient(o *common.ClientOptions) (*Client, error) { firewallRulesClient := sql.NewFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&firewallRulesClient.Client, o.ResourceManagerAuthorizer) - geoBackupPoliciesClient := sql.NewGeoBackupPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&geoBackupPoliciesClient.Client, o.ResourceManagerAuthorizer) + geoBackupPoliciesClient, err := geobackuppolicies.NewGeoBackupPoliciesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Geo Backup Policies Client: %+v", err) + } + o.Configure(geoBackupPoliciesClient.Client, o.Authorizers.ResourceManager) jobAgentsClient := sql.NewJobAgentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&jobAgentsClient.Client, o.ResourceManagerAuthorizer) @@ -99,26 +116,48 @@ func NewClient(o *common.ClientOptions) (*Client, error) { jobCredentialsClient := sql.NewJobCredentialsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&jobCredentialsClient.Client, o.ResourceManagerAuthorizer) - longTermRetentionPoliciesClient := sql.NewLongTermRetentionPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&longTermRetentionPoliciesClient.Client, o.ResourceManagerAuthorizer) + longTermRetentionPoliciesClient, err := longtermretentionpolicies.NewLongTermRetentionPoliciesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Long Term Retention Policies Client: %+v", err) + } + o.Configure(longTermRetentionPoliciesClient.Client, o.Authorizers.ResourceManager) outboundFirewallRulesClient := sql.NewOutboundFirewallRulesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&outboundFirewallRulesClient.Client, o.ResourceManagerAuthorizer) - replicationLinksClient := sql.NewReplicationLinksClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&replicationLinksClient.Client, o.ResourceManagerAuthorizer) - - restorableDroppedDatabasesClient := sql.NewRestorableDroppedDatabasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&restorableDroppedDatabasesClient.Client, o.ResourceManagerAuthorizer) - - serverAzureADAdministratorsClient := sql.NewServerAzureADAdministratorsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&serverAzureADAdministratorsClient.Client, o.ResourceManagerAuthorizer) - - serverAzureADOnlyAuthenticationsClient := sql.NewServerAzureADOnlyAuthenticationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&serverAzureADOnlyAuthenticationsClient.Client, o.ResourceManagerAuthorizer) - - serverConnectionPoliciesClient := sql.NewServerConnectionPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&serverConnectionPoliciesClient.Client, o.ResourceManagerAuthorizer) + replicationLinksClient, err := replicationlinks.NewReplicationLinksClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Replication Links Client: %+v", err) + } + o.Configure(replicationLinksClient.Client, o.Authorizers.ResourceManager) + + // NOTE: Remove once Azure Bug 2805551 ReplicationLink API ListByDatabase missed subsubcriptionId in partnerDatabaseId in response body has been released + legacyReplicationLinksClient := sql.NewReplicationLinksClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&legacyReplicationLinksClient.Client, o.ResourceManagerAuthorizer) + + restorableDroppedDatabasesClient, err := restorabledroppeddatabases.NewRestorableDroppedDatabasesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Restorable Dropped Databases Client: %+v", err) + } + o.Configure(restorableDroppedDatabasesClient.Client, o.Authorizers.ResourceManager) + + serverAzureADAdministratorsClient, err := serverazureadadministrators.NewServerAzureADAdministratorsClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Server Azure Active Directory Administrators Client: %+v", err) + } + o.Configure(serverAzureADAdministratorsClient.Client, o.Authorizers.ResourceManager) + + serverAzureADOnlyAuthenticationsClient, err := serverazureadonlyauthentications.NewServerAzureADOnlyAuthenticationsClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Azure Active Directory Only Authentication Client: %+v", err) + } + o.Configure(serverAzureADOnlyAuthenticationsClient.Client, o.Authorizers.ResourceManager) + + serverConnectionPoliciesClient, err := serverconnectionpolicies.NewServerConnectionPoliciesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Server Connection Policies Client: %+v", err) + } + o.Configure(serverConnectionPoliciesClient.Client, o.Authorizers.ResourceManager) serverDNSAliasClient := sql.NewServerDNSAliasesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&serverDNSAliasClient.Client, o.ResourceManagerAuthorizer) @@ -132,17 +171,29 @@ func NewClient(o *common.ClientOptions) (*Client, error) { serverKeysClient := sql.NewServerKeysClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&serverKeysClient.Client, o.ResourceManagerAuthorizer) - serverSecurityAlertPoliciesClient := sql.NewServerSecurityAlertPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&serverSecurityAlertPoliciesClient.Client, o.ResourceManagerAuthorizer) + legacyServerSecurityAlertPoliciesClient := sql.NewServerSecurityAlertPoliciesClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&legacyServerSecurityAlertPoliciesClient.Client, o.ResourceManagerAuthorizer) + + serverSecurityAlertPoliciesClient, err := serversecurityalertpolicies.NewServerSecurityAlertPoliciesClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Server Security Alert Policies Client: %+v", err) + } + o.Configure(serverSecurityAlertPoliciesClient.Client, o.Authorizers.ResourceManager) serverVulnerabilityAssessmentsClient := sql.NewServerVulnerabilityAssessmentsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&serverVulnerabilityAssessmentsClient.Client, o.ResourceManagerAuthorizer) - serversClient := sql.NewServersClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&serversClient.Client, o.ResourceManagerAuthorizer) + serversClient, err := servers.NewServersClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Server Client: %+v", err) + } + o.Configure(serversClient.Client, o.Authorizers.ResourceManager) - transparentDataEncryptionsClient := sql.NewTransparentDataEncryptionsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) - o.ConfigureClient(&transparentDataEncryptionsClient.Client, o.ResourceManagerAuthorizer) + transparentDataEncryptionsClient, err := transparentdataencryptions.NewTransparentDataEncryptionsClientWithBaseURI(o.Environment.ResourceManager) + if err != nil { + return nil, fmt.Errorf("building Transparent Data Encryptions Client: %+v", err) + } + o.Configure(transparentDataEncryptionsClient.Client, o.Authorizers.ResourceManager) virtualMachinesAvailabilityGroupListenersClient := availabilitygrouplisteners.NewAvailabilityGroupListenersClientWithBaseURI(o.ResourceManagerEndpoint) o.ConfigureClient(&virtualMachinesAvailabilityGroupListenersClient.Client, o.ResourceManagerAuthorizer) @@ -157,36 +208,44 @@ func NewClient(o *common.ClientOptions) (*Client, error) { o.ConfigureClient(&virtualNetworkRulesClient.Client, o.ResourceManagerAuthorizer) return &Client{ - BackupShortTermRetentionPoliciesClient: &backupShortTermRetentionPoliciesClient, + // Clients using the Track1 SDK which need to be gradually switched over to `hashicorp/go-azure-sdk` DatabaseExtendedBlobAuditingPoliciesClient: &databaseExtendedBlobAuditingPoliciesClient, - DatabaseSecurityAlertPoliciesClient: &databaseSecurityAlertPoliciesClient, DatabaseVulnerabilityAssessmentRuleBaselinesClient: &databaseVulnerabilityAssessmentRuleBaselinesClient, - DatabasesClient: &databasesClient, ElasticPoolsClient: &elasticPoolsClient, EncryptionProtectorClient: &encryptionProtectorClient, FailoverGroupsClient: &failoverGroupsClient, FirewallRulesClient: &firewallRulesClient, - GeoBackupPoliciesClient: &geoBackupPoliciesClient, JobAgentsClient: &jobAgentsClient, JobCredentialsClient: &jobCredentialsClient, - LongTermRetentionPoliciesClient: &longTermRetentionPoliciesClient, OutboundFirewallRulesClient: &outboundFirewallRulesClient, - ReplicationLinksClient: &replicationLinksClient, - RestorableDroppedDatabasesClient: &restorableDroppedDatabasesClient, - ServerAzureADAdministratorsClient: &serverAzureADAdministratorsClient, - ServerAzureADOnlyAuthenticationsClient: &serverAzureADOnlyAuthenticationsClient, - ServerConnectionPoliciesClient: &serverConnectionPoliciesClient, ServerDNSAliasClient: &serverDNSAliasClient, ServerDevOpsAuditSettingsClient: &serverDevOpsAuditSettingsClient, ServerExtendedBlobAuditingPoliciesClient: &serverExtendedBlobAuditingPoliciesClient, ServerKeysClient: &serverKeysClient, - ServerSecurityAlertPoliciesClient: &serverSecurityAlertPoliciesClient, ServerVulnerabilityAssessmentsClient: &serverVulnerabilityAssessmentsClient, - ServersClient: &serversClient, - TransparentDataEncryptionsClient: &transparentDataEncryptionsClient, VirtualMachinesAvailabilityGroupListenersClient: &virtualMachinesAvailabilityGroupListenersClient, VirtualMachinesClient: &virtualMachinesClient, VirtualMachineGroupsClient: &virtualMachineGroupsClient, VirtualNetworkRulesClient: &virtualNetworkRulesClient, + + // Legacy Clients + LegacyDatabasesClient: &legacyDatabasesClient, + LegacyServerSecurityAlertPoliciesClient: &legacyServerSecurityAlertPoliciesClient, + LegacyReplicationLinksClient: &legacyReplicationLinksClient, + + // 2023-02-01-preview Clients + BackupShortTermRetentionPoliciesClient: backupShortTermRetentionPoliciesClient, + DatabasesClient: databasesClient, + DatabaseSecurityAlertPoliciesClient: databaseSecurityAlertPoliciesClient, + GeoBackupPoliciesClient: geoBackupPoliciesClient, + LongTermRetentionPoliciesClient: longTermRetentionPoliciesClient, + ReplicationLinksClient: replicationLinksClient, + RestorableDroppedDatabasesClient: restorableDroppedDatabasesClient, + ServerAzureADAdministratorsClient: serverAzureADAdministratorsClient, + ServerAzureADOnlyAuthenticationsClient: serverAzureADOnlyAuthenticationsClient, + ServerConnectionPoliciesClient: serverConnectionPoliciesClient, + ServerSecurityAlertPoliciesClient: serverSecurityAlertPoliciesClient, + TransparentDataEncryptionsClient: transparentDataEncryptionsClient, + ServersClient: serversClient, }, nil } diff --git a/internal/services/mssql/custompollers/mssql_deleteserverazureadonlyauthentication_poller.go b/internal/services/mssql/custompollers/mssql_deleteserverazureadonlyauthentication_poller.go new file mode 100644 index 000000000000..16e359cd9e2d --- /dev/null +++ b/internal/services/mssql/custompollers/mssql_deleteserverazureadonlyauthentication_poller.go @@ -0,0 +1,59 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package custompollers + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverazureadonlyauthentications" + "github.com/hashicorp/go-azure-sdk/sdk/client/pollers" +) + +var _ pollers.PollerType = &MsSqlServerDeleteServerAzureADOnlyAuthenticationPoller{} + +func NewMsSqlServerDeleteServerAzureADOnlyAuthenticationPoller(client *serverazureadonlyauthentications.ServerAzureADOnlyAuthenticationsClient, serverId commonids.SqlServerId) *MsSqlServerDeleteServerAzureADOnlyAuthenticationPoller { + return &MsSqlServerDeleteServerAzureADOnlyAuthenticationPoller{ + client: client, + serverId: serverId, + } +} + +type MsSqlServerDeleteServerAzureADOnlyAuthenticationPoller struct { + client *serverazureadonlyauthentications.ServerAzureADOnlyAuthenticationsClient + serverId commonids.SqlServerId +} + +func (p *MsSqlServerDeleteServerAzureADOnlyAuthenticationPoller) Poll(ctx context.Context) (*pollers.PollResult, error) { + resp, err := p.client.Get(ctx, p.serverId) + if err != nil { + return nil, fmt.Errorf("retrieving %s: %+v", p.serverId, err) + } + + if resp.Model == nil { + return nil, fmt.Errorf("retrieving %s: `model` was nil", p.serverId) + } + + name := pointer.From(resp.Model.Name) + azureAdOnlyAuthentication := true + if props := resp.Model.Properties; props != nil { + azureAdOnlyAuthentication = props.AzureADOnlyAuthentication + } + + if !azureAdOnlyAuthentication && strings.EqualFold(name, "Default") { + return &pollers.PollResult{ + Status: pollers.PollingStatusSucceeded, + PollInterval: 5 * time.Second, + }, nil + } + + return &pollers.PollResult{ + Status: pollers.PollingStatusInProgress, + PollInterval: 5 * time.Second, + }, nil +} diff --git a/internal/services/mssql/helper/elasticpool.go b/internal/services/mssql/helper/elasticpool.go index a7464e03ce0b..cd252fe1c89d 100644 --- a/internal/services/mssql/helper/elasticpool.go +++ b/internal/services/mssql/helper/elasticpool.go @@ -269,14 +269,14 @@ func MSSQLElasticPoolValidateSKU(diff *pluginsdk.ResourceDiff) error { // Universal check for both DTU and vCore based SKUs if !nameTierIsValid(s) { - return fmt.Errorf("Mismatch between SKU name '%s' and tier '%s', expected 'tier' to be '%s'", s.Name, s.Tier, getTierFromName[strings.ToLower(s.Name)]) + return fmt.Errorf("mismatch between SKU name '%s' and tier '%s', expected 'tier' to be '%s'", s.Name, s.Tier, getTierFromName[strings.ToLower(s.Name)]) } // Verify that Family is valid if s.SkuType == DTU && s.Family != "" { - return fmt.Errorf("Invalid attribute 'family'(%s) for service tier '%s', remove the 'family' attribute from the configuration file", s.Family, s.Tier) + return fmt.Errorf("invalid attribute 'family'(%s) for service tier '%s', remove the 'family' attribute from the configuration file", s.Family, s.Tier) } else if s.SkuType == VCore && !nameContainsFamily(s) { - return fmt.Errorf("Mismatch between SKU name '%s' and family '%s', expected '%s'", s.Name, s.Family, getFamilyFromName(s)) + return fmt.Errorf("mismatch between SKU name '%s' and family '%s', expected '%s'", s.Name, s.Family, getFamilyFromName(s)) } // get max GB and do validation based on SKU type diff --git a/internal/services/mssql/helper/sql_retention_policies.go b/internal/services/mssql/helper/sql_retention_policies.go index 070cd9a25bcf..901bd3768954 100644 --- a/internal/services/mssql/helper/sql_retention_policies.go +++ b/internal/services/mssql/helper/sql_retention_policies.go @@ -7,11 +7,12 @@ import ( "strconv" "strings" - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "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/longtermretentionpolicies" "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func LongTermRetentionPolicySchema() *pluginsdk.Schema { @@ -98,62 +99,62 @@ func ShortTermRetentionPolicySchema() *pluginsdk.Schema { } } -func ExpandLongTermRetentionPolicy(input []interface{}) *sql.BaseLongTermRetentionPolicyProperties { +func ExpandLongTermRetentionPolicy(input []interface{}) *longtermretentionpolicies.LongTermRetentionPolicyProperties { if len(input) == 0 || input[0] == nil { return nil } - longTermRetentionPolicy := input[0].(map[string]interface{}) + policy := input[0].(map[string]interface{}) - longTermPolicyProperties := sql.BaseLongTermRetentionPolicyProperties{ - WeeklyRetention: utils.String("PT0S"), - MonthlyRetention: utils.String("PT0S"), - YearlyRetention: utils.String("PT0S"), - WeekOfYear: utils.Int32(1), + output := longtermretentionpolicies.LongTermRetentionPolicyProperties{ + WeeklyRetention: pointer.To("PT0S"), + MonthlyRetention: pointer.To("PT0S"), + YearlyRetention: pointer.To("PT0S"), + WeekOfYear: pointer.To(int64(1)), } - if v, ok := longTermRetentionPolicy["weekly_retention"]; ok { - longTermPolicyProperties.WeeklyRetention = utils.String(v.(string)) + if v, ok := policy["weekly_retention"]; ok { + output.WeeklyRetention = pointer.To(v.(string)) } - if v, ok := longTermRetentionPolicy["monthly_retention"]; ok { - longTermPolicyProperties.MonthlyRetention = utils.String(v.(string)) + if v, ok := policy["monthly_retention"]; ok { + output.MonthlyRetention = pointer.To(v.(string)) } - if v, ok := longTermRetentionPolicy["yearly_retention"]; ok { - longTermPolicyProperties.YearlyRetention = utils.String(v.(string)) + if v, ok := policy["yearly_retention"]; ok { + output.YearlyRetention = pointer.To(v.(string)) } - if v, ok := longTermRetentionPolicy["week_of_year"]; ok { - longTermPolicyProperties.WeekOfYear = utils.Int32(int32(v.(int))) + if v, ok := policy["week_of_year"]; ok { + output.WeekOfYear = pointer.To(int64(v.(int))) } - return &longTermPolicyProperties + return pointer.To(output) } -func FlattenLongTermRetentionPolicy(longTermRetentionPolicy *sql.LongTermRetentionPolicy, d *pluginsdk.ResourceData) []interface{} { - if longTermRetentionPolicy == nil { +func FlattenLongTermRetentionPolicy(input *longtermretentionpolicies.LongTermRetentionPolicy) []interface{} { + if input == nil { return []interface{}{} } monthlyRetention := "PT0S" - if longTermRetentionPolicy.MonthlyRetention != nil { - monthlyRetention = *longTermRetentionPolicy.MonthlyRetention + if input.Properties.MonthlyRetention != nil { + monthlyRetention = pointer.From(input.Properties.MonthlyRetention) } weeklyRetention := "PT0S" - if longTermRetentionPolicy.WeeklyRetention != nil { - weeklyRetention = *longTermRetentionPolicy.WeeklyRetention + if input.Properties.WeeklyRetention != nil { + weeklyRetention = pointer.From(input.Properties.WeeklyRetention) } - weekOfYear := int32(1) - if longTermRetentionPolicy.WeekOfYear != nil && *longTermRetentionPolicy.WeekOfYear != 0 { - weekOfYear = *longTermRetentionPolicy.WeekOfYear + weekOfYear := int64(1) + if input.Properties.WeekOfYear != nil && pointer.From(input.Properties.WeekOfYear) != 0 { + weekOfYear = pointer.From(input.Properties.WeekOfYear) } yearlyRetention := "PT0S" - if longTermRetentionPolicy.YearlyRetention != nil { - yearlyRetention = *longTermRetentionPolicy.YearlyRetention + if input.Properties.YearlyRetention != nil { + yearlyRetention = *input.Properties.YearlyRetention } return []interface{}{ @@ -166,45 +167,47 @@ func FlattenLongTermRetentionPolicy(longTermRetentionPolicy *sql.LongTermRetenti } } -func ExpandShortTermRetentionPolicy(input []interface{}) *sql.BackupShortTermRetentionPolicyProperties { +func ExpandShortTermRetentionPolicy(input []interface{}) *backupshorttermretentionpolicies.BackupShortTermRetentionPolicyProperties { if len(input) == 0 || input[0] == nil { return nil } - shortTermRetentionPolicy := input[0].(map[string]interface{}) + policy := input[0].(map[string]interface{}) - shortTermPolicyProperties := sql.BackupShortTermRetentionPolicyProperties{ - RetentionDays: utils.Int32(7), + props := backupshorttermretentionpolicies.BackupShortTermRetentionPolicyProperties{ + RetentionDays: pointer.To(int64(7)), } - if v, ok := shortTermRetentionPolicy["retention_days"]; ok { - shortTermPolicyProperties.RetentionDays = utils.Int32(int32(v.(int))) + if v, ok := policy["retention_days"]; ok { + props.RetentionDays = pointer.To(int64(v.(int))) } - if v, ok := shortTermRetentionPolicy["backup_interval_in_hours"]; ok { - shortTermPolicyProperties.DiffBackupIntervalInHours = utils.Int32(int32(v.(int))) + if v, ok := policy["backup_interval_in_hours"]; ok { + props.DiffBackupIntervalInHours = pointer.To(backupshorttermretentionpolicies.DiffBackupIntervalInHours(int64(v.(int)))) } - return &shortTermPolicyProperties + return &props } -func FlattenShortTermRetentionPolicy(shortTermRetentionPolicy *sql.BackupShortTermRetentionPolicy, d *pluginsdk.ResourceData) []interface{} { +func FlattenShortTermRetentionPolicy(input *backupshorttermretentionpolicies.BackupShortTermRetentionPolicy) []interface{} { result := make([]interface{}, 0) - if shortTermRetentionPolicy == nil { + if input == nil { return result } - flattenShortTermRetentionPolicy := map[string]interface{}{} + output := map[string]interface{}{} - flattenShortTermRetentionPolicy["retention_days"] = int32(7) - if shortTermRetentionPolicy.RetentionDays != nil { - flattenShortTermRetentionPolicy["retention_days"] = *shortTermRetentionPolicy.RetentionDays + output["retention_days"] = int64(7) + if input.Properties.RetentionDays != nil { + output["retention_days"] = pointer.From(input.Properties.RetentionDays) } - if shortTermRetentionPolicy.DiffBackupIntervalInHours != nil { - flattenShortTermRetentionPolicy["backup_interval_in_hours"] = *shortTermRetentionPolicy.DiffBackupIntervalInHours + if input.Properties.DiffBackupIntervalInHours != nil { + output["backup_interval_in_hours"] = pointer.From(input.Properties.DiffBackupIntervalInHours) } - result = append(result, flattenShortTermRetentionPolicy) + + result = append(result, output) + return result } diff --git a/internal/services/mssql/mssql_database_data_source.go b/internal/services/mssql/mssql_database_data_source.go index 7e23527f9923..a020602f24f6 100644 --- a/internal/services/mssql/mssql_database_data_source.go +++ b/internal/services/mssql/mssql_database_data_source.go @@ -7,14 +7,16 @@ import ( "fmt" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/databases" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceMsSqlDatabase() *pluginsdk.Resource { @@ -83,7 +85,7 @@ func dataSourceMsSqlDatabase() *pluginsdk.Resource { Computed: true, }, - "tags": tags.SchemaDataSource(), + "tags": commonschema.TagsDataSource(), }, } } @@ -95,41 +97,58 @@ func dataSourceMsSqlDatabaseRead(d *pluginsdk.ResourceData, meta interface{}) er name := d.Get("name").(string) mssqlServerId := d.Get("server_id").(string) - serverId, err := parse.ServerID(mssqlServerId) + serverId, err := commonids.ParseSqlServerID(mssqlServerId) if err != nil { return err } - resp, err := client.Get(ctx, serverId.ResourceGroup, serverId.Name, name) + databaseId := commonids.NewSqlDatabaseID(serverId.SubscriptionId, serverId.ResourceGroupName, serverId.ServerName, name) + + resp, err := client.Get(ctx, databaseId, databases.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return fmt.Errorf("Database %q (Resource Group %q, SQL Server %q) was not found", name, serverId.ResourceGroup, serverId.Name) + if response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("%s was not found", databaseId) } - return fmt.Errorf("making Read request on AzureRM Database %s (Resource Group %q, SQL Server %q): %+v", name, serverId.ResourceGroup, serverId.Name, err) + return fmt.Errorf("making Read request on AzureRM %s: %+v", databaseId, err) } - d.SetId(parse.NewDatabaseID(serverId.SubscriptionId, serverId.ResourceGroup, serverId.Name, name).ID()) + d.SetId(databaseId.ID()) d.Set("name", name) d.Set("server_id", mssqlServerId) - if props := resp.DatabaseProperties; props != nil { - d.Set("collation", props.Collation) - d.Set("elastic_pool_id", props.ElasticPoolID) - d.Set("license_type", props.LicenseType) - if props.MaxSizeBytes != nil { - d.Set("max_size_gb", int32((*props.MaxSizeBytes)/int64(1073741824))) + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + d.Set("collation", props.Collation) + d.Set("elastic_pool_id", props.ElasticPoolId) + d.Set("license_type", string(pointer.From(props.LicenseType))) + d.Set("read_replica_count", props.HighAvailabilityReplicaCount) + d.Set("sku_name", props.CurrentServiceObjectiveName) + d.Set("zone_redundant", props.ZoneRedundant) + + maxSizeGb := int64(0) + if props.MaxSizeBytes != nil { + maxSizeGb = (pointer.From(props.MaxSizeBytes)) / int64(1073741824) + } + d.Set("max_size_gb", maxSizeGb) + + readScale := databases.DatabaseReadScaleDisabled + if props.ReadScale != nil { + readScale = pointer.From(props.ReadScale) + } + d.Set("read_scale", readScale == databases.DatabaseReadScaleEnabled) + + storageAccountType := string(databases.BackupStorageRedundancyGeo) + if props.CurrentBackupStorageRedundancy != nil { + storageAccountType = string(pointer.From(props.CurrentBackupStorageRedundancy)) + } + d.Set("storage_account_type", storageAccountType) } - d.Set("read_replica_count", props.HighAvailabilityReplicaCount) - if props.ReadScale == sql.DatabaseReadScaleEnabled { - d.Set("read_scale", true) - } else if props.ReadScale == sql.DatabaseReadScaleDisabled { - d.Set("read_scale", false) + + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err } - d.Set("sku_name", props.CurrentServiceObjectiveName) - d.Set("storage_account_type", sql.RequestedBackupStorageRedundancy(props.CurrentBackupStorageRedundancy)) - d.Set("zone_redundant", props.ZoneRedundant) } - return tags.FlattenAndSet(d, resp.Tags) + return nil } diff --git a/internal/services/mssql/mssql_database_extended_auditing_policy_resource.go b/internal/services/mssql/mssql_database_extended_auditing_policy_resource.go index af75527acb60..814beab390c0 100644 --- a/internal/services/mssql/mssql_database_extended_auditing_policy_resource.go +++ b/internal/services/mssql/mssql_database_extended_auditing_policy_resource.go @@ -9,6 +9,8 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" @@ -103,7 +105,7 @@ func resourceMsSqlDatabaseExtendedAuditingPolicyCreateUpdate(d *pluginsdk.Resour existing, err := client.Get(ctx, dbId.ResourceGroup, dbId.ServerName, dbId.Name) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("Failed to check for presence of existing Database %q Sql Auditing (MsSql Server %q / Resource Group %q): %s", dbId.Name, dbId.ServerName, dbId.ResourceGroup, err) + return fmt.Errorf("checking for the presence of existing %s: %+v", dbId, err) } } @@ -133,26 +135,31 @@ func resourceMsSqlDatabaseExtendedAuditingPolicyCreateUpdate(d *pluginsdk.Resour } if _, err = client.CreateOrUpdate(ctx, dbId.ResourceGroup, dbId.ServerName, dbId.Name, params); err != nil { - return fmt.Errorf("creating MsSql Database %q Extended Auditing Policy (Sql Server %q / Resource Group %q): %+v", dbId.Name, dbId.ServerName, dbId.ResourceGroup, err) + return fmt.Errorf("creating extended auditing policy for %s: %+v", dbId, err) } read, err := client.Get(ctx, dbId.ResourceGroup, dbId.ServerName, dbId.Name) if err != nil { - return fmt.Errorf("retrieving MsSql Database %q Extended Auditing Policy (MsSql Server Name %q / Resource Group %q): %+v", dbId.Name, dbId.ServerName, dbId.ResourceGroup, err) + return fmt.Errorf("retrieving the extended auditing policy for %s: %+v", dbId, err) } - if read.ID == nil || *read.ID == "" { - return fmt.Errorf("reading MsSql Database %q Extended Auditing Policy (MsSql Server Name %q / Resource Group %q) ID is empty or nil", dbId.Name, dbId.ServerName, dbId.ResourceGroup) + if read.ID == nil || pointer.From(read.ID) == "" { + return fmt.Errorf("the extended auditing policy ID for %s is 'nil' or 'empty'", dbId.String()) } - d.SetId(*read.ID) + // TODO: update this to use the Database ID - requiring a State Migration + readId, err := parse.DatabaseExtendedAuditingPolicyID(pointer.From(read.ID)) + if err != nil { + return err + } + + d.SetId(readId.ID()) return resourceMsSqlDatabaseExtendedAuditingPolicyRead(d, meta) } func resourceMsSqlDatabaseExtendedAuditingPolicyRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).MSSQL.DatabaseExtendedBlobAuditingPoliciesClient - dbClient := meta.(*clients.Client).MSSQL.DatabasesClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -170,12 +177,8 @@ func resourceMsSqlDatabaseExtendedAuditingPolicyRead(d *pluginsdk.ResourceData, return fmt.Errorf("reading MsSql Database %s Extended Auditing Policy (MsSql Server Name %q / Resource Group %q): %s", id.DatabaseName, id.ServerName, id.ResourceGroup, err) } - dbResp, err := dbClient.Get(ctx, id.ResourceGroup, id.ServerName, id.DatabaseName) - if err != nil || *dbResp.ID == "" { - return fmt.Errorf("reading MsSql Database %q ID is empty or nil(Resource Group %q): %s", id.ServerName, id.ResourceGroup, err) - } - - d.Set("database_id", dbResp.ID) + databaseId := commonids.NewSqlDatabaseID(id.SubscriptionId, id.ResourceGroup, id.ServerName, id.DatabaseName) + d.Set("database_id", databaseId.ID()) if props := resp.ExtendedDatabaseBlobAuditingPolicyProperties; props != nil { d.Set("storage_endpoint", props.StorageEndpoint) diff --git a/internal/services/mssql/mssql_database_resource.go b/internal/services/mssql/mssql_database_resource.go index 5f00d7466f6d..0a4bac92eabf 100644 --- a/internal/services/mssql/mssql_database_resource.go +++ b/internal/services/mssql/mssql_database_resource.go @@ -11,10 +11,20 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck - "github.com/Azure/go-autorest/autorest/date" "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" "github.com/hashicorp/go-azure-sdk/resource-manager/maintenance/2022-07-01-preview/publicmaintenanceconfigurations" + "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/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" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serversecurityalertpolicies" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/transparentdataencryptions" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -23,7 +33,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/migration" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/suppress" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -75,8 +84,8 @@ func resourceMsSqlDatabase() *pluginsdk.Resource { } func resourceMsSqlDatabaseImporter(ctx context.Context, d *pluginsdk.ResourceData, meta interface{}) ([]*pluginsdk.ResourceData, error) { - client := meta.(*clients.Client).MSSQL.DatabasesClient - replicationLinksClient := meta.(*clients.Client).MSSQL.ReplicationLinksClient + legacyClient := meta.(*clients.Client).MSSQL.LegacyDatabasesClient + legacyreplicationLinksClient := meta.(*clients.Client).MSSQL.LegacyReplicationLinksClient resourcesClient := meta.(*clients.Client).Resource.ResourcesClient id, err := parse.DatabaseID(d.Id()) @@ -84,7 +93,7 @@ func resourceMsSqlDatabaseImporter(ctx context.Context, d *pluginsdk.ResourceDat return nil, err } - partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, client, replicationLinksClient, resourcesClient, *id, []sql.ReplicationRole{sql.ReplicationRolePrimary}) + partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, legacyClient, legacyreplicationLinksClient, resourcesClient, *id, []sql.ReplicationRole{sql.ReplicationRolePrimary}) if err != nil { return nil, err } @@ -97,25 +106,26 @@ func resourceMsSqlDatabaseImporter(ctx context.Context, d *pluginsdk.ResourceDat return nil, fmt.Errorf("parsing ID for Replication Partner Database %q: %+v", *partnerDatabase.ID, err) } - d.Set("create_mode", string(sql.CreateModeSecondary)) + d.Set("create_mode", string(databases.CreateModeSecondary)) d.Set("creation_source_database_id", partnerDatabaseId.ID()) return []*pluginsdk.ResourceData{d}, nil } - d.Set("create_mode", string(sql.CreateModeDefault)) + d.Set("create_mode", string(databases.CreateModeDefault)) return []*pluginsdk.ResourceData{d}, nil } func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).MSSQL.DatabasesClient + legacyClient := meta.(*clients.Client).MSSQL.LegacyDatabasesClient serversClient := meta.(*clients.Client).MSSQL.ServersClient - securityAlertPoliciesClient := meta.(*clients.Client).MSSQL.DatabaseSecurityAlertPoliciesClient + databaseSecurityAlertPoliciesClient := meta.(*clients.Client).MSSQL.DatabaseSecurityAlertPoliciesClient longTermRetentionClient := meta.(*clients.Client).MSSQL.LongTermRetentionPoliciesClient shortTermRetentionClient := meta.(*clients.Client).MSSQL.BackupShortTermRetentionPoliciesClient geoBackupPoliciesClient := meta.(*clients.Client).MSSQL.GeoBackupPoliciesClient - replicationLinksClient := meta.(*clients.Client).MSSQL.ReplicationLinksClient + legacyReplicationLinksClient := meta.(*clients.Client).MSSQL.LegacyReplicationLinksClient resourcesClient := meta.(*clients.Client).Resource.ResourcesClient transparentEncryptionClient := meta.(*clients.Client).MSSQL.TransparentDataEncryptionsClient @@ -130,31 +140,35 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er name := d.Get("name").(string) - serverId, err := parse.ServerID(d.Get("server_id").(string)) + serverId, err := commonids.ParseSqlServerID(d.Get("server_id").(string)) if err != nil { return fmt.Errorf("parsing server ID: %+v", err) } - id := parse.NewDatabaseID(serverId.SubscriptionId, serverId.ResourceGroup, serverId.Name, name) + id := commonids.NewSqlDatabaseID(serverId.SubscriptionId, serverId.ResourceGroupName, serverId.ServerName, name) - if existing, err := client.Get(ctx, serverId.ResourceGroup, serverId.Name, name); err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if existing, err := client.Get(ctx, id, databases.DefaultGetOperationOptions()); err != nil { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } else { return tf.ImportAsExistsError("azurerm_mssql_database", id.ID()) } - server, err := serversClient.Get(ctx, serverId.ResourceGroup, serverId.Name, "") + server, err := serversClient.Get(ctx, *serverId, servers.DefaultGetOperationOptions()) if err != nil { return fmt.Errorf("retrieving %s: %q", serverId, err) } - if server.Location == nil || *server.Location == "" { - return fmt.Errorf("reading %s: Location was nil/empty", serverId) + if server.Model == nil { + return fmt.Errorf("server model was nil") + } + + if server.Model.Location == "" { + return fmt.Errorf("reading %s: Location was empty", serverId) } - location := *server.Location + location := server.Model.Location ledgerEnabled := d.Get("ledger_enabled").(bool) // When databases are replicating, the primary cannot have a SKU belonging to a higher service tier than any of its @@ -172,8 +186,13 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er locks.ByID(id.ID()) defer locks.UnlockByID(id.ID()) + legacyId, err := parse.DatabaseID(id.ID()) + if err != nil { + return fmt.Errorf("parsing ID for Replication Partner Database %s: %+v", id, err) + } + if skuName := d.Get("sku_name"); skuName != "" { - partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, client, replicationLinksClient, resourcesClient, id, []sql.ReplicationRole{sql.ReplicationRoleSecondary, sql.ReplicationRoleNonReadableSecondary}) + partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, legacyClient, legacyReplicationLinksClient, resourcesClient, *legacyId, []sql.ReplicationRole{sql.ReplicationRoleSecondary, sql.ReplicationRoleNonReadableSecondary}) if err != nil { return err } @@ -198,7 +217,7 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er // See: https://docs.microsoft.com/en-us/azure/azure-sql/database/active-geo-replication-overview#configuring-secondary-database if partnerDatabase.Sku != nil && partnerDatabase.Sku.Name != nil && helper.CompareDatabaseSkuServiceTiers(skuName.(string), *partnerDatabase.Sku.Name) { - future, err := client.Update(ctx, partnerDatabaseId.ResourceGroup, partnerDatabaseId.ServerName, partnerDatabaseId.Name, sql.DatabaseUpdate{ + future, err := legacyClient.Update(ctx, partnerDatabaseId.ResourceGroup, partnerDatabaseId.ServerName, partnerDatabaseId.Name, sql.DatabaseUpdate{ Sku: &sql.Sku{ Name: utils.String(skuName.(string)), }, @@ -207,40 +226,39 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("updating SKU of Replication Partner %s: %+v", partnerDatabaseId, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if err = future.WaitForCompletionRef(ctx, legacyClient.Client); err != nil { return fmt.Errorf("waiting for SKU update for Replication Partner %s: %+v", partnerDatabaseId, err) } } } } - params := sql.Database{ - Name: &name, - Location: &location, - DatabaseProperties: &sql.DatabaseProperties{ - AutoPauseDelay: utils.Int32(int32(d.Get("auto_pause_delay_in_minutes").(int))), - Collation: utils.String(d.Get("collation").(string)), - ElasticPoolID: utils.String(d.Get("elastic_pool_id").(string)), - LicenseType: sql.DatabaseLicenseType(d.Get("license_type").(string)), + input := databases.Database{ + Location: location, + Properties: &databases.DatabaseProperties{ + AutoPauseDelay: pointer.To(int64(d.Get("auto_pause_delay_in_minutes").(int))), + Collation: pointer.To(d.Get("collation").(string)), + ElasticPoolId: pointer.To(d.Get("elastic_pool_id").(string)), + LicenseType: pointer.To(databases.DatabaseLicenseType(d.Get("license_type").(string))), MinCapacity: utils.Float(d.Get("min_capacity").(float64)), - HighAvailabilityReplicaCount: utils.Int32(int32(d.Get("read_replica_count").(int))), - SampleName: sql.SampleName(d.Get("sample_name").(string)), - RequestedBackupStorageRedundancy: sql.RequestedBackupStorageRedundancy(d.Get("storage_account_type").(string)), - ZoneRedundant: utils.Bool(d.Get("zone_redundant").(bool)), - IsLedgerOn: utils.Bool(ledgerEnabled), + HighAvailabilityReplicaCount: pointer.To(int64(d.Get("read_replica_count").(int))), + SampleName: pointer.To(databases.SampleName(d.Get("sample_name").(string))), + RequestedBackupStorageRedundancy: pointer.To(databases.BackupStorageRedundancy(d.Get("storage_account_type").(string))), + ZoneRedundant: pointer.To(d.Get("zone_redundant").(bool)), + IsLedgerOn: pointer.To(ledgerEnabled), }, Tags: tags.Expand(d.Get("tags").(map[string]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.CreateModeSecondary)) && !dbok { + if _, dbok := d.GetOk("creation_source_database_id"); ok && (createMode.(string) == string(databases.CreateModeCopy) || createMode.(string) == string(databases.CreateModePointInTimeRestore) || createMode.(string) == string(databases.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 { + if _, dbok := d.GetOk("recover_database_id"); ok && createMode.(string) == string(databases.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 { + if _, dbok := d.GetOk("restore_dropped_database_id"); ok && createMode.(string) == string(databases.CreateModeRestore) && !dbok { return fmt.Errorf("'restore_dropped_database_id' is required for create_mode %s", createMode.(string)) } @@ -251,125 +269,132 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er if v, ok := d.GetOk("maintenance_configuration_name"); ok { maintenanceConfigId = publicmaintenanceconfigurations.NewPublicMaintenanceConfigurationID(serverId.SubscriptionId, v.(string)) } - params.MaintenanceConfigurationID = utils.String(maintenanceConfigId.ID()) + input.Properties.MaintenanceConfigurationId = utils.String(maintenanceConfigId.ID()) } - params.DatabaseProperties.CreateMode = sql.CreateMode(createMode.(string)) + input.Properties.CreateMode = pointer.To(databases.CreateMode(createMode.(string))) if v, ok := d.GetOk("max_size_gb"); ok { // `max_size_gb` is Computed, so has a value after the first run - if createMode != string(sql.CreateModeOnlineSecondary) && createMode != string(sql.CreateModeSecondary) { - params.DatabaseProperties.MaxSizeBytes = utils.Int64(int64(v.(int)) * 1073741824) + if createMode != string(databases.CreateModeOnlineSecondary) && createMode != string(databases.CreateModeSecondary) { + input.Properties.MaxSizeBytes = pointer.To(int64(v.(int)) * 1073741824) } // `max_size_gb` only has change if it is configured - if d.HasChange("max_size_gb") && (createMode == string(sql.CreateModeOnlineSecondary) || createMode == string(sql.CreateModeSecondary)) { + if d.HasChange("max_size_gb") && (createMode == string(databases.CreateModeOnlineSecondary) || createMode == string(databases.CreateModeSecondary)) { return fmt.Errorf("it is not possible to change maximum size nor advised to configure maximum size in secondary create mode for %s", id) } } - readScale := sql.DatabaseReadScaleDisabled + readScale := databases.DatabaseReadScaleDisabled if v := d.Get("read_scale").(bool); v { - readScale = sql.DatabaseReadScaleEnabled + readScale = databases.DatabaseReadScaleEnabled } - params.DatabaseProperties.ReadScale = readScale + input.Properties.ReadScale = pointer.To(readScale) if v, ok := d.GetOk("restore_point_in_time"); ok { - if cm, ok := d.GetOk("create_mode"); ok && cm.(string) != string(sql.CreateModePointInTimeRestore) { - return fmt.Errorf("'restore_point_in_time' is supported only for create_mode %s", string(sql.CreateModePointInTimeRestore)) - } - restorePointInTime, err := time.Parse(time.RFC3339, v.(string)) - if err != nil { - return fmt.Errorf("parsing `restore_point_in_time` value %q for %s: %+v", v, id, err) + if cm, ok := d.GetOk("create_mode"); ok && cm.(string) != string(databases.CreateModePointInTimeRestore) { + return fmt.Errorf("'restore_point_in_time' is supported only for create_mode %s", string(databases.CreateModePointInTimeRestore)) } - params.DatabaseProperties.RestorePointInTime = &date.Time{Time: restorePointInTime} + + input.Properties.RestorePointInTime = pointer.To(v.(string)) } skuName, ok := d.GetOk("sku_name") if ok { - params.Sku = &sql.Sku{ - Name: utils.String(skuName.(string)), - } + input.Sku = pointer.To(databases.Sku{ + Name: skuName.(string), + }) } if v, ok := d.GetOk("creation_source_database_id"); ok { - params.DatabaseProperties.SourceDatabaseID = utils.String(v.(string)) + input.Properties.SourceDatabaseId = pointer.To(v.(string)) } if v, ok := d.GetOk("recover_database_id"); ok { - params.DatabaseProperties.RecoverableDatabaseID = utils.String(v.(string)) + input.Properties.RecoverableDatabaseId = pointer.To(v.(string)) } if v, ok := d.GetOk("restore_dropped_database_id"); ok { - params.DatabaseProperties.RestorableDroppedDatabaseID = utils.String(v.(string)) + input.Properties.RestorableDroppedDatabaseId = pointer.To(v.(string)) } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, params) + err = client.CreateOrUpdateThenPoll(ctx, id, input) if err != nil { - return fmt.Errorf("creating/updating %s: %+v", id, err) - } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for create/update of %s: %+v", id, err) + return fmt.Errorf("creating %s: %+v", id, err) } // Wait for the ProvisioningState to become "Succeeded" log.Printf("[DEBUG] Waiting for %s to become ready", id) pendingStatuses := make([]string, 0) - for _, s := range sql.PossibleDatabaseStatusValues() { - if s != sql.DatabaseStatusOnline { - pendingStatuses = append(pendingStatuses, string(s)) + for _, s := range databases.PossibleValuesForDatabaseStatus() { + if s != string(databases.DatabaseStatusOnline) { + pendingStatuses = append(pendingStatuses, s) } } + + deadline, ok := ctx.Deadline() + if !ok { + return fmt.Errorf("internal-error: context had no deadline") + } + + // NOTE: Internal x-ref, this is another case of hashicorp/go-azure-sdk#307 so this can be removed once that's fixed stateConf := &pluginsdk.StateChangeConf{ Pending: pendingStatuses, - Target: []string{string(sql.DatabaseStatusOnline)}, + Target: []string{string(databases.DatabaseStatusOnline)}, Refresh: func() (interface{}, string, error) { log.Printf("[DEBUG] Checking to see if %s is online...", id) - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, id, databases.DefaultGetOperationOptions()) if err != nil { return nil, "", fmt.Errorf("polling for the status of %s: %+v", id, err) } - if props := resp.DatabaseProperties; props != nil { - return resp, string(props.Status), nil + if resp.Model != nil && resp.Model.Properties != nil && resp.Model.Properties.Status != nil { + return resp, string(pointer.From(resp.Model.Properties.Status)), nil } return resp, "", nil }, - MinTimeout: 1 * time.Minute, ContinuousTargetOccurence: 2, + MinTimeout: 1 * time.Minute, + Timeout: time.Until(deadline), } - stateConf.Timeout = d.Timeout(pluginsdk.TimeoutCreate) - + // NOTE: Internal x-ref, this is another case of hashicorp/go-azure-sdk#307 so this can be removed once that's fixed if _, err = stateConf.WaitForStateContext(ctx); err != nil { return fmt.Errorf("waiting for %s to become ready: %+v", id, err) } // Cannot set transparent data encryption for secondary databases - if createMode != string(sql.CreateModeOnlineSecondary) && createMode != string(sql.CreateModeSecondary) { - statusProperty := sql.TransparentDataEncryptionStatusDisabled - encryptionStatus := d.Get("transparent_data_encryption_enabled").(bool) - if encryptionStatus { - statusProperty = sql.TransparentDataEncryptionStatusEnabled + if createMode != string(databases.CreateModeOnlineSecondary) && createMode != string(databases.CreateModeSecondary) { + state := transparentdataencryptions.TransparentDataEncryptionStateDisabled + if v := d.Get("transparent_data_encryption_enabled").(bool); v { + state = transparentdataencryptions.TransparentDataEncryptionStateEnabled } - _, err := transparentEncryptionClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, sql.TransparentDataEncryption{ - TransparentDataEncryptionProperties: &sql.TransparentDataEncryptionProperties{ - Status: statusProperty, + + input := transparentdataencryptions.LogicalDatabaseTransparentDataEncryption{ + Properties: &transparentdataencryptions.TransparentDataEncryptionProperties{ + State: state, }, - }) + } + + err := transparentEncryptionClient.CreateOrUpdateThenPoll(ctx, id, input) if err != nil { return fmt.Errorf("while enabling Transparent Data Encryption for %q: %+v", id.String(), err) } + // NOTE: Internal x-ref, this is another case of hashicorp/go-azure-sdk#307 so this can be removed once that's fixed if err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *pluginsdk.RetryError { - c, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + c, err := client.Get(ctx, id, databases.DefaultGetOperationOptions()) if err != nil { - return pluginsdk.NonRetryableError(fmt.Errorf("while polling cluster %s for status: %+v", id.String(), err)) + return pluginsdk.NonRetryableError(fmt.Errorf("while polling %s for status: %+v", id.String(), err)) } - if c.DatabaseProperties.Status == sql.DatabaseStatusScaling { - return pluginsdk.RetryableError(fmt.Errorf("database %s is still scaling", id.String())) + if c.Model != nil && c.Model.Properties != nil && c.Model.Properties.Status != nil { + if c.Model.Properties.Status == pointer.To(databases.DatabaseStatusScaling) { + return pluginsdk.RetryableError(fmt.Errorf("database %s is still scaling", id.String())) + } + } else { + return pluginsdk.RetryableError(fmt.Errorf("retrieving database status %s: Model, Properties or Status is nil", id.String())) } return nil @@ -380,13 +405,9 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er if _, ok := d.GetOk("import"); ok { importParameters := expandMsSqlServerImport(d) - importFuture, err := client.Import(ctx, id.ResourceGroup, id.ServerName, id.Name, importParameters) + err := client.ImportThenPoll(ctx, id, importParameters) if err != nil { - return fmt.Errorf("while import bacpac into the new database %s (Resource Group %s): %+v", id.Name, id.ResourceGroup, err) - } - - if err = importFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("while import bacpac into the new database %s (Resource Group %s): %+v", id.Name, id.ResourceGroup, err) + return fmt.Errorf("while import bacpac into the new database %s: %+v", id, err) } } @@ -394,38 +415,31 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er // For datawarehouse SKUs only if strings.HasPrefix(skuName.(string), "DW") { - isEnabled := d.Get("geo_backup_enabled").(bool) - var geoBackupPolicyState sql.GeoBackupPolicyState + enabled := d.Get("geo_backup_enabled").(bool) // The default geo backup policy configuration for a new resource is 'enabled', so we don't need to set it in that scenario - if !isEnabled { - if isEnabled { - geoBackupPolicyState = sql.GeoBackupPolicyStateEnabled - } else { - geoBackupPolicyState = sql.GeoBackupPolicyStateDisabled + if !enabled { + input := geobackuppolicies.GeoBackupPolicy{ + Properties: pointer.To(geobackuppolicies.GeoBackupPolicyProperties{ + State: geobackuppolicies.GeoBackupPolicyStateDisabled, + }), } - geoBackupPolicy := sql.GeoBackupPolicy{ - GeoBackupPolicyProperties: &sql.GeoBackupPolicyProperties{ - State: geoBackupPolicyState, - }, - } - - if _, err := geoBackupPoliciesClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, geoBackupPolicy); err != nil { - return fmt.Errorf("setting Geo Backup Policies for %s: %+v", id, err) + if _, err := geoBackupPoliciesClient.CreateOrUpdate(ctx, id, input); err != nil { + return fmt.Errorf("setting Geo Backup Policies %s: %+v", id, err) } } } if err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *pluginsdk.RetryError { - result, err := securityAlertPoliciesClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, expandMsSqlServerSecurityAlertPolicy(d)) + result, err := databaseSecurityAlertPoliciesClient.CreateOrUpdate(ctx, id, expandMsSqlDatabaseSecurityAlertPolicy(d)) - if utils.ResponseWasNotFound(result.Response) { - return pluginsdk.RetryableError(fmt.Errorf("database %s is still creating", id.String())) + if response.WasNotFound(result.HttpResponse) { + return pluginsdk.RetryableError(fmt.Errorf("database %s is still creating", id)) } if err != nil { - return pluginsdk.NonRetryableError(fmt.Errorf("setting database threat detection policy for %s: %+v", id, err)) + return pluginsdk.NonRetryableError(fmt.Errorf("setting database threat detection policy %s: %+v", id, err)) } return nil @@ -433,44 +447,37 @@ func resourceMsSqlDatabaseCreate(d *pluginsdk.ResourceData, meta interface{}) er return nil } - longTermRetentionProps := helper.ExpandLongTermRetentionPolicy(d.Get("long_term_retention_policy").([]interface{})) - if longTermRetentionProps != nil { - longTermRetentionPolicy := sql.LongTermRetentionPolicy{} + securityAlertPolicyProps := helper.ExpandLongTermRetentionPolicy(d.Get("long_term_retention_policy").([]interface{})) + if securityAlertPolicyProps != nil { + securityAlertPolicyPayload := longtermretentionpolicies.LongTermRetentionPolicy{} // DataWarehouse SKU's do not support LRP currently if !strings.HasPrefix(skuName.(string), "DW") { - longTermRetentionPolicy.BaseLongTermRetentionPolicyProperties = longTermRetentionProps + securityAlertPolicyPayload.Properties = securityAlertPolicyProps } - longTermRetentionfuture, err := longTermRetentionClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, longTermRetentionPolicy) + err := longTermRetentionClient.CreateOrUpdateThenPoll(ctx, id, securityAlertPolicyPayload) if err != nil { return fmt.Errorf("setting Long Term Retention Policies for %s: %+v", id, err) } - - if err = longTermRetentionfuture.WaitForCompletionRef(ctx, longTermRetentionClient.Client); err != nil { - return fmt.Errorf("waiting for update of Long Term Retention Policies for %s: %+v", id, err) - } } - backupShortTermPolicyProps := helper.ExpandShortTermRetentionPolicy(d.Get("short_term_retention_policy").([]interface{})) - if backupShortTermPolicyProps != nil { - backupShortTermPolicy := sql.BackupShortTermRetentionPolicy{} + shortTermSecurityAlertPolicyProps := helper.ExpandShortTermRetentionPolicy(d.Get("short_term_retention_policy").([]interface{})) + if securityAlertPolicyProps != nil { + securityAlertPolicyPayload := backupshorttermretentionpolicies.BackupShortTermRetentionPolicy{} if !strings.HasPrefix(skuName.(string), "DW") { - backupShortTermPolicy.BackupShortTermRetentionPolicyProperties = backupShortTermPolicyProps + securityAlertPolicyPayload.Properties = shortTermSecurityAlertPolicyProps } + if strings.HasPrefix(skuName.(string), "HS") { - backupShortTermPolicy.BackupShortTermRetentionPolicyProperties.DiffBackupIntervalInHours = nil + securityAlertPolicyPayload.Properties.DiffBackupIntervalInHours = nil } - shortTermRetentionFuture, err := shortTermRetentionClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, backupShortTermPolicy) + err := shortTermRetentionClient.CreateOrUpdateThenPoll(ctx, id, securityAlertPolicyPayload) if err != nil { return fmt.Errorf("setting Short Term Retention Policies for %s: %+v", id, err) } - - if err = shortTermRetentionFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of Short Term Retention Policies for %s: %+v", id, err) - } } return resourceMsSqlDatabaseRead(d, meta) @@ -488,115 +495,136 @@ func resourceMsSqlDatabaseRead(d *pluginsdk.ResourceData, meta interface{}) erro ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DatabaseID(d.Id()) + id, err := commonids.ParseDatabaseID(d.Id()) if err != nil { return err } - serverId := parse.NewServerID(id.SubscriptionId, id.ResourceGroup, id.ServerName) + serverId := commonids.NewSqlServerID(id.SubscriptionId, id.ResourceGroupName, id.ServerName) + d.Set("server_id", serverId.ID()) - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, pointer.From(id), databases.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { d.SetId("") return nil } return fmt.Errorf("retrieving %s: %+v", id, err) } - d.Set("name", resp.Name) - d.Set("server_id", serverId.ID()) - + geoBackupPolicy := true skuName := "" + elasticPoolId := "" + minCapacity := float64(0) ledgerEnabled := false - if props := resp.DatabaseProperties; props != nil { - d.Set("auto_pause_delay_in_minutes", props.AutoPauseDelay) - d.Set("collation", props.Collation) - d.Set("elastic_pool_id", props.ElasticPoolID) - if props.LicenseType != "" { - d.Set("license_type", props.LicenseType) - } else { - // value not returned, try to set from existing state/config - d.Set("license_type", d.Get("license_type").(string)) - } - if props.MaxSizeBytes != nil { - d.Set("max_size_gb", int32((*props.MaxSizeBytes)/int64(1073741824))) - } - d.Set("min_capacity", props.MinCapacity) - d.Set("read_replica_count", props.HighAvailabilityReplicaCount) - if props.ReadScale == sql.DatabaseReadScaleEnabled { - d.Set("read_scale", true) - } else if props.ReadScale == sql.DatabaseReadScaleDisabled { - d.Set("read_scale", false) - } - if props.CurrentServiceObjectiveName != nil { - skuName = *props.CurrentServiceObjectiveName - } - d.Set("sku_name", skuName) - d.Set("storage_account_type", string(props.CurrentBackupStorageRedundancy)) - d.Set("zone_redundant", props.ZoneRedundant) - if props.IsLedgerOn != nil { - ledgerEnabled = *props.IsLedgerOn - } - configurationName := "" - if v := props.MaintenanceConfigurationID; v != nil { - maintenanceConfigId, err := publicmaintenanceconfigurations.ParsePublicMaintenanceConfigurationIDInsensitively(*v) - if err != nil { + if model := resp.Model; model != nil { + d.Set("name", id.DatabaseName) + + if props := model.Properties; props != nil { + minCapacity = pointer.From(props.MinCapacity) + + requestedBackupStorageRedundancy := "" + if props.RequestedBackupStorageRedundancy != nil { + requestedBackupStorageRedundancy = string(*props.RequestedBackupStorageRedundancy) + } + + d.Set("auto_pause_delay_in_minutes", pointer.From(props.AutoPauseDelay)) + d.Set("collation", pointer.From(props.Collation)) + d.Set("read_replica_count", pointer.From(props.HighAvailabilityReplicaCount)) + d.Set("storage_account_type", requestedBackupStorageRedundancy) + d.Set("zone_redundant", pointer.From(props.ZoneRedundant)) + d.Set("read_scale", pointer.From(props.ReadScale) == databases.DatabaseReadScaleEnabled) + + if props.ElasticPoolId != nil { + elasticPoolId = pointer.From(props.ElasticPoolId) + } + + if props.LicenseType != nil { + d.Set("license_type", string(pointer.From(props.LicenseType))) + } else { + // value not returned, try to set from state + d.Set("license_type", d.Get("license_type").(string)) + } + + if props.MaxSizeBytes != nil { + d.Set("max_size_gb", int32((*props.MaxSizeBytes)/int64(1073741824))) + } + + if props.CurrentServiceObjectiveName != nil { + skuName = *props.CurrentServiceObjectiveName + } + + if props.IsLedgerOn != nil { + ledgerEnabled = *props.IsLedgerOn + } + + configurationName := "" + if v := props.MaintenanceConfigurationId; v != nil { + maintenanceConfigId, err := publicmaintenanceconfigurations.ParsePublicMaintenanceConfigurationIDInsensitively(pointer.From(v)) + if err != nil { + return err + } + configurationName = maintenanceConfigId.PublicMaintenanceConfigurationName + } + + d.Set("elastic_pool_id", elasticPoolId) + d.Set("min_capacity", minCapacity) + d.Set("sku_name", skuName) + d.Set("maintenance_configuration_name", configurationName) + d.Set("ledger_enabled", ledgerEnabled) + + if err := tags.FlattenAndSet(d, resp.Model.Tags); err != nil { return err } - configurationName = maintenanceConfigId.PublicMaintenanceConfigurationName } - d.Set("maintenance_configuration_name", configurationName) - d.Set("ledger_enabled", ledgerEnabled) - } + // DW SKU's do not currently support LRP and do not honour normal SRP operations + if !strings.HasPrefix(skuName, "DW") { + longTermPolicy, err := longTermRetentionClient.Get(ctx, pointer.From(id)) + if err != nil { + return fmt.Errorf("retrieving Long Term Retention Policies for %s: %+v", id, err) + } - securityAlertPolicy, err := securityAlertPoliciesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) - if err == nil { - if err := d.Set("threat_detection_policy", flattenMsSqlServerSecurityAlertPolicy(d, securityAlertPolicy)); err != nil { - return fmt.Errorf("setting `threat_detection_policy`: %+v", err) - } - } + if model := longTermPolicy.Model; model != nil { + if err := d.Set("long_term_retention_policy", helper.FlattenLongTermRetentionPolicy(model)); err != nil { + return fmt.Errorf("setting `long_term_retention_policy`: %+v", err) + } + } - geoBackupPolicy := true + shortTermPolicy, err := shortTermRetentionClient.Get(ctx, pointer.From(id)) - // DW SKU's do not currently support LRP and do not honour normal SRP operations - if !strings.HasPrefix(skuName, "DW") { - longTermPolicy, err := longTermRetentionClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) - if err != nil { - return fmt.Errorf("retrieving Long Term Retention Policies for %s: %+v", id, err) - } - if err := d.Set("long_term_retention_policy", helper.FlattenLongTermRetentionPolicy(&longTermPolicy, d)); err != nil { - return fmt.Errorf("setting `long_term_retention_policy`: %+v", err) - } + if model := shortTermPolicy.Model; model != nil { + if err != nil { + return fmt.Errorf("retrieving Short Term Retention Policies for %s: %+v", id, err) + } - shortTermPolicy, err := shortTermRetentionClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) - if err != nil { - return fmt.Errorf("retrieving Short Term Retention Policies for %s: %+v", id, err) - } + if err := d.Set("short_term_retention_policy", helper.FlattenShortTermRetentionPolicy(model)); err != nil { + return fmt.Errorf("setting `short_term_retention_policy`: %+v", err) + } + } + } else { + // DW SKUs need the retention policies to be empty for state consistency + emptySlice := make([]interface{}, 0) + d.Set("long_term_retention_policy", emptySlice) + d.Set("short_term_retention_policy", emptySlice) - if err := d.Set("short_term_retention_policy", helper.FlattenShortTermRetentionPolicy(&shortTermPolicy, d)); err != nil { - return fmt.Errorf("setting `short_term_retention_policy`: %+v", err) - } - } else { - // DW SKUs need the retention policies zeroing for state consistency - zero := make([]interface{}, 0) - d.Set("long_term_retention_policy", zero) - d.Set("short_term_retention_policy", zero) + geoPoliciesResponse, err := geoBackupPoliciesClient.Get(ctx, pointer.From(id)) + if err != nil { + if response.WasNotFound(geoPoliciesResponse.HttpResponse) { + d.SetId("") + return nil + } - geoPoliciesResponse, err := geoBackupPoliciesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) - if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - d.SetId("") - return nil + return fmt.Errorf("retrieving Geo Backup Policies for %s: %+v", id, err) } - return fmt.Errorf("retrieving Geo Backup Policies for %s: %+v", id, err) - } - // For Datawarehouse SKUs, set the geo-backup policy setting - if strings.HasPrefix(skuName, "DW") && geoPoliciesResponse.GeoBackupPolicyProperties.State == sql.GeoBackupPolicyStateDisabled { - geoBackupPolicy = false + // For Datawarehouse SKUs, set the geo-backup policy setting + if model := geoPoliciesResponse.Model; model != nil { + if strings.HasPrefix(skuName, "DW") && model.Properties.State == geobackuppolicies.GeoBackupPolicyStateDisabled { + geoBackupPolicy = false + } + } } } @@ -604,27 +632,38 @@ func resourceMsSqlDatabaseRead(d *pluginsdk.ResourceData, meta interface{}) erro return fmt.Errorf("setting `geo_backup_enabled`: %+v", err) } - tde, err := transparentEncryptionClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + securityAlertPolicy, err := securityAlertPoliciesClient.Get(ctx, pointer.From(id)) + if err == nil && securityAlertPolicy.Model != nil { + if err := d.Set("threat_detection_policy", flattenMsSqlServerSecurityAlertPolicy(d, pointer.From(securityAlertPolicy.Model))); err != nil { + return fmt.Errorf("setting `threat_detection_policy`: %+v", err) + } + } + + tde, err := transparentEncryptionClient.Get(ctx, pointer.From(id)) if err != nil { - return fmt.Errorf("while retrieving Transparent Data Encryption status of %q: %+v", id.String(), err) + return fmt.Errorf("while retrieving Transparent Data Encryption state for %s: %+v", id, err) } - tdeStatus := false - if tde.TransparentDataEncryptionProperties != nil && tde.TransparentDataEncryptionProperties.Status == sql.TransparentDataEncryptionStatusEnabled { - tdeStatus = true + + tdeState := false + if model := tde.Model; model != nil { + if props := model.Properties; props != nil { + tdeState = (props.State == transparentdataencryptions.TransparentDataEncryptionStateEnabled) + } } - d.Set("transparent_data_encryption_enabled", tdeStatus) + d.Set("transparent_data_encryption_enabled", tdeState) - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).MSSQL.DatabasesClient + legacyClient := meta.(*clients.Client).MSSQL.LegacyDatabasesClient serversClient := meta.(*clients.Client).MSSQL.ServersClient securityAlertPoliciesClient := meta.(*clients.Client).MSSQL.DatabaseSecurityAlertPoliciesClient longTermRetentionClient := meta.(*clients.Client).MSSQL.LongTermRetentionPoliciesClient shortTermRetentionClient := meta.(*clients.Client).MSSQL.BackupShortTermRetentionPoliciesClient geoBackupPoliciesClient := meta.(*clients.Client).MSSQL.GeoBackupPoliciesClient - replicationLinksClient := meta.(*clients.Client).MSSQL.ReplicationLinksClient + legacyReplicationLinksClient := meta.(*clients.Client).MSSQL.LegacyReplicationLinksClient resourcesClient := meta.(*clients.Client).Resource.ResourcesClient transparentEncryptionClient := meta.(*clients.Client).MSSQL.TransparentDataEncryptionsClient @@ -640,19 +679,19 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er name := d.Get("name").(string) - serverId, err := parse.ServerID(d.Get("server_id").(string)) + serverId, err := commonids.ParseSqlServerID(d.Get("server_id").(string)) if err != nil { return fmt.Errorf("parsing server ID: %+v", err) } - id := parse.NewDatabaseID(serverId.SubscriptionId, serverId.ResourceGroup, serverId.Name, name) + id := commonids.NewSqlDatabaseID(serverId.SubscriptionId, serverId.ResourceGroupName, serverId.ServerName, name) - _, err = client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + _, err = client.Get(ctx, id, databases.DefaultGetOperationOptions()) if err != nil { return fmt.Errorf("retrieving %s: %+q", id, err) } - _, err = serversClient.Get(ctx, serverId.ResourceGroup, serverId.Name, "") + _, err = serversClient.Get(ctx, pointer.From(serverId), servers.DefaultGetOperationOptions()) if err != nil { return fmt.Errorf("retrieving %s: %q", serverId, err) } @@ -681,21 +720,26 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er locks.ByID(id.ID()) defer locks.UnlockByID(id.ID()) + legacyId, err := parse.DatabaseID(id.ID()) + if err != nil { + return fmt.Errorf("parsing ID for Replication Partner Database %s: %+v", id, err) + } + if d.HasChange("sku_name") && skuName != "" { - partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, client, replicationLinksClient, resourcesClient, id, []sql.ReplicationRole{sql.ReplicationRoleSecondary, sql.ReplicationRoleNonReadableSecondary}) + partnerDatabases, err := helper.FindDatabaseReplicationPartners(ctx, legacyClient, legacyReplicationLinksClient, resourcesClient, *legacyId, []sql.ReplicationRole{sql.ReplicationRoleSecondary, sql.ReplicationRoleNonReadableSecondary}) if err != nil { return err } // Place a lock for the partner databases, so they can't update themselves whilst we're poking their SKUs - for _, partnerDatabase := range partnerDatabases { - partnerDatabaseId, err := parse.DatabaseID(*partnerDatabase.ID) + for _, v := range partnerDatabases { + id, err := parse.DatabaseID(pointer.From(v.ID)) if err != nil { - return fmt.Errorf("parsing ID for Replication Partner Database %q: %+v", *partnerDatabase.ID, err) + return fmt.Errorf("parsing ID for Replication Partner Database %q: %+v", id.ID(), err) } - locks.ByID(partnerDatabaseId.ID()) - defer locks.UnlockByID(partnerDatabaseId.ID()) + locks.ByID(id.ID()) + defer locks.UnlockByID(id.ID()) } // Update the SKUs of any partner databases where deemed necessary @@ -707,7 +751,7 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er // See: https://docs.microsoft.com/en-us/azure/azure-sql/database/active-geo-replication-overview#configuring-secondary-database if partnerDatabase.Sku != nil && partnerDatabase.Sku.Name != nil && helper.CompareDatabaseSkuServiceTiers(skuName, *partnerDatabase.Sku.Name) { - future, err := client.Update(ctx, partnerDatabaseId.ResourceGroup, partnerDatabaseId.ServerName, partnerDatabaseId.Name, sql.DatabaseUpdate{ + future, err := legacyClient.Update(ctx, partnerDatabaseId.ResourceGroup, partnerDatabaseId.ServerName, partnerDatabaseId.Name, sql.DatabaseUpdate{ Sku: &sql.Sku{ Name: pointer.To(skuName), }, @@ -716,26 +760,26 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er return fmt.Errorf("updating SKU of Replication Partner %s: %+v", partnerDatabaseId, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if err = future.WaitForCompletionRef(ctx, legacyClient.Client); err != nil { return fmt.Errorf("waiting for SKU update for Replication Partner %s: %+v", partnerDatabaseId, err) } } } } - payload := sql.DatabaseUpdate{} - props := sql.DatabaseProperties{} + payload := databases.DatabaseUpdate{} + props := databases.DatabaseUpdateProperties{} if d.HasChange("auto_pause_delay_in_minutes") { - props.AutoPauseDelay = pointer.To(int32(d.Get("auto_pause_delay_in_minutes").(int))) + props.AutoPauseDelay = pointer.To(int64(d.Get("auto_pause_delay_in_minutes").(int))) } if d.HasChange("elastic_pool_id") { - props.ElasticPoolID = pointer.To(d.Get("elastic_pool_id").(string)) + props.ElasticPoolId = pointer.To(d.Get("elastic_pool_id").(string)) } if d.HasChange("license_type") { - props.LicenseType = sql.DatabaseLicenseType(d.Get("license_type").(string)) + props.LicenseType = pointer.To(databases.DatabaseLicenseType(d.Get("license_type").(string))) } if d.HasChange("min_capacity") { @@ -743,15 +787,15 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er } if d.HasChange("read_replica_count") { - props.HighAvailabilityReplicaCount = pointer.To(int32(d.Get("read_replica_count").(int))) + props.HighAvailabilityReplicaCount = pointer.To(int64(d.Get("read_replica_count").(int))) } if d.HasChange("sample_name") { - props.SampleName = sql.SampleName(d.Get("sample_name").(string)) + props.SampleName = pointer.To(databases.SampleName(d.Get("sample_name").(string))) } if d.HasChange("storage_account_type") { - props.RequestedBackupStorageRedundancy = sql.RequestedBackupStorageRedundancy(d.Get("storage_account_type").(string)) + props.RequestedBackupStorageRedundancy = pointer.To(databases.BackupStorageRedundancy(d.Get("storage_account_type").(string))) } if d.HasChange("zone_redundant") { @@ -769,127 +813,134 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er if v, ok := d.GetOk("maintenance_configuration_name"); ok { maintenanceConfigId = publicmaintenanceconfigurations.NewPublicMaintenanceConfigurationID(serverId.SubscriptionId, v.(string)) } - props.MaintenanceConfigurationID = pointer.To(maintenanceConfigId.ID()) + props.MaintenanceConfigurationId = pointer.To(maintenanceConfigId.ID()) } createMode := d.Get("create_mode").(string) if v, ok := d.GetOk("max_size_gb"); ok { // `max_size_gb` is Computed, so has a value after the first run - if createMode != string(sql.CreateModeOnlineSecondary) && createMode != string(sql.CreateModeSecondary) { + if createMode != string(databases.CreateModeOnlineSecondary) && createMode != string(databases.CreateModeSecondary) { props.MaxSizeBytes = utils.Int64(int64(v.(int)) * 1073741824) } // `max_size_gb` only has change if it is configured - if d.HasChange("max_size_gb") && (createMode == string(sql.CreateModeOnlineSecondary) || createMode == string(sql.CreateModeSecondary)) { + if d.HasChange("max_size_gb") && (createMode == string(databases.CreateModeOnlineSecondary) || createMode == string(databases.CreateModeSecondary)) { return fmt.Errorf("it is not possible to change maximum size nor advised to configure maximum size in secondary create mode for %s", id) } } if d.HasChanges("read_scale") { - readScale := sql.DatabaseReadScaleDisabled + readScale := databases.DatabaseReadScaleDisabled if v := d.Get("read_scale").(bool); v { - readScale = sql.DatabaseReadScaleEnabled + readScale = databases.DatabaseReadScaleEnabled } - props.ReadScale = readScale + props.ReadScale = pointer.To(readScale) } if d.HasChange("restore_point_in_time") { if v, ok := d.GetOk("restore_point_in_time"); ok { - if createMode != string(sql.CreateModePointInTimeRestore) { - return fmt.Errorf("'restore_point_in_time' is supported only for create_mode %s", string(sql.CreateModePointInTimeRestore)) + if createMode != string(databases.CreateModePointInTimeRestore) { + return fmt.Errorf("'restore_point_in_time' is supported only for create_mode %s", string(databases.CreateModePointInTimeRestore)) } - restorePointInTime, err := time.Parse(time.RFC3339, v.(string)) - if err != nil { - return fmt.Errorf("parsing `restore_point_in_time` value %q for %s: %+v", v, id, err) - } - props.RestorePointInTime = &date.Time{Time: restorePointInTime} + props.RestorePointInTime = pointer.To(v.(string)) } } if d.HasChange("sku_name") { - payload.Sku = &sql.Sku{ - Name: pointer.To(skuName), - } + payload.Sku = pointer.To(databases.Sku{ + Name: skuName, + }) } if d.HasChange("recover_database_id") { - props.RecoverableDatabaseID = pointer.To(d.Get("recover_database_id").(string)) + props.RecoverableDatabaseId = pointer.To(d.Get("recover_database_id").(string)) } if d.HasChange("restore_dropped_database_id") { - props.RestorableDroppedDatabaseID = pointer.To(d.Get("restore_dropped_database_id").(string)) + props.RestorableDroppedDatabaseId = pointer.To(d.Get("restore_dropped_database_id").(string)) } - payload.DatabaseProperties = pointer.To(props) + payload.Properties = pointer.To(props) - future, err := client.Update(ctx, id.ResourceGroup, id.ServerName, id.Name, payload) + err = client.UpdateThenPoll(ctx, id, payload) if err != nil { return fmt.Errorf("updating %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of %s: %+v", id, err) - } - // Wait for the ProvisioningState to become "Succeeded" log.Printf("[DEBUG] Waiting for %s to become ready", id) pendingStatuses := make([]string, 0) - for _, s := range sql.PossibleDatabaseStatusValues() { - if s != sql.DatabaseStatusOnline { - pendingStatuses = append(pendingStatuses, string(s)) + for _, s := range databases.PossibleValuesForDatabaseStatus() { + if s != string(databases.DatabaseStatusOnline) { + pendingStatuses = append(pendingStatuses, s) } } + + deadline, ok := ctx.Deadline() + if !ok { + return fmt.Errorf("internal-error: context had no deadline") + } + + // NOTE: Internal x-ref, this is another case of hashicorp/go-azure-sdk#307 so this can be removed once that's fixed stateConf := &pluginsdk.StateChangeConf{ Pending: pendingStatuses, - Target: []string{string(sql.DatabaseStatusOnline)}, + Target: []string{string(databases.DatabaseStatusOnline)}, Refresh: func() (interface{}, string, error) { log.Printf("[DEBUG] Checking to see if %s is online...", id) - resp, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.Get(ctx, id, databases.DefaultGetOperationOptions()) if err != nil { return nil, "", fmt.Errorf("polling for the status of %s: %+v", id, err) } - if props := resp.DatabaseProperties; props != nil { - return resp, string(props.Status), nil + if model := resp.Model; model != nil { + if props := model.Properties; props != nil { + return resp, string(pointer.From(props.Status)), nil + } } - return resp, "", nil + return resp.Model, "", nil }, - MinTimeout: 1 * time.Minute, + ContinuousTargetOccurence: 2, + MinTimeout: 1 * time.Minute, + Timeout: time.Until(deadline), } - stateConf.Timeout = d.Timeout(pluginsdk.TimeoutUpdate) if _, err = stateConf.WaitForStateContext(ctx); err != nil { return fmt.Errorf("waiting for %s to become ready: %+v", id, err) } // Cannot set transparent data encryption for secondary databases - if createMode != string(sql.CreateModeOnlineSecondary) && createMode != string(sql.CreateModeSecondary) { - statusProperty := sql.TransparentDataEncryptionStatusDisabled + if createMode != string(databases.CreateModeOnlineSecondary) && createMode != string(databases.CreateModeSecondary) { + state := transparentdataencryptions.TransparentDataEncryptionStateDisabled if d.HasChange("transparent_data_encryption_enabled") { - encryptionStatus := d.Get("transparent_data_encryption_enabled").(bool) - if encryptionStatus { - statusProperty = sql.TransparentDataEncryptionStatusEnabled + if v := d.Get("transparent_data_encryption_enabled").(bool); v { + state = transparentdataencryptions.TransparentDataEncryptionStateEnabled } - _, err := transparentEncryptionClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, sql.TransparentDataEncryption{ - TransparentDataEncryptionProperties: &sql.TransparentDataEncryptionProperties{ - Status: statusProperty, - }, - }) + + input := transparentdataencryptions.LogicalDatabaseTransparentDataEncryption{ + Properties: pointer.To(transparentdataencryptions.TransparentDataEncryptionProperties{ + State: state, + }), + } + + err := transparentEncryptionClient.CreateOrUpdateThenPoll(ctx, id, input) if err != nil { - return fmt.Errorf("while enabling Transparent Data Encryption for %q: %+v", id.String(), err) + return fmt.Errorf("while updating Transparent Data Encryption state for %s: %+v", id, err) } + // NOTE: Internal x-ref, this is another case of hashicorp/go-azure-sdk#307 so this can be removed once that's fixed if err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *pluginsdk.RetryError { - c, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + c, err := client.Get(ctx, id, databases.DefaultGetOperationOptions()) if err != nil { - return pluginsdk.NonRetryableError(fmt.Errorf("while polling cluster %s for status: %+v", id.String(), err)) - } - if c.DatabaseProperties.Status == sql.DatabaseStatusScaling { - return pluginsdk.RetryableError(fmt.Errorf("database %s is still scaling", id.String())) + return pluginsdk.NonRetryableError(fmt.Errorf("while polling %s for status: %+v", id.String(), err)) } + if model := c.Model; model != nil && model.Properties != nil && model.Properties.Status != nil { + if model.Properties.Status == pointer.To(databases.DatabaseStatusScaling) { + return pluginsdk.RetryableError(fmt.Errorf("database %s is still scaling", id.String())) + } + } return nil }); err != nil { return nil @@ -901,13 +952,10 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er if d.HasChange("import") { if _, ok := d.GetOk("import"); ok { importParameters := expandMsSqlServerImport(d) - importFuture, err := client.Import(ctx, id.ResourceGroup, id.ServerName, id.Name, importParameters) - if err != nil { - return fmt.Errorf("while import bacpac into the new database %s (Resource Group %s): %+v", id.Name, id.ResourceGroup, err) - } - if err = importFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("while import bacpac into the new database %s (Resource Group %s): %+v", id.Name, id.ResourceGroup, err) + err := client.ImportThenPoll(ctx, id, importParameters) + if err != nil { + return fmt.Errorf("while importing the BACPAC file into the new database %s: %+v", id.ID(), err) } } } @@ -917,29 +965,29 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er // For datawarehouse SKUs only if strings.HasPrefix(skuName, "DW") && d.HasChange("geo_backup_enabled") { isEnabled := d.Get("geo_backup_enabled").(bool) - var geoBackupPolicyState sql.GeoBackupPolicyState + var geoBackupPolicyState geobackuppolicies.GeoBackupPolicyState if isEnabled { - geoBackupPolicyState = sql.GeoBackupPolicyStateEnabled + geoBackupPolicyState = geobackuppolicies.GeoBackupPolicyStateEnabled } else { - geoBackupPolicyState = sql.GeoBackupPolicyStateDisabled + geoBackupPolicyState = geobackuppolicies.GeoBackupPolicyStateDisabled } - geoBackupPolicy := sql.GeoBackupPolicy{ - GeoBackupPolicyProperties: &sql.GeoBackupPolicyProperties{ + geoBackupPolicy := geobackuppolicies.GeoBackupPolicy{ + Properties: &geobackuppolicies.GeoBackupPolicyProperties{ State: geoBackupPolicyState, }, } - if _, err := geoBackupPoliciesClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, geoBackupPolicy); err != nil { + if _, err := geoBackupPoliciesClient.CreateOrUpdate(ctx, id, geoBackupPolicy); err != nil { return fmt.Errorf("setting Geo Backup Policies for %s: %+v", id, err) } } if err = pluginsdk.Retry(d.Timeout(pluginsdk.TimeoutCreate), func() *pluginsdk.RetryError { - result, err := securityAlertPoliciesClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, expandMsSqlServerSecurityAlertPolicy(d)) + result, err := securityAlertPoliciesClient.CreateOrUpdate(ctx, id, expandMsSqlDatabaseSecurityAlertPolicy(d)) - if utils.ResponseWasNotFound(result.Response) { + if response.WasNotFound(result.HttpResponse) { return pluginsdk.RetryableError(fmt.Errorf("database %s is still creating", id.String())) } @@ -956,21 +1004,17 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er v := d.Get("long_term_retention_policy") longTermRetentionProps := helper.ExpandLongTermRetentionPolicy(v.([]interface{})) if longTermRetentionProps != nil { - longTermRetentionPolicy := sql.LongTermRetentionPolicy{} + longTermRetentionPolicy := longtermretentionpolicies.LongTermRetentionPolicy{} // DataWarehouse SKU's do not support LRP currently if !strings.HasPrefix(skuName, "DW") { - longTermRetentionPolicy.BaseLongTermRetentionPolicyProperties = longTermRetentionProps + longTermRetentionPolicy.Properties = longTermRetentionProps } - longTermRetentionfuture, err := longTermRetentionClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, longTermRetentionPolicy) + err := longTermRetentionClient.CreateOrUpdateThenPoll(ctx, id, longTermRetentionPolicy) if err != nil { return fmt.Errorf("setting Long Term Retention Policies for %s: %+v", id, err) } - - if err = longTermRetentionfuture.WaitForCompletionRef(ctx, longTermRetentionClient.Client); err != nil { - return fmt.Errorf("waiting for update of Long Term Retention Policies for %s: %+v", id, err) - } } } @@ -978,23 +1022,20 @@ func resourceMsSqlDatabaseUpdate(d *pluginsdk.ResourceData, meta interface{}) er v := d.Get("short_term_retention_policy") backupShortTermPolicyProps := helper.ExpandShortTermRetentionPolicy(v.([]interface{})) if backupShortTermPolicyProps != nil { - backupShortTermPolicy := sql.BackupShortTermRetentionPolicy{} + backupShortTermPolicy := backupshorttermretentionpolicies.BackupShortTermRetentionPolicy{} if !strings.HasPrefix(skuName, "DW") { - backupShortTermPolicy.BackupShortTermRetentionPolicyProperties = backupShortTermPolicyProps + backupShortTermPolicy.Properties = backupShortTermPolicyProps } + if strings.HasPrefix(skuName, "HS") { - backupShortTermPolicy.BackupShortTermRetentionPolicyProperties.DiffBackupIntervalInHours = nil + backupShortTermPolicy.Properties.DiffBackupIntervalInHours = nil } - shortTermRetentionFuture, err := shortTermRetentionClient.CreateOrUpdate(ctx, id.ResourceGroup, id.ServerName, id.Name, backupShortTermPolicy) + err := shortTermRetentionClient.CreateOrUpdateThenPoll(ctx, id, backupShortTermPolicy) if err != nil { return fmt.Errorf("setting Short Term Retention Policies for %s: %+v", id, err) } - - if err = shortTermRetentionFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for update of Short Term Retention Policies for %s: %+v", id, err) - } } } @@ -1006,27 +1047,23 @@ func resourceMsSqlDatabaseDelete(d *pluginsdk.ResourceData, meta interface{}) er ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.DatabaseID(d.Id()) + id, err := commonids.ParseDatabaseID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.ServerName, id.Name) + err = client.DeleteThenPoll(ctx, pointer.From(id)) if err != nil { return fmt.Errorf("deleting %s: %+v", id, err) } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting deletion of %s: %+v", id, err) - } - return nil } -func flattenMsSqlServerSecurityAlertPolicy(d *pluginsdk.ResourceData, policy sql.DatabaseSecurityAlertPolicy) []interface{} { +func flattenMsSqlServerSecurityAlertPolicy(d *pluginsdk.ResourceData, policy databasesecurityalertpolicies.DatabaseSecurityAlertPolicy) []interface{} { // The SQL database security alert API always returns the default value even if never set. // If the values are on their default one, threat it as not set. - properties := policy.SecurityAlertsPolicyProperties + properties := policy.Properties if properties == nil { return []interface{}{} } @@ -1073,13 +1110,13 @@ func flattenMsSqlServerSecurityAlertPolicy(d *pluginsdk.ResourceData, policy sql return []interface{}{securityAlertPolicy} } -func expandMsSqlServerSecurityAlertPolicy(d *pluginsdk.ResourceData) sql.DatabaseSecurityAlertPolicy { - policy := sql.DatabaseSecurityAlertPolicy{ - SecurityAlertsPolicyProperties: &sql.SecurityAlertsPolicyProperties{ - State: sql.SecurityAlertsPolicyStateDisabled, - }, +func expandMsSqlDatabaseSecurityAlertPolicy(d *pluginsdk.ResourceData) databasesecurityalertpolicies.DatabaseSecurityAlertPolicy { + policy := databasesecurityalertpolicies.DatabaseSecurityAlertPolicy{ + Properties: pointer.To(databasesecurityalertpolicies.SecurityAlertsPolicyProperties{ + State: databasesecurityalertpolicies.SecurityAlertsPolicyStateDisabled, + }), } - properties := policy.SecurityAlertsPolicyProperties + properties := policy.Properties td, ok := d.GetOk("threat_detection_policy") if !ok { @@ -1089,8 +1126,8 @@ func expandMsSqlServerSecurityAlertPolicy(d *pluginsdk.ResourceData) sql.Databas if tdl := td.([]interface{}); len(tdl) > 0 { securityAlert := tdl[0].(map[string]interface{}) - properties.State = sql.SecurityAlertsPolicyState(securityAlert["state"].(string)) - properties.EmailAccountAdmins = utils.Bool(securityAlert["email_account_admins"].(string) == "Enabled") + properties.State = databasesecurityalertpolicies.SecurityAlertsPolicyState(securityAlert["state"].(string)) + properties.EmailAccountAdmins = utils.Bool(securityAlert["email_account_admins"].(string) == string(EmailAccountAdminsStatusEnabled)) if v, ok := securityAlert["disabled_alerts"]; ok { alerts := v.(*pluginsdk.Set).List() @@ -1109,7 +1146,7 @@ func expandMsSqlServerSecurityAlertPolicy(d *pluginsdk.ResourceData) sql.Databas properties.EmailAddresses = &expandedEmails } if v, ok := securityAlert["retention_days"]; ok { - properties.RetentionDays = utils.Int32(int32(v.(int))) + properties.RetentionDays = pointer.To(int64(v.(int))) } if v, ok := securityAlert["storage_account_access_key"]; ok && v.(string) != "" { properties.StorageAccountAccessKey = utils.String(v.(string)) @@ -1124,23 +1161,23 @@ func expandMsSqlServerSecurityAlertPolicy(d *pluginsdk.ResourceData) sql.Databas return policy } -func expandMsSqlServerImport(d *pluginsdk.ResourceData) (out sql.ImportExistingDatabaseDefinition) { +func expandMsSqlServerImport(d *pluginsdk.ResourceData) (out databases.ImportExistingDatabaseDefinition) { v := d.Get("import") dbImportRefs := v.([]interface{}) dbImportRef := dbImportRefs[0].(map[string]interface{}) - out = sql.ImportExistingDatabaseDefinition{ - StorageKeyType: sql.StorageKeyType(dbImportRef["storage_key_type"].(string)), - StorageKey: utils.String(dbImportRef["storage_key"].(string)), - StorageURI: utils.String(dbImportRef["storage_uri"].(string)), - AdministratorLogin: utils.String(dbImportRef["administrator_login"].(string)), - AdministratorLoginPassword: utils.String(dbImportRef["administrator_login_password"].(string)), - AuthenticationType: utils.String(dbImportRef["authentication_type"].(string)), + out = databases.ImportExistingDatabaseDefinition{ + StorageKeyType: databases.StorageKeyType(dbImportRef["storage_key_type"].(string)), + StorageKey: dbImportRef["storage_key"].(string), + StorageUri: dbImportRef["storage_uri"].(string), + AdministratorLogin: dbImportRef["administrator_login"].(string), + AdministratorLoginPassword: dbImportRef["administrator_login_password"].(string), + AuthenticationType: pointer.To(dbImportRef["authentication_type"].(string)), } if storageAccountId, ok := d.GetOk("storage_account_id"); ok { - out.NetworkIsolation = &sql.NetworkIsolationSettings{ - StorageAccountResourceID: utils.String(storageAccountId.(string)), - SQLServerResourceID: utils.String(d.Get("server_id").(string)), + out.NetworkIsolation = &databases.NetworkIsolationSettings{ + StorageAccountResourceId: pointer.To(storageAccountId.(string)), + SqlServerResourceId: pointer.To(d.Get("server_id").(string)), } } return @@ -1157,6 +1194,20 @@ func resourceMsSqlDatabaseMaintenanceNames() []string { "SQL_UAENorth_DB_1", "SQL_BrazilSoutheast_DB_2", "SQL_UAENorth_DB_2"} } +type EmailAccountAdminsStatus string + +const ( + EmailAccountAdminsStatusDisabled EmailAccountAdminsStatus = "Disabled" + EmailAccountAdminsStatusEnabled EmailAccountAdminsStatus = "Enabled" +) + +func PossibleValuesForEmailAccountAdminsStatus() []string { + return []string{ + string(EmailAccountAdminsStatusDisabled), + string(EmailAccountAdminsStatusEnabled), + } +} + func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { return map[string]*pluginsdk.Schema{ "name": { @@ -1184,19 +1235,9 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { Type: pluginsdk.TypeString, Optional: true, ForceNew: true, - Default: string(sql.CreateModeDefault), - ValidateFunc: validation.StringInSlice([]string{ - string(sql.CreateModeCopy), - string(sql.CreateModeDefault), - string(sql.CreateModeOnlineSecondary), - string(sql.CreateModePointInTimeRestore), - string(sql.CreateModeRestore), - string(sql.CreateModeRecovery), - string(sql.CreateModeRestoreExternalBackup), - string(sql.CreateModeRestoreExternalBackupSecondary), - string(sql.CreateModeRestoreLongTermRetentionBackup), - string(sql.CreateModeSecondary), - }, false), + Default: string(databases.CreateModeDefault), + ValidateFunc: validation.StringInSlice(databases.PossibleValuesForCreateMode(), + false), ConflictsWith: []string{"import"}, }, "import": { @@ -1217,10 +1258,8 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { "storage_key_type": { Type: pluginsdk.TypeString, Required: true, - ValidateFunc: validation.StringInSlice([]string{ - string(sql.StorageKeyTypeSharedAccessKey), - string(sql.StorageKeyTypeStorageAccessKey), - }, false), + ValidateFunc: validation.StringInSlice(databases.PossibleValuesForStorageKeyType(), + false), }, "administrator_login": { Type: pluginsdk.TypeString, @@ -1267,10 +1306,8 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { Type: pluginsdk.TypeString, Optional: true, Computed: true, - ValidateFunc: validation.StringInSlice([]string{ - string(sql.DatabaseLicenseTypeBasePrice), - string(sql.DatabaseLicenseTypeLicenseIncluded), - }, false), + ValidateFunc: validation.StringInSlice(databases.PossibleValuesForDatabaseLicenseType(), + false), }, "long_term_retention_policy": helper.LongTermRetentionPolicySchema(), @@ -1329,7 +1366,7 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { Optional: true, Computed: true, ValidateFunc: validation.StringInSlice([]string{ - string(sql.SampleNameAdventureWorksLT), + string(databases.SampleNameAdventureWorksLT), }, false), }, @@ -1351,12 +1388,9 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { "storage_account_type": { Type: pluginsdk.TypeString, Optional: true, - Default: string(sql.CurrentBackupStorageRedundancyGeo), - ValidateFunc: validation.StringInSlice([]string{ - string(sql.CurrentBackupStorageRedundancyGeo), - string(sql.CurrentBackupStorageRedundancyLocal), - string(sql.CurrentBackupStorageRedundancyZone), - }, false), + Default: string(databases.BackupStorageRedundancyGeo), + ValidateFunc: validation.StringInSlice(databases.PossibleValuesForBackupStorageRedundancy(), + false), }, "zone_redundant": { @@ -1386,14 +1420,14 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { }, }, + // NOTE: this is a Boolean in SDK rather than a String + // TODO: update this to be `email_account_admins_enabled` in 4.0 "email_account_admins": { Type: pluginsdk.TypeString, Optional: true, - Default: "Disabled", - ValidateFunc: validation.StringInSlice([]string{ - "Disabled", - "Enabled", - }, false), + Default: EmailAccountAdminsStatusDisabled, + ValidateFunc: validation.StringInSlice(PossibleValuesForEmailAccountAdminsStatus(), + false), }, "email_addresses": { @@ -1411,15 +1445,17 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { ValidateFunc: validation.IntAtLeast(0), }, + // NOTE: I believe that this was originally implemented incorrect, where it exposed the + // 'serveradvancedthreatprotectionsettings.PossibleValuesForAdvancedThreatProtectionState' + // which contains the values of 'Enabled', 'Disabled', and 'New' + // where 'serversecurityalertpolicies.PossibleValuesForSecurityAlertsPolicyState' + // only contains 'Enabled' and 'Disabled' "state": { Type: pluginsdk.TypeString, Optional: true, - Default: string(sql.SecurityAlertPolicyStateDisabled), - ValidateFunc: validation.StringInSlice([]string{ - string(sql.SecurityAlertPolicyStateDisabled), - string(sql.SecurityAlertPolicyStateEnabled), - string(sql.SecurityAlertPolicyStateNew), - }, false), + Default: string(serversecurityalertpolicies.SecurityAlertsPolicyStateDisabled), + ValidateFunc: validation.StringInSlice(serversecurityalertpolicies.PossibleValuesForSecurityAlertsPolicyState(), + false), }, "storage_account_access_key": { @@ -1465,6 +1501,6 @@ func resourceMsSqlDatabaseSchema() map[string]*pluginsdk.Schema { Default: true, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), } } diff --git a/internal/services/mssql/mssql_database_resource_test.go b/internal/services/mssql/mssql_database_resource_test.go index 2f51ee95c2c4..71cc2aabbf0c 100644 --- a/internal/services/mssql/mssql_database_resource_test.go +++ b/internal/services/mssql/mssql_database_resource_test.go @@ -10,12 +10,14 @@ import ( "testing" "time" + "github.com/hashicorp/go-azure-helpers/lang/pointer" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/databases" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) type MsSqlDatabaseResource struct{} @@ -717,13 +719,14 @@ func TestAccMsSqlDatabase_geoBackupPolicy(t *testing.T) { }) } -func TestAccMsSqlDatabase_transitDataEncryption(t *testing.T) { +func TestAccMsSqlDatabase_TransparentDataEncryptionUpdate(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_mssql_database", "test") r := MsSqlDatabaseResource{} + // NOTE: You can only update TDE on DW SKU's... data.ResourceTest(t, r, []acceptance.TestStep{ { - Config: r.withTransitDataEncryptionOnDwSku(data, true), + Config: r.transparentDataEncryptionUpdate(data, true), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("transparent_data_encryption_enabled").HasValue("true"), @@ -731,13 +734,21 @@ func TestAccMsSqlDatabase_transitDataEncryption(t *testing.T) { }, data.ImportStep(), { - Config: r.withTransitDataEncryptionOnDwSku(data, false), + Config: r.transparentDataEncryptionUpdate(data, false), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), check.That(data.ResourceName).Key("transparent_data_encryption_enabled").HasValue("false"), ), }, data.ImportStep(), + { + Config: r.transparentDataEncryptionUpdate(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("transparent_data_encryption_enabled").HasValue("true"), + ), + }, + data.ImportStep(), }) } @@ -783,21 +794,21 @@ func TestAccMsSqlDatabase_bacpac(t *testing.T) { } func (MsSqlDatabaseResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { - id, err := parse.DatabaseID(state.ID) + id, err := commonids.ParseDatabaseID(state.ID) if err != nil { return nil, err } - resp, err := client.MSSQL.DatabasesClient.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) + resp, err := client.MSSQL.DatabasesClient.Get(ctx, *id, databases.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - return nil, fmt.Errorf("SQL Database %q (Server %q, Resource Group %q) does not exist", id.Name, id.ServerName, id.ResourceGroup) + if response.WasNotFound(resp.HttpResponse) { + return nil, fmt.Errorf("SQL %s does not exist", id) } - return nil, fmt.Errorf("reading SQL Database %q (Server %q, Resource Group %q): %v", id.Name, id.ServerName, id.ResourceGroup, err) + return nil, fmt.Errorf("reading SQL %s: %v", id, err) } - return utils.Bool(resp.ID != nil), nil + return pointer.To(resp.Model != nil), nil } func (MsSqlDatabaseResource) template(data acceptance.TestData) string { @@ -1716,7 +1727,7 @@ resource "azurerm_mssql_database" "test" { `, r.template(data), data.RandomIntOfLength(15), data.RandomInteger) } -func (r MsSqlDatabaseResource) withTransitDataEncryptionOnDwSku(data acceptance.TestData, state bool) string { +func (r MsSqlDatabaseResource) transparentDataEncryptionUpdate(data acceptance.TestData, state bool) string { return fmt.Sprintf(` %s diff --git a/internal/services/mssql/mssql_database_vulnerability_assessment_rule_baseline_resource.go b/internal/services/mssql/mssql_database_vulnerability_assessment_rule_baseline_resource.go index 61bfce7ebef3..960e1cf134c2 100644 --- a/internal/services/mssql/mssql_database_vulnerability_assessment_rule_baseline_resource.go +++ b/internal/services/mssql/mssql_database_vulnerability_assessment_rule_baseline_resource.go @@ -106,7 +106,7 @@ func resourceMsSqlDatabaseVulnerabilityAssessmentRuleBaselineCreateUpdate(d *plu return fmt.Errorf("retrieving Server Vulnerability Assessment Settings: %+v", err) } if vulnerabilityAssessment.StorageContainerPath == nil { - return fmt.Errorf("Storage Container Path not set in Server Vulnerability Assessment Settings") + return fmt.Errorf("storage container path not set in Server Vulnerability Assessment Settings") } // TODO: requires import diff --git a/internal/services/mssql/mssql_failover_group_resource.go b/internal/services/mssql/mssql_failover_group_resource.go index ada30a6b7794..f5052adc6f4e 100644 --- a/internal/services/mssql/mssql_failover_group_resource.go +++ b/internal/services/mssql/mssql_failover_group_resource.go @@ -9,8 +9,10 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/servers" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" @@ -181,16 +183,16 @@ func (r MsSqlFailoverGroupResource) Create() sdk.ResourceFunc { return fmt.Errorf("decoding: %+v", err) } - serverId, err := parse.ServerID(model.ServerId) + serverId, err := commonids.ParseSqlServerID(model.ServerId) if err != nil { return err } - if _, err = serversClient.Get(ctx, serverId.ResourceGroup, serverId.Name, ""); err != nil { + if _, err = serversClient.Get(ctx, *serverId, servers.DefaultGetOperationOptions()); err != nil { return fmt.Errorf("retrieving %s: %+v", serverId, err) } - id := parse.NewFailoverGroupID(subscriptionId, serverId.ResourceGroup, serverId.Name, model.Name) + id := parse.NewFailoverGroupID(subscriptionId, serverId.ResourceGroupName, serverId.ServerName, model.Name) existing, err := client.Get(ctx, id.ResourceGroup, id.ServerName, id.Name) if err != nil { diff --git a/internal/services/mssql/mssql_server_data_source.go b/internal/services/mssql/mssql_server_data_source.go index e05f4cff91ca..38c495cc5bc3 100644 --- a/internal/services/mssql/mssql_server_data_source.go +++ b/internal/services/mssql/mssql_server_data_source.go @@ -7,14 +7,16 @@ import ( "fmt" "time" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" + "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" - "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" - "github.com/hashicorp/terraform-provider-azurerm/utils" ) func dataSourceMsSqlServer() *pluginsdk.Resource { @@ -60,7 +62,7 @@ func dataSourceMsSqlServer() *pluginsdk.Resource { }, }, - "tags": tags.SchemaDataSource(), + "tags": commonschema.TagsDataSource(), }, } } @@ -72,11 +74,11 @@ func dataSourceMsSqlServerRead(d *pluginsdk.ResourceData, meta interface{}) erro ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + id := commonids.NewSqlServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) - resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + resp, err := client.Get(ctx, id, servers.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return fmt.Errorf("%s was not found", id) } @@ -84,30 +86,38 @@ func dataSourceMsSqlServerRead(d *pluginsdk.ResourceData, meta interface{}) erro } d.SetId(id.ID()) - d.Set("location", location.NormalizeNilable(resp.Location)) + if model := resp.Model; model != nil { + // NOTE: In the new API Location is just a string, not a pointer.. + d.Set("location", location.Normalize(model.Location)) + + if props := model.Properties; props != nil { + d.Set("version", props.Version) + d.Set("administrator_login", props.AdministratorLogin) + d.Set("fully_qualified_domain_name", props.FullyQualifiedDomainName) + } - 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) - } + identity, err := identity.FlattenLegacySystemAndUserAssignedMap(model.Identity) + if err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } - identity, err := flattenSqlServerIdentity(resp.Identity) - if err != nil { - return fmt.Errorf("setting `identity`: %+v", err) - } + if err := d.Set("identity", identity); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } - if err := d.Set("identity", identity); err != nil { - return fmt.Errorf("setting `identity`: %+v", err) - } + restorableListPage, err := restorableDroppedDatabasesClient.ListByServerComplete(ctx, id) + if err != nil { + return fmt.Errorf("listing %s Restorable Dropped Databases: %v", id, err) + } - restorableListPage, err := restorableDroppedDatabasesClient.ListByServerComplete(ctx, id.ResourceGroup, id.Name) - if err != nil { - return fmt.Errorf("listing %s Restorable Dropped Databases: %v", id, err) - } - if err := d.Set("restorable_dropped_database_ids", flattenSqlServerRestorableDatabases(restorableListPage.Response())); err != nil { - return fmt.Errorf("setting `restorable_dropped_database_ids`: %+v", err) + if err := d.Set("restorable_dropped_database_ids", flattenSqlServerRestorableDatabases(restorableListPage)); err != nil { + return fmt.Errorf("setting `restorable_dropped_database_ids`: %+v", err) + } + + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err + } } - return tags.FlattenAndSet(d, resp.Tags) + return nil } diff --git a/internal/services/mssql/mssql_server_extended_auditing_policy_resource.go b/internal/services/mssql/mssql_server_extended_auditing_policy_resource.go index 79506941992f..64039333f999 100644 --- a/internal/services/mssql/mssql_server_extended_auditing_policy_resource.go +++ b/internal/services/mssql/mssql_server_extended_auditing_policy_resource.go @@ -10,6 +10,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck "github.com/gofrs/uuid" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" @@ -104,16 +105,16 @@ func resourceMsSqlServerExtendedAuditingPolicyCreateUpdate(d *pluginsdk.Resource log.Printf("[INFO] preparing arguments for MsSql Server Extended Auditing Policy creation.") - serverId, err := parse.ServerID(d.Get("server_id").(string)) + serverId, err := commonids.ParseSqlServerID(d.Get("server_id").(string)) if err != nil { return err } if d.IsNewResource() { - existing, err := client.Get(ctx, serverId.ResourceGroup, serverId.Name) + existing, err := client.Get(ctx, serverId.ResourceGroupName, serverId.ServerName) if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("Failed to check for presence of existing Server %q Sql Auditing (Resource Group %q): %s", serverId.Name, serverId.ResourceGroup, err) + return fmt.Errorf("retrieving MsSql Server Extended Auditing Policy %s: %+v", serverId, err) } } @@ -150,24 +151,16 @@ func resourceMsSqlServerExtendedAuditingPolicyCreateUpdate(d *pluginsdk.Resource params.ExtendedServerBlobAuditingPolicyProperties.StorageAccountAccessKey = utils.String(v.(string)) } - future, err := client.CreateOrUpdate(ctx, serverId.ResourceGroup, serverId.Name, params) + future, err := client.CreateOrUpdate(ctx, serverId.ResourceGroupName, serverId.ServerName, params) if err != nil { - return fmt.Errorf("creating MsSql Server %q Extended Auditing Policy (Resource Group %q): %+v", serverId.Name, serverId.ResourceGroup, err) + return fmt.Errorf("creating MsSql Server Extended Auditing Policy %s: %+v", serverId, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of MsSql Server %q Extended Auditing Policy (Resource Group %q): %+v", serverId.Name, serverId.ResourceGroup, err) + return fmt.Errorf("waiting for creation of MsSql Server Extended Auditing Policy %s: %+v", serverId, err) } - read, err := client.Get(ctx, serverId.ResourceGroup, serverId.Name) - if err != nil { - return fmt.Errorf("retrieving MsSql Server %q Extended Auditing Policy (Resource Group %q): %+v", serverId.Name, serverId.ResourceGroup, err) - } - - if read.Name == nil || *read.Name == "" { - return fmt.Errorf("reading MsSql Server %q Extended Auditing Policy (Resource Group %q) Name is empty or nil", serverId.Name, serverId.ResourceGroup) - } - id := parse.NewServerExtendedAuditingPolicyID(subscriptionId, serverId.ResourceGroup, serverId.Name, *read.Name) + id := parse.NewServerExtendedAuditingPolicyID(subscriptionId, serverId.ResourceGroupName, serverId.ServerName, "default") d.SetId(id.ID()) @@ -176,7 +169,6 @@ func resourceMsSqlServerExtendedAuditingPolicyCreateUpdate(d *pluginsdk.Resource func resourceMsSqlServerExtendedAuditingPolicyRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).MSSQL.ServerExtendedBlobAuditingPoliciesClient - serverClient := meta.(*clients.Client).MSSQL.ServersClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -191,15 +183,11 @@ func resourceMsSqlServerExtendedAuditingPolicyRead(d *pluginsdk.ResourceData, me d.SetId("") return nil } - return fmt.Errorf("reading MsSql Server %s Extended Auditing Policy (Resource Group %q): %s", id.ServerName, id.ResourceGroup, err) - } - - serverResp, err := serverClient.Get(ctx, id.ResourceGroup, id.ServerName, "") - if err != nil || serverResp.ID == nil || *serverResp.ID == "" { - return fmt.Errorf("reading MsSql Server %q ID is empty or nil(Resource Group %q): %s", id.ServerName, id.ResourceGroup, err) + return fmt.Errorf("reading MsSql Server Extended Auditing Policy %s: %+v", id, err) } - d.Set("server_id", serverResp.ID) + serverId := commonids.NewSqlServerID(id.SubscriptionId, id.ResourceGroup, id.ServerName) + d.Set("server_id", serverId.ID()) if props := resp.ExtendedServerBlobAuditingPolicyProperties; props != nil { d.Set("storage_endpoint", props.StorageEndpoint) diff --git a/internal/services/mssql/mssql_server_microsoft_support_auditing_policy_resource.go b/internal/services/mssql/mssql_server_microsoft_support_auditing_policy_resource.go index a41e9aad75b3..de203b9a2aae 100644 --- a/internal/services/mssql/mssql_server_microsoft_support_auditing_policy_resource.go +++ b/internal/services/mssql/mssql_server_microsoft_support_auditing_policy_resource.go @@ -10,6 +10,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck "github.com/gofrs/uuid" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" @@ -90,16 +91,16 @@ func resourceMsSqlServerMicrosoftSupportAuditingPolicyCreateUpdate(d *pluginsdk. log.Printf("[INFO] preparing arguments for MsSql Server Microsoft Support Auditing Policy creation.") - serverId, err := parse.ServerID(d.Get("server_id").(string)) + serverId, err := commonids.ParseSqlServerID(d.Get("server_id").(string)) if err != nil { return err } if d.IsNewResource() { - existing, err := client.Get(ctx, serverId.ResourceGroup, serverId.Name, "default") + existing, err := client.Get(ctx, serverId.ResourceGroupName, serverId.ServerName, "default") if err != nil { if !utils.ResponseWasNotFound(existing.Response) { - return fmt.Errorf("Failed to check for presence of existing Server %q Sql Microsoft Support Auditing (Resource Group %q): %s", serverId.Name, serverId.ResourceGroup, err) + return fmt.Errorf("retrieving MsSql Server Microsoft Support Auditing Policy %s: %+v", serverId, err) } } @@ -134,24 +135,16 @@ func resourceMsSqlServerMicrosoftSupportAuditingPolicyCreateUpdate(d *pluginsdk. params.ServerDevOpsAuditSettingsProperties.StorageAccountAccessKey = utils.String(v.(string)) } - future, err := client.CreateOrUpdate(ctx, serverId.ResourceGroup, serverId.Name, "default", params) + future, err := client.CreateOrUpdate(ctx, serverId.ResourceGroupName, serverId.ServerName, "default", params) if err != nil { - return fmt.Errorf("creating MsSql Server %q Microsoft Support Auditing Policy (Resource Group %q): %+v", serverId.Name, serverId.ResourceGroup, err) + return fmt.Errorf("creating MsSql Server Microsoft Support Auditing Policy %s: %+v", serverId, err) } if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for creation of MsSql Server %q Microsoft Support Auditing Policy (Resource Group %q): %+v", serverId.Name, serverId.ResourceGroup, err) + return fmt.Errorf("waiting for the creation of the MsSql Server Microsoft Support Auditing Policy %s: %+v", serverId, err) } - read, err := client.Get(ctx, serverId.ResourceGroup, serverId.Name, "default") - if err != nil { - return fmt.Errorf("retrieving MsSql Server %q Microsoft Support Auditing Policy (Resource Group %q): %+v", serverId.Name, serverId.ResourceGroup, err) - } - - if read.Name == nil || *read.Name == "" { - return fmt.Errorf("reading MsSql Server %q Microsoft Support Auditing Policy (Resource Group %q) Name is empty or nil", serverId.Name, serverId.ResourceGroup) - } - id := parse.NewServerMicrosoftSupportAuditingPolicyID(subscriptionId, serverId.ResourceGroup, serverId.Name, *read.Name) + id := parse.NewServerMicrosoftSupportAuditingPolicyID(subscriptionId, serverId.ResourceGroupName, serverId.ServerName, "default") d.SetId(id.ID()) @@ -160,7 +153,6 @@ func resourceMsSqlServerMicrosoftSupportAuditingPolicyCreateUpdate(d *pluginsdk. func resourceMsSqlServerMicrosoftSupportAuditingPolicyRead(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).MSSQL.ServerDevOpsAuditSettingsClient - serverClient := meta.(*clients.Client).MSSQL.ServersClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -178,12 +170,9 @@ func resourceMsSqlServerMicrosoftSupportAuditingPolicyRead(d *pluginsdk.Resource return fmt.Errorf("reading MsSql Server %s Microsoft Support Auditing Policy (Resource Group %q): %s", id.ServerName, id.ResourceGroup, err) } - serverResp, err := serverClient.Get(ctx, id.ResourceGroup, id.ServerName, "") - if err != nil || serverResp.ID == nil || *serverResp.ID == "" { - return fmt.Errorf("reading MsSql Server %q ID is empty or nil(Resource Group %q): %s", id.ServerName, id.ResourceGroup, err) - } + serverId := commonids.NewSqlServerID(id.SubscriptionId, id.ResourceGroup, id.ServerName) - d.Set("server_id", serverResp.ID) + d.Set("server_id", serverId.ID()) if props := resp.ServerDevOpsAuditSettingsProperties; props != nil { d.Set("blob_storage_endpoint", props.StorageEndpoint) diff --git a/internal/services/mssql/mssql_server_resource.go b/internal/services/mssql/mssql_server_resource.go index f27a437a98e5..7adf9b29e33f 100644 --- a/internal/services/mssql/mssql_server_resource.go +++ b/internal/services/mssql/mssql_server_resource.go @@ -7,24 +7,29 @@ import ( "context" "fmt" "log" - "net/http" "time" - "github.com/Azure/azure-sdk-for-go/services/preview/sql/mgmt/v5.0/sql" // nolint: staticcheck - "github.com/gofrs/uuid" "github.com/hashicorp/go-azure-helpers/lang/pointer" "github.com/hashicorp/go-azure-helpers/lang/response" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" "github.com/hashicorp/go-azure-helpers/resourcemanager/commonschema" "github.com/hashicorp/go-azure-helpers/resourcemanager/identity" + "github.com/hashicorp/go-azure-helpers/resourcemanager/location" + "github.com/hashicorp/go-azure-helpers/resourcemanager/tags" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/restorabledroppeddatabases" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverazureadadministrators" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverazureadonlyauthentications" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/serverconnectionpolicies" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/servers" + "github.com/hashicorp/go-azure-sdk/sdk/client/pollers" "github.com/hashicorp/terraform-provider-azurerm/helpers/azure" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" keyVaultParser "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/parse" keyVaultValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/keyvault/validate" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/custompollers" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/mssql/validate" - "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" @@ -127,12 +132,9 @@ func resourceMsSqlServer() *pluginsdk.Resource { "connection_policy": { Type: pluginsdk.TypeString, Optional: true, - Default: string(sql.ServerConnectionTypeDefault), - ValidateFunc: validation.StringInSlice([]string{ - string(sql.ServerConnectionTypeDefault), - string(sql.ServerConnectionTypeProxy), - string(sql.ServerConnectionTypeRedirect), - }, false), + Default: string(serverconnectionpolicies.ServerConnectionTypeDefault), + ValidateFunc: validation.StringInSlice(serverconnectionpolicies.PossibleValuesForServerConnectionType(), + false), }, "identity": commonschema.SystemAssignedUserAssignedIdentityOptional(), @@ -153,6 +155,7 @@ func resourceMsSqlServer() *pluginsdk.Resource { }, }, + // TODO 4.0: Switch this field to use None pattern... "minimum_tls_version": { Type: pluginsdk.TypeString, Optional: true, @@ -190,7 +193,7 @@ func resourceMsSqlServer() *pluginsdk.Resource { }, }, - "tags": tags.Schema(), + "tags": commonschema.Tags(), }, CustomizeDiff: pluginsdk.CustomDiffWithAll( @@ -208,49 +211,47 @@ func resourceMsSqlServerCreate(d *pluginsdk.ResourceData, meta interface{}) erro ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + id := commonids.NewSqlServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) location := azure.NormalizeLocation(d.Get("location").(string)) version := d.Get("version").(string) - t := d.Get("tags").(map[string]interface{}) - metadata := tags.Expand(t) - - existing, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + existing, err := client.Get(ctx, id, servers.DefaultGetOperationOptions()) if err != nil { - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return fmt.Errorf("checking for presence of existing %s: %+v", id, err) } } - if !utils.ResponseWasNotFound(existing.Response) { + if !response.WasNotFound(existing.HttpResponse) { return tf.ImportAsExistsError("azurerm_mssql_server", id.ID()) } - props := sql.Server{ - Location: utils.String(location), - Tags: metadata, - ServerProperties: &sql.ServerProperties{ - Version: utils.String(version), - PublicNetworkAccess: sql.ServerNetworkAccessFlagEnabled, - RestrictOutboundNetworkAccess: sql.ServerNetworkAccessFlagDisabled, + props := servers.Server{ + Location: location, + Tags: tags.Expand(d.Get("tags").(map[string]interface{})), + Properties: &servers.ServerProperties{ + Version: pointer.To(version), + PublicNetworkAccess: pointer.To(servers.ServerPublicNetworkAccessFlagEnabled), + RestrictOutboundNetworkAccess: pointer.To(servers.ServerNetworkAccessFlagDisabled), }, } if v := d.Get("administrator_login"); v.(string) != "" { - props.ServerProperties.AdministratorLogin = utils.String(v.(string)) + props.Properties.AdministratorLogin = utils.String(v.(string)) } if v := d.Get("administrator_login_password"); v.(string) != "" { - props.ServerProperties.AdministratorLoginPassword = utils.String(v.(string)) + props.Properties.AdministratorLoginPassword = utils.String(v.(string)) } + // NOTE: You must set the admin before setting the values of the admin... if azureADAdministrator, ok := d.GetOk("azuread_administrator"); ok { - props.ServerProperties.Administrators = expandMsSqlServerAdministrators(azureADAdministrator.([]interface{})) + props.Properties.Administrators = expandMsSqlServerAdministrators(azureADAdministrator.([]interface{})) } if v, ok := d.GetOk("identity"); ok { - expandedIdentity, err := expandSqlServerIdentity(v.([]interface{})) + expandedIdentity, err := identity.ExpandLegacySystemAndUserAssignedMap(v.([]interface{})) if err != nil { return fmt.Errorf("expanding `identity`: %+v", err) } @@ -266,56 +267,50 @@ func resourceMsSqlServerCreate(d *pluginsdk.ResourceData, meta interface{}) erro } if keyId.NestedItemType == keyVaultParser.NestedItemTypeKey { - // msSql requires the versioned key URL... - props.KeyID = pointer.To(keyId.ID()) + // NOTE: msSql requires the versioned key URL... + props.Properties.KeyId = pointer.To(keyId.ID()) } else { return fmt.Errorf("key vault key id must be a reference to a key, got %s", keyId.NestedItemType) } } if primaryUserAssignedIdentityID, ok := d.GetOk("primary_user_assigned_identity_id"); ok { - props.PrimaryUserAssignedIdentityID = utils.String(primaryUserAssignedIdentityID.(string)) + props.Properties.PrimaryUserAssignedIdentityId = pointer.To(primaryUserAssignedIdentityID.(string)) } - // if you pass the Key ID you must also define the PrimaryUserAssignedIdentityID... - if props.KeyID != nil && props.PrimaryUserAssignedIdentityID == nil { + // NOTE: If you pass the Key ID you must also define the PrimaryUserAssignedIdentityID... + if props.Properties.KeyId != nil && props.Properties.PrimaryUserAssignedIdentityId == nil { return fmt.Errorf("the `primary_user_assigned_identity_id` field must be specified to use the 'transparent_data_encryption_key_vault_key_id' in %s", id) } if v := d.Get("public_network_access_enabled"); !v.(bool) { - props.ServerProperties.PublicNetworkAccess = sql.ServerNetworkAccessFlagDisabled + props.Properties.PublicNetworkAccess = pointer.To(servers.ServerPublicNetworkAccessFlagDisabled) } if v := d.Get("outbound_network_restriction_enabled"); v.(bool) { - props.ServerProperties.RestrictOutboundNetworkAccess = sql.ServerNetworkAccessFlagEnabled + props.Properties.RestrictOutboundNetworkAccess = pointer.To(servers.ServerNetworkAccessFlagEnabled) } + // TODO 4.0: Switch this field to use None pattern... if v := d.Get("minimum_tls_version"); v.(string) != "Disabled" { - props.ServerProperties.MinimalTLSVersion = utils.String(v.(string)) + props.Properties.MinimalTlsVersion = pointer.To(v.(string)) } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, props) + err = client.CreateOrUpdateThenPoll(ctx, id, props) if err != nil { - return fmt.Errorf("issuing create request for %s: %+v", id.String(), err) - } - - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - if response.WasConflict(future.Response()) { - return fmt.Errorf("SQL Server names need to be globally unique and %q is already in use", id.Name) - } - - return fmt.Errorf("waiting for creation/update of %s: %+v", id.String(), err) + return fmt.Errorf("creating %s: %+v", id, err) } d.SetId(id.ID()) - connection := sql.ServerConnectionPolicy{ - ServerConnectionPolicyProperties: &sql.ServerConnectionPolicyProperties{ - ConnectionType: sql.ServerConnectionType(d.Get("connection_policy").(string)), + connection := serverconnectionpolicies.ServerConnectionPolicy{ + Properties: &serverconnectionpolicies.ServerConnectionPolicyProperties{ + ConnectionType: serverconnectionpolicies.ServerConnectionType(d.Get("connection_policy").(string)), }, } - if _, err = connectionClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, connection); err != nil { - return fmt.Errorf("issuing create request for Connection Policy %s: %+v", id.String(), err) + + if err = connectionClient.CreateOrUpdateThenPoll(ctx, id, connection); err != nil { + return fmt.Errorf("creating Connection Policy for %s: %+v", id, err) } return resourceMsSqlServerRead(d, meta) @@ -323,157 +318,164 @@ func resourceMsSqlServerCreate(d *pluginsdk.ResourceData, meta interface{}) erro func resourceMsSqlServerUpdate(d *pluginsdk.ResourceData, meta interface{}) error { client := meta.(*clients.Client).MSSQL.ServersClient - subscriptionId := meta.(*clients.Client).Account.SubscriptionId connectionClient := meta.(*clients.Client).MSSQL.ServerConnectionPoliciesClient adminClient := meta.(*clients.Client).MSSQL.ServerAzureADAdministratorsClient aadOnlyAuthenticationsClient := meta.(*clients.Client).MSSQL.ServerAzureADOnlyAuthenticationsClient ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) defer cancel() - id := parse.NewServerID(subscriptionId, d.Get("resource_group_name").(string), d.Get("name").(string)) + id, err := commonids.ParseSqlServerID(d.Id()) + if err != nil { + return err + } - existing, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + existing, err := client.Get(ctx, *id, servers.DefaultGetOperationOptions()) if err != nil { return fmt.Errorf("retrieving %s: %+v", id, err) } - location := azure.NormalizeLocation(d.Get("location").(string)) - version := d.Get("version").(string) - - t := d.Get("tags").(map[string]interface{}) - metadata := tags.Expand(t) - - props := sql.Server{ - Location: utils.String(location), - Tags: metadata, - ServerProperties: &sql.ServerProperties{ - Version: utils.String(version), - PublicNetworkAccess: sql.ServerNetworkAccessFlagEnabled, - RestrictOutboundNetworkAccess: sql.ServerNetworkAccessFlagDisabled, - }, - } + if payload := existing.Model; payload != nil { + if d.HasChange("tags") { + payload.Tags = tags.Expand(d.Get("tags").(map[string]interface{})) + } - if v, ok := d.GetOk("identity"); ok { - expandedIdentity, err := expandSqlServerIdentity(v.([]interface{})) - if err != nil { - return fmt.Errorf("expanding `identity`: %+v", err) + if d.HasChange("identity") { + expanded, err := identity.ExpandLegacySystemAndUserAssignedMap(d.Get("identity").([]interface{})) + if err != nil { + return fmt.Errorf("expanding `identity`: %+v", err) + } + payload.Identity = expanded } - props.Identity = expandedIdentity - } else { - props.Identity = existing.Identity - } - if d.HasChange("key_vault_key_id") { - keyVaultKeyId := d.Get(("transparent_data_encryption_key_vault_key_id")).(string) + if d.HasChange("transparent_data_encryption_key_vault_key_id") { + keyVaultKeyId := d.Get(("transparent_data_encryption_key_vault_key_id")).(string) - keyId, err := keyVaultParser.ParseNestedItemID(keyVaultKeyId) - if err != nil { - return fmt.Errorf("unable to parse key: %q: %+v", keyVaultKeyId, err) - } + keyId, err := keyVaultParser.ParseNestedItemID(keyVaultKeyId) + if err != nil { + return fmt.Errorf("unable to parse key: %q: %+v", keyVaultKeyId, err) + } - if keyId.NestedItemType == keyVaultParser.NestedItemTypeKey { - props.KeyID = pointer.To(keyId.ID()) - } else { - return fmt.Errorf("key vault key id must be a reference to a key, got %s", keyId.NestedItemType) + if keyId.NestedItemType == keyVaultParser.NestedItemTypeKey { + payload.Properties.KeyId = pointer.To(keyId.ID()) + } else { + return fmt.Errorf("key vault key id must be a reference to a key, got %s", keyId.NestedItemType) + } } - } - if primaryUserAssignedIdentityID, ok := d.GetOk("primary_user_assigned_identity_id"); ok { - props.PrimaryUserAssignedIdentityID = utils.String(primaryUserAssignedIdentityID.(string)) - } - - // if you pass the Key ID you must also define the PrimaryUserAssignedIdentityID... - if props.KeyID != nil && props.PrimaryUserAssignedIdentityID == nil { - return fmt.Errorf("the `primary_user_assigned_identity_id` field must be specified to use the 'transparent_data_encryption_key_vault_key_id' in %s", id) - } + if primaryUserAssignedIdentityID, ok := d.GetOk("primary_user_assigned_identity_id"); ok { + payload.Properties.PrimaryUserAssignedIdentityId = pointer.To(primaryUserAssignedIdentityID.(string)) + } - if v := d.Get("public_network_access_enabled"); !v.(bool) { - props.ServerProperties.PublicNetworkAccess = sql.ServerNetworkAccessFlagDisabled - } + // if you pass the Key ID you must also define the PrimaryUserAssignedIdentityID... + if payload.Properties.KeyId != nil && payload.Properties.PrimaryUserAssignedIdentityId == nil { + return fmt.Errorf("the `primary_user_assigned_identity_id` field must be specified to use the 'transparent_data_encryption_key_vault_key_id' in %s", id) + } - if v := d.Get("outbound_network_restriction_enabled"); v.(bool) { - props.ServerProperties.RestrictOutboundNetworkAccess = sql.ServerNetworkAccessFlagEnabled - } + payload.Properties.PublicNetworkAccess = pointer.To(servers.ServerPublicNetworkAccessFlagDisabled) + payload.Properties.RestrictOutboundNetworkAccess = pointer.To(servers.ServerNetworkAccessFlagDisabled) - if d.HasChange("administrator_login_password") { - adminPassword := d.Get("administrator_login_password").(string) - props.ServerProperties.AdministratorLoginPassword = utils.String(adminPassword) - } + if v := d.Get("public_network_access_enabled"); v.(bool) { + payload.Properties.PublicNetworkAccess = pointer.To(servers.ServerPublicNetworkAccessFlagEnabled) + } - if v := d.Get("minimum_tls_version"); v.(string) != "Disabled" { - props.ServerProperties.MinimalTLSVersion = utils.String(v.(string)) - } + if v := d.Get("outbound_network_restriction_enabled"); v.(bool) { + payload.Properties.RestrictOutboundNetworkAccess = pointer.To(servers.ServerNetworkAccessFlagEnabled) + } - future, err := client.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, props) - if err != nil { - return fmt.Errorf("issuing update request for %s: %+v", id.String(), err) - } + if d.HasChange("administrator_login_password") { + adminPassword := d.Get("administrator_login_password").(string) + payload.Properties.AdministratorLoginPassword = pointer.To(adminPassword) + } - if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { - if response.WasConflict(future.Response()) { - return fmt.Errorf("SQL Server names need to be globally unique and %q is already in use", id.Name) + if d.HasChange("minimum_tls_version") { + payload.Properties.MinimalTlsVersion = pointer.To(d.Get("minimum_tls_version").(string)) } - return fmt.Errorf("waiting for update of %s: %+v", id.String(), err) + err := client.CreateOrUpdateThenPoll(ctx, *id, *payload) + if err != nil { + return fmt.Errorf("updating %s: %+v", id, err) + } } - d.SetId(id.ID()) - if d.HasChange("azuread_administrator") { - aadOnlyDeleteFuture, err := aadOnlyAuthenticationsClient.Delete(ctx, id.ResourceGroup, id.Name) + // need to check if aadOnly is enabled or not before calling delete, else you will get the following error: + // InvalidServerAADOnlyAuthNoAADAdminPropertyName: AAD Admin is not configured, AAD Admin must be set + // before enabling/disabling AAD Only Authentication. + log.Printf("[INFO] Checking if Azure Active Directory Administrators exist") + aadOnlyAdmin := false + + resp, err := adminClient.Get(ctx, pointer.From(id)) if err != nil { - if aadOnlyDeleteFuture.Response() == nil || aadOnlyDeleteFuture.Response().StatusCode != http.StatusBadRequest { - return fmt.Errorf("deleting AD Only Authentications %s: %+v", id.String(), err) + if !response.WasNotFound(resp.HttpResponse) { + return fmt.Errorf("retrieving Azure Active Directory Administrators %s: %+v", pointer.From(id), err) } - log.Printf("[INFO] AD Only Authentication is not removed as AD Admin is not set for %s: %+v", id.String(), err) - } else if err = aadOnlyDeleteFuture.WaitForCompletionRef(ctx, adminClient.Client); err != nil { - return fmt.Errorf("waiting for deletion of AD Only Authentications %s: %+v", id.String(), err) + } else { + aadOnlyAdmin = true } - if adminParams := expandMsSqlServerAdministrator(d.Get("azuread_administrator").([]interface{})); adminParams != nil { - adminFuture, err := adminClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, *adminParams) + if aadOnlyAdmin { + resp, err := aadOnlyAuthenticationsClient.Delete(ctx, *id) if err != nil { - return fmt.Errorf("creating AAD admin %s: %+v", id.String(), err) + log.Printf("[INFO] Deletion of Azure Active Directory Only Authentication failed for %s: %+v", pointer.From(id), err) + return fmt.Errorf("deleting Azure Active Directory Only Authentications for %s: %+v", pointer.From(id), err) + } + + // NOTE: This call does not return a future it returns a response, but you will get a future back if the status code is 202... + // https://learn.microsoft.com/en-us/rest/api/sql/server-azure-ad-only-authentications/delete?view=rest-sql-2023-05-01-preview&tabs=HTTP + if response.WasStatusCode(resp.HttpResponse, 202) { + // NOTE: It was accepted but not completed, it is now an async operation... + // create a custom poller and wait for it to complete as 'Succeeded'... + log.Printf("[INFO] Delete Azure Active Directory Only Administrators response was a 202 WaitForStateContext...") + + initialDelayDuration := 5 * time.Second + pollerType := custompollers.NewMsSqlServerDeleteServerAzureADOnlyAuthenticationPoller(aadOnlyAuthenticationsClient, pointer.From(id)) + poller := pollers.NewPoller(pollerType, initialDelayDuration, pollers.DefaultNumberOfDroppedConnectionsToAllow) + if err := poller.PollUntilDone(ctx); err != nil { + return fmt.Errorf("waiting for the deletion of the Azure Active Directory Only Administrator: %+v", err) + } } + } - if err = adminFuture.WaitForCompletionRef(ctx, adminClient.Client); err != nil { - return fmt.Errorf("waiting for creation of AAD admin %s: %+v", id.String(), err) + log.Printf("[INFO] Expanding 'azuread_administrator' to see if we need Create or Delete") + if adminProps := expandMsSqlServerAdministrator(d.Get("azuread_administrator").([]interface{})); adminProps != nil { + err := adminClient.CreateOrUpdateThenPoll(ctx, *id, pointer.From(adminProps)) + if err != nil { + return fmt.Errorf("creating Azure Active Directory Administrator %s: %+v", id, err) } } else { - adminDelFuture, err := adminClient.Delete(ctx, id.ResourceGroup, id.Name) + _, err := adminClient.Get(ctx, *id) if err != nil { - return fmt.Errorf("deleting AAD admin %s: %+v", id.String(), err) + return fmt.Errorf("retrieving Azure Active Directory Administrator %s: %+v", id, err) } - if err = adminDelFuture.WaitForCompletionRef(ctx, adminClient.Client); err != nil { - return fmt.Errorf("waiting for deletion of AAD admin %s: %+v", id.String(), err) + err = adminClient.DeleteThenPoll(ctx, *id) + if err != nil { + return fmt.Errorf("deleting Azure Active Directory Administrator %s: %+v", id, err) } } } if aadOnlyAuthentictionsEnabled := expandMsSqlServerAADOnlyAuthentictions(d.Get("azuread_administrator").([]interface{})); d.HasChange("azuread_administrator") && aadOnlyAuthentictionsEnabled { - aadOnlyAuthentictionsParams := sql.ServerAzureADOnlyAuthentication{ - AzureADOnlyAuthProperties: &sql.AzureADOnlyAuthProperties{ - AzureADOnlyAuthentication: utils.Bool(aadOnlyAuthentictionsEnabled), + aadOnlyAuthentictionsProps := serverazureadonlyauthentications.ServerAzureADOnlyAuthentication{ + Properties: &serverazureadonlyauthentications.AzureADOnlyAuthProperties{ + AzureADOnlyAuthentication: aadOnlyAuthentictionsEnabled, }, } - aadOnlyEnabledFuture, err := aadOnlyAuthenticationsClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, aadOnlyAuthentictionsParams) - if err != nil { - return fmt.Errorf("setting AAD only authentication for %s: %+v", id.String(), err) - } - if err = aadOnlyEnabledFuture.WaitForCompletionRef(ctx, adminClient.Client); err != nil { - return fmt.Errorf("waiting for setting of AAD only authentication for %s: %+v", id.String(), err) + err := aadOnlyAuthenticationsClient.CreateOrUpdateThenPoll(ctx, *id, aadOnlyAuthentictionsProps) + if err != nil { + return fmt.Errorf("updating Azure Active Directory Only Authentication for %s: %+v", id, err) } } - connection := sql.ServerConnectionPolicy{ - ServerConnectionPolicyProperties: &sql.ServerConnectionPolicyProperties{ - ConnectionType: sql.ServerConnectionType(d.Get("connection_policy").(string)), + connection := serverconnectionpolicies.ServerConnectionPolicy{ + Properties: &serverconnectionpolicies.ServerConnectionPolicyProperties{ + ConnectionType: serverconnectionpolicies.ServerConnectionType(d.Get("connection_policy").(string)), }, } - if _, err = connectionClient.CreateOrUpdate(ctx, id.ResourceGroup, id.Name, connection); err != nil { - return fmt.Errorf("issuing update request for Connection Policy %s: %+v", id.String(), err) + + if err = connectionClient.CreateOrUpdateThenPoll(ctx, *id, connection); err != nil { + return fmt.Errorf("updating request for Connection Policy %s: %+v", id, err) } return resourceMsSqlServerRead(d, meta) @@ -486,81 +488,93 @@ func resourceMsSqlServerRead(d *pluginsdk.ResourceData, meta interface{}) error ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ServerID(d.Id()) + id, err := commonids.ParseSqlServerID(d.Id()) if err != nil { return err } - resp, err := client.Get(ctx, id.ResourceGroup, id.Name, "") + resp, err := client.Get(ctx, *id, servers.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { - log.Printf("[INFO] Error reading SQL Server %s - removing from state", id.String()) + if response.WasNotFound(resp.HttpResponse) { + log.Printf("[INFO] Error retrieving SQL Server %s - removing from state", id) d.SetId("") return nil } - return fmt.Errorf("reading SQL Server %s: %v", id.Name, err) + return fmt.Errorf("retrieving SQL Server %s: %v", id, err) } - d.Set("name", id.Name) - d.Set("resource_group_name", id.ResourceGroup) - if location := resp.Location; location != nil { - d.Set("location", azure.NormalizeLocation(*location)) - } - identity, err := flattenSqlServerIdentity(resp.Identity) - if err != nil { - return fmt.Errorf("setting `identity`: %+v", err) - } + d.Set("name", id.ServerName) + d.Set("resource_group_name", id.ResourceGroupName) - if err := d.Set("identity", identity); err != nil { - return fmt.Errorf("setting `identity`: %+v", err) - } + if model := resp.Model; model != nil { + d.Set("location", location.Normalize(model.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) - // todo remove `|| *v == "None"` when https://github.com/Azure/azure-rest-api-specs/issues/24348 is addressed - if v := props.MinimalTLSVersion; v == nil || *v == "None" { - d.Set("minimum_tls_version", "Disabled") - } else { - d.Set("minimum_tls_version", props.MinimalTLSVersion) + identity, err := identity.FlattenLegacySystemAndUserAssignedMap(model.Identity) + if err != nil { + return fmt.Errorf("setting `identity`: %+v", err) } - d.Set("public_network_access_enabled", props.PublicNetworkAccess == sql.ServerNetworkAccessFlagEnabled) - d.Set("outbound_network_restriction_enabled", props.RestrictOutboundNetworkAccess == sql.ServerNetworkAccessFlagEnabled) - primaryUserAssignedIdentityID := "" - if props.PrimaryUserAssignedIdentityID != nil && *props.PrimaryUserAssignedIdentityID != "" { - parsedPrimaryUserAssignedIdentityID, err := commonids.ParseUserAssignedIdentityIDInsensitively(*props.PrimaryUserAssignedIdentityID) - if err != nil { - return err + + if err := d.Set("identity", identity); err != nil { + return fmt.Errorf("setting `identity`: %+v", err) + } + + if props := model.Properties; props != nil { + d.Set("version", props.Version) + d.Set("administrator_login", props.AdministratorLogin) + d.Set("fully_qualified_domain_name", props.FullyQualifiedDomainName) + + // todo remove `|| *v == "None"` when https://github.com/Azure/azure-rest-api-specs/issues/24348 is addressed + if v := props.MinimalTlsVersion; v == nil || *v == "None" { + d.Set("minimum_tls_version", "Disabled") + } else { + d.Set("minimum_tls_version", props.MinimalTlsVersion) + } + + d.Set("public_network_access_enabled", pointer.From(props.PublicNetworkAccess) == servers.ServerPublicNetworkAccessFlagEnabled) + d.Set("outbound_network_restriction_enabled", pointer.From(props.RestrictOutboundNetworkAccess) == servers.ServerNetworkAccessFlagEnabled) + + primaryUserAssignedIdentityID := "" + if props.PrimaryUserAssignedIdentityId != nil && pointer.From(props.PrimaryUserAssignedIdentityId) != "" { + parsedPrimaryUserAssignedIdentityID, err := commonids.ParseUserAssignedIdentityIDInsensitively(pointer.From(props.PrimaryUserAssignedIdentityId)) + if err != nil { + return err + } + primaryUserAssignedIdentityID = parsedPrimaryUserAssignedIdentityID.ID() + } + + d.Set("primary_user_assigned_identity_id", primaryUserAssignedIdentityID) + d.Set("transparent_data_encryption_key_vault_key_id", props.KeyId) + + if props.Administrators != nil { + d.Set("azuread_administrator", flatternMsSqlServerAdministrators(*props.Administrators)) } - primaryUserAssignedIdentityID = parsedPrimaryUserAssignedIdentityID.ID() } - d.Set("primary_user_assigned_identity_id", primaryUserAssignedIdentityID) - d.Set("transparent_data_encryption_key_vault_key_id", props.KeyID) - if props.Administrators != nil { - d.Set("azuread_administrator", flatternMsSqlServerAdministrators(*props.Administrators)) + + if err := tags.FlattenAndSet(d, model.Tags); err != nil { + return err } } - connection, err := connectionClient.Get(ctx, id.ResourceGroup, id.Name) + connection, err := connectionClient.Get(ctx, pointer.From(id)) if err != nil { - return fmt.Errorf("reading SQL Server %s Blob Connection Policy: %v ", id.Name, err) + return fmt.Errorf("reading SQL Server Blob Connection Policy %s: %v ", id, err) } - if props := connection.ServerConnectionPolicyProperties; props != nil { - d.Set("connection_policy", string(props.ConnectionType)) + if model := connection.Model; model != nil && model.Properties != nil { + d.Set("connection_policy", string(model.Properties.ConnectionType)) } - restorableListPage, err := restorableDroppedDatabasesClient.ListByServer(ctx, id.ResourceGroup, id.Name) + restorableListPage, err := restorableDroppedDatabasesClient.ListByServerComplete(ctx, pointer.From(id)) if err != nil { - return fmt.Errorf("listing SQL Server %s Restorable Dropped Databases: %v", id.Name, err) + return fmt.Errorf("listing SQL Server Restorable Dropped Databases %s: %v", id, err) } - if err := d.Set("restorable_dropped_database_ids", flattenSqlServerRestorableDatabases(restorableListPage.Response())); err != nil { + + if err := d.Set("restorable_dropped_database_ids", flattenSqlServerRestorableDatabases(restorableListPage)); err != nil { return fmt.Errorf("setting `restorable_dropped_database_ids`: %+v", err) } - return tags.FlattenAndSet(d, resp.Tags) + return nil } func resourceMsSqlServerDelete(d *pluginsdk.ResourceData, meta interface{}) error { @@ -568,121 +582,71 @@ func resourceMsSqlServerDelete(d *pluginsdk.ResourceData, meta interface{}) erro ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() - id, err := parse.ServerID(d.Id()) + id, err := commonids.ParseSqlServerID(d.Id()) if err != nil { return err } - future, err := client.Delete(ctx, id.ResourceGroup, id.Name) - if err != nil { - return fmt.Errorf("deleting SQL Server %s: %+v", id.Name, err) - } - - return future.WaitForCompletionRef(ctx, client.Client) -} - -func expandSqlServerIdentity(input []interface{}) (*sql.ResourceIdentity, error) { - expanded, err := identity.ExpandSystemAndUserAssignedMap(input) + err = client.DeleteThenPoll(ctx, pointer.From(id)) if err != nil { - return nil, err - } - - out := sql.ResourceIdentity{ - Type: sql.IdentityType(string(expanded.Type)), - } - if expanded.Type == identity.TypeUserAssigned || expanded.Type == identity.TypeSystemAssignedUserAssigned { - out.UserAssignedIdentities = make(map[string]*sql.UserIdentity) - for k := range expanded.IdentityIds { - out.UserAssignedIdentities[k] = &sql.UserIdentity{ - // intentionally empty - } - } - } - - return &out, nil -} - -func flattenSqlServerIdentity(input *sql.ResourceIdentity) (*[]interface{}, error) { - var transform *identity.SystemAndUserAssignedMap - - if input != nil { - transform = &identity.SystemAndUserAssignedMap{ - Type: identity.Type(string(input.Type)), - IdentityIds: make(map[string]identity.UserAssignedIdentityDetails), - } - if input.PrincipalID != nil { - transform.PrincipalId = input.PrincipalID.String() - } - if input.TenantID != nil { - transform.TenantId = input.TenantID.String() - } - for k, v := range input.UserAssignedIdentities { - details := identity.UserAssignedIdentityDetails{} - if v.ClientID != nil { - details.ClientId = utils.String(v.ClientID.String()) - } - if v.PrincipalID != nil { - details.PrincipalId = utils.String(v.PrincipalID.String()) - } - transform.IdentityIds[k] = details - } + return fmt.Errorf("deleting SQL Server %s: %+v", id, err) } - return identity.FlattenSystemAndUserAssignedMap(transform) + return nil } func expandMsSqlServerAADOnlyAuthentictions(input []interface{}) bool { if len(input) == 0 || input[0] == nil { return false } + admin := input[0].(map[string]interface{}) + if v, ok := admin["azuread_authentication_only"]; ok && v != nil { return v.(bool) } + return false } -func expandMsSqlServerAdministrator(input []interface{}) *sql.ServerAzureADAdministrator { +func expandMsSqlServerAdministrator(input []interface{}) *serverazureadadministrators.ServerAzureADAdministrator { if len(input) == 0 || input[0] == nil { return nil } - admin := input[0].(map[string]interface{}) - sid, _ := uuid.FromString(admin["object_id"].(string)) + v := input[0].(map[string]interface{}) - adminParams := sql.ServerAzureADAdministrator{ - AdministratorProperties: &sql.AdministratorProperties{ - AdministratorType: utils.String("ActiveDirectory"), - Login: utils.String(admin["login_username"].(string)), - Sid: &sid, + adminProps := serverazureadadministrators.ServerAzureADAdministrator{ + Properties: &serverazureadadministrators.AdministratorProperties{ + AdministratorType: serverazureadadministrators.AdministratorType(servers.AdministratorTypeActiveDirectory), + Login: v["login_username"].(string), + Sid: v["object_id"].(string), }, } - if v, ok := admin["tenant_id"]; ok && v != "" { - tid, _ := uuid.FromString(v.(string)) - adminParams.TenantID = &tid + if t, ok := v["tenant_id"]; ok && t != "" { + adminProps.Properties.TenantId = pointer.To(t.(string)) } - return &adminParams + return pointer.To(adminProps) } -func expandMsSqlServerAdministrators(input []interface{}) *sql.ServerExternalAdministrator { +func expandMsSqlServerAdministrators(input []interface{}) *servers.ServerExternalAdministrator { if len(input) == 0 || input[0] == nil { return nil } admin := input[0].(map[string]interface{}) - sid, _ := uuid.FromString(admin["object_id"].(string)) + sid := admin["object_id"].(string) - adminParams := sql.ServerExternalAdministrator{ - AdministratorType: sql.AdministratorTypeActiveDirectory, - Login: utils.String(admin["login_username"].(string)), - Sid: &sid, + adminParams := servers.ServerExternalAdministrator{ + AdministratorType: pointer.To(servers.AdministratorTypeActiveDirectory), + Login: pointer.To(admin["login_username"].(string)), + Sid: pointer.To(sid), } if v, ok := admin["tenant_id"]; ok && v != "" { - tid, _ := uuid.FromString(v.(string)) - adminParams.TenantID = &tid + adminParams.TenantId = pointer.To(v.(string)) } if v, ok := admin["azuread_authentication_only"]; ok && v != "" { @@ -693,23 +657,23 @@ func expandMsSqlServerAdministrators(input []interface{}) *sql.ServerExternalAdm return &adminParams } -func flatternMsSqlServerAdministrators(admin sql.ServerExternalAdministrator) []interface{} { +func flatternMsSqlServerAdministrators(admin servers.ServerExternalAdministrator) []interface{} { var login, sid, tid string if admin.Login != nil { login = *admin.Login } if admin.Sid != nil { - sid = admin.Sid.String() + sid = pointer.From(admin.Sid) } - if admin.TenantID != nil { - tid = admin.TenantID.String() + if admin.TenantId != nil { + tid = pointer.From(admin.TenantId) } var aadOnlyAuthentictionsEnabled bool if admin.AzureADOnlyAuthentication != nil { - aadOnlyAuthentictionsEnabled = *admin.AzureADOnlyAuthentication + aadOnlyAuthentictionsEnabled = pointer.From(admin.AzureADOnlyAuthentication) } return []interface{}{ @@ -722,18 +686,20 @@ func flatternMsSqlServerAdministrators(admin sql.ServerExternalAdministrator) [] } } -func flattenSqlServerRestorableDatabases(resp sql.RestorableDroppedDatabaseListResult) []string { - if resp.Value == nil || len(*resp.Value) == 0 { +func flattenSqlServerRestorableDatabases(resp restorabledroppeddatabases.ListByServerCompleteResult) []string { + if len(resp.Items) == 0 { return []string{} } + res := make([]string, 0) - for _, r := range *resp.Value { + for _, r := range resp.Items { var id string - if r.ID != nil { - id = *r.ID + if r.Id != nil { + id = *r.Id + res = append(res, id) } - res = append(res, id) } + return res } diff --git a/internal/services/mssql/mssql_server_resource_test.go b/internal/services/mssql/mssql_server_resource_test.go index 0b802301e45c..60a8278907dd 100644 --- a/internal/services/mssql/mssql_server_resource_test.go +++ b/internal/services/mssql/mssql_server_resource_test.go @@ -8,6 +8,9 @@ import ( "fmt" "testing" + "github.com/hashicorp/go-azure-helpers/lang/response" + "github.com/hashicorp/go-azure-helpers/resourcemanager/commonids" + "github.com/hashicorp/go-azure-sdk/resource-manager/sql/2023-02-01-preview/servers" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance" "github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -225,7 +228,7 @@ func TestAccMsSqlServer_azureadAdminWithAADAuthOnly(t *testing.T) { }) } -func TestAccMsSqlServer_updateAzureadAuthenticationOnlyWithIdentity(t *testing.T) { +func TestAccMsSqlServer_azureadAuthenticationOnlyWithIdentityUpdate(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_mssql_server", "test") r := MsSqlServerResource{} @@ -244,6 +247,13 @@ func TestAccMsSqlServer_updateAzureadAuthenticationOnlyWithIdentity(t *testing.T ), }, data.ImportStep("administrator_login_password"), + { + Config: r.updateAzureadAuthenticationOnlyWithIdentity(data, false), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("administrator_login_password"), }) } @@ -262,21 +272,52 @@ func TestAccMsSqlServer_TDECMKServerDeployment(t *testing.T) { }) } +func TestAccMsSqlServer_CMKServerTagsUpdate(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_mssql_server", "test") + r := MsSqlServerResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.CMKServerTags(data, "Sandbox"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("administrator_login_password"), + { + Config: r.CMKServerTags(data, "Production"), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("administrator_login_password"), + { + Config: r.CMKServerNoTags(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("administrator_login_password"), + }) +} + func (MsSqlServerResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { id, err := parse.ServerID(state.ID) if err != nil { return nil, err } - resp, err := client.MSSQL.ServersClient.Get(ctx, id.ResourceGroup, id.Name, "") + serverId := commonids.NewSqlServerID(id.SubscriptionId, id.ResourceGroup, id.Name) + + resp, err := client.MSSQL.ServersClient.Get(ctx, serverId, servers.DefaultGetOperationOptions()) if err != nil { - if utils.ResponseWasNotFound(resp.Response) { + if response.WasNotFound(resp.HttpResponse) { return nil, fmt.Errorf("SQL Server %q (Resource Group %q) does not exist", id.Name, id.ResourceGroup) } return nil, fmt.Errorf("reading SQL Server %q (Resource Group %q): %v", id.Name, id.ResourceGroup, err) } - return utils.Bool(resp.ID != nil), nil + return utils.Bool(resp.Model != nil), nil } func (MsSqlServerResource) basic(data acceptance.TestData) string { @@ -847,3 +888,169 @@ resource "azurerm_key_vault_key" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomString) } + +func (MsSqlServerResource) CMKServerTags(data acceptance.TestData, tag string) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "test" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-mssql-%[1]d" + location = "%[2]s" +} + +resource "azurerm_user_assigned_identity" "test" { + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + name = "test_identity_2112" +} + +resource "azurerm_mssql_server" "test" { + name = "acctestsqlserver%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + version = "12.0" + administrator_login = "DaveLister" + administrator_login_password = "7h1515K4711" + minimum_tls_version = "1.2" + + azuread_administrator { + login_username = azurerm_user_assigned_identity.test.name + object_id = azurerm_user_assigned_identity.test.principal_id + } + + identity { + type = "UserAssigned" + identity_ids = [azurerm_user_assigned_identity.test.id] + } + + primary_user_assigned_identity_id = azurerm_user_assigned_identity.test.id + transparent_data_encryption_key_vault_key_id = azurerm_key_vault_key.test.id + + tags = { + DB = "%[4]s" + } +} + +resource "azurerm_key_vault" "test" { + name = "vault%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + enabled_for_disk_encryption = true + tenant_id = azurerm_user_assigned_identity.test.tenant_id + soft_delete_retention_days = 7 + purge_protection_enabled = true + + sku_name = "standard" + + access_policy { + tenant_id = data.azurerm_client_config.test.tenant_id + object_id = data.azurerm_client_config.test.object_id + + key_permissions = ["Get", "List", "Create", "Delete", "Update", "Recover", "Purge", "GetRotationPolicy"] + } + + access_policy { + tenant_id = azurerm_user_assigned_identity.test.tenant_id + object_id = azurerm_user_assigned_identity.test.principal_id + + key_permissions = ["Get", "WrapKey", "UnwrapKey"] + } +} + +resource "azurerm_key_vault_key" "test" { + depends_on = [azurerm_key_vault.test] + + name = "key-%[3]s" + key_vault_id = azurerm_key_vault.test.id + key_type = "RSA" + key_size = 2048 + + key_opts = ["unwrapKey", "wrapKey"] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString, tag) +} + +func (MsSqlServerResource) CMKServerNoTags(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "test" {} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-mssql-%[1]d" + location = "%[2]s" +} + +resource "azurerm_user_assigned_identity" "test" { + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + name = "test_identity_2112" +} + +resource "azurerm_mssql_server" "test" { + name = "acctestsqlserver%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + version = "12.0" + administrator_login = "DaveLister" + administrator_login_password = "7h1515K4711" + minimum_tls_version = "1.2" + + azuread_administrator { + login_username = azurerm_user_assigned_identity.test.name + object_id = azurerm_user_assigned_identity.test.principal_id + } + + identity { + type = "UserAssigned" + identity_ids = [azurerm_user_assigned_identity.test.id] + } + + primary_user_assigned_identity_id = azurerm_user_assigned_identity.test.id + transparent_data_encryption_key_vault_key_id = azurerm_key_vault_key.test.id +} + +resource "azurerm_key_vault" "test" { + name = "vault%[1]d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + enabled_for_disk_encryption = true + tenant_id = azurerm_user_assigned_identity.test.tenant_id + soft_delete_retention_days = 7 + purge_protection_enabled = true + + sku_name = "standard" + + access_policy { + tenant_id = data.azurerm_client_config.test.tenant_id + object_id = data.azurerm_client_config.test.object_id + + key_permissions = ["Get", "List", "Create", "Delete", "Update", "Recover", "Purge", "GetRotationPolicy"] + } + + access_policy { + tenant_id = azurerm_user_assigned_identity.test.tenant_id + object_id = azurerm_user_assigned_identity.test.principal_id + + key_permissions = ["Get", "WrapKey", "UnwrapKey"] + } +} + +resource "azurerm_key_vault_key" "test" { + depends_on = [azurerm_key_vault.test] + + name = "key-%[3]s" + key_vault_id = azurerm_key_vault.test.id + key_type = "RSA" + key_size = 2048 + + key_opts = ["unwrapKey", "wrapKey"] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomString) +} diff --git a/internal/services/mssql/mssql_server_security_alert_policy_resource.go b/internal/services/mssql/mssql_server_security_alert_policy_resource.go index d8d893c2da43..3721fdf0cc2a 100644 --- a/internal/services/mssql/mssql_server_security_alert_policy_resource.go +++ b/internal/services/mssql/mssql_server_security_alert_policy_resource.go @@ -115,7 +115,7 @@ func resourceMsSqlServerSecurityAlertPolicy() *pluginsdk.Resource { } func resourceMsSqlServerSecurityAlertPolicyCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).MSSQL.ServerSecurityAlertPoliciesClient + client := meta.(*clients.Client).MSSQL.LegacyServerSecurityAlertPoliciesClient subscriptionId := meta.(*clients.Client).Account.SubscriptionId ctx, cancel := timeouts.ForCreateUpdate(meta.(*clients.Client).StopContext, d) defer cancel() @@ -151,7 +151,7 @@ func resourceMsSqlServerSecurityAlertPolicyCreateUpdate(d *pluginsdk.ResourceDat } func resourceMsSqlServerSecurityAlertPolicyRead(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).MSSQL.ServerSecurityAlertPoliciesClient + client := meta.(*clients.Client).MSSQL.LegacyServerSecurityAlertPoliciesClient ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) defer cancel() @@ -222,7 +222,7 @@ func resourceMsSqlServerSecurityAlertPolicyRead(d *pluginsdk.ResourceData, meta } func resourceMsSqlServerSecurityAlertPolicyDelete(d *pluginsdk.ResourceData, meta interface{}) error { - client := meta.(*clients.Client).MSSQL.ServerSecurityAlertPoliciesClient + client := meta.(*clients.Client).MSSQL.LegacyServerSecurityAlertPoliciesClient ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) defer cancel() diff --git a/internal/services/mssql/mssql_server_security_alert_policy_resource_test.go b/internal/services/mssql/mssql_server_security_alert_policy_resource_test.go index f27d189beae5..e6801dc82aa7 100644 --- a/internal/services/mssql/mssql_server_security_alert_policy_resource_test.go +++ b/internal/services/mssql/mssql_server_security_alert_policy_resource_test.go @@ -61,7 +61,7 @@ func (MsSqlServerSecurityAlertPolicyResource) Exists(ctx context.Context, client return nil, err } - resp, err := client.MSSQL.ServerSecurityAlertPoliciesClient.Get(ctx, id.ResourceGroup, id.ServerName) + resp, err := client.MSSQL.LegacyServerSecurityAlertPoliciesClient.Get(ctx, id.ResourceGroup, id.ServerName) if err != nil { if utils.ResponseWasNotFound(resp.Response) { return nil, fmt.Errorf("SQL Security Alert Policy for server %q (Resource Group %q) does not exist", id.ServerName, id.ResourceGroup) diff --git a/internal/services/mssql/mssql_server_transparent_data_encryption_resource.go b/internal/services/mssql/mssql_server_transparent_data_encryption_resource.go index 042099c9b194..42e38c1c825d 100644 --- a/internal/services/mssql/mssql_server_transparent_data_encryption_resource.go +++ b/internal/services/mssql/mssql_server_transparent_data_encryption_resource.go @@ -112,7 +112,7 @@ func resourceMsSqlTransparentDataEncryptionCreateUpdate(d *pluginsdk.ResourceDat // Set the encryption protector properties keyId, err := keyVaultParser.ParseNestedItemID(keyVaultKeyId) if err != nil { - return fmt.Errorf("Unable to parse key: %q: %+v", keyVaultKeyId, err) + return fmt.Errorf("unable to parse key: %q: %+v", keyVaultKeyId, err) } // Make sure it's a key, if not, throw an error @@ -123,7 +123,7 @@ func resourceMsSqlTransparentDataEncryptionCreateUpdate(d *pluginsdk.ResourceDat // Extract the vault name from the keyvault base url idURL, err := url.ParseRequestURI(keyId.KeyVaultBaseUrl) if err != nil { - return fmt.Errorf("Unable to parse key vault hostname: %s", keyId.KeyVaultBaseUrl) + return fmt.Errorf("unable to parse key vault hostname: %s", keyId.KeyVaultBaseUrl) } hostParts := strings.Split(idURL.Host, ".") @@ -132,7 +132,7 @@ func resourceMsSqlTransparentDataEncryptionCreateUpdate(d *pluginsdk.ResourceDat // Create the key path for the Encryption Protector. Format is: {vaultname}_{key}_{key_version} serverKeyName = fmt.Sprintf("%s_%s_%s", vaultName, keyName, keyVersion) } else { - return fmt.Errorf("Key vault key id must be a reference to a key, but got: %s", keyId.NestedItemType) + return fmt.Errorf("key vault key id must be a reference to a key, but got: %s", keyId.NestedItemType) } } diff --git a/internal/services/mssql/mssql_server_vulnerability_assessment_resource.go b/internal/services/mssql/mssql_server_vulnerability_assessment_resource.go index e52fa5b699cb..c82257a497cc 100644 --- a/internal/services/mssql/mssql_server_vulnerability_assessment_resource.go +++ b/internal/services/mssql/mssql_server_vulnerability_assessment_resource.go @@ -109,14 +109,14 @@ func resourceMsSqlServerVulnerabilityAssessmentCreateUpdate(d *pluginsdk.Resourc return err } - policyClient := meta.(*clients.Client).MSSQL.ServerSecurityAlertPoliciesClient + policyClient := meta.(*clients.Client).MSSQL.LegacyServerSecurityAlertPoliciesClient policy, err := policyClient.Get(ctx, policyId.ResourceGroup, policyId.ServerName) if err != nil { return fmt.Errorf("retrieving Security Alert Policy: %+v", err) } if policy.State != sql.SecurityAlertsPolicyStateEnabled { - return fmt.Errorf("Security Alert Policy is not enabled") + return fmt.Errorf("security alert policy is not enabled") } log.Printf("[INFO] preparing arguments for mssql server vulnerability assessment creation.") @@ -182,7 +182,7 @@ func resourceMsSqlServerVulnerabilityAssessmentRead(d *pluginsdk.ResourceData, m return fmt.Errorf("making read request to mssql server vulnerability assessment: %+v", err) } - policyClient := meta.(*clients.Client).MSSQL.ServerSecurityAlertPoliciesClient + policyClient := meta.(*clients.Client).MSSQL.LegacyServerSecurityAlertPoliciesClient policy, err := policyClient.Get(ctx, id.ResourceGroup, id.ServerName) if err != nil { return fmt.Errorf("retrieving Security Alert Policy by ID: %+v", err) diff --git a/website/docs/d/mssql_database.html.markdown b/website/docs/d/mssql_database.html.markdown index c0deadc5809a..ec5824993f6d 100644 --- a/website/docs/d/mssql_database.html.markdown +++ b/website/docs/d/mssql_database.html.markdown @@ -45,6 +45,8 @@ output "database_id" { ## Attributes Reference +* `id` - The ID of the database. + * `collation` - The collation of the database. * `elastic_pool_id` - The id of the elastic pool containing this database. diff --git a/website/docs/d/mssql_elasticpool.html.markdown b/website/docs/d/mssql_elasticpool.html.markdown index f47652505688..eae5553694d3 100644 --- a/website/docs/d/mssql_elasticpool.html.markdown +++ b/website/docs/d/mssql_elasticpool.html.markdown @@ -34,6 +34,8 @@ output "elasticpool_id" { ## Attributes Reference +* `id` - The ID of the elastic pool. + * `license_type` - The license type to apply for this database. * `location` - Specifies the supported Azure location where the resource exists. diff --git a/website/docs/r/mssql_database.html.markdown b/website/docs/r/mssql_database.html.markdown index 35afde3707bd..87f89e4abcb8 100644 --- a/website/docs/r/mssql_database.html.markdown +++ b/website/docs/r/mssql_database.html.markdown @@ -123,7 +123,7 @@ The following arguments are supported: * `transparent_data_encryption_enabled` - (Optional) If set to true, Transparent Data Encryption will be enabled on the database. Defaults to `true`. --> **NOTE:** TDE cannot be disabled on servers with SKUs other than ones starting with DW. +-> **NOTE:** `transparent_data_encryption_enabled` can only be set to `false` on DW (e.g, DataWarehouse) server SKUs. * `zone_redundant` - (Optional) Whether or not this database is zone redundant, which means the replicas of this database will be spread across multiple availability zones. This property is only settable for Premium and Business Critical databases. @@ -143,9 +143,9 @@ a `import` block supports the following: --- a `threat_detection_policy` block supports the following: -* `state` - (Optional) The State of the Policy. Possible values are `Enabled`, `Disabled` or `New`. Defaults to `Disabled`. +* `state` - (Optional) The State of the Policy. Possible values are `Enabled` or `Disabled`. Defaults to `Disabled`. * `disabled_alerts` - (Optional) Specifies a list of alerts which should be disabled. Possible values include `Access_Anomaly`, `Sql_Injection` and `Sql_Injection_Vulnerability`. -* `email_account_admins` - (Optional) Should the account administrators be emailed when this alert is triggered? Possible values are `Disabled` and `Enabled`. Defaults to `Disabled`. +* `email_account_admins` - (Optional) Should the account administrators be emailed when this alert is triggered? Possible values are `Enabled` or `Disabled`. Defaults to `Disabled`. * `email_addresses` - (Optional) A list of email addresses which alerts should be sent to. * `retention_days` - (Optional) Specifies the number of days to keep in the Threat Detection audit logs. * `storage_account_access_key` - (Optional) Specifies the identifier key of the Threat Detection audit storage account. Required if `state` is `Enabled`.