{"id":2130,"date":"2016-10-31T05:00:00","date_gmt":"2016-10-31T05:00:00","guid":{"rendered":"https:\/\/www.microsoft.com\/reallifecode\/index.php\/2016\/10\/31\/automated-azure-template-validations\/"},"modified":"2020-03-15T06:50:43","modified_gmt":"2020-03-15T13:50:43","slug":"automated-azure-template-validations","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ise\/automated-azure-template-validations\/","title":{"rendered":"Automated Azure Template Validations"},"content":{"rendered":"<p>This past year, Azure introduced the concept of \u2018Resource Groups\u2019 and the ability to write <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/resource-group-authoring-templates\/\">templates to deploy resources to Azure<\/a>. This makes it easy to describe your infrastructure as code which you can easily redeploy.<\/p>\n<p>The Azure engineering team maintains an <a href=\"https:\/\/github.com\/Azure\/azure-quickstart-templates\">open source repository of sample templates<\/a> where anyone can contribute a useful template that can be used by anyone to deploy resources to Azure. For example, you can deploy anything from a simple Linux virtual machine to an entire Mesos cluster with Marathon and Swarm and pretty much anything in between. This repository has become the <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/templates\/\">central place for all community-curated templates<\/a> for provisioning Azure resources for a variety of partners such as WordPress, Dokku, Deis, Cloud Foundry and many others.<\/p>\n<h1 id=\"the-problem\">The Problem<\/h2>\n<p>When maintaining an open source repository, it\u2019s important to make clear the expectation of quality and validation in each contribution to that project. Many times that\u2019s done by utilizing continuous integration to validate that contributions work and don\u2019t regress any other part of the project. This method makes projects very contribution-friendly while driving the quality of the project for users.<\/p>\n<p>As the <a href=\"https:\/\/github.com\/azure\/azure-quickstart-templates\">Quickstart Templates<\/a> project has grown, one of the problems encountered is the review process for each new template that enters the repository. Validation of the template wasn\u2019t very streamlined, and there wasn\u2019t any per-merge validation of submitted templates. The people reviewing submissions must manually validate them, which makes it tough to spot pesky bugs in templates before deployment as well as during actual template deployments. This issue led to many template files having errors from JSON syntax validation to problems deploying to Azure Resource Manager (ARM).<\/p>\n<p>What the project needed was a community-friendly way of doing basic validation of a template, as well as deploying the template to Azure to test that it works. This approach provides a guarantee to the community that every submitted and modified template works for users who wish to use them.<\/p>\n<h1 id=\"the-solution\">The Solution<\/h2>\n<p><a href=\"http:\/\/travis-ci.org\">Travis CI<\/a> is one of the most trusted CI-as-a-Service platforms in the industry for open source projects. They provide free compute time for open source projects to run tests for each commit and pull request received on GitHub. Because JSON templates comprise the Quickstart Templates repository, using JavaScript tooling to run tests comes quite natural.<\/p>\n<p>The solution requires templates to be validated end-to-end in an automated way which is public enough for everyone in the community to view. At the same time, the solution cannot expose the credentials of the test account. The Azure Quickstart Templates repository is unique in that nearly all templates are self-contained in their folder, and each should conform to a uniform convention. A typical template folder has the following structure:<\/p>\n<ul>\n<li><strong>azuredeploy.json<\/strong> &#8211; The actual Azure Resource Manager template language file, describing the resources to deploy<\/li>\n<li><strong>azuredeploy.parameters.json<\/strong> &#8211; The placeholder parameters file to use for the deployment<\/li>\n<li><strong>metadata.json<\/strong> &#8211; A metadata file describing the template, the date created and the author information. The Azure template search indexer uses this file.<\/li>\n<li><strong>README.md<\/strong> &#8211; A readme file including information about the template and a \u2018Deploy to Azure\u2019 button for quick point-and-click deployments of a template.<\/li>\n<\/ul>\n<p>With a fully end-to-end validation solution, we quickly spotted many templates with issues ranging from naming conventions to ARM template language errors.<\/p>\n<h3 id=\"architectural-diagram\">Architectural Diagram<\/h3>\n<p>The diagram below outlines the high-level overview of the solution\u2019s architecture. We\u2019ll do a deep dive of each part later but the basic flow is:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2016\/10\/ss4.png\" alt=\"Diagram of solution detailed in the list below, showing how template contributor pulls Quickstart template and validates it using Travis CI and ARM validation server.\" \/><\/p>\n<ol>\n<li>Contributors open <a href=\"https:\/\/help.github.com\/articles\/using-pull-requests\/\">pull requests<\/a> against the <a href=\"https:\/\/github.com\/azure\/azure-quickstart-templates\">Azure\/azure-quickstart-templates<\/a> repository for new template contributions<\/li>\n<li><a href=\"https:\/\/travis-ci.org\/\">Travis CI<\/a> responds to the <a href=\"https:\/\/developer.github.com\/webhooks\/\">GitHub pull request web hook<\/a> and clones the pull request contents.<\/li>\n<li>Travis executes the dynamically generated mocha.js test suite within the repo and deploys in parallel only the modified templates in the pull request.<\/li>\n<li>The <a href=\"https:\/\/github.com\/sedouard\/azure-arm-validator\">ARM validation server<\/a> accepts the requested templates, deploys them to Azure and returns the deployment result back to Travis CI.<\/li>\n<li>Travis receives the test result from the ARM validation server and reports the status back to the GitHub pull request.<\/li>\n<li>The contributor sees the test result on their pull request.<\/li>\n<\/ol>\n<h2 id=\"validations\">Validations<\/h2>\n<h3 id=\"metadata-files\">Metadata Files<\/h3>\n<p>To validate that the <code class=\"highlighter-rouge\">metadata.json<\/code> file conforms to the required schema, we use an awesome Node.js module called <a href=\"https:\/\/npmjs.com\/skeemas\">skeemas<\/a> to describe the required schema and validate the JSON against it:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"lang:default decode:true \">var metadata = tryParse(metadataPath, metadataData);\r\n\r\n  var result = skeemas.validate(metadata, {\r\n    properties: {\r\n      itemDisplayName: {\r\n        type: 'string',\r\n        required: true,\r\n        minLength: 10,\r\n        maxLength: 60\r\n      },\r\n      description: {\r\n        type: 'string',\r\n        required: true,\r\n        minLength: 10,\r\n        maxLength: 1000\r\n      },\r\n      summary: {\r\n        type: 'string',\r\n        required: true,\r\n        minLength: 10,\r\n        maxLength: 200\r\n      },\r\n      githubUsername: {\r\n        type: 'string',\r\n        required: true,\r\n        minLength: 2\r\n      },\r\n      dateUpdated: {\r\n        type: 'string',\r\n        required: true,\r\n        minLength: 10\r\n      }\r\n    },\r\n    additionalProperties: false\r\n  });<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>You can see that the second parameter describes the required schema of the metadata file by specifying the field names and their minimum and maximum lengths, as well as enforcing that no other properties exist. This requirement makes it easy to validate the template without the need to write additional logic.<\/p>\n<h3 id=\"template-files\">Template Files<\/h3>\n<p>Template and parameters files are statically validated using the Azure API, so no real logic was required besides submitting the template and parameters for validation. If static validation passes, then the template is deployed to an ephemeral resource group. The validation passes if the deployment is successful, otherwise it will fail with the Azure Resource Manager error.<\/p>\n<h2 id=\"contributor-friendly-ci\">Contributor-Friendly CI<\/h2>\n<p>If you are familiar with Travis, it allows you to run CI test suites on <a href=\"https:\/\/help.github.com\/articles\/using-pull-requests\/\">GitHub pull requests<\/a> which puts a pass checkmark or fail X mark for the commits in your pull request. This mark allows contributors of new templates to understand if their contribution to the Quickstart Templates repository is formatted correctly.<\/p>\n<p>Since running CI tests on a pull request is essentially the same thing as running arbitrary code from anyone on the internet, Travis doesn\u2019t allow for any <a href=\"http:\/\/docs.travis-ci.com\/user\/environment-variables\/#Encrypted-Variables\"><em>secure<\/em> environment variables<\/a> to be exposed to pull requests. It treats pull requests as untrusted code since anyone can execute a <code class=\"highlighter-rouge\">printenv<\/code> command to reveal your sensitive information to the world.<\/p>\n<p>At the same time, full validation of templates submitted by the community is valuable for ensuring the quality of the sample templates.<\/p>\n<h2 id=\"an-arm-validation-server\">An ARM Validation Server<\/h2>\n<p>To protect our test account credentials, while still allowing for deployment validation, an \u2018<a href=\"https:\/\/github.com\/sedouard\/azure-arm-validator\">ARM Template Server<\/a>\u2019 was built, which essentially is a wrapper around the <a href=\"http:\/\/npmjs.org\/azure-cli\">Azure CLI<\/a> exposing a simple RESTful API to validate and deploy templates without needing credentials. This setup allows us to make subscription management changes while providing limited access to the requesting client. This server is very simple, tiny and uses the <a href=\"http:\/\/expressjs.com\">Express<\/a> web framework for <a href=\"https:\/\/nodejs.org\">Node.js<\/a> deployed using <a href=\"\/developerblog\/2015\/10\/30\/streamlined-dokku-deployment-on-azure\/\">Dokku on Azure<\/a>.<\/p>\n<p>The most important thing about the server is to remove resources as soon as they are provisioned to minimize the load on our subscription, as well as avoid running arbitrary untrusted code within our subscription.<\/p>\n<p>The API has two simple endpoints:<\/p>\n<h3 id=\"post-validate\">POST \/validate<\/h3>\n<p><code class=\"highlighter-rouge\">POST \/validate<\/code> validates the template by using the Azure CLI command <code class=\"highlighter-rouge\">azure group template validate<\/code>. The post body is simple and requires the Azure deployment template as the <code class=\"highlighter-rouge\">template<\/code> value and the <code class=\"highlighter-rouge\">parameters<\/code> file as the parameters.<\/p>\n<div class=\"language-json highlighter-rouge\">\n<pre class=\"lang:default decode:true \">{\r\n  \"template\": \"[azuredeploy.json contents]\",\r\n  \"parameters\" : \"[azuredeploy.parameters.json contents]\"\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<h3 id=\"post-deploy\">POST \/deploy<\/h3>\n<p><code class=\"highlighter-rouge\">POST \/deploy<\/code> deploys the template using long polling. The post body is the same as the <code class=\"highlighter-rouge\">\/validate<\/code> endpoint. The response status is always <code class=\"highlighter-rouge\">HTTP 202 Accepted<\/code> and its body must be inspected to understand the result of the deployment<\/p>\n<p>Sometimes template parameters are required to be unique or have a public key. For the <code class=\"highlighter-rouge\">POST \/deploy<\/code> API, any unique parameters are replaced with a unique value. For example, given the parameters file:<\/p>\n<div class=\"language-json highlighter-rouge\">\n<pre class=\"lang:default decode:true \">{\r\n  \"$schema\": \"http:\/\/schema.management.azure.com\/schemas\/2015-01-01\/deploymentParameters.json#\",\r\n  \"contentVersion\": \"1.0.0.0\",\r\n  \"parameters\": {\r\n    \"newStorageAccountName\": {\r\n      \"value\": \"GEN-UNQIUE-12\"\r\n    },\r\n    \"adminUsername\": {\r\n      \"value\": \"azureuser\"\r\n    },\r\n    \"sshPublicKey\": {\r\n      \"value\": \"SSH-PUB-KEY\"\r\n    },\r\n    \"dnsNameForPublicIP\": {\r\n      \"value\": \"GEN-UNIQUE\"\r\n    },\r\n    \"departmentName\": {\r\n      \"value\": \"myDepartment\"\r\n    },\r\n    \"applicationName\": {\r\n      \"value\": \"myApp\"\r\n    },\r\n    \"createdBy\": {\r\n      \"value\": \"myName\"\r\n    }\r\n  }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>The validation server can be configured to replace any placeholder <code class=\"highlighter-rouge\">GEN-UNIQUE<\/code> or <code class=\"highlighter-rouge\">GEN-UNIQUE-[N]<\/code> value with a unique value. This configuration works for other things, such as the placeholder value <code class=\"highlighter-rouge\">SSH-PUB-KEY<\/code> which the server will replace with an actual SSH public key. You can read the <a href=\"https:\/\/github.com\/azure\/azure-quickstart-templates#parameters-file-placeholders\">latest documentation<\/a> for more details.<\/p>\n<h3 id=\"long-polling\">Long Polling<\/h3>\n<p><a href=\"https:\/\/www.pubnub.com\/blog\/2014-12-01-http-long-polling\/\">Long polling<\/a> is the technique of making an HTTP request from a client to a server that keeps the connection open for an extended time until the client leaves or retrieves posted data. Before the advent of web sockets, this was used to simulate push-like behavior.<\/p>\n<p>The default Azure deployment CLI command holds an HTTP connection open to the resource management API until the deployment is complete, which can take a while. Because of this, when a client sends a template for deployment via <code class=\"highlighter-rouge\">POST \/deploy<\/code>, the server holds open the HTTP connection and sends the headers immediately. What\u2019s not obvious right away is that most cloud services, including Azure, will quietly close your HTTP connection if you don\u2019t transmit anything in a certain amount of time. The validation server gets around this issue by sending non-significant bytes to the client (\u2018 \u2018 characters) until the deployment completes.<\/p>\n<p>When the deployment is complete, although the status code is both HTTP 202 for success or failure, you can differentiate a successful deployment vs. an unsuccessful deployment by examining the response body:<\/p>\n<p>Successful Deployment:<\/p>\n<p><strong>HTTP 202 Accepted:<\/strong><\/p>\n<div class=\"language-json highlighter-rouge\">\n<pre class=\"lang:default decode:true \">{\r\n  \"result\": \"Deployment Successful\"\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>Failed Deployment:<\/p>\n<p><strong>HTTP 202 Accepted<\/strong><\/p>\n<div class=\"language-json highlighter-rouge\">\n<pre class=\"lang:default decode:true \">{\r\n  \"_rgName\": \"[the deployed test resource group name. The group is in the process of deleting by the time this message returns and is not accessible by the client]\",\r\n  \"command\": \"[the azure-cli command]\",\r\n  \"parameters\":\"[the parameters JSON used to deploy the provided template, including any generated values]\"\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<h3 id=\"cleaning-up-deployments\">Cleaning up Deployments<\/h3>\n<p>It\u2019s critical to quickly delete resources provisioned by the test run, especially in the case of untrusted pull requests which can be any arbitrary cloud deployment.<\/p>\n<p>All resource groups are immediately deleted after deployment to combat this risk. Storing each resource group name in a small <a href=\"http:\/\/mongodb.org\">MongoDB<\/a> database for persistence purposes ensures the test subscription always deletes the deployment. In the event of a restart during deployment, any leftover resource groups not removed from the database will be requested to be deleted on startup.<\/p>\n<h3 id=\"deploying-the-server\">Deploying the Server<\/h3>\n<p>We host our server using a <a href=\"http:\/\/progrium.viewdocs.io\/dokku\/\">Dokku<\/a> server on Azure. We won\u2019t go into much details on the specifics, but you can check out our previous post on <a href=\"\/developerblog\/2015\/10\/30\/streamlined-dokku-deployment-on-azure\/\">deploying Dokku apps to Azure<\/a>. Dokku provides us with straightforward nginx web server configuration and Heroku-like deployments, and helps us run multiple instances of the server. It also allows us to update the server without stopping current test runs with <a href=\"http:\/\/dokku.viewdocs.io\/dokku\/checks-examples\/\">zero-downtime deployments<\/a>. In short, Dokku keeps previous versions of the application running until web traffic to that version is complete. During this time new requests are routed to the latest version.<\/p>\n<h2 id=\"dynamically-generating-template-validations\">Dynamically Generating Template Validations<\/h2>\n<p>Although the actual template validations happen on the ARM Validation Server, the <a href=\"http:\/\/mochajs.org\">Mocha.js<\/a> test harness which runs within Travis CI controls the test case generation and execution for each template.<\/p>\n<h3 id=\"the-test-framework\">The Test Framework<\/h3>\n<p>Mocha is a powerful test execution framework for JavaScript tests on the server or browser. The use case for mocha is unique in that we generate a test dynamically based on the number of template directories. A test object in mocha is very straight-forward:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"lang:default decode:true \">{\r\n  args: ['template-directory-name\/azuredeploy.json', 'template-directory-name\/azuredeploy.parameters.json', 'template-directory-name\/metadata.json'],\r\n  expected: true\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>By using Node\u2019s <a href=\"https:\/\/nodejs.org\/api\/fs.html#fs_fs_readdir_path_callback\"><code class=\"highlighter-rouge\">fs.readdir<\/code> API<\/a>, we can obtain the list of directories to test, and generate an array of these test objects. For flexibility, tests won\u2019t be generated for directories with a <code class=\"highlighter-rouge\">.ci_skip<\/code> file placed at its root.<\/p>\n<p>Using the existing Mocha functions <code class=\"highlighter-rouge\">describe<\/code> and <code class=\"highlighter-rouge\">it<\/code>, we can verbosely describe tests which will be used by the test reporter:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"lang:default decode:true \">describe('Template Validation Suite', function() {\r\n\r\n\/** code omitted for brevity **\/\r\n\r\n  tests.forEach(function(test) {\r\n    it(test.args[0] + ' &amp; ' + test.args[1] + ' should be valid', function() {\r\n      \/\/ validate template files are in correct place\r\n      test.args.forEach(function (path) {\r\n        var res = ensureExists.apply(null, [path]);\r\n      });\r\n\r\n      \/\/ validatate metadata.json\r\n      validateMetadata.apply(null, [test.args[2]]);\r\n\r\n      \/\/ template validation\r\n      return validateTemplate.apply(null, test.args)\r\n      .then(function (result) {\r\n        debug('template validation sucessful, deploying template...');\r\n        return deployTemplate.apply(null, test.args);\r\n      })\r\n      .then(function () {\r\n        \/\/ success\r\n        return assert(true);\r\n      })\r\n      .catch(function (err) {\r\n        assert(false, errorString + ' nnServer Error:' + JSON.stringify(err));\r\n      });\r\n    });\r\n  });\r\n});<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<h3 id=\"doing-things-in-parallel\">Doing Things in Parallel<\/h3>\n<p>This kind of testing is extremely IO bound, so running template validations in parallel can save a ton of time. A few things come together nicely here:<\/p>\n<ul>\n<li>Azure Resource Management APIs support simultaneous deployments<\/li>\n<li>Node.js is asynchronous, so our test validation server can handle many parallel test requests at once<\/li>\n<li>Using <a href=\"http:\/\/npmjs.org\/mocha.parallel\">the mocha.parallel extension<\/a>, we can run batches of tests in parallel within Travis<\/li>\n<\/ul>\n<p>Using the <code class=\"highlighter-rouge\">parallel<\/code> function within <code class=\"highlighter-rouge\">mocha.parallel<\/code> we can modify the code snippet from the last section to run in parallel by batching our tests in groups:<\/p>\n<div class=\"language-js highlighter-rouge\">\n<pre class=\"lang:default decode:true \">describe('Template Validation Suite', function() {\r\n  \/** code omitted for brevity **\/\r\n\r\n  \/\/ testGroups is an array of test arrays\r\n  testGroups.forEach(function(tests) {\r\n    tests.forEach(function(test) {\r\n      parallel('Running ' + tests.length + ' Parallel Template Validation(s)...', function () {\r\n        it(test.args[0] + ' &amp; ' + test.args[1] + ' should be valid', function() {\r\n          \/\/ validate template files are in correct place\r\n          test.args.forEach(function (path) {\r\n          var res = ensureExists.apply(null, [path]);\r\n          });\r\n\r\n          validateMetadata.apply(null, [test.args[2]]);\r\n\r\n          return validateTemplate.apply(null, test.args)\r\n          .then(function (result) {\r\n          debug('template validation sucessful, deploying template...');\r\n          return deployTemplate.apply(null, test.args);\r\n          })\r\n          .then(function () {\r\n          \/\/ success\r\n          return assert(true);\r\n          })\r\n          .catch(function (err) {\r\n          assert(false, errorString + ' nnServer Error:' + JSON.stringify(err));\r\n          });\r\n        });\r\n      });\r\n    });\r\n  });\r\n});<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>You can batch tests by a configurable amount which can control the test run from violating <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/azure-subscription-service-limits\/\">subscription limitations<\/a> by capping the number of parallel deployments.<\/p>\n<p>Test output looks like below (some stack traces omitted for brevity):<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"lang:default highlight:0 decode:true \">Running 3 Parallel Template Validation(s)...\r\n...\r\n      \u2713 101-simple-linux-vm\/azuredeploy.json &amp; 101-simple-linux-vm\/azuredeploy.parameters.json should be valid (153820ms)\r\n      1) 101-tags-vm\/azuredeploy.json &amp; 101-tags-vm\/azuredeploy.parameters.json should be valid\r\n      2) 101-webapp-with-golang\/azuredeploy.json &amp; 101-webapp-with-golang\/azuredeploy.parameters.json should be valid\r\n\r\n\r\n  1 passing (3m)\r\n  2 failing\r\n\r\n  1) Template Validation Suite Running 3 Parallel Template Validation(s)... 101-tags-vm\/azuredeploy.json &amp; 101-tags-vm\/azuredeploy.parameters.json should be valid:\r\n\r\n      AssertionError: Template Validiation Failed. Try deploying your template with the commands:\r\nazure group template validate --resource-group (your_group_name)  --template-file 101-tags-vm\/azuredeploy.json --parameters-file 101-tags-vm\/azuredeploy.parameters.json\r\nazure group deployment create --resource-group (your_group_name)  --template-file 101-tags-vm\/azuredeploy.json --parameters-file 101-tags-vm\/azuredeploy.parameters.json\r\n\r\nServer Error:{\"error\":\"Deployment provisioning state was not successfuln\",\"_rgName\":\"sedouard-ci4a407279-5a6b-3b78-7670-947cd5dd7bcf\",\"command\":\"azure group deployment create --resource-group (your_group_name) --template-file azuredeploy.json --parameters-file azuredeploy.parameters.json\",\"parameters\":\"{\"$schema\":\"http:\/\/schema.management.azure.com\/schemas\/2015-01-01\/deploymentParameters.json#\",\"contentVersion\":\"1.0.0.0\",\"parameters\":{\"newStorageAccountName\":{\"value\":\"@invalid-account-name\"},\"adminUsername\":{\"value\":\"okdude\"},\"adminPassword\":{\"value\":\"Cortama131\"},\"dnsNameForPublicIP\":{\"value\":\"citest25c541ad90ba1dfd\"},\"departmentName\":{\"value\":\"myDepartment\"},\"applicationName\":{\"value\":\"myApp\"},\"createdBy\":{\"value\":\"myName\"}}}\"}\r\n      + expected - actual\r\n\r\n      -false\r\n      +true\r\n\r\n      at test\/tests.js:288:13\r\n  2) Template Validation Suite Running 3 Parallel Template Validation(s)... 101-webapp-with-golang\/azuredeploy.json &amp; 101-webapp-with-golang\/azuredeploy.parameters.json should be valid:\r\n\r\n      AssertionError: Template Validation Failed. Try deploying your template with the commands:\r\nazure group template validate --resource-group (your_group_name)  --template-file 101-webapp-with-golang\/azuredeploy.json --parameters-file 101-webapp-with-golang\/azuredeploy.parameters.json\r\nazure group deployment create --resource-group (your_group_name)  --template-file 101-webapp-with-golang\/azuredeploy.json --parameters-file 101-webapp-with-golang\/azuredeploy.parameters.json\r\n\r\nServer Error:{\"error\":\"Deployment provisioning state was not successfuln\",\"_rgName\":\"sedouard-ci6df55539-52be-9916-e237-67bf0c4eba0f\",\"command\":\"azure group deployment create --resource-group (your_group_name) --template-file azuredeploy.json --parameters-file azuredeploy.parameters.json\",\"parameters\":\"{\"$schema\":\"http:\/\/schema.management.azure.com\/schemas\/2015-01-01\/deploymentParameters.json\",\"contentVersion\":\"1.0.0.0\",\"parameters\":{\"siteName\":{\"value\":\"$!@!@#D\"},\"appServicePlanName\":{\"value\":\"demoHostingPlan\"},\"siteLocation\":{\"value\":\"West U\"},\"sku\":{\"value\":\"Free\"},\"workerSize\":{\"value\":\"0\"},\"use32bitWorkerProcess\":{\"value\":true},\"enableAlwaysOn\":{\"value\":false}}}\"}\r\n      + expected - actual\r\n\r\n      -false\r\n      +true\r\n\r\n      at test\/tests.js:288:13<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>The log above explains that 1 template validation passed and 2 failed. For each failure, you get a generated command line to re-run the deployment. You can take a look at a real run <a href=\"https:\/\/travis-ci.org\/Azure\/azure-quickstart-templates\/builds\/97762489\">on Travis CI here<\/a>.<\/p>\n<h2 id=\"testing-changes-only\">Testing Changes Only<\/h2>\n<p>If you take a look at the Quickstart Templates, there are heaps of templates and running each template validation for every single commit doesn\u2019t make much sense.<\/p>\n<p>Travis CI makes available to us the commit range which is exposed via an environment variable, <code class=\"highlighter-rouge\">TRAVIS_COMMIT_RANGE<\/code>. Its value looks something like:<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"lang:default decode:true \">TRAVIS_COMMIT_RANGE=[Last Commit Hash]...[First Commit Hash]<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>The <code class=\"highlighter-rouge\">Last Commit Hash<\/code> value is the hash of the last commit on the branch that you are testing. The <code class=\"highlighter-rouge\">First Commit Hash<\/code> value is the hash of the first commit representing the point the <code class=\"highlighter-rouge\">HEAD<\/code> and <code class=\"highlighter-rouge\">BASE<\/code> branch diverged.<\/p>\n<p>By executing a <a href=\"https:\/\/git-scm.com\/docs\/git-diff\"><code class=\"highlighter-rouge\">git diff \u2013name-only<\/code><\/a> command using <code class=\"highlighter-rouge\">First Commit Hash\u2026Last Commit Hash<\/code> we can precisely calculate the changes in the pull request.<\/p>\n<div class=\"highlighter-rouge\">\n<pre class=\"lang:default decode:true \">git diff --name-only 8965c253425198806c9cfd7f5abd10ced263dcbb\u20261f39d53c1b73959e73233fc2b9e5286be952cf83\r\n\r\n  modified:   101-simple-linux-vm\/azuredeploy.json\r\n  modified:   101-tags-vm\/azuredeploy.parameters.json\r\n  modified:   101-webapp-with-golang\/azuredeploy.parameters.json\r\n  modified:   test\/tests.js<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>Using this information, by matching directory names, like those shown above, we can generate tests only for templates that have changed. This method is necessary because of the vast number of templates and how forcing compliance of all templates at once is not reasonable.<\/p>\n<p>By only testing changes to the repository, we decrease workflow time tremendously since contributors only have to be concerned about their own templates passing validation. At the same time, maintainers can run a test on the entire repository by changing an environment variable.<\/p>\n<h1 id=\"how-to-submit-your-own-azure-template\">How to Submit Your Own Azure Template<\/h2>\n<h2 id=\"ensuring-your-template-compliance\">Ensuring Your Template Compliance<\/h2>\n<p>Once you\u2019re done creating your template, ensure:<\/p>\n<ul>\n<li>Your template deploys via PowerShell, <a href=\"http:\/\/npmjs.org\/azure-cli\">Azure CLI<\/a> or the <a href=\"https:\/\/portal.azure.com\">Azure portal<\/a><\/li>\n<li>Any unique parameters in your <code class=\"highlighter-rouge\">azuredeploy.parameters.json<\/code> file such as domain names or storage account names have the placeholder <code class=\"highlighter-rouge\">GEN-UNIQUE<\/code> or <code class=\"highlighter-rouge\">GEN-UNIQUE-[N]<\/code> where <code class=\"highlighter-rouge\">[N]<\/code> is the length of the unique parameter.<\/li>\n<li>Any public SSH key parameter in your <code class=\"highlighter-rouge\">azuredeploy.parameters.json<\/code> file has <code class=\"highlighter-rouge\">SSH-PUB-KEY<\/code> as the place-holder value<\/li>\n<li>Read the <a href=\"https:\/\/github.com\/Azure\/azure-quickstart-templates\/blob\/master\/1-CONTRIBUTION-GUIDE\/README.md#contribution-guide\">contribution guide<\/a> to make sure you comply with template folder naming conventions, and also follow the <a href=\"https:\/\/guides.github.com\/introduction\/flow\/\">GitHub workflow<\/a><\/li>\n<\/ul>\n<h2 id=\"checking-your-template-validation\">Checking Your Template Validation<\/h2>\n<p>When you create a new pull request to the Quickstart Templates repository, you\u2019ll notice a box toward the bottom of the feed indicating your test run is progress:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2016\/10\/ss1.png\" alt=\"GitHub in-progress dialog showing some checks haven't completed yet, with a check mark indicating the branch is up to date with the base branch\" \/><\/p>\n<p>Click the \u2018Details\u2019 link, and you can see the tests run live, which will show you the actual error log output.<\/p>\n<p>After some time (depending on how many templates you\u2019ve submitted) you\u2019ll either see a pass or fail message.<\/p>\n<p>Pass:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2016\/10\/ss2.png\" alt=\"Test pass dialog showing all checks have passed and the Travis CI build passed\" \/><\/p>\n<p>Fail:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/cse\/wp-content\/uploads\/sites\/55\/2016\/10\/ss3.png\" alt=\"Test fail dialog showing all checks have failed and the Travis CI build failed\" \/><\/p>\n<p>In the case your test fails and you aren\u2019t exactly sure why, you can checkout the parameters used by the test in the error output. The tests use the cross-platform <a href=\"https:\/\/npmjs.org\/azure-cli\">azure-cli<\/a> and, as the test output suggests, you can do the template validation yourself by executing:<\/p>\n<div class=\"language-bash highlighter-rouge\">\n<pre class=\"lang:default decode:true \">azure group create (your_group_name) westus\r\n\r\n### Validate your template\r\nazure group template validate --resource-group (your_group_name)  --template-file 201-1-vm-loadbalancer-2-nics\/azuredeploy.json --parameters-file 201-1-vm-loadbalancer-2-nics\/azuredeploy.parameters.json\r\n\r\n### Deploy your template\r\nazure group deployment create --resource-group (your_group_name)  --template-file 201-1-vm-loadbalancer-2-nics\/azuredeploy.json --parameters-file 201-1-vm-loadbalancer-2-nics\/azuredeploy.parameters.json<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<p>You can then check the Azure portal for the deployment error diagnostics. After your template passes validation, maintainers will see this on your pull request and be able to merge your template pending a code review.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>An in-depth look at how we validate Azure deployment templates for our community repository.<\/p>\n","protected":false},"author":21345,"featured_media":11086,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[10,16],"tags":[60,91,302,362],"class_list":["post-2130","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure-app-services","category-devops","tag-azure","tag-azure-resource-manager-arm","tag-quickstart-templates","tag-travis-ci"],"acf":[],"blog_post_summary":"<p>An in-depth look at how we validate Azure deployment templates for our community repository.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2130","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/users\/21345"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/comments?post=2130"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/posts\/2130\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media\/11086"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/media?parent=2130"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/categories?post=2130"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ise\/wp-json\/wp\/v2\/tags?post=2130"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}