{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "vnetName": {
      "type": "string",
      "defaultValue": "vnet01",
      "metadata": {
        "description": "Name of new vnet to deploy into."
      }
    },
    "vnetAddressRange": {
      "type": "string",
      "defaultValue": "10.0.0.0/16",
      "metadata": {
        "description": "IP prefix for available addresses in vnet address space."
      }
    },
    "subnetAddressRange": {
      "type": "string",
      "defaultValue": "10.0.0.0/24",
      "metadata": {
        "description": "Subnet IP prefix MUST be within vnet IP prefix address space."
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources."
      }
    },
    "adminPublicKey": {
      "type": "string",
      "metadata": {
        "description": "The ssh public key for the VMs."
      }
    },
    "sizeOfDiskInGB": {
      "type": "int",
      "defaultValue": 128,
      "minValue": 128,
      "maxValue": 1024,
      "metadata": {
        "description": "Size of data disk in GB 128-1024"
      }
    },
    "vmSize": {
      "type": "string",
      "defaultValue": "Standard_D2s_v3",
      "metadata": {
        "description": "Size of the VMs"
      }
    },
    "numberOfArtifactory": {
      "type": "int",
      "defaultValue": 1,
      "minValue": 1,
      "maxValue": 5,
      "metadata": {
        "description": "Number of Artifactory servers."
      }
    },
    "numberOfXray": {
      "type": "int",
      "defaultValue": 1,
      "minValue": 1,
      "maxValue": 5,
      "metadata": {
        "description": "Number of Xray servers."
      }
    },
    "numberOfDb": {
      "type": "int",
      "defaultValue": 1,
      "minValue": 1,
      "maxValue": 2,
      "metadata": {
        "description": "Number of database servers."
      }
    }
  },
  "variables": {
    "vnetName": "[parameters('vnetName')]",
    "vnetAddressRange": "[parameters('vnetAddressRange')]",
    "subnetAddressRange": "[parameters('subnetAddressRange')]",
    "subnetName": "mainSubnet",
    "loadBalancerName": "LB",
    "loadBalancerIp": "lbIp",
    "numberOfArtifactory": "[parameters('numberOfArtifactory')]",
    "numberOfXray": "[parameters('numberOfXray')]",
    "numberOfDb": "[parameters('numberOfDb')]",
    "availabilitySetName": "availSet",
    "vmArtPri": "vmArtPri",
    "vmArtSec": "vmArtSec",
    "vmXray": "vmXray",
    "vmDb": "vmDb",
    "storageAccountNameDiag": "[concat('diag',uniqueString(resourceGroup().id))]",
    "subnet-id": "[resourceId('Microsoft.Network/virtualNetworks/subnets',variables('vnetName'),variables('subnetName'))]",
    "imagePublisher": "Canonical",
    "imageOffer": "UbuntuServer",
    "imageSku": "16.04-LTS",
    "mainNsg": "mainNsg",
    "adminUsername": "ubuntu"
  },
  "resources": [
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[variables('loadBalancerIp')]",
      "location": "[parameters('location')]",
      "properties": {
        "publicIPAllocationMethod": "Static"
      }
    },
    {
      "type": "Microsoft.Compute/availabilitySets",
      "name": "[variables('availabilitySetName')]",
      "apiVersion": "2019-12-01",
      "location": "[parameters('location')]",
      "sku": {
        "name": "Aligned"
      },
      "properties": {
        "platformFaultDomainCount": 2,
        "platformUpdateDomainCount": 2
      }
    },
    {
      "apiVersion": "2019-06-01",
      "type": "Microsoft.Storage/storageAccounts",
      "name": "[variables('storageAccountNameDiag')]",
      "location": "[parameters('location')]",
      "kind": "StorageV2",
      "sku": {
        "name": "Standard_LRS"
      }
    },
    {
      "comments": "Simple Network Security Group for subnet [Subnet]",
      "type": "Microsoft.Network/networkSecurityGroups",
      "apiVersion": "2019-08-01",
      "name": "[variables('mainNsg')]",
      "location": "[parameters('location')]",
      "properties": {
        "securityRules": [
          {
            "name": "allow-ssh",
            "properties": {
              "description": "Allow SSH",
              "protocol": "TCP",
              "sourcePortRange": "*",
              "destinationPortRange": "22",
              "sourceAddressPrefix": "*",
              "destinationAddressPrefix": "*",
              "access": "Allow",
              "priority": 100,
              "direction": "Inbound",
              "sourcePortRanges": [],
              "destinationPortRanges": [],
              "sourceAddressPrefixes": [],
              "destinationAddressPrefixes": []
            }
          },
          {
            "name": "allow-http",
            "properties": {
              "description": "Allow HTTP",
              "protocol": "TCP",
              "sourcePortRange": "*",
              "destinationPortRange": "80",
              "sourceAddressPrefix": "*",
              "destinationAddressPrefix": "*",
              "access": "Allow",
              "priority": 110,
              "direction": "Inbound",
              "sourcePortRanges": [],
              "destinationPortRanges": [],
              "sourceAddressPrefixes": [],
              "destinationAddressPrefixes": []
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Network/virtualNetworks",
      "name": "[variables('vnetName')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mainNsg'))]"
      ],
      "properties": {
        "addressSpace": {
          "addressPrefixes": [
            "[variables('vnetAddressRange')]"
          ]
        },
        "subnets": [
          {
            "name": "[variables('subnetName')]",
            "properties": {
              "addressPrefix": "[variables('subnetAddressRange')]",
              "networkSecurityGroup": {
                "id": "[resourceId('Microsoft.Network/networkSecurityGroups', variables('mainNsg'))]"
              }
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2018-10-01",
      "name": "[variables('loadBalancerName')]",
      "type": "Microsoft.Network/loadBalancers",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/publicIPAddresses/',variables('loadBalancerIp'))]"
      ],
      "properties": {
        "frontendIpConfigurations": [
          {
            "name": "LBFE",
            "properties": {
              "publicIPAddress": {
                "id": "[resourceId('Microsoft.Network/publicIPAddresses',variables('loadBalancerIp'))]"
              }
            }
          }
        ],
        "backendAddressPools": [
          {
            "name": "LBArt"
          }
        ],
        "inboundNatRules": [
          {
            "name": "ssh",
            "properties": {
              "frontendIPConfiguration": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations',variables('loadBalancerName'),'LBFE')]"
              },
              "frontendPort": 22,
              "backendPort": 22,
              "enableFloatingIP": false,
              "idleTimeoutInMinutes": 4,
              "protocol": "Tcp",
              "enableTcpReset": false
            }
          }
        ],
        "loadBalancingRules": [
          {
            "properties": {
              "frontendIPConfiguration": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/frontendIPConfigurations', variables('loadBalancerName'), 'LBFE')]"
              },
              "backendAddressPool": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools', variables('loadBalancerName'), 'LBArt')]"
              },
              "probe": {
                "id": "[resourceId('Microsoft.Network/loadBalancers/probes', variables('loadBalancerName'), 'lbprobe')]"
              },
              "protocol": "Tcp",
              "frontendPort": 80,
              "backendPort": 80,
              "idleTimeoutInMinutes": 15
            },
            "name": "lbrule"
          }
        ],
        "probes": [
          {
            "properties": {
              "protocol": "Tcp",
              "port": 80,
              "intervalInSeconds": 15,
              "numberOfProbes": 2
            },
            "name": "lbprobe"
          }
        ]
      }
    },
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[variables('vmArtPri')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[variables('vnetName')]",
        "[variables('loadBalancerName')]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnet-id')]"
              },
              "loadBalancerBackendAddressPools": [
                {
                  "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools',variables('loadBalancerName'),'LBArt')]"
                }
              ],
              "loadBalancerInboundNatRules": [
                {
                  "id": "[resourceId('Microsoft.Network/loadBalancers/inboundNatRules', variables('loadBalancerName'), 'ssh')]"
                }
              ]
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat(variables('vmArtSec'),copyindex())]",
      "copy": {
        "name": "netIntLoop",
        "count": "[sub(variables('numberOfArtifactory'),1)]"
      },
      "location": "[parameters('location')]",
      "dependsOn": [
        "[variables('vnetName')]",
        "[variables('loadBalancerName')]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnet-id')]"
              },
              "loadBalancerBackendAddressPools": [
                {
                  "id": "[resourceId('Microsoft.Network/loadBalancers/backendAddressPools',variables('loadBalancerName'),'LBArt')]"
                }
              ]
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat(variables('vmXray'),copyindex())]",
      "copy": {
        "name": "netXrLoop",
        "count": "[variables('numberOfXray')]"
      },
      "location": "[parameters('location')]",
      "dependsOn": [
        "[variables('vnetName')]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnet-id')]"
              }
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2019-08-01",
      "type": "Microsoft.Network/networkInterfaces",
      "name": "[concat(variables('vmDb'),copyindex())]",
      "copy": {
        "name": "netDbLoop",
        "count": "[variables('numberOfDb')]"
      },
      "location": "[parameters('location')]",
      "dependsOn": [
        "[variables('vnetName')]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "ipconfig",
            "properties": {
              "privateIPAllocationMethod": "Dynamic",
              "subnet": {
                "id": "[variables('subnet-id')]"
              }
            }
          }
        ]
      }
    },
    {
      "apiVersion": "2019-12-01",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[variables('vmArtPri')]",
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameDiag'))]",
        "[resourceId('Microsoft.Network/networkInterfaces', variables('vmArtPri'))]",
        "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
      ],
      "properties": {
        "availabilitySet": {
          "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
        },
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[variables('vmArtPri')]",
          "adminUsername": "[variables('adminUsername')]",
          "linuxConfiguration": {
            "disablePasswordAuthentication": true,
            "ssh": {
              "publicKeys": [
                {
                  "path": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]",
                  "keyData": "[parameters('adminPublicKey')]"
                }
              ]
            }
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[variables('imageSku')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',variables('vmArtPri'))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[reference(variables('storageAccountNameDiag'), '2019-06-01').primaryEndpoints.blob]"
          }
        }
      }
    },
    {
      "apiVersion": "2019-12-01",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[concat(variables('vmArtSec'), copyindex())]",
      "copy": {
        "name": "virtualMachineLoop",
        "count": "[sub(variables('numberOfArtifactory'),1)]"
      },
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameDiag'))]",
        "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmArtSec'),copyindex()))]",
        "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
      ],
      "properties": {
        "availabilitySet": {
          "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
        },
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[concat(variables('vmArtSec'), copyindex())]",
          "adminUsername": "[variables('adminUsername')]",
          "linuxConfiguration": {
            "disablePasswordAuthentication": true,
            "ssh": {
              "publicKeys": [
                {
                  "path": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]",
                  "keyData": "[parameters('adminPublicKey')]"
                }
              ]
            }
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[variables('imageSku')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('vmArtSec'),copyindex()))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[reference(variables('storageAccountNameDiag'), '2019-06-01').primaryEndpoints.blob]"
          }
        }
      }
    },
    {
      "apiVersion": "2019-12-01",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[concat(variables('vmXray'), copyindex())]",
      "copy": {
        "name": "virtualMachineLoop",
        "count": "[variables('numberOfXray')]"
      },
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameDiag'))]",
        "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmXray'),copyindex()))]",
        "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
      ],
      "properties": {
        "availabilitySet": {
          "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
        },
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[concat(variables('vmXray'), copyindex())]",
          "adminUsername": "[variables('adminUsername')]",
          "linuxConfiguration": {
            "disablePasswordAuthentication": true,
            "ssh": {
              "publicKeys": [
                {
                  "path": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]",
                  "keyData": "[parameters('adminPublicKey')]"
                }
              ]
            }
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[variables('imageSku')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('vmXray'),copyindex()))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[reference(variables('storageAccountNameDiag'), '2019-06-01').primaryEndpoints.blob]"
          }
        }
      }
    },
    {
      "apiVersion": "2019-12-01",
      "type": "Microsoft.Compute/virtualMachines",
      "name": "[concat(variables('vmDb'), copyindex())]",
      "copy": {
        "name": "virtualMachineLoop",
        "count": "[variables('numberOfDb')]"
      },
      "location": "[parameters('location')]",
      "dependsOn": [
        "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountNameDiag'))]",
        "[resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmDb'),copyindex()))]",
        "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
      ],
      "properties": {
        "availabilitySet": {
          "id": "[resourceId('Microsoft.Compute/availabilitySets', variables('availabilitySetName'))]"
        },
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "computerName": "[concat(variables('vmDb'), copyindex())]",
          "adminUsername": "[variables('adminUsername')]",
          "linuxConfiguration": {
            "disablePasswordAuthentication": true,
            "ssh": {
              "publicKeys": [
                {
                  "path": "[concat('/home/', variables('adminUsername'), '/.ssh/authorized_keys')]",
                  "keyData": "[parameters('adminPublicKey')]"
                }
              ]
            }
          }
        },
        "storageProfile": {
          "imageReference": {
            "publisher": "[variables('imagePublisher')]",
            "offer": "[variables('imageOffer')]",
            "sku": "[variables('imageSku')]",
            "version": "latest"
          },
          "osDisk": {
            "createOption": "FromImage"
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[resourceId('Microsoft.Network/networkInterfaces',concat(variables('vmDb'),copyindex()))]"
            }
          ]
        },
        "diagnosticsProfile": {
          "bootDiagnostics": {
            "enabled": true,
            "storageUri": "[reference(variables('storageAccountNameDiag'), '2019-06-01').primaryEndpoints.blob]"
          }
        }
      }
    }
  ],
  "outputs": {
    "lbIp": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.Network/publicIPAddresses', variables('loadBalancerIp'))).ipAddress]"
    },
    "vmArtPriIp": {
      "type": "string",
      "value": "[reference(resourceId('Microsoft.Network/networkInterfaces', variables('vmArtPri'))).ipConfigurations[0].properties.privateIPAddress]"
    },
    "vmArtSecArrIp": {
      "type": "array",
      "copy": {
        "count": "[sub(variables('numberOfArtifactory'),1)]",
        "input": "[reference(resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmArtSec'),copyindex()))).ipConfigurations[0].properties.privateIPAddress]"
      }
    },
    "vmXrayArrIp": {
      "type": "array",
      "copy": {
        "count": "[variables('numberOfXray')]",
        "input": "[reference(resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmXray'),copyindex()))).ipConfigurations[0].properties.privateIPAddress]"
      }
    },
    "vmDbArrIp": {
      "type": "array",
      "copy": {
        "count": "[variables('numberOfDb')]",
        "input": "[reference(resourceId('Microsoft.Network/networkInterfaces', concat(variables('vmDb'),copyindex()))).ipConfigurations[0].properties.privateIPAddress]"
      }
    }
  }
}