api: deprecate the concept of extensions in v2.1

We want to remove the extension infrastructure in the v2.1 API during
the next release. To make that possible, we must deprecate the
configuration now.

Also deprecating the osapi_v3 group, and moving to osapi_v21.

UpgradeImpact
DocImpact

Part of blueprint nova-api-deprecate-extensions

Change-Id: I084444b11dceda7cf8f88c157aa67d36490fce49
This commit is contained in:
John Garbutt 2015-08-19 13:46:52 +01:00 committed by John Garbutt
parent 19810750b4
commit 11507eeceb
17 changed files with 70 additions and 52 deletions

View File

@ -43,20 +43,26 @@ from nova import wsgi as base_wsgi
api_opts = [ api_opts = [
cfg.BoolOpt('enabled', cfg.BoolOpt('enabled',
default=True, default=True,
help='DEPRECATED: Whether the V3 API is enabled or not. ' help='DEPRECATED: Whether the V2.1 API is enabled or not. '
'This option will be removed in the 14.0.0 "N" release.', 'This option will be removed in the near future.',
deprecated_for_removal=True), deprecated_for_removal=True, deprecated_group='osapi_v21'),
cfg.ListOpt('extensions_blacklist', cfg.ListOpt('extensions_blacklist',
default=[], default=[],
help='A list of v3 API extensions to never load. ' help='DEPRECATED: A list of v2.1 API extensions to never '
'Specify the extension aliases here.'), 'load. Specify the extension aliases here. '
'This option will be removed in the near future. '
'After that point you have to run all of the API.',
deprecated_for_removal=True, deprecated_group='osapi_v21'),
cfg.ListOpt('extensions_whitelist', cfg.ListOpt('extensions_whitelist',
default=[], default=[],
help='If the list is not empty then a v3 API extension ' help='DEPRECATED: If the list is not empty then a v2.1 '
'will only be loaded if it exists in this list. Specify ' 'API extension will only be loaded if it exists in this '
'the extension aliases here.') 'list. Specify the extension aliases here. '
'This option will be removed in the near future. '
'After that point you have to run all of the API.',
deprecated_for_removal=True, deprecated_group='osapi_v21')
] ]
api_opts_group = cfg.OptGroup(name='osapi_v3', title='API v3 Options') api_opts_group = cfg.OptGroup(name='osapi_v21', title='API v2.1 Options')
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
CONF = cfg.CONF CONF = cfg.CONF
@ -323,27 +329,36 @@ class APIRouterV21(base_wsgi.Router):
# Check whitelist is either empty or if not then the extension # Check whitelist is either empty or if not then the extension
# is in the whitelist # is in the whitelist
if (not CONF.osapi_v3.extensions_whitelist or if (not CONF.osapi_v21.extensions_whitelist or
ext.obj.alias in CONF.osapi_v3.extensions_whitelist): ext.obj.alias in CONF.osapi_v21.extensions_whitelist):
# Check the extension is not in the blacklist # Check the extension is not in the blacklist
if ext.obj.alias not in CONF.osapi_v3.extensions_blacklist: blacklist = CONF.osapi_v21.extensions_blacklist
if ext.obj.alias not in blacklist:
return self._register_extension(ext) return self._register_extension(ext)
return False return False
if not CONF.osapi_v3.enabled: if not CONF.osapi_v21.enabled:
LOG.info(_LI("V3 API has been disabled by configuration")) LOG.info(_LI("V3 API has been disabled by configuration"))
LOG.warning(_LW("In the M release you must run the v2.1 API."))
return return
if (CONF.osapi_v21.extensions_blacklist or
CONF.osapi_v21.extensions_whitelist):
LOG.warning(
_LW('In the M release you must run all of the API. '
'The concept of API extensions will be removed from '
'the codebase to ensure there is a single Compute API.'))
self.init_only = init_only self.init_only = init_only
LOG.debug("v3 API Extension Blacklist: %s", LOG.debug("v3 API Extension Blacklist: %s",
CONF.osapi_v3.extensions_blacklist) CONF.osapi_v21.extensions_blacklist)
LOG.debug("v3 API Extension Whitelist: %s", LOG.debug("v3 API Extension Whitelist: %s",
CONF.osapi_v3.extensions_whitelist) CONF.osapi_v21.extensions_whitelist)
in_blacklist_and_whitelist = set( in_blacklist_and_whitelist = set(
CONF.osapi_v3.extensions_whitelist).intersection( CONF.osapi_v21.extensions_whitelist).intersection(
CONF.osapi_v3.extensions_blacklist) CONF.osapi_v21.extensions_blacklist)
if len(in_blacklist_and_whitelist) != 0: if len(in_blacklist_and_whitelist) != 0:
LOG.warning(_LW("Extensions in both blacklist and whitelist: %s"), LOG.warning(_LW("Extensions in both blacklist and whitelist: %s"),
list(in_blacklist_and_whitelist)) list(in_blacklist_and_whitelist))

View File

@ -51,8 +51,10 @@ CONF.import_opt('enable_instance_password',
'nova.api.openstack.compute.legacy_v2.servers') 'nova.api.openstack.compute.legacy_v2.servers')
CONF.import_opt('network_api_class', 'nova.network') CONF.import_opt('network_api_class', 'nova.network')
CONF.import_opt('reclaim_instance_interval', 'nova.compute.manager') CONF.import_opt('reclaim_instance_interval', 'nova.compute.manager')
CONF.import_opt('extensions_blacklist', 'nova.api.openstack', group='osapi_v3') CONF.import_opt('extensions_blacklist', 'nova.api.openstack',
CONF.import_opt('extensions_whitelist', 'nova.api.openstack', group='osapi_v3') group='osapi_v21')
CONF.import_opt('extensions_whitelist', 'nova.api.openstack',
group='osapi_v21')
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
authorize = extensions.os_compute_authorizer(ALIAS) authorize = extensions.os_compute_authorizer(ALIAS)
@ -100,11 +102,12 @@ class ServersController(wsgi.Controller):
def check_whiteblack_lists(ext): def check_whiteblack_lists(ext):
# Check whitelist is either empty or if not then the extension # Check whitelist is either empty or if not then the extension
# is in the whitelist # is in the whitelist
if (not CONF.osapi_v3.extensions_whitelist or if (not CONF.osapi_v21.extensions_whitelist or
ext.obj.alias in CONF.osapi_v3.extensions_whitelist): ext.obj.alias in CONF.osapi_v21.extensions_whitelist):
# Check the extension is not in the blacklist # Check the extension is not in the blacklist
if ext.obj.alias not in CONF.osapi_v3.extensions_blacklist: extensions_blacklist = CONF.osapi_v21.extensions_blacklist
if ext.obj.alias not in extensions_blacklist:
return True return True
else: else:
LOG.warning(_LW("Not loading %s because it is " LOG.warning(_LW("Not loading %s because it is "

View File

@ -21,7 +21,7 @@ from nova.api.openstack import wsgi
CONF = cfg.CONF CONF = cfg.CONF
CONF.import_opt('enabled', 'nova.api.openstack', group='osapi_v3') CONF.import_opt('enabled', 'nova.api.openstack', group='osapi_v21')
LINKS = { LINKS = {
'v2.0': { 'v2.0': {
@ -80,7 +80,7 @@ VERSIONS = {
class Versions(wsgi.Resource): class Versions(wsgi.Resource):
def __init__(self): def __init__(self):
super(Versions, self).__init__(None) super(Versions, self).__init__(None)
if not CONF.osapi_v3.enabled: if not CONF.osapi_v21.enabled:
del VERSIONS["v2.1"] del VERSIONS["v2.1"]
def index(self, req, body=None): def index(self, req, body=None):

View File

@ -143,5 +143,5 @@ def list_opts():
nova.api.openstack.compute.legacy_v2.servers.server_opts, nova.api.openstack.compute.legacy_v2.servers.server_opts,
)), )),
('neutron', nova.api.metadata.handler.metadata_proxy_opts), ('neutron', nova.api.metadata.handler.metadata_proxy_opts),
('osapi_v3', nova.api.openstack.api_opts), ('osapi_v21', nova.api.openstack.api_opts),
] ]

View File

@ -55,7 +55,7 @@ from nova import utils
CONF = cfg.CONF CONF = cfg.CONF
CONF.import_opt('enabled', 'nova.api.openstack', group='osapi_v3') CONF.import_opt('enabled', 'nova.api.openstack', group='osapi_v21')
logging.register_options(CONF) logging.register_options(CONF)
CONF.set_override('use_stderr', False) CONF.set_override('use_stderr', False)

View File

@ -54,7 +54,7 @@ class ApiSampleTestBaseV3(testscenarios.WithScenarios,
whitelist.update(set(self.extra_extensions_to_load)) whitelist.update(set(self.extra_extensions_to_load))
CONF.set_override('extensions_whitelist', whitelist, CONF.set_override('extensions_whitelist', whitelist,
'osapi_v3') 'osapi_v21')
expected_middleware = [] expected_middleware = []
if (not hasattr(self, '_test') or (self._test == 'v2.1')): if (not hasattr(self, '_test') or (self._test == 'v2.1')):
# NOTE(gmann)For v2.1 API testing, override /v2 endpoint with v2.1 # NOTE(gmann)For v2.1 API testing, override /v2 endpoint with v2.1

View File

@ -241,7 +241,7 @@ class ServersControllerCreateTestV21(test.TestCase):
extension_info=ext_info) extension_info=ext_info)
CONF.set_override('extensions_blacklist', CONF.set_override('extensions_blacklist',
'os-availability-zone', 'os-availability-zone',
'osapi_v3') 'osapi_v21')
self.no_availability_zone_controller = servers_v21.ServersController( self.no_availability_zone_controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)

View File

@ -45,10 +45,10 @@ class BlockDeviceMappingTestV21(test.TestCase):
self.controller = servers_v21.ServersController( self.controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)
CONF.set_override('extensions_blacklist', 'os-block-device-mapping', CONF.set_override('extensions_blacklist', 'os-block-device-mapping',
'osapi_v3') 'osapi_v21')
self.no_bdm_v2_controller = servers_v21.ServersController( self.no_bdm_v2_controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)
CONF.set_override('extensions_blacklist', '', 'osapi_v3') CONF.set_override('extensions_blacklist', '', 'osapi_v21')
def setUp(self): def setUp(self):
super(BlockDeviceMappingTestV21, self).setUp() super(BlockDeviceMappingTestV21, self).setUp()

View File

@ -40,16 +40,16 @@ class BlockDeviceMappingTestV21(test.TestCase):
def _setup_controller(self): def _setup_controller(self):
ext_info = extension_info.LoadedExtensionInfo() ext_info = extension_info.LoadedExtensionInfo()
CONF.set_override('extensions_blacklist', 'os-block-device-mapping', CONF.set_override('extensions_blacklist', 'os-block-device-mapping',
'osapi_v3') 'osapi_v21')
self.controller = servers_v21.ServersController( self.controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)
CONF.set_override('extensions_blacklist', CONF.set_override('extensions_blacklist',
['os-block-device-mapping-v1', ['os-block-device-mapping-v1',
'os-block-device-mapping'], 'os-block-device-mapping'],
'osapi_v3') 'osapi_v21')
self.no_volumes_controller = servers_v21.ServersController( self.no_volumes_controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)
CONF.set_override('extensions_blacklist', '', 'osapi_v3') CONF.set_override('extensions_blacklist', '', 'osapi_v21')
def setUp(self): def setUp(self):
super(BlockDeviceMappingTestV21, self).setUp() super(BlockDeviceMappingTestV21, self).setUp()
@ -299,7 +299,7 @@ class BlockDeviceMappingTestV21(test.TestCase):
CONF.set_override('extensions_blacklist', CONF.set_override('extensions_blacklist',
['os-block-device-mapping', ['os-block-device-mapping',
'os-block-device-mapping-v1'], 'os-block-device-mapping-v1'],
'osapi_v3') 'osapi_v21')
controller = servers_v21.ServersController(extension_info=ext_info) controller = servers_v21.ServersController(extension_info=ext_info)
bdm = [{'device_name': 'foo1', bdm = [{'device_name': 'foo1',
'volume_id': fakes.FAKE_UUID, 'volume_id': fakes.FAKE_UUID,
@ -328,7 +328,7 @@ class BlockDeviceMappingTestV21(test.TestCase):
def test_create_instance_both_bdm_formats(self): def test_create_instance_both_bdm_formats(self):
ext_info = extension_info.LoadedExtensionInfo() ext_info = extension_info.LoadedExtensionInfo()
CONF.set_override('extensions_blacklist', '', 'osapi_v3') CONF.set_override('extensions_blacklist', '', 'osapi_v21')
both_controllers = servers_v21.ServersController( both_controllers = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)
bdm = [{'device_name': 'foo'}] bdm = [{'device_name': 'foo'}]

View File

@ -98,7 +98,7 @@ class ServersControllerCreateTestV21(test.TestCase):
extension_info=ext_info) extension_info=ext_info)
CONF.set_override('extensions_blacklist', CONF.set_override('extensions_blacklist',
'os-config-drive', 'os-config-drive',
'osapi_v3') 'osapi_v21')
self.no_config_drive_controller = servers_v21.ServersController( self.no_config_drive_controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)

View File

@ -73,7 +73,7 @@ class ExtensionLoadingTestCase(test.NoDBTestCase):
def test_extensions_blacklist(self): def test_extensions_blacklist(self):
app = compute.APIRouterV21() app = compute.APIRouterV21()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
CONF.set_override('extensions_blacklist', ['os-hosts'], 'osapi_v3') CONF.set_override('extensions_blacklist', ['os-hosts'], 'osapi_v21')
app = compute.APIRouterV21() app = compute.APIRouterV21()
self.assertNotIn('os-hosts', app._loaded_extension_info.extensions) self.assertNotIn('os-hosts', app._loaded_extension_info.extensions)
@ -102,7 +102,7 @@ class ExtensionLoadingTestCase(test.NoDBTestCase):
app = compute.APIRouterV21() app = compute.APIRouterV21()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
CONF.set_override('extensions_whitelist', ['servers', 'os-hosts'], CONF.set_override('extensions_whitelist', ['servers', 'os-hosts'],
'osapi_v3') 'osapi_v21')
app = compute.APIRouterV21() app = compute.APIRouterV21()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
@ -115,7 +115,7 @@ class ExtensionLoadingTestCase(test.NoDBTestCase):
app = compute.APIRouterV21() app = compute.APIRouterV21()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
CONF.set_override('extensions_whitelist', ['servers'], 'osapi_v3') CONF.set_override('extensions_whitelist', ['servers'], 'osapi_v21')
app = compute.APIRouterV21() app = compute.APIRouterV21()
self.assertNotIn('os-hosts', app._loaded_extension_info.extensions) self.assertNotIn('os-hosts', app._loaded_extension_info.extensions)
@ -129,8 +129,8 @@ class ExtensionLoadingTestCase(test.NoDBTestCase):
app = compute.APIRouterV21() app = compute.APIRouterV21()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
CONF.set_override('extensions_whitelist', ['servers', 'os-hosts'], CONF.set_override('extensions_whitelist', ['servers', 'os-hosts'],
'osapi_v3') 'osapi_v21')
CONF.set_override('extensions_blacklist', ['os-hosts'], 'osapi_v3') CONF.set_override('extensions_blacklist', ['os-hosts'], 'osapi_v21')
app = compute.APIRouterV21() app = compute.APIRouterV21()
self.assertNotIn('os-hosts', app._loaded_extension_info.extensions) self.assertNotIn('os-hosts', app._loaded_extension_info.extensions)
self.assertIn('servers', app._loaded_extension_info.extensions) self.assertIn('servers', app._loaded_extension_info.extensions)

View File

@ -65,7 +65,7 @@ class MultiCreateExtensionTestV21(test.TestCase):
self.controller = servers_v21.ServersController( self.controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)
CONF.set_override('extensions_blacklist', 'os-multiple-create', CONF.set_override('extensions_blacklist', 'os-multiple-create',
'osapi_v3') 'osapi_v21')
self.no_mult_create_controller = servers_v21.ServersController( self.no_mult_create_controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)

View File

@ -181,7 +181,7 @@ class ServersControllerCreateTestV21(test.TestCase):
def _set_up_controller(self): def _set_up_controller(self):
ext_info = extension_info.LoadedExtensionInfo() ext_info = extension_info.LoadedExtensionInfo()
CONF.set_override('extensions_blacklist', 'os-scheduler-hints', CONF.set_override('extensions_blacklist', 'os-scheduler-hints',
'osapi_v3') 'osapi_v21')
self.no_scheduler_hints_controller = servers_v21.ServersController( self.no_scheduler_hints_controller = servers_v21.ServersController(
extension_info=ext_info) extension_info=ext_info)

View File

@ -3546,7 +3546,7 @@ class TestServersExtensionPoint(test.NoDBTestCase):
def setUp(self): def setUp(self):
super(TestServersExtensionPoint, self).setUp() super(TestServersExtensionPoint, self).setUp()
CONF.set_override('extensions_whitelist', ['os-disk-config'], CONF.set_override('extensions_whitelist', ['os-disk-config'],
'osapi_v3') 'osapi_v21')
self.stubs.Set(disk_config, 'DiskConfig', FakeExt) self.stubs.Set(disk_config, 'DiskConfig', FakeExt)
def _test_load_extension_point(self, name): def _test_load_extension_point(self, name):
@ -3576,7 +3576,7 @@ class TestServersExtensionPoint(test.NoDBTestCase):
class TestServersExtensionSchema(test.NoDBTestCase): class TestServersExtensionSchema(test.NoDBTestCase):
def setUp(self): def setUp(self):
super(TestServersExtensionSchema, self).setUp() super(TestServersExtensionSchema, self).setUp()
CONF.set_override('extensions_whitelist', ['disk_config'], 'osapi_v3') CONF.set_override('extensions_whitelist', ['disk_config'], 'osapi_v21')
def _test_load_extension_schema(self, name): def _test_load_extension_schema(self, name):
setattr(FakeExt, 'get_server_%s_schema' % name, setattr(FakeExt, 'get_server_%s_schema' % name,

View File

@ -62,7 +62,7 @@ class ServersControllerCreateTest(test.TestCase):
ext_info = extension_info.LoadedExtensionInfo() ext_info = extension_info.LoadedExtensionInfo()
self.controller = servers.ServersController(extension_info=ext_info) self.controller = servers.ServersController(extension_info=ext_info)
CONF.set_override('extensions_blacklist', 'os-user-data', CONF.set_override('extensions_blacklist', 'os-user-data',
'osapi_v3') 'osapi_v21')
self.no_user_data_controller = servers.ServersController( self.no_user_data_controller = servers.ServersController(
extension_info=ext_info) extension_info=ext_info)

View File

@ -71,7 +71,7 @@ class ExtensionLoadingTestCase(test.NoDBTestCase):
def test_extensions_blacklist(self): def test_extensions_blacklist(self):
app = compute.APIRouterV3() app = compute.APIRouterV3()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
CONF.set_override('extensions_blacklist', ['os-hosts'], 'osapi_v3') CONF.set_override('extensions_blacklist', ['os-hosts'], 'osapi_v21')
app = compute.APIRouterV3() app = compute.APIRouterV3()
self.assertNotIn('os-hosts', app._loaded_extension_info.extensions) self.assertNotIn('os-hosts', app._loaded_extension_info.extensions)
@ -85,7 +85,7 @@ class ExtensionLoadingTestCase(test.NoDBTestCase):
app = compute.APIRouterV3() app = compute.APIRouterV3()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
CONF.set_override('extensions_whitelist', ['servers', 'os-hosts'], CONF.set_override('extensions_whitelist', ['servers', 'os-hosts'],
'osapi_v3') 'osapi_v21')
app = compute.APIRouterV3() app = compute.APIRouterV3()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
@ -98,7 +98,7 @@ class ExtensionLoadingTestCase(test.NoDBTestCase):
app = compute.APIRouterV3() app = compute.APIRouterV3()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
CONF.set_override('extensions_whitelist', ['servers'], 'osapi_v3') CONF.set_override('extensions_whitelist', ['servers'], 'osapi_v21')
app = compute.APIRouterV3() app = compute.APIRouterV3()
self.assertNotIn('os-hosts', app._loaded_extension_info.extensions) self.assertNotIn('os-hosts', app._loaded_extension_info.extensions)
@ -112,8 +112,8 @@ class ExtensionLoadingTestCase(test.NoDBTestCase):
app = compute.APIRouterV3() app = compute.APIRouterV3()
self.assertIn('os-hosts', app._loaded_extension_info.extensions) self.assertIn('os-hosts', app._loaded_extension_info.extensions)
CONF.set_override('extensions_whitelist', ['servers', 'os-hosts'], CONF.set_override('extensions_whitelist', ['servers', 'os-hosts'],
'osapi_v3') 'osapi_v21')
CONF.set_override('extensions_blacklist', ['os-hosts'], 'osapi_v3') CONF.set_override('extensions_blacklist', ['os-hosts'], 'osapi_v21')
app = compute.APIRouterV3() app = compute.APIRouterV3()
self.assertNotIn('os-hosts', app._loaded_extension_info.extensions) self.assertNotIn('os-hosts', app._loaded_extension_info.extensions)
self.assertIn('servers', app._loaded_extension_info.extensions) self.assertIn('servers', app._loaded_extension_info.extensions)

View File

@ -63,7 +63,7 @@ class ConfFixture(config_fixture.Config):
self.conf.set_default('sqlite_synchronous', False, self.conf.set_default('sqlite_synchronous', False,
group='api_database') group='api_database')
self.conf.set_default('fatal_exception_format_errors', True) self.conf.set_default('fatal_exception_format_errors', True)
self.conf.set_default('enabled', True, 'osapi_v3') self.conf.set_default('enabled', True, 'osapi_v21')
self.conf.set_default('force_dhcp_release', False) self.conf.set_default('force_dhcp_release', False)
self.conf.set_default('periodic_enable', False) self.conf.set_default('periodic_enable', False)
self.addCleanup(utils.cleanup_dns_managers) self.addCleanup(utils.cleanup_dns_managers)