From f38cecfdfc54c16e7cd8533c91255d07498a982b Mon Sep 17 00:00:00 2001 From: Flavio Percoco Date: Fri, 18 Mar 2016 09:50:07 -0400 Subject: [PATCH] Disable DEPRECATED API versions by default API v1.0 has been deprecated for a while and v1.1 will be deprecated soon. We shouldn't be enabling deprecated API versions by default. This patch adds a decorator to disable deprecated APIs by default unless they have been explicitly enabled in the environment. Co-Authored-By: Fei Long Wang Change-Id: I62fb4d18bc6c9f5455bff0d56e42269b4590b454 --- devstack/plugin.sh | 1 + ...-deprecated-versions-44656aeb8ebb8881.yaml | 7 ++++ zaqar/common/configs.py | 4 ++ zaqar/common/decorators.py | 35 ++++++++++++++++ zaqar/tests/etc/drivers_storage_invalid.conf | 1 + .../tests/etc/drivers_transport_invalid.conf | 1 + zaqar/tests/etc/functional-tests.conf | 1 + zaqar/tests/etc/functional-zaqar.conf | 3 ++ zaqar/tests/etc/keystone_auth.conf | 1 + zaqar/tests/etc/websocket_mongodb.conf | 1 + .../etc/websocket_mongodb_keystone_auth.conf | 1 + .../etc/websocket_mongodb_subscriptions.conf | 1 + zaqar/tests/etc/wsgi_faulty.conf | 1 + zaqar/tests/etc/wsgi_fifo_mongodb.conf | 1 + zaqar/tests/etc/wsgi_mongodb.conf | 1 + .../etc/wsgi_mongodb_default_limits.conf | 5 ++- zaqar/tests/etc/wsgi_mongodb_pooled.conf | 1 + zaqar/tests/etc/wsgi_mongodb_validation.conf | 3 ++ zaqar/tests/etc/wsgi_redis.conf | 1 + zaqar/tests/etc/wsgi_redis_pooled.conf | 1 + zaqar/tests/etc/wsgi_sqlalchemy.conf | 1 + zaqar/tests/etc/wsgi_sqlalchemy_pooled.conf | 1 + zaqar/tests/unit/common/test_decorators.py | 42 +++++++++++++++++++ zaqar/transport/wsgi/driver.py | 5 ++- zaqar/transport/wsgi/v1_0/__init__.py | 6 +-- zaqar/transport/wsgi/v1_1/__init__.py | 3 ++ zaqar/transport/wsgi/v2_0/__init__.py | 3 ++ 27 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/support-turnoff-deprecated-versions-44656aeb8ebb8881.yaml diff --git a/devstack/plugin.sh b/devstack/plugin.sh index a8547f3a0..a39685301 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -84,6 +84,7 @@ function configure_zaqar { iniset $ZAQAR_CONF DEFAULT debug True iniset $ZAQAR_CONF DEFAULT unreliable True iniset $ZAQAR_CONF DEFAULT admin_mode True + iniset $ZAQAR_CONF DEFAULT enable_deprecated_api_versions 1 iniset $ZAQAR_CONF signed_url secret_key notreallysecret if is_service_enabled key; then diff --git a/releasenotes/notes/support-turnoff-deprecated-versions-44656aeb8ebb8881.yaml b/releasenotes/notes/support-turnoff-deprecated-versions-44656aeb8ebb8881.yaml new file mode 100644 index 000000000..8d332ab6e --- /dev/null +++ b/releasenotes/notes/support-turnoff-deprecated-versions-44656aeb8ebb8881.yaml @@ -0,0 +1,7 @@ +--- +features: + - Currently, the v1 API is still accessible though it has been deprecated + for a while. And we're going to deprecate v1.1 soon. To keep the backward + compatibility, a new config option - ``enable_deprecated_api_versions`` + is added so that operator can totally turn off an API version or still + support it by adding the API version to the list of the new config option. diff --git a/zaqar/common/configs.py b/zaqar/common/configs.py index 204f7282e..85851d918 100644 --- a/zaqar/common/configs.py +++ b/zaqar/common/configs.py @@ -31,6 +31,10 @@ _GENERAL_OPTIONS = ( deprecated_opts=[cfg.DeprecatedOpt('sharding')]), cfg.BoolOpt('unreliable', default=False, help='Disable all reliability constraints.'), + cfg.ListOpt('enable_deprecated_api_versions', default=[], + item_type=cfg.types.List(item_type=cfg.types.String( + choices=('1', '1.1'))), + help='List of deprecated API versions to enable.'), ) _DRIVER_OPTIONS = ( diff --git a/zaqar/common/decorators.py b/zaqar/common/decorators.py index 5537335e1..5d6c5317c 100644 --- a/zaqar/common/decorators.py +++ b/zaqar/common/decorators.py @@ -20,6 +20,9 @@ from oslo_cache import core from oslo_log import log as logging from oslo_serialization import jsonutils +from zaqar.i18n import _LW + + LOG = logging.getLogger(__name__) @@ -183,3 +186,35 @@ def lazy_property(write=False, delete=True): fdel=delete and deleter, doc=fn.__doc__) return wrapper + + +def api_version_manager(version_info): + """Manage API versions based on their status + + This decorator disables `DEPRECATED` APIs by default unless the user + explicitly enables it by adding it to the `enable_deprecated_api_versions` + configuration option. + + :param version_info: Dictionary containing the API version info. + """ + api_version = version_info['id'] + api_updated = version_info['updated'] + deprecated = version_info['status'] == 'DEPRECATED' + + def wrapper(fn): + @functools.wraps(fn) + def register_api(driver, conf): + if (deprecated and + [api_version] not in conf.enable_deprecated_api_versions): + return None + + if deprecated: + LOG.warning(_LW('Enabling API version %(version)s. ' + 'This version was marked as deprecated in ' + '%(updated)s. Using it may expose security ' + 'issues, unexpected behavior or damage your ' + 'data.') % {'version': api_version, + 'updated': api_updated}) + return fn(driver, conf) + return register_api + return wrapper diff --git a/zaqar/tests/etc/drivers_storage_invalid.conf b/zaqar/tests/etc/drivers_storage_invalid.conf index f289cd591..797fe9bdb 100644 --- a/zaqar/tests/etc/drivers_storage_invalid.conf +++ b/zaqar/tests/etc/drivers_storage_invalid.conf @@ -2,6 +2,7 @@ debug = False verbose = False admin_mode = False +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/drivers_transport_invalid.conf b/zaqar/tests/etc/drivers_transport_invalid.conf index 575fbf776..3b1317107 100644 --- a/zaqar/tests/etc/drivers_transport_invalid.conf +++ b/zaqar/tests/etc/drivers_transport_invalid.conf @@ -1,6 +1,7 @@ [DEFAULT] debug = False verbose = False +enable_deprecated_api_versions = 1 [drivers] transport = invalid diff --git a/zaqar/tests/etc/functional-tests.conf b/zaqar/tests/etc/functional-tests.conf index 38d8dc66b..f49983ebc 100644 --- a/zaqar/tests/etc/functional-tests.conf +++ b/zaqar/tests/etc/functional-tests.conf @@ -1,6 +1,7 @@ [DEFAULT] # run_tests = True unreliable = True +enable_deprecated_api_versions = 1 [zaqar] # url = http://0.0.0.0:8888 diff --git a/zaqar/tests/etc/functional-zaqar.conf b/zaqar/tests/etc/functional-zaqar.conf index f71fad1fa..b00644ce3 100644 --- a/zaqar/tests/etc/functional-zaqar.conf +++ b/zaqar/tests/etc/functional-zaqar.conf @@ -5,6 +5,8 @@ verbose = True # Show debugging output in logs (sets DEBUG log level output) debug = True +enable_deprecated_api_versions = 1 + # Log to this file! ; log_file = /var/log/zaqar/server.log @@ -20,6 +22,7 @@ debug = True ;syslog_log_facility = LOG_LOCAL0 unreliable = True +enable_deprecated_api_versions = 1, 1.1 [drivers] # Transport driver module (e.g., wsgi, zmq) diff --git a/zaqar/tests/etc/keystone_auth.conf b/zaqar/tests/etc/keystone_auth.conf index 647807714..ef8776d77 100644 --- a/zaqar/tests/etc/keystone_auth.conf +++ b/zaqar/tests/etc/keystone_auth.conf @@ -3,6 +3,7 @@ auth_strategy = keystone debug = False verbose = False +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/websocket_mongodb.conf b/zaqar/tests/etc/websocket_mongodb.conf index 81c4f42c0..76e6d7515 100644 --- a/zaqar/tests/etc/websocket_mongodb.conf +++ b/zaqar/tests/etc/websocket_mongodb.conf @@ -1,5 +1,6 @@ [DEFAULT] unreliable = True +enable_deprecated_api_versions = 1 [drivers] diff --git a/zaqar/tests/etc/websocket_mongodb_keystone_auth.conf b/zaqar/tests/etc/websocket_mongodb_keystone_auth.conf index 64e98f0f3..ebe1ddfc4 100644 --- a/zaqar/tests/etc/websocket_mongodb_keystone_auth.conf +++ b/zaqar/tests/etc/websocket_mongodb_keystone_auth.conf @@ -1,5 +1,6 @@ [DEFAULT] auth_strategy = keystone +enable_deprecated_api_versions = 1 [drivers] diff --git a/zaqar/tests/etc/websocket_mongodb_subscriptions.conf b/zaqar/tests/etc/websocket_mongodb_subscriptions.conf index 56a97899d..b5014cf50 100644 --- a/zaqar/tests/etc/websocket_mongodb_subscriptions.conf +++ b/zaqar/tests/etc/websocket_mongodb_subscriptions.conf @@ -1,5 +1,6 @@ [DEFAULT] unreliable = True +enable_deprecated_api_versions = 1 [drivers] diff --git a/zaqar/tests/etc/wsgi_faulty.conf b/zaqar/tests/etc/wsgi_faulty.conf index c07ebc4ba..064d15aa0 100644 --- a/zaqar/tests/etc/wsgi_faulty.conf +++ b/zaqar/tests/etc/wsgi_faulty.conf @@ -1,6 +1,7 @@ [DEFAULT] debug = False verbose = False +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/wsgi_fifo_mongodb.conf b/zaqar/tests/etc/wsgi_fifo_mongodb.conf index 5b0c8cb65..27649ad45 100644 --- a/zaqar/tests/etc/wsgi_fifo_mongodb.conf +++ b/zaqar/tests/etc/wsgi_fifo_mongodb.conf @@ -2,6 +2,7 @@ debug = False verbose = False unreliable = True +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/wsgi_mongodb.conf b/zaqar/tests/etc/wsgi_mongodb.conf index 134ef39e1..629865a55 100644 --- a/zaqar/tests/etc/wsgi_mongodb.conf +++ b/zaqar/tests/etc/wsgi_mongodb.conf @@ -2,6 +2,7 @@ debug = False verbose = False unreliable = True +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/wsgi_mongodb_default_limits.conf b/zaqar/tests/etc/wsgi_mongodb_default_limits.conf index 6c35848e3..38462c674 100644 --- a/zaqar/tests/etc/wsgi_mongodb_default_limits.conf +++ b/zaqar/tests/etc/wsgi_mongodb_default_limits.conf @@ -1,3 +1,6 @@ +[DEFAULT] +enable_deprecated_api_versions = 1 + [drivers] transport = wsgi -message_store = mongodb +message_store = mongodb \ No newline at end of file diff --git a/zaqar/tests/etc/wsgi_mongodb_pooled.conf b/zaqar/tests/etc/wsgi_mongodb_pooled.conf index 4eadd48b4..092ee5e89 100644 --- a/zaqar/tests/etc/wsgi_mongodb_pooled.conf +++ b/zaqar/tests/etc/wsgi_mongodb_pooled.conf @@ -2,6 +2,7 @@ pooling = True admin_mode = True unreliable = True +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/wsgi_mongodb_validation.conf b/zaqar/tests/etc/wsgi_mongodb_validation.conf index 7cdedf3c5..cb52665c2 100644 --- a/zaqar/tests/etc/wsgi_mongodb_validation.conf +++ b/zaqar/tests/etc/wsgi_mongodb_validation.conf @@ -1,3 +1,6 @@ +[DEFAULT] +enable_deprecated_api_versions = 1 + [drivers] transport = wsgi message_store = mongodb diff --git a/zaqar/tests/etc/wsgi_redis.conf b/zaqar/tests/etc/wsgi_redis.conf index a06ea5108..77f48cb04 100644 --- a/zaqar/tests/etc/wsgi_redis.conf +++ b/zaqar/tests/etc/wsgi_redis.conf @@ -1,6 +1,7 @@ [DEFAULT] debug = False verbose = False +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/wsgi_redis_pooled.conf b/zaqar/tests/etc/wsgi_redis_pooled.conf index 4a97eaeb1..4b989a7c1 100644 --- a/zaqar/tests/etc/wsgi_redis_pooled.conf +++ b/zaqar/tests/etc/wsgi_redis_pooled.conf @@ -1,5 +1,6 @@ [DEFAULT] pooling = True +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/wsgi_sqlalchemy.conf b/zaqar/tests/etc/wsgi_sqlalchemy.conf index d13f7b30e..0fb54ad70 100644 --- a/zaqar/tests/etc/wsgi_sqlalchemy.conf +++ b/zaqar/tests/etc/wsgi_sqlalchemy.conf @@ -2,6 +2,7 @@ debug = False verbose = False admin_mode = False +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/etc/wsgi_sqlalchemy_pooled.conf b/zaqar/tests/etc/wsgi_sqlalchemy_pooled.conf index 4fc1fe611..160704736 100644 --- a/zaqar/tests/etc/wsgi_sqlalchemy_pooled.conf +++ b/zaqar/tests/etc/wsgi_sqlalchemy_pooled.conf @@ -1,6 +1,7 @@ [DEFAULT] pooling = True admin_mode = True +enable_deprecated_api_versions = 1 [drivers] transport = wsgi diff --git a/zaqar/tests/unit/common/test_decorators.py b/zaqar/tests/unit/common/test_decorators.py index 35512960c..90b2f0cff 100644 --- a/zaqar/tests/unit/common/test_decorators.py +++ b/zaqar/tests/unit/common/test_decorators.py @@ -18,12 +18,17 @@ from oslo_cache import core from oslo_config import cfg from zaqar.common import cache as oslo_cache +from zaqar.common import configs from zaqar.common import decorators from zaqar.tests import base class TestDecorators(base.TestBase): + def setUp(self): + super(TestDecorators, self).setUp() + self.conf.register_opts(configs._GENERAL_OPTIONS) + def test_memoized_getattr(self): class TestClass(object): @@ -141,3 +146,40 @@ class TestDecorators(base.TestBase): self.assertEqual(name, user) self.assertEqual(2 + i, instance.user_gets) + + def test_api_version_manager(self): + self.config(enable_deprecated_api_versions=[]) + # 1. Test accessing current API version + VERSION = { + 'id': '1', + 'status': 'CURRENT', + 'updated': 'Just yesterday' + } + + @decorators.api_version_manager(VERSION) + def public_endpoint_1(driver, conf): + return True + + self.assertTrue(public_endpoint_1(None, self.conf)) + + # 2. Test accessing deprecated API version + VERSION = { + 'id': '1', + 'status': 'DEPRECATED', + 'updated': 'A long time ago' + } + + @decorators.api_version_manager(VERSION) + def public_endpoint_2(driver, conf): + self.fail('Deprecated API enabled') + + public_endpoint_2(None, self.conf) + + # 3. Test enabling deprecated API version + self.config(enable_deprecated_api_versions=[['1']]) + + @decorators.api_version_manager(VERSION) + def public_endpoint_3(driver, conf): + return True + + self.assertTrue(public_endpoint_3(None, self.conf)) diff --git a/zaqar/transport/wsgi/driver.py b/zaqar/transport/wsgi/driver.py index 87938525d..a82195c60 100644 --- a/zaqar/transport/wsgi/driver.py +++ b/zaqar/transport/wsgi/driver.py @@ -131,8 +131,9 @@ class Driver(transport.DriverBase): self.app.add_error_handler(Exception, self._error_handler) for version_path, endpoints in catalog: - for route, resource in endpoints: - self.app.add_route(version_path + route, resource) + if endpoints: + for route, resource in endpoints: + self.app.add_route(version_path + route, resource) def _init_middleware(self): """Initialize WSGI middlewarez.""" diff --git a/zaqar/transport/wsgi/v1_0/__init__.py b/zaqar/transport/wsgi/v1_0/__init__.py index 40066b605..1176975b4 100644 --- a/zaqar/transport/wsgi/v1_0/__init__.py +++ b/zaqar/transport/wsgi/v1_0/__init__.py @@ -14,6 +14,7 @@ from oslo_log import log as logging +from zaqar.common import decorators from zaqar.transport.wsgi.v1_0 import claims from zaqar.transport.wsgi.v1_0 import health from zaqar.transport.wsgi.v1_0 import homedoc @@ -46,10 +47,8 @@ VERSION = { } +@decorators.api_version_manager(VERSION) def public_endpoints(driver, conf): - LOG.warning('Zaqar\'s API version 1.0 will be turned off by default ' - 'during the Newton cycle') - queue_controller = driver._storage.queue_controller message_controller = driver._storage.message_controller claim_controller = driver._storage.claim_controller @@ -96,6 +95,7 @@ def public_endpoints(driver, conf): ] +@decorators.api_version_manager(VERSION) def private_endpoints(driver, conf): if not conf.pooling: return [] diff --git a/zaqar/transport/wsgi/v1_1/__init__.py b/zaqar/transport/wsgi/v1_1/__init__.py index 3ca00773d..bfdab7122 100644 --- a/zaqar/transport/wsgi/v1_1/__init__.py +++ b/zaqar/transport/wsgi/v1_1/__init__.py @@ -14,6 +14,7 @@ from oslo_log import log as logging +from zaqar.common import decorators from zaqar.transport.wsgi.v1_1 import claims from zaqar.transport.wsgi.v1_1 import flavors from zaqar.transport.wsgi.v1_1 import health @@ -47,6 +48,7 @@ VERSION = { } +@decorators.api_version_manager(VERSION) def public_endpoints(driver, conf): LOG.warning('Zaqar\'s API version 1.1 will enter deprecation during the ' 'Newton cycle. As part of that, it will be marked as ' @@ -104,6 +106,7 @@ def public_endpoints(driver, conf): ] +@decorators.api_version_manager(VERSION) def private_endpoints(driver, conf): catalogue = [ diff --git a/zaqar/transport/wsgi/v2_0/__init__.py b/zaqar/transport/wsgi/v2_0/__init__.py index 310326584..46078bd6a 100644 --- a/zaqar/transport/wsgi/v2_0/__init__.py +++ b/zaqar/transport/wsgi/v2_0/__init__.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations under # the License. +from zaqar.common import decorators from zaqar.transport.wsgi.v2_0 import claims from zaqar.transport.wsgi.v2_0 import flavors from zaqar.transport.wsgi.v2_0 import health @@ -44,6 +45,7 @@ VERSION = { } +@decorators.api_version_manager(VERSION) def public_endpoints(driver, conf): queue_controller = driver._storage.queue_controller message_controller = driver._storage.message_controller @@ -117,6 +119,7 @@ def public_endpoints(driver, conf): ] +@decorators.api_version_manager(VERSION) def private_endpoints(driver, conf): catalogue = [