Remove dependency on novaclient list_extensions API
The novaclient list_extensions API binding was removed in the 16.0.0 release [1]. The ability to enable/disable extensions in nova has been deprecated since Liberty [2] and was removed in Newton [3]. For horizon this only matters for the OPENSTACK_NOVA_EXTENSIONS_BLACKLIST config setting and some javascript code used to compile panels based on enabled extensions. In order to work with novaclient 16.0.0+, this change removes the list_extensions usage since all extensions are enabled in nova and thus for horizon a nova extension is only not supported if it's in the configured blacklist. To continue supporting the javascript code which uses the getExtensions function, the extension names are hard-coded. Note that the method meant to test that code, _test_extension_list, was wrong but never ran because of the underscore prefix on the method name. That is fixed here. [1] https://review.opendev.org/686516/ [2] https://review.opendev.org/214592/ [3] https://review.opendev.org/351362/ Change-Id: Iebb1e78c718b931d632445e4de6d7a29ccb92be2 Closes-Bug: #1847959
This commit is contained in:
parent
85a1dddf12
commit
b148c92075
@ -30,7 +30,6 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from novaclient import api_versions
|
||||
from novaclient import exceptions as nova_exceptions
|
||||
from novaclient.v2 import instance_action as nova_instance_action
|
||||
from novaclient.v2 import list_extensions as nova_list_extensions
|
||||
from novaclient.v2 import servers as nova_servers
|
||||
|
||||
from horizon import exceptions as horizon_exceptions
|
||||
@ -49,6 +48,113 @@ INSTANCE_ACTIVE_STATE = 'ACTIVE'
|
||||
VOLUME_STATE_AVAILABLE = "available"
|
||||
DEFAULT_QUOTA_NAME = 'default'
|
||||
|
||||
# python-novaclient 16.0.0 removed the list_extensions module and the
|
||||
# GET /extensions API is deprecated since Newton. Furthermore, the ability
|
||||
# to enable/disable compute API extensions was also removed in Newton.
|
||||
# Therefore we hard-code the list of extensions here until the
|
||||
# OPENSTACK_NOVA_EXTENSIONS_BLACKLIST setting is no longer used.
|
||||
EXTENSIONS = (
|
||||
'AccessIPs',
|
||||
'AdminActions',
|
||||
'AdminPassword',
|
||||
'Agents',
|
||||
'Aggregates',
|
||||
'AssistedVolumeSnapshots',
|
||||
'AttachInterfaces',
|
||||
'AvailabilityZone',
|
||||
'BareMetalExtStatus',
|
||||
'BareMetalNodes',
|
||||
'BlockDeviceMapping',
|
||||
'BlockDeviceMappingV2Boot',
|
||||
'CellCapacities',
|
||||
'Cells',
|
||||
'Certificates',
|
||||
'Cloudpipe',
|
||||
'CloudpipeUpdate',
|
||||
'ConfigDrive',
|
||||
'ConsoleAuthTokens',
|
||||
'ConsoleOutput',
|
||||
'Consoles',
|
||||
'CreateBackup',
|
||||
'Createserverext',
|
||||
'DeferredDelete',
|
||||
'DiskConfig',
|
||||
'Evacuate',
|
||||
'ExtendedAvailabilityZone',
|
||||
'ExtendedEvacuateFindHost',
|
||||
'ExtendedFloatingIps',
|
||||
'ExtendedHypervisors',
|
||||
'ExtendedIps',
|
||||
'ExtendedIpsMac',
|
||||
'ExtendedNetworks',
|
||||
'ExtendedQuotas',
|
||||
'ExtendedRescueWithImage',
|
||||
'ExtendedServerAttributes',
|
||||
'ExtendedServices',
|
||||
'ExtendedServicesDelete',
|
||||
'ExtendedStatus',
|
||||
'ExtendedStatus',
|
||||
'ExtendedVolumes',
|
||||
'FixedIPs',
|
||||
'FlavorAccess',
|
||||
'FlavorDisabled',
|
||||
'FlavorExtraData',
|
||||
'FlavorExtraSpecs',
|
||||
'FlavorManage',
|
||||
'FlavorRxtx',
|
||||
'FlavorSwap',
|
||||
'FloatingIpDns',
|
||||
'FloatingIpPools',
|
||||
'FloatingIps',
|
||||
'FloatingIpsBulk',
|
||||
'Fping',
|
||||
'HideServerAddresses',
|
||||
'Hosts',
|
||||
'HypervisorStatus',
|
||||
'Hypervisors',
|
||||
'ImageSize',
|
||||
'InstanceActions',
|
||||
'Keypairs',
|
||||
'LockServer',
|
||||
'MigrateServer',
|
||||
'Migrations',
|
||||
'Multinic',
|
||||
'MultipleCreate',
|
||||
'NetworkAssociationSupport',
|
||||
'Networks',
|
||||
'OSInstanceUsageAuditLog',
|
||||
'OSTenantNetworks',
|
||||
'PauseServer',
|
||||
'Personality',
|
||||
'PreserveEphemeralOnRebuild',
|
||||
'QuotaClasses',
|
||||
'Quotas',
|
||||
'Rescue',
|
||||
'SchedulerHints',
|
||||
'SecurityGroupDefaultRules',
|
||||
'SecurityGroups',
|
||||
'ServerDiagnostics',
|
||||
'ServerExternalEvents',
|
||||
'ServerGroupQuotas',
|
||||
'ServerGroups',
|
||||
'ServerListMultiStatus',
|
||||
'ServerPassword',
|
||||
'ServerSortKeys',
|
||||
'ServerStartStop',
|
||||
'ServerUsage',
|
||||
'Services',
|
||||
'Shelve',
|
||||
'SimpleTenantUsage',
|
||||
'SuspendServer',
|
||||
'UsedLimits',
|
||||
'UsedLimitsForAdmin',
|
||||
'UserData',
|
||||
'UserQuotas',
|
||||
'VirtualInterfaces',
|
||||
'VolumeAttachmentUpdate',
|
||||
'Volumes'
|
||||
)
|
||||
|
||||
|
||||
get_microversion = _nova.get_microversion
|
||||
server_get = _nova.server_get
|
||||
@ -1010,13 +1116,10 @@ def interface_detach(request, server, port_id):
|
||||
@profiler.trace
|
||||
@memoized.memoized
|
||||
def list_extensions(request):
|
||||
"""List all nova extensions, except the ones in the blacklist."""
|
||||
"""List all nova extension names, except the ones in the blacklist."""
|
||||
blacklist = set(settings.OPENSTACK_NOVA_EXTENSIONS_BLACKLIST)
|
||||
nova_api = _nova.novaclient(request)
|
||||
return tuple(
|
||||
extension for extension in
|
||||
nova_list_extensions.ListExtManager(nova_api).show_all()
|
||||
if extension.name not in blacklist
|
||||
extension for extension in EXTENSIONS if extension not in blacklist
|
||||
)
|
||||
|
||||
|
||||
@ -1028,10 +1131,7 @@ def extension_supported(extension_name, request):
|
||||
Example values for the extension_name include AdminActions, ConsoleOutput,
|
||||
etc.
|
||||
"""
|
||||
for ext in list_extensions(request):
|
||||
if ext.name == extension_name:
|
||||
return True
|
||||
return False
|
||||
return extension_name in list_extensions(request)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
|
@ -512,13 +512,13 @@ class Extensions(generic.View):
|
||||
"""Get a list of extensions.
|
||||
|
||||
The listing result is an object with property "items". Each item is
|
||||
an image.
|
||||
an object with property "name".
|
||||
|
||||
Example GET:
|
||||
http://localhost/api/nova/extensions
|
||||
"""
|
||||
result = api.nova.list_extensions(request)
|
||||
return {'items': [e.to_dict() for e in result]}
|
||||
return {'items': [{'name': e} for e in result]}
|
||||
|
||||
|
||||
@urls.register
|
||||
|
@ -548,12 +548,7 @@
|
||||
* {
|
||||
* "items": [
|
||||
* {
|
||||
* "alias": "NMN",
|
||||
* "description": "Multiple network support.",
|
||||
* "links": [],
|
||||
* "name": "Multinic",
|
||||
* "namespace": "http://docs.openstack.org/compute/ext/multinic/api/v1.1",
|
||||
* "updated": "2011-06-09T00:00:00Z"
|
||||
* "name": "Multinic"
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
|
@ -487,15 +487,9 @@ class NovaRestTestCase(test.TestCase):
|
||||
# Extensions
|
||||
#
|
||||
@test.create_mocks({api.nova: ['list_extensions']})
|
||||
@mock.patch.object(settings,
|
||||
'OPENSTACK_NOVA_EXTENSIONS_BLACKLIST', ['baz'])
|
||||
def _test_extension_list(self):
|
||||
def test_extension_list(self):
|
||||
request = self.mock_rest_request()
|
||||
self.mock_list_extensions.return_value = [
|
||||
mock.Mock(**{'to_dict.return_value': {'name': 'foo'}}),
|
||||
mock.Mock(**{'to_dict.return_value': {'name': 'bar'}}),
|
||||
mock.Mock(**{'to_dict.return_value': {'name': 'baz'}}),
|
||||
]
|
||||
self.mock_list_extensions.return_value = ['foo', 'bar']
|
||||
response = nova.Extensions().get(request)
|
||||
self.assertStatusCode(response, 200)
|
||||
self.assertEqual({"items": [{"name": "foo"}, {"name": "bar"}]},
|
||||
|
@ -72,6 +72,15 @@ class ComputeApiTests(test.APIMockTestCase):
|
||||
# To handle upgrade_api
|
||||
mock_novaclient.api_version = api_versions.APIVersion(version)
|
||||
|
||||
@override_settings(OPENSTACK_NOVA_EXTENSIONS_BLACKLIST=['ConsoleOutput'])
|
||||
def test_extension_supported(self):
|
||||
self.assertTrue(api.nova.extension_supported(
|
||||
'Evacuate', mock.sentinel.request))
|
||||
self.assertFalse(api.nova.extension_supported(
|
||||
'ConsoleOutput', mock.sentinel.request))
|
||||
self.assertFalse(api.nova.extension_supported(
|
||||
'DoesNotExist', mock.sentinel.request))
|
||||
|
||||
@mock.patch.object(api._nova, 'novaclient')
|
||||
def test_server_reboot(self, mock_novaclient):
|
||||
server = self.servers.first()
|
||||
|
Loading…
x
Reference in New Issue
Block a user