X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=blobdiff_plain;f=osm_ro%2Fvimconn_azure.py;h=24a9878d5c58ea93c0c585f47a7c5498125ce504;hp=88b50c5aa1d979cb0953cd85ae0e53846897c9f8;hb=deb74b2cd86e0b17ca4d37b1d0f4568b0246c681;hpb=3447855594c5874fbdd978a7cbc53cbf431f1a9c diff --git a/osm_ro/vimconn_azure.py b/osm_ro/vimconn_azure.py index 88b50c5a..24a9878d 100755 --- a/osm_ro/vimconn_azure.py +++ b/osm_ro/vimconn_azure.py @@ -14,6 +14,7 @@ from azure.mgmt.resource import ResourceManagementClient from azure.mgmt.network import NetworkManagementClient from azure.mgmt.compute import ComputeManagementClient + class vimconnector(vimconn.vimconnector): def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None, @@ -30,23 +31,23 @@ class vimconnector(vimconn.vimconnector): # CREDENTIALS self.credentials = ServicePrincipalCredentials( - client_id= user, - secret= passwd, - tenant= tenant_id + client_id=user, + secret=passwd, + tenant=(tenant_id or tenant_name) ) - - #SUBSCRIPTION + + # SUBSCRIPTION if 'subscription_id' in config: self.subscription_id = config.get('subscription_id') self.logger.debug('Setting subscription '+str(self.subscription_id)) else: raise vimconn.vimconnException('Subscription not specified') - #REGION + # 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 + # RESOURCE_GROUP if 'resource_group' in config: self.resource_group = config.get('resource_group') else: @@ -59,13 +60,17 @@ class vimconnector(vimconn.vimconnector): self.pub_key = config.get('pub_key') def _reload_connection(self): - '''Sets connections to work with Azure service APIs - ''' + """ + Sets connections to work with Azure service APIs + :return: + """ self.logger.debug('Reloading API Connection') try: self.conn = ResourceManagementClient(self.credentials, self.subscription_id) self.conn_compute = ComputeManagementClient(self.credentials, self.subscription_id) self.conn_vnet = NetworkManagementClient(self.credentials, self.subscription_id) + self._check_or_create_resource_group() + self._check_or_create_vnet() except Exception as e: self.format_vimconn_exception(e) @@ -79,29 +84,47 @@ class vimconnector(vimconn.vimconnector): return str(resource_id.split('/')[4]) def _check_subnets_for_vm(self, net_list): - #All subnets must belong to the same resource group and vnet - if len(set(self._get_resource_group_name_from_resource_id(net['id'])+self._get_resource_name_from_resource_id(net['id']) for net in net_list)) != 1: + # All subnets must belong to the same resource group and vnet + if len(set(self._get_resource_group_name_from_resource_id(net['id']) + + self._get_resource_name_from_resource_id(net['id']) for net in net_list)) != 1: raise self.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET') def format_vimconn_exception(self, e): - '''Params: an Exception object - Returns: Raises the exception 'e' passed in mehtod parameters - ''' + """ + Params: an Exception object + :param e: + :return: Raises the proper vimconnException + """ self.conn = None self.conn_vnet = None raise vimconn.vimconnConnectionException(type(e).__name__ + ': ' + str(e)) def _check_or_create_resource_group(self): - '''Creates a resource group in indicated region - ''' + """ + Creates a resource group in indicated region + :return: None + """ self.logger.debug('Creating RG {} in location {}'.format(self.resource_group, self.region)) - self.conn.resource_groups.create_or_update(self.resource_group, {'location':self.region}) + self.conn.resource_groups.create_or_update(self.resource_group, {'location': self.region}) + + def _check_or_create_vnet(self): + try: + vnet_params = { + 'location': self.region, + 'address_space': { + 'address_prefixes': "10.0.0.0/8" + }, + } + self.conn_vnet.virtual_networks.create_or_update(self.resource_group, self.vnet_name, vnet_params) + except Exception as e: + self.format_vimconn_exception(e) def new_network(self, net_name, net_type, ip_profile=None, shared=False, vlan=None): - '''Adds a tenant network to VIM - Params: - 'net_name': name of the network - 'ip_profile': is a dict containing the IP parameters of the network (Currently only IPv4 is implemented) + """ + Adds a tenant network to VIM + :param net_name: name of the network + :param net_type: + :param ip_profile: is a dict containing the IP parameters of the network (Currently only IPv4 is implemented) 'ip-version': can be one of ['IPv4','IPv6'] 'subnet-address': ip_prefix_schema, that is X.X.X.X/Y 'gateway-address': (Optional) ip_schema, that is X.X.X.X @@ -110,21 +133,26 @@ class vimconnector(vimconn.vimconnector): 'enabled': {'type': 'boolean'}, 'start-address': ip_schema, first IP to grant 'count': number of IPs to grant. - Returns a tuple with the network identifier and created_items, or raises an exception on error + :param shared: + :param vlan: + :return: a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same as not present. - ''' + """ + return self._new_subnet(net_name, ip_profile) def _new_subnet(self, net_name, ip_profile): - '''Adds a tenant network to VIM - It creates a new VNET with a single subnet - ''' + """ + Adds a tenant network to VIM. It creates a new VNET with a single subnet + :param net_name: + :param ip_profile: + :return: + """ self.logger.debug('Adding a subnet to VNET '+self.vnet_name) self._reload_connection() - self._check_or_create_resource_group() if ip_profile is None: # TODO get a non used vnet ip range /24 and allocate automatically @@ -187,8 +215,56 @@ class vimconnector(vimconn.vimconnector): return async_nic_creation.result() + def get_image_list(self, filter_dict={}): + """ + The urn contains for marketplace 'publisher:offer:sku:version' + + :param filter_dict: + :return: + """ + image_list = [] + + self._reload_connection() + if filter_dict.get("name"): + params = filter_dict["name"].split(":") + if len(params) >= 3: + publisher = params[0] + offer = params[1] + sku = params[2] + version = None + if len(params) == 4: + version = params[3] + images = self.conn_compute.virtual_machine_images.list(self.region, publisher, offer, sku) + for image in images: + if version: + image_version = str(image.id).split("/")[-1] + if image_version != version: + continue + image_list.append({ + 'id': str(image.id), + 'name': self._get_resource_name_from_resource_id(image.id) + }) + return image_list + + images = self.conn_compute.virtual_machine_images.list() + + for image in images: + # TODO implement filter_dict + if filter_dict: + if filter_dict.get("id") and str(image.id) != filter_dict["id"]: + continue + if filter_dict.get("name") and \ + self._get_resource_name_from_resource_id(image.id) != filter_dict["name"]: + continue + # TODO add checksum + image_list.append({ + 'id': str(image.id), + 'name': self._get_resource_name_from_resource_id(image.id), + }) + return image_list + def get_network_list(self, filter_dict={}): - '''Obtain tenant networks of VIM + """Obtain tenant networks of VIM Filter_dict can be: name: network name id: network uuid @@ -197,7 +273,7 @@ class vimconnector(vimconn.vimconnector): admin_state_up: boolean status: 'ACTIVE' Returns the network list of dictionaries - ''' + """ self.logger.debug('Getting all subnets from VIM') try: self._reload_connection() @@ -229,7 +305,8 @@ class vimconnector(vimconn.vimconnector): return self._new_vminstance(vm_name, image_id, flavor_id, net_list) - def _new_vminstance(self, vm_name, image_id, flavor_id, net_list, cloud_config=None, disk_list=None, availability_zone_index=None, availability_zone_list=None): + def _new_vminstance(self, vm_name, image_id, flavor_id, net_list, cloud_config=None, disk_list=None, + availability_zone_index=None, availability_zone_list=None): #Create NICs self._check_subnets_for_vm(net_list) vm_nics = [] @@ -292,27 +369,27 @@ class vimconnector(vimconn.vimconnector): self.format_vimconn_exception(e) def get_flavor_id_from_data(self, flavor_dict): - self.logger.debug("Getting flavor id from data") - self._reload_connection() - vm_sizes_list = [vm_size.serialize() for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region)] - - cpus = flavor_dict['vcpus'] - memMB = flavor_dict['ram'] - - filteredSizes = [size for size in vm_sizes_list if size['numberOfCores'] > cpus and size['memoryInMB'] > memMB] - listedFilteredSizes = sorted(filteredSizes, key=lambda k: k['numberOfCores']) - - return listedFilteredSizes[0]['name'] - - def check_vim_connectivity(): + self.logger.debug("Getting flavor id from data") + self._reload_connection() + vm_sizes_list = [vm_size.serialize() for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region)] + + cpus = flavor_dict['vcpus'] + memMB = flavor_dict['ram'] + + filteredSizes = [size for size in vm_sizes_list if size['numberOfCores'] > cpus and size['memoryInMB'] > memMB] + listedFilteredSizes = sorted(filteredSizes, key=lambda k: k['numberOfCores']) + + return listedFilteredSizes[0]['name'] + + def check_vim_connectivity(self): try: self._reload_connection() - return true - except: - raise vimconn.vimconnException("Connectivity issue with Azure API") + return True + except Exception as e: + raise vimconn.vimconnException("Connectivity issue with Azure API: {}".format(e)) def get_network(self, net_id): - resGroup= self._get_resource_group_name_from_resource_id(net_id) + resGroup = self._get_resource_group_name_from_resource_id(net_id) resName = self._get_resource_name_from_resource_id(net_id) self._reload_connection() @@ -321,21 +398,21 @@ class vimconnector(vimconn.vimconnector): return vnet def delete_network(self, net_id): - resGroup= self._get_resource_group_name_from_resource_id(net_id) + resGroup = self._get_resource_group_name_from_resource_id(net_id) resName = self._get_resource_name_from_resource_id(net_id) self._reload_connection() self.conn_vnet.virtual_networks.delete(resGroup, resName) def delete_vminstance(self, vm_id): - resGroup= self._get_resource_group_name_from_resource_id(net_id) + resGroup = self._get_resource_group_name_from_resource_id(net_id) resName = self._get_resource_name_from_resource_id(net_id) self._reload_connection() self.conn_compute.virtual_machines.delete(resGroup, resName) def get_vminstance(self, vm_id): - resGroup= self._get_resource_group_name_from_resource_id(net_id) + resGroup = self._get_resource_group_name_from_resource_id(net_id) resName = self._get_resource_name_from_resource_id(net_id) self._reload_connection() @@ -351,7 +428,6 @@ class vimconnector(vimconn.vimconnector): # TODO refresh_nets_status ver estado activo -# TODO PRIORITARY get_image_list # TODO refresh_vms_status ver estado activo # TODO get_vminstance_console for getting console @@ -361,13 +437,12 @@ if __name__ == "__main__": vim_id='azure' vim_name='azure' needed_test_params = { - "client_id": "AZURE_CLIENT_ID", # TODO delete private information - "secret": "AZURE_SECRET", # TODO delete private information - "tenant": "AZURE_TENANT", # TODO delete private information - "resource_group": "AZURE_RESOURCE_GROUP", # TODO delete private information # 'testOSMlive2', - # TODO maybe it should be created a resouce_group per VNFD - "subscription_id": "AZURE_SUBSCRIPTION_ID", # TODO delete private information 'ca3d18ab-d373-4afb-a5d6-7c44f098d16a' - "vnet_name": "AZURE_VNET_NAME", + "client_id": "AZURE_CLIENT_ID", + "secret": "AZURE_SECRET", + "tenant": "AZURE_TENANT", + "resource_group": "AZURE_RESOURCE_GROUP", + "subscription_id": "AZURE_SUBSCRIPTION_ID", + "vnet_name": "AZURE_VNET_NAME", } test_params = {} @@ -381,13 +456,13 @@ if __name__ == "__main__": 'region_name': getenv("AZURE_REGION_NAME", 'westeurope'), 'resource_group': getenv("AZURE_RESOURCE_GROUP"), 'subscription_id': getenv("AZURE_SUBSCRIPTION_ID"), - 'pub_key': getenv("AZURE_PUB_KEY", None), # TODO delete private information 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKlMlDqCEYmtD3NzHTzQXcu9Oj3U+CKYCU4D+kwEN5BuKs5J9lPFA9B2MsK9MYsyXoG4Gkt3ENHyzY+dgCN3eLdyiyOAtpHKddqO+5CG3mZoTlONTSofZm2pbnCoWh8UdKlBUvD467gFbw+HcBnXXY89zhdBIkhjQELcuZc0je8XsYrw++9DEJW9GBlREE8E/RustYlF5/MsNHvIxZqKNhBocX4Cj/nUdV+aGxTMa4pEnFi8gDA8xuYK9mDA/GNFd47TMa6kd+YLlojlfzp1GGDiwDK1px1TpjjzXan/dMMFbCsL5dgpuFul34U0yOdg7iEgoAUUwTGvHQsMyIl+BJ sergio@MININT-SCP2P2V', + 'pub_key': getenv("AZURE_PUB_KEY", None), 'vnet_name': getenv("AZURE_VNET_NAME", 'myNetwork'), } - + virtualMachine = { - 'name':'sergio', - 'description':'new VM', + 'name': 'sergio', + 'description': 'new VM', 'status': 'running', 'image': { 'publisher': 'Canonical', @@ -409,11 +484,12 @@ if __name__ == "__main__": } ########################### - azure=vimconnector(vim_id, vim_name, tenant_id=test_params["tenant"], tenant_name=None, url=None, url_admin=None, - user=test_params["client_id"], passwd=test_params["secret"], log_level=None, config=config) + azure = vimconnector(vim_id, vim_name, tenant_id=test_params["tenant"], tenant_name=None, url=None, url_admin=None, + user=test_params["client_id"], passwd=test_params["secret"], log_level=None, config=config) + + # azure.get_flavor_id_from_data("here") + # subnets=azure.get_network_list() + # azure.new_vminstance(virtualMachine['name'], virtualMachine['description'], virtualMachine['status'], + # virtualMachine['image'], virtualMachine['hardware_profile']['vm_size'], subnets) - #azure.get_flavor_id_from_data("here") - #subnets=azure.get_network_list() - #azure.new_vminstance(virtualMachine['name'], virtualMachine['description'], virtualMachine['status'], virtualMachine['image'], virtualMachine['hardware_profile']['vm_size'], subnets) - # azure.get_flavor("Standard_A11") \ No newline at end of file