├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cleanup.js ├── index.js ├── package.json └── templates └── template.json /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | obj/ 3 | .ntvs_analysis.* 4 | node_modules -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Azure samples 2 | 3 | Thank you for your interest in contributing to Azure samples! 4 | 5 | ## Ways to contribute 6 | 7 | You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways: 8 | 9 | - Submit feedback on [this sample page](https://azure.microsoft.com/documentation/samples/resource-manager-node-template-deployment/) whether it was helpful or not. 10 | - Submit issues through [issue tracker](https://github.com/Azure-Samples/resource-manager-node-template-deployment/issues) on GitHub. We are actively monitoring the issues and improving our samples. 11 | - If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | languages: 4 | - javascript 5 | products: 6 | - azure 7 | description: "This sample explains how to use Azure Resource Manager templates to deploy your resources to Azure 8 | using the Azure SDK for Node.js." 9 | urlFragment: resource-manager-node-template-deployment 10 | --- 11 | 12 | # Deploy an SSH Enabled VM with a Template in Node.js 13 | 14 | This sample explains how to use Azure Resource Manager templates to deploy your resources to Azure 15 | using the Azure SDK for Node.js. 16 | 17 | When deploying an application definition with a template, you can provide parameter values to customize how the 18 | resources are created. You specify values for these parameters either inline or in a parameter file. 19 | 20 | ** On this page** 21 | 22 | - [Running this sample](#run) 23 | - [What is index.js doing?](#example) 24 | - [Deploy the template](#deploy) 25 | 26 | 27 | ## Running this sample 28 | 29 | 1. If you don't already have it, [get node.js](https://nodejs.org). 30 | 31 | 2. Clone the repository. 32 | 33 | ``` 34 | git clone git@github.com:Azure-Samples/resource-manager-node-template-deployment.git 35 | ``` 36 | 37 | 3. Install the dependencies. 38 | 39 | ``` 40 | cd resource-manager-node-template-deployment 41 | npm install 42 | ``` 43 | 44 | 4. Create an Azure service principal either through 45 | [Azure CLI](https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal-cli/), 46 | [PowerShell](https://azure.microsoft.com/documentation/articles/resource-group-authenticate-service-principal/) 47 | or [the portal](https://azure.microsoft.com/documentation/articles/resource-group-create-service-principal-portal/). 48 | 49 | 5. Set the following environment variables using the information from the service principle that you created. 50 | 51 | ``` 52 | export AZURE_SUBSCRIPTION_ID={your subscription id} 53 | export CLIENT_ID={your client id} 54 | export APPLICATION_SECRET={your client secret} 55 | export DOMAIN={your tenant id as a guid OR the domain name of your org } 56 | ``` 57 | 58 | > [AZURE.NOTE] On Windows, use `set` instead of `export`. 59 | 60 | 6. Run the sample. 61 | 62 | ``` 63 | // By default the script will use the ssh public key from your default ssh location 64 | node index.js [path/to/ssh_public_key] 65 | ``` 66 | 67 | 7. To clean up after index.js, run the cleanup script. 68 | 69 | ``` 70 | node cleanup.js 71 | ``` 72 | 73 | 74 | ## What is index.js doing? 75 | 76 | The sample starts by logging in using your service principal. 77 | 78 | ``` 79 | _validateEnvironmentVariables(); 80 | var clientId = process.env['CLIENT_ID']; 81 | var domain = process.env['DOMAIN']; 82 | var secret = process.env['APPLICATION_SECRET']; 83 | var subscriptionId = process.env['AZURE_SUBSCRIPTION_ID']; 84 | var publicSSHKeyPath = process.argv[2] || "~/.ssh/id_rsa.pub"; 85 | var resourceClient; 86 | //Sample Config 87 | var randomIds = {}; 88 | var location = 'eastus'; 89 | var resourceGroupName = _generateRandomId('testrg', randomIds); 90 | var deploymentName = _generateRandomId('testdeployment', randomIds); 91 | var dnsLabelPrefix = _generateRandomId('testdnslable', randomIds); 92 | 93 | /////////////////////////////////////// 94 | //Entrypoint for the sample script // 95 | /////////////////////////////////////// 96 | 97 | msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain, function (err, credentials) { 98 | if (err) return console.log(err); 99 | resourceClient = new ResourceManagementClient(credentials, subscriptionId); 100 | ``` 101 | 102 | Then it creates a resource group into which the VM will be deployed. 103 | 104 | ``` 105 | var groupParameters = { location: location, tags: { sampletag: 'sampleValue' } }; 106 | resourceClient.resourceGroups.createOrUpdate(resourceGroupName, groupParameters, callback); 107 | ``` 108 | 109 | 110 | ### Deploy the template 111 | 112 | Now, the sample loads the template and deploys it into the resource group that it just created. 113 | 114 | ``` 115 | try { 116 | var templateFilePath = path.join(__dirname, "templates/template.json"); 117 | var template = JSON.parse(fs.readFileSync(templateFilePath, 'utf8')); 118 | var publicSSHKey = fs.readFileSync(expandTilde(publicSSHKeyPath), 'utf8'); 119 | } catch (ex) { 120 | return callback(ex); 121 | } 122 | 123 | var parameters = { 124 | "sshKeyData": { 125 | "value": publicSSHKey 126 | }, 127 | "vmName": { 128 | "value": "azure-deployment-sample-vm" 129 | }, 130 | "dnsLabelPrefix": { 131 | "value": dnsLabelPrefix 132 | } 133 | }; 134 | var deploymentParameters = { 135 | "properties": { 136 | "parameters": parameters, 137 | "template": template, 138 | "mode": "Incremental" 139 | } 140 | }; 141 | 142 | resourceClient.deployments.createOrUpdate(resourceGroupName, 143 | deploymentName, 144 | deploymentParameters, 145 | callback); 146 | ``` 147 | 148 | ## More information 149 | 150 | Please refer to [Azure SDK for Node](https://github.com/Azure/azure-sdk-for-node) for more information. 151 | -------------------------------------------------------------------------------- /cleanup.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for 4 | * license information. 5 | */ 6 | 'use strict'; 7 | 8 | var util = require('util'); 9 | var msRestAzure = require('ms-rest-azure'); 10 | var ResourceManagementClient = require('azure-arm-resource').ResourceManagementClient; 11 | 12 | _validateEnvironmentVariables(); 13 | _validateParameters(); 14 | var clientId = process.env['CLIENT_ID']; 15 | var domain = process.env['DOMAIN']; 16 | var secret = process.env['APPLICATION_SECRET']; 17 | var subscriptionId = process.env['AZURE_SUBSCRIPTION_ID']; 18 | var resourceGroupName = process.argv[2]; 19 | var deploymentName = process.argv[3]; 20 | var resourceClient; 21 | 22 | function deleteDeployment(callback) { 23 | console.log(util.format('\nDeleting deployment: %s'), deploymentName); 24 | return resourceClient.deployments.deleteMethod(resourceGroupName, deploymentName, callback); 25 | } 26 | 27 | function deleteResourceGroup(callback) { 28 | console.log('\nDeleting resource group: ' + resourceGroupName); 29 | return resourceClient.resourceGroups.deleteMethod(resourceGroupName, callback); 30 | } 31 | 32 | function _validateEnvironmentVariables() { 33 | var envs = []; 34 | if (!process.env['CLIENT_ID']) envs.push('CLIENT_ID'); 35 | if (!process.env['DOMAIN']) envs.push('DOMAIN'); 36 | if (!process.env['APPLICATION_SECRET']) envs.push('APPLICATION_SECRET'); 37 | if (!process.env['AZURE_SUBSCRIPTION_ID']) envs.push('AZURE_SUBSCRIPTION_ID'); 38 | if (envs.length > 0) { 39 | throw new Error(util.format('please set/export the following environment variables: %s', envs.toString())); 40 | } 41 | } 42 | 43 | function _validateParameters() { 44 | if (!process.argv[2] || !process.argv[3]) { 45 | throw new Error('Please provide the resource group and the resource name by executing the script as follows: "node cleanup.js ".'); 46 | } 47 | } 48 | 49 | //Entrypoint of the cleanup script 50 | msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain, function (err, credentials) { 51 | if (err) return console.log(err); 52 | resourceClient = new ResourceManagementClient(credentials, subscriptionId); 53 | deleteDeployment(function (err, result) { 54 | if (err) return console.log('Error occured in deleting the deployment: ' + deploymentName + '\n' + util.inspect(err, { depth: null })); 55 | console.log('Successfully deleted the deployment: ' + deploymentName); 56 | console.log('\nDeleting the resource group can take few minutes, so please be patient :).'); 57 | deleteResourceGroup(function (err, result) { 58 | if (err) return console.log('Error occured in deleting the resource group: ' + resourceGroupName + '\n' + util.inspect(err, { depth: null })); 59 | console.log('Successfully deleted the resourcegroup: ' + resourceGroupName); 60 | }); 61 | }); 62 | }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for 4 | * license information. 5 | */ 6 | 'use strict'; 7 | 8 | var fs = require('fs'); 9 | var path = require('path'); 10 | var util = require('util'); 11 | var async = require('async'); 12 | var expandTilde = require('expand-tilde'); 13 | var msRestAzure = require('ms-rest-azure'); 14 | var ResourceManagementClient = require('azure-arm-resource').ResourceManagementClient; 15 | 16 | _validateEnvironmentVariables(); 17 | var clientId = process.env['CLIENT_ID']; 18 | var domain = process.env['DOMAIN']; 19 | var secret = process.env['APPLICATION_SECRET']; 20 | var subscriptionId = process.env['AZURE_SUBSCRIPTION_ID']; 21 | var publicSSHKeyPath = process.argv[2] || "~/.ssh/id_rsa.pub"; 22 | var resourceClient; 23 | //Sample Config 24 | var randomIds = {}; 25 | var location = 'eastus'; 26 | var resourceGroupName = _generateRandomId('testrg', randomIds); 27 | var deploymentName = _generateRandomId('testdeployment', randomIds); 28 | var dnsLabelPrefix = _generateRandomId('testdnslable', randomIds); 29 | 30 | /////////////////////////////////////// 31 | //Entrypoint for the sample script // 32 | /////////////////////////////////////// 33 | 34 | msRestAzure.loginWithServicePrincipalSecret(clientId, secret, domain, function (err, credentials) { 35 | if (err) return console.log(err); 36 | resourceClient = new ResourceManagementClient(credentials, subscriptionId); 37 | // Work flow of this sample: 38 | // 1. create a resource group 39 | // 2. load a VM template and deploy it. 40 | // 3. delete deployed resource(optional) 41 | // 4. delete a resource group(optional) 42 | 43 | async.series([ 44 | function (callback) { 45 | //Task 1 46 | createResourceGroup(function (err, result, request, response) { 47 | if (err) { 48 | return callback(err); 49 | } 50 | callback(null, result); 51 | }); 52 | }, 53 | function (callback) { 54 | //Task 2 55 | loadTemplateAndDeploy(function (err, result, request, response) { 56 | if (err) { 57 | return callback(err); 58 | } 59 | console.log(util.format('\nDeployed template %s : \n%s', deploymentName, util.inspect(result, { depth: null }))); 60 | callback(null, result); 61 | }); 62 | } 63 | ], 64 | // Once above operations finish, cleanup and exit. 65 | function (err, results) { 66 | if (err) { 67 | console.log(util.format('\n??????Error occurred in one of the operations.\n%s', 68 | util.inspect(err, { depth: null }))); 69 | } else { 70 | //console.log(util.format('\n######You can browse the website at: https://%s.', results[4].enabledHostNames[0])); 71 | } 72 | console.log('\n###### Exit ######'); 73 | console.log(util.format('Please execute the following script for cleanup:\nnode cleanup.js %s', resourceGroupName, deploymentName)); 74 | process.exit(); 75 | }); 76 | }); 77 | 78 | 79 | // Helper functions 80 | function createResourceGroup(callback) { 81 | var groupParameters = { location: location, tags: { sampletag: 'sampleValue' } }; 82 | console.log('\nCreating resource group: ' + resourceGroupName); 83 | return resourceClient.resourceGroups.createOrUpdate(resourceGroupName, groupParameters, callback); 84 | } 85 | 86 | function loadTemplateAndDeploy(callback) { 87 | try { 88 | var templateFilePath = path.join(__dirname, "templates/template.json"); 89 | var template = JSON.parse(fs.readFileSync(templateFilePath, 'utf8')); 90 | var publicSSHKey = fs.readFileSync(expandTilde(publicSSHKeyPath), 'utf8'); 91 | } catch (ex) { 92 | return callback(ex); 93 | } 94 | 95 | console.log('\nLoaded template from template.json'); 96 | var parameters = { 97 | "sshKeyData": { 98 | "value": publicSSHKey 99 | }, 100 | "vmName": { 101 | "value": "azure-deployment-sample-vm" 102 | }, 103 | "dnsLabelPrefix": { 104 | "value": dnsLabelPrefix 105 | } 106 | }; 107 | var deploymentParameters = { 108 | "properties": { 109 | "parameters": parameters, 110 | "template": template, 111 | "mode": "Incremental" 112 | } 113 | }; 114 | 115 | console.log(util.format('\nDeploying template %s : \n%s', deploymentName, util.inspect(template, { depth: null }))); 116 | return resourceClient.deployments.createOrUpdate(resourceGroupName, 117 | deploymentName, 118 | deploymentParameters, 119 | callback); 120 | } 121 | 122 | function deleteDeployment(callback) { 123 | console.log(util.format('\nDeleting deployment %s in resource group %s'), 124 | deploymentName, resourceGroupName); 125 | return resourceClient.deployments.deleteMethod(resourceGroupName, deploymentName, callback); 126 | } 127 | 128 | function deleteResourceGroup(callback) { 129 | console.log('\nDeleting resource group: ' + resourceGroupName); 130 | return resourceClient.resourceGroups.deleteMethod(resourceGroupName, callback); 131 | } 132 | 133 | function _validateEnvironmentVariables() { 134 | var envs = []; 135 | if (!process.env['CLIENT_ID']) envs.push('CLIENT_ID'); 136 | if (!process.env['DOMAIN']) envs.push('DOMAIN'); 137 | if (!process.env['APPLICATION_SECRET']) envs.push('APPLICATION_SECRET'); 138 | if (!process.env['AZURE_SUBSCRIPTION_ID']) envs.push('AZURE_SUBSCRIPTION_ID'); 139 | if (envs.length > 0) { 140 | throw new Error(util.format('please set/export the following environment variables: %s', envs.toString())); 141 | } 142 | } 143 | 144 | function _generateRandomId(prefix, exsitIds) { 145 | var newNumber; 146 | while (true) { 147 | newNumber = prefix + Math.floor(Math.random() * 10000); 148 | if (!exsitIds || !(newNumber in exsitIds)) { 149 | break; 150 | } 151 | } 152 | return newNumber; 153 | } 154 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resource-manager-node-template-deployment", 3 | "author": "Microsoft Corporation", 4 | "contributors": [ 5 | "Chen, Hao ", 6 | "Zavery, Amar " 7 | ], 8 | "version": "0.1.0", 9 | "description": "An example illustrating how to use node.js to deploy an Azure Resource Manager Template.", 10 | "tags": [ 11 | "azure", 12 | "sdk" 13 | ], 14 | "keywords": [ 15 | "node", 16 | "azure" 17 | ], 18 | "main": "./index.js", 19 | "license": "MIT", 20 | "dependencies": { 21 | "async": "0.2.7", 22 | "azure-arm-resource": "^1.4.4-preview", 23 | "expand-tilde": "^1.2.2", 24 | "ms-rest-azure": "^1.14.3" 25 | }, 26 | "homepage": "https://github.com/Azure-Samples/resource-manager-node-template-deployment", 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/Azure-Samples/resource-manager-node-template-deployment" 30 | }, 31 | "bugs": { 32 | "url": "https://github.com/azure/azures-sdk-for-node/issues" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /templates/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "adminUserName": { 6 | "type": "string", 7 | "defaultValue": "azureSample", 8 | "metadata": { 9 | "description": "User name for the Virtual Machine." 10 | } 11 | }, 12 | "sshKeyData": { 13 | "type": "string", 14 | "metadata": { 15 | "description": "SSH rsa public key file as a string." 16 | } 17 | }, 18 | "dnsLabelPrefix": { 19 | "type": "string", 20 | "metadata": { 21 | "description": "Unique DNS Name for the Public IP used to access the Virtual Machine." 22 | } 23 | }, 24 | "vmSize": { 25 | "type": "string", 26 | "defaultValue": "Standard_D1", 27 | "metadata": { 28 | "description": "Size of the VM" 29 | } 30 | }, 31 | "vmName": { 32 | "type": "string", 33 | "metadata": { 34 | "description": "Name of the VM" 35 | } 36 | }, 37 | "imagePublisher": { 38 | "type": "string", 39 | "defaultValue": "canonical", 40 | "metadata": { 41 | "description": "Name of the image publisher" 42 | } 43 | }, 44 | "imageOffer": { 45 | "type": "string", 46 | "defaultValue": "ubuntuserver", 47 | "metadata": { 48 | "description": "Name of the image offer" 49 | } 50 | }, 51 | "imageSku": { 52 | "type": "string", 53 | "defaultValue": "16.04-DAILY-LTS", 54 | "metadata": { 55 | "description": "Name of the image sku" 56 | } 57 | }, 58 | "imageVersion": { 59 | "type": "string", 60 | "defaultValue": "latest", 61 | "metadata": { 62 | "description": "Name of the image sku" 63 | } 64 | }, 65 | "subnetName": { 66 | "type": "string", 67 | "defaultValue": "azsample-subnet", 68 | "metadata": { 69 | "description": "Name of the subnet" 70 | } 71 | }, 72 | "virtualNetworkName": { 73 | "type": "string", 74 | "defaultValue": "azsampleVNET", 75 | "metadata": { 76 | "description": "Name of the virtual network" 77 | } 78 | } 79 | }, 80 | "variables": { 81 | "storageAccountName": "[concat(uniquestring(resourceGroup().id), 'azsample')]", 82 | "location": "[resourceGroup().location]", 83 | "osDiskName": "osDisk1", 84 | "addressPrefix": "10.0.0.0/16", 85 | "subnetPrefix": "10.0.0.0/24", 86 | "vmStorageAccountContainerName": "azsample-vhds", 87 | "nicName": "[concat(parameters('vmName'), '-azsampleNIC')]", 88 | "publicIPAddressName": "[concat(parameters('vmName'), '-azsamplePublicIP')]", 89 | "publicIPAddressType": "Dynamic", 90 | "storageAccountType": "Standard_LRS", 91 | "networkSecurityGroupName": "[concat(parameters('vmName'), '-azsampleNSG')]", 92 | "sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]", 93 | "vnetID": "[resourceId('Microsoft.Network/virtualNetworks', parameters('virtualNetworkName'))]", 94 | "subnetRef": "[concat(variables('vnetID'),'/subnets/',parameters('subnetName'))]", 95 | "apiVersion": "2015-06-15" 96 | }, 97 | "resources": [ 98 | { 99 | "type": "Microsoft.Storage/storageAccounts", 100 | "name": "[variables('storageAccountName')]", 101 | "apiVersion": "[variables('apiVersion')]", 102 | "location": "[variables('location')]", 103 | "properties": { 104 | "accountType": "[variables('storageAccountType')]" 105 | } 106 | }, 107 | { 108 | "apiVersion": "[variables('apiVersion')]", 109 | "type": "Microsoft.Network/networkSecurityGroups", 110 | "name": "[variables('networkSecurityGroupName')]", 111 | "location": "[variables('location')]", 112 | "properties": { 113 | "securityRules": [ 114 | { 115 | "name": "ssh_rule", 116 | "properties": { 117 | "description": "Locks inbound down to ssh default port 22.", 118 | "protocol": "Tcp", 119 | "sourcePortRange": "*", 120 | "destinationPortRange": "22", 121 | "sourceAddressPrefix": "*", 122 | "destinationAddressPrefix": "*", 123 | "access": "Allow", 124 | "priority": 123, 125 | "direction": "Inbound" 126 | } 127 | } 128 | ] 129 | } 130 | }, 131 | { 132 | "apiVersion": "[variables('apiVersion')]", 133 | "type": "Microsoft.Network/publicIPAddresses", 134 | "name": "[variables('publicIPAddressName')]", 135 | "location": "[variables('location')]", 136 | "properties": { 137 | "publicIPAllocationMethod": "[variables('publicIPAddressType')]", 138 | "dnsSettings": { 139 | "domainNameLabel": "[parameters('dnsLabelPrefix')]" 140 | } 141 | } 142 | }, 143 | { 144 | "apiVersion": "[variables('apiVersion')]", 145 | "type": "Microsoft.Network/virtualNetworks", 146 | "name": "[parameters('virtualNetworkName')]", 147 | "location": "[variables('location')]", 148 | "dependsOn": [ 149 | "[concat('Microsoft.Network/networkSecurityGroups/', variables('networkSecurityGroupName'))]" 150 | ], 151 | "properties": { 152 | "addressSpace": { 153 | "addressPrefixes": [ 154 | "[variables('addressPrefix')]" 155 | ] 156 | }, 157 | "subnets": [ 158 | { 159 | "name": "[parameters('subnetName')]", 160 | "properties": { 161 | "addressPrefix": "[variables('subnetPrefix')]", 162 | "networkSecurityGroup": { 163 | "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('networkSecurityGroupName'))]" 164 | } 165 | } 166 | } 167 | ] 168 | } 169 | }, 170 | { 171 | "apiVersion": "[variables('apiVersion')]", 172 | "type": "Microsoft.Network/networkInterfaces", 173 | "name": "[variables('nicName')]", 174 | "location": "[variables('location')]", 175 | "dependsOn": [ 176 | "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]", 177 | "[concat('Microsoft.Network/virtualNetworks/', parameters('virtualNetworkName'))]" 178 | ], 179 | "properties": { 180 | "ipConfigurations": [ 181 | { 182 | "name": "ipconfig1", 183 | "properties": { 184 | "privateIPAllocationMethod": "Dynamic", 185 | "publicIPAddress": { 186 | "id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]" 187 | }, 188 | "subnet": { 189 | "id": "[variables('subnetRef')]" 190 | } 191 | } 192 | } 193 | ] 194 | } 195 | }, 196 | { 197 | "apiVersion": "[variables('apiVersion')]", 198 | "type": "Microsoft.Compute/virtualMachines", 199 | "name": "[parameters('vmName')]", 200 | "location": "[variables('location')]", 201 | "dependsOn": [ 202 | "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'))]", 203 | "[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]" 204 | ], 205 | "properties": { 206 | "hardwareProfile": { 207 | "vmSize": "[parameters('vmSize')]" 208 | }, 209 | "osProfile": { 210 | "computerName": "[parameters('vmName')]", 211 | "adminUsername": "[parameters('adminUsername')]", 212 | "linuxConfiguration": { 213 | "disablePasswordAuthentication": "true", 214 | "ssh": { 215 | "publicKeys": [ 216 | { 217 | "path": "[variables('sshKeyPath')]", 218 | "keyData": "[parameters('sshKeyData')]" 219 | } 220 | ] 221 | } 222 | } 223 | }, 224 | "storageProfile": { 225 | "imageReference": { 226 | "publisher": "[parameters('imagePublisher')]", 227 | "offer": "[parameters('imageOffer')]", 228 | "sku": "[parameters('imageSku')]", 229 | "version": "latest" 230 | }, 231 | "osDisk": { 232 | "name": "osdisk", 233 | "vhd": { 234 | "uri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net/',variables('vmStorageAccountContainerName'),'/', variables('osDiskName'),'.vhd')]" 235 | }, 236 | "caching": "ReadWrite", 237 | "createOption": "FromImage" 238 | } 239 | }, 240 | "networkProfile": { 241 | "networkInterfaces": [ 242 | { 243 | "id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]" 244 | } 245 | ] 246 | }, 247 | "diagnosticsProfile": { 248 | "bootDiagnostics": { 249 | "enabled": "true", 250 | "storageUri": "[concat('http://',variables('storageAccountName'),'.blob.core.windows.net')]" 251 | } 252 | } 253 | } 254 | } 255 | ] 256 | } 257 | --------------------------------------------------------------------------------