diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index 214ecce1b7..dc5670500d 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -29,6 +29,7 @@ This module deploys an Azure SQL Server. | `Microsoft.Sql/servers/databases/backupShortTermRetentionPolicies` | [2023-08-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/2023-08-01-preview/servers/databases/backupShortTermRetentionPolicies) | | `Microsoft.Sql/servers/elasticPools` | [2023-08-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/2023-08-01-preview/servers/elasticPools) | | `Microsoft.Sql/servers/encryptionProtector` | [2023-08-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/2023-08-01-preview/servers/encryptionProtector) | +| `Microsoft.Sql/servers/failoverGroups` | [2024-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/2024-05-01-preview/servers/failoverGroups) | | `Microsoft.Sql/servers/firewallRules` | [2023-08-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/2023-08-01-preview/servers/firewallRules) | | `Microsoft.Sql/servers/keys` | [2023-08-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/2023-08-01-preview/servers/keys) | | `Microsoft.Sql/servers/securityAlertPolicies` | [2023-08-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/2023-08-01-preview/servers/securityAlertPolicies) | @@ -47,11 +48,12 @@ The following section provides usage examples for the module, which were used to - [With audit settings](#example-2-with-audit-settings) - [Using only defaults](#example-3-using-only-defaults) - [Using elastic pool](#example-4-using-elastic-pool) -- [Deploying with a key vault reference to save secrets](#example-5-deploying-with-a-key-vault-reference-to-save-secrets) -- [Using large parameter set](#example-6-using-large-parameter-set) -- [With a secondary database](#example-7-with-a-secondary-database) -- [With vulnerability assessment](#example-8-with-vulnerability-assessment) -- [WAF-aligned](#example-9-waf-aligned) +- [Using failover groups](#example-5-using-failover-groups) +- [Deploying with a key vault reference to save secrets](#example-6-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-7-using-large-parameter-set) +- [With a secondary database](#example-8-with-a-secondary-database) +- [With vulnerability assessment](#example-9-with-vulnerability-assessment) +- [WAF-aligned](#example-10-waf-aligned) ### Example 1: _With an administrator_ @@ -446,7 +448,313 @@ param location = ''

-### Example 5: _Deploying with a key vault reference to save secrets_ +### Example 5: _Using failover groups_ + +This instance deploys the module with failover groups. + + +

+ +via Bicep module + +```bicep +module server 'br/public:avm/res/sql/server:' = { + name: 'serverDeployment' + params: { + // Required parameters + name: 'ssfog001' + // Non-required parameters + administratorLogin: 'adminUserName' + administratorLoginPassword: '' + databases: [ + { + maxSizeBytes: 2147483648 + name: 'ssfog-db1' + sku: { + name: 'S1' + tier: 'Standard' + } + zoneRedundant: false + } + { + maxSizeBytes: 2147483648 + name: 'ssfog-db2' + sku: { + capacity: 2 + name: 'GP_Gen5' + tier: 'GeneralPurpose' + } + zoneRedundant: false + } + { + maxSizeBytes: 2147483648 + name: 'ssfog-db3' + sku: { + name: 'S1' + tier: 'Standard' + } + zoneRedundant: false + } + ] + failoverGroups: [ + { + databases: [ + 'ssfog-db1' + ] + name: 'ssfog-fg-geo' + partnerServers: [ + '' + ] + readWriteEndpoint: { + failoverPolicy: 'Manual' + } + secondaryType: 'Geo' + } + { + databases: [ + 'ssfog-db2' + ] + name: 'ssfog-fg-standby' + partnerServers: [ + '' + ] + readWriteEndpoint: { + failoverPolicy: 'Automatic' + failoverWithDataLossGracePeriodMinutes: 60 + } + secondaryType: 'Standby' + } + { + databases: [ + 'ssfog-db3' + ] + name: 'ssfog-fg-readonly' + partnerServers: [ + '' + ] + readOnlyEndpoint: { + failoverPolicy: 'Enabled' + targetServer: '' + } + readWriteEndpoint: { + failoverPolicy: 'Manual' + } + secondaryType: 'Geo' + } + ] + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "ssfog001" + }, + // Non-required parameters + "administratorLogin": { + "value": "adminUserName" + }, + "administratorLoginPassword": { + "value": "" + }, + "databases": { + "value": [ + { + "maxSizeBytes": 2147483648, + "name": "ssfog-db1", + "sku": { + "name": "S1", + "tier": "Standard" + }, + "zoneRedundant": false + }, + { + "maxSizeBytes": 2147483648, + "name": "ssfog-db2", + "sku": { + "capacity": 2, + "name": "GP_Gen5", + "tier": "GeneralPurpose" + }, + "zoneRedundant": false + }, + { + "maxSizeBytes": 2147483648, + "name": "ssfog-db3", + "sku": { + "name": "S1", + "tier": "Standard" + }, + "zoneRedundant": false + } + ] + }, + "failoverGroups": { + "value": [ + { + "databases": [ + "ssfog-db1" + ], + "name": "ssfog-fg-geo", + "partnerServers": [ + "" + ], + "readWriteEndpoint": { + "failoverPolicy": "Manual" + }, + "secondaryType": "Geo" + }, + { + "databases": [ + "ssfog-db2" + ], + "name": "ssfog-fg-standby", + "partnerServers": [ + "" + ], + "readWriteEndpoint": { + "failoverPolicy": "Automatic", + "failoverWithDataLossGracePeriodMinutes": 60 + }, + "secondaryType": "Standby" + }, + { + "databases": [ + "ssfog-db3" + ], + "name": "ssfog-fg-readonly", + "partnerServers": [ + "" + ], + "readOnlyEndpoint": { + "failoverPolicy": "Enabled", + "targetServer": "" + }, + "readWriteEndpoint": { + "failoverPolicy": "Manual" + }, + "secondaryType": "Geo" + } + ] + }, + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/sql/server:' + +// Required parameters +param name = 'ssfog001' +// Non-required parameters +param administratorLogin = 'adminUserName' +param administratorLoginPassword = '' +param databases = [ + { + maxSizeBytes: 2147483648 + name: 'ssfog-db1' + sku: { + name: 'S1' + tier: 'Standard' + } + zoneRedundant: false + } + { + maxSizeBytes: 2147483648 + name: 'ssfog-db2' + sku: { + capacity: 2 + name: 'GP_Gen5' + tier: 'GeneralPurpose' + } + zoneRedundant: false + } + { + maxSizeBytes: 2147483648 + name: 'ssfog-db3' + sku: { + name: 'S1' + tier: 'Standard' + } + zoneRedundant: false + } +] +param failoverGroups = [ + { + databases: [ + 'ssfog-db1' + ] + name: 'ssfog-fg-geo' + partnerServers: [ + '' + ] + readWriteEndpoint: { + failoverPolicy: 'Manual' + } + secondaryType: 'Geo' + } + { + databases: [ + 'ssfog-db2' + ] + name: 'ssfog-fg-standby' + partnerServers: [ + '' + ] + readWriteEndpoint: { + failoverPolicy: 'Automatic' + failoverWithDataLossGracePeriodMinutes: 60 + } + secondaryType: 'Standby' + } + { + databases: [ + 'ssfog-db3' + ] + name: 'ssfog-fg-readonly' + partnerServers: [ + '' + ] + readOnlyEndpoint: { + failoverPolicy: 'Enabled' + targetServer: '' + } + readWriteEndpoint: { + failoverPolicy: 'Manual' + } + secondaryType: 'Geo' + } +] +param location = '' +``` + +
+

+ +### Example 6: _Deploying with a key vault reference to save secrets_ This instance deploys the module saving all its secrets in a key vault. @@ -557,7 +865,7 @@ param secretsExportConfiguration = {

-### Example 6: _Using large parameter set_ +### Example 7: _Using large parameter set_ This instance deploys the module with most of its features enabled. @@ -1097,7 +1405,7 @@ param vulnerabilityAssessmentsObj = {

-### Example 7: _With a secondary database_ +### Example 8: _With a secondary database_ This instance deploys the module with a secondary database. @@ -1229,7 +1537,7 @@ param tags = {

-### Example 8: _With vulnerability assessment_ +### Example 9: _With vulnerability assessment_ This instance deploys the module with a vulnerability assessment. @@ -1412,7 +1720,7 @@ param vulnerabilityAssessmentsObj = {

-### Example 9: _WAF-aligned_ +### Example 10: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1868,6 +2176,7 @@ param vulnerabilityAssessmentsObj = { | [`elasticPools`](#parameter-elasticpools) | array | The Elastic Pools to create in the server. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`encryptionProtectorObj`](#parameter-encryptionprotectorobj) | object | The encryption protection configuration. | +| [`failoverGroups`](#parameter-failovergroups) | array | The failover groups configuration. | | [`federatedClientId`](#parameter-federatedclientid) | string | The Client id used for cross tenant CMK scenario. | | [`firewallRules`](#parameter-firewallrules) | array | The firewall rules to create in the server. | | [`isIPv6Enabled`](#parameter-isipv6enabled) | string | Whether or not to enable IPv6 support for this server. | @@ -3068,6 +3377,140 @@ The encryption protector type. ] ``` +### Parameter: `failoverGroups` + +The failover groups configuration. + +- Required: No +- Type: array +- Default: `[]` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`databases`](#parameter-failovergroupsdatabases) | array | List of databases in the failover group. | +| [`name`](#parameter-failovergroupsname) | string | The name of the failover group. | +| [`partnerServers`](#parameter-failovergroupspartnerservers) | array | List of the partner servers for the failover group. | +| [`readWriteEndpoint`](#parameter-failovergroupsreadwriteendpoint) | object | Read-write endpoint of the failover group instance. | +| [`secondaryType`](#parameter-failovergroupssecondarytype) | string | Databases secondary type on partner server. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`readOnlyEndpoint`](#parameter-failovergroupsreadonlyendpoint) | object | Read-only endpoint of the failover group instance. | + +### Parameter: `failoverGroups.databases` + +List of databases in the failover group. + +- Required: Yes +- Type: array + +### Parameter: `failoverGroups.name` + +The name of the failover group. + +- Required: Yes +- Type: string + +### Parameter: `failoverGroups.partnerServers` + +List of the partner servers for the failover group. + +- Required: Yes +- Type: array + +### Parameter: `failoverGroups.readWriteEndpoint` + +Read-write endpoint of the failover group instance. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`failoverPolicy`](#parameter-failovergroupsreadwriteendpointfailoverpolicy) | string | Failover policy of the read-write endpoint for the failover group. If failoverPolicy is Automatic then failoverWithDataLossGracePeriodMinutes is required. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`failoverWithDataLossGracePeriodMinutes`](#parameter-failovergroupsreadwriteendpointfailoverwithdatalossgraceperiodminutes) | int | Grace period before failover with data loss is attempted for the read-write endpoint. | + +### Parameter: `failoverGroups.readWriteEndpoint.failoverPolicy` + +Failover policy of the read-write endpoint for the failover group. If failoverPolicy is Automatic then failoverWithDataLossGracePeriodMinutes is required. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Automatic' + 'Manual' + ] + ``` + +### Parameter: `failoverGroups.readWriteEndpoint.failoverWithDataLossGracePeriodMinutes` + +Grace period before failover with data loss is attempted for the read-write endpoint. + +- Required: No +- Type: int + +### Parameter: `failoverGroups.secondaryType` + +Databases secondary type on partner server. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Geo' + 'Standby' + ] + ``` + +### Parameter: `failoverGroups.readOnlyEndpoint` + +Read-only endpoint of the failover group instance. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`failoverPolicy`](#parameter-failovergroupsreadonlyendpointfailoverpolicy) | string | Failover policy of the read-only endpoint for the failover group. | +| [`targetServer`](#parameter-failovergroupsreadonlyendpointtargetserver) | string | The target partner server where the read-only endpoint points to. | + +### Parameter: `failoverGroups.readOnlyEndpoint.failoverPolicy` + +Failover policy of the read-only endpoint for the failover group. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `failoverGroups.readOnlyEndpoint.targetServer` + +The target partner server where the read-only endpoint points to. + +- Required: Yes +- Type: string + ### Parameter: `federatedClientId` The Client id used for cross tenant CMK scenario. diff --git a/avm/res/sql/server/audit-settings/main.json b/avm/res/sql/server/audit-settings/main.json index bc4622ef3b..5271c6c6b1 100644 --- a/avm/res/sql/server/audit-settings/main.json +++ b/avm/res/sql/server/audit-settings/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "4626140114742164628" + "version": "0.32.4.45862", + "templateHash": "14061468320361890476" }, "name": "Azure SQL Server Audit Settings", "description": "This module deploys an Azure SQL Server Audit Settings.", @@ -123,10 +123,7 @@ "storageAccountAccessKey": "[if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('isManagedIdentityInUse'))), listKeys(parameters('storageAccountResourceId'), '2019-06-01').keys[0].value, null())]", "storageAccountSubscriptionId": "[if(not(empty(parameters('storageAccountResourceId'))), split(parameters('storageAccountResourceId'), '/')[2], null())]", "storageEndpoint": "[if(not(empty(parameters('storageAccountResourceId'))), format('https://{0}.blob.{1}', last(split(parameters('storageAccountResourceId'), '/')), environment().suffixes.storage), null())]" - }, - "dependsOn": [ - "server" - ] + } }, "storageAccount_sbdc_rbac": { "condition": "[and(parameters('isManagedIdentityInUse'), not(empty(parameters('storageAccountResourceId'))))]", @@ -152,8 +149,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "2903956714854050681" + "version": "0.32.4.45862", + "templateHash": "12732093554587495593" } }, "parameters": { diff --git a/avm/res/sql/server/database/backup-long-term-retention-policy/main.json b/avm/res/sql/server/database/backup-long-term-retention-policy/main.json index 9ca0defd7f..d9e07837fc 100644 --- a/avm/res/sql/server/database/backup-long-term-retention-policy/main.json +++ b/avm/res/sql/server/database/backup-long-term-retention-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "3060709558343951533" + "version": "0.32.4.45862", + "templateHash": "1446282995445489550" }, "name": "SQL Server Database Long Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Long-Term Backup Retention Policy.", @@ -77,10 +77,7 @@ "existing": true, "type": "Microsoft.Sql/servers/databases", "apiVersion": "2023-08-01-preview", - "name": "[format('{0}/{1}', parameters('serverName'), parameters('databaseName'))]", - "dependsOn": [ - "server" - ] + "name": "[format('{0}/{1}', parameters('serverName'), parameters('databaseName'))]" }, "server": { "existing": true, @@ -99,10 +96,7 @@ "weeklyRetention": "[parameters('weeklyRetention')]", "weekOfYear": "[parameters('weekOfYear')]", "yearlyRetention": "[parameters('yearlyRetention')]" - }, - "dependsOn": [ - "server::database" - ] + } } }, "outputs": { diff --git a/avm/res/sql/server/database/backup-short-term-retention-policy/main.json b/avm/res/sql/server/database/backup-short-term-retention-policy/main.json index 9ee0400fe2..f746effa8e 100644 --- a/avm/res/sql/server/database/backup-short-term-retention-policy/main.json +++ b/avm/res/sql/server/database/backup-short-term-retention-policy/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "1465086214783345027" + "version": "0.32.4.45862", + "templateHash": "2726045612900421237" }, "name": "Azure SQL Server Database Short Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Short-Term Backup Retention Policy.", diff --git a/avm/res/sql/server/database/main.json b/avm/res/sql/server/database/main.json index cb0d743aea..65ce61c10c 100644 --- a/avm/res/sql/server/database/main.json +++ b/avm/res/sql/server/database/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "10088627667414343400" + "version": "0.32.4.45862", + "templateHash": "8657415553449823149" }, "name": "SQL Server Database", "description": "This module deploys an Azure SQL Server Database.", @@ -645,10 +645,7 @@ "sourceResourceId": "[parameters('sourceResourceId')]", "useFreeLimit": "[parameters('useFreeLimit')]", "zoneRedundant": "[parameters('zoneRedundant')]" - }, - "dependsOn": [ - "server" - ] + } }, "database_diagnosticSettings": { "copy": { @@ -721,8 +718,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "1465086214783345027" + "version": "0.32.4.45862", + "templateHash": "2726045612900421237" }, "name": "Azure SQL Server Database Short Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Short-Term Backup Retention Policy.", @@ -839,8 +836,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "3060709558343951533" + "version": "0.32.4.45862", + "templateHash": "1446282995445489550" }, "name": "SQL Server Database Long Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Long-Term Backup Retention Policy.", @@ -911,10 +908,7 @@ "existing": true, "type": "Microsoft.Sql/servers/databases", "apiVersion": "2023-08-01-preview", - "name": "[format('{0}/{1}', parameters('serverName'), parameters('databaseName'))]", - "dependsOn": [ - "server" - ] + "name": "[format('{0}/{1}', parameters('serverName'), parameters('databaseName'))]" }, "server": { "existing": true, @@ -933,10 +927,7 @@ "weeklyRetention": "[parameters('weeklyRetention')]", "weekOfYear": "[parameters('weekOfYear')]", "yearlyRetention": "[parameters('yearlyRetention')]" - }, - "dependsOn": [ - "server::database" - ] + } } }, "outputs": { diff --git a/avm/res/sql/server/elastic-pool/main.json b/avm/res/sql/server/elastic-pool/main.json index a18c568bcd..20e9aa6b4b 100644 --- a/avm/res/sql/server/elastic-pool/main.json +++ b/avm/res/sql/server/elastic-pool/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "9050866823207809352" + "version": "0.32.4.45862", + "templateHash": "9155929618024075319" }, "name": "SQL Server Elastic Pool", "description": "This module deploys an Azure SQL Server Elastic Pool.", @@ -251,10 +251,7 @@ "perDatabaseSettings": "[if(not(empty(parameters('perDatabaseSettings'))), createObject('autoPauseDelay', tryGet(parameters('perDatabaseSettings'), 'autoPauseDelay'), 'maxCapacity', json(tryGet(parameters('perDatabaseSettings'), 'maxCapacity')), 'minCapacity', json(tryGet(parameters('perDatabaseSettings'), 'minCapacity'))), null())]", "preferredEnclaveType": "[parameters('preferredEnclaveType')]", "zoneRedundant": "[parameters('zoneRedundant')]" - }, - "dependsOn": [ - "server" - ] + } } }, "outputs": { diff --git a/avm/res/sql/server/encryption-protector/main.json b/avm/res/sql/server/encryption-protector/main.json index b6e43da350..5162817ddd 100644 --- a/avm/res/sql/server/encryption-protector/main.json +++ b/avm/res/sql/server/encryption-protector/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "3436938593239210559" + "version": "0.32.4.45862", + "templateHash": "16275612719201291134" }, "name": "Azure SQL Server Encryption Protector", "description": "This module deploys an Azure SQL Server Encryption Protector.", diff --git a/avm/res/sql/server/failover-group/README.md b/avm/res/sql/server/failover-group/README.md new file mode 100644 index 0000000000..6036d7f355 --- /dev/null +++ b/avm/res/sql/server/failover-group/README.md @@ -0,0 +1,164 @@ +# Azure SQL Server failover group `[Microsoft.Sql/servers/failoverGroups]` + +This module deploys Azure SQL Server failover group. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Sql/servers/failoverGroups` | [2024-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Sql/2024-05-01-preview/servers/failoverGroups) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`databases`](#parameter-databases) | array | List of databases in the failover group. | +| [`name`](#parameter-name) | string | The name of the failover group. | +| [`partnerServers`](#parameter-partnerservers) | array | List of the partner servers for the failover group. | +| [`readWriteEndpoint`](#parameter-readwriteendpoint) | object | Read-write endpoint of the failover group instance. | +| [`secondaryType`](#parameter-secondarytype) | string | Databases secondary type on partner server. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`serverName`](#parameter-servername) | string | The Name of SQL Server. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`readOnlyEndpoint`](#parameter-readonlyendpoint) | object | Read-only endpoint of the failover group instance. | + +### Parameter: `databases` + +List of databases in the failover group. + +- Required: Yes +- Type: array + +### Parameter: `name` + +The name of the failover group. + +- Required: Yes +- Type: string + +### Parameter: `partnerServers` + +List of the partner servers for the failover group. + +- Required: Yes +- Type: array + +### Parameter: `readWriteEndpoint` + +Read-write endpoint of the failover group instance. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`failoverPolicy`](#parameter-readwriteendpointfailoverpolicy) | string | Failover policy of the read-write endpoint for the failover group. If failoverPolicy is Automatic then failoverWithDataLossGracePeriodMinutes is required. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`failoverWithDataLossGracePeriodMinutes`](#parameter-readwriteendpointfailoverwithdatalossgraceperiodminutes) | int | Grace period before failover with data loss is attempted for the read-write endpoint. | + +### Parameter: `readWriteEndpoint.failoverPolicy` + +Failover policy of the read-write endpoint for the failover group. If failoverPolicy is Automatic then failoverWithDataLossGracePeriodMinutes is required. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Automatic' + 'Manual' + ] + ``` + +### Parameter: `readWriteEndpoint.failoverWithDataLossGracePeriodMinutes` + +Grace period before failover with data loss is attempted for the read-write endpoint. + +- Required: No +- Type: int + +### Parameter: `secondaryType` + +Databases secondary type on partner server. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Geo' + 'Standby' + ] + ``` + +### Parameter: `serverName` + +The Name of SQL Server. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `readOnlyEndpoint` + +Read-only endpoint of the failover group instance. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`failoverPolicy`](#parameter-readonlyendpointfailoverpolicy) | string | Failover policy of the read-only endpoint for the failover group. | +| [`targetServer`](#parameter-readonlyendpointtargetserver) | string | The target partner server where the read-only endpoint points to. | + +### Parameter: `readOnlyEndpoint.failoverPolicy` + +Failover policy of the read-only endpoint for the failover group. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `readOnlyEndpoint.targetServer` + +The target partner server where the read-only endpoint points to. + +- Required: Yes +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the deployed failover group. | +| `resourceGroupName` | string | The resource group of the deployed failover group. | +| `resourceId` | string | The resource ID of the deployed failover group. | diff --git a/avm/res/sql/server/failover-group/main.bicep b/avm/res/sql/server/failover-group/main.bicep new file mode 100644 index 0000000000..97f542d580 --- /dev/null +++ b/avm/res/sql/server/failover-group/main.bicep @@ -0,0 +1,83 @@ +metadata name = 'Azure SQL Server failover group' +metadata description = 'This module deploys Azure SQL Server failover group.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the failover group.') +param name string + +@description('Conditional. The Name of SQL Server. Required if the template is used in a standalone deployment.') +param serverName string + +@description('Required. List of databases in the failover group.') +param databases string[] + +@description('Required. List of the partner servers for the failover group.') +param partnerServers string[] + +@description('Optional. Read-only endpoint of the failover group instance.') +param readOnlyEndpoint failoverGroupReadOnlyEndpointType? + +@description('Required. Read-write endpoint of the failover group instance.') +param readWriteEndpoint failoverGroupReadWriteEndpointType + +@description('Required. Databases secondary type on partner server.') +param secondaryType 'Geo' | 'Standby' + +resource server 'Microsoft.Sql/servers@2023-08-01-preview' existing = { + name: serverName +} + +// https://stackoverflow.com/questions/78337117/azure-sql-failover-group-fails-on-second-run +// https://github.com/Azure/bicep-types-az/issues/2153 + +resource failoverGroup 'Microsoft.Sql/servers/failoverGroups@2024-05-01-preview' = { + name: name + parent: server + properties: { + databases: [for db in databases: resourceId('Microsoft.Sql/servers/databases', serverName, db)] + partnerServers: [ + for partnerServer in partnerServers: { + id: resourceId(resourceGroup().name, 'Microsoft.Sql/servers', partnerServer) + } + ] + readOnlyEndpoint: !empty(readOnlyEndpoint) + ? { + failoverPolicy: readOnlyEndpoint!.failoverPolicy + targetServer: resourceId(resourceGroup().name, 'Microsoft.Sql/servers', readOnlyEndpoint!.targetServer) + } + : null + readWriteEndpoint: readWriteEndpoint + secondaryType: secondaryType + } +} + +// =============== // +// Outputs // +// =============== // + +@description('The name of the deployed failover group.') +output name string = failoverGroup.name + +@description('The resource ID of the deployed failover group.') +output resourceId string = failoverGroup.id + +@description('The resource group of the deployed failover group.') +output resourceGroupName string = resourceGroup().name + +@export() +type failoverGroupReadOnlyEndpointType = { + @description('Required. Failover policy of the read-only endpoint for the failover group.') + failoverPolicy: 'Disabled' | 'Enabled' + + @description('Required. The target partner server where the read-only endpoint points to.') + targetServer: string +} + +@export() +type failoverGroupReadWriteEndpointType = { + @description('Required. Failover policy of the read-write endpoint for the failover group. If failoverPolicy is Automatic then failoverWithDataLossGracePeriodMinutes is required.') + failoverPolicy: 'Automatic' | 'Manual' + + @description('Optional. Grace period before failover with data loss is attempted for the read-write endpoint.') + failoverWithDataLossGracePeriodMinutes: int? +} diff --git a/avm/res/sql/server/failover-group/main.json b/avm/res/sql/server/failover-group/main.json new file mode 100644 index 0000000000..5a1646c153 --- /dev/null +++ b/avm/res/sql/server/failover-group/main.json @@ -0,0 +1,176 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9895671062189651492" + }, + "name": "Azure SQL Server failover group", + "description": "This module deploys Azure SQL Server failover group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "failoverGroupReadOnlyEndpointType": { + "type": "object", + "properties": { + "failoverPolicy": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. Failover policy of the read-only endpoint for the failover group." + } + }, + "targetServer": { + "type": "string", + "metadata": { + "description": "Required. The target partner server where the read-only endpoint points to." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "failoverGroupReadWriteEndpointType": { + "type": "object", + "properties": { + "failoverPolicy": { + "type": "string", + "allowedValues": [ + "Automatic", + "Manual" + ], + "metadata": { + "description": "Required. Failover policy of the read-write endpoint for the failover group. If failoverPolicy is Automatic then failoverWithDataLossGracePeriodMinutes is required." + } + }, + "failoverWithDataLossGracePeriodMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Grace period before failover with data loss is attempted for the read-write endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the failover group." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Conditional. The Name of SQL Server. Required if the template is used in a standalone deployment." + } + }, + "databases": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of databases in the failover group." + } + }, + "partnerServers": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of the partner servers for the failover group." + } + }, + "readOnlyEndpoint": { + "$ref": "#/definitions/failoverGroupReadOnlyEndpointType", + "nullable": true, + "metadata": { + "description": "Optional. Read-only endpoint of the failover group instance." + } + }, + "readWriteEndpoint": { + "$ref": "#/definitions/failoverGroupReadWriteEndpointType", + "metadata": { + "description": "Required. Read-write endpoint of the failover group instance." + } + }, + "secondaryType": { + "type": "string", + "allowedValues": [ + "Geo", + "Standby" + ], + "metadata": { + "description": "Required. Databases secondary type on partner server." + } + } + }, + "resources": { + "server": { + "existing": true, + "type": "Microsoft.Sql/servers", + "apiVersion": "2023-08-01-preview", + "name": "[parameters('serverName')]" + }, + "failoverGroup": { + "type": "Microsoft.Sql/servers/failoverGroups", + "apiVersion": "2024-05-01-preview", + "name": "[format('{0}/{1}', parameters('serverName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "databases", + "count": "[length(parameters('databases'))]", + "input": "[resourceId('Microsoft.Sql/servers/databases', parameters('serverName'), parameters('databases')[copyIndex('databases')])]" + }, + { + "name": "partnerServers", + "count": "[length(parameters('partnerServers'))]", + "input": { + "id": "[resourceId(resourceGroup().name, 'Microsoft.Sql/servers', parameters('partnerServers')[copyIndex('partnerServers')])]" + } + } + ], + "readOnlyEndpoint": "[if(not(empty(parameters('readOnlyEndpoint'))), createObject('failoverPolicy', parameters('readOnlyEndpoint').failoverPolicy, 'targetServer', resourceId(resourceGroup().name, 'Microsoft.Sql/servers', parameters('readOnlyEndpoint').targetServer)), null())]", + "readWriteEndpoint": "[parameters('readWriteEndpoint')]", + "secondaryType": "[parameters('secondaryType')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed failover group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed failover group." + }, + "value": "[resourceId('Microsoft.Sql/servers/failoverGroups', parameters('serverName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed failover group." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/sql/server/firewall-rule/main.json b/avm/res/sql/server/firewall-rule/main.json index 4fd36122c5..ada4f1daee 100644 --- a/avm/res/sql/server/firewall-rule/main.json +++ b/avm/res/sql/server/firewall-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "16725482503837347177" + "version": "0.32.4.45862", + "templateHash": "13930335465721760554" }, "name": "Azure SQL Server Firewall Rule", "description": "This module deploys an Azure SQL Server Firewall Rule.", diff --git a/avm/res/sql/server/key/main.json b/avm/res/sql/server/key/main.json index 0d108b281b..ea6b28ab6c 100644 --- a/avm/res/sql/server/key/main.json +++ b/avm/res/sql/server/key/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "16457177770650062823" + "version": "0.32.4.45862", + "templateHash": "9410818536577318640" }, "name": "Azure SQL Server Keys", "description": "This module deploys an Azure SQL Server Key.", @@ -63,10 +63,7 @@ "properties": { "serverKeyType": "[parameters('serverKeyType')]", "uri": "[parameters('uri')]" - }, - "dependsOn": [ - "server" - ] + } } }, "outputs": { diff --git a/avm/res/sql/server/main.bicep b/avm/res/sql/server/main.bicep index 33c61e2822..02e2e18537 100644 --- a/avm/res/sql/server/main.bicep +++ b/avm/res/sql/server/main.bicep @@ -129,6 +129,9 @@ param auditSettings auditSettingsType = {} //Use the defaults from the child mod @description('Optional. Key vault reference and secret settings for the module\'s secrets export.') param secretsExportConfiguration secretsExportConfigurationType? +@description('Optional. The failover groups configuration.') +param failoverGroups failoverGroupType[] = [] + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') @@ -516,6 +519,24 @@ module secretsExport 'modules/keyVaultExport.bicep' = if (secretsExportConfigura } } +module failover_groups 'failover-group/main.bicep' = [ + for (failoverGroup, index) in failoverGroups: { + name: '${uniqueString(deployment().name, location)}-Sql-FailoverGroup-${index}' + params: { + name: failoverGroup.name + serverName: server.name + databases: failoverGroup.databases + partnerServers: failoverGroup.partnerServers + readOnlyEndpoint: failoverGroup.?readOnlyEndpoint + readWriteEndpoint: failoverGroup.readWriteEndpoint + secondaryType: failoverGroup.secondaryType + } + dependsOn: [ + server_databases + ] + } +] + @description('The name of the deployed SQL server.') output name string = server.name @@ -559,6 +580,7 @@ import { diagnosticSettingFullType } from 'br/public:avm/utl/types/avm-common-ty import { elasticPoolPerDatabaseSettingsType, elasticPoolSkuType } from 'elastic-pool/main.bicep' import { databaseSkuType, shortTermBackupRetentionPolicyType, longTermBackupRetentionPolicyType } from 'database/main.bicep' import { recurringScansType } from 'vulnerability-assessment/main.bicep' +import { failoverGroupReadOnlyEndpointType, failoverGroupReadWriteEndpointType } from 'failover-group/main.bicep' @export() type auditSettingsType = { @@ -900,3 +922,24 @@ type securityAlerPolicyType = { @description('Optional. Specifies the blob storage endpoint. This blob storage will hold all Threat Detection audit logs.') storageEndpoint: string? } + +@export() +type failoverGroupType = { + @description('Required. The name of the failover group.') + name: string + + @description('Required. List of databases in the failover group.') + databases: string[] + + @description('Required. List of the partner servers for the failover group.') + partnerServers: string[] + + @description('Optional. Read-only endpoint of the failover group instance.') + readOnlyEndpoint: failoverGroupReadOnlyEndpointType? + + @description('Required. Read-write endpoint of the failover group instance.') + readWriteEndpoint: failoverGroupReadWriteEndpointType + + @description('Required. Databases secondary type on partner server.') + secondaryType: 'Geo' | 'Standby' +} diff --git a/avm/res/sql/server/main.json b/avm/res/sql/server/main.json index e6817c82b9..06d4cc8a3d 100644 --- a/avm/res/sql/server/main.json +++ b/avm/res/sql/server/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "2810003323744846464" + "version": "0.32.4.45862", + "templateHash": "16838754880391375086" }, "name": "Azure SQL Servers", "description": "This module deploys an Azure SQL Server.", @@ -861,6 +861,61 @@ "__bicep_export!": true } }, + "failoverGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the failover group." + } + }, + "databases": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of databases in the failover group." + } + }, + "partnerServers": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of the partner servers for the failover group." + } + }, + "readOnlyEndpoint": { + "$ref": "#/definitions/failoverGroupReadOnlyEndpointType", + "nullable": true, + "metadata": { + "description": "Optional. Read-only endpoint of the failover group instance." + } + }, + "readWriteEndpoint": { + "$ref": "#/definitions/failoverGroupReadWriteEndpointType", + "metadata": { + "description": "Required. Read-write endpoint of the failover group instance." + } + }, + "secondaryType": { + "type": "string", + "allowedValues": [ + "Geo", + "Standby" + ], + "metadata": { + "description": "Required. Databases secondary type on partner server." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, "_1.privateEndpointCustomDnsConfigType": { "type": "object", "properties": { @@ -1255,6 +1310,59 @@ } } }, + "failoverGroupReadOnlyEndpointType": { + "type": "object", + "properties": { + "failoverPolicy": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. Failover policy of the read-only endpoint for the failover group." + } + }, + "targetServer": { + "type": "string", + "metadata": { + "description": "Required. The target partner server where the read-only endpoint points to." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "failover-group/main.bicep" + } + } + }, + "failoverGroupReadWriteEndpointType": { + "type": "object", + "properties": { + "failoverPolicy": { + "type": "string", + "allowedValues": [ + "Automatic", + "Manual" + ], + "metadata": { + "description": "Required. Failover policy of the read-write endpoint for the failover group. If failoverPolicy is Automatic then failoverWithDataLossGracePeriodMinutes is required." + } + }, + "failoverWithDataLossGracePeriodMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Grace period before failover with data loss is attempted for the read-write endpoint." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "failover-group/main.bicep" + } + } + }, "lockType": { "type": "object", "properties": { @@ -1904,6 +2012,16 @@ "metadata": { "description": "Optional. Key vault reference and secret settings for the module's secrets export." } + }, + "failoverGroups": { + "type": "array", + "items": { + "$ref": "#/definitions/failoverGroupType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The failover groups configuration." + } } }, "variables": { @@ -2154,8 +2272,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "10088627667414343400" + "version": "0.32.4.45862", + "templateHash": "8657415553449823149" }, "name": "SQL Server Database", "description": "This module deploys an Azure SQL Server Database.", @@ -2794,10 +2912,7 @@ "sourceResourceId": "[parameters('sourceResourceId')]", "useFreeLimit": "[parameters('useFreeLimit')]", "zoneRedundant": "[parameters('zoneRedundant')]" - }, - "dependsOn": [ - "server" - ] + } }, "database_diagnosticSettings": { "copy": { @@ -2870,8 +2985,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "1465086214783345027" + "version": "0.32.4.45862", + "templateHash": "2726045612900421237" }, "name": "Azure SQL Server Database Short Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Short-Term Backup Retention Policy.", @@ -2988,8 +3103,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "3060709558343951533" + "version": "0.32.4.45862", + "templateHash": "1446282995445489550" }, "name": "SQL Server Database Long Term Backup Retention Policies", "description": "This module deploys an Azure SQL Server Database Long-Term Backup Retention Policy.", @@ -3060,10 +3175,7 @@ "existing": true, "type": "Microsoft.Sql/servers/databases", "apiVersion": "2023-08-01-preview", - "name": "[format('{0}/{1}', parameters('serverName'), parameters('databaseName'))]", - "dependsOn": [ - "server" - ] + "name": "[format('{0}/{1}', parameters('serverName'), parameters('databaseName'))]" }, "server": { "existing": true, @@ -3082,10 +3194,7 @@ "weeklyRetention": "[parameters('weeklyRetention')]", "weekOfYear": "[parameters('weekOfYear')]", "yearlyRetention": "[parameters('yearlyRetention')]" - }, - "dependsOn": [ - "server::database" - ] + } } }, "outputs": { @@ -3222,8 +3331,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "9050866823207809352" + "version": "0.32.4.45862", + "templateHash": "9155929618024075319" }, "name": "SQL Server Elastic Pool", "description": "This module deploys an Azure SQL Server Elastic Pool.", @@ -3468,10 +3577,7 @@ "perDatabaseSettings": "[if(not(empty(parameters('perDatabaseSettings'))), createObject('autoPauseDelay', tryGet(parameters('perDatabaseSettings'), 'autoPauseDelay'), 'maxCapacity', json(tryGet(parameters('perDatabaseSettings'), 'maxCapacity')), 'minCapacity', json(tryGet(parameters('perDatabaseSettings'), 'minCapacity'))), null())]", "preferredEnclaveType": "[parameters('preferredEnclaveType')]", "zoneRedundant": "[parameters('zoneRedundant')]" - }, - "dependsOn": [ - "server" - ] + } } }, "outputs": { @@ -4309,8 +4415,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "16725482503837347177" + "version": "0.32.4.45862", + "templateHash": "13930335465721760554" }, "name": "Azure SQL Server Firewall Rule", "description": "This module deploys an Azure SQL Server Firewall Rule.", @@ -4417,8 +4523,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "11325013625158751172" + "version": "0.32.4.45862", + "templateHash": "8387055438108067427" }, "name": "Azure SQL Server Virtual Network Rules", "description": "This module deploys an Azure SQL Server Virtual Network Rule.", @@ -4540,8 +4646,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "15381579869855736341" + "version": "0.32.4.45862", + "templateHash": "3334922704579421997" }, "name": "Azure SQL Server Security Alert Policies", "description": "This module deploys an Azure SQL Server Security Alert Policy.", @@ -4647,10 +4753,7 @@ "state": "[parameters('state')]", "storageAccountAccessKey": "[parameters('storageAccountAccessKey')]", "storageEndpoint": "[parameters('storageEndpoint')]" - }, - "dependsOn": [ - "server" - ] + } } }, "outputs": { @@ -4719,8 +4822,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "12724764985088418792" + "version": "0.32.4.45862", + "templateHash": "8667024977156507359" }, "name": "Azure SQL Server Vulnerability Assessments", "description": "This module deploys an Azure SQL Server Vulnerability Assessment.", @@ -4819,10 +4922,7 @@ "storageContainerPath": "[format('https://{0}.blob.{1}/vulnerability-assessment/', last(split(parameters('storageAccountResourceId'), '/')), environment().suffixes.storage)]", "storageAccountAccessKey": "[if(parameters('useStorageAccountAccessKey'), listKeys(parameters('storageAccountResourceId'), '2019-06-01').keys[0].value, null())]", "recurringScans": "[parameters('recurringScans')]" - }, - "dependsOn": [ - "server" - ] + } }, "storageAccount_sbdc_rbac": { "condition": "[and(not(parameters('useStorageAccountAccessKey')), parameters('createStorageRoleAssignment'))]", @@ -4850,8 +4950,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "2903956714854050681" + "version": "0.32.4.45862", + "templateHash": "12732093554587495593" } }, "parameters": { @@ -4946,8 +5046,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "16457177770650062823" + "version": "0.32.4.45862", + "templateHash": "9410818536577318640" }, "name": "Azure SQL Server Keys", "description": "This module deploys an Azure SQL Server Key.", @@ -5004,10 +5104,7 @@ "properties": { "serverKeyType": "[parameters('serverKeyType')]", "uri": "[parameters('uri')]" - }, - "dependsOn": [ - "server" - ] + } } }, "outputs": { @@ -5069,8 +5166,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "3436938593239210559" + "version": "0.32.4.45862", + "templateHash": "16275612719201291134" }, "name": "Azure SQL Server Encryption Protector", "description": "This module deploys an Azure SQL Server Encryption Protector.", @@ -5202,8 +5299,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "4626140114742164628" + "version": "0.32.4.45862", + "templateHash": "14061468320361890476" }, "name": "Azure SQL Server Audit Settings", "description": "This module deploys an Azure SQL Server Audit Settings.", @@ -5320,10 +5417,7 @@ "storageAccountAccessKey": "[if(and(not(empty(parameters('storageAccountResourceId'))), not(parameters('isManagedIdentityInUse'))), listKeys(parameters('storageAccountResourceId'), '2019-06-01').keys[0].value, null())]", "storageAccountSubscriptionId": "[if(not(empty(parameters('storageAccountResourceId'))), split(parameters('storageAccountResourceId'), '/')[2], null())]", "storageEndpoint": "[if(not(empty(parameters('storageAccountResourceId'))), format('https://{0}.blob.{1}', last(split(parameters('storageAccountResourceId'), '/')), environment().suffixes.storage), null())]" - }, - "dependsOn": [ - "server" - ] + } }, "storageAccount_sbdc_rbac": { "condition": "[and(parameters('isManagedIdentityInUse'), not(empty(parameters('storageAccountResourceId'))))]", @@ -5349,8 +5443,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "2903956714854050681" + "version": "0.32.4.45862", + "templateHash": "12732093554587495593" } }, "parameters": { @@ -5437,8 +5531,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "17763074267065683265" + "version": "0.32.4.45862", + "templateHash": "13358857530802564116" } }, "definitions": { @@ -5529,10 +5623,7 @@ "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('secretsToSet')[copyIndex()].name)]", "properties": { "value": "[parameters('secretsToSet')[copyIndex()].value]" - }, - "dependsOn": [ - "keyVault" - ] + } } }, "outputs": { @@ -5559,6 +5650,224 @@ "dependsOn": [ "server" ] + }, + "failover_groups": { + "copy": { + "name": "failover_groups", + "count": "[length(parameters('failoverGroups'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Sql-FailoverGroup-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('failoverGroups')[copyIndex()].name]" + }, + "serverName": { + "value": "[parameters('name')]" + }, + "databases": { + "value": "[parameters('failoverGroups')[copyIndex()].databases]" + }, + "partnerServers": { + "value": "[parameters('failoverGroups')[copyIndex()].partnerServers]" + }, + "readOnlyEndpoint": { + "value": "[tryGet(parameters('failoverGroups')[copyIndex()], 'readOnlyEndpoint')]" + }, + "readWriteEndpoint": { + "value": "[parameters('failoverGroups')[copyIndex()].readWriteEndpoint]" + }, + "secondaryType": { + "value": "[parameters('failoverGroups')[copyIndex()].secondaryType]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.32.4.45862", + "templateHash": "9895671062189651492" + }, + "name": "Azure SQL Server failover group", + "description": "This module deploys Azure SQL Server failover group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "failoverGroupReadOnlyEndpointType": { + "type": "object", + "properties": { + "failoverPolicy": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Required. Failover policy of the read-only endpoint for the failover group." + } + }, + "targetServer": { + "type": "string", + "metadata": { + "description": "Required. The target partner server where the read-only endpoint points to." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "failoverGroupReadWriteEndpointType": { + "type": "object", + "properties": { + "failoverPolicy": { + "type": "string", + "allowedValues": [ + "Automatic", + "Manual" + ], + "metadata": { + "description": "Required. Failover policy of the read-write endpoint for the failover group. If failoverPolicy is Automatic then failoverWithDataLossGracePeriodMinutes is required." + } + }, + "failoverWithDataLossGracePeriodMinutes": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Grace period before failover with data loss is attempted for the read-write endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the failover group." + } + }, + "serverName": { + "type": "string", + "metadata": { + "description": "Conditional. The Name of SQL Server. Required if the template is used in a standalone deployment." + } + }, + "databases": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of databases in the failover group." + } + }, + "partnerServers": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. List of the partner servers for the failover group." + } + }, + "readOnlyEndpoint": { + "$ref": "#/definitions/failoverGroupReadOnlyEndpointType", + "nullable": true, + "metadata": { + "description": "Optional. Read-only endpoint of the failover group instance." + } + }, + "readWriteEndpoint": { + "$ref": "#/definitions/failoverGroupReadWriteEndpointType", + "metadata": { + "description": "Required. Read-write endpoint of the failover group instance." + } + }, + "secondaryType": { + "type": "string", + "allowedValues": [ + "Geo", + "Standby" + ], + "metadata": { + "description": "Required. Databases secondary type on partner server." + } + } + }, + "resources": { + "server": { + "existing": true, + "type": "Microsoft.Sql/servers", + "apiVersion": "2023-08-01-preview", + "name": "[parameters('serverName')]" + }, + "failoverGroup": { + "type": "Microsoft.Sql/servers/failoverGroups", + "apiVersion": "2024-05-01-preview", + "name": "[format('{0}/{1}', parameters('serverName'), parameters('name'))]", + "properties": { + "copy": [ + { + "name": "databases", + "count": "[length(parameters('databases'))]", + "input": "[resourceId('Microsoft.Sql/servers/databases', parameters('serverName'), parameters('databases')[copyIndex('databases')])]" + }, + { + "name": "partnerServers", + "count": "[length(parameters('partnerServers'))]", + "input": { + "id": "[resourceId(resourceGroup().name, 'Microsoft.Sql/servers', parameters('partnerServers')[copyIndex('partnerServers')])]" + } + } + ], + "readOnlyEndpoint": "[if(not(empty(parameters('readOnlyEndpoint'))), createObject('failoverPolicy', parameters('readOnlyEndpoint').failoverPolicy, 'targetServer', resourceId(resourceGroup().name, 'Microsoft.Sql/servers', parameters('readOnlyEndpoint').targetServer)), null())]", + "readWriteEndpoint": "[parameters('readWriteEndpoint')]", + "secondaryType": "[parameters('secondaryType')]" + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed failover group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed failover group." + }, + "value": "[resourceId('Microsoft.Sql/servers/failoverGroups', parameters('serverName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed failover group." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "server", + "server_databases" + ] } }, "outputs": { diff --git a/avm/res/sql/server/security-alert-policy/main.json b/avm/res/sql/server/security-alert-policy/main.json index af541d3817..66d411ea9e 100644 --- a/avm/res/sql/server/security-alert-policy/main.json +++ b/avm/res/sql/server/security-alert-policy/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "15381579869855736341" + "version": "0.32.4.45862", + "templateHash": "3334922704579421997" }, "name": "Azure SQL Server Security Alert Policies", "description": "This module deploys an Azure SQL Server Security Alert Policy.", @@ -112,10 +112,7 @@ "state": "[parameters('state')]", "storageAccountAccessKey": "[parameters('storageAccountAccessKey')]", "storageEndpoint": "[parameters('storageEndpoint')]" - }, - "dependsOn": [ - "server" - ] + } } }, "outputs": { diff --git a/avm/res/sql/server/tests/e2e/failover-group/dependencies.bicep b/avm/res/sql/server/tests/e2e/failover-group/dependencies.bicep new file mode 100644 index 0000000000..4e15f23d52 --- /dev/null +++ b/avm/res/sql/server/tests/e2e/failover-group/dependencies.bicep @@ -0,0 +1,21 @@ +@description('Required. The name of the server.') +param serverName string + +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +resource server 'Microsoft.Sql/servers@2021-11-01' = { + name: serverName + location: location + properties: { + administratorLogin: 'adminUserName' + administratorLoginPassword: password + } +} + +@description('The name of the deployed secondary server.') +output secondaryServerName string = server.name diff --git a/avm/res/sql/server/tests/e2e/failover-group/main.test.bicep b/avm/res/sql/server/tests/e2e/failover-group/main.test.bicep new file mode 100644 index 0000000000..d8ff3b2a5f --- /dev/null +++ b/avm/res/sql/server/tests/e2e/failover-group/main.test.bicep @@ -0,0 +1,146 @@ +targetScope = 'subscription' + +metadata name = 'Using failover groups' +metadata description = 'This instance deploys the module with failover groups.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-sql.servers-${serviceShort}-rg' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ssfog' + +@description('Optional. The password to leverage for the login.') +@secure() +param password string = newGuid() + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// Use paired regions +// https://learn.microsoft.com/en-us/azure/reliability/cross-region-replication-azure +var locationPrimary = 'eastasia' +var locationSecondary = 'southeastasia' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: locationPrimary +} + +// Create a secondary server for the failover group +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, locationSecondary)}-nestedDependencies' + params: { + serverName: '${namePrefix}${serviceShort}002' + location: locationSecondary + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, locationPrimary)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: locationPrimary + administratorLogin: 'adminUserName' + administratorLoginPassword: password + databases: [ + { + name: '${namePrefix}-${serviceShort}-db1' + sku: { + name: 'S1' + tier: 'Standard' + } + maxSizeBytes: 2147483648 + zoneRedundant: false + } + { + name: '${namePrefix}-${serviceShort}-db2' + sku: { + name: 'GP_Gen5' + tier: 'GeneralPurpose' + capacity: 2 + } + maxSizeBytes: 2147483648 + // licenseType: 'LicenseIncluded' + zoneRedundant: false + } + { + name: '${namePrefix}-${serviceShort}-db3' + sku: { + name: 'S1' + tier: 'Standard' + } + maxSizeBytes: 2147483648 + zoneRedundant: false + } + ] + failoverGroups: [ + // Geo failover group with read-write endpoint failover + { + name: '${namePrefix}-${serviceShort}-fg-geo' + databases: [ + '${namePrefix}-${serviceShort}-db1' + ] + partnerServers: [ + nestedDependencies.outputs.secondaryServerName + ] + readWriteEndpoint: { + failoverPolicy: 'Manual' + } + secondaryType: 'Geo' + } + // Standby failover group + { + name: '${namePrefix}-${serviceShort}-fg-standby' + databases: [ + '${namePrefix}-${serviceShort}-db2' + ] + partnerServers: [ + nestedDependencies.outputs.secondaryServerName + ] + readWriteEndpoint: { + failoverPolicy: 'Automatic' + failoverWithDataLossGracePeriodMinutes: 60 + } + secondaryType: 'Standby' + } + // Geo failover group with read-write AND read-only endpoint failover policy + { + name: '${namePrefix}-${serviceShort}-fg-readonly' + databases: [ + '${namePrefix}-${serviceShort}-db3' + ] + partnerServers: [ + nestedDependencies.outputs.secondaryServerName + ] + readWriteEndpoint: { + failoverPolicy: 'Manual' + } + readOnlyEndpoint: { + failoverPolicy: 'Enabled' + targetServer: nestedDependencies.outputs.secondaryServerName + } + secondaryType: 'Geo' + } + ] + } + } +] diff --git a/avm/res/sql/server/virtual-network-rule/main.json b/avm/res/sql/server/virtual-network-rule/main.json index aff0572634..52defee7d5 100644 --- a/avm/res/sql/server/virtual-network-rule/main.json +++ b/avm/res/sql/server/virtual-network-rule/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "11325013625158751172" + "version": "0.32.4.45862", + "templateHash": "8387055438108067427" }, "name": "Azure SQL Server Virtual Network Rules", "description": "This module deploys an Azure SQL Server Virtual Network Rule.", diff --git a/avm/res/sql/server/vulnerability-assessment/main.json b/avm/res/sql/server/vulnerability-assessment/main.json index 672112c20b..a7bf960e9b 100644 --- a/avm/res/sql/server/vulnerability-assessment/main.json +++ b/avm/res/sql/server/vulnerability-assessment/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "12724764985088418792" + "version": "0.32.4.45862", + "templateHash": "8667024977156507359" }, "name": "Azure SQL Server Vulnerability Assessments", "description": "This module deploys an Azure SQL Server Vulnerability Assessment.", @@ -105,10 +105,7 @@ "storageContainerPath": "[format('https://{0}.blob.{1}/vulnerability-assessment/', last(split(parameters('storageAccountResourceId'), '/')), environment().suffixes.storage)]", "storageAccountAccessKey": "[if(parameters('useStorageAccountAccessKey'), listKeys(parameters('storageAccountResourceId'), '2019-06-01').keys[0].value, null())]", "recurringScans": "[parameters('recurringScans')]" - }, - "dependsOn": [ - "server" - ] + } }, "storageAccount_sbdc_rbac": { "condition": "[and(not(parameters('useStorageAccountAccessKey')), parameters('createStorageRoleAssignment'))]", @@ -136,8 +133,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.31.92.45157", - "templateHash": "2903956714854050681" + "version": "0.32.4.45862", + "templateHash": "12732093554587495593" } }, "parameters": {