Azure: ARM-шаблон – добавить checkbox для Connection strings Slot Setting

Автор: | 09/09/2016
 

azure_logoИмеется шаблон, создание которого описано в посте 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" ]
          }
        },
...

arm_slot_setting_1

Запускаем создание стека (“группы ресурсов”, но “стек”, по аналогии с 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

arm_slot_setting_2

Намного интереснее получилось со свап-слотом.

По аналогии с 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:

arm_slot_setting_4

Запускаем (для дебага – отлично помогает -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

arm_slot_setting_3

Готово.