From: tierno Date: Mon, 7 Oct 2019 16:38:23 +0000 (+0000) Subject: Merge branch 'master' into Azure X-Git-Tag: v7.0.0rc1~15^2~2 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=commitdiff_plain;h=1fa49b16e92ff2e4f512ccc466fdc3dff31559e4;hp=29be7ef3b0d4e47f1ba2183b1644be8c49aa1045 Merge branch 'master' into Azure Change-Id: Ia9726dfe53813157c1e3002a44f041861722d424 Signed-off-by: tierno --- 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 24a9878d..384d7533 100755 --- a/osm_ro/vimconn_azure.py +++ b/osm_ro/vimconn_azure.py @@ -3,8 +3,11 @@ __author__='Sergio Gonzalez' __date__ ='$18-apr-2019 23:59:59$' +import base64 + import vimconn import logging +import netaddr from os import getenv from uuid import uuid4 @@ -15,14 +18,32 @@ 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 = { + "Deleting": "INACTIVE", + "Failed": "ERROR", + "Succeeded": "ACTIVE", + "Updating": "BUILD", + } + def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None, config={}, persistent_info={}): vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, config, persistent_info) + self.vnet_address_space = None # LOGGER self.logger = logging.getLogger('openmano.vim.azure') if log_level: @@ -36,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') @@ -75,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): """ @@ -97,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): """ @@ -108,14 +166,31 @@ 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": + pass + else: + raise + # if not exist, creates it try: vnet_params = { 'location': self.region, 'address_space': { - 'address_prefixes': "10.0.0.0/8" + 'address_prefixes': ["10.0.0.0/8"] }, } + 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 except Exception as e: self.format_vimconn_exception(e) @@ -141,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): @@ -155,76 +229,183 @@ class vimconnector(vimconn.vimconnector): self._reload_connection() if ip_profile is None: - # TODO get a non used vnet ip range /24 and allocate automatically - raise vimconn.vimconnException('Azure cannot create VNET with no CIDR') + # 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 + 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: - vnet_params= { - 'location': self.region, - 'address_space': { - 'address_prefixes': [ip_profile['subnet_address']] - }, - 'subnets': [ - { - 'name': "{}-{}".format(net_name[:24], uuid4()), - 'address_prefix': ip_profile['subnet_address'] - } - ] + #subnet_name = "{}-{}".format(net_name[:24], uuid4()) + subnet_name = net_name[:24] + subnet_params= { + 'address_prefix': ip_profile['subnet_address'] } - self.conn_vnet.virtual_networks.create_or_update(self.resource_group, self.vnet_name, vnet_params) - # TODO return a tuple (subnet-ID, 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: @@ -244,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={}): @@ -277,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) @@ -305,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': [ @@ -347,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']) + + return listedFilteredSizes[0]['name'] + + except Exception as e: + self.format_vimconn_exception(e) + + 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)] - filteredSizes = [size for size in vm_sizes_list if size['numberOfCores'] > cpus and size['memoryInMB'] > memMB] - listedFilteredSizes = sorted(filteredSizes, key=lambda k: k['numberOfCores']) + output_flavor = None + for size in vm_sizes_list: + if size['name'] == flavor_name: + output_flavor = size - return listedFilteredSizes[0]['name'] + return output_flavor + + except Exception as e: + self.format_vimconn_exception(e) def check_vim_connectivity(self): try: @@ -389,47 +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 + 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)) - def delete_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() - 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: + 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) + + out_nets[net_id] ={ + "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", + "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: + + resName = self._get_resource_name_from_resource_id(vm_id) + + 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: + 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 refresh_nets_status ver estado activo -# TODO refresh_vms_status ver estado activo -# TODO get_vminstance_console for getting console if __name__ == "__main__": @@ -492,4 +991,9 @@ if __name__ == "__main__": # 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 + azure.new_network("mynet", None) + net_id = "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/Microsoft."\ + "Network/virtualNetworks/test" + net_id_not_found = "/subscriptions/82f80cc1-876b-4591-9911-1fb5788384fd/resourceGroups/osmRG/providers/"\ + "Microsoft.Network/virtualNetworks/testALF" + azure.refresh_nets_status([net_id, net_id_not_found]) diff --git a/test/test_RO.py b/test/test_RO.py index 932853c5..014030b0 100755 --- a/test/test_RO.py +++ b/test/test_RO.py @@ -20,6 +20,15 @@ # ## +# DEBUG WITH PDB +from os import getenv +if 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)) @@ -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 @@ -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) @@ -788,7 +798,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 +817,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} @@ -931,6 +947,10 @@ class test_vimconn_get_image_list(test_base): self.__class__.test_index, inspect.currentframe().f_code.co_name) self.__class__.test_index += 1 + + # 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: @@ -1031,9 +1051,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 +1074,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 +1101,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,7 +1136,7 @@ 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' @@ -1119,9 +1147,9 @@ class test_vimconn_new_vminstance(test_base): '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 +1170,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 +1185,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 +1214,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 +1238,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 +1302,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 +1311,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 +1349,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 +1366,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,11 +1376,17 @@ 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: @@ -1402,9 +1446,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 +1546,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 +1567,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 +1579,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' @@ -1789,7 +1848,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 +1876,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 +1908,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) @@ -1897,7 +1959,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']) @@ -1927,8 +1990,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 +2008,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 +2195,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 +2228,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 +2559,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')