From: jamartinezv Date: Thu, 1 Aug 2019 09:45:15 +0000 (+0200) Subject: Azure Connector Improvemets X-Git-Tag: v7.0.0rc1~15^2~3 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=commitdiff_plain;h=14a823d1da13f3a9890ae0ae2b7162c60e451a14 Azure Connector Improvemets Change-Id: I4b84ff5a801adf33595bd4ef44012dfc663f6f0c Signed-off-by: jamartinezv --- diff --git a/LICENSE b/LICENSE index 8dada3ed..1be36763 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright Copyright 2019 ETSI Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/osm_ro/vimconn_azure.py b/osm_ro/vimconn_azure.py index fb3f4349..384d7533 100755 --- a/osm_ro/vimconn_azure.py +++ b/osm_ro/vimconn_azure.py @@ -3,6 +3,8 @@ __author__='Sergio Gonzalez' __date__ ='$18-apr-2019 23:59:59$' +import base64 + import vimconn import logging import netaddr @@ -15,8 +17,17 @@ from azure.mgmt.resource import ResourceManagementClient from azure.mgmt.network import NetworkManagementClient from azure.mgmt.compute import ComputeManagementClient + + from msrestazure.azure_exceptions import CloudError +if getenv('OSMRO_PDB_DEBUG'): + import sys + print(sys.path) + import pdb + pdb.set_trace() + + class vimconnector(vimconn.vimconnector): provision_state2osm = { @@ -46,6 +57,8 @@ class vimconnector(vimconn.vimconnector): tenant=(tenant_id or tenant_name) ) + self.tenant=(tenant_id or tenant_name) + # SUBSCRIPTION if 'subscription_id' in config: self.subscription_id = config.get('subscription_id') @@ -85,19 +98,54 @@ class vimconnector(vimconn.vimconnector): self.format_vimconn_exception(e) def _get_resource_name_from_resource_id(self, resource_id): - return str(resource_id.split('/')[-1]) + + try: + resource=str(resource_id.split('/')[-1]) + return resource + except Exception as e: + raise vimconn.vimconnNotFoundException("Resource name '{}' not found".format(resource_id)) def _get_location_from_resource_group(self, resource_group_name): - return self.conn.resource_groups.get(resource_group_name).location - + + try: + location=self.conn.resource_groups.get(resource_group_name).location + return location + except Exception as e: + raise vimconn.vimconnNotFoundException("Location '{}' not found".format(resource_group_name)) + + def _get_resource_group_name_from_resource_id(self, resource_id): - return str(resource_id.split('/')[4]) + + try: + rg=str(resource_id.split('/')[4]) + return rg + except Exception as e: + raise vimconn.vimconnNotFoundException("Resource group '{}' not found".format(resource_id)) + + + def _get_net_name_from_resource_id(self, resource_id): + + try: + net_name=str(resource_id.split('/')[8]) + return net_name + except Exception as e: + raise vimconn.vimconnNotFoundException("Net name '{}' not found".format(resource_id)) + 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: - raise self.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET') + # ERROR + # File "/root/RO/build/osm_ro/vimconn_azure.py", line 110, in + # self._get_resource_name_from_resource_id(net['id']) for net in net_list)) != 1: + #if len(set(self._get_resource_group_name_from_resource_id(net['net_id']) + + # self._get_resource_name_from_resource_id(net['net_id']) for net in net_list)) != 2: + # raise self.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET') + self.logger.debug('Checking subnets for VM') + num_elem_set = len(set(self._get_resource_group_name_from_resource_id(net['net_id']) + + self._get_resource_name_from_resource_id(net['net_id']) for net in net_list)) + + if ( num_elem_set != 1 ): + raise self.format_vimconn_exception('Azure VMs can only attach to subnets in same VNET') def format_vimconn_exception(self, e): """ @@ -107,7 +155,7 @@ class vimconnector(vimconn.vimconnector): """ self.conn = None self.conn_vnet = None - raise vimconn.vimconnConnectionException(type(e).__name__ + ': ' + str(e)) + raise vimconn.vimconnException(type(e).__name__ + ': ' + str(e)) def _check_or_create_resource_group(self): """ @@ -118,10 +166,12 @@ class vimconnector(vimconn.vimconnector): self.conn.resource_groups.create_or_update(self.resource_group, {'location': self.region}) def _check_or_create_vnet(self): + try: vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name) self.vnet_address_space = vnet.address_space.address_prefixes[0] self.vnet_id = vnet.id + return except CloudError as e: if e.error.error == "ResourceNotFound": @@ -137,6 +187,7 @@ class vimconnector(vimconn.vimconnector): }, } self.vnet_address_space = "10.0.0.0/8" + self.conn_vnet.virtual_networks.create_or_update(self.resource_group, self.vnet_name, vnet_params) vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name) self.vnet_id = vnet.id @@ -165,7 +216,6 @@ class vimconnector(vimconn.vimconnector): 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): @@ -189,68 +239,173 @@ class vimconnector(vimconn.vimconnector): break else: ip_profile = {"subnet_address": str(ip_range)} + self.logger.debug('ip_profile: ' + str(ip_range)) break else: vimconn.vimconnException("Cannot find a non-used subnet range in {}".format(self.vnet_address_space)) + else: + ip_profile = {"subnet_address": ip_profile['subnet_address']} + try: - subnet_name = "{}-{}".format(net_name[:24], uuid4()) + #subnet_name = "{}-{}".format(net_name[:24], uuid4()) + subnet_name = net_name[:24] subnet_params= { 'address_prefix': ip_profile['subnet_address'] } - self.conn_vnet.subnets.create_or_update(self.resource_group, self.vnet_name, subnet_name, subnet_params) - return "{}/subnet/{}".format(self.vnet_id, subnet_name), None + self.logger.debug('subnet_name : {}'.format(subnet_name)) + async_creation=self.conn_vnet.subnets.create_or_update(self.resource_group, self.vnet_name, subnet_name, subnet_params) + async_creation.wait() + + #return "{}/subnet/{}".format(self.vnet_id, subnet_name), None + return "{}/subnets/{}".format(self.vnet_id, subnet_name), None except Exception as e: self.format_vimconn_exception(e) - def _create_nic(self, subnet_id, nic_name, static_ip=None): + def _create_nic(self, net, nic_name, static_ip=None): + self._reload_connection() - - resource_group_name=self._get_resource_group_name_from_resource_id(subnet_id) - location = self._get_location_from_resource_group(resource_group_name) - - if static_ip: - async_nic_creation = self.conn_vnet.network_interfaces.create_or_update( - resource_group_name, - nic_name, - { - 'location': location, - 'ip_configurations': [{ - 'name': nic_name + 'ipconfiguration', - 'privateIPAddress': static_ip, - 'privateIPAllocationMethod': 'Static', - 'subnet': { - 'id': subnet_id - } - }] - } - ) - else: - async_nic_creation = self.conn_vnet.network_interfaces.create_or_update( - resource_group_name, - nic_name, - { + + subnet_id = net['net_id'] + location = self._get_location_from_resource_group(self.resource_group) + + try: + if static_ip: + async_nic_creation = self.conn_vnet.network_interfaces.create_or_update( + self.resource_group, + nic_name, + { + 'location': location, + 'ip_configurations': [{ + 'name': nic_name + '-ipconfiguration', + 'privateIPAddress': static_ip, + 'privateIPAllocationMethod': 'Static', + 'subnet': { + 'id': subnet_id + } + }] + } + ) + async_nic_creation.wait() + else: + ip_configuration_name = nic_name + '-ipconfiguration' + self.logger.debug('Create NIC') + async_nic_creation = self.conn_vnet.network_interfaces.create_or_update( + self.resource_group, + nic_name, + { + 'location': location, + 'ip_configurations': [{ + 'name': ip_configuration_name, + 'subnet': { + 'id': subnet_id + } + }] + } + ) + async_nic_creation.wait() + + public_ip = net.get('floating_ip') + if public_ip and public_ip == True: + self.logger.debug('Creating PUBLIC IP') + public_ip_addess_params = { 'location': location, - 'ip_configurations': [{ - 'name': nic_name + 'ipconfiguration', - 'subnet': { - 'id': subnet_id - } - }] + 'public_ip_allocation_method': 'Dynamic' } - ) + public_ip_name = nic_name + '-public-ip' + public_ip = self.conn_vnet.public_ip_addresses.create_or_update( + self.resource_group, + public_ip_name, + public_ip_addess_params + ) + self.logger.debug('Create PUBLIC IP: {}'.format(public_ip.result())) + + # Asociate NIC to Public IP + self.logger.debug('Getting NIC DATA') + nic_data = self.conn_vnet.network_interfaces.get( + self.resource_group, + nic_name) + + nic_data.ip_configurations[0].public_ip_address = public_ip.result() + + self.logger.debug('Updating NIC with public IP') + self.conn_vnet.network_interfaces.create_or_update( + self.resource_group, + nic_name, + nic_data) + except Exception as e: + self.format_vimconn_exception(e) + + result = async_nic_creation.result() return async_nic_creation.result() - def get_image_list(self, filter_dict={}): - """ - The urn contains for marketplace 'publisher:offer:sku:version' + def new_flavor(self, flavor_data): - :param filter_dict: - :return: + if flavor_data: + flavor_id = self.get_flavor_id_from_data(flavor_data) + + if flavor_id != []: + return flavor_id + else: + raise vimconn.vimconnNotFoundException("flavor '{}' not found".format(flavor_data)) + else: + vimconn.vimconnException("There is no data in the flavor_data input parameter") + + def new_tenant(self,tenant_name,tenant_description): + + raise vimconn.vimconnAuthException("It is not possible to create a TENANT in AZURE") + + def new_image(self, image_dict): + + self._reload_connection() + + try: + self.logger.debug('new_image - image_dict - {}'.format(image_dict)) + + if image_dict.get("name"): + image_name = image_dict.get("name") + else: + raise vimconn.vimconnException("There is no name in the image input data") + + if image_dict.get("location"): + params = image_dict["location"].split(":") + if len(params) >= 4: + publisher = params[0] + offer = params[1] + sku = params[2] + version = params[3] + #image_params = {'location': self.region, 'publisher': publisher, 'offer': offer, 'sku': sku, 'version': version } + image_params = {'location': self.region} + + self.conn_compute.images.create_or_update() + async_creation=self.conn_compute.images.create_or_update(self.resource_group, image_name, image_params) + image_id = async_creation.result().id + else: + raise vimconn.vimconnException("The image location is not correct: {}".format(image_dict["location"])) + return image_id + + except Exception as e: + self.format_vimconn_exception(e) + + def get_image_id_from_path(self, path): + """Get the image id from image path in the VIM database. + Returns the image_id or raises a vimconnNotFoundException """ - image_list = [] + def get_image_list(self, filter_dict={}): + """Obtain tenant images from VIM + Filter_dict can be: + name: image name + id: image uuid + checksum: image checksum + location: image path + Returns the image list of dictionaries: + [{}, ...] + List can be empty + """ self._reload_connection() + + image_list = [] if filter_dict.get("name"): params = filter_dict["name"].split(":") if len(params) >= 3: @@ -270,23 +425,7 @@ class vimconnector(vimconn.vimconnector): '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={}): @@ -303,25 +442,31 @@ class vimconnector(vimconn.vimconnector): self.logger.debug('Getting all subnets from VIM') try: self._reload_connection() - vnet = self.conn_vnet.virtual_networks.get(self.config["resource_group"], self.vnet_name) + + vnet = self.conn_vnet.virtual_networks.get(self.resource_group, self.vnet_name) subnet_list = [] - + for subnet in vnet.subnets: - # TODO implement filter_dict + if filter_dict: if filter_dict.get("id") and str(subnet.id) != filter_dict["id"]: continue if filter_dict.get("name") and \ - self._get_resource_name_from_resource_id(subnet.id) != filter_dict["name"]: + str(subnet.id) != filter_dict["name"]: continue + name = self._get_resource_name_from_resource_id(subnet.id) + subnet_list.append({ 'id': str(subnet.id), - 'name': self._get_resource_name_from_resource_id(subnet.id), - 'status': str(vnet.provisioning_state), # TODO Does subnet contains status??? - 'cidr_block': str(subnet.address_prefix) + 'name': self._get_resource_name_from_resource_id(subnet.id), + 'status' : self.provision_state2osm[subnet.provisioning_state], + 'cidr_block': str(subnet.address_prefix), + 'type': 'bridge', + 'shared': False } ) + return subnet_list except Exception as e: self.format_vimconn_exception(e) @@ -331,41 +476,57 @@ 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): - #Create NICs + #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, name, description, start, image_id, flavor_id, net_list, cloud_config=None, + disk_list=None, + availability_zone_index=None, availability_zone_list=None): + self._check_subnets_for_vm(net_list) vm_nics = [] for idx, net in enumerate(net_list): - subnet_id=net['subnet_id'] - nic_name = vm_name + '-nic-'+str(idx) - vm_nic = self._create_nic(subnet_id, nic_name) + # Fault with subnet_id + # subnet_id=net['subnet_id'] + # subnet_id=net['net_id'] + + nic_name = name + '-nic-'+str(idx) + vm_nic = self._create_nic(net, nic_name) vm_nics.append({ 'id': str(vm_nic.id)}) try: + # image_id are several fields of the image_id + image_reference = self.get_image_reference(image_id) + + # The virtual machine name must have less or 64 characters and it can not have the following + # characters: (~ ! @ # $ % ^ & * ( ) = + _ [ ] { } \ | ; : ' " , < > / ?.) + vm_name_aux = self.check_vm_name(name) + + # cloud-init configuration + # cloud config + if cloud_config: + config_drive, userdata = self._create_user_data(cloud_config) + custom_data = base64.b64encode(userdata.encode('utf-8')).decode('latin-1') + os_profile = { + 'computer_name': vm_name_aux, # TODO if vm_name cannot be repeated add uuid4() suffix + 'admin_username': 'osm', # TODO is it mandatory??? + 'admin_password': 'Osm-osm', # TODO is it mandatory??? + 'custom_data': custom_data + } + else: + os_profile = { + 'computer_name': vm_name_aux, # TODO if vm_name cannot be repeated add uuid4() suffix + 'admin_username': 'osm', # TODO is it mandatory??? + 'admin_password': 'Osm-osm', # TODO is it mandatory??? + } + vm_parameters = { 'location': self.region, - 'os_profile': { - 'computer_name': vm_name, # TODO if vm_name cannot be repeated add uuid4() suffix - 'admin_username': 'sergio', # TODO is it mandatory??? - 'linuxConfiguration': { - 'disablePasswordAuthentication': 'true', - 'ssh': { - 'publicKeys': [ - { - 'path': '/home/sergio/.ssh/authorized_keys', - 'keyData': self.pub_key - } - ] - } - } - - }, + 'os_profile': os_profile, 'hardware_profile': { - 'vm_size':flavor_id + 'vm_size': flavor_id }, 'storage_profile': { - 'image_reference': image_id + 'image_reference': image_reference }, 'network_profile': { 'network_interfaces': [ @@ -373,39 +534,119 @@ class vimconnector(vimconn.vimconnector): ] } } + creation_result = self.conn_compute.virtual_machines.create_or_update( self.resource_group, - vm_name, + vm_name_aux, vm_parameters ) - run_command_parameters = { - 'command_id': 'RunShellScript', # For linux, don't change it - 'script': [ - 'date > /home/sergio/test.txt' - ] - } - poller = self.conn_compute.virtual_machines.run_command( - self.resource_group, - vm_name, - run_command_parameters - ) - # TODO return a tuple (vm-ID, None) + #creation_result.wait() + result = creation_result.result() + + for index, subnet in enumerate(net_list): + net_list[index]['vim_id'] = result.id + + if start == True: + #self.logger.debug('Arrancamos VM y esperamos') + start_result = self.conn_compute.virtual_machines.start( + self.resource_group, + vm_name_aux) + #start_result.wait() + + return result.id, None + + #run_command_parameters = { + # 'command_id': 'RunShellScript', # For linux, don't change it + # 'script': [ + # 'date > /tmp/test.txt' + # ] + #} except Exception as e: + #self.logger.debug('AZURE <=== EX: _new_vminstance', exc_info=True) self.format_vimconn_exception(e) + # 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, imagen): + + # The data input format example: + # /Subscriptions/ca3d18ab-d373-4afb-a5d6-7c44f098d16a/Providers/Microsoft.Compute/Locations/westeurope/ + # Publishers/Canonical/ArtifactTypes/VMImage/ + # Offers/UbuntuServer/ + # Skus/18.04-LTS/ + # Versions/18.04.201809110 + publiser = str(imagen.split('/')[8]) + offer = str(imagen.split('/')[12]) + sku = str(imagen.split('/')[14]) + version = str(imagen.split('/')[16]) + + return { + 'publisher': publiser, + 'offer': offer, + 'sku': sku, + 'version': version + } + + # Azure VM names can not have some special characters + def check_vm_name( self, vm_name ): + + #chars_not_allowed_list = ['~','!','@','#','$','%','^','&','*','(',')','=','+','_','[',']','{','}','|',';',':','<','>','/','?','.'] + chars_not_allowed_list = "~!@#$%^&*()=+_[]{}|;:<>/?." + + # First: the VM name max length is 64 characters + vm_name_aux = vm_name[:64] + + # Second: replace not allowed characters + for elem in chars_not_allowed_list : + # Check if string is in the main string + if elem in vm_name_aux : + #self.logger.debug('Dentro del IF') + # Replace the string + vm_name_aux = vm_name_aux.replace(elem, '-') + + return vm_name_aux + + 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'] + try: + 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']) - 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'] + + except Exception as e: + self.format_vimconn_exception(e) - return listedFilteredSizes[0]['name'] + def _get_flavor_id_from_flavor_name(self, flavor_name): + self.logger.debug("Getting flavor id from falvor name {}".format(flavor_name)) + + try: + self._reload_connection() + vm_sizes_list = [vm_size.serialize() for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region)] + + output_flavor = None + for size in vm_sizes_list: + if size['name'] == flavor_name: + output_flavor = size + + return output_flavor + + except Exception as e: + self.format_vimconn_exception(e) def check_vim_connectivity(self): try: @@ -415,103 +656,279 @@ class vimconnector(vimconn.vimconnector): 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) + resName = self._get_resource_name_from_resource_id(net_id) - + self._reload_connection() - vnet = self.conn_vnet.virtual_networks.get(resGroup, resName) - return vnet - def delete_network(self, net_id): - resGroup = self._get_resource_group_name_from_resource_id(net_id) + filter_dict = {'name' : net_id} + network_list = self.get_network_list(filter_dict) + + if not network_list: + raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id)) + else: + return network_list[0] + + # Added created_items because it is neccesary + # self.vim.delete_network(net_vim_id, task["extra"].get("created_items")) + # TypeError: delete_network() takes exactly 2 arguments (3 given) + def delete_network(self, net_id, created_items=None): + + self.logger.debug('Deletting network {} - {}'.format(self.resource_group, 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) - resName = self._get_resource_name_from_resource_id(net_id) - + filter_dict = {'name' : net_id} + network_list = self.get_network_list(filter_dict) + if not network_list: + raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id)) + + try: + # Subnet API fails (CloudError: Azure Error: ResourceNotFound) + # Put the initial virtual_network API + async_delete=self.conn_vnet.subnets.delete(self.resource_group, self.vnet_name, resName) + return net_id + + except CloudError as e: + if e.error.error == "ResourceNotFound": + raise vimconn.vimconnNotFoundException("network '{}' not found".format(net_id)) + else: + raise + except Exception as e: + self.format_vimconn_exception(e) + + + + # Added third parameter because it is necesary + def delete_vminstance(self, vm_id, created_items=None): + + self.logger.debug('Deletting VM instance {} - {}'.format(self.resource_group, vm_id)) self._reload_connection() - self.conn_compute.virtual_machines.delete(resGroup, resName) + + try: + + resName = self._get_resource_name_from_resource_id(vm_id) + vm = self.conn_compute.virtual_machines.get(self.resource_group, resName) + + # Shuts down the virtual machine and releases the compute resources + #vm_stop = self.conn_compute.virtual_machines.power_off(self.resource_group, resName) + #vm_stop.wait() + + vm_delete = self.conn_compute.virtual_machines.delete(self.resource_group, resName) + vm_delete.wait() + + # Delete OS Disk + os_disk_name = vm.storage_profile.os_disk.name + self.logger.debug('Delete OS DISK - ' + os_disk_name) + self.conn_compute.disks.delete(self.resource_group, os_disk_name) + + # After deletting VM, it is necessary delete NIC, because if is not deleted delete_network + # does not work because Azure says that is in use the subnet + network_interfaces = vm.network_profile.network_interfaces + + for network_interface in network_interfaces: + + #self.logger.debug('nic - {}'.format(network_interface)) + + nic_name = self._get_resource_name_from_resource_id(network_interface.id) + + #self.logger.debug('nic_name - {}'.format(nic_name)) + + nic_data = self.conn_vnet.network_interfaces.get( + self.resource_group, + nic_name) + + exist_public_ip = nic_data.ip_configurations[0].public_ip_address + if exist_public_ip: + public_ip_id = nic_data.ip_configurations[0].public_ip_address.id + self.logger.debug('Public ip id - ' + public_ip_id) + + self.logger.debug('Delete NIC - ' + nic_name) + nic_delete = self.conn_vnet.network_interfaces.delete(self.resource_group, nic_name) + nic_delete.wait() + + # Delete public_ip + public_ip_name = self._get_resource_name_from_resource_id(public_ip_id) + + self.logger.debug('Delete PUBLIC IP - ' + public_ip_name) + public_ip = self.conn_vnet.public_ip_addresses.delete(self.resource_group, public_ip_name) + except CloudError as e: + if e.error.error == "ResourceNotFound": + raise vimconn.vimconnNotFoundException("No vminstance found '{}'".format(vm_id)) + else: + raise + except Exception as e: + self.format_vimconn_exception(e) + + def action_vminstance(self, vm_id, action_dict, created_items={}): + """Send and action over a VM instance from VIM + Returns the vm_id if the action was successfully sent to the VIM""" + + self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict)) + try: + self._reload_connection() + resName = self._get_resource_name_from_resource_id(vm_id) + if "start" in action_dict: + self.conn_compute.virtual_machines.start(self.resource_group,resName) + elif "stop" in action_dict or "shutdown" in action_dict or "shutoff" in action_dict: + self.conn_compute.virtual_machines.power_off(self.resource_group,resName) + elif "terminate" in action_dict: + self.conn_compute.virtual_machines.delete(self.resource_group,resName) + elif "reboot" in action_dict: + self.conn_compute.virtual_machines.restart(self.resource_group,resName) + return None + except CloudError as e: + if e.error.error == "ResourceNotFound": + raise vimconn.vimconnNotFoundException("No vm found '{}'".format(vm_id)) + else: + raise + except Exception as e: + self.format_vimconn_exception(e) + + def delete_flavor(self, flavor_id): + + raise vimconn.vimconnAuthException("It is not possible to delete a FLAVOR in AZURE") + + def delete_tenant(self,tenant_id,): + + raise vimconn.vimconnAuthException("It is not possible to delete a TENANT in AZURE") + + def delete_image(self, image_id): + + raise vimconn.vimconnAuthException("It is not possible to delete a IMAGE in AZURE") def get_vminstance(self, vm_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() - vm=self.conn_compute.virtual_machines.get(resGroup, resName) + try: + resName = self._get_resource_name_from_resource_id(vm_id) + vm=self.conn_compute.virtual_machines.get(self.resource_group, resName) + except CloudError as e: + if e.error.error == "ResourceNotFound": + raise vimconn.vimconnNotFoundException("No vminstance found '{}'".format(vm_id)) + else: + raise + except Exception as e: + self.format_vimconn_exception(e) return vm def get_flavor(self, flavor_id): self._reload_connection() - for vm_size in self.conn_compute.virtual_machine_sizes.list(self.region): - if vm_size.name == flavor_id : - return vm_size + + flavor_data = self._get_flavor_id_from_flavor_name(flavor_id) + if flavor_data: + flavor = { + 'id': flavor_id, + 'name': flavor_id, + 'ram': flavor_data['memoryInMB'], + 'vcpus': flavor_data['numberOfCores'], + 'disk': flavor_data['resourceDiskSizeInMB'] + } + return flavor + else: + raise vimconn.vimconnNotFoundException("flavor '{}' not found".format(flavor_id)) + + + def get_tenant_list(self, filter_dict={}): + + tenants_azure=[{'name': self.tenant, 'id': self.tenant}] + tenant_list=[] + + for tenant_azure in tenants_azure: + if filter_dict: + if filter_dict.get("id") and str(tenant_azure.get("id")) != filter_dict["id"]: + continue + if filter_dict.get("name") and str(tenant_azure.get("name")) != filter_dict["name"]: + continue + + tenant_list.append(tenant_azure) + + return tenant_list def refresh_nets_status(self, net_list): + out_nets = {} self._reload_connection() for net_id in net_list: try: - resGroup = self._get_resource_group_name_from_resource_id(net_id) + netName = self._get_net_name_from_resource_id(net_id) resName = self._get_resource_name_from_resource_id(net_id) - vnet = self.conn_vnet.virtual_networks.get(resGroup, resName) + net = self.conn_vnet.subnets.get(self.resource_group, netName, resName) + out_nets[net_id] ={ - "status": self.provision_state2osm[vnet.provisioning_state], - "vim_info": str(vnet) + "status": self.provision_state2osm[net.provisioning_state], + "vim_info": str(net) } except CloudError as e: if e.error.error == "ResourceNotFound": out_nets[net_id] = { "status": "DELETED", + "error_msg": str(e) } else: raise + except vimconn.vimconnNotFoundException as e: + out_nets[net_id] = { + "status": "DELETED", + "error_msg": str(e) + } except Exception as e: # TODO distinguish when it is deleted out_nets[net_id] = { "status": "VIM_ERROR", - "vim_info": str(vnet), "error_msg": str(e) } - return out_nets def refresh_vms_status(self, vm_list): + out_vms = {} + out_vms_dict = {} self._reload_connection() + for vm_id in vm_list: try: - resGroup = self._get_resource_group_name_from_resource_id(vm_id) + resName = self._get_resource_name_from_resource_id(vm_id) - vm = self.conn_compute.virtual_machines.get(resGroup, resName) - out_vms[vm_id] ={ - "status": self.provision_state2osm[vm.provisioning_state], - "vim_info": str(vm) - } - except CloudError as e: - if e.error.error == "ResourceNotFound": - out_vms[vm_id] = { - "status": "DELETED", - } - else: - raise + vm = self.conn_compute.virtual_machines.get(self.resource_group, resName) + out_vms_dict['status'] = self.provision_state2osm[vm.provisioning_state] + out_vms_dict['interfaces'] = [] + interface_dict = {} + + network_interfaces = vm.network_profile.network_interfaces + + for network_interface in network_interfaces: + + nic_name = self._get_resource_name_from_resource_id(network_interface.id) + interface_dict['vim_interface_id'] = vm_id + + nic_data = self.conn_vnet.network_interfaces.get( + self.resource_group, + nic_name) + + private_ip = nic_data.ip_configurations[0].private_ip_address + + interface_dict['mac_address'] = nic_data.mac_address + interface_dict['ip_address'] = private_ip + out_vms_dict['interfaces'].append(interface_dict) + except Exception as e: - # TODO distinguish when it is deleted - out_vms[vm_id] = { - "status": "VIM_ERROR", - "vim_info": str(vm), - "error_msg": str(e) - } + out_vms_dict['status'] = "DELETED" + out_vms_dict['error_msg'] = str(e) + vm = None + finally: + if vm: + out_vms_dict['vim_info'] = str(vm) + + out_vms[vm_id] = out_vms_dict return out_vms -# TODO get_vminstance_console for getting console if __name__ == "__main__": diff --git a/test/test_RO.py b/test/test_RO.py index 8f2a5507..be711c86 100755 --- a/test/test_RO.py +++ b/test/test_RO.py @@ -20,6 +20,15 @@ # ## +# DEBUG WITH PDB +import os +if os.getenv('OSMRO_PDB_DEBUG'): + import sys + print(sys.path) + import pdb + pdb.set_trace() + + """ Module for testing openmano functionality. It uses openmanoclient.py for invoking openmano """ @@ -291,7 +300,7 @@ class test_vimconn_connect(test_base): vca_object = test_config["vim_conn"].connect() logger.debug("{}".format(vca_object)) self.assertIsNotNone(vca_object) - elif test_config['vimtype'] == 'openstack': + elif test_config['vimtype'] in ('openstack', 'azure'): test_config["vim_conn"]._reload_connection() network_list = test_config["vim_conn"].get_network_list() logger.debug("{}".format(network_list)) @@ -308,7 +317,7 @@ class test_vimconn_new_network(test_base): self.__class__.test_index, inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - network = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + network, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type=network_type) self.__class__.network_id = network logger.debug("{}".format(network)) @@ -335,7 +344,7 @@ class test_vimconn_new_network(test_base): self.__class__.test_index += 1 for net_type in network_types: self.__class__.network_name = _get_random_string(20) - network_id = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + network_id, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type=net_type) delete_net_ids.append(network_id) @@ -392,7 +401,7 @@ class test_vimconn_new_network(test_base): self.__class__.test_index, inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - network = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + network, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type='mgmt', ip_profile=ip_profile) self.__class__.network_id = network @@ -417,7 +426,7 @@ class test_vimconn_new_network(test_base): self.__class__.test_index, inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - network = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + network, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type='bridge', shared=shared) self.__class__.network_id = network @@ -442,7 +451,7 @@ class test_vimconn_new_network(test_base): self.__class__.test_index, inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - network = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + network, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type='unknowntype') self.__class__.network_id = network logger.debug("{}".format(network)) @@ -466,7 +475,7 @@ class test_vimconn_new_network(test_base): # creating new network network_name = _get_random_string(20) net_type = 'bridge' - network_id = test_config["vim_conn"].new_network(net_name=network_name, + network_id, _ = test_config["vim_conn"].new_network(net_name=network_name, net_type=net_type) # refresh net status net_dict = test_config["vim_conn"].refresh_nets_status([network_id]) @@ -490,7 +499,7 @@ class test_vimconn_new_network(test_base): # refresh net status net_dict = test_config["vim_conn"].refresh_nets_status([unknown_net_id]) - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): self.assertEqual(net_dict[unknown_net_id]['status'], 'DELETED') else: # TODO : Fix vmware connector to return status DELETED as per vimconn.py @@ -503,7 +512,7 @@ class test_vimconn_get_network_list(test_base): # creating new network self.__class__.network_name = _get_random_string(20) self.__class__.net_type = 'bridge' - network = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + network, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type=self.__class__.net_type) self.__class__.network_id = network logger.debug("{}".format(network)) @@ -530,7 +539,8 @@ class test_vimconn_get_network_list(test_base): self.assertIn(self.__class__.network_name, net.get('name')) self.assertEqual(net.get('type'), self.__class__.net_type) self.assertEqual(net.get('status'), 'ACTIVE') - self.assertEqual(net.get('shared'), False) + if test_config['vimtype'] != 'azure': + self.assertEqual(net.get('shared'), False) def test_010_get_network_list_by_name(self): self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], @@ -538,7 +548,7 @@ class test_vimconn_get_network_list(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): network_name = test_config['vim_conn'].get_network(self.__class__.network_id)['name'] else: network_name = test_config['vim_conn'].get_network_name_by_id(self.__class__.network_id) @@ -572,7 +582,7 @@ class test_vimconn_get_network_list(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): network_name = test_config['vim_conn'].get_network(self.__class__.network_id)['name'] else: network_name = test_config['vim_conn'].get_network_name_by_id(self.__class__.network_id) @@ -592,7 +602,7 @@ class test_vimconn_get_network_list(test_base): self.__class__.test_index += 1 tenant_list = test_config["vim_conn"].get_tenant_list() - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): network_name = test_config['vim_conn'].get_network(self.__class__.network_id)['name'] else: network_name = test_config['vim_conn'].get_network_name_by_id(self.__class__.network_id) @@ -616,7 +626,7 @@ class test_vimconn_get_network_list(test_base): self.__class__.test_index += 1 status = 'ACTIVE' - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): network_name = test_config['vim_conn'].get_network(self.__class__.network_id)['name'] else: network_name = test_config['vim_conn'].get_network_name_by_id(self.__class__.network_id) @@ -645,7 +655,7 @@ class test_vimconn_get_network(test_base): # creating new network self.__class__.network_name = _get_random_string(20) self.__class__.net_type = 'bridge' - network = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + network, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type=self.__class__.net_type) self.__class__.network_id = network logger.debug("{}".format(network)) @@ -690,7 +700,7 @@ class test_vimconn_delete_network(test_base): # Creating network self.__class__.network_name = _get_random_string(20) self.__class__.net_type = 'bridge' - network = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + network, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type=self.__class__.net_type) self.__class__.network_id = network logger.debug("{}".format(network)) @@ -760,16 +770,23 @@ class test_vimconn_get_flavor(test_base): flavor_id = test_config["vim_conn"].new_flavor(flavor_data) # get flavor by id result = test_config["vim_conn"].get_flavor(flavor_id) - self.assertEqual(ram, result['ram']) - self.assertEqual(vcpus, result['vcpus']) - self.assertEqual(disk, result['disk']) - # delete flavor - result = test_config["vim_conn"].delete_flavor(flavor_id) - if result: - logger.info("Flavor id {} sucessfully deleted".format(result)) + if test_config['vimtype'] != 'azure': + self.assertEqual(ram, result['ram']) + self.assertEqual(vcpus, result['vcpus']) + self.assertEqual(disk, result['disk']) else: - logger.info("Failed to delete flavor id {}".format(result)) + self.assertTrue(ram <= result['ram']) + self.assertTrue(vcpus <= result['vcpus']) + self.assertTrue(disk <= result['disk']) + + # delete flavor + if test_config['vimtype'] != 'azure': + result = test_config["vim_conn"].delete_flavor(flavor_id) + if result: + logger.info("Flavor id {} sucessfully deleted".format(result)) + else: + logger.info("Failed to delete flavor id {}".format(result)) def test_010_get_flavor_negative(self): Non_exist_flavor_id = str(uuid.uuid4()) @@ -788,7 +805,7 @@ class test_vimconn_new_flavor(test_base): flavor_id = None def test_000_new_flavor(self): - flavor_data = {'name': _get_random_string(20), 'ram': 1024, 'vpcus': 1, 'disk': 10} + flavor_data = {'name': _get_random_string(20), 'ram': 1024, 'vcpus': 1, 'disk': 10} self.__class__.test_text = "{}.{}. TEST {}".format(test_config["test_number"], self.__class__.test_index, @@ -807,12 +824,18 @@ class test_vimconn_new_flavor(test_base): self.__class__.test_index += 1 # delete flavor - result = test_config["vim_conn"].delete_flavor(self.__class__.flavor_id) - if result: - logger.info("Flavor id {} sucessfully deleted".format(result)) + if test_config['vimtype'] == 'azure': + with self.assertRaises(Exception) as context: + test_config["vim_conn"].delete_flavor(self.__class__.flavor_id) + + self.assertEqual((context.exception).http_code, 401) else: - logger.error("Failed to delete flavor id {}".format(result)) - raise Exception ("Failed to delete created flavor") + result = test_config["vim_conn"].delete_flavor(self.__class__.flavor_id) + if result: + logger.info("Flavor id {} sucessfully deleted".format(result)) + else: + logger.error("Failed to delete flavor id {}".format(result)) + raise Exception ("Failed to delete created flavor") def test_020_new_flavor_negative(self): Invalid_flavor_data = {'ram': '1024', 'vcpus': 2.0, 'disk': 2.0} @@ -825,7 +848,10 @@ class test_vimconn_new_flavor(test_base): with self.assertRaises(Exception) as context: test_config["vim_conn"].new_flavor(Invalid_flavor_data) - self.assertEqual((context.exception).http_code, 400) + if test_config['vimtype'] == 'azure': + self.assertEqual((context.exception).http_code, 404) + else: + self.assertEqual((context.exception).http_code, 400) def test_030_delete_flavor_negative(self): Non_exist_flavor_id = str(uuid.uuid4()) @@ -838,7 +864,10 @@ class test_vimconn_new_flavor(test_base): with self.assertRaises(Exception) as context: test_config["vim_conn"].delete_flavor(Non_exist_flavor_id) - self.assertEqual((context.exception).http_code, 404) + if test_config['vimtype'] == 'azure': + self.assertEqual((context.exception).http_code, 401) + else: + self.assertEqual((context.exception).http_code, 404) class test_vimconn_new_image(test_base): @@ -850,7 +879,8 @@ class test_vimconn_new_image(test_base): image_path = test_config['image_path'] if image_path: - self.__class__.image_id = test_config["vim_conn"].new_image({ 'name': 'TestImage', 'location' : image_path, 'metadata': {'upload_location':None} }) + self.__class__.image_id = test_config["vim_conn"].new_image({ 'name': 'TestImage', 'location' : image_path, + 'metadata': {'upload_location':None} }) time.sleep(20) self.assertIsInstance(self.__class__.image_id, (str, unicode)) @@ -931,7 +961,11 @@ class test_vimconn_get_image_list(test_base): self.__class__.test_index, inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - image_list = test_config["vim_conn"].get_image_list() + + if test_config['image_name']: + image_list = test_config['vim_conn'].get_image_list({'name': test_config['image_name']}) + else: + image_list = test_config["vim_conn"].get_image_list() for item in image_list: if 'name' in item: @@ -991,7 +1025,7 @@ class test_vimconn_new_vminstance(test_base): self.__class__.network_name = _get_random_string(20) self.__class__.net_type = 'bridge' - self.__class__.network_id = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, + self.__class__.network_id, _ = test_config["vim_conn"].new_network(net_name=self.__class__.network_name, net_type=self.__class__.net_type) # find image name and image id if test_config['image_name']: @@ -1031,9 +1065,13 @@ class test_vimconn_new_vminstance(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] + net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, + 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] - self.__class__.instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id, flavor_id=flavor_id, net_list=net_list) + self.__class__.instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', + start=False, + image_id=self.__class__.image_id, + flavor_id=flavor_id, net_list=net_list) self.assertIsInstance(self.__class__.instance_id, (str, unicode)) @@ -1050,9 +1088,12 @@ class test_vimconn_new_vminstance(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'model': model_name, 'type': 'virtual', 'net_id': self.__class__.network_id}] + net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, + 'model': model_name, 'type': 'virtual', 'net_id': self.__class__.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id,flavor_id=flavor_id,net_list=net_list) + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=self.__class__.image_id, + flavor_id=flavor_id,net_list=net_list) self.assertIsInstance(instance_id, (str, unicode)) @@ -1074,11 +1115,12 @@ class test_vimconn_new_vminstance(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - net_list = [{'use': net_use, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] + net_list = [{'use': net_use, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', + 'net_id': self.__class__.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id,disk_list=None, - flavor_id=flavor_id, - net_list=net_list) + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=self.__class__.image_id,disk_list=None, + flavor_id=flavor_id, net_list=net_list) self.assertIsInstance(instance_id, (str, unicode)) # Deleting created vm instance @@ -1108,20 +1150,20 @@ class test_vimconn_new_vminstance(test_base): net_list=net_list) self.assertEqual(type(instance_id),str) - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): # create network of type data network_name = _get_random_string(20) net_type = 'data' - network_id = test_config["vim_conn"].new_network(net_name=network_name, + network_id, _ = test_config["vim_conn"].new_network(net_name=network_name, net_type=net_type) net_list = [{'use': net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'type': _type, 'net_id': network_id}] instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, - image_id=self.__class__.image_id, disk_list=None, - flavor_id=flavor_id, - net_list=net_list) + image_id=self.__class__.image_id, disk_list=None, + flavor_id=flavor_id, + net_list=net_list) self.assertEqual(type(instance_id), unicode) @@ -1142,11 +1184,12 @@ class test_vimconn_new_vminstance(test_base): name = 'eth0' user_name = 'test_user' - key_pairs = ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCy2w9GHMKKNkpCmrDK2ovc3XBYDETuLWwaW24S+feHhLBQiZlzh3gSQoINlA+2ycM9zYbxl4BGzEzpTVyCQFZv5PidG4m6ox7LR+KYkDcITMyjsVuQJKDvt6oZvRt6KbChcCi0n2JJD/oUiJbBFagDBlRslbaFI2mmqmhLlJ5TLDtmYxzBLpjuX4m4tv+pdmQVfg7DYHsoy0hllhjtcDlt1nn05WgWYRTu7mfQTWfVTavu+OjIX3e0WN6NW7yIBWZcE/Q9lC0II3W7PZDE3QaT55se4SPIO2JTdqsx6XGbekdG1n6adlduOI27sOU5m4doiyJ8554yVbuDB/z5lRBD alfonso.tiernosepulveda@telefonica.com'] + key_pairs = ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtAjl5R+GSKP3gFrdFxgizKEUzhXKQbyjaxJH9thsK 0/fDiYlaNEjvijgPgiVZkfwvqgWeLprPcpzL2j4jvmmSJ3+7C8ihCwObWP0VUiuewmbIINBPAR0RqusjMRyPsa+q0asFBPOoZLx3Cv3vzmC1AA3mKuCNeT EuA0rlWhDIOVwMcU5sP1grnmuexQB8HcR7BdKcA9y08pTwnCQR8vmtW77SRkaxEGXm4Gnw5qw8Z27mHdk2wWS2SnbVH7aFwWvDXc6jjf5TpEWypdr/EAPC +eJipeS2Oa4FsntEqAu3Fz6gp/9ub8uNqgCgHfMzs6FhYpZpipwS0hXYyF6eVsSx osm@osm'] - users_data = [{'key-pairs': ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCy2w9GHMKKNkpCmrDK2ovc3XBYDETuLWwaW24S+feHhLBQiZlzh3gSQoINlA+2ycM9zYbxl4BGzEzpTVyCQFZv5PidG4m6ox7LR+KYkDcITMyjsVuQJKDvt6oZvRt6KbChcCi0n2JJD/oUiJbBFagDBlRslbaFI2mmqmhLlJ5TLDtmYxzBLpjuX4m4tv+pdmQVfg7DYHsoy0hllhjtcDlt1nn05WgWYRTu7mfQTWfVTavu+OjIX3e0WN6NW7yIBWZcE/Q9lC0II3W7PZDE3QaT55se4SPIO2JTdqsx6XGbekdG1n6adlduOI27sOU5m4doiyJ8554yVbuDB/z5lRBD alfonso.tiernosepulveda@telefonica.com'], 'name': user_name}] + users_data = [{'key-pairs': ['ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtAjl5R+GSKP3gFrdFxgizKEUzhXKQbyjaxJH9thsK0/fDiYlaNEjvijgPgiVZkfwvqgWeLprPcpzL2j4jvmmSJ3+7C8ihCwObWP0VUiuewmbIINBPAR0RqusjMRyPsa+q0asFBPOoZLx3Cv3vzmC1AA3mKuCNeTEuA0rlWhDIOVwMcU5sP1grnmuexQB8HcR7BdKcA9y08pTwnCQR8vmtW77SRkaxEGXm4Gnw5qw8Z27mHdk2wWS2SnbVH7aFwWvDXc6jjf5TpEWypdr/EAPC+eJipeS2Oa4FsntEqAu3Fz6gp/9ub8uNqgCgHfMzs6FhYpZpipwS0hXYyF6eVsSx osm@osm'], 'name': 'cloudinit'}] cloud_data = {'config-files': [{'content': 'auto enp0s3\niface enp0s3 inet dhcp\n', 'dest': '/etc/network/interfaces.d/enp0s3.cfg', 'owner': 'root:root', 'permissions': '0644'}, {'content': '#! /bin/bash\nls -al >> /var/log/osm.log\n', 'dest': '/etc/rc.local', 'permissions': '0755'}, {'content': 'file content', 'dest': '/etc/test_delete'}], 'boot-data-drive': True, 'key-pairs': key_pairs, 'users': users_data } + #cloud_data = {'users': users_data } # create new flavor flavor_id = test_config["vim_conn"].new_flavor(flavor_data) @@ -1156,10 +1199,13 @@ class test_vimconn_new_vminstance(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] + net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, + 'type': 'virtual', 'net_id': self.__class__.network_id}] instance_id, _ = test_config["vim_conn"].new_vminstance(name='Cloud_vm', description='', start=False, - image_id=self.__class__.image_id, flavor_id=flavor_id,net_list=net_list,cloud_config=cloud_data) + image_id=self.__class__.image_id, + flavor_id=flavor_id,net_list=net_list, + cloud_config=cloud_data) self.assertIsInstance(instance_id, (str, unicode)) @@ -1182,12 +1228,13 @@ class test_vimconn_new_vminstance(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] + net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, + 'type': 'virtual', 'net_id': self.__class__.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='VM_test1', description='', start=False, image_id=self.__class__.image_id, - flavor_id=flavor_id, - net_list=net_list, - disk_list=device_data) + instance_id, _ = test_config["vim_conn"].new_vminstance(name='VM_test1', description='', start=False, + image_id=self.__class__.image_id, + flavor_id=flavor_id, net_list=net_list, + disk_list=device_data) self.assertIsInstance(instance_id, (str, unicode)) # Deleting created vm instance @@ -1205,12 +1252,14 @@ class test_vimconn_new_vminstance(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] + net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'port_security': True, + 'type': 'virtual', 'net_id': self.__class__.network_id}] with self.assertRaises(Exception) as context: - test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=unknown_image_id, - flavor_id=unknown_flavor_id, - net_list=net_list) + test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=unknown_image_id, + flavor_id=unknown_flavor_id, + net_list=net_list) self.assertIn((context.exception).http_code, (400, 404)) @@ -1267,7 +1316,7 @@ class test_vimconn_new_vminstance(test_base): if attr == 'interfaces': self.assertEqual(type(vm_info[self.__class__.instance_id][attr]), list) - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): vpci = "0000:00:11.0" name = "eth0" @@ -1276,9 +1325,12 @@ class test_vimconn_new_vminstance(test_base): # create new flavor flavor_id = test_config["vim_conn"].new_flavor(flavor_data) # create new vm instance - net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] + net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, + 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id, flavor_id=flavor_id, net_list=net_list) + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=self.__class__.image_id, + flavor_id=flavor_id, net_list=net_list) time.sleep(30) vm_list = [] @@ -1311,7 +1363,7 @@ class test_vimconn_new_vminstance(test_base): if test_config['vimtype'] == 'vmware': self.assertEqual(vm_dict,{}) - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): self.assertEqual(vm_dict[unknown_id]['status'], 'DELETED') def test_110_action_vminstance(self): @@ -1328,7 +1380,7 @@ class test_vimconn_new_vminstance(test_base): {action: None}) self.assertEqual(instance_id, self.__class__.instance_id) - if test_config['vimtype'] == 'openstack': + if test_config['vimtype'] in ('openstack', 'azure'): # create new vm instance vpci = "0000:00:11.0" name = "eth0" @@ -1338,22 +1390,27 @@ class test_vimconn_new_vminstance(test_base): # create new flavor flavor_id = test_config["vim_conn"].new_flavor(flavor_data) - net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] + net_list = [{'use': self.__class__.net_type, 'name': name, 'floating_ip': False, 'vpci': vpci, + 'port_security': True, 'type': 'virtual', 'net_id': self.__class__.network_id}] - new_instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, image_id=self.__class__.image_id, flavor_id=flavor_id, net_list=net_list) + new_instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', + start=False, image_id=self.__class__.image_id, + flavor_id=flavor_id, net_list=net_list) - action_list = ['shutdown','start','shutoff','rebuild','start','pause','start'] + if test_config['vimtype'] == 'openstack': + action_list = ['shutdown','start','shutoff','rebuild','start','pause','start'] + else: + action_list = ['shutdown','start','stop','start','shutoff','start','reboot'] # various action on vminstace for action in action_list: # sleep for sometime till status is changed time.sleep(25) - instance_id = test_config["vim_conn"].action_vminstance(new_instance_id, - { action: None}) + instance_id = test_config["vim_conn"].action_vminstance(new_instance_id, {action: None}) self.assertTrue(instance_id is None) - # Deleting created vm instance + #Deleting created vm instance logger.info("Deleting created vm intance") test_config["vim_conn"].delete_vminstance(new_instance_id) time.sleep(10) @@ -1402,9 +1459,12 @@ class test_vimconn_new_vminstance(test_base): self.assertEqual(sriov_net_name, list_item.get('name')) self.__class__.sriov_network_id = list_item.get('id') - net_list = [{'use': 'data', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'VF', 'net_id': self.__class__.sriov_network_id}] + net_list = [{'use': 'data', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'VF', + 'net_id': self.__class__.sriov_network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_sriov_vm', description='', start=False, image_id=self.__class__.image_id, flavor_id=flavor_id, net_list=net_list) + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_sriov_vm', description='', start=False, + image_id=self.__class__.image_id, flavor_id=flavor_id, + net_list=net_list) self.assertIsInstance(instance_id, (str, unicode)) @@ -1499,10 +1559,15 @@ class test_vimconn_new_tenant(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - self.__class__.tenant_id = test_config["vim_conn"].new_tenant(tenant_name, "") - time.sleep(15) + if test_config['vimtype'] != 'azure': + self.__class__.tenant_id = test_config["vim_conn"].new_tenant(tenant_name, "") + time.sleep(15) - self.assertIsInstance(self.__class__.tenant_id, (str, unicode)) + self.assertIsInstance(self.__class__.tenant_id, (str, unicode)) + else: + with self.assertRaises(Exception) as context: + test_config["vim_conn"].new_tenant(self.__class__.tenant_id) + self.assertEqual((context.exception).http_code, 401) def test_010_new_tenant_negative(self): @@ -1515,7 +1580,10 @@ class test_vimconn_new_tenant(test_base): with self.assertRaises(Exception) as context: test_config["vim_conn"].new_tenant(Invalid_tenant_name, "") - self.assertEqual((context.exception).http_code, 400) + if test_config['vimtype'] != 'azure': + self.assertEqual((context.exception).http_code, 400) + else: + self.assertEqual((context.exception).http_code, 401) def test_020_delete_tenant(self): @@ -1524,9 +1592,13 @@ class test_vimconn_new_tenant(test_base): inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 - tenant_id = test_config["vim_conn"].delete_tenant(self.__class__.tenant_id) - - self.assertIsInstance(tenant_id, (str, unicode)) + if test_config['vimtype'] != 'azure': + tenant_id = test_config["vim_conn"].delete_tenant(self.__class__.tenant_id) + self.assertIsInstance(tenant_id, (str, unicode)) + else: + with self.assertRaises(Exception) as context: + test_config["vim_conn"].delete_tenant(self.__class__.tenant_id) + self.assertEqual((context.exception).http_code, 401) def test_030_delete_tenant_negative(self): Non_exist_tenant_name = 'Test_30_tenant' @@ -1538,7 +1610,10 @@ class test_vimconn_new_tenant(test_base): with self.assertRaises(Exception) as context: test_config["vim_conn"].delete_tenant(Non_exist_tenant_name) - self.assertEqual((context.exception).http_code, 404) + if test_config['vimtype'] != 'azure': + self.assertEqual((context.exception).http_code, 404) + else: + self.assertEqual((context.exception).http_code, 401) def get_image_id(): @@ -1565,7 +1640,7 @@ class test_vimconn_vminstance_by_ip_address(test_base): # create network self.network_name = _get_random_string(20) - self.network_id = test_config["vim_conn"].new_network(net_name=self.network_name, + self.network_id, _ = test_config["vim_conn"].new_network(net_name=self.network_name, net_type='bridge') def tearDown(self): @@ -1700,7 +1775,7 @@ class test_vimconn_vminstance_by_adding_10_nics(test_base): i = 0 for i in range(10): self.network_name = _get_random_string(20) - network_id = test_config["vim_conn"].new_network(net_name=self.network_name, + network_id, _ = test_config["vim_conn"].new_network(net_name=self.network_name, net_type='bridge') self.net_ids.append(network_id) @@ -1736,8 +1811,8 @@ class test_vimconn_vminstance_by_adding_10_nics(test_base): 'port_security': True, 'type': 'virtual', 'net_id': net_id}) c = c+1 - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id, - flavor_id=flavor_id, net_list=net_list) + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=image_id, flavor_id=flavor_id, net_list=net_list) self.assertEqual(type(instance_id),str) logger.info("Deleting created vm instance") @@ -1752,7 +1827,7 @@ class test_vimconn_vminstance_by_existing_disk(test_base): def setUp(self): # create network self.network_name = _get_random_string(20) - self.network_id = test_config["vim_conn"].new_network(net_name=self.network_name, + self.network_id, _ = test_config["vim_conn"].new_network(net_name=self.network_name, net_type='bridge') def tearDown(self): @@ -1789,7 +1864,8 @@ class test_vimconn_vminstance_by_existing_disk(test_base): net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id, + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=image_id, flavor_id=flavor_id, net_list=net_list,disk_list=disk_list) self.assertEqual(type(instance_id),str) @@ -1816,7 +1892,8 @@ class test_vimconn_vminstance_by_existing_disk(test_base): net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id, + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=image_id, flavor_id=flavor_id, net_list=net_list,disk_list=disk_list) self.assertEqual(type(instance_id),str) @@ -1847,7 +1924,8 @@ class test_vimconn_vminstance_by_existing_disk(test_base): net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id, + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=image_id, flavor_id=flavor_id, net_list=net_list,disk_list=disk_list ) self.assertEqual(type(instance_id),str) @@ -1863,7 +1941,7 @@ class test_vimconn_vminstance_by_affinity_anti_affinity(test_base): def setUp(self): # create network self.network_name = _get_random_string(20) - self.network_id = test_config["vim_conn"].new_network(net_name=self.network_name, + self.network_id, _ = test_config["vim_conn"].new_network(net_name=self.network_name, net_type='bridge') def tearDown(self): @@ -1897,7 +1975,8 @@ class test_vimconn_vminstance_by_affinity_anti_affinity(test_base): net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id, + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=image_id, flavor_id=flavor_id, net_list=net_list,availability_zone_index=1, availability_zone_list=['HG_174','HG_175']) @@ -1913,7 +1992,7 @@ class test_vimconn_vminstance_by_numa_affinity(test_base): def setUp(self): # create network self.network_name = _get_random_string(20) - self.network_id = test_config["vim_conn"].new_network(net_name=self.network_name, + self.network_id, _ = test_config["vim_conn"].new_network(net_name=self.network_name, net_type='bridge') def tearDown(self): @@ -1927,8 +2006,8 @@ class test_vimconn_vminstance_by_numa_affinity(test_base): def test_000_vminstance_by_numa_affinity(self): flavor_data = {'extended': {'numas': [{'paired-threads-id': [['1', '3'], ['2', '4']], - ' paired-threads': 2, 'memory': 1}]}, - 'ram': 1024, 'vcpus': 1, 'disk': 10} + ' paired-threads': 2, 'memory': 1}]}, + 'ram': 1024, 'vcpus': 1, 'disk': 10} name = "eth10" # create new flavor @@ -1945,7 +2024,8 @@ class test_vimconn_vminstance_by_numa_affinity(test_base): net_list = [{'use': 'bridge', 'name': name, 'floating_ip': False, 'port_security': True, 'type': 'virtual', 'net_id': self.network_id}] - instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', image_id=image_id, + instance_id, _ = test_config["vim_conn"].new_vminstance(name='Test1_vm', description='', start=False, + image_id=image_id, flavor_id=flavor_id, net_list=net_list) self.assertEqual(type(instance_id),str) @@ -2131,7 +2211,8 @@ def test_vimconnector(args): test_config['sriov_net_name'] = args.sriov_net_name # vmware connector obj - test_config['vim_conn'] = vim.vimconnector(name=org_name, tenant_name=tenant_name, user=org_user,passwd=org_passwd, url=vim_url, config=config_params) + test_config['vim_conn'] = vim.vimconnector(name=org_name, tenant_name=tenant_name, user=org_user, + passwd=org_passwd, url=vim_url, config=config_params) elif args.vimtype == "aws": import vimconn_aws as vim @@ -2163,6 +2244,32 @@ def test_vimconnector(args): elif args.vimtype == "openvim": import vimconn_openvim as vim + elif args.vimtype == "azure": + import vimconn_azure as vim + + test_config["test_directory"] = os.path.dirname(__file__) + "/RO_tests" + + tenant_name = args.tenant_name + test_config['tenant'] = tenant_name + config_params = yaml.load(args.config_param) + os_user = config_params.get('user') + os_passwd = config_params.get('passwd') + vim_url = args.endpoint_url + test_config['image_path'] = args.image_path + test_config['image_name'] = args.image_name + #test_config['sriov_net_name'] = args.sriov_net_name + + # azure connector obj + vim_persistent_info = {} + test_config['vim_conn'] = vim.vimconnector( + uuid="test-uuid-1", name="VIO-azure", + tenant_id=None, tenant_name=tenant_name, + url=vim_url, url_admin=None, + user=os_user, passwd=os_passwd, + config=config_params, persistent_info=vim_persistent_info + ) + test_config['vim_conn'].debug = "true" + else: logger.critical("vimtype '{}' not supported".format(args.vimtype)) sys.exit(1) @@ -2468,7 +2575,7 @@ if __name__=="__main__": vimconn_parser.set_defaults(func=test_vimconnector) # Mandatory arguments mandatory_arguments = vimconn_parser.add_argument_group('mandatory arguments') - mandatory_arguments.add_argument('--vimtype', choices=['vmware', 'aws', 'openstack', 'openvim'], required=True, + mandatory_arguments.add_argument('--vimtype', choices=['vmware', 'aws', 'openstack', 'openvim','azure'], required=True, help='Set the vimconnector type to test') mandatory_arguments.add_argument('-c', '--config', dest='config_param', required=True, help='Set the vimconnector specific config parameters in dictionary format')