diff --git a/chef-ha-cluster/.ci_skip b/chef-ha-cluster/.ci_skip
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/chef-ha-cluster/README.md b/chef-ha-cluster/README.md
new file mode 100644
index 000000000000..61e92956b2b7
--- /dev/null
+++ b/chef-ha-cluster/README.md
@@ -0,0 +1,45 @@
+# Chef Backend High-Availability Cluster
+
+
+
+
+
+
+
+
+**This template has artifacts that need to be staged for deployment (Configuration Scripts) so use the below command with the upload flag to deploy this template or provide a storage account and SAS token when using the deploy button above.**
+You can optionally specify a storage account to use, if so the storage account must already exist within the subscription. If you don't want to specify a storage account
+one will be created by the script (think of this as "temp" storage for AzureRM) and reused by subsequent deployments.
+
+```PowerShell
+.\Deploy-AzureResourceGroup.ps1 -ResourceGroupLocation 'eastus' -ArtifactsStagingDirectory 'chef-ha-cluster' -UploadArtifacts
+```
+```bash
+azure-group-deploy.sh -a chef-ha-cluster -l eastus -u
+```
+
+This template deploys a Chef Backend High-Availability Cluster.
+`Tags: chef,cluster,ha`
+
+## Deployment steps
+
+You can click the "deploy to Azure" button at the beginning of this document or follow the instructions for command line deployment using the scripts in the root of this repo.
+
+## Usage
+
+#### Connect
+
+Connect using ssh
+To reach a frontend use port 50000,50001,50002 (FE0,1,2):
+```
+ssh -p 50000 chefadmin@yourhost.youregion.cloudapp.azure.com
+```
+To reach a backend do something like
+```
+ssh -o ProxyCommand="ssh -W %h:%p -p 50000 -q chefadmin@yourhost.youregion.cloudapp.azure.com" chefadmin@be0
+```
+
+#### Management
+
+See the chef documentation at [Chef](https://docs.chef.io/)
+
diff --git a/chef-ha-cluster/azuredeploy.json b/chef-ha-cluster/azuredeploy.json
new file mode 100644
index 000000000000..f2a0d28a6e41
--- /dev/null
+++ b/chef-ha-cluster/azuredeploy.json
@@ -0,0 +1,1095 @@
+{
+ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "_artifactsLocation": {
+ "type": "string",
+ "metadata": {
+ "description": "Auto-generated container in staging storage account to receive post-build staging folder upload"
+ }
+ },
+ "_artifactsLocationSasToken": {
+ "type": "securestring",
+ "metadata": {
+ "description": "Auto-generated token to access _artifactsLocation"
+ }
+ },
+ "adminUsername": {
+ "type": "string",
+ "minLength": 1,
+ "metadata": {
+ "description": "Administrator username on all VMs"
+ }
+ },
+ "chefBEType": {
+ "type": "string",
+ "defaultValue": "Premium_LRS",
+ "allowedValues": [
+ "Standard_LRS",
+ "Standard_ZRS",
+ "Standard_GRS",
+ "Standard_RAGRS",
+ "Premium_LRS"
+ ],
+ "metadata": {
+ "description": "Chef BE VM Storage Type must match chefBEvmSize"
+ }
+ },
+ "chefBEvmSize": {
+ "type": "string",
+ "defaultValue": "Standard_DS3_v2",
+ "allowedValues": [
+ "Standard_DS1",
+ "Standard_DS2",
+ "Standard_DS3",
+ "Standard_DS4",
+ "Standard_DS1_v2",
+ "Standard_DS2_v2",
+ "Standard_DS3_v2",
+ "Standard_DS4_v2",
+ "Standard_D1",
+ "Standard_D2",
+ "Standard_D3",
+ "Standard_D4",
+ "Standard_D1_v2",
+ "Standard_D2_v2",
+ "Standard_D3_v2",
+ "Standard_D4_v2",
+ "Standard_D5_v2",
+ "Standard_A0",
+ "Standard_A1",
+ "Standard_A2",
+ "Standard_A3",
+ "Standard_A4",
+ "Standard_A5"
+ ],
+ "minLength": 1,
+ "metadata": {
+ "description": "Chef BE VM Size must match chefBEType"
+ }
+ },
+ "chefDNSName": {
+ "type": "string",
+ "metadata": {
+ "description": "DNS name used for public IP addresses and as base for naming other resources. Must be globally unique and 3 to 61 characters long."
+ },
+ "minLength": 3,
+ "maxLength": 61
+ },
+ "chefFEType": {
+ "type": "string",
+ "defaultValue": "Standard_LRS",
+ "allowedValues": [
+ "Standard_LRS",
+ "Standard_ZRS",
+ "Standard_GRS",
+ "Standard_RAGRS",
+ "Premium_LRS"
+ ],
+ "metadata": {
+ "description": "Chef FE VM Storage Type must match chefFEvmSize"
+ }
+ },
+ "chefFEvmSize": {
+ "type": "string",
+ "defaultValue": "Standard_A3",
+ "allowedValues": [
+ "Standard_DS1",
+ "Standard_DS2",
+ "Standard_DS3",
+ "Standard_DS4",
+ "Standard_DS1_v2",
+ "Standard_DS2_v2",
+ "Standard_DS3_v2",
+ "Standard_DS4_v2",
+ "Standard_D1",
+ "Standard_D2",
+ "Standard_D3",
+ "Standard_D4",
+ "Standard_D1_v2",
+ "Standard_D2_v2",
+ "Standard_D3_v2",
+ "Standard_D4_v2",
+ "Standard_D5_v2",
+ "Standard_A0",
+ "Standard_A1",
+ "Standard_A2",
+ "Standard_A3",
+ "Standard_A4",
+ "Standard_A5"
+ ],
+ "minLength": 1,
+ "metadata": {
+ "description": "Chef FE VM Size must match chefFEType"
+ }
+ },
+ "sshKeyData": {
+ "type": "string",
+ "metadata": {
+ "description": "SSH rsa public key file as a string."
+ }
+ },
+ "storageURL": {
+ "type": "string",
+ "metadata": {
+ "description": "URL for Azure Storage should need changing for regional only"
+ },
+ "defaultValue": "core.windows.net"
+ },
+ "ubuntuVersion": {
+ "type": "string",
+ "defaultValue": "14.04.5-LTS",
+ "metadata": {
+ "description": "Ubuntu version"
+ }
+ }
+ },
+ "variables": {
+ "addressPrefix": "10.0.0.0/16",
+ "bePoolName": "chefpool",
+ "BEStorageAccountContainerName": "vhds",
+ "ChefBEAvailName": "BEAvail",
+ "chefbeName": "[concat('chefbe', uniqueString(resourceGroup().id))]",
+ "ChefFEAvailName": "FEAvail",
+ "cheffeName": "[concat('cheffe', uniqueString(resourceGroup().id))]",
+ "FE0setupscriptScriptFileName": "FE0Setup.sh",
+ "FE0setupscriptScriptFilePath": "[concat('scripts/', variables('FE0setupscriptScriptFileName'))]",
+ "FEsetupscriptScriptFileName": "FESetup.sh",
+ "FEsetupscriptScriptFilePath": "[concat('scripts/', variables('FEsetupscriptScriptFileName'))]",
+ "FEStorageAccountContainerName": "vhds",
+ "FollowerSetupScriptFileName": "BEFollowerSetup.sh",
+ "FollowerSetupScriptFilePath": "[concat('scripts/', variables('FollowerSetupScriptFileName'))]",
+ "frontEndIPConfigID": "[concat(variables('lbID'), '/frontendIPConfigurations/loadBalancerFrontEnd')]",
+ "imageReference": "[variables('osType')]",
+ "lbID": "[resourceId('Microsoft.Network/loadBalancers', variables('loadBalancerName'))]",
+ "lbProbeID": "[concat(variables('lbID'),'/probes/https')]",
+ "LeaderSetupScriptFileName": "BELeaderSetup.sh",
+ "LeaderSetupScriptFilePath": "[concat('scripts/', variables('LeaderSetupScriptFileName'))]",
+ "loadBalancerName": "cheffelb",
+ "location": "[resourceGroup().location]",
+ "natPoolName": "chefnatpool",
+ "osType": {
+ "publisher": "Canonical",
+ "offer": "UbuntuServer",
+ "sku": "[parameters('ubuntuVersion')]",
+ "version": "latest"
+ },
+ "publicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]",
+ "publicIPAddressName": "chefpublicip",
+ "sshKeyPath": "[concat('/home/',parameters('adminUserName'),'/.ssh/authorized_keys')]",
+ "subnetName": "chefsubnet",
+ "subnetPrefix": "10.0.0.0/24",
+ "SubnetRef": "[concat(variables('VnetID'), '/subnets/', variables('subnetName'))]",
+ "virtualNetworkName": "chefvnet",
+ "VnetID": "[resourceId('Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
+ },
+ "resources": [
+ {
+ "type": "Microsoft.Network/virtualNetworks",
+ "name": "[variables('virtualNetworkName')]",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "tags": {
+ "displayName": "ChefVirtualNetwork"
+ },
+ "properties": {
+ "addressSpace": {
+ "addressPrefixes": [
+ "[variables('addressPrefix')]"
+ ]
+ },
+ "subnets": [
+ {
+ "name": "[variables('subnetName')]",
+ "properties": {
+ "addressPrefix": "[variables('subnetPrefix')]"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "[variables('chefbeName')]",
+ "type": "Microsoft.Storage/storageAccounts",
+ "location": "[resourceGroup().location]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [ ],
+ "tags": {
+ "displayName": "BEStorage"
+ },
+ "properties": {
+ "accountType": "[parameters('chefBEType')]"
+ }
+ },
+ {
+ "name": "[variables('cheffeName')]",
+ "type": "Microsoft.Storage/storageAccounts",
+ "location": "[resourceGroup().location]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [ ],
+ "tags": {
+ "displayName": "FEStorage"
+ },
+ "properties": {
+ "accountType": "[parameters('chefFEType')]"
+ }
+ },
+ {
+ "type": "Microsoft.Network/publicIPAddresses",
+ "name": "[variables('publicIPAddressName')]",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "tags": {
+ "displayName": "FEPublicIP"
+ },
+ "properties": {
+ "publicIPAllocationMethod": "Dynamic",
+ "dnsSettings": {
+ "domainNameLabel": "[toLower(parameters('chefDNSName'))]"
+ }
+ }
+ },
+ {
+ "type": "Microsoft.Network/loadBalancers",
+ "name": "[variables('loadBalancerName')]",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "tags": {
+ "displayName": "FELoadBalancer"
+ },
+ "dependsOn": [
+ "[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]"
+ ],
+ "properties": {
+ "frontendIPConfigurations": [
+ {
+ "name": "LoadBalancerFrontEnd",
+ "properties": {
+ "publicIPAddress": {
+ "id": "[variables('publicIPAddressID')]"
+ }
+ }
+ }
+ ],
+ "backendAddressPools": [
+ {
+ "name": "[variables('bePoolName')]"
+ }
+ ],
+ "inboundNatRules": [
+ {
+ "name": "ssh-fe0",
+ "properties": {
+ "frontendIPConfiguration": {
+ "id": "[variables('frontEndIPConfigID')]"
+ },
+ "protocol": "tcp",
+ "frontendPort": 50000,
+ "backendPort": 22,
+ "enableFloatingIP": false
+ }
+ },
+ {
+ "name": "ssh-fe1",
+ "properties": {
+ "frontendIPConfiguration": {
+ "id": "[variables('frontEndIPConfigID')]"
+ },
+ "protocol": "tcp",
+ "frontendPort": 50001,
+ "backendPort": 22,
+ "enableFloatingIP": false
+ }
+ },
+ {
+ "name": "ssh-fe2",
+ "properties": {
+ "frontendIPConfiguration": {
+ "id": "[variables('frontEndIPConfigID')]"
+ },
+ "protocol": "tcp",
+ "frontendPort": 50002,
+ "backendPort": 22,
+ "enableFloatingIP": false
+ }
+ }
+ ],
+ "probes": [
+ {
+ "name": "https",
+ "properties": {
+ "protocol": "Tcp",
+ "port": 443
+ }
+ }
+ ],
+ "loadBalancingRules": [
+ {
+ "name": "https",
+ "properties": {
+ "protocol": "Tcp",
+ "backendAddressPool": { "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/backendAddressPools/', variables('bePoolName'))]" },
+ "backendPort": 443,
+ "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" },
+ "frontendPort": 443,
+ "probe": {
+ "id": "[variables('lbProbeID')]"
+ },
+ "loadDistribution": "SourceIPProtocol"
+ }
+ },
+ {
+ "name": "http",
+ "properties": {
+ "protocol": "Tcp",
+ "backendAddressPool": { "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/backendAddressPools/', variables('bePoolName'))]" },
+ "backendPort": 80,
+ "frontendIPConfiguration": { "id": "[variables('frontEndIPConfigID')]" },
+ "frontendPort": 80,
+ "probe": {
+ "id": "[variables('lbProbeID')]"
+ },
+ "loadDistribution": "SourceIPProtocol"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "[variables('ChefBEAvailName')]",
+ "type": "Microsoft.Compute/availabilitySets",
+ "location": "[resourceGroup().location]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [ ],
+ "tags": {
+ "displayName": "BEAvailSet"
+ },
+ "properties": {
+ "platformUpdateDomainCount": 3,
+ "platformFaultDomainCount": 3
+ }
+ },
+ {
+ "name": "[variables('ChefFEAvailName')]",
+ "type": "Microsoft.Compute/availabilitySets",
+ "location": "[resourceGroup().location]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [ ],
+ "tags": {
+ "displayName": "FEAvailSet"
+ },
+ "properties": {
+ "platformUpdateDomainCount": 3,
+ "platformFaultDomainCount": 3
+ }
+ },
+ {
+ "name": "BE0Nic",
+ "type": "Microsoft.Network/networkInterfaces",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
+ ],
+ "tags": {
+ "displayName": "BE0Nic"
+ },
+ "properties": {
+ "ipConfigurations": [
+ {
+ "name": "ipconfig1",
+ "properties": {
+ "privateIPAllocationMethod": "Static",
+ "subnet": {
+ "id": "[variables('SubnetRef')]"
+ },
+ "privateIPAddress": "10.0.0.10"
+
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "BE0",
+ "type": "Microsoft.Compute/virtualMachines",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Storage/storageAccounts/', variables('chefbeName'))]",
+ "[concat('Microsoft.Network/networkInterfaces/', 'BE0Nic')]",
+ "[concat('Microsoft.Compute/availabilitySets/',variables('ChefBEAvailName'))]"
+ ],
+ "tags": {
+ "displayName": "BE0"
+ },
+ "properties": {
+ "hardwareProfile": {
+ "vmSize": "[parameters('chefBEvmSize')]"
+ },
+ "osProfile": {
+ "computerName": "be0",
+ "adminUsername": "[parameters('adminusername')]",
+ "linuxConfiguration": {
+ "disablePasswordAuthentication": true,
+ "ssh": {
+ "publicKeys": [
+ {
+ "keyData": "[parameters('sshKeyData')]",
+ "path": "[variables('sshKeyPath')]"
+ }
+ ]
+ }
+ }
+
+ },
+ "storageProfile": {
+ "imageReference": "[variables('imageReference')]",
+ "osDisk": {
+ "name": "BE0OSDisk",
+ "vhd": {
+ "uri": "[concat('http://', variables('chefbeName'), '.blob.', parameters('storageURL'), '/', variables('BEStorageAccountContainerName'), '/', 'BE0OSDisk', '.vhd')]"
+ },
+ "caching": "ReadWrite",
+ "createOption": "FromImage"
+ }
+ },
+ "networkProfile": {
+ "networkInterfaces": [
+ {
+ "id": "[resourceId('Microsoft.Network/networkInterfaces', 'BE0Nic')]"
+ }
+ ]
+ },
+ "availabilitySet": {
+ "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('ChefBEAvailName'))]"
+ }
+ },
+ "resources": [
+ {
+ "name": "BE0Setup",
+ "type": "extensions",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Compute/virtualMachines/', 'BE0')]"
+ ],
+ "tags": {
+ "displayName": "BE0Setup"
+ },
+ "properties": {
+ "publisher": "Microsoft.OSTCExtensions",
+ "type": "CustomScriptForLinux",
+ "typeHandlerVersion": "1.4",
+ "autoUpgradeMinorVersion": true,
+ "settings": {
+ "fileUris": [
+ "[concat(parameters('_artifactsLocation'), '/', variables('LeaderSetupScriptFilePath'), parameters('_artifactsLocationSasToken'))]"
+ ]
+ },
+ "protectedSettings": {
+ "commandToExecute": "[concat('sh ', variables('LeaderSetupScriptFileName'), ' \"', parameters('_artifactsLocation'), '\" \"', parameters('_artifactsLocationSasToken'), '\"')]"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "BE1Nic",
+ "type": "Microsoft.Network/networkInterfaces",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
+ ],
+ "tags": {
+ "displayName": "BE1Nic"
+ },
+ "properties": {
+ "ipConfigurations": [
+ {
+ "name": "ipconfig1",
+ "properties": {
+ "privateIPAllocationMethod": "Static",
+ "subnet": {
+ "id": "[variables('SubnetRef')]"
+ },
+ "privateIPAddress": "10.0.0.11"
+
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "BE1",
+ "type": "Microsoft.Compute/virtualMachines",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Storage/storageAccounts/', variables('chefbeName'))]",
+ "[concat('Microsoft.Network/networkInterfaces/', 'BE1Nic')]",
+ "[concat('Microsoft.Compute/availabilitySets/',variables('ChefBEAvailName'))]"
+ ],
+ "tags": {
+ "displayName": "BE1"
+ },
+ "properties": {
+ "hardwareProfile": {
+ "vmSize": "[parameters('chefBEvmSize')]"
+ },
+ "osProfile": {
+ "computerName": "be1",
+ "adminUsername": "[parameters('adminusername')]",
+ "linuxConfiguration": {
+ "disablePasswordAuthentication": true,
+ "ssh": {
+ "publicKeys": [
+ {
+ "keyData": "[parameters('sshKeyData')]",
+ "path": "[variables('sshKeyPath')]"
+ }
+ ]
+ }
+ }
+
+ },
+ "storageProfile": {
+ "imageReference": "[variables('imageReference')]",
+ "osDisk": {
+ "name": "BE1OSDisk",
+ "vhd": {
+ "uri": "[concat('http://', variables('chefbeName'), '.blob.', parameters('storageURL'), '/', variables('BEStorageAccountContainerName'), '/', 'BE1OSDisk', '.vhd')]"
+ },
+ "caching": "ReadWrite",
+ "createOption": "FromImage"
+ }
+ },
+ "networkProfile": {
+ "networkInterfaces": [
+ {
+ "id": "[resourceId('Microsoft.Network/networkInterfaces', 'BE1Nic')]"
+ }
+ ]
+ },
+ "availabilitySet": {
+ "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('ChefBEAvailName'))]"
+ }
+ },
+ "resources": [
+ {
+ "name": "BE1Setup",
+ "type": "extensions",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Compute/virtualMachines/', 'BE1')]",
+ "[resourceId('Microsoft.Compute/virtualMachines/extensions', 'BE0', 'BE0Setup')]"
+
+ ],
+ "tags": {
+ "displayName": "BE1Setup"
+ },
+ "properties": {
+ "publisher": "Microsoft.OSTCExtensions",
+ "type": "CustomScriptForLinux",
+ "typeHandlerVersion": "1.4",
+ "autoUpgradeMinorVersion": true,
+ "settings": {
+ "fileUris": [
+ "[concat(parameters('_artifactsLocation'), '/', variables('FollowerSetupScriptFilePath'), parameters('_artifactsLocationSasToken'))]"
+ ]
+ },
+ "protectedSettings": {
+ "commandToExecute": "[concat('sh ', variables('FollowerSetupScriptFileName'), ' \"', parameters('_artifactsLocation'), '\" \"', parameters('_artifactsLocationSasToken'), '\"')]"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "BE2Nic",
+ "type": "Microsoft.Network/networkInterfaces",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
+ ],
+ "tags": {
+ "displayName": "BE2Nic"
+ },
+ "properties": {
+ "ipConfigurations": [
+ {
+ "name": "ipconfig1",
+ "properties": {
+ "privateIPAllocationMethod": "Static",
+ "subnet": {
+ "id": "[variables('SubnetRef')]"
+ },
+ "privateIPAddress": "10.0.0.12"
+
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "BE2",
+ "type": "Microsoft.Compute/virtualMachines",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Storage/storageAccounts/', variables('chefbeName'))]",
+ "[concat('Microsoft.Network/networkInterfaces/', 'BE2Nic')]",
+ "[concat('Microsoft.Compute/availabilitySets/',variables('ChefBEAvailName'))]"
+ ],
+ "tags": {
+ "displayName": "BE2"
+ },
+ "properties": {
+ "hardwareProfile": {
+ "vmSize": "[parameters('chefBEvmSize')]"
+ },
+ "osProfile": {
+ "computerName": "be2",
+ "adminUsername": "[parameters('adminusername')]",
+ "linuxConfiguration": {
+ "disablePasswordAuthentication": true,
+ "ssh": {
+ "publicKeys": [
+ {
+ "keyData": "[parameters('sshKeyData')]",
+ "path": "[variables('sshKeyPath')]"
+ }
+ ]
+ }
+ }
+
+ },
+ "storageProfile": {
+ "imageReference": "[variables('imageReference')]",
+ "osDisk": {
+ "name": "BE2OSDisk",
+ "vhd": {
+ "uri": "[concat('http://', variables('chefbeName'), '.blob.', parameters('storageURL'), '/', variables('BEStorageAccountContainerName'), '/', 'BE2OSDisk', '.vhd')]"
+ },
+ "caching": "ReadWrite",
+ "createOption": "FromImage"
+ }
+ },
+ "networkProfile": {
+ "networkInterfaces": [
+ {
+ "id": "[resourceId('Microsoft.Network/networkInterfaces', 'BE2Nic')]"
+ }
+ ]
+ },
+ "availabilitySet": {
+ "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('ChefBEAvailName'))]"
+ }
+ },
+ "resources": [
+ {
+ "name": "BE2Setup",
+ "type": "extensions",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Compute/virtualMachines/', 'BE2')]",
+ "[resourceId('Microsoft.Compute/virtualMachines/extensions', 'BE0', 'BE0Setup')]",
+ "[resourceId('Microsoft.Compute/virtualMachines/extensions', 'BE1', 'BE1Setup')]"
+ ],
+ "tags": {
+ "displayName": "BE2Setup"
+ },
+ "properties": {
+ "publisher": "Microsoft.OSTCExtensions",
+ "type": "CustomScriptForLinux",
+ "typeHandlerVersion": "1.4",
+ "autoUpgradeMinorVersion": true,
+ "settings": {
+ "fileUris": [
+ "[concat(parameters('_artifactsLocation'), '/', variables('FollowerSetupScriptFilePath'), parameters('_artifactsLocationSasToken'))]"
+ ]
+ },
+ "protectedSettings": {
+ "commandToExecute": "[concat('sh ', variables('FollowerSetupScriptFileName'), ' \"', parameters('_artifactsLocation'), '\" \"', parameters('_artifactsLocationSasToken'), '\"')]"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "FE0Nic",
+ "type": "Microsoft.Network/networkInterfaces",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
+ "[concat('Microsoft.Network/loadBalancers/', variables('loadBalancerName'))]"
+ ],
+ "tags": {
+ "displayName": "FE0Nic"
+ },
+ "properties": {
+ "ipConfigurations": [
+ {
+ "name": "ipconfig1",
+ "properties": {
+ "privateIPAllocationMethod": "Static",
+ "subnet": {
+ "id": "[variables('SubnetRef')]"
+ },
+ "privateIPAddress": "10.0.0.50",
+ "loadBalancerBackendAddressPools": [
+ {
+ "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/backendAddressPools/', variables('bePoolName'))]"
+ }
+ ],
+ "loadBalancerInboundNatRules": [
+ {
+ "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/inboundNatRules/ssh-fe0')]"
+ }
+ ]
+
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "FE0",
+ "type": "Microsoft.Compute/virtualMachines",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Storage/storageAccounts/', variables('cheffeName'))]",
+ "[concat('Microsoft.Network/networkInterfaces/', 'FE0Nic')]",
+ "[concat('Microsoft.Compute/availabilitySets/',variables('ChefFEAvailName'))]"
+ ],
+ "tags": {
+ "displayName": "FE0"
+ },
+ "properties": {
+ "hardwareProfile": {
+ "vmSize": "[parameters('chefFEvmSize')]"
+ },
+ "osProfile": {
+ "computerName": "fe0",
+ "adminUsername": "[parameters('adminusername')]",
+ "linuxConfiguration": {
+ "disablePasswordAuthentication": true,
+ "ssh": {
+ "publicKeys": [
+ {
+ "keyData": "[parameters('sshKeyData')]",
+ "path": "[variables('sshKeyPath')]"
+ }
+ ]
+ }
+ }
+
+ },
+ "storageProfile": {
+ "imageReference": "[variables('imageReference')]",
+ "osDisk": {
+ "name": "FE0OSDisk",
+ "vhd": {
+ "uri": "[concat('http://', variables('cheffeName'), '.blob.', parameters('storageURL'), '/', variables('FEStorageAccountContainerName'), '/', 'FE0OSDisk', '.vhd')]"
+ },
+ "caching": "ReadWrite",
+ "createOption": "FromImage"
+ }
+ },
+ "networkProfile": {
+ "networkInterfaces": [
+ {
+ "id": "[resourceId('Microsoft.Network/networkInterfaces', 'FE0Nic')]"
+ }
+ ]
+ },
+ "availabilitySet": {
+ "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('ChefFEAvailName'))]"
+ }
+ },
+ "resources": [
+ {
+ "name": "FE0Setup",
+ "type": "extensions",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Compute/virtualMachines/', 'FE0')]",
+ "[resourceId('Microsoft.Compute/virtualMachines/extensions', 'BE0', 'BE0Setup')]",
+ "[resourceId('Microsoft.Compute/virtualMachines/extensions', 'BE1', 'BE1Setup')]",
+ "[resourceId('Microsoft.Compute/virtualMachines/extensions', 'BE2', 'BE2Setup')]"
+ ],
+ "tags": {
+ "displayName": "FE0Setup"
+ },
+ "properties": {
+ "publisher": "Microsoft.OSTCExtensions",
+ "type": "CustomScriptForLinux",
+ "typeHandlerVersion": "1.4",
+ "autoUpgradeMinorVersion": true,
+ "settings": {
+ "fileUris": [
+ "[concat(parameters('_artifactsLocation'), '/', variables('FE0setupscriptScriptFilePath'), parameters('_artifactsLocationSasToken'))]"
+ ]
+ },
+ "protectedSettings": {
+ "commandToExecute": "[concat('sh ', variables('FE0setupscriptScriptFileName'), ' \"', parameters('_artifactsLocation'), '\" \"', parameters('_artifactsLocationSasToken'), '\"')]"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "FE1Nic",
+ "type": "Microsoft.Network/networkInterfaces",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
+ "[concat('Microsoft.Network/loadBalancers/', variables('loadBalancerName'))]"
+ ],
+ "tags": {
+ "displayName": "FE1Nic"
+ },
+ "properties": {
+ "ipConfigurations": [
+ {
+ "name": "ipconfig1",
+ "properties": {
+ "privateIPAllocationMethod": "Static",
+ "subnet": {
+ "id": "[variables('SubnetRef')]"
+ },
+ "privateIPAddress": "10.0.0.51",
+ "loadBalancerBackendAddressPools": [
+ {
+ "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/backendAddressPools/', variables('bePoolName'))]"
+ }
+ ],
+ "loadBalancerInboundNatRules": [
+ {
+ "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/inboundNatRules/ssh-fe1')]"
+ }
+ ]
+
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "FE1",
+ "type": "Microsoft.Compute/virtualMachines",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Storage/storageAccounts/', variables('cheffeName'))]",
+ "[concat('Microsoft.Network/networkInterfaces/', 'FE1Nic')]",
+ "[concat('Microsoft.Compute/availabilitySets/',variables('ChefFEAvailName'))]"
+ ],
+ "tags": {
+ "displayName": "FE1"
+ },
+ "properties": {
+ "hardwareProfile": {
+ "vmSize": "[parameters('chefFEvmSize')]"
+ },
+ "osProfile": {
+ "computerName": "fe1",
+ "adminUsername": "[parameters('adminusername')]",
+ "linuxConfiguration": {
+ "disablePasswordAuthentication": true,
+ "ssh": {
+ "publicKeys": [
+ {
+ "keyData": "[parameters('sshKeyData')]",
+ "path": "[variables('sshKeyPath')]"
+ }
+ ]
+ }
+ }
+
+ },
+ "storageProfile": {
+ "imageReference": "[variables('imageReference')]",
+ "osDisk": {
+ "name": "FE1OSDisk",
+ "vhd": {
+ "uri": "[concat('http://', variables('cheffeName'), '.blob.', parameters('storageURL'), '/', variables('FEStorageAccountContainerName'), '/', 'FE1OSDisk', '.vhd')]"
+ },
+ "caching": "ReadWrite",
+ "createOption": "FromImage"
+ }
+ },
+ "networkProfile": {
+ "networkInterfaces": [
+ {
+ "id": "[resourceId('Microsoft.Network/networkInterfaces', 'FE1Nic')]"
+ }
+ ]
+ },
+ "availabilitySet": {
+ "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('ChefFEAvailName'))]"
+ }
+ },
+ "resources": [
+ {
+ "name": "FE1Setup",
+ "type": "extensions",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Compute/virtualMachines/', 'FE1')]",
+ "[resourceId('Microsoft.Compute/virtualMachines/extensions', 'FE0', 'FE0Setup')]"
+ ],
+ "tags": {
+ "displayName": "FE1Setup"
+ },
+ "properties": {
+ "publisher": "Microsoft.OSTCExtensions",
+ "type": "CustomScriptForLinux",
+ "typeHandlerVersion": "1.4",
+ "autoUpgradeMinorVersion": true,
+ "settings": {
+ "fileUris": [
+ "[concat(parameters('_artifactsLocation'), '/', variables('FEsetupscriptScriptFilePath'), parameters('_artifactsLocationSasToken'))]"
+ ]
+ },
+ "protectedSettings": {
+ "commandToExecute": "[concat('sh ', variables('FEsetupscriptScriptFileName'), ' \"', parameters('_artifactsLocation'), '\" \"', parameters('_artifactsLocationSasToken'), '\"')]"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "FE2Nic",
+ "type": "Microsoft.Network/networkInterfaces",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]",
+ "[concat('Microsoft.Network/loadBalancers/', variables('loadBalancerName'))]"
+ ],
+ "tags": {
+ "displayName": "FE2Nic"
+ },
+ "properties": {
+ "ipConfigurations": [
+ {
+ "name": "ipconfig1",
+ "properties": {
+ "privateIPAllocationMethod": "Static",
+ "subnet": {
+ "id": "[variables('SubnetRef')]"
+ },
+ "privateIPAddress": "10.0.0.52",
+ "loadBalancerBackendAddressPools": [
+ {
+ "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/backendAddressPools/', variables('bePoolName'))]"
+ }
+ ],
+ "loadBalancerInboundNatRules": [
+ {
+ "id": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Network/loadBalancers/', variables('loadBalancerName'), '/inboundNatRules/ssh-fe2')]"
+ }
+ ]
+
+ }
+ }
+ ]
+ }
+ },
+ {
+ "name": "FE2",
+ "type": "Microsoft.Compute/virtualMachines",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Storage/storageAccounts/', variables('cheffeName'))]",
+ "[concat('Microsoft.Network/networkInterfaces/', 'FE2Nic')]",
+ "[concat('Microsoft.Compute/availabilitySets/',variables('ChefFEAvailName'))]"
+ ],
+ "tags": {
+ "displayName": "FE2"
+ },
+ "properties": {
+ "hardwareProfile": {
+ "vmSize": "[parameters('chefFEvmSize')]"
+ },
+ "osProfile": {
+ "computerName": "fe2",
+ "adminUsername": "[parameters('adminusername')]",
+ "linuxConfiguration": {
+ "disablePasswordAuthentication": true,
+ "ssh": {
+ "publicKeys": [
+ {
+ "keyData": "[parameters('sshKeyData')]",
+ "path": "[variables('sshKeyPath')]"
+ }
+ ]
+ }
+ }
+
+ },
+ "storageProfile": {
+ "imageReference": "[variables('imageReference')]",
+ "osDisk": {
+ "name": "FE2OSDisk",
+ "vhd": {
+ "uri": "[concat('http://', variables('cheffeName'), '.blob.', parameters('storageURL'), '/', variables('FEStorageAccountContainerName'), '/', 'FE2OSDisk', '.vhd')]"
+ },
+ "caching": "ReadWrite",
+ "createOption": "FromImage"
+ }
+ },
+ "networkProfile": {
+ "networkInterfaces": [
+ {
+ "id": "[resourceId('Microsoft.Network/networkInterfaces', 'FE2Nic')]"
+ }
+ ]
+ },
+ "availabilitySet": {
+ "id": "[resourceId('Microsoft.Compute/availabilitySets',variables('ChefFEAvailName'))]"
+ }
+ },
+ "resources": [
+ {
+ "name": "FE2Setup",
+ "type": "extensions",
+ "location": "[variables('location')]",
+ "apiVersion": "2015-06-15",
+ "dependsOn": [
+ "[concat('Microsoft.Compute/virtualMachines/', 'FE2')]",
+ "[resourceId('Microsoft.Compute/virtualMachines/extensions', 'FE0', 'FE0Setup')]"
+ ],
+ "tags": {
+ "displayName": "FE2Setup"
+ },
+ "properties": {
+ "publisher": "Microsoft.OSTCExtensions",
+ "type": "CustomScriptForLinux",
+ "typeHandlerVersion": "1.4",
+ "autoUpgradeMinorVersion": true,
+ "settings": {
+ "fileUris": [
+ "[concat(parameters('_artifactsLocation'), '/', variables('FEsetupscriptScriptFilePath'), parameters('_artifactsLocationSasToken'))]"
+ ]
+ },
+ "protectedSettings": {
+ "commandToExecute": "[concat('sh ', variables('FEsetupscriptScriptFileName'), ' \"', parameters('_artifactsLocation'), '\" \"', parameters('_artifactsLocationSasToken'), '\"')]"
+ }
+ }
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/chef-ha-cluster/azuredeploy.parameters.json b/chef-ha-cluster/azuredeploy.parameters.json
new file mode 100644
index 000000000000..1d09ea8baeff
--- /dev/null
+++ b/chef-ha-cluster/azuredeploy.parameters.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "adminUsername": {
+ "value": "chefadmin"
+ },
+ "chefDNSName": {
+ "value": "GEN-UNIQUE-13"
+ },
+ "sshKeyData": {
+ "value": "GEN-SSH-PUB-KEY"
+ }
+ }
+}
\ No newline at end of file
diff --git a/chef-ha-cluster/metadata.json b/chef-ha-cluster/metadata.json
new file mode 100644
index 000000000000..b7fcd137ad79
--- /dev/null
+++ b/chef-ha-cluster/metadata.json
@@ -0,0 +1,7 @@
+{
+ "itemDisplayName": "Chef Backend High-Availability Cluster",
+ "description": "This template creates a chef-backend cluster with front-end nodes attached",
+ "summary": "This template creates a chef-backend cluster with front-end nodes attached",
+ "githubUsername": "n6udp",
+ "dateUpdated": "2016-09-18"
+}
diff --git a/chef-ha-cluster/scripts/BEFollowerSetup.sh b/chef-ha-cluster/scripts/BEFollowerSetup.sh
new file mode 100644
index 000000000000..af8c1473769d
--- /dev/null
+++ b/chef-ha-cluster/scripts/BEFollowerSetup.sh
@@ -0,0 +1,10 @@
+# BE Secondary
+curl -o chef-backend-secrets.json "$1/chef-backend-secrets.json$2"
+#wget https://packages.chef.io/stable/ubuntu/14.04/chef-backend_1.0.9-1_amd64.deb
+#dpkg -i chef-backend_1.0.9-1_amd64.deb
+apt-get install -y apt-transport-https
+wget -qO - https://downloads.chef.io/packages-chef-io-public.key | sudo apt-key add -
+echo "deb https://packages.chef.io/stable-apt trusty main" > /etc/apt/sources.list.d/chef-stable.list
+apt-get update
+apt-get install -y chef-backend
+chef-backend-ctl join-cluster 10.0.0.10 -p `ip addr | grep "inet 10" | tr -s ' ' ' ' | cut -d " " -f3 | cut -d"/" -f1` -s chef-backend-secrets.json --accept-license --yes --verbose --quiet
diff --git a/chef-ha-cluster/scripts/BELeaderSetup.sh b/chef-ha-cluster/scripts/BELeaderSetup.sh
new file mode 100644
index 000000000000..2db693743d16
--- /dev/null
+++ b/chef-ha-cluster/scripts/BELeaderSetup.sh
@@ -0,0 +1,17 @@
+# Primary BE setup
+#wget https://packages.chef.io/stable/ubuntu/14.04/chef-backend_1.0.9-1_amd64.deb
+#dpkg -i chef-backend_1.0.9-1_amd64.deb
+apt-get install -y apt-transport-https
+wget -qO - https://downloads.chef.io/packages-chef-io-public.key | sudo apt-key add -
+echo "deb https://packages.chef.io/stable-apt trusty main" > /etc/apt/sources.list.d/chef-stable.list
+apt-get update
+apt-get install -y chef-backend
+echo "publish_address '10.0.0.10'" >> /etc/chef-backend/chef-backend.rb
+chef-backend-ctl create-cluster --accept-license --yes --quiet --verbose
+curl --upload-file /etc/chef-backend/chef-backend-secrets.json "$1/chef-backend-secrets.json$2" --header "x-ms-blob-type: BlockBlob"
+chef-backend-ctl gen-server-config fe0 -f chef-server.rb.fe0
+curl --upload-file chef-server.rb.fe0 "$1/chef-server.rb.fe0$2" --header "x-ms-blob-type: BlockBlob"
+chef-backend-ctl gen-server-config fe1 -f chef-server.rb.fe1
+curl --upload-file chef-server.rb.fe1 "$1/chef-server.rb.fe1$2" --header "x-ms-blob-type: BlockBlob"
+chef-backend-ctl gen-server-config fe2 -f chef-server.rb.fe2
+curl --upload-file chef-server.rb.fe2 "$1/chef-server.rb.fe2$2" --header "x-ms-blob-type: BlockBlob"
\ No newline at end of file
diff --git a/chef-ha-cluster/scripts/FE0Setup.sh b/chef-ha-cluster/scripts/FE0Setup.sh
new file mode 100644
index 000000000000..417d2e3f9107
--- /dev/null
+++ b/chef-ha-cluster/scripts/FE0Setup.sh
@@ -0,0 +1,18 @@
+# First FE
+#wget https://packages.chef.io/stable/ubuntu/14.04/chef-server-core_12.8.0-1_amd64.deb
+#dpkg -i chef-server-core_12.8.0-1_amd64.deb
+apt-get install -y apt-transport-https
+wget -qO - https://downloads.chef.io/packages-chef-io-public.key | sudo apt-key add -
+echo "deb https://packages.chef.io/stable-apt trusty main" > /etc/apt/sources.list.d/chef-stable.list
+apt-get update
+apt-get install -y chef-server-core chef-manage
+curl -o /etc/opscode/chef-server.rb "$1/chef-server.rb.fe0$2"
+chef-server-ctl reconfigure
+curl --upload-file /etc/opscode/private-chef-secrets.json "$1/private-chef-secrets.json$2" --header "x-ms-blob-type: BlockBlob"
+curl --upload-file /etc/opscode/webui_priv.pem "$1/webui_priv.pem$2" --header "x-ms-blob-type: BlockBlob"
+curl --upload-file /etc/opscode/webui_pub.pem "$1/webui_pub.pem$2" --header "x-ms-blob-type: BlockBlob"
+curl --upload-file /etc/opscode/pivotal.pem "$1/pivotal.pem$2" --header "x-ms-blob-type: BlockBlob"
+curl --upload-file /var/opt/opscode/upgrades/migration-level "$1/migration-level$2" --header "x-ms-blob-type: BlockBlob"
+sudo chef-server-ctl install chef-manage
+sudo chef-server-ctl reconfigure
+sudo chef-manage-ctl reconfigure --accept-license
\ No newline at end of file
diff --git a/chef-ha-cluster/scripts/FESetup.sh b/chef-ha-cluster/scripts/FESetup.sh
new file mode 100644
index 000000000000..6a34e580eda6
--- /dev/null
+++ b/chef-ha-cluster/scripts/FESetup.sh
@@ -0,0 +1,20 @@
+# Other FEs
+#wget https://packages.chef.io/stable/ubuntu/14.04/chef-server-core_12.8.0-1_amd64.deb
+#dpkg -i chef-server-core_12.8.0-1_amd64.deb
+apt-get install -y apt-transport-https
+wget -qO - https://downloads.chef.io/packages-chef-io-public.key | sudo apt-key add -
+echo "deb https://packages.chef.io/stable-apt trusty main" > /etc/apt/sources.list.d/chef-stable.list
+apt-get update
+apt-get install -y chef-server-core chef-manage
+curl -o /etc/opscode/chef-server.rb "$1/chef-server.rb.`hostname`$2"
+curl -o /etc/opscode/private-chef-secrets.json "$1/private-chef-secrets.json$2"
+curl -o /etc/opscode/webui_priv.pem "$1/webui_priv.pem$2"
+curl -o /etc/opscode/webui_pub.pem "$1/webui_pub.pem$2"
+curl -o /etc/opscode/pivotal.pem "$1/pivotal.pem$2"
+mkdir -p /var/opt/opscode/upgrades/
+curl -o /var/opt/opscode/upgrades/migration-level "$1/migration-level$2"
+touch /var/opt/opscode/bootstrapped
+chef-server-ctl reconfigure
+sudo chef-server-ctl install chef-manage
+sudo chef-server-ctl reconfigure
+sudo chef-manage-ctl reconfigure --accept-license
\ No newline at end of file