azurehpc/pyazhpc/arm.py

882 строки
35 KiB
Python
Исходник Обычный вид История

2020-01-24 19:39:55 +03:00
import json
2020-02-07 01:07:16 +03:00
import sys
2020-02-03 20:06:42 +03:00
import uuid
2020-01-24 19:39:55 +03:00
2020-04-04 05:27:15 +03:00
import azlog
2020-02-07 22:18:20 +03:00
import azutil
2020-04-04 05:27:15 +03:00
log = azlog.getLogger(__name__)
2020-02-07 01:07:16 +03:00
2020-01-24 19:39:55 +03:00
class ArmTemplate:
def __init__(self):
self.parameters = {}
self.variables = {}
self.resources = []
self.outputs = {}
self.avsets = set()
2020-01-24 19:39:55 +03:00
2020-02-06 09:56:23 +03:00
def _add_network(self, cfg):
resource_group = cfg["resource_group"]
2020-04-04 11:43:15 +03:00
vnet_resource_group = cfg["vnet"].get("resource_group", resource_group)
if resource_group != vnet_resource_group:
log.debug(f"using an existing vnet in {vnet_resource_group}")
return
2020-01-25 06:54:44 +03:00
location = cfg["location"]
vnet_name = cfg["vnet"]["name"]
2020-02-04 11:55:19 +03:00
address_prefix = cfg["vnet"]["address_prefix"]
subnet_names = cfg["vnet"]["subnets"]
subnets = []
for subnet_name in subnet_names:
subnet_address_prefix = cfg["vnet"]["subnets"][subnet_name]
subnets.append({
"name": subnet_name,
"properties": {
"addressPrefix": subnet_address_prefix
}
})
2020-01-25 01:47:50 +03:00
res = {
"apiVersion": "2018-10-01",
"type": "Microsoft.Network/virtualNetworks",
"name": vnet_name,
"location": location,
"properties": {
"addressSpace": {
"addressPrefixes": [
address_prefix
]
2020-02-04 11:55:19 +03:00
},
"subnets": subnets
2020-02-07 01:07:16 +03:00
}
2020-01-25 01:47:50 +03:00
}
self.resources.append(res)
resource_group = cfg["resource_group"]
for peer_name in cfg["vnet"].get("peer", {}).keys():
peer_resource_group = cfg["vnet"]["peer"][peer_name]["resource_group"]
peer_vnet_name = cfg["vnet"]["peer"][peer_name]["vnet_name"]
self.resources.append({
"type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
"apiVersion": "2019-11-01",
"name": f"{vnet_name}/{peer_name}-{peer_resource_group}",
"properties": {
"remoteVirtualNetwork": {
"id": f"[resourceId('{peer_resource_group}', 'Microsoft.Network/virtualNetworks', '{peer_vnet_name}')]"
},
"allowVirtualNetworkAccess": True,
"allowForwardedTraffic": True,
"allowGatewayTransit": False,
"useRemoteGateways": False,
},
"dependsOn": [
f"Microsoft.Network/virtualNetworks/{vnet_name}"
]
})
self.resources.append({
"type": "Microsoft.Resources/deployments",
"apiVersion": "2017-05-10",
"name": f"{peer_resource_group}peer",
"resourceGroup": peer_resource_group,
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"type": "Microsoft.Network/virtualNetworks/virtualNetworkPeerings",
"apiVersion": "2019-11-01",
"name": f"{peer_vnet_name}/{peer_name}-{resource_group}",
"properties": {
"remoteVirtualNetwork": {
"id": f"[resourceId('{resource_group}', 'Microsoft.Network/virtualNetworks', '{vnet_name}')]"
},
"allowVirtualNetworkAccess": True,
"allowForwardedTraffic": True,
"allowGatewayTransit": False,
"useRemoteGateways": False
}
}
],
"outputs": {}
},
"parameters": {}
},
"dependsOn": [
f"Microsoft.Network/virtualNetworks/{vnet_name}"
]
})
2020-01-25 01:47:50 +03:00
2020-03-12 22:12:26 +03:00
# private dns
dns_domain = cfg["vnet"].get("dns_domain", None)
if dns_domain:
log.info(f"add private dns ({dns_domain})")
self.resources.append({
"type": "Microsoft.Network/privateDnsZones",
"apiVersion": "2018-09-01",
"name": dns_domain,
"location": "global",
"properties": {},
"resources": [{
"type": "Microsoft.Network/privateDnsZones/virtualNetworkLinks",
"apiVersion": "2018-09-01",
"name": f"[concat('{dns_domain}', '/{vnet_name}')]",
"location": "global",
"dependsOn": [
f"[resourceId('Microsoft.Network/privateDnsZones', '{dns_domain}')]"
],
"properties": {
"registrationEnabled": True,
"virtualNetwork": {
"id": f"[resourceId('Microsoft.Network/virtualNetworks', '{vnet_name}')]"
}
}
}]
})
2020-03-10 19:46:26 +03:00
# add route tables first (and keep track of mapping to subnet)
route_table_map = {}
for route_name in cfg["vnet"].get("routes", {}).keys():
2020-04-16 17:30:56 +03:00
# TODO : Why is this unused ?
2020-03-10 19:46:26 +03:00
route_address_prefix = cfg["vnet"]["routes"][route_name]["address_prefix"]
route_next_hop = cfg["vnet"]["routes"][route_name]["next_hop"]
route_subnet = cfg["vnet"]["routes"][route_name]["subnet"]
route_table_map[route_subnet] = route_name
self.resources.append({
"type": "Microsoft.Network/routeTables",
"apiVersion": "2019-11-01",
"name": route_name,
"location": location,
"properties": {
"disableBgpRoutePropagation": False,
"routes": [
{
"name": route_name,
"properties": {
"addressPrefix": "1.2.3.4/32",
"nextHopType": "VirtualAppliance",
"nextHopIpAddress": f"[reference('{route_next_hop}nic').ipConfigurations[0].properties.privateIPAddress]"
}
}
]
},
"dependsOn": [
f"Microsoft.Network/networkInterfaces/{route_next_hop}nic"
]
})
self.resources.append({
"type": "Microsoft.Network/routeTables/routes",
"apiVersion": "2019-11-01",
"name": f"{route_name}/{route_name}",
"dependsOn": [
f"[resourceId('Microsoft.Network/routeTables', '{route_name}')]"
],
"properties": {
"addressPrefix": "1.2.3.4/32",
"nextHopType": "VirtualAppliance",
"nextHopIpAddress": f"[reference('{route_next_hop}nic').ipConfigurations[0].properties.privateIPAddress]"
}
})
subnet_address_prefix = cfg["vnet"]["subnets"][route_subnet]
self.resources.append({
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2019-11-01",
"name": f"{vnet_name}/{route_subnet}",
"dependsOn": [
f"[resourceId('Microsoft.Network/routeTables', '{route_name}')]"
],
"properties": {
"addressPrefix": subnet_address_prefix,
"routeTable": {
"id": f"[resourceId('Microsoft.Network/routeTables', '{route_name}')]"
}
}
})
def _add_netapp(self, cfg, name, deploy_network):
2020-02-07 01:07:16 +03:00
account = cfg["storage"][name]
loc = cfg["location"]
vnet = cfg["vnet"]["name"]
subnet = account["subnet"]
nicdeps = []
rg = cfg["resource_group"]
vnetrg = cfg["vnet"].get("resource_group", rg)
if (rg == vnetrg) and deploy_network:
2020-02-07 01:07:16 +03:00
log.debug("adding delegation to subnet")
rvnet = next((x for x in self.resources if x["name"] == vnet), [])
rsubnet = next((x for x in rvnet["properties"]["subnets"] if x["name"] == subnet), None)
if not rsubnet:
log.error("subnet ({}) for netapp storage ({}) does not exist".format(subnet, name))
sys.exit(1)
if "delegations" not in rsubnet["properties"]:
rsubnet["properties"]["delegations"] = []
rsubnet["properties"]["delegations"].append({
"properties": {
"serviceName": "Microsoft.Netapp/volumes"
},
"name": "netappdelegation"
})
nicdeps.append("Microsoft.Network/virtualNetworks/"+vnet)
subnetid = "[resourceId('Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]".format(vnet, subnet)
else:
subnetid = "[resourceId('{}', 'Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]".format(vnetrg, vnet, subnet)
addomain = account.get("joindomain", None)
props = {}
if addomain:
2020-02-07 22:18:20 +03:00
adip = azutil.get_vm_private_ip(rg, account["ad_server"])
2020-02-07 01:07:16 +03:00
adpassword = account["ad_password"]
adusername = account["ad_username"]
# TODO: previously we used ip address for the dns here
props["activeDirectories"] = [
{
"username": adusername,
"password": adpassword,
"domain": addomain,
2020-02-07 22:18:20 +03:00
"dns": adip,
2020-02-07 01:07:16 +03:00
"smbServerName": "anf"
}
]
self.resources.append({
"name": name,
"type": "Microsoft.NetApp/netAppAccounts",
"apiVersion": "2019-07-01",
"location": loc,
"tags": {},
"properties": props,
"dependsOn": nicdeps
})
for poolname in account.get("pools", {}).keys():
pool = account["pools"][poolname]
poolsize = pool["size"]
servicelevel = pool["service_level"]
self.resources.append({
"name": name+"/"+poolname,
"type": "Microsoft.NetApp/netAppAccounts/capacityPools",
"apiVersion": "2019-07-01",
"location": loc,
"tags": {},
"properties": {
"size": poolsize * 2**40,
"serviceLevel": servicelevel
},
"dependsOn": [
"[resourceId('Microsoft.NetApp/netAppAccounts', '{}')]".format(name)
],
})
for volname in pool.get("volumes", {}).keys():
vol = pool["volumes"][volname]
volsize = vol["size"]
voltype = vol.get("type", "nfs")
2020-04-16 17:30:56 +03:00
# TODO : Why is this unused ?
2020-02-07 01:07:16 +03:00
volmount = vol["mount"]
netapp_volume = {
"name": name+"/"+poolname+"/"+volname,
"type": "Microsoft.NetApp/netAppAccounts/capacityPools/volumes",
"apiVersion": "2019-07-01",
"location": loc,
"tags": {},
"properties": {
"creationToken": volname,
"serviceLevel": servicelevel,
"usageThreshold": volsize * 2**40,
"subnetId": subnetid
},
"dependsOn": [
"[resourceId('Microsoft.NetApp/netAppAccounts/capacityPools', '{}', '{}')]".format(name, poolname)
]
}
if voltype == "cifs":
netapp_volume["properties"]["protocolTypes"] = [
2020-02-07 22:18:20 +03:00
"CIFS"
2020-02-07 01:07:16 +03:00
]
self.resources.append(netapp_volume)
2020-06-17 11:10:13 +03:00
def _add_storageaccount(self, cfg, name):
loc = cfg["location"]
res = {
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2019-06-01",
"name": name,
"location": loc,
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {
"accessTier": "Hot"
},
"resources": []
}
for container in cfg["storage"][name].get("containers", []):
res["resources"].append(
{
"type": "blobServices/containers",
"apiVersion": "2019-06-01",
"name": f"default/{container}",
"dependsOn": [
name
]
}
)
self.resources.append(res)
2020-02-06 09:56:23 +03:00
def _add_proximity_group(self, cfg):
ppg = cfg.get("proximity_placement_group_name", None)
if ppg:
loc = cfg["location"]
self.resources.append({
"apiVersion": "2018-04-01",
"type": "Microsoft.Compute/proximityPlacementGroups",
"name": ppg,
"location": loc
})
def __helper_arm_create_osprofile(self, rname, rtype, adminuser, adminpass, sshkey, customdata):
2020-02-05 18:34:35 +03:00
if rtype == "vm":
name = "computerName"
else:
name = "computerNamePrefix"
2020-02-05 18:34:35 +03:00
osprofile = {
name: rname,
"adminUsername": adminuser
}
if customdata:
if customdata.startswith("http"):
customdata = "#include\n" + customdata
2020-07-03 03:34:37 +03:00
osprofile["customData"] = "[base64('" + customdata + "')]"
2020-02-05 18:34:35 +03:00
if adminpass != "<no-password>":
osprofile["adminPassword"] = adminpass
else:
osprofile["linuxConfiguration"] = {
"disablePasswordAuthentication": True,
"ssh": {
"publicKeys": [
{
"keyData": sshkey,
"path": "/home/{}/.ssh/authorized_keys".format(adminuser)
}
]
}
}
return osprofile
2020-03-07 09:25:52 +03:00
def __helper_arm_create_datadisks(self, sizes, sku, cache):
2020-02-05 18:34:35 +03:00
datadisks = []
for i, d in enumerate(sizes):
if d < 4096:
2020-03-07 09:25:52 +03:00
cacheoption = cache
2020-02-05 18:34:35 +03:00
else:
cacheoption = "None"
2020-06-24 14:37:03 +03:00
if sku == "UltraSSD_LRS":
cacheoption = "None"
2020-02-05 18:34:35 +03:00
datadisks.append({
"caching": cacheoption,
"managedDisk": {
"storageAccountType": sku
},
"createOption": "Empty",
"lun": i,
"diskSizeGB": d
})
return datadisks
def __helper_arm_create_image_reference(self, refstr):
2020-04-09 21:00:02 +03:00
if ":" in refstr:
2020-04-09 03:09:19 +03:00
return {
"publisher": refstr.split(":")[0],
"offer": refstr.split(":")[1],
"sku": refstr.split(":")[2],
"version": refstr.split(":")[3]
}
else:
return {
2020-04-09 21:00:02 +03:00
"id": refstr
2020-02-05 18:34:35 +03:00
}
2020-04-06 16:26:11 +03:00
def __helper_arm_add_zones(self, res, zones):
strzones = []
if type(zones) == list:
for z in zones:
2020-04-06 16:26:11 +03:00
strzones.append(z)
elif zones != None:
strzones.append(str(zones))
if len(strzones) > 0:
res["zones"] = strzones
def _add_vm(self, cfg, r, vnet_in_deployment):
2020-01-25 06:54:44 +03:00
res = cfg["resources"][r]
2020-02-05 18:34:35 +03:00
rtype = res["type"]
2020-02-03 20:06:42 +03:00
rsize = res["vm_type"]
2020-01-25 06:54:44 +03:00
rimage = res["image"]
ros = rimage.split(':')
2020-02-05 11:59:25 +03:00
rinstances = res.get("instances", 1)
2020-01-25 06:54:44 +03:00
rpip = res.get("public_ip", False)
rppg = res.get("proximity_placement_group", False)
2020-02-06 09:56:23 +03:00
rppgname = cfg.get("proximity_placement_group_name", None)
2020-04-06 16:26:11 +03:00
raz = res.get("availability_zones", None)
2020-01-25 06:54:44 +03:00
rsubnet = res["subnet"]
ran = res.get("accelerated_networking", False)
rlowpri = res.get("low_priority", False)
2020-04-08 01:38:19 +03:00
rosdisksize = res.get("os_disk_size", None)
rosstoragesku = res.get("os_storage_sku", "Premium_LRS")
2020-02-05 11:59:25 +03:00
rdatadisks = res.get("data_disks", [])
rstoragesku = res.get("storage_sku", "Premium_LRS")
2020-03-07 09:25:52 +03:00
rstoragecache = res.get("storage_cache", "ReadWrite")
2020-03-14 04:44:31 +03:00
rtags = res.get("resource_tags", {})
2020-04-07 21:13:47 +03:00
rmanagedidentity = res.get("managed_identity", None)
2020-02-03 20:06:42 +03:00
loc = cfg["location"]
ravset = res.get("availability_set")
customdata = res.get("custom_data", None)
2020-02-03 20:06:42 +03:00
adminuser = cfg["admin_user"]
rrg = cfg["resource_group"]
vnetname = cfg["vnet"]["name"]
vnetrg = cfg["vnet"].get("resource_group", rrg)
if vnet_in_deployment:
2020-02-04 11:55:19 +03:00
rsubnetid = "[resourceId('Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]".format(vnetname, rsubnet)
else:
rsubnetid = "[resourceId('{}', 'Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]".format(vnetrg, vnetname, rsubnet)
2020-02-03 20:06:42 +03:00
rpassword = res.get("password", "<no-password>")
with open(adminuser+"_id_rsa.pub") as f:
sshkey = f.read().strip()
if ravset and ravset not in self.avsets:
2020-05-12 10:04:49 +03:00
arm_avset = {
"name": ravset,
2020-03-30 10:49:33 +03:00
"type": "Microsoft.Compute/availabilitySets",
"apiVersion": "2018-10-01",
"location": loc,
"sku": {
"name": "Aligned"
},
2020-03-30 10:49:33 +03:00
"properties": {
"platformUpdateDomainCount": 1,
"platformFaultDomainCount": 1
}
2020-05-12 10:04:49 +03:00
}
if rppg:
arm_avset["properties"]["proximityPlacementGroup"] = {
"id": f"[resourceId('Microsoft.Compute/proximityPlacementGroups','{rppgname}')]"
}
arm_avset["dependsOn"] = [
f"Microsoft.Compute/proximityPlacementGroups/{rppgname}"
]
self.resources.append(arm_avset)
self.avsets.add(ravset)
2020-03-30 10:49:33 +03:00
2020-02-05 11:59:25 +03:00
rorig = r
for instance in range(1, rinstances+1):
if rinstances > 1:
r = "{}{:04}".format(rorig, instance)
2020-02-03 20:06:42 +03:00
2020-02-05 18:34:35 +03:00
nicdeps = []
if vnet_in_deployment:
2020-02-05 18:34:35 +03:00
nicdeps.append("Microsoft.Network/virtualNetworks/"+vnetname)
2020-02-05 11:59:25 +03:00
if rpip:
pipname = r+"_pip"
2020-05-05 20:50:55 +03:00
dnsname = azutil.get_dns_label(rrg, pipname, True)
2020-05-06 13:16:48 +03:00
if dnsname:
log.debug(f"dns name: {dnsname} (using existing one)")
else:
2020-05-05 20:50:55 +03:00
dnsname = r+str(uuid.uuid4())[:6]
2020-05-06 13:16:48 +03:00
log.debug(f"dns name: {dnsname}")
nsgname = r+"_nsg"
2020-02-03 20:06:42 +03:00
2020-02-05 11:59:25 +03:00
nicdeps.append("Microsoft.Network/publicIpAddresses/"+pipname)
nicdeps.append("Microsoft.Network/networkSecurityGroups/"+nsgname)
pipres = {
2020-02-05 11:59:25 +03:00
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2018-01-01",
"name": pipname,
"location": loc,
"dependsOn": [],
"tags": {},
"properties": {
"dnsSettings": {
"domainNameLabel": dnsname
}
}
}
self.__helper_arm_add_zones(pipres, raz)
self.resources.append(pipres)
2020-02-05 11:59:25 +03:00
2020-05-16 19:23:52 +03:00
if ros[0] == "MicrosoftWindowsServer" or ros[0] == "MicrosoftWindowsDesktop":
self.resources.append({
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2015-06-15",
"name": nsgname,
"location": loc,
"dependsOn": [],
"tags": {},
"properties": {
"securityRules": [
{
"name": "default-allow-rdp",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "3389",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 1000,
"direction": "Inbound"
}
2020-02-05 11:59:25 +03:00
}
]
}
})
else:
self.resources.append({
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2015-06-15",
"name": nsgname,
"location": loc,
"dependsOn": [],
"tags": {},
"properties": {
"securityRules": [
{
"name": "default-allow-ssh",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 1000,
"direction": "Inbound"
}
}
]
}
})
2020-02-05 11:59:25 +03:00
nicname = r+"_nic"
ipconfigname = r+"_ipconfig"
2020-02-05 11:59:25 +03:00
nicprops = {
"ipConfigurations": [
{
"name": ipconfigname,
"properties": {
"privateIPAllocationMethod": "Dynamic",
"subnet": {
"id": rsubnetid
}
}
2020-02-03 20:06:42 +03:00
}
2020-02-05 11:59:25 +03:00
],
"enableAcceleratedNetworking": ran
}
if rpip:
nicprops["ipConfigurations"][0]["properties"]["publicIPAddress"] = {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', '{}')]".format(pipname)
}
nicprops["networkSecurityGroup"] = {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', '{}')]".format(nsgname)
2020-02-03 20:06:42 +03:00
}
self.resources.append({
2020-02-05 11:59:25 +03:00
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2016-09-01",
"name": nicname,
2020-02-03 20:06:42 +03:00
"location": loc,
2020-02-05 11:59:25 +03:00
"dependsOn": nicdeps,
2020-02-03 20:06:42 +03:00
"tags": {},
2020-02-05 11:59:25 +03:00
"properties": nicprops
2020-02-03 20:06:42 +03:00
})
osprofile = self.__helper_arm_create_osprofile(r, rtype, adminuser, rpassword, sshkey, customdata)
2020-03-07 09:25:52 +03:00
datadisks = self.__helper_arm_create_datadisks(rdatadisks, rstoragesku, rstoragecache)
2020-02-05 18:34:35 +03:00
imageref = self.__helper_arm_create_image_reference(rimage)
2020-02-03 20:06:42 +03:00
deps = [ f"Microsoft.Network/networkInterfaces/{nicname}" ]
2020-02-06 09:56:23 +03:00
if rppg:
deps.append(f"Microsoft.Compute/proximityPlacementGroups/{rppgname}")
2020-03-30 10:49:33 +03:00
if ravset:
deps.append(f"Microsoft.Compute/availabilitySets/{ravset}")
2020-02-06 09:56:23 +03:00
vmres = {
2020-02-05 11:59:25 +03:00
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2019-07-01",
"name": r,
"location": loc,
2020-02-06 09:56:23 +03:00
"dependsOn": deps,
2020-03-14 04:44:31 +03:00
"tags": rtags,
2020-02-05 11:59:25 +03:00
"properties": {
"hardwareProfile": {
"vmSize": rsize
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', '{}')]".format(nicname)
}
]
},
"storageProfile": {
"osDisk": {
"name": f"{r}_osdisk",
2020-02-05 11:59:25 +03:00
"createOption": "fromImage",
"caching": "ReadWrite",
"managedDisk": {
"storageAccountType": rosstoragesku
},
2020-02-03 20:06:42 +03:00
},
2020-02-05 18:34:35 +03:00
"imageReference": imageref,
2020-02-05 11:59:25 +03:00
"dataDisks": datadisks
2020-02-03 20:06:42 +03:00
},
2020-02-05 11:59:25 +03:00
"osProfile": osprofile
}
2020-02-06 09:56:23 +03:00
}
2020-02-05 11:59:25 +03:00
2020-03-09 17:09:33 +03:00
if rlowpri:
vmres["properties"]["priority"] = "Spot"
vmres["properties"]["evictionPolicy"] = "Deallocate"
2020-02-06 09:56:23 +03:00
if rppg:
vmres["properties"]["proximityPlacementGroup"] = {
2020-03-30 10:49:33 +03:00
"id": f"[resourceId('Microsoft.Compute/proximityPlacementGroups','{rppgname}')]"
2020-02-06 09:56:23 +03:00
}
2020-06-24 14:37:03 +03:00
if rstoragesku == "UltraSSD_LRS" :
vmres["properties"]["additionalCapabilities"] = { "ultraSSDEnabled": True }
2020-06-24 14:37:03 +03:00
2020-03-30 10:49:33 +03:00
if ravset:
vmres["properties"]["availabilitySet"] = {
"id": f"[resourceId('Microsoft.Compute/availabilitySets','{ravset}')]"
2020-03-30 10:49:33 +03:00
}
2020-04-08 01:50:19 +03:00
if rosdisksize:
vmres["properties"]["storageProfile"]["osDisk"]["diskSizeGb"] = rosdisksize
2020-04-07 21:13:47 +03:00
if rmanagedidentity is not None:
vmres["identity"] = {
"type": "SystemAssigned"
}
role_lookup = {
"reader": "[resourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
"contributor": "[resourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
"owner": "[resourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]"
}
role = rmanagedidentity.get("role", "reader")
if role not in role_lookup:
log.error(f"{role} is an invalid role for a managed identity (options are: {', '.join(role_lookup.keys())})")
sys.exit(1)
scope_lookup = {
"resource_group": "[resourceGroup().id]",
"subscription": "[subscription().subscriptionId]"
}
2020-04-06 21:41:11 +03:00
scope = rmanagedidentity.get("scope", "resource_group")
2020-04-07 21:13:47 +03:00
if scope not in scope_lookup:
log.error(f"{scope} is an invalid scope for a managed identity (options are: {', '.join(scope_lookup.keys())})")
sys.exit(1)
self.resources.append({
"apiVersion": "2017-09-01",
"type": "Microsoft.Authorization/roleAssignments",
"name": f"[guid(subscription().subscriptionId, resourceGroup().id, '{r}')]",
"properties": {
"roleDefinitionId": role_lookup[role],
"principalId": f"[reference('{r}', '2017-12-01', 'Full').identity.principalId]",
"scope": scope_lookup[scope]
},
"dependsOn": [
f"[resourceId('Microsoft.Compute/virtualMachines/', '{r}')]"
]
})
self.__helper_arm_add_zones(vmres, raz)
2020-02-06 09:56:23 +03:00
self.resources.append(vmres)
def _add_vmss(self, cfg, r, vnet_in_deployment):
2020-02-05 18:34:35 +03:00
res = cfg["resources"][r]
rtype = res["type"]
rsize = res["vm_type"]
rimage = res["image"]
rinstances = res.get("instances")
rppg = res.get("proximity_placement_group", False)
2020-02-06 09:56:23 +03:00
rppgname = cfg.get("proximity_placement_group_name", None)
2020-04-06 16:26:11 +03:00
raz = res.get("availability_zones", None)
2020-06-13 17:19:15 +03:00
rfaultdomaincount = res.get("fault_domain_count", 1)
2020-02-05 18:34:35 +03:00
rsubnet = res["subnet"]
ran = res.get("accelerated_networking", False)
rlowpri = res.get("low_priority", False)
2020-04-08 01:50:19 +03:00
rosdisksize = res.get("os_disk_size", None)
rosstoragesku = res.get("os_storage_sku", "Premium_LRS")
2020-02-05 18:34:35 +03:00
rdatadisks = res.get("data_disks", [])
rstoragesku = res.get("storage_sku", "Premium_LRS")
2020-03-07 09:25:52 +03:00
rstoragecache = res.get("storage_cache", "ReadWrite")
customdata = res.get("custom_data", None)
2020-02-05 18:34:35 +03:00
loc = cfg["location"]
adminuser = cfg["admin_user"]
rrg = cfg["resource_group"]
2020-03-14 04:44:31 +03:00
rtags = res.get("resource_tags", {})
2020-02-05 18:34:35 +03:00
vnetname = cfg["vnet"]["name"]
vnetrg = cfg["vnet"].get("resource_group", rrg)
if vnet_in_deployment:
2020-02-05 18:34:35 +03:00
rsubnetid = "[resourceId('Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]".format(vnetname, rsubnet)
else:
rsubnetid = "[resourceId('{}', 'Microsoft.Network/virtualNetworks/subnets', '{}', '{}')]".format(vnetrg, vnetname, rsubnet)
rpassword = res.get("password", "<no-password>")
with open(adminuser+"_id_rsa.pub") as f:
sshkey = f.read().strip()
deps = []
if vnet_in_deployment:
2020-02-05 18:34:35 +03:00
deps.append("Microsoft.Network/virtualNetworks/"+vnetname)
2020-02-06 09:56:23 +03:00
if rppg:
deps.append("Microsoft.Compute/proximityPlacementGroups/"+rppgname)
osprofile = self.__helper_arm_create_osprofile(r, rtype, adminuser, rpassword, sshkey, customdata)
2020-03-07 09:25:52 +03:00
datadisks = self.__helper_arm_create_datadisks(rdatadisks, rstoragesku, rstoragecache)
2020-02-05 18:34:35 +03:00
imageref = self.__helper_arm_create_image_reference(rimage)
nicname = r+"_nic"
ipconfigname = r+"_ipconfig"
2020-02-06 09:56:23 +03:00
vmssres = {
2020-02-05 18:34:35 +03:00
"type": "Microsoft.Compute/virtualMachineScaleSets",
"apiVersion": "2019-07-01",
"name": r,
"location": loc,
"dependsOn": deps,
2020-03-14 04:44:31 +03:00
"tags": rtags,
2020-02-05 18:34:35 +03:00
"sku": {
"name": rsize,
"capacity": rinstances
},
"properties": {
"overprovision": True,
"upgradePolicy": {
"mode": "manual"
},
"virtualMachineProfile": {
"storageProfile": {
"osDisk": {
"createOption": "FromImage",
"caching": "ReadWrite",
"managedDisk": {
"storageAccountType": rosstoragesku
},
},
"dataDisks": datadisks,
"imageReference": imageref
},
"osProfile": osprofile,
"networkProfile": {
"networkInterfaceConfigurations": [
{
"name": nicname,
"properties": {
"primary": "true",
"ipConfigurations": [
{
"name": ipconfigname,
"properties": {
"subnet": {
"id": rsubnetid
}
}
}
],
"enableAcceleratedNetworking": ran
}
}
]
}
},
2020-03-09 17:09:33 +03:00
"singlePlacementGroup": True
2020-02-05 18:34:35 +03:00
}
2020-02-06 09:56:23 +03:00
}
2020-03-09 17:09:33 +03:00
if rfaultdomaincount:
vmssres["properties"]["platformFaultDomainCount"] = rfaultdomaincount
2020-03-09 17:09:33 +03:00
2020-02-06 09:56:23 +03:00
if rppg:
vmssres["properties"]["proximityPlacementGroup"] = {
"id": "[resourceId('Microsoft.Compute/proximityPlacementGroups','{}')]".format(rppgname)
}
2020-03-09 17:09:33 +03:00
if rlowpri:
vmssres["properties"]["virtualMachineProfile"]["priority"] = "Spot"
vmssres["properties"]["virtualMachineProfile"]["evictionPolicy"] = "Delete"
2020-04-08 01:50:19 +03:00
if rosdisksize:
vmssres["properties"]["virtualMachineProfile"]["storageProfile"]["osDisk"]["diskSizeGb"] = rosdisksize
2020-04-06 16:26:11 +03:00
self.__helper_arm_add_zones(vmssres, raz)
2020-02-06 09:56:23 +03:00
self.resources.append(vmssres)
2020-02-05 18:34:35 +03:00
2020-01-25 06:54:44 +03:00
def read_resources(self, cfg, vnet_in_deployment):
2020-02-07 01:07:16 +03:00
resources = cfg.get("resources", {})
2020-01-25 06:54:44 +03:00
for r in resources.keys():
rtype = cfg["resources"][r]["type"]
if rtype == "vm":
self._add_vm(cfg, r, vnet_in_deployment)
2020-02-05 18:34:35 +03:00
elif rtype == "vmss":
self._add_vmss(cfg, r, vnet_in_deployment)
elif rtype == "slurm_partition":
pass
2020-02-07 01:07:16 +03:00
else:
log.error("unrecognised resource type ({}) for {}".format(rtype, r))
def has_resources(self):
return len(self.resources) > 0
def read(self, cfg, deploy_network):
rg = cfg["resource_group"]
2020-04-27 14:02:25 +03:00
vnetrg = cfg["vnet"].get("resource_group", rg)
vnet_in_deployment = bool(rg == vnetrg) and deploy_network
if deploy_network:
self._add_network(cfg)
self._add_proximity_group(cfg)
self.read_resources(cfg, vnet_in_deployment)
2020-02-07 01:07:16 +03:00
storage = cfg.get("storage", {})
for s in storage.keys():
stype = cfg["storage"][s]["type"]
if stype == "anf":
self._add_netapp(cfg, s, deploy_network)
2020-06-17 11:10:13 +03:00
elif stype == "storageaccount":
self._add_storageaccount(cfg, s)
2020-02-07 01:07:16 +03:00
else:
log.error("unrecognised storage type ({}) for {}".format(stype, s))
2020-03-10 19:46:26 +03:00
2020-01-24 19:39:55 +03:00
def to_json(self):
return json.dumps({
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": self.parameters,
"variables": self.variables,
"resources": self.resources,
"outputs": self.outputs
}, indent=4)