From fdefbf6071373b8e61273cd1682ec895d8a82f44 Mon Sep 17 00:00:00 2001 From: Benjamin Engeset <99641908+BenjaminEngeset@users.noreply.github.com> Date: Tue, 9 Jul 2024 17:50:15 +0200 Subject: [PATCH] feat(new): Added Azure.SQL.MaintenanceWindow (#2978) * feat(new): Added Azure.SQL.MaintenanceWindow * Update src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 Co-authored-by: Bernie White * Update src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 Co-authored-by: Bernie White * Update src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 Co-authored-by: Bernie White * Update src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 Co-authored-by: Bernie White * Update src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 Co-authored-by: Bernie White * Update docs/en/rules/Azure.SQL.MaintenanceWindow.md Co-authored-by: Bernie White * feat: Added logic for SKUs and master database * fix: Hardcode location for readability --------- Co-authored-by: Bernie White --- docs/CHANGELOG-v1.md | 5 + docs/en/rules/Azure.SQL.MaintenanceWindow.md | 99 +++++++ src/PSRule.Rules.Azure/en/PSRule-rules.psd1 | 1 + .../rules/Azure.SQL.Rule.ps1 | 61 +++- .../Azure.SQL.Tests.ps1 | 26 ++ .../Resources.SQL.json | 273 ++++++++++++++++++ 6 files changed, 459 insertions(+), 6 deletions(-) create mode 100644 docs/en/rules/Azure.SQL.MaintenanceWindow.md diff --git a/docs/CHANGELOG-v1.md b/docs/CHANGELOG-v1.md index 8ebff6e9c0..329238166d 100644 --- a/docs/CHANGELOG-v1.md +++ b/docs/CHANGELOG-v1.md @@ -29,6 +29,11 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers ## Unreleased +- New rules: + - Azure SQL Database: + - Verify that Azure SQL databases have a customer-controlled maintenance window configured by @BenjaminEngeset. + [#2956](https://github.com/Azure/PSRule.Rules.Azure/issues/2956) + ## v1.38.0 What's changed since v1.37.0: diff --git a/docs/en/rules/Azure.SQL.MaintenanceWindow.md b/docs/en/rules/Azure.SQL.MaintenanceWindow.md new file mode 100644 index 0000000000..b2e898493f --- /dev/null +++ b/docs/en/rules/Azure.SQL.MaintenanceWindow.md @@ -0,0 +1,99 @@ +--- +severity: Important +pillar: Reliability +category: RE:04 Target metrics +resource: Azure Database +online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.SQL.MaintenanceWindow/ +--- + +# Customer-controlled maintenance window configuration + +## SYNOPSIS + +Configure a customer-controlled maintenance window for Azure SQL databases. + +## DESCRIPTION + +Azure SQL databases undergo periodic maintenance to ensure your managed database remains secure, stable, and up-to-date. This maintenance includes applying security updates, system upgrades, and software patches. + +Maintenance windows can be scheduled in two ways for each database: + +- System-Managed Schedule: The system automatically selects a 9-hour maintenance window between 8:00 AM to 5:00 PM local time, Monday - Sunday. + - Urgent updates may occur outside of it. To ensure all updates occur only during the maintenance window, select a non-default option. +- Custom Schedule: You can specify a preferred 8-hour maintenance window by choosing between two non-default maintenance windows: + - Weekday window: 10:00 PM to 6:00 AM local time, Monday - Thursday. + - Weekend window: 10:00 PM to 6:00 AM local time, Friday - Sunday. + +By configuring a customer-controlled maintenance window, you can schedule updates to occur during a preferred time, ideally outside business hours, minimizing disruptions. + +There are limitations to the non-default maintenance windows. You can find more details about this in the documentation. + +## RECOMMENDATION + +Consider using a customer-controlled maintenance window to efficiently schedule updates and minimize disruptions. + +## EXAMPLES + +### Configure with Azure template + +To configure databases that pass this rule: + +- Set the `properties.maintenanceConfigurationId` property to `/subscriptions//providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL__DB_1` or `SQL__DB_2`. + +For example: + +```json +{ + "type": "Microsoft.Sql/servers/databases", + "apiVersion": "2023-05-01-preview", + "name": "[format('{0}/{1}', parameters('serverName'), parameters('sqlDbName'))]", + "location": "westeurope", + "sku": { + "name": "P1", + "tier": "Premium" + }, + "properties": { + "maintenanceConfigurationId": "[subscriptionResourceId('Microsoft.Maintenance/publicMaintenanceConfigurations', 'SQL_WestEurope_DB_1')]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Sql/servers', parameters('serverName'))]" + ] +} +``` + +### Configure with Bicep + +To configure databases that pass this rule: + +- Set the `properties.maintenanceConfigurationId` property to `/subscriptions//providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL__DB_1` or `SQL__DB_2`. + +For example: + +```bicep +resource maintenanceWindow 'Microsoft.Maintenance/publicMaintenanceConfigurations@2023-04-01' existing = { + scope: subscription() + name: 'SQL_WestEurope_DB_1' +} + +resource sqlDb 'Microsoft.Sql/servers/databases@2023-05-01-preview' = { + parent: sqlServer + name: sqlDbName + location: 'westeurope' + sku: { + name: 'P1' + tier: 'Premium' + } + properties: { + maintenanceConfigurationId: maintenanceWindow.id + } +} +``` + +## LINKS + +- [RE:04 Target metrics](https://learn.microsoft.com/azure/well-architected/reliability/metrics) +- [Maintenance window in Azure SQL Database](https://learn.microsoft.com/azure/azure-sql/database/maintenance-window) +- [Configure maintenance window](https://learn.microsoft.com/azure/azure-sql/database/maintenance-window-configure) +- [Azure deployment reference - Maintenance Configuration](https://learn.microsoft.com/azure/templates/microsoft.maintenance/publicmaintenanceconfigurations) +- [Azure deployment reference - Azure SQL Database](https://learn.microsoft.com/azure/templates/microsoft.sql/servers/databases) +- [Azure deployment reference - Elastic Pool](https://learn.microsoft.com/azure/templates/microsoft.sql/servers/elasticpools) diff --git a/src/PSRule.Rules.Azure/en/PSRule-rules.psd1 b/src/PSRule.Rules.Azure/en/PSRule-rules.psd1 index 9ff9d8012d..2fd33f0666 100644 --- a/src/PSRule.Rules.Azure/en/PSRule-rules.psd1 +++ b/src/PSRule.Rules.Azure/en/PSRule-rules.psd1 @@ -110,4 +110,5 @@ ResStorageSensitiveDataThreatDetection = "The storage account '{0}' should have sensitive data threat detection in Microsoft Defender for Storage configured." ResAPIDefender = "The API '{0}' should be onboarded to Microsoft Defender for APIs." InsecureParameterType = "The parameter '{0}' with type '{1}' is not secure." + AzureSQLDatabaseMaintenanceWindow = "The {0} ({1}) should have a customer-controlled maintenance window configured." } diff --git a/src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 b/src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 index 5f78c11b0a..1ae7e1f228 100644 --- a/src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 +++ b/src/PSRule.Rules.Azure/rules/Azure.SQL.Rule.ps1 @@ -11,16 +11,16 @@ Rule 'Azure.SQL.FirewallRuleCount' -Ref 'AZR-000183' -Type 'Microsoft.Sql/servers' -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Security'; } { $firewallRules = @(GetSubResources -ResourceType 'Microsoft.Sql/servers/firewallRules'); $Assert. - LessOrEqual($firewallRules, '.', 10). - WithReason(($LocalizedData.ExceededFirewallRuleCount -f $firewallRules.Length, 10), $True); + LessOrEqual($firewallRules, '.', 10). + WithReason(($LocalizedData.ExceededFirewallRuleCount -f $firewallRules.Length, 10), $True); } # Synopsis: Determine if access from Azure services is required Rule 'Azure.SQL.AllowAzureAccess' -Ref 'AZR-000184' -Type 'Microsoft.Sql/servers' -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Security'; } { $firewallRules = @(GetSubResources -ResourceType 'Microsoft.Sql/servers/firewallRules' | Where-Object { - $_.ResourceName -eq 'AllowAllWindowsAzureIps' -or + $_.ResourceName -eq 'AllowAllWindowsAzureIps' -or ($_.properties.StartIpAddress -eq '0.0.0.0' -and $_.properties.EndIpAddress -eq '0.0.0.0') - }) + }) $firewallRules.Length -eq 0; } @@ -28,8 +28,8 @@ Rule 'Azure.SQL.AllowAzureAccess' -Ref 'AZR-000184' -Type 'Microsoft.Sql/servers Rule 'Azure.SQL.FirewallIPRange' -Ref 'AZR-000185' -Type 'Microsoft.Sql/servers' -Tag @{ release = 'GA'; ruleSet = '2020_06'; 'Azure.WAF/pillar' = 'Security'; } { $summary = GetIPAddressSummary $Assert. - LessOrEqual($summary, 'Public', 10). - WithReason(($LocalizedData.DBServerFirewallPublicIPRange -f $summary.Public, 10), $True); + LessOrEqual($summary, 'Public', 10). + WithReason(($LocalizedData.DBServerFirewallPublicIPRange -f $summary.Public, 10), $True); } # Synopsis: Enable Microsoft Defender for Cloud for Azure SQL logical server @@ -163,6 +163,55 @@ Rule 'Azure.SQL.FGName' -Ref 'AZR-000193' -Type 'Microsoft.Sql/servers/failoverG #endregion Failover group +#region Maintenance window + +# Synopsis: Configure a customer-controlled maintenance window for Azure SQL databases. +Rule 'Azure.SQL.MaintenanceWindow' -Ref 'AZR-000440' -Type 'Microsoft.Sql/servers', 'Microsoft.Sql/servers/databases', 'Microsoft.Sql/servers/elasticPools' -Tag @{ release = 'GA'; ruleSet = '2024_09'; 'Azure.WAF/pillar' = 'Reliability'; } { + $notSupportedSkus = '^(?:GP_Fsv2|HS_DC)_|B|S0|S1' + if ($PSRule.TargetType -eq 'Microsoft.Sql/servers') { + # Microsoft.Sql/servers/elasticPools maintenance configuration is inherited to all databases within the pool, so we only need to check databases that is not in a pool. + $resources = @(GetSubResources -ResourceType 'Microsoft.Sql/servers/databases', 'Microsoft.Sql/servers/elasticPools' | + Where-Object { ($_.sku.name -notmatch $notSupportedSkus) -or (-not $_.properties.psobject.Properties['elasticPoolId']) -or ($_.name -notlike '*/master' -or $_.name -eq 'master') }) + + if ($resources.Count -eq 0) { + return $Assert.Pass() + } + + foreach ($resource in $resources) { + $Assert.Match($resource, 'properties.maintenanceConfigurationId', '\/publicMaintenanceConfigurations\/SQL_[A-Za-z]+[A-Za-z0-9]*_DB_[12]$', $False). + Reason( + $LocalizedData.AzureSQLDatabaseMaintenanceWindow, + $(if ($resource.type -eq 'Microsoft.Sql/servers/databases') { 'database' } else { 'elastic pool' }), + $resource.Name + ).PathPrefix('resources') + } + } + + elseif ($PSRule.TargetType -eq 'Microsoft.Sql/servers/databases') { + if (($TargetObject.sku.name -match $notSupportedSkus) -or $TargetObject.properties.psobject.Properties['elasticPoolId'] -or ($PSRule.TargetName -like '*/master' -or $_.name -eq 'master')) { + return $Assert.Pass() + } + $Assert.Match($TargetObject, 'properties.maintenanceConfigurationId', '\/publicMaintenanceConfigurations\/SQL_[A-Za-z]+[A-Za-z0-9]*_DB_[12]$', $False). + Reason( + $LocalizedData.AzureSQLDatabaseMaintenanceWindow, + 'database', + $TargetObject.Name + ) + } + + # Microsoft.Sql/servers/elasticPools maintenance configuration is inherited to all databases within the pool. + else { + $Assert.Match($TargetObject, 'properties.maintenanceConfigurationId', '\/publicMaintenanceConfigurations\/SQL_[A-Za-z]+[A-Za-z0-9]*_DB_[12]$', $False). + Reason( + $LocalizedData.AzureSQLDatabaseMaintenanceWindow, + 'elastic pool', + $TargetObject.Name + ) + } +} + +#endregion Maintenance window + #region Helper functions function global:IsMasterDatabase { diff --git a/tests/PSRule.Rules.Azure.Tests/Azure.SQL.Tests.ps1 b/tests/PSRule.Rules.Azure.Tests/Azure.SQL.Tests.ps1 index 0ccb809037..127b8a987d 100644 --- a/tests/PSRule.Rules.Azure.Tests/Azure.SQL.Tests.ps1 +++ b/tests/PSRule.Rules.Azure.Tests/Azure.SQL.Tests.ps1 @@ -214,6 +214,32 @@ Describe 'Azure.SQL' -Tag 'SQL', 'SQLDB' { $ruleResult.Length | Should -Be 3; $ruleResult.TargetName | Should -BeIn 'server-B', 'server-D', 'AzureADOnlyAuthentication-B'; } + + It 'Azure.SQL.MaintenanceWindow' { + $filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.SQL.MaintenanceWindow' }; + + # Fail + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' }); + $ruleResult.Length | Should -Be 5; + $ruleResult.TargetName | Should -BeIn 'server-B', 'server-C', 'server-A/database-A', 'server-E/pool-A', 'server-F/pool-A'; + + $ruleResult[0].Reason | Should -BeExactly @( + "The database (database-A) should have a customer-controlled maintenance window configured."; + "The elastic pool (pool-A) should have a customer-controlled maintenance window configured."; + ) + $ruleResult[1].Reason | Should -BeExactly @( + "The database (database-A) should have a customer-controlled maintenance window configured."; + "The elastic pool (pool-A) should have a customer-controlled maintenance window configured."; + ) + $ruleResult[2].Reason | Should -BeExactly "The database (database-A) should have a customer-controlled maintenance window configured."; + $ruleResult[3].Reason | Should -BeExactly "The elastic pool (server-E/pool-A) should have a customer-controlled maintenance window configured."; + $ruleResult[4].Reason | Should -BeExactly "The elastic pool (server-F/pool-A) should have a customer-controlled maintenance window configured."; + + # Pass + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' }); + $ruleResult.Length | Should -Be 5; + $ruleResult.TargetName | Should -BeIn 'server-A', 'server-D', 'server-A/master', 'server-A/database-B', 'server-G/pool-A'; + } } Context 'Resource name - Azure.SQL.ServerName' { diff --git a/tests/PSRule.Rules.Azure.Tests/Resources.SQL.json b/tests/PSRule.Rules.Azure.Tests/Resources.SQL.json index 007d20584d..849e232a9f 100644 --- a/tests/PSRule.Rules.Azure.Tests/Resources.SQL.json +++ b/tests/PSRule.Rules.Azure.Tests/Resources.SQL.json @@ -284,6 +284,60 @@ "Type": "Microsoft.Sql/servers/firewallRules", "ResourceType": "Microsoft.Sql/servers/firewallRules", "SubscriptionId": "00000000-0000-0000-0000-000000000000" + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-B/databases/database-A", + "ResourceName": "database-A", + "Name": "database-A", + "Kind": "v12.0,user", + "Location": "region", + "Properties": { + "edition": "Standard", + "status": "Online", + "serviceLevelObjective": "S2", + "collation": "SQL_Latin1_General_CP1_CI_AS", + "maxSizeBytes": "268435456000", + "requestedServiceObjectiveName": "S2", + "sampleName": null, + "defaultSecondaryLocation": "region-B", + "earliestRestoreDate": "2019-01-01T00:00:00Z", + "elasticPoolName": null, + "containmentState": 2, + "readScale": "Disabled", + "failoverGroupId": null, + "zoneRedundant": false, + "isUpgradeRequested": false + }, + "ResourceGroupName": "test-rg", + "Type": "Microsoft.Sql/servers/databases", + "ResourceType": "Microsoft.Sql/servers/databases", + "SubscriptionId": "00000000-0000-0000-0000-000000000000" + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-B/elasticPools/pool-A", + "ResourceName": "pool-A", + "Name": "pool-A", + "Kind": null, + "Location": "region", + "Tags": null, + "Sku": { + "name": "StandardPool", + "tier": "Standard", + "capacity": 50 + }, + "Properties": { + "maxSizeBytes": 107374182400, + "perDatabaseSettings": { + "minCapacity": 0, + "maxCapacity": 50 + }, + "zoneRedundant": false, + "availabilityZone": "NoPreference" + }, + "ResourceGroupName": "test-rg", + "Type": "Microsoft.Sql/servers/elasticPools", + "ResourceType": "Microsoft.Sql/servers/elasticPools", + "SubscriptionId": "00000000-0000-0000-0000-000000000000" } ] }, @@ -396,6 +450,91 @@ "Type": "Microsoft.Sql/servers/azureADOnlyAuthentications", "ResourceType": "Microsoft.Sql/servers/azureADOnlyAuthentications", "SubscriptionId": "00000000-0000-0000-0000-000000000000" + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-C/databases/database-A", + "ResourceName": "database-A", + "Name": "database-A", + "Kind": "v12.0,user", + "Location": "region", + "Properties": { + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_Default", + "edition": "Standard", + "status": "Online", + "serviceLevelObjective": "S2", + "collation": "SQL_Latin1_General_CP1_CI_AS", + "maxSizeBytes": "268435456000", + "requestedServiceObjectiveName": "S2", + "sampleName": null, + "defaultSecondaryLocation": "region-B", + "earliestRestoreDate": "2019-01-01T00:00:00Z", + "elasticPoolName": null, + "containmentState": 2, + "readScale": "Disabled", + "failoverGroupId": null, + "zoneRedundant": false, + "isUpgradeRequested": false + }, + "ResourceGroupName": "test-rg", + "Type": "Microsoft.Sql/servers/databases", + "ResourceType": "Microsoft.Sql/servers/databases", + "SubscriptionId": "00000000-0000-0000-0000-000000000000" + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-C/databases/database-B", + "ResourceName": "database-B", + "Name": "database-B", + "Kind": "v12.0,user", + "Location": "region", + "Properties": { + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_WestEurope_DB_1", + "edition": "Standard", + "status": "Online", + "serviceLevelObjective": "S2", + "collation": "SQL_Latin1_General_CP1_CI_AS", + "maxSizeBytes": "268435456000", + "requestedServiceObjectiveName": "S2", + "sampleName": null, + "defaultSecondaryLocation": "region-B", + "earliestRestoreDate": "2019-01-01T00:00:00Z", + "elasticPoolName": null, + "containmentState": 2, + "readScale": "Disabled", + "failoverGroupId": null, + "zoneRedundant": false, + "isUpgradeRequested": false + }, + "ResourceGroupName": "test-rg", + "Type": "Microsoft.Sql/servers/databases", + "ResourceType": "Microsoft.Sql/servers/databases", + "SubscriptionId": "00000000-0000-0000-0000-000000000000" + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-C/elasticPools/pool-A", + "ResourceName": "pool-A", + "Name": "pool-A", + "Kind": null, + "Location": "region", + "Tags": null, + "Sku": { + "name": "StandardPool", + "tier": "Standard", + "capacity": 50 + }, + "Properties": { + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_Default", + "maxSizeBytes": 107374182400, + "perDatabaseSettings": { + "minCapacity": 0, + "maxCapacity": 50 + }, + "zoneRedundant": false, + "availabilityZone": "NoPreference" + }, + "ResourceGroupName": "test-rg", + "Type": "Microsoft.Sql/servers/elasticPools", + "ResourceType": "Microsoft.Sql/servers/elasticPools", + "SubscriptionId": "00000000-0000-0000-0000-000000000000" } ] }, @@ -480,6 +619,58 @@ "Type": "Microsoft.Sql/servers/auditingSettings", "ResourceType": "Microsoft.Sql/servers/auditingSettings", "SubscriptionId": "00000000-0000-0000-0000-000000000000" + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-D/databases/database-A", + "ResourceName": "database-A", + "Name": "database-A", + "Kind": "v12.0,user", + "Location": "region", + "Properties": { + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_WestEurope_DB_1", + "edition": "Standard", + "status": "Online", + "serviceLevelObjective": "S2", + "collation": "SQL_Latin1_General_CP1_CI_AS", + "maxSizeBytes": "268435456000", + "requestedServiceObjectiveName": "S2", + "sampleName": null, + "defaultSecondaryLocation": "region-B", + "earliestRestoreDate": "2019-01-01T00:00:00Z", + "elasticPoolName": null, + "containmentState": 2, + "readScale": "Disabled", + "failoverGroupId": null, + "zoneRedundant": false, + "isUpgradeRequested": false + } + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-D/elasticPools/pool-A", + "ResourceName": "pool-A", + "Name": "pool-A", + "Kind": null, + "Location": "region", + "Tags": null, + "Sku": { + "name": "StandardPool", + "tier": "Standard", + "capacity": 50 + }, + "Properties": { + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_WestEurope_DB_2", + "maxSizeBytes": 107374182400, + "perDatabaseSettings": { + "minCapacity": 0, + "maxCapacity": 50 + }, + "zoneRedundant": false, + "availabilityZone": "NoPreference" + }, + "ResourceGroupName": "test-rg", + "Type": "Microsoft.Sql/servers/elasticPools", + "ResourceType": "Microsoft.Sql/servers/elasticPools", + "SubscriptionId": "00000000-0000-0000-0000-000000000000" } ] }, @@ -520,6 +711,7 @@ "Location": "region", "SubscriptionId": "00000000-0000-0000-0000-000000000000", "Properties": { + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_Default", "edition": "Standard", "status": "Online", "serviceLevelObjective": "S2", @@ -547,6 +739,7 @@ "Location": "region", "SubscriptionId": "00000000-0000-0000-0000-000000000000", "Properties": { + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_WestEurope_DB_1", "edition": "Standard", "status": "Online", "serviceLevelObjective": "S2", @@ -620,5 +813,85 @@ "Properties": { "azureADOnlyAuthentication": true } + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-E/elasticPools/pool-A", + "ResourceName": "server-E/pool-A", + "Name": "server-E/pool-A", + "ResourceType": "Microsoft.Sql/servers/elasticPools", + "Type": "Microsoft.Sql/servers/elasticPools", + "Kind": null, + "ResourceGroupName": "test-rg", + "Location": "region", + "SubscriptionId": "00000000-0000-0000-0000-000000000000", + "Tags": null, + "Sku": { + "name": "StandardPool", + "tier": "Standard", + "capacity": 50 + }, + "Properties": { + "maxSizeBytes": 107374182400, + "perDatabaseSettings": { + "minCapacity": 0, + "maxCapacity": 50 + }, + "zoneRedundant": false, + "availabilityZone": "NoPreference" + } + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-F/elasticPools/pool-A", + "ResourceName": "server-F/pool-A", + "Name": "server-F/pool-A", + "ResourceType": "Microsoft.Sql/servers/elasticPools", + "Type": "Microsoft.Sql/servers/elasticPools", + "Kind": null, + "ResourceGroupName": "test-rg", + "Location": "region", + "SubscriptionId": "00000000-0000-0000-0000-000000000000", + "Tags": null, + "Sku": { + "name": "StandardPool", + "tier": "Standard", + "capacity": 50 + }, + "Properties": { + "maxSizeBytes": 107374182400, + "perDatabaseSettings": { + "minCapacity": 0, + "maxCapacity": 50 + }, + "zoneRedundant": false, + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_Default", + "availabilityZone": "NoPreference" + } + }, + { + "ResourceId": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/test-rg/providers/Microsoft.Sql/servers/server-G/elasticPools/pool-A", + "ResourceName": "server-G/pool-A", + "Name": "server-G/pool-A", + "ResourceType": "Microsoft.Sql/servers/elasticPools", + "Type": "Microsoft.Sql/servers/elasticPools", + "Kind": null, + "ResourceGroupName": "test-rg", + "Location": "region", + "SubscriptionId": "00000000-0000-0000-0000-000000000000", + "Tags": null, + "Sku": { + "name": "StandardPool", + "tier": "Standard", + "capacity": 50 + }, + "Properties": { + "maxSizeBytes": 107374182400, + "perDatabaseSettings": { + "minCapacity": 0, + "maxCapacity": 50 + }, + "zoneRedundant": false, + "maintenanceConfigurationId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Maintenance/publicMaintenanceConfigurations/SQL_WestEurope_DB_2", + "availabilityZone": "NoPreference" + } } ]