def _delete_port_group(self, pg_ref, name, ignore_in_use=False): while True: try: pg_delete_task = pg_ref.Destroy_Task() wait_for_task(pg_delete_task, si=self.connection) LOG.info(_LI('Network %(name)s deleted.') % {'name': name}) self._port_groups_by_name.pop(name, None) return True except vim.fault.ResourceInUse as e: if ignore_in_use: LOG.info( _LW("Could not delete port-group %(name)s. Reason: %(message)s" ) % { 'name': name, 'message': e.message }) return False else: raise exceptions.wrap_wmvare_vim_exception(e) except vim.fault.VimFault as e: if dvs_const.DELETED_TEXT in e.message: return True else: raise exceptions.wrap_wmvare_vim_exception(e) return False
def book_port(self, network, port_name, segment, net_name=None): try: if not net_name: net_name = self._get_net_name(self.dvs_name, network) pg = self._get_or_create_pg(net_name, network, segment) for iter in range(0, 4): try: port_info = self._lookup_unbound_port_or_increase_pg(pg) port_settings = self.builder.port_setting() port_settings.blocked = self.builder.blocked(False) update_spec = self.builder.port_config_spec( port_info.config.configVersion, port_settings, name=port_name) update_spec.key = port_info.key update_task = self.connection.invoke_api( self.connection.vim, 'ReconfigureDVPort_Task', self._dvs, port=[update_spec]) self.connection.wait_for_task(update_task) return port_info.key except vmware_exceptions.VimException as e: sleep(0.1) raise exceptions.wrap_wmvare_vim_exception(e) except vmware_exceptions.VimException as e: raise exceptions.wrap_wmvare_vim_exception(e)
def update_network(self, network, original=None): original_name = self._get_net_name(self.dvs_name, original) if original else None current_name = self._get_net_name(self.dvs_name, network) blocked = not network['admin_state_up'] try: pg_ref = self._get_pg_by_name(original_name or current_name) pg_config_info = self._get_config_by_ref(pg_ref) if (pg_config_info.defaultPortConfig.blocked.value != blocked or (original_name and original_name != current_name)): # we upgrade only defaultPortConfig, because it is inherited # by all ports in PortGroup, unless they are explicitly # overwritten on specific port. pg_spec = self._build_pg_update_spec( pg_config_info.configVersion, blocked=blocked) pg_spec.name = current_name pg_update_task = self.connection.invoke_api( self.connection.vim, 'ReconfigureDVPortgroup_Task', pg_ref, spec=pg_spec) self.connection.wait_for_task(pg_update_task) LOG.info(_LI('Network %(name)s updated'), {'name': current_name}) except vmware_exceptions.VimException as e: raise exceptions.wrap_wmvare_vim_exception(e)
def update_dvportgroup(self, pg_ref, config_version, port_config=None, name=None, retries=3): if retries <= 0: LOG.error("Maximum number of update retries reached for portgroup {}.".format(pg_ref)) return try: pg_spec = self.builder.pg_config(port_config) pg_spec.configVersion = config_version if name: pg_spec.name = name now = timeutils.utcnow() pg_update_task = self.connection.invoke_api( self.connection.vim, 'ReconfigureDVPortgroup_Task', pg_ref, spec=pg_spec) self.connection.wait_for_task(pg_update_task) delta = timeutils.utcnow() - now stats.timing('networking_dvs.dvportgroup.updated', delta) LOG.debug("Updating portgroup {} took {} seconds.".format(pg_ref, delta.seconds)) except vmware_exceptions.VimException as e: if dvs_const.CONCURRENT_MODIFICATION_TEXT in str(e): LOG.debug("Concurrent modification detected, will retry.") config_version = vim_util.get_object_property( self.connection.vim, pg_ref, "config.configVersion") return self.update_dvportgroup(pg_ref, config_version, port_config, name, retries-1) if dvs_const.BULK_FAULT_TEXT in str(e): info = get_task_info(self.connection, pg_update_task) self.rectifyForFault(info.error.fault) return raise exceptions.wrap_wmvare_vim_exception(e)
def update_mtu(self, max_mtu): if max_mtu == self._max_mtu: return try: pg_config_info = self._build_dvswitch_update_spec() pg_config_info.maxMtu = max_mtu pg_config_info.configVersion = self._config_version pg_update_task = self._dvs.ReconfigureDvs_Task(spec=pg_config_info) wait_for_task(pg_update_task, si=self.connection) self.max_mtu = max_mtu except vim.fault.VimFault as e: raise exceptions.wrap_wmvare_vim_exception(e)
def switch_port_blocked_state(self, port): try: port_info = self.get_port_info(port) port_settings = self.builder.port_setting() state = not port['admin_state_up'] port_settings.blocked = self.builder.blocked(state) update_spec = self.builder.port_config_spec( port_info.config.configVersion, port_settings) update_spec.key = port_info.key self.update_ports([update_spec]) except exceptions.PortNotFound: LOG.debug("Port %s was not found. Nothing to block." % port['id']) except vmware_exceptions.VimException as e: raise exceptions.wrap_wmvare_vim_exception(e)
def book_port(self, network, port_name, segment, net_name=None): try: if not net_name: net_name = self._get_net_name(self.dvs_name, network) pg = self._get_or_create_pg(net_name, network, segment) for iter in range(0, 4): try: port_info = self._lookup_unbound_port_or_increase_pg(pg) port_settings = builder.port_setting() port_settings.blocked = builder.blocked(False) update_spec = builder.port_config_spec( port_info.config.configVersion, port_settings, name=port_name) update_spec.key = port_info.key update_task = self.submit_update_ports([update_spec]) wait_for_task(update_task, si=self.connection) return port_info.key except vim.fault.VimFault as e: sleep(0.1) raise exceptions.wrap_wmvare_vim_exception(e) except vim.fault.VimFault as e: raise exceptions.wrap_wmvare_vim_exception(e)
def release_port(self, port): try: port_info = self.get_port_info(port) update_spec = builder.port_config_spec( port_info.config.configVersion, name='') update_spec.key = port_info.key # setting = builder.port_setting() # setting.filterPolicy = builder.filter_policy([]) # update_spec.setting = setting update_spec.operation = 'remove' update_task = self.submit_update_ports([update_spec]) wait_for_task(update_task, si=self.connection) self.remove_block(port_info.key) except exceptions.PortNotFound: LOG.debug("Port %s was not found. Nothing to delete." % port['id']) except exceptions.ResourceInUse: LOG.debug("Port %s in use. Nothing to delete." % port['id']) except vim.fault.VimFault as e: raise exceptions.wrap_wmvare_vim_exception(e)
def __init__(self, dvs_name, connection=None, pool=None, rectify_wait=120): self.connection = connection self.dvs_name = dvs_name self._uuid = None self.pool = pool self._update_spec_queue = [] self.ports_by_key = {} self._blocked_ports = set() self._service_content = connection.vim.retrieve_service_content() self.builder = spec_builder.SpecBuilder( self.connection.vim.client.factory) self.hosts_to_rectify = {} self.rectify_wait = rectify_wait try: self._dvs, self._datacenter = self._get_dvs(dvs_name, connection) # (SlOPS) To do release blocked port after use self._blocked_ports = set() except vmware_exceptions.VimException as e: raise exceptions.wrap_wmvare_vim_exception(e)
def release_port(self, port): try: port_info = self.get_port_info(port) update_spec = self.builder.port_config_spec( port_info.config.configVersion, name='') update_spec.key = port_info.key #setting = self.builder.port_setting() #setting.filterPolicy = self.builder.filter_policy([]) #update_spec.setting = setting update_spec.operation = 'remove' update_task = self.connection.invoke_api( self.connection.vim, 'ReconfigureDVPort_Task', self._dvs, port=[update_spec]) self.connection.wait_for_task(update_task) self.remove_block(port_info.key) except exceptions.PortNotFound: LOG.debug("Port %s was not found. Nothing to delete." % port['id']) except exceptions.ResourceInUse: LOG.debug("Port %s in use. Nothing to delete." % port['id']) except vmware_exceptions.VimException as e: raise exceptions.wrap_wmvare_vim_exception(e)
def create_network(self, network, segment): name = self._get_net_name(self.dvs_name, network) blocked = not network['admin_state_up'] try: pg_spec = self._build_pg_create_spec(name, segment['segmentation_id'], blocked) pg_create_task = self._dvs.CreateDVPortgroup_Task(spec=pg_spec) result = wait_for_task(pg_create_task, si=self.connection) except vim.fault.VimFault as e: raise exceptions.wrap_wmvare_vim_exception(e) else: pg = result.result self._port_groups_by_name[name] = pg LOG.info(_LI('Network %(name)s created \n%(pg_ref)s'), { 'name': name, 'pg_ref': pg }) return pg
def _delete_port_group(self, pg_ref, name, ignore_in_use=False): while True: try: pg_delete_task = self.connection.invoke_api( self.connection.vim, 'Destroy_Task', pg_ref) self.connection.wait_for_task(pg_delete_task) LOG.info(_LI('Network %(name)s deleted.') % {'name': name}) break except vmware_exceptions.VimException as e: if not ignore_in_use or not re.match("The resource '\d*' is in use.", e.message): raise exceptions.wrap_wmvare_vim_exception(e) else: LOG.warn(_LW("Could not delete port-group %(name)s. Reason: %(message)s") % {'name': name, 'message': e.message}) break except vmware_exceptions.VMwareDriverException as e: if dvs_const.DELETED_TEXT in e.message: sleep(0.1) else: raise
def create_network(self, network, segment): name = self._get_net_name(self.dvs_name, network) blocked = not network['admin_state_up'] try: pg_spec = self._build_pg_create_spec( name, segment['segmentation_id'], blocked) pg_create_task = self.connection.invoke_api( self.connection.vim, 'CreateDVPortgroup_Task', self._dvs, spec=pg_spec) result = self.connection.wait_for_task(pg_create_task) except vmware_exceptions.VimException as e: raise exceptions.wrap_wmvare_vim_exception(e) else: pg = result.result LOG.info(_LI('Network %(name)s created \n%(pg_ref)s'), {'name': name, 'pg_ref': pg}) return pg
def __init__(self, dvs_name, connection=None, pool=None, rectify_wait=120): self.connection = connection self.dvs_name = dvs_name self.max_mtu = None self.pool = pool self._update_spec_queue = [] self.ports_by_key = {} self._blocked_ports = set() self.hosts_to_rectify = {} self.rectify_wait = rectify_wait try: self._dvs, self._datacenter = self._get_dvs(dvs_name, connection) # (SlOPS) To do release blocked port after use self._blocked_ports = set() except vim.fault.VimFault as e: raise exceptions.wrap_wmvare_vim_exception(e) dvs_config = self._dvs.config self._uuid = dvs_config.uuid self._max_mtu = dvs_config.maxMtu self._config_version = dvs_config.configVersion self._port_groups_by_name = {}
def create_dvportgroup(self, sg_set, port_config, update=True): """ Creates an automatically-named dvportgroup on the dvswitch with the specified sg rules and marks it as such through the description Returns a dictionary with "key" and "ref" keys. Note, that while a portgroup's key and managed object id have the same string format and appear identical under normal use it is possible to have them diverge by the use of the backup and restore feature of the dvs for example. As such, one should not rely on any equivalence between them. """ # There is a create_network method a few lines above # which seems to be part of a non-used call path # starting from the dvs_agent_rpc_api. TODO - remove it dvpg_name = dvportgroup_name(self.uuid, sg_set) portgroups = self._get_portgroups() if dvpg_name in portgroups: existing = portgroups[dvpg_name] if update: self.update_dvportgroup(existing, port_config) return existing if CONF.AGENT.dry_run: return try: pg_spec = builder.pg_config(port_config) pg_spec.name = dvpg_name pg_spec.numPorts = 0 pg_spec.type = 'earlyBinding' pg_spec.description = sg_set now = timeutils.utcnow() pg_create_task = self._dvs.CreateDVPortgroup_Task(spec=pg_spec) result = wait_for_task(pg_create_task, si=self.connection) pg_ref = result.result props = util.get_object_properties_dict(self.connection, pg_ref, ["key"]) delta = timeutils.utcnow() - now stats.timing('networking_dvs.dvportgroup.created', delta) LOG.debug("Creating portgroup {} took {} seconds.".format( pg_ref.value, delta.seconds)) pg = PortGroup(key=props["key"], ref=pg_ref, name=dvpg_name, config_version=0, description=sg_set, default_port_config=port_config) self._port_groups_by_name[dvpg_name] = pg return pg except vim.fault.DuplicateName as dn: LOG.info( "Untagged portgroup with matching name {} found, will update and use." .format(dvpg_name)) if dvpg_name not in portgroups: portgroups = self._get_portgroups(refresh=True) if dvpg_name not in portgroups: LOG.error( "Portgroup with matching name {} not found while expected." .format(dvpg_name)) return existing = portgroups[dvpg_name] if update: self.update_dvportgroup(existing, port_config) return existing except vim.fault.VimFault as e: raise exceptions.wrap_wmvare_vim_exception(e)
def _apply_queued_update_specs(self, update_specs, callbacks, retries=5): if not update_specs: return failed_keys = [] for i in range(retries): try: value = self.update_ports(update_specs) for spec in update_specs: port = self.ports_by_key[spec.key] port_desc = port.get('port_desc', None) if port_desc and port_desc.config_version: port_desc.config_version = str(int(port_desc.config_version) + 1) if callbacks: succeeded_keys = [str(spec.key) for spec in update_specs] for callback in callbacks: if callable(callback): callback(self, succeeded_keys, failed_keys) return value except vmware_exceptions.VimException as e: if dvs_const.CONCURRENT_MODIFICATION_TEXT in e.msg: for port_info in self.get_port_info_by_portkey([spec.key for spec in update_specs]): port_key = str(port_info.key) port = self.ports_by_key[port_key] port_desc = port['port_desc'] update_spec_index = None update_spec = None for index, item in enumerate(update_specs): if item.key == port_key: update_spec = item update_spec_index = index break connection_cookie = getattr(port_info, "connectionCookie", None) if connection_cookie: connection_cookie = str(connection_cookie) if connection_cookie != port_desc.connection_cookie: LOG.error("Cookie mismatch {} {} {} <> {}".format(port_desc.mac_address, port_desc.port_key, port_desc.connection_cookie, connection_cookie)) if update_spec_index: failed_keys.append(port_key) del update_specs[update_spec_index] else: config_version = str(port_info.config.configVersion) port_desc.config_version = config_version if update_spec: LOG.debug("Config version {} {} from {} ({}) to {}".format(port_desc.mac_address, port_desc.port_key, port_desc.config_version, update_spec.configVersion, config_version)) update_spec.configVersion = config_version continue raise exceptions.wrap_wmvare_vim_exception(e)
def update_dvportgroup(self, pg, port_config=None, name=None, retries=3): for ntry in six.moves.xrange(retries): pg_ref = pg.ref if not pg.name: LOG.debug("Missing name for %s", pg_ref.value) if pg.async_fetch: LOG.warning("Blocking on port-group %s", pg.name) pg.async_fetch.wait() default_port_config = pg.default_port_config if (name == pg.name or not name) \ and (default_port_config or not port_config) \ and not _config_differs(default_port_config, port_config): LOG.debug("Skipping update: No changes to known config on %s", pg.name) return try: pg_spec = builder.pg_config(port_config) pg_spec.configVersion = str(pg.config_version) if name and name != pg.name: pg_spec.name = name now = timeutils.utcnow() if not CONF.AGENT.dry_run: pg_update_task = pg_ref.ReconfigureDVPortgroup_Task( spec=pg_spec) else: LOG.debug(pg_spec) pg.config_version = str(int(pg.config_version) + 1) pg.default_port_config = port_config if not CONF.AGENT.dry_run: wait_for_task(pg_update_task, si=self.connection) delta = timeutils.utcnow() - now stats.timing('networking_dvs.dvportgroup.updated', delta) LOG.debug("Updating portgroup {} took {} seconds.".format( pg_ref.value, delta.seconds)) return except vim.fault.DvsOperationBulkFault as e: self.rectify_for_fault(e) except vim.fault.VimFault as e: if dvs_const.CONCURRENT_MODIFICATION_TEXT in str(e) \ and ntry != retries - 1: LOG.debug("Concurrent modification detected, will retry.") ## TODO A proper read-out of the current config props = util.get_object_properties_dict( self.connection, pg_ref, ["config.configVersion", "config.defaultPortConfig"]) pg.config_version = props["config.configVersion"] pg.default_port_config = props["config.defaultPortConfig"] continue raise exceptions.wrap_wmvare_vim_exception(e)
def create_dvportgroup(self, sg_attr_key, sg_set, port_config): """ Creates an automatically-named dvportgroup on the dvswitch with the specified sg rules and marks it as such through a custom attribute Returns a dictionary with "key" and "ref" keys. Note, that while a portgroup's key and managed object id have the same string format and appear identical under normal use it is possible to have them diverge by the use of the backup and restore feature of the dvs for example. As such, one should not rely on any equivalence between them. """ # There is a create_network method a few lines above # which seems to be part of a non-used call path # starting from the dvs_agent_rpc_api. TODO - remove it dvpg_name = self.dvportgroup_name(sg_set) try: pg_spec = self.builder.pg_config(port_config) pg_spec.name = dvpg_name pg_spec.numPorts = 0 pg_spec.type = 'earlyBinding' pg_spec.description = sg_set now = timeutils.utcnow() pg_create_task = self.connection.invoke_api( self.connection.vim, 'CreateDVPortgroup_Task', self._dvs, spec=pg_spec) result = self.connection.wait_for_task(pg_create_task) pg_ref = result.result # Tag the portgroup for the specific security group set self.connection.invoke_api( self.connection.vim, "SetField", self._service_content.customFieldsManager, entity=pg_ref, key=sg_attr_key, value=sg_set) props = vim_util.get_object_properties_dict(self.connection.vim, pg_ref, ["key"]) delta = timeutils.utcnow() - now stats.timing('networking_dvs.dvportgroup.created', delta) LOG.debug("Creating portgroup {} took {} seconds.".format(pg_ref, delta.seconds)) return {"key": props["key"], "ref": pg_ref} except vmware_exceptions.DuplicateName as dn: LOG.info("Untagged portgroup with matching name {} found, will update and use.".format(dvpg_name)) portgroups = self._get_portgroups() for existing in portgroups: if existing['name'] != dvpg_name: continue break # found it else: LOG.error("Portgroup with matching name {} not found while expected.".format(dvpg_name)) return self.update_dvportgroup(existing["ref"], existing["config.configVersion"], port_config) # Tag the portgroup for the specific security group set self.connection.invoke_api( self.connection.vim, "SetField", self._service_content.customFieldsManager, entity=existing["ref"], key=sg_attr_key, value=sg_set) return existing except vmware_exceptions.VimException as e: raise exceptions.wrap_wmvare_vim_exception(e)