diff --git a/neutron/api/v2/attributes.py b/neutron/api/v2/attributes.py index 45ac2f12a44..33d75f33420 100644 --- a/neutron/api/v2/attributes.py +++ b/neutron/api/v2/attributes.py @@ -13,13 +13,11 @@ # License for the specific language governing permissions and limitations # under the License. -from neutron_lib.api import converters as lib_converters +from neutron_lib.api import attributes as attrs from neutron_lib.api.definitions import network as net_def from neutron_lib.api.definitions import port as port_def from neutron_lib.api.definitions import subnet as subnet_def from neutron_lib.api.definitions import subnetpool as subnetpool_def -from neutron_lib import constants -from neutron_lib.db import constants as db_const # Defining a constant to avoid repeating string literal in several modules @@ -30,250 +28,8 @@ CORE_RESOURCES = {net_def.RESOURCE_NAME: net_def.COLLECTION_NAME, subnet_def.RESOURCE_NAME: subnet_def.COLLECTION_NAME, subnetpool_def.RESOURCE_NAME: subnetpool_def.COLLECTION_NAME, port_def.RESOURCE_NAME: port_def.COLLECTION_NAME} -# Note: a default of ATTR_NOT_SPECIFIED indicates that an -# attribute is not required, but will be generated by the plugin -# if it is not specified. Particularly, a value of ATTR_NOT_SPECIFIED -# is different from an attribute that has been specified with a value of -# None. For example, if 'gateway_ip' is omitted in a request to -# create a subnet, the plugin will receive ATTR_NOT_SPECIFIED -# and the default gateway_ip will be generated. -# However, if gateway_ip is specified as None, this means that -# the subnet does not have a gateway IP. -# The following is a short reference for understanding attribute info: -# default: default value of the attribute (if missing, the attribute -# becomes mandatory. -# allow_post: the attribute can be used on POST requests. -# allow_put: the attribute can be used on PUT requests. -# validate: specifies rules for validating data in the attribute. -# convert_to: transformation to apply to the value before it is returned -# is_visible: the attribute is returned in GET responses. -# required_by_policy: the attribute is required by the policy engine and -# should therefore be filled by the API layer even if not present in -# request body. -# enforce_policy: the attribute is actively part of the policy enforcing -# mechanism, ie: there might be rules which refer to this attribute. -RESOURCE_ATTRIBUTE_MAP = { - net_def.COLLECTION_NAME: { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, - 'default': '', 'is_visible': True}, - 'subnets': {'allow_post': False, 'allow_put': False, - 'default': [], - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': lib_converters.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': { - 'type:string': db_const.PROJECT_ID_FIELD_SIZE}, - 'required_by_policy': True, - 'is_visible': True}, - SHARED: {'allow_post': True, - 'allow_put': True, - 'default': False, - 'convert_to': lib_converters.convert_to_boolean, - 'is_visible': True, - 'required_by_policy': True, - 'enforce_policy': True}, - }, - port_def.COLLECTION_NAME: { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'name': {'allow_post': True, 'allow_put': True, 'default': '', - 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, - 'is_visible': True}, - 'network_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': lib_converters.convert_to_boolean, - 'is_visible': True}, - 'mac_address': {'allow_post': True, 'allow_put': True, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:mac_address': None}, - 'enforce_policy': True, - 'is_visible': True}, - 'fixed_ips': {'allow_post': True, 'allow_put': True, - 'default': constants.ATTR_NOT_SPECIFIED, - 'convert_list_to': - lib_converters.convert_kvp_list_to_dict, - 'validate': {'type:fixed_ips': None}, - 'enforce_policy': True, - 'is_visible': True}, - 'device_id': {'allow_post': True, 'allow_put': True, - 'validate': { - 'type:string': db_const.DEVICE_ID_FIELD_SIZE}, - 'default': '', - 'is_visible': True}, - 'device_owner': {'allow_post': True, 'allow_put': True, - 'validate': { - 'type:string': db_const.DEVICE_OWNER_FIELD_SIZE}, - 'default': '', 'enforce_policy': True, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': { - 'type:string': db_const.PROJECT_ID_FIELD_SIZE}, - 'required_by_policy': True, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - }, - subnet_def.COLLECTION_NAME: { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'name': {'allow_post': True, 'allow_put': True, 'default': '', - 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, - 'is_visible': True}, - 'ip_version': {'allow_post': True, 'allow_put': False, - 'convert_to': lib_converters.convert_to_int, - 'validate': {'type:values': [4, 6]}, - 'is_visible': True}, - 'network_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'subnetpool_id': {'allow_post': True, - 'allow_put': False, - 'default': constants.ATTR_NOT_SPECIFIED, - 'required_by_policy': False, - 'validate': {'type:subnetpool_id_or_none': None}, - 'is_visible': True}, - 'prefixlen': {'allow_post': True, - 'allow_put': False, - 'validate': {'type:non_negative': None}, - 'convert_to': lib_converters.convert_to_int, - 'default': constants.ATTR_NOT_SPECIFIED, - 'required_by_policy': False, - 'is_visible': False}, - 'cidr': {'allow_post': True, - 'allow_put': False, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:subnet_or_none': None}, - 'required_by_policy': False, - 'is_visible': True}, - 'gateway_ip': {'allow_post': True, 'allow_put': True, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:ip_address_or_none': None}, - 'is_visible': True}, - 'allocation_pools': {'allow_post': True, 'allow_put': True, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:ip_pools': None}, - 'is_visible': True}, - 'dns_nameservers': {'allow_post': True, 'allow_put': True, - 'convert_to': - lib_converters.convert_none_to_empty_list, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:nameservers': None}, - 'is_visible': True}, - 'host_routes': {'allow_post': True, 'allow_put': True, - 'convert_to': - lib_converters.convert_none_to_empty_list, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:hostroutes': None}, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': { - 'type:string': db_const.PROJECT_ID_FIELD_SIZE}, - 'required_by_policy': True, - 'is_visible': True}, - 'enable_dhcp': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': lib_converters.convert_to_boolean, - 'is_visible': True}, - 'ipv6_ra_mode': {'allow_post': True, 'allow_put': False, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:values': constants.IPV6_MODES}, - 'is_visible': True}, - 'ipv6_address_mode': {'allow_post': True, 'allow_put': False, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:values': - constants.IPV6_MODES}, - 'is_visible': True}, - SHARED: {'allow_post': False, - 'allow_put': False, - 'default': False, - 'convert_to': lib_converters.convert_to_boolean, - 'is_visible': False, - 'required_by_policy': True, - 'enforce_policy': True}, - }, - subnetpool_def.COLLECTION_NAME: { - 'id': {'allow_post': False, - 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'name': {'allow_post': True, - 'allow_put': True, - 'validate': {'type:not_empty_string': None}, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, - 'allow_put': False, - 'validate': { - 'type:string': db_const.PROJECT_ID_FIELD_SIZE}, - 'required_by_policy': True, - 'is_visible': True}, - 'prefixes': {'allow_post': True, - 'allow_put': True, - 'validate': {'type:subnet_list': None}, - 'is_visible': True}, - 'default_quota': {'allow_post': True, - 'allow_put': True, - 'validate': {'type:non_negative': None}, - 'convert_to': lib_converters.convert_to_int, - 'default': constants.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - 'ip_version': {'allow_post': False, - 'allow_put': False, - 'is_visible': True}, - 'default_prefixlen': {'allow_post': True, - 'allow_put': True, - 'validate': {'type:non_negative': None}, - 'convert_to': lib_converters.convert_to_int, - 'default': constants.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - 'min_prefixlen': {'allow_post': True, - 'allow_put': True, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:non_negative': None}, - 'convert_to': lib_converters.convert_to_int, - 'is_visible': True}, - 'max_prefixlen': {'allow_post': True, - 'allow_put': True, - 'default': constants.ATTR_NOT_SPECIFIED, - 'validate': {'type:non_negative': None}, - 'convert_to': lib_converters.convert_to_int, - 'is_visible': True}, - 'is_default': {'allow_post': True, - 'allow_put': True, - 'default': False, - 'convert_to': lib_converters.convert_to_boolean, - 'is_visible': True, - 'required_by_policy': True, - 'enforce_policy': True}, - SHARED: {'allow_post': True, - 'allow_put': False, - 'default': False, - 'convert_to': lib_converters.convert_to_boolean, - 'is_visible': True, - 'required_by_policy': True, - 'enforce_policy': True}, - } -} +RESOURCE_ATTRIBUTE_MAP = attrs.RESOURCES # Identify the attribute used by a resource to reference another resource diff --git a/neutron/tests/base.py b/neutron/tests/base.py index 4b6c4f232fe..bfed6010985 100644 --- a/neutron/tests/base.py +++ b/neutron/tests/base.py @@ -288,7 +288,7 @@ class BaseTestCase(DietTestCase): super(BaseTestCase, self).setUp() self.useFixture(lockutils.ExternalLockFixture()) - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) cfg.CONF.set_override('state_path', self.get_default_temp_dir().path) diff --git a/neutron/tests/functional/api/test_policies.py b/neutron/tests/functional/api/test_policies.py index 9f0515c8f8d..6e8f2f2effc 100644 --- a/neutron/tests/functional/api/test_policies.py +++ b/neutron/tests/functional/api/test_policies.py @@ -16,12 +16,12 @@ import os.path from neutron_lib import context +from neutron_lib import fixture from neutron.api import extensions from neutron.api.v2 import attributes from neutron import policy from neutron.tests import base -from neutron.tests import tools TEST_PATH = os.path.dirname(os.path.abspath(__file__)) @@ -39,7 +39,7 @@ class APIPolicyTestCase(base.BaseTestCase): def setUp(self): super(APIPolicyTestCase, self).setUp() - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) self.extension_path = os.path.abspath(os.path.join( TEST_PATH, "../../../extensions")) self.addCleanup(policy.reset) diff --git a/neutron/tests/tools.py b/neutron/tests/tools.py index 4958dee0799..440590d6c1c 100644 --- a/neutron/tests/tools.py +++ b/neutron/tests/tools.py @@ -24,51 +24,16 @@ import fixtures import mock import netaddr from neutron_lib import constants -from neutron_lib import fixture from neutron_lib.utils import helpers from neutron_lib.utils import net from oslo_utils import netutils from oslo_utils import timeutils import unittest2 -from neutron.api.v2 import attributes from neutron.common import constants as n_const from neutron.services.logapi.common import constants as log_const -class AttributeMapMemento(fixture.APIDefinitionFixture): - """Create a copy of the resource attribute map so it can be restored during - test cleanup. - - There are a few reasons why this is not included in a class derived - from BaseTestCase: - - - Test cases may need more control about when the backup is - made, especially if they are not direct descendants of - BaseTestCase. - - - Inheritance is a bit of overkill for this facility and it's a - stretch to rationalize the "is a" criteria. - """ - - def _setUp(self): - self.backup_global_resources = False - super(AttributeMapMemento, self)._setUp() - # Shallow copy is not a proper choice for keeping a backup copy as - # the RESOURCE_ATTRIBUTE_MAP map is modified in place through the - # 0th level keys. Ideally deepcopy() would be used but this seems - # to result in test failures. A compromise is to copy one level - # deeper than a shallow copy. - self.contents_backup = {} - for res, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.items(): - self.contents_backup[res] = attrs.copy() - self.addCleanup(self.restore) - - def restore(self): - super(AttributeMapMemento, self)._restore() - attributes.RESOURCE_ATTRIBUTE_MAP = self.contents_backup - - class WarningsFixture(fixtures.Fixture): """Filters out warnings during test runs.""" diff --git a/neutron/tests/unit/api/v2/test_base.py b/neutron/tests/unit/api/v2/test_base.py index 94efeb885c9..0dd8c894395 100644 --- a/neutron/tests/unit/api/v2/test_base.py +++ b/neutron/tests/unit/api/v2/test_base.py @@ -21,6 +21,7 @@ from neutron_lib.callbacks import registry from neutron_lib import constants from neutron_lib import context from neutron_lib import exceptions as n_exc +from neutron_lib import fixture from neutron_lib.plugins import directory from oslo_config import cfg from oslo_db import exception as db_exc @@ -42,7 +43,6 @@ from neutron import quota from neutron.quota import resource_registry from neutron.tests import base from neutron.tests import fake_notifier -from neutron.tests import tools from neutron.tests.unit import dummy_plugin from neutron.tests.unit import testlib_api @@ -1123,7 +1123,7 @@ class SubresourceTest(base.BaseTestCase): plugin = 'neutron.tests.unit.api.v2.test_base.TestSubresourcePlugin' extensions.PluginAwareExtensionManager._instance = None - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) self.config_parse() self.setup_coreplugin(plugin, load_plugins=False) @@ -1454,7 +1454,7 @@ class ExtensionTestCase(base.BaseTestCase): # Ensure existing ExtensionManager is not used extensions.PluginAwareExtensionManager._instance = None - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) # Create the default configurations self.config_parse() diff --git a/neutron/tests/unit/db/test_db_base_plugin_v2.py b/neutron/tests/unit/db/test_db_base_plugin_v2.py index 3fd204ae7be..051ed6d9b18 100644 --- a/neutron/tests/unit/db/test_db_base_plugin_v2.py +++ b/neutron/tests/unit/db/test_db_base_plugin_v2.py @@ -26,6 +26,7 @@ from neutron_lib.callbacks import registry from neutron_lib import constants from neutron_lib import context from neutron_lib import exceptions as lib_exc +from neutron_lib import fixture from neutron_lib.plugins import directory from neutron_lib.utils import helpers from neutron_lib.utils import net @@ -116,7 +117,7 @@ class NeutronDbPluginV2TestCase(testlib_api.WebTestCase): extensions.PluginAwareExtensionManager._instance = None # Save the attributes map in case the plugin will alter it # loading extensions - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) self._tenant_id = TEST_TENANT_ID if not plugin: @@ -6652,7 +6653,7 @@ class DbOperationBoundMixin(object): def setUp(self, *args, **kwargs): super(DbOperationBoundMixin, self).setUp(*args, **kwargs) - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) self._recorded_statements = [] def _event_incrementer(conn, clauseelement, *args, **kwargs): diff --git a/neutron/tests/unit/extensions/base.py b/neutron/tests/unit/extensions/base.py index 8364ccced23..c1cfdbbaecd 100644 --- a/neutron/tests/unit/extensions/base.py +++ b/neutron/tests/unit/extensions/base.py @@ -17,6 +17,7 @@ # under the License. import mock +from neutron_lib import fixture from oslo_config import cfg from oslo_utils import uuidutils from webob import exc @@ -25,7 +26,6 @@ import webtest from neutron.api import extensions from neutron import manager from neutron import quota -from neutron.tests import tools from neutron.tests.unit.api import test_extensions from neutron.tests.unit.api.v2 import test_base from neutron.tests.unit import testlib_api @@ -54,7 +54,7 @@ class ExtensionTestCase(testlib_api.WebTestCase): # Ensure existing ExtensionManager is not used extensions.PluginAwareExtensionManager._instance = None - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) # Create the default configurations self.config_parse() diff --git a/neutron/tests/unit/extensions/test_providernet.py b/neutron/tests/unit/extensions/test_providernet.py index d2fcf62141b..fe424c40fb0 100644 --- a/neutron/tests/unit/extensions/test_providernet.py +++ b/neutron/tests/unit/extensions/test_providernet.py @@ -16,6 +16,7 @@ import mock from neutron_lib.api.definitions import provider_net from neutron_lib import context +from neutron_lib import fixture from neutron_lib.plugins import constants from neutron_lib.plugins import directory from oslo_config import cfg @@ -27,7 +28,6 @@ from neutron.api import extensions from neutron.api.v2 import router from neutron.extensions import providernet as pnet from neutron import quota -from neutron.tests import tools from neutron.tests.unit.api import test_extensions from neutron.tests.unit.api.v2 import test_base from neutron.tests.unit import testlib_api @@ -59,7 +59,7 @@ class ProvidernetExtensionTestCase(testlib_api.WebTestCase): # Ensure existing ExtensionManager is not used extensions.PluginAwareExtensionManager._instance = None - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) # Update the plugin and extensions path self.setup_coreplugin(plugin, load_plugins=False) diff --git a/neutron/tests/unit/extensions/test_quotasv2.py b/neutron/tests/unit/extensions/test_quotasv2.py index d9309af6459..8c216eb8517 100644 --- a/neutron/tests/unit/extensions/test_quotasv2.py +++ b/neutron/tests/unit/extensions/test_quotasv2.py @@ -18,6 +18,7 @@ import sys import mock from neutron_lib import context from neutron_lib.db import constants +from neutron_lib import fixture from oslo_config import cfg import testtools from webob import exc @@ -32,7 +33,6 @@ from neutron.db.quota import driver from neutron import quota from neutron.quota import resource_registry from neutron.tests import base -from neutron.tests import tools from neutron.tests.unit.api.v2 import test_base from neutron.tests.unit import testlib_api @@ -49,7 +49,7 @@ class QuotaExtensionTestCase(testlib_api.WebTestCase): # Ensure existing ExtensionManager is not used extensions.PluginAwareExtensionManager._instance = None - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) # Create the default configurations self.config_parse() diff --git a/neutron/tests/unit/extensions/test_quotasv2_detail.py b/neutron/tests/unit/extensions/test_quotasv2_detail.py index 0692a328167..2639456970d 100644 --- a/neutron/tests/unit/extensions/test_quotasv2_detail.py +++ b/neutron/tests/unit/extensions/test_quotasv2_detail.py @@ -15,17 +15,16 @@ import mock +from neutron_lib import context +from neutron_lib import fixture from oslo_config import cfg import webtest -from neutron_lib import context - from neutron.api import extensions from neutron.api.v2 import router from neutron.common import config from neutron.conf import quota as qconf from neutron import quota -from neutron.tests import tools from neutron.tests.unit.api.v2 import test_base from neutron.tests.unit import testlib_api @@ -42,7 +41,7 @@ class DetailQuotaExtensionTestCase(testlib_api.WebTestCase): # Ensure existing ExtensionManager is not used extensions.PluginAwareExtensionManager._instance = None - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) # Create the default configurations self.config_parse() diff --git a/neutron/tests/unit/plugins/ml2/test_security_group.py b/neutron/tests/unit/plugins/ml2/test_security_group.py index ce6308f38dd..b2c495b4da3 100644 --- a/neutron/tests/unit/plugins/ml2/test_security_group.py +++ b/neutron/tests/unit/plugins/ml2/test_security_group.py @@ -22,10 +22,10 @@ from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources from neutron_lib import constants as const from neutron_lib import context +from neutron_lib import fixture from neutron_lib.plugins import directory from neutron.extensions import securitygroup as ext_sg -from neutron.tests import tools from neutron.tests.unit.agent import test_securitygroups_rpc as test_sg_rpc from neutron.tests.unit.api.v2 import test_base from neutron.tests.unit.extensions import test_securitygroup as test_sg @@ -41,7 +41,7 @@ class Ml2SecurityGroupsTestCase(test_sg.SecurityGroupDBTestCase): notifier_cls = notifier_p.start() self.notifier = mock.Mock() notifier_cls.return_value = self.notifier - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) super(Ml2SecurityGroupsTestCase, self).setUp('ml2') diff --git a/neutron/tests/unit/plugins/ml2/test_tracked_resources.py b/neutron/tests/unit/plugins/ml2/test_tracked_resources.py index 48a4553e46c..3c1f724e26c 100644 --- a/neutron/tests/unit/plugins/ml2/test_tracked_resources.py +++ b/neutron/tests/unit/plugins/ml2/test_tracked_resources.py @@ -12,10 +12,10 @@ import mock from neutron_lib import context +from neutron_lib import fixture from oslo_utils import uuidutils from neutron.db.quota import api as quota_db_api -from neutron.tests import tools from neutron.tests.unit.api import test_extensions from neutron.tests.unit.extensions import test_l3 from neutron.tests.unit.extensions import test_securitygroup @@ -162,7 +162,7 @@ class TestL3ResourcesEventHandler(BaseTestEventHandler, def setUp(self): super(TestL3ResourcesEventHandler, self).setUp() - self.useFixture(tools.AttributeMapMemento()) + self.useFixture(fixture.APIDefinitionFixture()) ext_mgr = test_l3.L3TestExtensionManager() self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)