Search code examples
azureazure-cloud-servicesazure-resource-managerazure-automation

Deploying autoscale settings using ARM template that depend on Cloud Service


I'm using ARM template file to deploy two resources:

  1. An Azure Cloud Service (with 4 roles)
  2. Autoscale settings (that include rules for all 4 roles)

If the Cloud Service exists, and the roles are running, then I have no issue in deploying both in parallel, it works successfully with the following template.

The issue occurs when the cloud service is being deployed for the first time. This is reasonable as the autoscale settings need a targetResourceUri to apply the rules, if that resource does not exist - it is good thing to fail the deployment.

For that, they've invented the dependsOn property, but for some reason I cannot get it to work, the autoscale rules fail to be deployed due the targetResourceUri not exists (the scale rules are being deployed too quickly, before the roles are deployed).

Here's the template:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "serviceName": {
      "type": "string"
    },
    "PackageLink": {
      "type": "string"
    },
    "serviceConfigurationLink": {
      "type": "string"
    },
    "deploymentLabel": {
      "type": "string"
    },
    "autoscaled_resource_name": {
      "defaultValue": "autoscale-rules-default",
      "type": "string"
    },
    "metricResourceUri_cpu": {
      "type": "string"
    },
    "autoscale_resourceUri": {
      "type": "string"
    },
    "autoscale_rules_enabled": {
      "defaultValue": true,
      "type": "bool"
    },
    "min_instance_count": {
      "type": "string"
    },
    "max_instance_count": {
      "type": "string"
    },
    "default_instance_count_when_metric_unavailable": {
      "type": "string"
    }
  },
  "variables": {
    "resourceLocation": "[resourcegroup().location]"
  },
  "resources": [
    {
      "apiVersion": "2016-04-01",
      "type": "Microsoft.ClassicCompute/domainNames",
      "name": "[parameters('serviceName')]",
      "location": "[variables('resourceLocation')]",
      "resources": [
        {
          "apiVersion": "2016-04-01",
          "name": "production",
          "type": "deploymentSlots",
          "dependsOn": [
            "[resourceId('Microsoft.ClassicCompute/domainNames', parameters('serviceName'))]"
          ],
          "properties": {
            "packageLink": {
              "uri": "[parameters('PackageLink')]"
            },
            "deploymentLabel": "[parameters('deploymentLabel')]",
            "ConfigurationLink": {
              "uri": "[parameters('serviceConfigurationLink')]"
            },
            "deploymentOptions": "StartDeployment"
          }
        }
      ]
    },
    {
      "type": "microsoft.insights/autoscalesettings",
      "name": "[parameters('autoscaled_resource_name')]",
      "apiVersion": "2014-04-01",
      "location": "eastus",
      "dependsOn": [
        "[parameters('serviceName')]"
      ],
      "properties": {
        "profiles": [
          {
            "name": "[parameters('autoscaled_resource_name')]",
            "capacity": {
              "minimum": "[parameters('min_instance_count')]",
              "maximum": "[parameters('max_instance_count')]",
              "default": "[parameters('default_instance_count_when_metric_unavailable')]"
            },
            "rules": [
              {
                "metricTrigger": {
                  "metricName": "Percentage CPU",
                  "metricNamespace": "",
                  "metricResourceUri": "[parameters('metricResourceUri_cpu')]",
                  "timeGrain": "PT5M",
                  "statistic": "Average",
                  "timeWindow": "PT5M",
                  "timeAggregation": "Average",
                  "operator": "GreaterThan",
                  "threshold": 85
                },
                "scaleAction": {
                  "direction": "Increase",
                  "type": "PercentChangeCount",
                  "value": "45",
                  "cooldown": "PT10M"
                }
              }
            ]
          }
        ],
        "enabled": "[parameters('autoscale_rules_enabled')]",
        "name": "[parameters('autoscaled_resource_name')]",
        "targetResourceUri": "[parameters('autoscale_resourceUri')]",
        "notifications": [
          {
            "operation": "Scale",
            "email": {
              "sendToSubscriptionAdministrator": true,
              "sendToSubscriptionCoAdministrators": true,
              "customEmails": []
            }
          }
        ]
      }
    }
  ]
}

Here's the powershell log:

VERBOSE: Performing the operation "Creating Deployment" on target "************".
WARNING: The DeploymentDebug setting has been enabled. This can potentially log secrets like passwords used in resource
 property or listKeys operations when you retrieve the deployment operations through
Get-AzureRmResourceGroupDeploymentOperation
VERBOSE: 1:00:25 AM - Template is valid.
VERBOSE: 1:00:28 AM - Create template deployment 'azuredeploy-0615-2200'
VERBOSE: 1:00:28 AM - Checking deployment status in 5 seconds
VERBOSE: 1:00:34 AM - Checking deployment status in 10 seconds
VERBOSE: 1:00:44 AM - Resource Microsoft.ClassicCompute/domainNames/deploymentSlots '************/production'
provisioning status is running
New-AzureRmResourceGroupDeployment : 1:00:44 AM - Resource microsoft.insights/autoscalesettings
'autoscale-rules-default' failed with message '{
  "code": "TargetResourceNotFound",
  "message": "The target resource id '/subscriptions/************/resourceGroups/"************/providers/Microsoft.ClassicCompute/domainNames/"************/slots/Production/roles/WorkerRole' was not found."
}'
At C:\Users\************\Deploy-AzureResourceGroup.ps1:98 char:1
+ New-AzureRmResourceGroupDeployment -Name ((Get-ChildItem $TemplateFil ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [New-AzureRmResourceGroupDeployment], Exception
    + FullyQualifiedErrorId : Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation.NewAzureResourceGroupDep
   loymentCmdlet

VERBOSE: 1:00:44 AM - Resource Microsoft.ClassicCompute/domainNames '************' provisioning status is succeeded
VERBOSE: 1:00:45 AM - Checking deployment status in 15 seconds
VERBOSE: 1:01:00 AM - Checking deployment status in 20 seconds
VERBOSE: 1:01:21 AM - Checking deployment status in 25 seconds
VERBOSE: 1:01:47 AM - Checking deployment status in 30 seconds

It looks like the autoscale rules are being deployed even before there's a confirmation on the successful creation of the cloud service.

Do I have a mistake in my configuration?


Solution

  • The depended resources, in my case autoscalesettings should be depended on the deployment of the cloud service, which is either production or staging - both of them of type: Microsoft.ClassicCompute/domainNames/deploymentSlots.

    The important part is this:

      "dependsOn": [
        "[resourceId('Microsoft.ClassicCompute/domainNames/deploymentSlots', parameters('serviceName'), 'production')]"
      ]
    

    Here's how I've done:

    {
      "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
        "deploymentLabel": {
          "type": "string"
        },
        "serviceName": {
          "type": "string"
        },
        "PackageLink": {
          "type": "securestring"
        },
        "serviceConfigurationLink": {
          "type": "securestring"
        },
        "autoscaled_resource_name": {
          "type": "string"
        },
        "metricResourceUri": {
          "type": "string"
        },
        "autoscale_resourceUri": {
          "type": "string"
        }
      },
      "variables": {
        "resourceLocation": "[resourcegroup().location]"
      },
      "resources": [
        {
          "apiVersion": "2016-04-01",
          "type": "Microsoft.ClassicCompute/domainNames",
          "name": "[parameters('serviceName')]",
          "location": "[variables('resourceLocation')]",
          "resources": [
            {
              "apiVersion": "2016-04-01",
              "name": "production",
              "type": "deploymentSlots",
              "dependsOn": [
                "[resourceId('Microsoft.ClassicCompute/domainNames', parameters('serviceName'))]"
              ],
              "properties": {
                "packageLink": {
                  "uri": "[parameters('PackageLink')]"
                },
                "deploymentLabel": "[parameters('deploymentLabel')]",
                "ConfigurationLink": {
                  "uri": "[parameters('serviceConfigurationLink')]"
                },
                "deploymentOptions": "StartDeployment"
              }
            }
          ]
        },
        {
          "type": "microsoft.insights/autoscalesettings",
          "name": "[parameters('autoscaled_resource_name')]",
          "apiVersion": "2014-04-01",
          "location": "eastus",
          "dependsOn": [
            "[resourceId('Microsoft.ClassicCompute/domainNames/deploymentSlots', parameters('serviceName'), 'production')]"
          ], 
          "properties": {
            "profiles": [],
            "enabled": true,
            "name": "[parameters('autoscaled_resource_name')]",
            "targetResourceUri": "[parameters('autoscale_resourceUri')]"
          }
        }
      ]
    }