X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=RO-VIM-openstack%2Fosm_rovim_openstack%2Fvimconn_openstack.py;h=99cb64f1edb229c8d3c3ede2e6731563a1255e4c;hb=cb66c7eab3945f92e9815cbb4007ed61679333d9;hp=289c8278e5669e662e91db4958082a8e4be28fd3;hpb=1ec592d80c7f07874b08a14984deb21fddb31441;p=osm%2FRO.git diff --git a/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py index 289c8278..99cb64f1 100644 --- a/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py +++ b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py @@ -410,13 +410,16 @@ class vimconnector(vimconn.VimConnector): """Transform a keystone, nova, neutron exception into a vimconn exception discovering the cause""" message_error = str(exception) + tip = "" if isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound, ksExceptions.NotFound, gl1Exceptions.HTTPNotFound)): raise vimconn.VimConnNotFoundException(type(exception).__name__ + ": " + message_error) elif isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError, ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed)): - raise vimconn.VimConnConnectionException(type(exception).__name__ + ": " + message_error) + if type(exception).__name__ == "SSLError": + tip = " (maybe option 'insecure' must be added to the VIM)" + raise vimconn.VimConnConnectionException("Invalid URL or credentials{}: {}".format(tip, message_error)) elif isinstance(exception, (KeyError, nvExceptions.BadRequest, ksExceptions.BadRequest)): raise vimconn.VimConnException(type(exception).__name__ + ": " + message_error) elif isinstance(exception, (nvExceptions.ClientException, ksExceptions.ClientException, @@ -566,9 +569,10 @@ class vimconnector(vimconn.VimConnector): provider_physical_network = provider_physical_network[0] if not provider_physical_network: - raise vimconn.VimConnConflictException("You must provide a 'dataplane_physical_net' at VIM_config " - "for creating underlay networks. or use the NS instantiation" - " parameter provider-network:physical-network for the VLD") + raise vimconn.VimConnConflictException( + "missing information needed for underlay networks. Provide 'dataplane_physical_net' " + "configuration at VIM or use the NS instantiation parameter 'provider-network.physical-network'" + " for the VLD") if not self.config.get('multisegment_support'): network_dict["provider:physical_network"] = provider_physical_network @@ -1222,19 +1226,19 @@ class vimconnector(vimconn.VimConnector): vim_id: filled/added by this function floating_ip: True/False (or it can be None) 'cloud_config': (optional) dictionary with: - 'key-pairs': (optional) list of strings with the public key to be inserted to the default user - 'users': (optional) list of users to be inserted, each item is a dict with: - 'name': (mandatory) user name, - 'key-pairs': (optional) list of strings with the public key to be inserted to the user - 'user-data': (optional) string is a text script to be passed directly to cloud-init - 'config-files': (optional). List of files to be transferred. Each item is a dict with: - 'dest': (mandatory) string with the destination absolute path - 'encoding': (optional, by default text). Can be one of: - 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64' - 'content' (mandatory): string with the content of the file - 'permissions': (optional) string with file permissions, typically octal notation '0644' - 'owner': (optional) file owner, string with the format 'owner:group' - 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk) + 'key-pairs': (optional) list of strings with the public key to be inserted to the default user + 'users': (optional) list of users to be inserted, each item is a dict with: + 'name': (mandatory) user name, + 'key-pairs': (optional) list of strings with the public key to be inserted to the user + 'user-data': (optional) string is a text script to be passed directly to cloud-init + 'config-files': (optional). List of files to be transferred. Each item is a dict with: + 'dest': (mandatory) string with the destination absolute path + 'encoding': (optional, by default text). Can be one of: + 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64' + 'content' (mandatory): string with the content of the file + 'permissions': (optional) string with file permissions, typically octal notation '0644' + 'owner': (optional) file owner, string with the format 'owner:group' + 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk) 'disk_list': (optional) list with additional disks to the VM. Each item is a dict with: 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted 'size': (mandatory) string with the size of the disk in GB @@ -1418,20 +1422,23 @@ class vimconnector(vimconn.VimConnector): # print "DONE :-)", server # pool_id = None - if external_network: - floating_ips = self.neutron.list_floatingips().get("floatingips", ()) for floating_network in external_network: try: assigned = False + floating_ip_retries = 3 + # In case of RO in HA there can be conflicts, two RO trying to assign same floating IP, so retry + # several times while not assigned: - if floating_ips: - ip = floating_ips.pop(0) - if ip.get("port_id", False) or ip.get('tenant_id') != server.tenant_id: + floating_ips = self.neutron.list_floatingips().get("floatingips", ()) + random.shuffle(floating_ips) # randomize + for fip in floating_ips: + if fip.get("port_id") or fip.get('tenant_id') != server.tenant_id: continue if isinstance(floating_network['floating_ip'], str): - if ip.get("floating_network_id") != floating_network['floating_ip']: + if fip.get("floating_network_id") != floating_network['floating_ip']: continue - free_floating_ip = ip["id"] + free_floating_ip = fip["id"] + break else: if isinstance(floating_network['floating_ip'], str) and \ floating_network['floating_ip'].lower() != "true": @@ -1458,31 +1465,44 @@ class vimconnector(vimconn.VimConnector): # self.logger.debug("Creating floating IP") new_floating_ip = self.neutron.create_floatingip(param) free_floating_ip = new_floating_ip['floatingip']['id'] + created_items["floating_ip:" + str(free_floating_ip)] = True except Exception as e: raise vimconn.VimConnException(type(e).__name__ + ": Cannot create new floating_ip " + str(e), http_code=vimconn.HTTP_Conflict) - while not assigned: - try: - # the vim_id key contains the neutron.port_id - self.neutron.update_floatingip(free_floating_ip, - {"floatingip": {"port_id": floating_network["vim_id"]}}) - # Using nove is deprecated on nova client 10.0 - assigned = True - except Exception as e: - # openstack need some time after VM creation to asign an IP. So retry if fails - vm_status = self.nova.servers.get(server.id).status - if vm_status != 'ACTIVE' and vm_status != 'ERROR': - if time.time() - vm_start_time < server_timeout: - time.sleep(5) - continue - raise vimconn.VimConnException( - "Cannot create floating_ip: {} {}".format(type(e).__name__, e), - http_code=vimconn.HTTP_Conflict) + try: + # for race condition ensure not already assigned + fip = self.neutron.show_floatingip(free_floating_ip) + if fip['floatingip']['port_id']: + continue + # the vim_id key contains the neutron.port_id + self.neutron.update_floatingip(free_floating_ip, + {"floatingip": {"port_id": floating_network["vim_id"]}}) + # for race condition ensure not re-assigned to other VM after 5 seconds + time.sleep(5) + fip = self.neutron.show_floatingip(free_floating_ip) + if fip['floatingip']['port_id'] != floating_network["vim_id"]: + self.logger.error("floating_ip {} re-assigned to other port".format(free_floating_ip)) + continue + self.logger.debug("Assigned floating_ip {} to VM {}".format(free_floating_ip, server.id)) + assigned = True + except Exception as e: + # openstack need some time after VM creation to assign an IP. So retry if fails + vm_status = self.nova.servers.get(server.id).status + if vm_status not in ('ACTIVE', 'ERROR'): + if time.time() - vm_start_time < server_timeout: + time.sleep(5) + continue + elif floating_ip_retries > 0: + floating_ip_retries -= 1 + continue + raise vimconn.VimConnException( + "Cannot create floating_ip: {} {}".format(type(e).__name__, e), + http_code=vimconn.HTTP_Conflict) except Exception as e: if not floating_network['exit_on_floating_ip_error']: - self.logger.warning("Cannot create floating_ip. %s", str(e)) + self.logger.error("Cannot create floating_ip. %s", str(e)) continue raise @@ -1614,8 +1634,13 @@ class vimconnector(vimconn.VimConnector): keep_waiting = True else: self.cinder.volumes.delete(k_id) + created_items[k] = None + elif k_item == "floating_ip": # floating ip + self.neutron.delete_floatingip(k_id) + created_items[k] = None + except Exception as e: - self.logger.error("Error deleting volume: {}: {}".format(type(e).__name__, e)) + self.logger.error("Error deleting {}: {}".format(k, e)) if keep_waiting: time.sleep(1) elapsed_time += 1