##
import base64
-from osm_ro_plugin import vimconn
import logging
-import netaddr
+from os import getenv
import re
-from os import getenv
+from azure.core.exceptions import ResourceNotFoundError
from azure.identity import ClientSecretCredential
-from azure.mgmt.resource import ResourceManagementClient
-from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.compute import ComputeManagementClient
-from azure.mgmt.compute.models import DiskCreateOption
-from azure.core.exceptions import ResourceNotFoundError
+from azure.mgmt.network import NetworkManagementClient
+from azure.mgmt.resource import ResourceManagementClient
from azure.profiles import ProfileDefinition
-from msrestazure.azure_exceptions import CloudError
+from cryptography.hazmat.backends import default_backend as crypto_default_backend
+from cryptography.hazmat.primitives import serialization as crypto_serialization
+from cryptography.hazmat.primitives.asymmetric import rsa
from msrest.exceptions import AuthenticationError
+from msrestazure.azure_exceptions import CloudError
import msrestazure.tools as azure_tools
+import netaddr
+from osm_ro_plugin import vimconn
from requests.exceptions import ConnectionError
-from cryptography.hazmat.primitives import serialization as crypto_serialization
-from cryptography.hazmat.primitives.asymmetric import rsa
-from cryptography.hazmat.backends import default_backend as crypto_default_backend
-
__author__ = "Isabel Lloret, Sergio Gonzalez, Alfonso Tierno, Gerardo Garcia"
__date__ = "$18-apr-2019 23:59:59$"
pdb.set_trace()
-class vimconnector(vimconn.VimConnector):
+def find_in_list(the_list, condition_lambda):
+ for item in the_list:
+ if condition_lambda(item):
+ return item
+ else:
+ return None
+
+class vimconnector(vimconn.VimConnector):
# Translate azure provisioning state to OSM provision state
# The first three ones are the transitional status once a user initiated action has been requested
# Once the operation is complete, it will transition into the states Succeeded or Failed
# Variable that indicates if client must be reloaded or initialized
self.reload_client = True
- self.vnet_address_space = None
+ self.vnet_address_space = []
# LOGGER
self.logger = logging.getLogger("ro.vim.azure")
else:
raise vimconn.VimConnException("Subscription not specified")
- # REGION
- if "region_name" in config:
- self.region = config.get("region_name")
- else:
- raise vimconn.VimConnException(
- "Azure region_name is not specified at config"
- )
-
# RESOURCE_GROUP
if "resource_group" in config:
self.resource_group = config.get("resource_group")
"Azure resource_group is not specified at config"
)
+ # REGION
+ if "region_name" in config:
+ self.region = config.get("region_name")
+ else:
+ raise vimconn.VimConnException(
+ "Azure region_name is not specified at config"
+ )
+
# VNET_NAME
if "vnet_name" in config:
self.vnet_name = config["vnet_name"]
+ # VNET_RESOURCE_GROUP
+ self.vnet_resource_group = config.get("vnet_resource_group")
+
# TODO - not used, do anything about it?
# public ssh key
self.pub_key = config.get("pub_key")
if "flavors_pattern" in config:
self._config["flavors_pattern"] = config["flavors_pattern"]
+ def _find_in_capabilities(self, capabilities, name):
+ cap = find_in_list(capabilities, lambda c: c["name"] == name)
+ if cap:
+ return cap.get("value")
+ else:
+ return None
+
def _reload_connection(self):
"""
Called before any operation, checks python azure clients
"""
try:
vnet = self.conn_vnet.virtual_networks.get(
- self.resource_group, self.vnet_name
+ self.vnet_resource_group or self.resource_group, self.vnet_name
)
- self.vnet_address_space = vnet.address_space.address_prefixes[0]
+ self.vnet_address_space = vnet.address_space.address_prefixes
self.vnet_id = vnet.id
return
except CloudError as e:
if e.error.error and "notfound" in e.error.error.lower():
- pass
+ self.logger.exception("CloudError Exception occured.")
# continue and create it
else:
self._format_vimconn_exception(e)
"location": self.region,
"address_space": {"address_prefixes": ["10.0.0.0/8"]},
}
- self.vnet_address_space = "10.0.0.0/8"
+ self.vnet_address_space = ["10.0.0.0/8"]
self.logger.debug("create base vnet: %s", self.vnet_name)
self.conn_vnet.virtual_networks.begin_create_or_update(
- self.resource_group, self.vnet_name, vnet_params
+ self.vnet_resource_group or self.resource_group,
+ self.vnet_name,
+ vnet_params,
)
vnet = self.conn_vnet.virtual_networks.get(
- self.resource_group, self.vnet_name
+ self.vnet_resource_group or self.resource_group, self.vnet_name
)
self.vnet_id = vnet.id
except Exception as e:
if ip_profile is None:
# get a non used vnet ip range /24 and allocate automatically inside the range self.vnet_address_space
used_subnets = self.get_network_list()
- for ip_range in netaddr.IPNetwork(self.vnet_address_space).subnet(24):
- for used_subnet in used_subnets:
- subnet_range = netaddr.IPNetwork(used_subnet["cidr_block"])
-
- if subnet_range in ip_range or ip_range in subnet_range:
- # this range overlaps with an existing subnet ip range. Breaks and look for another
+ for space in self.vnet_address_space:
+ for ip_range in netaddr.IPNetwork(space).subnet(24):
+ for used_subnet in used_subnets:
+ subnet_range = netaddr.IPNetwork(used_subnet["cidr_block"])
+
+ if subnet_range in ip_range or ip_range in subnet_range:
+ # this range overlaps with an existing subnet ip range. Breaks and look for another
+ break
+ else:
+ ip_profile = {"subnet_address": str(ip_range)}
+ self.logger.debug(
+ "dinamically obtained ip_profile: %s", ip_range
+ )
break
- else:
- ip_profile = {"subnet_address": str(ip_range)}
- self.logger.debug("dinamically obtained ip_profile: %s", ip_range)
+ if ip_profile is not None:
break
else:
raise vimconn.VimConnException(
self.logger.debug("creating subnet_name: {}".format(subnet_name))
async_creation = self.conn_vnet.subnets.begin_create_or_update(
- self.resource_group, self.vnet_name, subnet_name, subnet_params
+ self.vnet_resource_group or self.resource_group,
+ self.vnet_name,
+ subnet_name,
+ subnet_params,
)
async_creation.wait()
# TODO - do not wait here, check where it is used
Adds a prefix to the subnet_name with a number in case the indicated name is repeated
Checks subnets with the indicated name (without suffix) and adds a suffix with a number
"""
- all_subnets = self.conn_vnet.subnets.list(self.resource_group, self.vnet_name)
+ all_subnets = self.conn_vnet.subnets.list(
+ self.vnet_resource_group or self.resource_group, self.vnet_name
+ )
# Filter to subnets starting with the indicated name
subnets = list(
filter(lambda subnet: (subnet.name.startswith(subnet_name)), all_subnets)
return name
- def _create_nic(self, net, nic_name, static_ip=None, created_items={}):
+ def _create_nic(self, net, nic_name, region=None, static_ip=None, created_items={}):
self.logger.debug("create nic name %s, net_name %s", nic_name, net)
self._reload_connection()
subnet_id = net["net_id"]
- location = self._get_location_from_resource_group(self.resource_group)
+ location = self.region or self._get_location_from_resource_group(
+ self.resource_group
+ )
+
try:
net_ifz = {"location": location}
net_ip_config = {
self._reload_connection()
vnet = self.conn_vnet.virtual_networks.get(
- self.resource_group, self.vnet_name
+ self.vnet_resource_group or self.resource_group, self.vnet_name
)
subnet_list = []
start,
image_id,
flavor_id,
+ affinity_group_list,
net_list,
cloud_config=None,
disk_list=None,
# subnet_id=net["net_id"]
nic_name = vm_name + "-nic-" + str(idx)
vm_nic, nic_items = self._create_nic(
- net, nic_name, net.get("ip_address"), created_items
+ net, nic_name, self.region, net.get("ip_address"), created_items
)
vm_nics.append({"id": str(vm_nic.id)})
net["vim_id"] = vm_nic.id
virtual_machine = creation_result.result()
self.logger.debug("created vm name: %s", vm_name)
- """ Por ahora no hacer polling para ver si tarda menos
- # Add disks if they are provided
- if disk_list:
- for disk_index, disk in enumerate(disk_list):
- self.logger.debug(
- "add disk size: %s, image: %s",
- disk.get("size"),
- disk.get("image"),
- )
- self._add_newvm_disk(
- virtual_machine, vm_name, disk_index, disk, created_items
- )
-
- if start:
- self.conn_compute.virtual_machines.start(self.resource_group, vm_name)
- # start_result.wait()
- """
-
return virtual_machine.id, created_items
- # run_command_parameters = {
- # "command_id": "RunShellScript", # For linux, don't change it
- # "script": [
- # "date > /tmp/test.txt"
- # ]
- # }
except Exception as e:
# Rollback vm creacion
vm_id = None
self._format_vimconn_exception(e)
def _build_os_profile(self, vm_name, cloud_config, image_id):
-
# initial os_profile
os_profile = {"computer_name": vm_name}
def _get_azure_availability_zones(self):
return self.AZURE_ZONES
- def _add_newvm_disk(
- self, virtual_machine, vm_name, disk_index, disk, created_items={}
- ):
- disk_name = None
- data_disk = None
-
- # Check if must create empty disk or from image
- if disk.get("vim_id"):
- # disk already exists, just get
- parsed_id = azure_tools.parse_resource_id(disk.get("vim_id"))
- disk_name = parsed_id.get("name")
- data_disk = self.conn_compute.disks.get(self.resource_group, disk_name)
- else:
- disk_name = vm_name + "_DataDisk_" + str(disk_index)
- if not disk.get("image_id"):
- self.logger.debug("create new data disk name: %s", disk_name)
- async_disk_creation = self.conn_compute.disks.begin_create_or_update(
- self.resource_group,
- disk_name,
- {
- "location": self.region,
- "disk_size_gb": disk.get("size"),
- "creation_data": {"create_option": DiskCreateOption.empty},
- },
- )
- data_disk = async_disk_creation.result()
- created_items[data_disk.id] = True
- else:
- image_id = disk.get("image_id")
-
- if azure_tools.is_valid_resource_id(image_id):
- parsed_id = azure_tools.parse_resource_id(image_id)
-
- # Check if image is snapshot or disk
- image_name = parsed_id.get("name")
- type = parsed_id.get("resource_type")
-
- if type == "snapshots" or type == "disks":
- self.logger.debug("create disk from copy name: %s", image_name)
- # ¿Should check that snapshot exists?
- async_disk_creation = (
- self.conn_compute.disks.begin_create_or_update(
- self.resource_group,
- disk_name,
- {
- "location": self.region,
- "creation_data": {
- "create_option": "Copy",
- "source_uri": image_id,
- },
- },
- )
- )
- data_disk = async_disk_creation.result()
- created_items[data_disk.id] = True
- else:
- raise vimconn.VimConnNotFoundException(
- "Invalid image_id: %s ", image_id
- )
- else:
- raise vimconn.VimConnNotFoundException(
- "Invalid image_id: %s ", image_id
- )
-
- # Attach the disk created
- virtual_machine.storage_profile.data_disks.append(
- {
- "lun": disk_index,
- "name": disk_name,
- "create_option": DiskCreateOption.attach,
- "managed_disk": {"id": data_disk.id},
- "disk_size_gb": disk.get("size"),
- }
- )
- self.logger.debug("attach disk name: %s", disk_name)
- self.conn_compute.virtual_machines.begin_create_or_update(
- self.resource_group, virtual_machine.name, virtual_machine
- )
-
- # It is necesary extract from image_id data to create the VM with this format
- # "image_reference": {
- # "publisher": vm_reference["publisher"],
- # "offer": vm_reference["offer"],
- # "sku": vm_reference["sku"],
- # "version": vm_reference["version"]
- # },
def _get_image_reference(self, image_id):
try:
# The data input format example:
try:
self._reload_connection()
vm_sizes_list = [
- vm_size.serialize()
+ vm_size.as_dict()
for vm_size in self.conn_compute.resource_skus.list(
- "location={}".format(self.region)
+ filter="location eq '{}'".format(self.region)
)
]
numberInterfaces = len(filter_dict.get("interfaces", [])) or 0
# Filter
- if self._config.get("flavors_pattern"):
- filtered_sizes = [
- size
- for size in vm_sizes_list
- if size["capabilities"]["vCPUs"] >= cpus
- and size["capabilities"]["MemoryGB"] >= memMB / 1024
- and size["capabilities"]["MaxNetworkInterfaces"] >= numberInterfaces
- and re.search(self._config.get("flavors_pattern"), size["name"])
- ]
- else:
- filtered_sizes = [
- size
- for size in vm_sizes_list
- if size["capabilities"]["vCPUs"] >= cpus
- and size["capabilities"]["MemoryGB"] >= memMB / 1024
- and size["capabilities"]["MaxNetworkInterfaces"] >= numberInterfaces
- ]
+ filtered_sizes = []
+ for size in vm_sizes_list:
+ if size["resource_type"] == "virtualMachines":
+ size_cpus = int(
+ self._find_in_capabilities(size["capabilities"], "vCPUs")
+ )
+ size_memory = float(
+ self._find_in_capabilities(size["capabilities"], "MemoryGB")
+ )
+ size_interfaces = self._find_in_capabilities(
+ size["capabilities"], "MaxNetworkInterfaces"
+ )
+ if size_interfaces:
+ size_interfaces = int(size_interfaces)
+ else:
+ self.logger.debug(
+ "Flavor with no defined MaxNetworkInterfaces: {}".format(
+ size["name"]
+ )
+ )
+ continue
+ if (
+ size_cpus >= cpus
+ and size_memory >= memMB / 1024
+ and size_interfaces >= numberInterfaces
+ ):
+ if self._config.get("flavors_pattern"):
+ if re.search(
+ self._config.get("flavors_pattern"), size["name"]
+ ):
+ new_size = {
+ e["name"]: e["value"] for e in size["capabilities"]
+ }
+ new_size["name"] = size["name"]
+ filtered_sizes.append(new_size)
+ else:
+ new_size = {
+ e["name"]: e["value"] for e in size["capabilities"]
+ }
+ new_size["name"] = size["name"]
+ filtered_sizes.append(new_size)
# Sort
listedFilteredSizes = sorted(
filtered_sizes,
key=lambda k: (
- k["numberOfCores"],
- k["memoryInMB"],
- k["resourceDiskSizeInMB"],
+ int(k["vCPUs"]),
+ float(k["MemoryGB"]),
+ int(k["MaxNetworkInterfaces"]),
+ int(k["MaxResourceVolumeMB"]),
),
)
try:
self._reload_connection()
vm_sizes_list = [
- vm_size.serialize()
+ vm_size.as_dict()
for vm_size in self.conn_compute.resource_skus.list(
- "location={}".format(self.region)
+ filter="location eq '{}'".format(self.region)
)
]
def delete_network(self, net_id, created_items=None):
self.logger.debug(
- "deleting network {} - {}".format(self.resource_group, net_id)
+ "deleting network {} - {}".format(
+ self.vnet_resource_group or self.resource_group, net_id
+ )
)
self._reload_connection()
try:
# Obtain subnets ant try to delete nic first
subnet = self.conn_vnet.subnets.get(
- self.resource_group, self.vnet_name, res_name
+ self.vnet_resource_group or self.resource_group,
+ self.vnet_name,
+ res_name,
)
if not subnet:
raise vimconn.VimConnNotFoundException(
# Subnet API fails (CloudError: Azure Error: ResourceNotFound)
# Put the initial virtual_network API
async_delete = self.conn_vnet.subnets.begin_delete(
- self.resource_group, self.vnet_name, res_name
+ self.vnet_resource_group or self.resource_group,
+ self.vnet_name,
+ res_name,
)
async_delete.wait()
self._format_vimconn_exception(e)
def delete_inuse_nic(self, nic_name):
-
# Obtain nic data
nic_data = self.conn_vnet.network_interfaces.get(self.resource_group, nic_name)
# TODO - check if there is a public ip to delete and delete it
if network_interfaces:
-
# Deallocate the vm
async_vm_deallocate = (
self.conn_compute.virtual_machines.begin_deallocate(
nic_delete.wait()
self.logger.debug("deleted NIC name: %s", nic_name)
- def delete_vminstance(self, vm_id, created_items=None):
+ def delete_vminstance(self, vm_id, created_items=None, volumes_to_hold=None):
"""Deletes a vm instance from the vim."""
self.logger.debug(
"deleting VM instance {} - {}".format(self.resource_group, vm_id)
netName = self._get_net_name_from_resource_id(net_id)
resName = self._get_resource_name_from_resource_id(net_id)
- net = self.conn_vnet.subnets.get(self.resource_group, netName, resName)
+ net = self.conn_vnet.subnets.get(
+ self.vnet_resource_group or self.resource_group, netName, resName
+ )
out_nets[net_id] = {
"status": self.provision_state2osm[net.provisioning_state],
vm = self.conn_compute.virtual_machines.get(
self.resource_group, res_name
)
- out_vm["vim_info"] = str(vm)
+ img = vm.storage_profile.image_reference
+ images = self._get_version_image_list(
+ img.publisher, img.offer, img.sku, img.version
+ )
+ vim_info = {
+ "id": vm.id,
+ "name": vm.name,
+ "location": vm.location,
+ "provisioning_state": vm.provisioning_state,
+ "vm_id": vm.vm_id,
+ "type": vm.type,
+ "flavor": {"id": vm.hardware_profile.vm_size},
+ "image": images[0],
+ }
+ out_vm["vim_info"] = str(vim_info)
out_vm["status"] = self.provision_state2osm.get(
vm.provisioning_state, "OTHER"
)
self.logger.debug("Public ip address is: %s", public_ip.ip_address)
ips.append(public_ip.ip_address)
+ subnet = nic_data.ip_configurations[0].subnet.id
+ if subnet:
+ interface_dict["vim_net_id"] = subnet
+
private_ip = nic_data.ip_configurations[0].private_ip_address
ips.append(private_ip)
else:
return self._default_admin_user
+ def migrate_instance(self, vm_id, compute_host=None):
+ """
+ Migrate a vdu
+ param:
+ vm_id: ID of an instance
+ compute_host: Host to migrate the vdu to
+ """
+ # TODO: Add support for migration
+ raise vimconn.VimConnNotImplemented("Not implemented")
+
+ def resize_instance(self, vm_id, flavor_id=None):
+ """
+ resize a vdu
+ param:
+ vm_id: ID of an instance
+ flavor_id: flavor id to resize the vdu
+ """
+ # TODO: Add support for resize
+ raise vimconn.VimConnNotImplemented("Not implemented")
+
if __name__ == "__main__":
# Init logger
log_level=None,
config=config,
)
-
- """
- logger.debug("List images")
- image = azure.get_image_list({"name": "Canonical:UbuntuServer:18.04-LTS:18.04.201809110"})
- logger.debug("image: {}".format(image))
-
- logger.debug("List networks")
- network_list = azure.get_network_list({"name": "internal"})
- logger.debug("Network_list: {}".format(network_list))
-
- logger.debug("List flavors")
- flavors = azure.get_flavor_id_from_data({"vcpu": "2"})
- logger.debug("flavors: {}".format(flavors))
- """
-
- """
- # Create network and test machine
- #new_network_id, _ = azure.new_network("testnet1", "data")
- new_network_id = ("/subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/resourceGroups/{}/providers")
- "/Microsoft.Network/virtualNetworks/osm_vnet/subnets/testnet1"
- ).format(test_params["resource_group"])
- logger.debug("new_network_id: {}".format(new_network_id))
-
- logger.debug("Delete network")
- new_network_id = azure.delete_network(new_network_id)
- logger.debug("deleted network_id: {}".format(new_network_id))
- """
-
- """
- logger.debug("List networks")
- network_list = azure.get_network_list({"name": "internal"})
- logger.debug("Network_list: {}".format(network_list))
-
- logger.debug("Show machine isabelvm")
- vmachine = azure.get_vminstance( ("/subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/resourceGroups/{}"
- "/providers/Microsoft.Compute/virtualMachines/isabelVM"
- ).format(test_params["resource_group"])
- )
- logger.debug("Vmachine: {}".format(vmachine))
- """
-
- logger.debug("List images")
- image = azure.get_image_list({"name": "Canonical:UbuntuServer:16.04"})
- # image = azure.get_image_list({"name": "Canonical:UbuntuServer:18.04-LTS"})
- logger.debug("image: {}".format(image))
-
- """
- # Create network and test machine
- new_network_id, _ = azure.new_network("testnet1", "data")
- image_id = ("/Subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/Providers/Microsoft.Compute"
- "/Locations/northeurope/Publishers/Canonical/ArtifactTypes/VMImage/Offers/UbuntuServer"
- "/Skus/18.04-LTS/Versions/18.04.201809110")
- """
- """
-
- network_id = ("subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/resourceGroups/{}
- "/providers/Microsoft.Network/virtualNetworks/osm_vnet/subnets/internal"
- ).format(test_params["resource_group"])
- """
-
- """
- logger.debug("Create machine")
- image_id = ("/Subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/Providers/Microsoft.Compute/Locations"
- "/northeurope/Publishers/Canonical/ArtifactTypes/VMImage/Offers/UbuntuServer/Skus/18.04-LTS"
- "/Versions/18.04.202103151")
- cloud_config = {"user-data": (
- "#cloud-config\n"
- "password: osm4u\n"
- "chpasswd: { expire: False }\n"
- "ssh_pwauth: True\n\n"
- "write_files:\n"
- "- content: |\n"
- " # My new helloworld file\n\n"
- " owner: root:root\n"
- " permissions: '0644'\n"
- " path: /root/helloworld.txt",
- "key-pairs": [
- ("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/p7fuw/W0+6uhx9XNPY4dN/K2cXZweDfjJN8W/sQ1AhKvn"
- "j0MF+dbBdsd2tfq6XUhx5LiKoGTunRpRonOw249ivH7pSyNN7FYpdLaij7Krn3K+QRNEOahMI4eoqdglVftA3"
- "vlw4Oe/aZOU9BXPdRLxfr9hRKzg5zkK91/LBkEViAijpCwK6ODPZLDDUwY4iihYK9R5eZ3fmM4+3k3Jd0hPRk"
- "B5YbtDQOu8ASWRZ9iTAWqr1OwQmvNc6ohSVg1tbq3wSxj/5bbz0J24A7TTpY0giWctne8Qkl/F2e0ZSErvbBB"
- "GXKxfnq7sc23OK1hPxMAuS+ufzyXsnL1+fB4t2iF azureuser@osm-test-client\n"
- )]
- }
- network_id = ("subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/resourceGroups/{}/providers"
- "/Microsoft.Network/virtualNetworks/osm_vnet/subnets/internal"
- ).format(test_params["resource_group"])
- vm = azure.new_vminstance(name="isabelvm",
- description="testvm",
- start=True,
- image_id=image_id,
- flavor_id="Standard_B1ls",
- net_list = [{"net_id": network_id, "name": "internal", "use": "mgmt", "floating_ip":True}],
- cloud_config = cloud_config)
- logger.debug("vm: {}".format(vm))
- """
-
- """
- # Delete nonexistent vm
- try:
- logger.debug("Delete machine")
- vm_id = ("/subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/resourceGroups/{}/providers/Microsoft.Compute/"
- "virtualMachines/isabelvm"
- ).format(test_params["resource_group"])
- created_items = {
- ("/subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/resourceGroups/{}/providers/Microsoft.Network"
- "/networkInterfaces/isabelvm-nic-0"
- ).format(test_params["resource_group"]): True,
- ("/subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/resourceGroups/{}/providers/Microsoft.Network"
- "/publicIPAddresses/isabelvm-nic-0-public-ip"
- ).format(test_params["resource_group"]): True
- }
- azure.delete_vminstance(vm_id, created_items)
- except vimconn.VimConnNotFoundException as e:
- print("Ok: excepcion no encontrada")
- """
-
- """
- network_id = ("/subscriptions/5c1a2458-dfde-4adf-a4e3-08fa0e21d171/resourceGroups/{}/providers/Microsoft.Network"
- "/virtualNetworks/osm_vnet/subnets/hfcloudinit-internal-1"
- ).format(test_params["resource_group"])
- azure.delete_network(network_id)
- """