{"id":80136,"date":"2018-08-02T19:25:53","date_gmt":"2018-08-02T19:25:53","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=80136"},"modified":"2021-02-23T19:21:15","modified_gmt":"2021-02-23T19:21:15","slug":"azure-devops-show-me-the-json","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/cloud\/azure\/azure-devops-show-me-the-json\/","title":{"rendered":"Azure DevOps: Show Me the JSON!"},"content":{"rendered":"<p>Are you building and deploying Azure ARM resources, click by click, in the portal? If you haven\u2019t learned how to deploy with JSON template files yet, then you should. And I hope that this article will help.<\/p>\n<p>Using JSON documents to define and deploy Azure resources, can save you lots of time by avoiding a step-by-step mouse clicking through a web GUI, waiting for each page to load, so you can define your resources. There are many rinse and repeat steps when building out a network. You can also use these JSON templates to improve consistency of standard naming conventions and adherence to configuration details of commonly used Azure resources, while parameterizing for things that change almost every time, i.e. resource names, IP addresses, usernames, passwords, etc.<\/p>\n<p>In this article, I\u2019ll teach you a little about JSON, then walk you through the process of building a JSON document that will define<\/p>\n<ul>\n<li>a resource group<\/li>\n<li>a virtual network<\/li>\n<li>two subnets<\/li>\n<li>network security groups<\/li>\n<li>a VPN gateway<\/li>\n<li>a VPN connection<\/li>\n<li>a managed disk VM<\/li>\n<li>an unmanaged disk VM<\/li>\n<li>public IP addresses<\/li>\n<\/ul>\n<p>It takes about 30 minutes to execute that whole build out, and 25 minutes of it is just waiting for the VPN gateway to spin up. It builds the two servers in about five minutes!<\/p>\n<p>I like to deploy using the <em>Templates<\/em> blade in Azure, because there are fewer authentication prompts to deal with, and it enables me to test the process for less technical users who would prefer to not look at PowerShell scripts or .NET code. Figure 1 shows the first page of a template.<\/p>\n<p>To get to the Templates blade, click <em>All services<\/em> and search for <em>Templates<\/em>. If you want to add it to your side menu, click the star. Once there, click the <em>Add<\/em> button. Here you can define a template. You can also copy and paste in my final JSON document and try it out. Figure 1 shows a template.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1440\" height=\"412\" class=\"wp-image-80137\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-217.png\" \/><\/p>\n<p class=\"caption\">Figure 1: The template edtior<\/p>\n<p>Once you click <em>Deploy<\/em>, you\u2019ll see a screen where settings can be modified before your resources are created as shown in Figure 2.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"744\" height=\"768\" class=\"wp-image-80138\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-218.png\" \/><\/p>\n<p class=\"caption\">Figure 2: Deploying the Azure template<\/p>\n<p>When you use the portal to define and deploy resources such as VMs, behind the scenes, it is building a JSON document for each that it will process to deploy your defined resources. You can download all of these JSON documents! To see JSON documents for your existing resources, open any resource, then click <em>Automation Script<\/em>. There, you will see a script that defines everything in your subscription as shown in Figure 3.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1497\" height=\"841\" class=\"wp-image-80139\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-219.png\" \/><\/p>\n<p class=\"caption\">Figure 3: The resource automation script<\/p>\n<p>Another option is to define a new resource, then click the <em>Download template and parameters<\/em> link instead of the <em>Create<\/em> button. Figure 4 shows this option.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"901\" height=\"880\" class=\"wp-image-80140\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-220.png\" \/><\/p>\n<p class=\"caption\">Figure 4: Download instead of creating<\/p>\n<p>Downloading the template for resources is a great shortcut for learning how to create new JSON templates for future deployments!<\/p>\n<h2>JSON Basics<\/h2>\n<p>Let\u2019s start by looking at the basics of JSON documents. JSON documents are text documents that convey structured data, such as name-value pairs of strings, integers, and Booleans. The documents are organized into arrays and documents, where documents are also collections of strings, integers, Booleans, and arrays of them, too. Name-value pairs are quoted strings, separated by colons. When defining integers or Booleans only the name needs to be quoted. Arrays are defined with square brackets <strong>[<\/strong> and <strong>]<\/strong>, and the array elements are separated by commas. Data that defines objects is often defined in JSON \u2018documents,\u2019 which are collections of name value pairs of any data type. In JSON, documents are defined with curly brackets <strong>{<\/strong> and <strong>}<\/strong>.<\/p>\n<p>An empty JSON document would contain only <strong>{}<\/strong>. Here is a simple Hello World JSON document that is like a contact card. I\u2019ve demonstrated basic strings and an object. But no arrays, here. There will be plenty of array examples below.<\/p>\n<pre><code>  {\r\n    \"FirstName\": \"Brian\",\r\n    \"LastName\": \"Flynn\",\r\n    \"Status\": \"Hello World!\",\r\n    \"Address\": {\r\n    \"Address\": \"123 My Street\",\r\n    \"City\": \"Boulder\",\r\n    \"State\": \"CO\"\r\n    }\r\n}<\/code><\/pre>\n<h2>Understanding the Azure Deployment Template<\/h2>\n<p>The JSON document for deploying resources in Azure uses all the features of JSON to describe everything needed to create virtual machines and more. It may seem daunting at first, but once you have reusable templates in place, you will save lot of time.<\/p>\n<p>The entire Azure Deployment Template JSON document is wrapped in curly brackets, with a header comprised of two strings that specify the schema and content version.<\/p>\n<p>There are three sections to the Azure deployment template that I will discuss. I\u2019m not going to talk about the outputs section.<\/p>\n<p><strong>Parameters \u2013<\/strong> You don\u2019t have to use this section, at all, but it can be very useful. This section defines parameters which the Azure web portal will prompt users to define when they use this template to deploy resources. If you deploy using PowerShell, a parameters JSON document is used to pass in the parameters, which also must be defined in the deployment script. In the web form, you can define drop down menus, where you wish to limit, and\/or display options.<\/p>\n<p><strong>Variables \u2013<\/strong> You don\u2019t have to use this section, at all, but it can be very useful. This section gives you some ability to build variables that can be used, and re-used, in the resources section. Variables defined above, are also in scope lower in the variables section.<\/p>\n<p><strong>Resources \u2013<\/strong> You must use this section. This is where you define the actual resources.<\/p>\n<pre><code>{\r\n    \"$schema\": \"https:\/\/schema.management.azure.com\/schemas\/2015-01-01\/deploymentTemplate.json#\",\r\n    \"contentVersion\": \"1.0.0.0\",\r\n    \"parameters\": {\r\n\t\t\u2026 DEFINE YOUR PARAMETERS HERE \u2026\r\n    },\r\n    \"variables\": {\r\n\t\t\u2026 DEFINE YOUR VARIABLES HERE \u2026\r\n    },\r\n    \"resources\": [\r\n\t\t\u2026 DEFINE YOUR RESOURCES HERE \u2026\r\n    ],\r\n    \"outputs\": {}\r\n}<\/code><\/pre>\n<p>When you define a parameter, it is accessible in the variables and resources sections. It is useful for retrieving specific string values from the end user, which will then be used in the deployment.<\/p>\n<p>When you define a variable, it is accessible in the variables and resources section. You can store strings, integers, Booleans, documents, and arrays in variables. It is useful for applying formulaic patterns, like naming conventions where a name is based off one or more inputs.<\/p>\n<p>The format for accessing parameters and variables, is as follows\u2026<\/p>\n<p>\u201cMyElementFromAParameter\u201d: \u201c[parameters(\u2018MyParameter\u2019)]\u201d,<\/p>\n<p>\u201cMyElementFromAVariable\u201d: \u201c[variables(\u2018MyVariable\u2019)\u201d<\/p>\n<p>Notice how the resources section is delimited with square brackets (<strong>[])<\/strong> rather than curly braces (<strong>{})<\/strong>. That is because the resources section defines an array of resources. Arrays are delimited with square brackets, while the parameters and variables sections are defined as two documents, delimited by curly braces. And documents can be nested inside other documents, as well as contain arrays.<\/p>\n<p>So, you\u2019ve got it now! Right!? OK, maybe you\u2019d like a few focused examples to look at. Let\u2019s take it from the top, aka the parameters section. Here is an example snippet from the parameters section of my JSON document. It defines an admin name and password as well as the name of the VNET. It defines default values, since I can anticipate some likely values. Tool tips can be specified by setting the metadata description. These tool tips put those little <em>(i)<\/em> icons next to the field names in the Azure portal web form.<\/p>\n<pre><code>\r\n        \"adminUsername\": {\r\n            \"type\": \"string\",\r\n            \"defaultValue\": \"MyAdminUser\",\r\n            \"metadata\": {\r\n                \"description\": \"Default Admin username\"\r\n            }\r\n        },\r\n        \"adminPassword\": {\r\n            \"type\": \"securestring\",\r\n            \"metadata\": {\r\n                \"description\": \"Default Admin password\"\r\n            }\r\n        },\r\n        \"VnetName\": {\r\n            \"type\": \"string\",\r\n            \"defaultValue\": \"AzureVnet\",\r\n            \"metadata\": {\r\n                \"description\": \"Used in name prefixes.\"\r\n            }\r\n        },\r\n        \"VnetAddress\": {\r\n            \"type\": \"string\",\r\n            \"defaultValue\": \"10.0.0.0\/16\"\r\n        }<\/code><\/pre>\n<p>Here is an example snippet from the variables section of my JSON document, and it defines a handful of variables that are used to define the networking. The first variable defined, <strong>virtualNetworkPrefix<\/strong>, is set directly to the value from the parameters section. I\u2019m using a concatenation function to dynamically define the subnet names by appending <strong>_Subnet1<\/strong> and <strong>_Subnet2<\/strong> to the VNET name. To define the NSG rules for subnet 1, I\u2019m defining an array of documents, where each document represents a single NSG rule. Within the document defining the NSG, is a document defining the properties of the NSG.<\/p>\n<pre><code>\r\n        \"virtualNetworkName\": \"[parameters('VnetName')]\",\r\n        \"virtualNetworkPrefix\": \"[parameters('VnetAddress')]\",\r\n        \"subnet1Name\": \"[concat(parameters('VnetName'), '_Subnet1')]\",\r\n        \"subnet1Prefix\": \"[parameters('Subnet1Address')]\",\r\n        \"subnet2Name\": \"[concat(parameters('VnetName'), '_Subnet2')]\",\r\n        \"subnet2Prefix\": \"[parameters('Subnet2Address')]\",\r\n        \"DemoVnetSubnet1NetworkSecurityGroupName\": \"[concat(parameters('VnetName'), '_Subnet1_NSG')]\",\r\n        \"DemoVnetSubnet1NetworkSecurityGroupSecurityRules\": [\r\n            {\r\n                \"name\": \"RDP_Location1\",\r\n                \"properties\": {\r\n                    \"priority\": 1000,\r\n                    \"sourceAddressPrefix\": \"1.2.3.4\/20\",\r\n                    \"protocol\": \"Tcp\",\r\n                    \"destinationPortRange\": \"3389\",\r\n                    \"access\": \"Allow\",\r\n                    \"direction\": \"Inbound\",\r\n                    \"sourcePortRange\": \"*\",\r\n                    \"destinationAddressPrefix\": \"*\"\r\n                }\r\n            },\r\n            {\r\n                \"name\": \"RDP_Location2\",\r\n                \"properties\": {\r\n                    \"priority\": 1001,\r\n                    \"sourceAddressPrefix\": \"5.6.7.8\/32\",\r\n                    \"protocol\": \"Tcp\",\r\n                    \"destinationPortRange\": \"3389\",\r\n                    \"access\": \"Allow\",\r\n                    \"direction\": \"Inbound\",\r\n                    \"sourcePortRange\": \"*\",\r\n                    \"destinationAddressPrefix\": \"*\"\r\n                }\r\n            }\r\n        ]<\/code><\/pre>\n<p>Here are some simple examples of resources, from the resources section of my Azure JSON document, and in it, you can see where I am using the variables function to call for variables defined up above, in the variables section. You can also see how I am setting the location to be the location of the current resource group, in scope, which was set by either a prompt in the PowerShell script that processes the JSON document, or the Azure portal web form. I also want to particularly point out where I set the NSG rules using the variable, <strong>DemoVnetSubnet1NetworkSecurityGroupSecurityRules<\/strong>, I defined above, in the variables section. See how you can pass strings, documents and arrays inside variables?<\/p>\n<pre><code>\r\n        {\r\n            \"type\": \"Microsoft.Storage\/storageAccounts\",\r\n            \"name\": \"[variables('diagStorageAccountName')]\",\r\n            \"apiVersion\": \"2017-06-01\",\r\n            \"location\": \"[resourceGroup().location]\",\r\n            \"sku\": {\r\n                \"name\": \"[variables('diagStorageAccountType')]\"\r\n            },\r\n            \"kind\": \"Storage\",\r\n            \"properties\": {}\r\n        },\r\n        {\r\n            \"type\": \"Microsoft.Storage\/storageAccounts\",\r\n            \"name\": \"[variables('premStorageAccountName')]\",\r\n            \"apiVersion\": \"2017-06-01\",\r\n            \"location\": \"[resourceGroup().location]\",\r\n            \"sku\": {\r\n                \"name\": \"[variables('premStorageAccountType')]\"\r\n            },\r\n            \"kind\": \"Storage\",\r\n            \"properties\": {}\r\n        },\r\n        {\r\n            \"type\": \"Microsoft.Storage\/storageAccounts\",\r\n            \"name\": \"[variables('stdStorageAccountName')]\",\r\n            \"apiVersion\": \"2017-06-01\",\r\n            \"location\": \"[resourceGroup().location]\",\r\n            \"sku\": {\r\n                \"name\": \"[variables('stdStorageAccountType')]\"\r\n            },\r\n            \"kind\": \"Storage\",\r\n            \"properties\": {}\r\n        },\r\n        {\r\n            \"name\": \"[variables('DemoVnetSubnet1NetworkSecurityGroupName')]\",\r\n            \"type\": \"Microsoft.Network\/networkSecurityGroups\",\r\n            \"apiVersion\": \"2016-09-01\",\r\n            \"location\": \"[resourceGroup().location]\",\r\n            \"comments\": \"Network Security Group (NSG) for your network\",\r\n            \"properties\": {\r\n                \"securityRules\": \"[variables('DemoVnetSubnet1NetworkSecurityGroupSecurityRules')]\"\r\n            }\r\n        }<\/code><\/pre>\n<p>So far, this is simple, as long as you have all of the formats to follow. And you can find lots of examples on GitHub, as well as finding your way to the formats, by defining resources via the Azure web portal, then downloading the JSON document, instead of deploying it. Or, by going to look at the JSON for already deployed resources.<\/p>\n<p>The next thing you need to learn, is how to chain resource definitions, by defining which resources depend on the others. Here is a more complicated resource definition which demonstrates defining dependencies. Notice how an element of the resource is named <strong>dependsOn<\/strong>, and how it is an array of resource names, which I am passing in via variables defined in my variables section. The resource I am defining is the VNET, and it depends on two NSGs, so the two NSGs have to be deployed first. By defining the resource with these dependencies, Azure knows how to walk through my document deploying everything in the right order, regardless of what order they are defined in my JSON document.<\/p>\n<pre><code>\r\n        {\r\n            \"type\": \"Microsoft.Network\/virtualNetworks\",\r\n            \"name\": \"[variables('virtualNetworkName')]\",\r\n            \"apiVersion\": \"2017-06-01\",\r\n            \"location\": \"[resourceGroup().location]\",\r\n            \"comments\": \"This will build a Virtual Network.\",\r\n            \"dependsOn\": [\r\n                \"[variables('DemoVnetSubnet1NetworkSecurityGroupName')]\",\r\n                \"[variables('DemoVnetSubnet2NetworkSecurityGroupName')]\"\r\n            ],\r\n            \"properties\": {\r\n                \"addressSpace\": {\r\n                    \"addressPrefixes\": [\r\n                        \"[variables('virtualNetworkPrefix')]\"\r\n                    ]\r\n                },\r\n                \"subnets\": [\r\n                    {\r\n                        \"name\": \"[variables('subnet1Name')]\",\r\n                        \"properties\": {\r\n                            \"addressPrefix\": \"[variables('subnet1Prefix')]\",\r\n                            \"networkSecurityGroup\": {\r\n                                \"id\": \"[resourceId('Microsoft.Network\/networkSecurityGroups', variables('DemoVnetSubnet1NetworkSecurityGroupName'))]\"\r\n                            }\r\n                        }\r\n                    },\r\n                    {\r\n                        \"name\": \"[variables('subnet2Name')]\",\r\n                        \"properties\": {\r\n                            \"addressPrefix\": \"[variables('subnet2Prefix')]\",\r\n                            \"networkSecurityGroup\": {\r\n                                \"id\": \"[resourceId('Microsoft.Network\/networkSecurityGroups', variables('DemoVnetSubnet2NetworkSecurityGroupName'))]\"\r\n                            }\r\n                        }\r\n                    },\r\n                    {\r\n                        \"name\": \"GatewaySubnet\",\r\n                        \"properties\": {\r\n                            \"addressPrefix\": \"[parameters('gatewaySubnetPrefix')]\"\r\n                        }\r\n                    }\r\n                ]\r\n            }\r\n        }<\/code><\/pre>\n<h2>The JSON Document<\/h2>\n<p>To build the final JSON document that you can download at the bottom of the article, I started by building out JSON templates for a small handful of resources, bit by bit, testing a deployment, then deleting the resource group it went into. Then I started adding a few more resources, testing a deployment then deleting the resource group\u2026 Putting dependencies in where needed\u2026 There were several rinse and repeat cycles. Each time, it either successfully deployed, or it didn\u2019t. And when it didn\u2019t, I examined errors, adjusted my JSON, and tried again. Eventually, it all culminated in the document, which you could paste into the template editor in Azure, save, and deploy.<\/p>\n<p>As you read through it, notice how some variables are defined as simple strings, delimited with quotes. Some variables are defined as documents, delimited with curly brackets. And other variables are defined as arrays, delimited with square brackets. Sometimes documents are nested inside of documents, arrays inside of documents, or documents inside of arrays. You may wish to change something that can\u2019t be changed from the template blade web form. You may wish to add another server. To do that, you would need to copy and paste some server resources that are already defined, make any necessary changes like the variable names used in it. Then copy the set of variables for those set of resources, make necessary changes to the variable names and values. Repeat for the parameters section. After a little bit of trial and error, you should be good to go.<\/p>\n<h2>Conclusion<\/h2>\n<p>Hopefully, this write-up gives you a quick boot up on deploying Azure resources with JSON. For anything you do often, this can save you a lot of time. It can also help you maintain standard naming conventions and configuration details. And if you want a document that details what you have defined, it\u2019s a great way to version control your environment. I expect that the cloud is going to bring our infrastructure teams into source control in ways they never thought possible.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Creating resources in Azure, while not difficult, can be time consuming if you use the manual steps. One way to automate the process is by using JSON templates to save time and enforce standards. In this article, Brian Flynn describes how to create JSON templates for deploying a network with virtual machines. &hellip;<\/p>\n","protected":false},"author":320871,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[137091],"tags":[95506],"coauthors":[60978],"class_list":["post-80136","post","type-post","status-publish","format-standard","hentry","category-azure","tag-automate"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/80136","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/320871"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=80136"}],"version-history":[{"count":13,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/80136\/revisions"}],"predecessor-version":[{"id":80234,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/80136\/revisions\/80234"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=80136"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=80136"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=80136"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=80136"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}