X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=RO-VIM-azure%2Fosm_rovim_azure%2Fvimconn_azure.py;h=06bc97031666e1a9c9a80c6cfb91032dacecc942;hb=HEAD;hp=68f77113cd3b75371b9ad7c805e6d486931411b8;hpb=89278b8df3845c0c1fa862ba9be8c635ce3bfa64;p=osm%2FRO.git diff --git a/RO-VIM-azure/osm_rovim_azure/vimconn_azure.py b/RO-VIM-azure/osm_rovim_azure/vimconn_azure.py index 68f77113..06bc9703 100755 --- a/RO-VIM-azure/osm_rovim_azure/vimconn_azure.py +++ b/RO-VIM-azure/osm_rovim_azure/vimconn_azure.py @@ -14,28 +14,26 @@ ## 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$" @@ -58,7 +56,6 @@ def find_in_list(the_list, condition_lambda): 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 @@ -206,7 +203,7 @@ class vimconnector(vimconn.VimConnector): # 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") @@ -249,6 +246,9 @@ class vimconnector(vimconn.VimConnector): 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") @@ -405,15 +405,15 @@ class vimconnector(vimconn.VimConnector): """ 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) @@ -424,14 +424,16 @@ class vimconnector(vimconn.VimConnector): "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: @@ -483,16 +485,21 @@ class vimconnector(vimconn.VimConnector): 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( @@ -511,7 +518,10 @@ class vimconnector(vimconn.VimConnector): 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 @@ -526,7 +536,9 @@ class vimconnector(vimconn.VimConnector): 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) @@ -551,6 +563,7 @@ class vimconnector(vimconn.VimConnector): location = self.region or self._get_location_from_resource_group( self.resource_group ) + try: net_ifz = {"location": location} net_ip_config = { @@ -816,7 +829,7 @@ class vimconnector(vimconn.VimConnector): 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 = [] @@ -855,6 +868,7 @@ class vimconnector(vimconn.VimConnector): start, image_id, flavor_id, + affinity_group_list, net_list, cloud_config=None, disk_list=None, @@ -941,32 +955,8 @@ class vimconnector(vimconn.VimConnector): 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 @@ -984,7 +974,6 @@ class vimconnector(vimconn.VimConnector): 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} @@ -1101,92 +1090,6 @@ class vimconnector(vimconn.VimConnector): 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: @@ -1242,7 +1145,7 @@ class vimconnector(vimconn.VimConnector): vm_sizes_list = [ vm_size.as_dict() for vm_size in self.conn_compute.resource_skus.list( - "location eq '{}'".format(self.region) + filter="location eq '{}'".format(self.region) ) ] @@ -1320,7 +1223,7 @@ class vimconnector(vimconn.VimConnector): vm_sizes_list = [ vm_size.as_dict() for vm_size in self.conn_compute.resource_skus.list( - "location eq '{}'".format(self.region) + filter="location eq '{}'".format(self.region) ) ] @@ -1360,7 +1263,9 @@ class vimconnector(vimconn.VimConnector): 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() @@ -1369,7 +1274,9 @@ class vimconnector(vimconn.VimConnector): 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( @@ -1388,7 +1295,9 @@ class vimconnector(vimconn.VimConnector): # 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() @@ -1409,7 +1318,6 @@ class vimconnector(vimconn.VimConnector): 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) @@ -1432,7 +1340,6 @@ class vimconnector(vimconn.VimConnector): # 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( @@ -1464,7 +1371,7 @@ class vimconnector(vimconn.VimConnector): 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) @@ -1801,7 +1708,9 @@ class vimconnector(vimconn.VimConnector): 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], @@ -1878,7 +1787,21 @@ class vimconnector(vimconn.VimConnector): 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" ) @@ -1958,6 +1881,10 @@ class vimconnector(vimconn.VimConnector): 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) @@ -1981,6 +1908,26 @@ class vimconnector(vimconn.VimConnector): 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 @@ -2035,128 +1982,3 @@ if __name__ == "__main__": 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({"vcpus": 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) - """