From 87a36cacc6e68d64cc0d792412eb73431687abcd Mon Sep 17 00:00:00 2001 From: Boden R Date: Wed, 17 Jan 2018 15:50:26 -0700 Subject: [PATCH] remove tag and tag_ext extensions The tag and tag_ext extensions are deprecated for removal, but are not used widely today [1]. Rather than rehoming these extensions to neutron-lib and carrying out their deprecation life-cycle for no apparent reason, this patch proposes we just remove them now. While [2] initially removed these extensions, we had to revert them with [3]. Depends-On: I295a5b84eb7fa3439561fa009b7499f94d8df4d2 [1] http://codesearch.openstack.org/?q=from%20neutron.extensions%20import%20(tag_ext%7Ctag) [2] I0d7bcd789b468b1dd3f7ea13e6751a46203d6778 [3] If16443616eee703b66d57b6422dd451a443fbc64 Change-Id: I97095453610fff114d999a526d67e78119546ff5 --- doc/source/admin/config-dhcp-ha.rst | 2 - doc/source/contributor/internals/tag.rst | 7 +- doc/source/install/verify.rst | 3 - neutron/extensions/tag.py | 85 ---- neutron/extensions/tag_ext.py | 95 ---- neutron/extensions/tagging.py | 22 +- neutron/services/tag/tag_plugin.py | 2 +- .../tests/contrib/hooks/api_all_extensions | 2 - neutron/tests/unit/extensions/test_tag.py | 406 ------------------ 9 files changed, 4 insertions(+), 620 deletions(-) delete mode 100644 neutron/extensions/tag.py delete mode 100644 neutron/extensions/tag_ext.py delete mode 100644 neutron/tests/unit/extensions/test_tag.py diff --git a/doc/source/admin/config-dhcp-ha.rst b/doc/source/admin/config-dhcp-ha.rst index aa20df28c36..811e91f4795 100644 --- a/doc/source/admin/config-dhcp-ha.rst +++ b/doc/source/admin/config-dhcp-ha.rst @@ -30,7 +30,6 @@ scalability and HA. | agent | agent | | Subnet Allocation | subnet_allocation | | L3 Agent Scheduler | l3_agent_scheduler | - | Tag support | tag | | Neutron external network | external-net | | Neutron Service Flavors | flavors | | Network MTU | net-mtu | @@ -45,7 +44,6 @@ scalability and HA. | Resource timestamps | standard-attr-timestamp | | Neutron Service Type Management | service-type | | Router Flavor Extension | l3-flavors | - | Tag support for resources: subnet, subnetpool, port, router | tag-ext | | Neutron Extra DHCP opts | extra_dhcp_opt | | Resource revision numbers | standard-attr-revisions | | Pagination support | pagination | diff --git a/doc/source/contributor/internals/tag.rst b/doc/source/contributor/internals/tag.rst index 18d9acb92bf..34793e15cbc 100644 --- a/doc/source/contributor/internals/tag.rst +++ b/doc/source/contributor/internals/tag.rst @@ -50,12 +50,7 @@ Which Resources --------------- Tag system uses standardattr mechanism so it's targeting to resources that have -the mechanism. The system is provided by 'tag' extension, 'tag-ext' -extension, and 'tagging' extension. The 'tag' extension supports networks only. -The 'tag-ext' extension supports subnets, ports, routers, and subnet pools. -The 'tagging' extension supports resources with standard attribute so it -means that 'tag' and 'tag-ext' extensions are unnecessary now. These extensions -will be removed. Some resources with standard attribute don't suit fit tag +the mechanism. Some resources with standard attribute don't suit fit tag support usecases (e.g. security_group_rule). If new tag support resource is added, the resource model should inherit HasStandardAttributes and then it must implement the property 'api_parent' and 'tag_support'. And also the change diff --git a/doc/source/install/verify.rst b/doc/source/install/verify.rst index 4ef4adbac30..b3d3ced75af 100644 --- a/doc/source/install/verify.rst +++ b/doc/source/install/verify.rst @@ -40,8 +40,6 @@ Verify operation | | | subnets from a subnet pool | | DHCP Agent Scheduler | dhcp_agent_scheduler | Schedule networks among | | | | dhcp agents | - | Tag support | tag | Enables to set tag on | - | | | resources. | | Neutron external network | external-net | Adds external network | | | | attribute to network | | | | resource. | @@ -73,7 +71,6 @@ Verify operation | Neutron Service Type | service-type | API for retrieving service | | Management | | providers for Neutron | | | | advanced services | - | Tag support for | tag-ext | Extends tag support to | | resources: subnet, | | more L2 and L3 resources. | | subnetpool, port, router | | | | Neutron Extra DHCP opts | extra_dhcp_opt | Extra options | diff --git a/neutron/extensions/tag.py b/neutron/extensions/tag.py deleted file mode 100644 index 67394af1633..00000000000 --- a/neutron/extensions/tag.py +++ /dev/null @@ -1,85 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from neutron_lib.api.definitions import network -from neutron_lib.api import extensions as api_extensions -from neutron_lib.api import faults -from neutron_lib.plugins import directory - -from neutron.api import extensions -from neutron.api.v2 import resource as api_resource -from neutron.extensions import tagging - - -# This extension is deprecated because tagging supports all resources - -TAG_SUPPORTED_RESOURCES = { - # We shouldn't add new resources here. If more resources need to be tagged, - # we must add them in new extension. - network.COLLECTION_NAME: network.RESOURCE_NAME, -} - - -class TagController(tagging.TaggingController): - def __init__(self): - self.plugin = directory.get_plugin(tagging.TAG_PLUGIN_TYPE) - self.supported_resources = TAG_SUPPORTED_RESOURCES - - -class Tag(api_extensions.ExtensionDescriptor): - """Extension class supporting tags.""" - - @classmethod - def get_name(cls): - return "Tag support" - - @classmethod - def get_alias(cls): - return "tag" - - @classmethod - def get_description(cls): - return "Enables to set tag on resources." - - @classmethod - def get_updated(cls): - return "2016-01-01T00:00:00-00:00" - - @classmethod - def get_resources(cls): - """Returns Ext Resources.""" - exts = [] - action_status = {'index': 200, 'show': 204, 'update': 201, - 'update_all': 200, 'delete': 204, 'delete_all': 204} - controller = api_resource.Resource(TagController(), - faults.FAULT_MAP, - action_status=action_status) - collection_methods = {"delete_all": "DELETE", - "update_all": "PUT"} - exts = [] - for collection_name, member_name in TAG_SUPPORTED_RESOURCES.items(): - parent = {'member_name': member_name, - 'collection_name': collection_name} - exts.append(extensions.ResourceExtension( - tagging.TAGS, controller, parent, - collection_methods=collection_methods)) - return exts - - def get_extended_resources(self, version): - if version != "2.0": - return {} - EXTENDED_ATTRIBUTES_2_0 = {} - for collection_name in TAG_SUPPORTED_RESOURCES: - EXTENDED_ATTRIBUTES_2_0[collection_name] = ( - tagging.TAG_ATTRIBUTE_MAP) - return EXTENDED_ATTRIBUTES_2_0 diff --git a/neutron/extensions/tag_ext.py b/neutron/extensions/tag_ext.py deleted file mode 100644 index 7b74143bee4..00000000000 --- a/neutron/extensions/tag_ext.py +++ /dev/null @@ -1,95 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from neutron_lib.api.definitions import l3 as l3_apidef -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.api import extensions as api_extensions -from neutron_lib.api import faults -from neutron_lib.plugins import directory - -from neutron.api import extensions -from neutron.api.v2 import resource as api_resource -from neutron.extensions import tagging - - -# This extension is deprecated because tagging supports all resources - -TAG_SUPPORTED_RESOURCES = { - # We shouldn't add new resources here. If more resources need to be tagged, - # we must add them in new extension. - subnet_def.COLLECTION_NAME: subnet_def.RESOURCE_NAME, - port_def.COLLECTION_NAME: port_def.RESOURCE_NAME, - subnetpool_def.COLLECTION_NAME: subnetpool_def.RESOURCE_NAME, - l3_apidef.ROUTERS: l3_apidef.ROUTER, -} - - -class TagExtController(tagging.TaggingController): - def __init__(self): - self.plugin = directory.get_plugin(tagging.TAG_PLUGIN_TYPE) - self.supported_resources = TAG_SUPPORTED_RESOURCES - - -class Tag_ext(api_extensions.ExtensionDescriptor): - """Extension class supporting tags for ext resources.""" - - @classmethod - def get_name(cls): - return ("Tag support for resources: %s" - % ', '.join(TAG_SUPPORTED_RESOURCES.values())) - - @classmethod - def get_alias(cls): - return "tag-ext" - - @classmethod - def get_description(cls): - return "Extends tag support to more L2 and L3 resources." - - @classmethod - def get_updated(cls): - return "2017-01-01T00:00:00-00:00" - - @classmethod - def get_resources(cls): - """Returns Ext Resources.""" - exts = [] - action_status = {'index': 200, 'show': 204, 'update': 201, - 'update_all': 200, 'delete': 204, 'delete_all': 204} - controller = api_resource.Resource(TagExtController(), - faults.FAULT_MAP, - action_status=action_status) - collection_methods = {"delete_all": "DELETE", - "update_all": "PUT"} - exts = [] - for collection_name, member_name in TAG_SUPPORTED_RESOURCES.items(): - parent = {'member_name': member_name, - 'collection_name': collection_name} - exts.append(extensions.ResourceExtension( - tagging.TAGS, controller, parent, - collection_methods=collection_methods)) - return exts - - def get_optional_extensions(self): - return ['router'] - - def get_extended_resources(self, version): - if version != "2.0": - return {} - EXTENDED_ATTRIBUTES_2_0 = {} - for collection_name in TAG_SUPPORTED_RESOURCES: - EXTENDED_ATTRIBUTES_2_0[collection_name] = ( - tagging.TAG_ATTRIBUTE_MAP) - return EXTENDED_ATTRIBUTES_2_0 diff --git a/neutron/extensions/tagging.py b/neutron/extensions/tagging.py index 6a130d94dcb..449b5f380f2 100644 --- a/neutron/extensions/tagging.py +++ b/neutron/extensions/tagging.py @@ -33,24 +33,8 @@ TAG = 'tag' TAGS = TAG + 's' MAX_TAG_LEN = 60 TAG_PLUGIN_TYPE = 'TAG' -# Not support resources supported by tag, tag-ext -EXCEPTION_RESOURCES = ['networks', 'subnets', 'ports', 'subnetpools', - 'routers'] - -# TODO(hichihara): This method is removed after tag, tag-ext extensions -# have been removed. -def get_tagging_supported_resources(): - # Removes some resources supported by tag, tag-ext - parent_map = standard_attr.get_tag_resource_parent_map() - remove_resources = [res for res in parent_map - if res in EXCEPTION_RESOURCES] - for resource in remove_resources: - del parent_map[resource] - return parent_map - - -TAG_SUPPORTED_RESOURCES = get_tagging_supported_resources() +TAG_SUPPORTED_RESOURCES = standard_attr.get_tag_resource_parent_map() TAG_ATTRIBUTE_MAP = { TAGS: {'allow_post': False, 'allow_put': False, 'is_visible': True} } @@ -187,9 +171,7 @@ class Tagging(api_extensions.ExtensionDescriptor): return "2017-01-01T00:00:00-00:00" def get_required_extensions(self): - # This is needed so that depending project easily moves from old - # extensions although this extension self can run without them. - return ['tag', 'tag-ext'] + return [] @classmethod def get_resources(cls): diff --git a/neutron/services/tag/tag_plugin.py b/neutron/services/tag/tag_plugin.py index 5ba032c3648..153da550641 100644 --- a/neutron/services/tag/tag_plugin.py +++ b/neutron/services/tag/tag_plugin.py @@ -37,7 +37,7 @@ resource_model_map = standard_attr.get_standard_attr_resource_model_map() class TagPlugin(common_db_mixin.CommonDbMixin, tagging.TagPluginBase): """Implementation of the Neutron Tag Service Plugin.""" - supported_extension_aliases = ['tag', 'tag-ext', 'standard-attr-tag'] + supported_extension_aliases = ['standard-attr-tag'] def __new__(cls, *args, **kwargs): inst = super(TagPlugin, cls).__new__(cls, *args, **kwargs) diff --git a/neutron/tests/contrib/hooks/api_all_extensions b/neutron/tests/contrib/hooks/api_all_extensions index 47c19becf34..88c01b9ca3e 100644 --- a/neutron/tests/contrib/hooks/api_all_extensions +++ b/neutron/tests/contrib/hooks/api_all_extensions @@ -46,7 +46,5 @@ NETWORK_API_EXTENSIONS+=",standard-attr-revisions" NETWORK_API_EXTENSIONS+=",standard-attr-timestamp" NETWORK_API_EXTENSIONS+=",standard-attr-tag" NETWORK_API_EXTENSIONS+=",subnet_allocation" -NETWORK_API_EXTENSIONS+=",tag" -NETWORK_API_EXTENSIONS+=",tag-ext" NETWORK_API_EXTENSIONS+=",trunk" NETWORK_API_EXTENSIONS+=",trunk-details" diff --git a/neutron/tests/unit/extensions/test_tag.py b/neutron/tests/unit/extensions/test_tag.py deleted file mode 100644 index e2ba1b673ae..00000000000 --- a/neutron/tests/unit/extensions/test_tag.py +++ /dev/null @@ -1,406 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from neutron_lib.api import attributes -from neutron_lib import context -from oslo_utils import uuidutils -import testscenarios - -from neutron.api import extensions -from neutron.common import config -import neutron.extensions -from neutron.objects.qos import policy -from neutron.objects import trunk -from neutron.services.tag import tag_plugin -from neutron.tests import fake_notifier -from neutron.tests.unit.extensions import test_l3 -from neutron.tests.unit.extensions import test_securitygroup - - -DB_PLUGIN_KLASS = 'neutron.tests.unit.extensions.test_tag.TestTagPlugin' - -load_tests = testscenarios.load_tests_apply_scenarios -extensions_path = ':'.join(neutron.extensions.__path__) - - -class TestTagPlugin(test_securitygroup.SecurityGroupTestPlugin, - test_l3.TestL3NatBasePlugin): - - __native_pagination_support = True - __native_sorting_support = True - - supported_extension_aliases = ["external-net", "security-group"] - - -class TestTagApiBase(test_securitygroup.SecurityGroupsTestCase, - test_l3.L3NatTestCaseMixin): - scenarios = [ - ('Network Tag Test', - dict(collection='networks', - member='network')), - ('Subnet Tag Test', - dict(collection='subnets', - member='subnet')), - ('Port Tag Test', - dict(collection='ports', - member='port')), - ('Subnetpool Tag Test', - dict(collection='subnetpools', - member='subnetpool')), - ('Router Tag Test', - dict(collection='routers', - member='router')), - ('Floatingip Tag Test', - dict(collection='floatingips', - member='floatingip')), - ('Securitygroup Tag Test', - dict(collection='security-groups', - member='security_group')), - ('QoS Policy Tag Test', - dict(collection='policies', - member='policy')), - ('Trunk Tag Test', - dict(collection='trunks', - member='trunk')), - ] - - def setUp(self): - service_plugins = { - 'TAG': "neutron.services.tag.tag_plugin.TagPlugin", - 'router': - "neutron.tests.unit.extensions.test_l3.TestL3NatServicePlugin"} - super(TestTagApiBase, self).setUp(plugin=DB_PLUGIN_KLASS, - service_plugins=service_plugins) - plugin = tag_plugin.TagPlugin() - l3_plugin = test_l3.TestL3NatServicePlugin() - sec_plugin = test_securitygroup.SecurityGroupTestPlugin() - ext_mgr = extensions.PluginAwareExtensionManager( - extensions_path, {'router': l3_plugin, 'TAG': plugin, - 'sec': sec_plugin} - ) - ext_mgr.extend_resources("2.0", attributes.RESOURCES) - app = config.load_paste_app('extensions_test_app') - self.ext_api = extensions.ExtensionMiddleware(app, ext_mgr=ext_mgr) - - def _is_object(self): - return self.collection in ['policies', 'trunks'] - - def _prepare_make_resource(self): - if self.collection == "floatingips": - net = self._make_network(self.fmt, 'net1', True) - self._set_net_external(net['network']['id']) - self._make_subnet(self.fmt, net, '10.0.0.1', '10.0.0.0/24') - info = {'network_id': net['network']['id']} - self._make_router(self.fmt, None, - external_gateway_info=info) - self.net = net['network'] - - def _make_object(self): - ctxt = context.get_admin_context() - if self.collection == "policies": - self.obj = policy.QosPolicy(context=ctxt, - id=uuidutils.generate_uuid(), - project_id='tenant', name='pol1', - rules=[]) - elif self.collection == "trunks": - net = self._make_network(self.fmt, 'net1', True) - port = self._make_port(self.fmt, net['network']['id']) - self.obj = trunk.Trunk(context=ctxt, - id=uuidutils.generate_uuid(), - project_id='tenant', name='', - port_id=port['port']['id']) - self.obj.create() - return self.obj.id - - def _make_resource(self): - if self._is_object(): - return self._make_object() - - if self.collection == "networks": - res = self._make_network(self.fmt, 'net1', True) - elif self.collection == "subnets": - net = self._make_network(self.fmt, 'net1', True) - res = self._make_subnet(self.fmt, net, '10.0.0.1', '10.0.0.0/24') - elif self.collection == "ports": - net = self._make_network(self.fmt, 'net1', True) - res = self._make_port(self.fmt, net['network']['id']) - elif self.collection == "subnetpools": - res = self._make_subnetpool(self.fmt, ['10.0.0.0/8'], - name='my pool', tenant_id="tenant") - elif self.collection == "routers": - res = self._make_router(self.fmt, None) - elif self.collection == "floatingips": - res = self._make_floatingip(self.fmt, self.net['id']) - elif self.collection == "security-groups": - res = self._make_security_group(self.fmt, 'sec1', '') - return res[self.member]['id'] - - def _get_object_tags(self): - ctxt = context.get_admin_context() - res = self.obj.get_object(ctxt, id=self.resource_id) - return res.to_dict()['tags'] - - def _get_resource_tags(self): - if self._is_object(): - return self._get_object_tags() - - res = self._show(self.collection, self.resource_id) - return res[self.member]['tags'] - - def _put_tag(self, tag): - req = self._req('PUT', self.collection, id=self.resource_id, - subresource='tags', sub_id=tag) - return req.get_response(self.ext_api) - - def _put_tags(self, tags=None, body=None): - if tags: - body = {'tags': tags} - elif body: - body = body - else: - body = {} - req = self._req('PUT', self.collection, data=body, id=self.resource_id, - subresource='tags') - return req.get_response(self.ext_api) - - def _get_tag(self, tag): - req = self._req('GET', self.collection, id=self.resource_id, - subresource='tags', sub_id=tag) - return req.get_response(self.ext_api) - - def _delete_tag(self, tag): - req = self._req('DELETE', self.collection, id=self.resource_id, - subresource='tags', sub_id=tag) - return req.get_response(self.ext_api) - - def _delete_tags(self): - req = self._req('DELETE', self.collection, id=self.resource_id, - subresource='tags') - return req.get_response(self.ext_api) - - def _assertEqualTags(self, expected, actual): - self.assertEqual(set(expected), set(actual)) - - def _get_tags_filter_objects(self, tags, tags_any, not_tags, - not_tags_any): - filters = {} - if tags: - filters['tags'] = tags - if tags_any: - filters['tags-any'] = tags_any - if not_tags: - filters['not-tags'] = not_tags - if not_tags_any: - filters['not-tags-any'] = not_tags_any - - if self.collection == "policies": - obj_class = policy.QosPolicy - elif self.collection == "trunks": - obj_class = trunk.Trunk - ctxt = context.get_admin_context() - res = obj_class.get_objects(ctxt, **filters) - return [n.id for n in res] - - def _make_query_string(self, tags, tags_any, not_tags, not_tags_any): - filter_strings = [] - if tags: - filter_strings.append("tags=" + ','.join(tags)) - if tags_any: - filter_strings.append("tags-any=" + ','.join(tags_any)) - if not_tags: - filter_strings.append("not-tags=" + ','.join(not_tags)) - if not_tags_any: - filter_strings.append("not-tags-any=" + ','.join(not_tags_any)) - - return '&'.join(filter_strings) - - def _get_tags_filter_resources(self, tags=None, tags_any=None, - not_tags=None, not_tags_any=None): - if self._is_object(): - return self._get_tags_filter_objects(tags, tags_any, not_tags, - not_tags_any) - - params = self._make_query_string(tags, tags_any, not_tags, - not_tags_any) - res = self._list(self.collection, query_params=params) - return [n['id'] for n in res[self.collection.replace('-', '_')]] - - def _test_notification_report(self, expect_notify): - notify = set(n['event_type'] for n in fake_notifier.NOTIFICATIONS) - duplicated_notify = expect_notify & notify - self.assertEqual(expect_notify, duplicated_notify) - - fake_notifier.reset() - - -class TestResourceTagApi(TestTagApiBase): - - def setUp(self): - super(TestResourceTagApi, self).setUp() - self._prepare_make_resource() - self.resource_id = self._make_resource() - - def test_put_tag(self): - expect_notify = set(['tag.create.start', - 'tag.create.end']) - res = self._put_tag('red') - self.assertEqual(201, res.status_int) - tags = self._get_resource_tags() - self._assertEqualTags(['red'], tags) - self._test_notification_report(expect_notify) - res = self._put_tag('blue') - self.assertEqual(201, res.status_int) - tags = self._get_resource_tags() - self._assertEqualTags(['red', 'blue'], tags) - self._test_notification_report(expect_notify) - - def test_put_tag_exists(self): - res = self._put_tag('blue') - self.assertEqual(201, res.status_int) - res = self._put_tag('blue') - self.assertEqual(201, res.status_int) - - def test_put_tags(self): - expect_notify = set(['tag.update.start', - 'tag.update.end']) - res = self._put_tags(['red', 'green']) - self.assertEqual(200, res.status_int) - tags = self._get_resource_tags() - self._assertEqualTags(['red', 'green'], tags) - self._test_notification_report(expect_notify) - - def test_put_invalid_tags(self): - res = self._put_tags() - self.assertEqual(400, res.status_int) - res = self._put_tags(body=7) - self.assertEqual(400, res.status_int) - res = self._put_tags(body={'invalid': True}) - self.assertEqual(400, res.status_int) - - def test_put_tags_replace(self): - res = self._put_tags(['red', 'green']) - self.assertEqual(200, res.status_int) - tags = self._get_resource_tags() - self._assertEqualTags(['red', 'green'], tags) - res = self._put_tags(['blue', 'red']) - self.assertEqual(200, res.status_int) - tags = self._get_resource_tags() - self._assertEqualTags(['blue', 'red'], tags) - - def test_get_tag(self): - res = self._put_tag('red') - self.assertEqual(201, res.status_int) - res = self._get_tag('red') - self.assertEqual(204, res.status_int) - - def test_get_tag_notfound(self): - res = self._put_tag('red') - self.assertEqual(201, res.status_int) - res = self._get_tag('green') - self.assertEqual(404, res.status_int) - - def test_delete_tag(self): - expect_notify = set(['tag.delete.start', - 'tag.delete.end']) - res = self._put_tags(['red', 'green']) - self.assertEqual(200, res.status_int) - res = self._delete_tag('red') - self.assertEqual(204, res.status_int) - tags = self._get_resource_tags() - self._assertEqualTags(['green'], tags) - self._test_notification_report(expect_notify) - - def test_delete_tag_notfound(self): - res = self._put_tags(['red', 'green']) - self.assertEqual(200, res.status_int) - res = self._delete_tag('blue') - self.assertEqual(404, res.status_int) - - def test_delete_tags(self): - expect_notify = set(['tag.delete_all.start', - 'tag.delete_all.end']) - res = self._put_tags(['red', 'green']) - self.assertEqual(200, res.status_int) - res = self._delete_tags() - self.assertEqual(204, res.status_int) - tags = self._get_resource_tags() - self._assertEqualTags([], tags) - self._test_notification_report(expect_notify) - - -class TestResourceTagFilter(TestTagApiBase): - - def setUp(self): - super(TestResourceTagFilter, self).setUp() - self._prepare_resource_tags() - - def _make_tags(self, resource_id, tags): - body = {'tags': tags} - req = self._req('PUT', self.collection, data=body, id=resource_id, - subresource='tags') - return req.get_response(self.ext_api) - - def _prepare_resource_tags(self): - self._prepare_make_resource() - self.res1 = self._make_resource() - self.res2 = self._make_resource() - self.res3 = self._make_resource() - self.res4 = self._make_resource() - self.res5 = self._make_resource() - self.res_ids = [self.res1, self.res2, self.res3, self.res4, self.res5] - - self._make_tags(self.res1, ['red']) - self._make_tags(self.res2, ['red', 'blue']) - self._make_tags(self.res3, ['red', 'blue', 'green']) - self._make_tags(self.res4, ['green']) - # res5: no tags - - def _assertEqualResources(self, expected, resources): - actual = [n for n in resources if n in self.res_ids] - self.assertEqual(set(expected), set(actual)) - - def test_filter_tags_single(self): - resources = self._get_tags_filter_resources(tags=['red']) - self._assertEqualResources([self.res1, self.res2, self.res3], - resources) - - def test_filter_tags_multi(self): - resources = self._get_tags_filter_resources(tags=['red', 'blue']) - self._assertEqualResources([self.res2, self.res3], resources) - - def test_filter_tags_any_single(self): - resources = self._get_tags_filter_resources(tags_any=['blue']) - self._assertEqualResources([self.res2, self.res3], resources) - - def test_filter_tags_any_multi(self): - resources = self._get_tags_filter_resources(tags_any=['red', 'blue']) - self._assertEqualResources([self.res1, self.res2, self.res3], - resources) - - def test_filter_not_tags_single(self): - resources = self._get_tags_filter_resources(not_tags=['red']) - self._assertEqualResources([self.res4, self.res5], resources) - - def test_filter_not_tags_multi(self): - resources = self._get_tags_filter_resources(not_tags=['red', 'blue']) - self._assertEqualResources([self.res1, self.res4, self.res5], - resources) - - def test_filter_not_tags_any_single(self): - resources = self._get_tags_filter_resources(not_tags_any=['blue']) - self._assertEqualResources([self.res1, self.res4, self.res5], - resources) - - def test_filter_not_tags_any_multi(self): - resources = self._get_tags_filter_resources(not_tags_any=['red', - 'blue']) - self._assertEqualResources([self.res4, self.res5], resources)