def test_validate_subport_missing_segmenation_type(self): validator = rules.SubPortsValidator( self.segmentation_types, [{ 'port_id': uuidutils.generate_uuid(), 'segmentation_id': 100 }]) self.assertRaises(n_exc.InvalidInput, validator.validate, self.context)
def test__prepare_subports_raise_no_provider_ext(self): validator = rules.SubPortsValidator( self.segmentation_types, [{'port_id': uuidutils.generate_uuid(), 'segmentation_type': 'inherit'}]) self.assertRaises(n_exc.InvalidInput, validator._prepare_subports, self.context)
def test_validate_subport_missing_port_id(self): validator = rules.SubPortsValidator( self.segmentation_types, [{'segmentation_type': 'fake', 'segmentation_id': 100}]) self.assertRaises(n_exc.InvalidInput, validator.validate, self.context, basic_validation=True)
def test_validate_subport_vlan_id_not_an_int(self): validator = rules.SubPortsValidator( self.segmentation_types, [{ 'port_id': uuidutils.generate_uuid(), 'segmentation_type': 'vlan', 'segmentation_id': 'IamNotAnumber' }]) self.assertRaises(n_exc.InvalidInput, validator.validate, self.context)
def test_validate_subport_valid_vlan_id_as_string(self): validator = rules.SubPortsValidator( self.segmentation_types, [{'port_id': uuidutils.generate_uuid(), 'segmentation_type': 'vlan', 'segmentation_id': '2'}]) with mock.patch.object(rules.TrunkPortValidator, 'validate') as f: validator.validate(self.context) f.assert_called_once_with(self.context, parent_port=False)
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 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 test_validate_subport_subport_and_trunk_shared_port_id(self): shared_id = uuidutils.generate_uuid() validator = rules.SubPortsValidator( self.segmentation_types, [{'port_id': shared_id, 'segmentation_type': 'vlan', 'segmentation_id': 2}], shared_id) self.assertRaises(trunk_exc.ParentPortInUse, validator.validate, self.context)
def _test_validate_subport_trunk_mtu(self, subport_net_mtu, trunk_net_mtu): plugin = directory.get_plugin() orig_get_network = plugin.get_network orig_get_networks = plugin.get_networks def get_networks_adjust_mtu(*args, **kwargs): res = orig_get_networks(*args, **kwargs) res[0][api.MTU] = subport_net_mtu return res def get_network_adjust_mtu(*args, **kwargs): res = orig_get_network(*args, **kwargs) if res['name'] == 'net_trunk': if trunk_net_mtu == 'exc': raise n_exc.NetworkNotFound(net_id='net-id') res[api.MTU] = trunk_net_mtu elif res['name'] == 'net_subport': res[api.MTU] = subport_net_mtu return res with self.network('net_trunk') as trunk_net,\ self.subnet(network=trunk_net) as trunk_subnet,\ self.port(subnet=trunk_subnet) as trunk_port,\ self.network('net_subport') as subport_net,\ self.subnet(network=subport_net) as subport_subnet,\ self.port(subnet=subport_subnet) as subport,\ mock.patch.object(plugin, "get_network", side_effect=get_network_adjust_mtu),\ mock.patch.object(plugin, "get_networks", side_effect=get_networks_adjust_mtu): trunk = { 'port_id': trunk_port['port']['id'], 'tenant_id': 'test_tenant', 'sub_ports': [{ 'port_id': subport['port']['id'], 'segmentation_type': 'vlan', 'segmentation_id': 2 }] } validator = rules.SubPortsValidator(self.segmentation_types, trunk['sub_ports'], trunk['port_id']) if subport_net_mtu is None or trunk_net_mtu is None: validator.validate(self.context) elif subport_net_mtu == 'exc' or trunk_net_mtu == 'exc': validator.validate(self.context) elif subport_net_mtu <= trunk_net_mtu: validator.validate(self.context) else: self.assertRaises(trunk_exc.SubPortMtuGreaterThanTrunkPortMtu, validator.validate, self.context)
def validate(self, context, trunk): """Return a valid trunk or raises an error if unable to do so.""" trunk_details = trunk trunk_validator = rules.TrunkPortValidator(trunk['port_id']) trunk_details['port_id'] = trunk_validator.validate(context) subports_validator = rules.SubPortsValidator( self._segmentation_types, trunk['sub_ports'], trunk['port_id']) trunk_details['sub_ports'] = subports_validator.validate(context) return trunk_details
def validate_subports(self, context, subports, trunk, basic_validation=False, trunk_validation=True): """Validate subports data in the trunk and return a valid subport.""" subports_validator = rules.SubPortsValidator(self._segmentation_types, subports, trunk['port_id']) subports = subports_validator.validate( context, basic_validation=basic_validation, trunk_validation=trunk_validation) return subports
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 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