X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=vimconn_openstack.py;h=e0a3aa31dc0cf4e94d8321515cff887df29fd06f;hb=1f3a67138592443a8bd68ab936e071cb5bccda55;hp=6e5f007752f7622d350db086ed6fe685a81376a3;hpb=a4e1a6ed87de04788ec6855fc8a5e722914e4f03;p=osm%2FRO.git diff --git a/vimconn_openstack.py b/vimconn_openstack.py index 6e5f0077..e0a3aa31 100644 --- a/vimconn_openstack.py +++ b/vimconn_openstack.py @@ -31,6 +31,7 @@ import vimconn import json import yaml import logging +import netaddr from novaclient import client as nClient, exceptions as nvExceptions import keystoneclient.v2_0.client as ksClient @@ -55,7 +56,7 @@ netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE', } class vimconnector(vimconn.vimconnector): - def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level="DEBUG", config={}): + def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None, config={}): '''using common constructor parameters. In this case 'url' is the keystone authorization url, 'url_admin' is not use @@ -81,7 +82,9 @@ class vimconnector(vimconn.vimconnector): self.k_creds['password'] = passwd self.n_creds['api_key'] = passwd self.reload_client = True - self.logger = logging.getLogger('mano.vim.openstack') + self.logger = logging.getLogger('openmano.vim.openstack') + if log_level: + self.logger.setLevel( getattr(logging, log_level) ) def __setitem__(self,index, value): '''Set individuals parameters @@ -171,8 +174,8 @@ class vimconnector(vimconn.vimconnector): def _format_exception(self, exception): '''Transform a keystone, nova, neutron exception into a vimconn exception''' if isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError, - ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed, - neClient.exceptions.ConnectionFailed)): + ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed + )): raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception)) elif isinstance(exception, (nvExceptions.ClientException, ksExceptions.ClientException, neExceptions.NeutronException, nvExceptions.BadRequest)): @@ -200,7 +203,7 @@ class vimconnector(vimconn.vimconnector): for tenant in tenant_class_list: tenant_list.append(tenant.to_dict()) return tenant_list - except (ksExceptions.ConnectionError, ksExceptions.ClientException) as e: + except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError) as e: self._format_exception(e) def new_tenant(self, tenant_name, tenant_description): @@ -210,7 +213,7 @@ class vimconnector(vimconn.vimconnector): self._reload_connection() tenant=self.keystone.tenants.create(tenant_name, tenant_description) return tenant.id - except (ksExceptions.ConnectionError, ksExceptions.ClientException) as e: + except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError) as e: self._format_exception(e) def delete_tenant(self, tenant_id): @@ -220,13 +223,15 @@ class vimconnector(vimconn.vimconnector): self._reload_connection() self.keystone.tenants.delete(tenant_id) return tenant_id - except (ksExceptions.ConnectionError, ksExceptions.ClientException) as e: + except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError) as e: self._format_exception(e) - def new_network(self,net_name,net_type, shared=False, cidr=None, vlan=None): + def new_network(self,net_name, net_type, ip_profile=None, shared=False, vlan=None): '''Adds a tenant network to VIM. Returns the network identifier''' self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type) + #self.logger.debug(">>>>>>>>>>>>>>>>>> IP profile %s", str(ip_profile)) try: + new_net = None self._reload_connection() network_dict = {'name': net_name, 'admin_state_up': True} if net_type=="data" or net_type=="ptp": @@ -239,17 +244,44 @@ class vimconnector(vimconn.vimconnector): network_dict["shared"]=shared new_net=self.neutron.create_network({'network':network_dict}) #print new_net - #create fake subnetwork - if not cidr: - cidr="192.168.111.0/24" + #create subnetwork, even if there is no profile + if not ip_profile: + ip_profile = {} + if 'subnet_address' not in ip_profile: + #Fake subnet is required + ip_profile['subnet_address'] = "192.168.111.0/24" + if 'ip_version' not in ip_profile: + ip_profile['ip_version'] = "IPv4" subnet={"name":net_name+"-subnet", "network_id": new_net["network"]["id"], - "ip_version": 4, - "cidr": cidr + "ip_version": 4 if ip_profile['ip_version']=="IPv4" else 6, + "cidr": ip_profile['subnet_address'] } + if 'gateway_address' in ip_profile: + subnet['gateway_ip'] = ip_profile['gateway_address'] + if ip_profile.get('dns_address'): + #TODO: manage dns_address as a list of addresses separated by commas + subnet['dns_nameservers'] = [] + subnet['dns_nameservers'].append(ip_profile['dns_address']) + if 'dhcp_enabled' in ip_profile: + subnet['enable_dhcp'] = False if ip_profile['dhcp_enabled']=="false" else True + if 'dhcp_start_address' in ip_profile: + subnet['allocation_pools']=[] + subnet['allocation_pools'].append(dict()) + subnet['allocation_pools'][0]['start'] = ip_profile['dhcp_start_address'] + if 'dhcp_count' in ip_profile: + #parts = ip_profile['dhcp_start_address'].split('.') + #ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3]) + ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address'])) + ip_int += ip_profile['dhcp_count'] - 1 + ip_str = str(netaddr.IPAddress(ip_int)) + subnet['allocation_pools'][0]['end'] = ip_str + #self.logger.debug(">>>>>>>>>>>>>>>>>> Subnet: %s", str(subnet)) self.neutron.create_subnet({"subnet": subnet} ) return new_net["network"]["id"] - except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException) as e: + except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e: + if new_net: + self.neutron.delete_network(new_net['network']['id']) self._format_exception(e) def get_network_list(self, filter_dict={}): @@ -270,7 +302,7 @@ class vimconnector(vimconn.vimconnector): net_list=net_dict["networks"] self.__net_os2mano(net_list) return net_list - except (neExceptions.ConnectionFailed, neClient.exceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException) as e: + except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e: self._format_exception(e) def get_network(self, net_id): @@ -310,7 +342,7 @@ class vimconnector(vimconn.vimconnector): self.neutron.delete_network(net_id) return net_id except (neExceptions.ConnectionFailed, neExceptions.NetworkNotFoundClient, neExceptions.NeutronException, - neClient.exceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException) as e: + ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e: self._format_exception(e) def refresh_nets_status(self, net_list): @@ -341,9 +373,12 @@ class vimconnector(vimconn.vimconnector): net["status"] = "OTHER" net["error_msg"] = "VIM status reported " + net_vim['status'] - if net['status'] == "ACIVE" and not net_vim['admin_state_up']: + if net['status'] == "ACTIVE" and not net_vim['admin_state_up']: net['status'] = 'DOWN' - net['vim_info'] = yaml.safe_dump(net_vim) + try: + net['vim_info'] = yaml.safe_dump(net_vim, default_flow_style=True, width=256) + except yaml.representer.RepresenterError: + net['vim_info'] = str(net_vim) if net_vim.get('fault'): #TODO net['error_msg'] = str(net_vim['fault']) except vimconn.vimconnNotFoundException as e: @@ -365,7 +400,7 @@ class vimconnector(vimconn.vimconnector): flavor = self.nova.flavors.find(id=flavor_id) #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema) return flavor.to_dict() - except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException) as e: + except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e: self._format_exception(e) def new_flavor(self, flavor_data, change_name_if_used=True): @@ -451,7 +486,7 @@ class vimconnector(vimconn.vimconnector): self.nova.flavors.delete(flavor_id) return flavor_id #except nvExceptions.BadRequest as e: - except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException) as e: + except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e: self._format_exception(e) def new_image(self,image_dict): @@ -513,7 +548,7 @@ class vimconnector(vimconn.vimconnector): return new_image.id except (nvExceptions.Conflict, ksExceptions.ClientException, nvExceptions.ClientException) as e: self._format_exception(e) - except (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError) as e: + except (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError, ConnectionError) as e: if retry==max_retries: continue self._format_exception(e) @@ -528,12 +563,11 @@ class vimconnector(vimconn.vimconnector): self._reload_connection() self.nova.images.delete(image_id) return image_id - except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError) as e: #TODO remove + except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: #TODO remove self._format_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 - ''' + '''Get the image id from image path in the VIM database. Returns the image_id''' try: self._reload_connection() images = self.nova.images.list() @@ -541,9 +575,38 @@ class vimconnector(vimconn.vimconnector): if image.metadata.get("location")==path: return image.id raise vimconn.vimconnNotFoundException("image with location '{}' not found".format( path)) - except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError) as e: + except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: self._format_exception(e) + def get_image_list(self, filter_dict={}): + '''Obtain tenant images from VIM + Filter_dict can be: + id: image id + name: image name + checksum: image checksum + Returns the image list of dictionaries: + [{}, ...] + List can be empty + ''' + self.logger.debug("Getting image list from VIM filter: '%s'", str(filter_dict)) + try: + self._reload_connection() + filter_dict_os=filter_dict.copy() + #First we filter by the available filter fields: name, id. The others are removed. + filter_dict_os.pop('checksum',None) + image_list=self.nova.images.findall(**filter_dict_os) + if len(image_list)==0: + return [] + #Then we filter by the rest of filter fields: checksum + filtered_list = [] + for image in image_list: + image_dict=self.glance.images.get(image.id) + if image_dict['checksum']==filter_dict.get('checksum'): + filtered_list.append(image) + return filtered_list + except (ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: + self._format_exception(e) + def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None): '''Adds a VM instance to VIM Params: @@ -660,8 +723,8 @@ class vimconnector(vimconn.vimconnector): # except nvExceptions.NotFound as e: # error_value=-vimconn.HTTP_Not_Found # error_text= "vm instance %s not found" % vm_id - except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError, - neClient.exceptions.ConnectionFailed) as e: + except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError + ) as e: self._format_exception(e) except TypeError as e: raise vimconn.vimconnException(type(e).__name__ + ": "+ str(e), http_code=vimconn.HTTP_Bad_Request) @@ -674,7 +737,7 @@ class vimconnector(vimconn.vimconnector): server = self.nova.servers.find(id=vm_id) #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema) return server.to_dict() - except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound) as e: + except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e: self._format_exception(e) def get_vminstance_console(self,vm_id, console_type="vnc"): @@ -725,7 +788,7 @@ class vimconnector(vimconn.vimconnector): return console_dict raise vimconn.vimconnUnexpectedResponse("Unexpected response from VIM") - except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.BadRequest) as e: + except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.BadRequest, ConnectionError) as e: self._format_exception(e) def delete_vminstance(self, vm_id): @@ -743,7 +806,7 @@ class vimconnector(vimconn.vimconnector): self.logger.error("Error deleting port: " + type(e).__name__ + ": "+ str(e)) self.nova.servers.delete(vm_id) return vm_id - except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException) as e: + except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e: self._format_exception(e) #TODO insert exception vimconn.HTTP_Unauthorized #if reaching here is because an exception @@ -782,7 +845,10 @@ class vimconnector(vimconn.vimconnector): else: vm['status'] = "OTHER" vm['error_msg'] = "VIM status reported " + vm_vim['status'] - vm['vim_info'] = yaml.safe_dump(vm_vim) + try: + vm['vim_info'] = yaml.safe_dump(vm_vim, default_flow_style=True, width=256) + except yaml.representer.RepresenterError: + vm['vim_info'] = str(vm_vim) vm["interfaces"] = [] if vm_vim.get('fault'): vm['error_msg'] = str(vm_vim['fault']) @@ -792,7 +858,10 @@ class vimconnector(vimconn.vimconnector): port_dict=self.neutron.list_ports(device_id=vm_id) for port in port_dict["ports"]: interface={} - interface['vim_info'] = yaml.safe_dump(port) + try: + interface['vim_info'] = yaml.safe_dump(port, default_flow_style=True, width=256) + except yaml.representer.RepresenterError: + interface['vim_info'] = str(port) interface["mac_address"] = port.get("mac_address") interface["vim_net_id"] = port["network_id"] interface["vim_interface_id"] = port["id"] @@ -889,7 +958,7 @@ class vimconnector(vimconn.vimconnector): raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict)) return vm_id - except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound) as e: + except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e: self._format_exception(e) #TODO insert exception vimconn.HTTP_Unauthorized