Имеется шаблон, создание которого описано в посте Azure: ARM – ручное создание шаблона.
В шаблоне создаётся WebApp со swap-слотом, Storage Account, SQL сервер и две и базы.
Требуется добавить ещё две базы для свап-слота, и установить Slot setting чекбокс для Connection Strings, что бы приложение на PROD использовало свои базы, а STAGE — свои.
Шаблон, получившийся в результате — можно взять тут>>>.
Имеющиеся переменные:
...
"variables": {
"hostingPlanName": "[concat(resourceGroup().name, '-app-plan')]",
"webSiteName": "[concat(resourceGroup().name, '-app')]",
"sqlserverName": "[concat(resourceGroup().name, '-sql-server')]",
"sqlDBbasename": "[concat(resourceGroup().name, '-DB-database')]",
"sqlCMSbasename": "[concat(resourceGroup().name, '-CMS-database')]",
"storageAccountName": "[concat(uniquestring(resourceGroup().id), 'storage')]",
"slotName": "staging"
},
...
Добавляем ещё две для двух баз:
...
"sqlDBbasenameStage": "[concat(resourceGroup().name, '-DB-database', '-stage')]",
"sqlCMSbasenameStage": "[concat(resourceGroup().name, '-CMS-database', '-stage')]",
...
Находим создание ресурса Microsoft.Sql/servers, и в его resources добавляем создание баз:
...
{
"name": "[variables('sqlDBbasenameStage')]",
"type": "databases",
"location": "[resourceGroup().location]",
"tags": {
"Application": "JM Platform swap-slot DB database"
},
"apiVersion": "2014-04-01-preview",
"dependsOn": [
"[variables('sqlserverName')]"
],
"properties": {
"edition": "[parameters('edition')]",
"collation": "[parameters('collation')]",
"maxSizeBytes": "[parameters('maxSizeBytes')]",
"requestedServiceObjectiveName": "[parameters('requestedServiceObjectiveName')]"
}
},
{
"name": "[variables('sqlCMSbasenameStage')]",
"type": "databases",
"location": "[resourceGroup().location]",
"tags": {
"Application": "JM Platform swap-slot CMS database"
},
"apiVersion": "2014-04-01-preview",
"dependsOn": [
"[variables('sqlserverName')]"
],
"properties": {
"edition": "[parameters('edition')]",
"collation": "[parameters('collation')]",
"maxSizeBytes": "[parameters('maxSizeBytes')]",
"requestedServiceObjectiveName": "[parameters('requestedServiceObjectiveName')]"
}
},
...
Переходим к Connection strings для WebApp.
Находим ресурс Microsoft.Web/sites, в resources которого имеется элемент "type": "config", в properties которого указаны Connection strings:
...
"properties": {
"sqlDBConnection": {
"value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlDBbasename'), ';User Id=', parameters('administratorLogin'), '@', variables('sqlserverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
"type": "SQLServer"
},
"sqlCMSConnection": {
"value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlCMSbasename'), ';User Id=', parameters('administratorLogin'), '@', variables('sqlserverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
"type": "SQLServer"
}
}
...
Для того, что бы эти параметры приложения были отмечены как Slot setting — добавляем ещё один ресурс "type": "config" внутри блока resources ресурса "Microsoft.Web/sites", в котором перечисляем строки для Slot setting:
...
{
"apiVersion": "2014-11-01",
"name": "slotconfignames",
"type": "config",
"dependsOn": [
"[variables('webSiteName')]"
],
"properties": {
"connectionStringNames": [ "sqlCMSConnection", "sqlDBConnection" ]
}
},
...
Запускаем создание стека («группы ресурсов», но «стек», по аналогии с AWS CloudFormation — мне нравится больше), и проверяем:
$ azure group create -l westeurope -n jm-platfrom-dev-eu-slot-test-7 -d SlotTesting -f jm-platform-clear-sql.json -e jm-platform-clear-sql.parameters.json ... data: Location: westeurope data: Provisioning State: Succeeded data: Tags: null data: info: group create command OK
Намного интереснее получилось со свап-слотом.
По аналогии с WebApp — для слота "type": "slots" я добавил ресурс "type": "config" со своим блоком properties:
...
{
"apiVersion": "2014-11-01",
"name": "slotconfignames",
"type": "config",
"dependsOn": [
"[variables('webSiteName')]"
],
"properties": {
"connectionStringNames": [ "sqlCMSConnectionStage", "sqlDBConnectionStage" ]
}
}
...
Что привело меня к удивительной ошибке:
$ azure group create -l westeurope -n amids-test-2 -d SlotTesting -f jm-platform-clear-sql.json -e jm-platform-clear-sql.parameters.json info: Executing command group create + Getting resource group amids-test-1 + Creating resource group amids-test-1 info: Created resource group amids-test-1 + Initializing template configurations and parameters + Creating a deployment error: Long running operation failed with error: 'At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.'. info: Error information has been recorded to /home/setevoy/.azure/azure.err error: group create command failed
И сама ошибка:
$ cat /home/setevoy/.azure/azure.err | grep body
{ body: '{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-debug for usage details.","details":[{"code":"NotFound","message":"{\\r\\n \\"error\\": {\\r\\n \\"code\\": \\"BadRequest\\",\\r\\n \\"message\\": \\"\\"\\r\\n }\\r\\n}"}]}}'
Сообщение:
«details»:[{«code»:»NotFound»,»message»:»{\\r\\n \\»error\\»: {\\r\\n \\»code\\»: \\»BadRequest\\»,\\r\\n \\»message\\»: \\»\\»\\r\\n }\\r\\n}»}]}}’
Повергло меня в полное уныние, и я даже добавил его в пост Azure: почему никогда.
Помогла мне (на удивление) тех. поддержка Azure.
Для добавления Slot setting в Deployment slot приложения — в блок "name": "slotconfignames" ресурса "type": "Microsoft.Web/sites" добавляем ещё две базы:
...
{
"apiVersion": "2014-11-01",
"name": "slotconfignames",
"type": "config",
"dependsOn": [
"[variables('webSiteName')]"
],
"properties": {
"connectionStringNames": [ "sqlCMSConnection", "sqlDBConnection","sqlCMSConnectionStage", "sqlDBConnectionStage" ]
}
},
...
А в блок properties слота — два параметра со строками подключения, используя переменные sqlCMSbasenameStage и sqlDBbasenameStage, добавленные ранее:
...
"properties": {
"sqlDBConnectionStage": {
"value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlDBbasenameStage'), ';User Id=', parameters('administratorLogin'), '@', variables('sqlserverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
"type": "SQLAzure"
},
"sqlCMSConnectionStage": {
"value": "[concat('Data Source=tcp:', reference(concat('Microsoft.Sql/servers/', variables('sqlserverName'))).fullyQualifiedDomainName, ',1433;Initial Catalog=', variables('sqlCMSbasenameStage'), ';User Id=', parameters('administratorLogin'), '@', variables('sqlserverName'), ';Password=', parameters('administratorLoginPassword'), ';')]",
"type": "SQLAzure"
}
}
...
Структуру вложенности блоков проще понять со скрина PyCharm:
Запускаем (для дебага — отлично помогает -vv):
$ azure group create -l westeurope -n jm-platfrom-dev-eu-slot-test-41 -d SlotTesting -f jm-platform-clear-sql.json -e jm-platform-clear-sql.parameters.json
Готово.








