From f92a0a4b3e05d06b044eefa18ba2c75a21083efb Mon Sep 17 00:00:00 2001 From: Lee Burton Date: Sun, 18 Sep 2016 03:31:29 -0700 Subject: [PATCH 1/4] Add chef-ha-cluster template --- chef-ha-cluster/README.md | 45 + chef-ha-cluster/azuredeploy.json | 1083 +++++++++++++++++++ chef-ha-cluster/azuredeploy.parameters.json | 15 + chef-ha-cluster/metadata.json | 7 + chef-ha-cluster/scripts/BEFollowerSetup.sh | 10 + chef-ha-cluster/scripts/BELeaderSetup.sh | 17 + chef-ha-cluster/scripts/FE0Setup.sh | 18 + chef-ha-cluster/scripts/FESetup.sh | 20 + 8 files changed, 1215 insertions(+) create mode 100644 chef-ha-cluster/README.md create mode 100644 chef-ha-cluster/azuredeploy.json create mode 100644 chef-ha-cluster/azuredeploy.parameters.json create mode 100644 chef-ha-cluster/metadata.json create mode 100644 chef-ha-cluster/scripts/BEFollowerSetup.sh create mode 100644 chef-ha-cluster/scripts/BELeaderSetup.sh create mode 100644 chef-ha-cluster/scripts/FE0Setup.sh create mode 100644 chef-ha-cluster/scripts/FESetup.sh diff --git a/chef-ha-cluster/README.md b/chef-ha-cluster/README.md new file mode 100644 index 000000000000..86cdffd4cd53 --- /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. +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..9a79f8baa9ae --- /dev/null +++ b/chef-ha-cluster/azuredeploy.json @@ -0,0 +1,1083 @@ +{ + "$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" + ] + }, + "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 + }, + "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" + ] + }, + "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 + }, + "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 From 8d24f32419412586caa55b81e4f0e19fb5534eb6 Mon Sep 17 00:00:00 2001 From: Lee Burton Date: Sun, 18 Sep 2016 03:38:47 -0700 Subject: [PATCH 2/4] Add chef-ha-cluster metadata descriptions --- chef-ha-cluster/azuredeploy.json | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/chef-ha-cluster/azuredeploy.json b/chef-ha-cluster/azuredeploy.json index 9a79f8baa9ae..f2a0d28a6e41 100644 --- a/chef-ha-cluster/azuredeploy.json +++ b/chef-ha-cluster/azuredeploy.json @@ -30,7 +30,10 @@ "Standard_GRS", "Standard_RAGRS", "Premium_LRS" - ] + ], + "metadata": { + "description": "Chef BE VM Storage Type must match chefBEvmSize" + } }, "chefBEvmSize": { "type": "string", @@ -60,7 +63,10 @@ "Standard_A4", "Standard_A5" ], - "minLength": 1 + "minLength": 1, + "metadata": { + "description": "Chef BE VM Size must match chefBEType" + } }, "chefDNSName": { "type": "string", @@ -79,7 +85,10 @@ "Standard_GRS", "Standard_RAGRS", "Premium_LRS" - ] + ], + "metadata": { + "description": "Chef FE VM Storage Type must match chefFEvmSize" + } }, "chefFEvmSize": { "type": "string", @@ -109,7 +118,10 @@ "Standard_A4", "Standard_A5" ], - "minLength": 1 + "minLength": 1, + "metadata": { + "description": "Chef FE VM Size must match chefFEType" + } }, "sshKeyData": { "type": "string", From 774fcf1644706aa6471f2c73445b2a3d1ec56732 Mon Sep 17 00:00:00 2001 From: Lee Burton Date: Sun, 18 Sep 2016 03:49:42 -0700 Subject: [PATCH 3/4] Add default URL for chef-ha-cluster artifacts --- chef-ha-cluster/azuredeploy.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/chef-ha-cluster/azuredeploy.json b/chef-ha-cluster/azuredeploy.json index f2a0d28a6e41..52d9c00f3c00 100644 --- a/chef-ha-cluster/azuredeploy.json +++ b/chef-ha-cluster/azuredeploy.json @@ -6,13 +6,15 @@ "type": "string", "metadata": { "description": "Auto-generated container in staging storage account to receive post-build staging folder upload" - } + }, + "defaultValue": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/chef-ha-cluster" }, "_artifactsLocationSasToken": { "type": "securestring", "metadata": { "description": "Auto-generated token to access _artifactsLocation" - } + }, + "defaultValue": "" }, "adminUsername": { "type": "string", From 4a7283bfd7fbe6bd529504a6591c83d2726bde83 Mon Sep 17 00:00:00 2001 From: Lee Burton Date: Tue, 20 Sep 2016 10:33:27 -0700 Subject: [PATCH 4/4] Skip CI for now as artifact write is a unsupported scenario and also remove default artifactlocation and add a note about the deploy button. --- chef-ha-cluster/.ci_skip | 0 chef-ha-cluster/README.md | 2 +- chef-ha-cluster/azuredeploy.json | 6 ++---- 3 files changed, 3 insertions(+), 5 deletions(-) create mode 100644 chef-ha-cluster/.ci_skip 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 index 86cdffd4cd53..61e92956b2b7 100644 --- a/chef-ha-cluster/README.md +++ b/chef-ha-cluster/README.md @@ -7,7 +7,7 @@ -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. +**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. diff --git a/chef-ha-cluster/azuredeploy.json b/chef-ha-cluster/azuredeploy.json index 52d9c00f3c00..f2a0d28a6e41 100644 --- a/chef-ha-cluster/azuredeploy.json +++ b/chef-ha-cluster/azuredeploy.json @@ -6,15 +6,13 @@ "type": "string", "metadata": { "description": "Auto-generated container in staging storage account to receive post-build staging folder upload" - }, - "defaultValue": "https://raw.githubusercontent.com/Azure/azure-quickstart-templates/master/chef-ha-cluster" + } }, "_artifactsLocationSasToken": { "type": "securestring", "metadata": { "description": "Auto-generated token to access _artifactsLocation" - }, - "defaultValue": "" + } }, "adminUsername": { "type": "string",