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 <flwang@catalyst.net.nz>

Change-Id: I62fb4d18bc6c9f5455bff0d56e42269b4590b454
This commit is contained in:
Flavio Percoco 2016-03-18 09:50:07 -04:00 committed by Fei Long Wang
parent 9f5b518150
commit f38cecfdfc
27 changed files with 126 additions and 6 deletions

View File

@ -84,6 +84,7 @@ function configure_zaqar {
iniset $ZAQAR_CONF DEFAULT debug True iniset $ZAQAR_CONF DEFAULT debug True
iniset $ZAQAR_CONF DEFAULT unreliable True iniset $ZAQAR_CONF DEFAULT unreliable True
iniset $ZAQAR_CONF DEFAULT admin_mode 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 iniset $ZAQAR_CONF signed_url secret_key notreallysecret
if is_service_enabled key; then if is_service_enabled key; then

View File

@ -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.

View File

@ -31,6 +31,10 @@ _GENERAL_OPTIONS = (
deprecated_opts=[cfg.DeprecatedOpt('sharding')]), deprecated_opts=[cfg.DeprecatedOpt('sharding')]),
cfg.BoolOpt('unreliable', default=False, cfg.BoolOpt('unreliable', default=False,
help='Disable all reliability constraints.'), 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 = ( _DRIVER_OPTIONS = (

View File

@ -20,6 +20,9 @@ from oslo_cache import core
from oslo_log import log as logging from oslo_log import log as logging
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from zaqar.i18n import _LW
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -183,3 +186,35 @@ def lazy_property(write=False, delete=True):
fdel=delete and deleter, fdel=delete and deleter,
doc=fn.__doc__) doc=fn.__doc__)
return wrapper 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

View File

@ -2,6 +2,7 @@
debug = False debug = False
verbose = False verbose = False
admin_mode = False admin_mode = False
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -1,6 +1,7 @@
[DEFAULT] [DEFAULT]
debug = False debug = False
verbose = False verbose = False
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = invalid transport = invalid

View File

@ -1,6 +1,7 @@
[DEFAULT] [DEFAULT]
# run_tests = True # run_tests = True
unreliable = True unreliable = True
enable_deprecated_api_versions = 1
[zaqar] [zaqar]
# url = http://0.0.0.0:8888 # url = http://0.0.0.0:8888

View File

@ -5,6 +5,8 @@ verbose = True
# Show debugging output in logs (sets DEBUG log level output) # Show debugging output in logs (sets DEBUG log level output)
debug = True debug = True
enable_deprecated_api_versions = 1
# Log to this file! # Log to this file!
; log_file = /var/log/zaqar/server.log ; log_file = /var/log/zaqar/server.log
@ -20,6 +22,7 @@ debug = True
;syslog_log_facility = LOG_LOCAL0 ;syslog_log_facility = LOG_LOCAL0
unreliable = True unreliable = True
enable_deprecated_api_versions = 1, 1.1
[drivers] [drivers]
# Transport driver module (e.g., wsgi, zmq) # Transport driver module (e.g., wsgi, zmq)

View File

@ -3,6 +3,7 @@ auth_strategy = keystone
debug = False debug = False
verbose = False verbose = False
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -1,5 +1,6 @@
[DEFAULT] [DEFAULT]
unreliable = True unreliable = True
enable_deprecated_api_versions = 1
[drivers] [drivers]

View File

@ -1,5 +1,6 @@
[DEFAULT] [DEFAULT]
auth_strategy = keystone auth_strategy = keystone
enable_deprecated_api_versions = 1
[drivers] [drivers]

View File

@ -1,5 +1,6 @@
[DEFAULT] [DEFAULT]
unreliable = True unreliable = True
enable_deprecated_api_versions = 1
[drivers] [drivers]

View File

@ -1,6 +1,7 @@
[DEFAULT] [DEFAULT]
debug = False debug = False
verbose = False verbose = False
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -2,6 +2,7 @@
debug = False debug = False
verbose = False verbose = False
unreliable = True unreliable = True
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -2,6 +2,7 @@
debug = False debug = False
verbose = False verbose = False
unreliable = True unreliable = True
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -1,3 +1,6 @@
[DEFAULT]
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi
message_store = mongodb message_store = mongodb

View File

@ -2,6 +2,7 @@
pooling = True pooling = True
admin_mode = True admin_mode = True
unreliable = True unreliable = True
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -1,3 +1,6 @@
[DEFAULT]
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi
message_store = mongodb message_store = mongodb

View File

@ -1,6 +1,7 @@
[DEFAULT] [DEFAULT]
debug = False debug = False
verbose = False verbose = False
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -1,5 +1,6 @@
[DEFAULT] [DEFAULT]
pooling = True pooling = True
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -2,6 +2,7 @@
debug = False debug = False
verbose = False verbose = False
admin_mode = False admin_mode = False
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -1,6 +1,7 @@
[DEFAULT] [DEFAULT]
pooling = True pooling = True
admin_mode = True admin_mode = True
enable_deprecated_api_versions = 1
[drivers] [drivers]
transport = wsgi transport = wsgi

View File

@ -18,12 +18,17 @@ from oslo_cache import core
from oslo_config import cfg from oslo_config import cfg
from zaqar.common import cache as oslo_cache from zaqar.common import cache as oslo_cache
from zaqar.common import configs
from zaqar.common import decorators from zaqar.common import decorators
from zaqar.tests import base from zaqar.tests import base
class TestDecorators(base.TestBase): class TestDecorators(base.TestBase):
def setUp(self):
super(TestDecorators, self).setUp()
self.conf.register_opts(configs._GENERAL_OPTIONS)
def test_memoized_getattr(self): def test_memoized_getattr(self):
class TestClass(object): class TestClass(object):
@ -141,3 +146,40 @@ class TestDecorators(base.TestBase):
self.assertEqual(name, user) self.assertEqual(name, user)
self.assertEqual(2 + i, instance.user_gets) 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))

View File

@ -131,8 +131,9 @@ class Driver(transport.DriverBase):
self.app.add_error_handler(Exception, self._error_handler) self.app.add_error_handler(Exception, self._error_handler)
for version_path, endpoints in catalog: for version_path, endpoints in catalog:
for route, resource in endpoints: if endpoints:
self.app.add_route(version_path + route, resource) for route, resource in endpoints:
self.app.add_route(version_path + route, resource)
def _init_middleware(self): def _init_middleware(self):
"""Initialize WSGI middlewarez.""" """Initialize WSGI middlewarez."""

View File

@ -14,6 +14,7 @@
from oslo_log import log as logging 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 claims
from zaqar.transport.wsgi.v1_0 import health from zaqar.transport.wsgi.v1_0 import health
from zaqar.transport.wsgi.v1_0 import homedoc from zaqar.transport.wsgi.v1_0 import homedoc
@ -46,10 +47,8 @@ VERSION = {
} }
@decorators.api_version_manager(VERSION)
def public_endpoints(driver, conf): 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 queue_controller = driver._storage.queue_controller
message_controller = driver._storage.message_controller message_controller = driver._storage.message_controller
claim_controller = driver._storage.claim_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): def private_endpoints(driver, conf):
if not conf.pooling: if not conf.pooling:
return [] return []

View File

@ -14,6 +14,7 @@
from oslo_log import log as logging 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 claims
from zaqar.transport.wsgi.v1_1 import flavors from zaqar.transport.wsgi.v1_1 import flavors
from zaqar.transport.wsgi.v1_1 import health from zaqar.transport.wsgi.v1_1 import health
@ -47,6 +48,7 @@ VERSION = {
} }
@decorators.api_version_manager(VERSION)
def public_endpoints(driver, conf): def public_endpoints(driver, conf):
LOG.warning('Zaqar\'s API version 1.1 will enter deprecation during the ' LOG.warning('Zaqar\'s API version 1.1 will enter deprecation during the '
'Newton cycle. As part of that, it will be marked as ' '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): def private_endpoints(driver, conf):
catalogue = [ catalogue = [

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations under # License for the specific language governing permissions and limitations under
# the License. # the License.
from zaqar.common import decorators
from zaqar.transport.wsgi.v2_0 import claims from zaqar.transport.wsgi.v2_0 import claims
from zaqar.transport.wsgi.v2_0 import flavors from zaqar.transport.wsgi.v2_0 import flavors
from zaqar.transport.wsgi.v2_0 import health from zaqar.transport.wsgi.v2_0 import health
@ -44,6 +45,7 @@ VERSION = {
} }
@decorators.api_version_manager(VERSION)
def public_endpoints(driver, conf): def public_endpoints(driver, conf):
queue_controller = driver._storage.queue_controller queue_controller = driver._storage.queue_controller
message_controller = driver._storage.message_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): def private_endpoints(driver, conf):
catalogue = [ catalogue = [