def remove_subports(self, context, trunk_id, subports): """Remove one or more subports from trunk.""" with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) subports_validator = rules.SubPortsValidator( self._segmentation_types, subports) # the subports are being removed, therefore we do not need to # enforce any specific trunk rules, other than basic validation # of the request body. subports = subports_validator.validate( context, basic_validation=True, trunk_validation=False) current_subports = {p.port_id: p for p in trunk.sub_ports} removed_subports = [] for subport in subports: subport_obj = current_subports.pop(subport['port_id'], None) if not subport_obj: raise trunk_exc.SubPortNotFound(trunk_id=trunk_id, port_id=subport['port_id']) subport_obj.delete() removed_subports.append(subport_obj) trunk.sub_ports = list(current_subports.values()) registry.notify( constants.SUBPORTS, events.AFTER_DELETE, self, removed_subports=removed_subports) return trunk
def delete_trunk(self, context, trunk_id): """Delete the trunk port.""" LOG.debug("Deleting trunk_id %s", trunk_id) deleted_from_db = False with db_context_writer.using(context): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) trunk_port_validator = rules.TrunkPortValidator(trunk.port_id) if not trunk_port_validator.is_bound(context): trunk.delete() deleted_from_db = True payload = callbacks.TrunkPayload(context, trunk_id, original_trunk=trunk) registry.notify(trunk_const.TRUNK, events.PRECOMMIT_DELETE, self, payload=payload) else: raise trunk_exc.TrunkInUse(trunk_id=trunk_id) if deleted_from_db: registry.notify(trunk_const.TRUNK, events.AFTER_DELETE, self, payload=payload)
def delete_trunk(self, context, trunk_id): """Delete the specified trunk.""" with db_api.CONTEXT_WRITER.using(context): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) trunk_port_validator = rules.TrunkPortValidator(trunk.port_id) if trunk_port_validator.can_be_trunked_or_untrunked(context): # NOTE(status_police): when a trunk is deleted, the logical # object disappears from the datastore, therefore there is no # status transition involved. If PRECOMMIT failures occur, # the trunk remains in the status where it was. try: trunk.delete() except Exception as e: with excutils.save_and_reraise_exception(): LOG.warning('Trunk driver raised exception when ' 'deleting trunk port %s: %s', trunk_id, str(e)) payload = events.DBEventPayload(context, resource_id=trunk_id, states=(trunk,)) registry.publish(resources.TRUNK, events.PRECOMMIT_DELETE, self, payload=payload) else: LOG.info('Trunk driver does not consider trunk %s ' 'untrunkable', trunk_id) raise trunk_exc.TrunkInUse(trunk_id=trunk_id) registry.publish(resources.TRUNK, events.AFTER_DELETE, self, payload=events.DBEventPayload( context, resource_id=trunk_id, states=(trunk,)))
def delete_trunk(self, context, trunk_id): """Delete the specified trunk.""" with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) trunk_port_validator = rules.TrunkPortValidator(trunk.port_id) if trunk_port_validator.can_be_trunked_or_untrunked(context): # NOTE(status_police): when a trunk is deleted, the logical # object disappears from the datastore, therefore there is no # status transition involved. If PRECOMMIT failures occur, # the trunk remains in the status where it was. trunk.delete() payload = callbacks.TrunkPayload(context, trunk_id, original_trunk=trunk) registry.notify(resources.TRUNK, events.PRECOMMIT_DELETE, self, payload=payload) else: raise trunk_exc.TrunkInUse(trunk_id=trunk_id) registry.notify(resources.TRUNK, events.AFTER_DELETE, self, payload=payload)
def add_subports(self, context, trunk_id, subports): """Add one or more subports to trunk.""" # Check for basic validation since the request body here is not # automatically validated by the API layer. subports_validator = rules.SubPortsValidator( self._segmentation_types, subports) subports = subports_validator.validate(context, basic_validation=True) added_subports = [] with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) for subport in subports: obj = trunk_objects.SubPort( context=context, trunk_id=trunk_id, port_id=subport['port_id'], segmentation_type=subport['segmentation_type'], segmentation_id=subport['segmentation_id']) obj.create() trunk['sub_ports'].append(obj) added_subports.append(obj) registry.notify( constants.SUBPORTS, events.AFTER_CREATE, self, added_subports=added_subports) return trunk
def remove_subports(self, context, trunk_id, subports): """Remove one or more subports from trunk.""" subports = subports['sub_ports'] with db_api.CONTEXT_WRITER.using(context): trunk = self._get_trunk(context, trunk_id) original_trunk = copy.deepcopy(trunk) rules.trunk_can_be_managed(context, trunk) subports_validator = rules.SubPortsValidator( self._segmentation_types, subports) # the subports are being removed, therefore we do not need to # enforce any specific trunk rules, other than basic validation # of the request body. subports = subports_validator.validate( context, basic_validation=True, trunk_validation=False) current_subports = {p.port_id: p for p in trunk.sub_ports} removed_subports = [] for subport in subports: subport_obj = current_subports.pop(subport['port_id'], None) if not subport_obj: raise trunk_exc.SubPortNotFound(trunk_id=trunk_id, port_id=subport['port_id']) subport_obj.delete() removed_subports.append(subport_obj) del trunk.sub_ports[:] trunk.sub_ports.extend(current_subports.values()) # NOTE(status_police): the trunk status should transition to # DOWN irrespective of the status in which it is in to allow # the user to resolve potential conflicts due to prior add_subports # operations. # Should a trunk be in DOWN or BUILD state (e.g. when dealing # with multiple concurrent requests), the status is still forced # to DOWN. See add_subports() for more details. trunk.update(status=constants.TRUNK_DOWN_STATUS) payload = events.DBEventPayload(context, resource_id=trunk_id, states=(original_trunk, trunk,), metadata={ 'subports': removed_subports }) if removed_subports: registry.publish(resources.SUBPORTS, events.PRECOMMIT_DELETE, self, payload=payload) if removed_subports: payload = events.DBEventPayload(context, resource_id=trunk_id, states=(original_trunk, trunk,), metadata={ 'subports': removed_subports }) registry.publish( resources.SUBPORTS, events.AFTER_DELETE, self, payload=payload) return trunk
def add_subports(self, context, trunk_id, subports): """Add one or more subports to trunk.""" with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) # Check for basic validation since the request body here is not # automatically validated by the API layer. subports = subports['sub_ports'] subports_validator = rules.SubPortsValidator( self._segmentation_types, subports, trunk['port_id']) subports = subports_validator.validate(context, basic_validation=True) added_subports = [] rules.trunk_can_be_managed(context, trunk) original_trunk = copy.deepcopy(trunk) # NOTE(status_police): the trunk status should transition to # DOWN (and finally in ACTIVE or ERROR), only if it is not in # ERROR status already. A user should attempt to resolve the ERROR # condition before adding more subports to the trunk. Should a # trunk be in DOWN or BUILD state (e.g. when dealing with # multiple concurrent requests), the status is still forced to # DOWN and thus can potentially overwrite an interleaving state # change to ACTIVE. Eventually the driver should bring the status # back to ACTIVE or ERROR. if trunk.status == constants.ERROR_STATUS: raise trunk_exc.TrunkInErrorState(trunk_id=trunk_id) else: trunk.update(status=constants.DOWN_STATUS) for subport in subports: obj = trunk_objects.SubPort( context=context, trunk_id=trunk_id, port_id=subport['port_id'], segmentation_type=subport['segmentation_type'], segmentation_id=subport['segmentation_id']) obj.create() trunk['sub_ports'].append(obj) added_subports.append(obj) payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=added_subports) if added_subports: registry.notify(resources.SUBPORTS, events.PRECOMMIT_CREATE, self, payload=payload) if added_subports: registry.notify(resources.SUBPORTS, events.AFTER_CREATE, self, payload=payload) return trunk
def delete_trunk(self, context, trunk_id): """Delete the specified trunk.""" with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) trunk_port_validator = rules.TrunkPortValidator(trunk.port_id) if not trunk_port_validator.is_bound(context): trunk.delete() else: raise trunk_exc.TrunkInUse(trunk_id=trunk_id)
def remove_subports(self, context, trunk_id, subports): """Remove one or more subports from trunk.""" subports = subports['sub_ports'] with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) original_trunk = copy.deepcopy(trunk) rules.trunk_can_be_managed(context, trunk) subports_validator = rules.SubPortsValidator( self._segmentation_types, subports) # the subports are being removed, therefore we do not need to # enforce any specific trunk rules, other than basic validation # of the request body. subports = subports_validator.validate( context, basic_validation=True, trunk_validation=False) current_subports = {p.port_id: p for p in trunk.sub_ports} removed_subports = [] for subport in subports: subport_obj = current_subports.pop(subport['port_id'], None) if not subport_obj: raise trunk_exc.SubPortNotFound(trunk_id=trunk_id, port_id=subport['port_id']) subport_obj.delete() removed_subports.append(subport_obj) del trunk.sub_ports[:] trunk.sub_ports.extend(current_subports.values()) # NOTE(status_police): the trunk status should transition to # PENDING irrespective of the status in which it is in to allow # the user to resolve potential conflicts due to prior add_subports # operations. # Should a trunk be in PENDING or BUILD state (e.g. when dealing # with multiple concurrent requests), the status is still forced # to PENDING. See add_subports() for more details. trunk.status = constants.PENDING_STATUS trunk.update() payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=removed_subports) if removed_subports: registry.notify(constants.SUBPORTS, events.PRECOMMIT_DELETE, self, payload=payload) if removed_subports: registry.notify( constants.SUBPORTS, events.AFTER_DELETE, self, payload=payload) return trunk
def add_subports(self, context, trunk_id, subports): """Add one or more subports to trunk.""" with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) # Check for basic validation since the request body here is not # automatically validated by the API layer. subports = subports['sub_ports'] subports_validator = rules.SubPortsValidator( self._segmentation_types, subports, trunk['port_id']) subports = subports_validator.validate( context, basic_validation=True) added_subports = [] rules.trunk_can_be_managed(context, trunk) original_trunk = copy.deepcopy(trunk) # NOTE(status_police): the trunk status should transition to # DOWN (and finally in ACTIVE or ERROR), only if it is not in # ERROR status already. A user should attempt to resolve the ERROR # condition before adding more subports to the trunk. Should a # trunk be in DOWN or BUILD state (e.g. when dealing with # multiple concurrent requests), the status is still forced to # DOWN and thus can potentially overwrite an interleaving state # change to ACTIVE. Eventually the driver should bring the status # back to ACTIVE or ERROR. if trunk.status == constants.ERROR_STATUS: raise trunk_exc.TrunkInErrorState(trunk_id=trunk_id) else: trunk.update(status=constants.DOWN_STATUS) for subport in subports: obj = trunk_objects.SubPort( context=context, trunk_id=trunk_id, port_id=subport['port_id'], segmentation_type=subport['segmentation_type'], segmentation_id=subport['segmentation_id']) obj.create() trunk['sub_ports'].append(obj) added_subports.append(obj) payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=added_subports) if added_subports: registry.notify(constants.SUBPORTS, events.PRECOMMIT_CREATE, self, payload=payload) if added_subports: registry.notify( constants.SUBPORTS, events.AFTER_CREATE, self, payload=payload) return trunk
def remove_subports(self, context, trunk_id, subports): """Remove one or more subports from the trunk.""" LOG.debug("Removing subports %s from trunk %s", subports, trunk_id) trunk = self._get_trunk(context, trunk_id) original_trunk = copy.deepcopy(trunk) subports = subports['sub_ports'] subports = self.validate_subports(context, subports, trunk, basic_validation=True, trunk_validation=False) removed_subports = [] rules.trunk_can_be_managed(context, trunk) # The trunk should not be in the ERROR_STATUS if trunk.status == trunk_const.ERROR_STATUS: raise trunk_exc.TrunkInErrorState(trunk_id=trunk_id) else: # The trunk will transition to DOWN and subsequently to ACTIVE # when a subport is removed. trunk.update(status=trunk_const.DOWN_STATUS) current_subports = {p.port_id: p for p in trunk.sub_ports} # Ensure that all sub-ports to be removed are actually present for subport in subports: if subport['port_id'] not in current_subports: raise trunk_exc.SubPortNotFound(trunk_id=trunk_id, port_id=subport['port_id']) with neutron_db_api.context_manager.writer.using(context): for subport in subports: subport_obj = current_subports.pop(subport['port_id']) subport_obj.delete() removed_subports.append(subport_obj) if removed_subports: del trunk.sub_ports[:] trunk.sub_ports.extend(current_subports.values()) payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=removed_subports) registry.notify(trunk_const.SUBPORTS, events.PRECOMMIT_DELETE, self, payload=payload) self.send_subport_update_to_etcd(context, trunk) if removed_subports: registry.notify(trunk_const.SUBPORTS, events.AFTER_DELETE, self, payload=payload) return trunk
def delete_trunk(self, context, trunk_id): """Delete the specified trunk.""" with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) trunk_port_validator = rules.TrunkPortValidator(trunk.port_id) if not trunk_port_validator.is_bound(context): trunk.delete() payload = callbacks.TrunkPayload(context, trunk_id, original_trunk=trunk) registry.notify(constants.TRUNK, events.PRECOMMIT_DELETE, self, payload=payload) else: raise trunk_exc.TrunkInUse(trunk_id=trunk_id) registry.notify(constants.TRUNK, events.AFTER_DELETE, self, payload=payload)
def remove_subports(self, context, trunk_id, subports): """Remove one or more subports from trunk.""" subports = subports['sub_ports'] with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) original_trunk = copy.deepcopy(trunk) rules.trunk_can_be_managed(context, trunk) subports_validator = rules.SubPortsValidator( self._segmentation_types, subports) # the subports are being removed, therefore we do not need to # enforce any specific trunk rules, other than basic validation # of the request body. subports = subports_validator.validate(context, basic_validation=True, trunk_validation=False) current_subports = {p.port_id: p for p in trunk.sub_ports} removed_subports = [] for subport in subports: subport_obj = current_subports.pop(subport['port_id'], None) if not subport_obj: raise trunk_exc.SubPortNotFound(trunk_id=trunk_id, port_id=subport['port_id']) subport_obj.delete() removed_subports.append(subport_obj) del trunk.sub_ports[:] trunk.sub_ports.extend(current_subports.values()) payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=removed_subports) if removed_subports: registry.notify(constants.SUBPORTS, events.PRECOMMIT_DELETE, self, payload=payload) if removed_subports: registry.notify(constants.SUBPORTS, events.AFTER_DELETE, self, payload=payload) return trunk
def add_subports(self, context, trunk_id, subports): """Add one or more subports to a trunk.""" LOG.debug("Adding subports %s to trunk %s", subports, trunk_id) trunk = self._get_trunk(context, trunk_id) subports = subports['sub_ports'] subports = self.validate_subports(context, subports, trunk, basic_validation=True) added_subports = [] rules.trunk_can_be_managed(context, trunk) original_trunk = copy.deepcopy(trunk) # The trunk should not be in the ERROR_STATUS if trunk.status == trunk_const.ERROR_STATUS: raise trunk_exc.TrunkInErrorState(trunk_id=trunk_id) else: # The trunk will transition to DOWN and subsequently to ACTIVE # when a subport is added. trunk.update(status=trunk_const.DOWN_STATUS) with db_context_writer.using(context): for subport in subports: subport_obj = trunk_objects.SubPort( context=context, trunk_id=trunk_id, port_id=subport['port_id'], segmentation_type=subport['segmentation_type'], segmentation_id=subport['segmentation_id']) subport_obj.create() trunk['sub_ports'].append(subport_obj) added_subports.append(subport_obj) payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=added_subports) if added_subports: registry.notify(trunk_const.SUBPORTS, events.PRECOMMIT_CREATE, self, payload=payload) self.send_subport_update_to_etcd(context, trunk) if added_subports: registry.notify(trunk_const.SUBPORTS, events.AFTER_CREATE, self, payload=payload) return trunk
def remove_subports(self, context, trunk_id, subports): """Remove one or more subports from the trunk.""" LOG.debug("Removing subports %s from trunk %s", subports, trunk_id) trunk = self._get_trunk(context, trunk_id) original_trunk = copy.deepcopy(trunk) subports = subports['sub_ports'] subports = self.validate_subports(context, subports, trunk, basic_validation=True, trunk_validation=False) removed_subports = [] rules.trunk_can_be_managed(context, trunk) # The trunk should not be in the ERROR_STATUS if trunk.status == trunk_const.ERROR_STATUS: raise trunk_exc.TrunkInErrorState(trunk_id=trunk_id) else: # The trunk will transition to DOWN and subsequently to ACTIVE # when a subport is removed. trunk.update(status=trunk_const.DOWN_STATUS) current_subports = {p.port_id: p for p in trunk.sub_ports} # Ensure that all sub-ports to be removed are actually present for subport in subports: if subport['port_id'] not in current_subports: raise trunk_exc.SubPortNotFound(trunk_id=trunk_id, port_id=subport['port_id']) with neutron_db_api.context_manager.writer.using(context): for subport in subports: subport_obj = current_subports.pop(subport['port_id']) subport_obj.delete() removed_subports.append(subport_obj) if removed_subports: del trunk.sub_ports[:] trunk.sub_ports.extend(current_subports.values()) payload = callbacks.TrunkPayload( context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=removed_subports ) registry.notify(trunk_const.SUBPORTS, events.PRECOMMIT_DELETE, self, payload=payload) self.send_subport_update_to_etcd(context, trunk) if removed_subports: registry.notify(trunk_const.SUBPORTS, events.AFTER_DELETE, self, payload=payload) return trunk
def add_subports(self, context, trunk_id, subports): """Add one or more subports to a trunk.""" LOG.debug("Adding subports %s to trunk %s", subports, trunk_id) trunk = self._get_trunk(context, trunk_id) subports = subports['sub_ports'] subports = self.validate_subports(context, subports, trunk, basic_validation=True) added_subports = [] rules.trunk_can_be_managed(context, trunk) original_trunk = copy.deepcopy(trunk) # The trunk should not be in the ERROR_STATUS if trunk.status == trunk_const.ERROR_STATUS: raise trunk_exc.TrunkInErrorState(trunk_id=trunk_id) else: # The trunk will transition to DOWN and subsequently to ACTIVE # when a subport is added. trunk.update(status=trunk_const.DOWN_STATUS) with neutron_db_api.context_manager.writer.using(context): for subport in subports: subport_obj = trunk_objects.SubPort( context=context, trunk_id=trunk_id, port_id=subport['port_id'], segmentation_type=subport['segmentation_type'], segmentation_id=subport['segmentation_id']) subport_obj.create() trunk['sub_ports'].append(subport_obj) added_subports.append(subport_obj) payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=added_subports) if added_subports: registry.notify(trunk_const.SUBPORTS, events.PRECOMMIT_CREATE, self, payload=payload) self.send_subport_update_to_etcd(context, trunk) if added_subports: registry.notify(trunk_const.SUBPORTS, events.AFTER_CREATE, self, payload=payload) return trunk
def delete_trunk(self, context, trunk_id): """Delete the specified trunk.""" with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) trunk_port_validator = rules.TrunkPortValidator(trunk.port_id) if not trunk_port_validator.is_bound(context): # NOTE(status_police): when a trunk is deleted, the logical # object disappears from the datastore, therefore there is no # status transition involved. If PRECOMMIT failures occur, # the trunk remains in the status where it was. trunk.delete() payload = callbacks.TrunkPayload(context, trunk_id, original_trunk=trunk) registry.notify(constants.TRUNK, events.PRECOMMIT_DELETE, self, payload=payload) else: raise trunk_exc.TrunkInUse(trunk_id=trunk_id) registry.notify(constants.TRUNK, events.AFTER_DELETE, self, payload=payload)
def add_subports(self, context, trunk_id, subports): """Add one or more subports to trunk.""" # Check for basic validation since the request body here is not # automatically validated by the API layer. subports = subports['sub_ports'] subports_validator = rules.SubPortsValidator(self._segmentation_types, subports) subports = subports_validator.validate(context, basic_validation=True) added_subports = [] with db_api.autonested_transaction(context.session): trunk = self._get_trunk(context, trunk_id) original_trunk = copy.deepcopy(trunk) rules.trunk_can_be_managed(context, trunk) for subport in subports: obj = trunk_objects.SubPort( context=context, trunk_id=trunk_id, port_id=subport['port_id'], segmentation_type=subport['segmentation_type'], segmentation_id=subport['segmentation_id']) obj.create() trunk['sub_ports'].append(obj) added_subports.append(obj) payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=added_subports) if added_subports: registry.notify(constants.SUBPORTS, events.PRECOMMIT_CREATE, self, payload=payload) if added_subports: registry.notify(constants.SUBPORTS, events.AFTER_CREATE, self, payload=payload) return trunk
def delete_trunk(self, context, trunk_id): """Delete the trunk port.""" LOG.debug("Deleting trunk_id %s", trunk_id) deleted_from_db = False with neutron_db_api.context_manager.writer.using(context): trunk = self._get_trunk(context, trunk_id) rules.trunk_can_be_managed(context, trunk) trunk_port_validator = rules.TrunkPortValidator(trunk.port_id) if not trunk_port_validator.is_bound(context): trunk.delete() deleted_from_db = True payload = callbacks.TrunkPayload(context, trunk_id, original_trunk=trunk) registry.notify(trunk_const.TRUNK, events.PRECOMMIT_DELETE, self, payload=payload) else: raise trunk_exc.TrunkInUse(trunk_id=trunk_id) if deleted_from_db: registry.notify(trunk_const.TRUNK, events.AFTER_DELETE, self, payload=payload)
def remove_subports(self, context, trunk_id, subports): """Remove one or more subports from the trunk. param: subports: {u'sub_ports': [{u'port_id': u'fa006724-dbca-4e7f-bb6b-ec70162eb681'}]} """ LOG.debug("Removing subports %s from trunk %s", subports, trunk_id) trunk = self._get_trunk(context, trunk_id) original_trunk = copy.deepcopy(trunk) # key-value data corresponding to original trunk original_trunk_data = self._get_trunk_data(trunk) # ID's of subports to remove subports_to_remove = [pid['port_id'] for pid in subports['sub_ports']] LOG.debug('trunk subports to remove: %s', subports_to_remove) subports = subports['sub_ports'] subports = self.validate_subports(context, subports, trunk, basic_validation=True, trunk_validation=False) removed_subports = [] rules.trunk_can_be_managed(context, trunk) # The trunk should not be in the ERROR_STATUS if trunk.status == trunk_const.ERROR_STATUS: raise trunk_exc.TrunkInErrorState(trunk_id=trunk_id) else: # The trunk will transition to DOWN and subsequently to ACTIVE # when a subport is removed. trunk.update(status=trunk_const.DOWN_STATUS) current_subports = {p.port_id: p for p in trunk.sub_ports} # Ensure that all sub-ports to be removed are actually present for subport in subports: if subport['port_id'] not in current_subports: raise trunk_exc.SubPortNotFound(trunk_id=trunk_id, port_id=subport['port_id']) with db_context_writer.using(context): for subport in subports: subport_obj = current_subports.pop(subport['port_id']) subport_obj.delete() removed_subports.append(subport_obj) if removed_subports: del trunk.sub_ports[:] trunk.sub_ports.extend(current_subports.values()) payload = callbacks.TrunkPayload(context, trunk_id, current_trunk=trunk, original_trunk=original_trunk, subports=removed_subports) registry.notify(trunk_const.SUBPORTS, events.PRECOMMIT_DELETE, self, payload=payload) self.send_subport_update_to_etcd(context, trunk) # Subport data to remove subports = [ subport for subport in original_trunk_data['sub_ports'] if subport['port_id'] in subports_to_remove ] original_trunk_data['sub_ports'] = subports trunk_data = self.add_data_to_subports(context, original_trunk_data) # Remove all remote-group subport keys from etcd LOG.debug('trunk data with subports to remove: %s', trunk_data) for subport_data in trunk_data['sub_ports']: self._write_remote_group_journal(context, subport_data, remove_key=True) if removed_subports: registry.notify(trunk_const.SUBPORTS, events.AFTER_DELETE, self, payload=payload) return trunk