Add Microversion support to Horizon
This patch adds microversion support to Horizon, as well as documentation, service references, tests and an example. Implements: blueprint microversion-support Change-Id: Ic5aa559dbc13aa84d8e4a14b68f26f5d84183fa9
This commit is contained in:
parent
39eea5ce22
commit
24e52a8765
@ -92,6 +92,7 @@ the following topic guides.
|
||||
topics/workflows
|
||||
topics/tables
|
||||
topics/policy
|
||||
topics/microversion_support
|
||||
topics/angularjs
|
||||
topics/testing
|
||||
topics/javascript_testing
|
||||
|
47
doc/source/topics/microversion_support.rst
Normal file
47
doc/source/topics/microversion_support.rst
Normal file
@ -0,0 +1,47 @@
|
||||
============================
|
||||
Horizon Microversion Support
|
||||
============================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Several services use API microversions, which allows consumers of that API to
|
||||
specify an exact version when making a request. This can be useful in ensuring
|
||||
a feature continues to work as expected across many service releases.
|
||||
|
||||
Adding a feature that was introduced in a microversion
|
||||
======================================================
|
||||
|
||||
1. Add the feature to the ``MICROVERSION_FEATURES`` dict in
|
||||
``openstack_dashboard/api/microversions.py`` under the appropriate
|
||||
service name. The feature should have at least two versions listed; the
|
||||
minimum version (i.e. the version that introduced the feature) and
|
||||
the current working version. Providing multiple versions reduces project
|
||||
maintenance overheads and helps Horizon work with older service
|
||||
deployments.
|
||||
|
||||
2. Use the ``is_feature_available`` function for your service to show or hide
|
||||
the function.::
|
||||
|
||||
from openstack_dashboard.api import service
|
||||
|
||||
...
|
||||
|
||||
def allowed(self, request):
|
||||
return service.is_feature_available('feature')
|
||||
|
||||
3. Send the correct microversion with ``get_microversion`` function in the API
|
||||
layer.::
|
||||
|
||||
def resource_list(request):
|
||||
try:
|
||||
microversion = get_microversion(request, 'feature')
|
||||
client = serviceclient(request, microversion)
|
||||
return client.resource_list()
|
||||
|
||||
Microversion references
|
||||
=======================
|
||||
|
||||
:Nova: http://docs.openstack.org/developer/nova/api_microversion_history.html
|
||||
:Cinder: http://docs.openstack.org/developer/cinder/devref/api_microversion_history.html
|
||||
:API-WG: http://specs.openstack.org/openstack/api-wg/guidelines/microversion_specification.html
|
56
openstack_dashboard/api/microversions.py
Normal file
56
openstack_dashboard/api/microversions.py
Normal file
@ -0,0 +1,56 @@
|
||||
# Copyright 2017 Cisco Systems
|
||||
#
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
# A list of features and their supported microversions. Note that these are
|
||||
# explicit functioning versions, not a range.
|
||||
# There should be a minimum of two versions per feature. The first entry in
|
||||
# this list should always be the lowest possible API microversion for a
|
||||
# feature i.e. the version at which that feature was introduced. The second
|
||||
# entry should be the current service version when the feature was added to
|
||||
# horizon.
|
||||
# Further documentation can be found at
|
||||
# http://docs.openstack.org/developer/horizon/topics/microversion_support.html
|
||||
MICROVERSION_FEATURES = {
|
||||
"nova": {
|
||||
"locked_attribute": ["2.9", "2.42"]
|
||||
},
|
||||
"cinder": {
|
||||
"consistency_groups": ["2.0", "3.10"],
|
||||
"message_list": ["3.5", "3.29"]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# NOTE(robcresswell): Since each client implements their own wrapper class for
|
||||
# API objects, we'll need to allow that to be passed in. In the future this
|
||||
# should be replaced by some common handling in Oslo.
|
||||
def get_microversion_for_feature(service, feature, wrapper_class,
|
||||
min_ver, max_ver):
|
||||
"""Retrieves that highest known functional microversion for a feature"""
|
||||
try:
|
||||
service_features = MICROVERSION_FEATURES[service]
|
||||
except KeyError:
|
||||
LOG.debug("'%s' could not be found in the MICROVERSION_FEATURES "
|
||||
"dict" % service)
|
||||
return None
|
||||
feature_versions = service_features[feature]
|
||||
for version in reversed(feature_versions):
|
||||
microversion = wrapper_class(version)
|
||||
if microversion.matches(min_ver, max_ver):
|
||||
return microversion
|
||||
return None
|
@ -43,6 +43,7 @@ from horizon.utils.memoized import memoized
|
||||
from horizon.utils.memoized import memoized_with_request
|
||||
|
||||
from openstack_dashboard.api import base
|
||||
from openstack_dashboard.api import microversions
|
||||
from openstack_dashboard.api import network_base
|
||||
from openstack_dashboard.contrib.developer.profiler import api as profiler
|
||||
|
||||
@ -52,7 +53,6 @@ LOG = logging.getLogger(__name__)
|
||||
VERSIONS = base.APIVersionManager("compute", preferred_version=2)
|
||||
VERSIONS.load_supported_version(1.1, {"client": nova_client, "version": 1.1})
|
||||
VERSIONS.load_supported_version(2, {"client": nova_client, "version": 2})
|
||||
VERSIONS.load_supported_version(2.9, {"client": nova_client, "version": 2.9})
|
||||
|
||||
# API static values
|
||||
INSTANCE_ACTIVE_STATE = 'ACTIVE'
|
||||
@ -62,6 +62,17 @@ INSECURE = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
|
||||
CACERT = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
|
||||
|
||||
|
||||
def get_microversion(request, feature):
|
||||
client = novaclient(request)
|
||||
min_ver, max_ver = api_versions._get_server_version_range(client)
|
||||
return (microversions.get_microversion_for_feature(
|
||||
'nova', feature, api_versions.APIVersion, min_ver, max_ver))
|
||||
|
||||
|
||||
def is_feature_available(request, feature):
|
||||
return bool(get_microversion(request, feature))
|
||||
|
||||
|
||||
class VNCConsole(base.APIDictWrapper):
|
||||
"""Wrapper for the "console" dictionary.
|
||||
|
||||
@ -849,12 +860,14 @@ def server_stop(request, instance_id):
|
||||
|
||||
@profiler.trace
|
||||
def server_lock(request, instance_id):
|
||||
novaclient(request).servers.lock(instance_id)
|
||||
microversion = get_microversion(request, "locked_attribute")
|
||||
novaclient(request, version=microversion).servers.lock(instance_id)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
def server_unlock(request, instance_id):
|
||||
novaclient(request).servers.unlock(instance_id)
|
||||
microversion = get_microversion(request, "locked_attribute")
|
||||
novaclient(request, version=microversion).servers.unlock(instance_id)
|
||||
|
||||
|
||||
@profiler.trace
|
||||
|
@ -884,11 +884,12 @@ class LockInstance(policy.PolicyTargetMixin, tables.BatchAction):
|
||||
|
||||
# to only allow unlocked instances to be locked
|
||||
def allowed(self, request, instance):
|
||||
# if not locked, lock should be available
|
||||
if getattr(instance, 'locked', False):
|
||||
return False
|
||||
if not api.nova.extension_supported('AdminActions', request):
|
||||
return False
|
||||
if not api.nova.is_feature_available(request, "locked_attribute"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def action(self, request, obj_id):
|
||||
@ -921,6 +922,8 @@ class UnlockInstance(policy.PolicyTargetMixin, tables.BatchAction):
|
||||
return False
|
||||
if not api.nova.extension_supported('AdminActions', request):
|
||||
return False
|
||||
if not api.nova.is_feature_available(request, "locked_attribute"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def action(self, request, obj_id):
|
||||
|
@ -120,6 +120,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'server_list',
|
||||
'tenant_absolute_limits',
|
||||
'extension_supported',
|
||||
'is_feature_available',
|
||||
),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: (
|
||||
@ -130,9 +131,11 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
})
|
||||
def _get_index(self):
|
||||
servers = self.servers.list()
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -191,7 +194,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
@helpers.create_stubs({
|
||||
api.nova: ('flavor_list', 'server_list', 'flavor_get',
|
||||
'tenant_absolute_limits', 'extension_supported',),
|
||||
'tenant_absolute_limits', 'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',
|
||||
@ -202,9 +206,11 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
flavors = self.flavors.list()
|
||||
full_flavors = OrderedDict([(f.id, f) for f in flavors])
|
||||
search_opts = {'marker': None, 'paginate': True}
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \
|
||||
@ -235,7 +241,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
@helpers.create_stubs({
|
||||
api.nova: ('flavor_list', 'server_list', 'tenant_absolute_limits',
|
||||
'extension_supported',),
|
||||
'extension_supported', 'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',
|
||||
@ -248,9 +254,11 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
servers = self.servers.list()
|
||||
servers[0] = volume_server
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -380,15 +388,15 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_pause',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_pause_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -410,15 +418,15 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_pause',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_pause_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -441,15 +449,15 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_unpause',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_unpause_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
server.status = "PAUSED"
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -471,7 +479,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_unpause',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_unpause_instance_exception(self):
|
||||
@ -479,8 +488,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
server = servers[0]
|
||||
server.status = "PAUSED"
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -584,15 +592,15 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_suspend',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_suspend_instance(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -615,15 +623,15 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_suspend',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_suspend_instance_exception(self):
|
||||
servers = self.servers.list()
|
||||
server = servers[0]
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -633,8 +641,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \
|
||||
.AndReturn([servers, False])
|
||||
api.network.servers_update_addresses(IsA(http.HttpRequest), servers)
|
||||
api.nova.server_suspend(IsA(http.HttpRequest), six.text_type(server.id)) \
|
||||
.AndRaise(self.exceptions.nova)
|
||||
api.nova.server_suspend(
|
||||
IsA(http.HttpRequest), six.text_type(server.id)
|
||||
).AndRaise(self.exceptions.nova)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
@ -646,7 +655,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_resume',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_resume_instance(self):
|
||||
@ -654,8 +664,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
server = servers[0]
|
||||
server.status = "SUSPENDED"
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -677,7 +686,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_resume',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available'),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_resume_instance_exception(self):
|
||||
@ -685,8 +695,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
server = servers[0]
|
||||
server.status = "SUSPENDED"
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
@ -710,7 +719,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_shelve',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_shelve_instance(self):
|
||||
@ -739,7 +749,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_shelve',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_shelve_instance_exception(self):
|
||||
@ -770,7 +781,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_unshelve',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_unshelve_instance(self):
|
||||
@ -801,7 +813,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_unshelve',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_unshelve_instance_exception(self):
|
||||
@ -833,7 +846,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_lock',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_lock_instance(self):
|
||||
@ -842,6 +856,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
api.nova.extension_supported('AdminActions', IsA(
|
||||
http.HttpRequest)).MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.glance.image_list_detailed(IgnoreArg()).AndReturn((
|
||||
self.images.list(), False, False))
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -863,7 +880,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_lock',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_lock_instance_exception(self):
|
||||
@ -872,6 +890,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
api.nova.extension_supported('AdminActions', IsA(
|
||||
http.HttpRequest)).MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.glance.image_list_detailed(IgnoreArg()).AndReturn((
|
||||
self.images.list(), False, False))
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -894,7 +915,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_unlock',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available'),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_unlock_instance(self):
|
||||
@ -902,6 +924,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
server = servers[0]
|
||||
api.nova.extension_supported('AdminActions', IsA(
|
||||
http.HttpRequest)).MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
.AndReturn(self.flavors.list())
|
||||
api.glance.image_list_detailed(IgnoreArg()).AndReturn((
|
||||
@ -923,7 +948,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_unlock',
|
||||
'server_list',
|
||||
'flavor_list',
|
||||
'extension_supported',),
|
||||
'extension_supported',
|
||||
'is_feature_available'),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
def test_unlock_instance_exception(self):
|
||||
@ -932,6 +958,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
api.nova.extension_supported('AdminActions', IsA(
|
||||
http.HttpRequest)).MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(IsA(
|
||||
http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.glance.image_list_detailed(IgnoreArg()).AndReturn((
|
||||
self.images.list(), False, False))
|
||||
search_opts = {'marker': None, 'paginate': True}
|
||||
@ -956,7 +985,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
"server_get",
|
||||
"instance_volumes_list",
|
||||
"flavor_get",
|
||||
"extension_supported"
|
||||
"extension_supported",
|
||||
'is_feature_available',
|
||||
),
|
||||
api.network: (
|
||||
"server_security_groups",
|
||||
@ -1002,6 +1032,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
|
||||
@ -1365,7 +1398,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
@helpers.create_stubs({
|
||||
api.nova: ('flavor_list', 'server_list', 'tenant_absolute_limits',
|
||||
'extension_supported',),
|
||||
'extension_supported', 'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',
|
||||
@ -1373,9 +1406,11 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
})
|
||||
def _test_instances_index_retrieve_password_action(self):
|
||||
servers = self.servers.list()
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -1556,6 +1591,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@helpers.create_stubs({api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'server_group_list',
|
||||
@ -1791,6 +1827,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
self.test_launch_instance_get(only_one_network=True)
|
||||
|
||||
@helpers.create_stubs({api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'server_group_list',
|
||||
@ -1890,6 +1927,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'port_create',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
@ -2001,6 +2039,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'port_create',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
@ -2123,6 +2162,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'port_list'),
|
||||
api.nova: ('server_create',
|
||||
'extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
@ -2222,6 +2262,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list'),
|
||||
@ -2298,6 +2339,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'port_create',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
@ -2423,6 +2465,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'port_create',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
@ -2494,6 +2537,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'volume_snapshot_list',),
|
||||
api.network: ('security_group_list',),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',),
|
||||
@ -2549,6 +2593,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'port_delete',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
@ -2656,6 +2701,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',),
|
||||
@ -2734,6 +2780,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'server_group_list',
|
||||
@ -2839,6 +2886,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',),
|
||||
@ -2936,6 +2984,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',),
|
||||
@ -3079,6 +3128,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'server_group_list',
|
||||
@ -3192,7 +3242,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
@helpers.create_stubs({
|
||||
api.nova: ('flavor_list', 'server_list', 'tenant_absolute_limits',
|
||||
'extension_supported',),
|
||||
'extension_supported', 'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',
|
||||
@ -3203,9 +3253,11 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
limits = self.limits['absolute']
|
||||
limits['totalInstancesUsed'] = 0
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -3239,7 +3291,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
@helpers.create_stubs({
|
||||
api.nova: ('flavor_list', 'server_list', 'tenant_absolute_limits',
|
||||
'extension_supported',),
|
||||
'extension_supported', 'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',
|
||||
@ -3250,9 +3302,11 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
limits = self.limits['absolute']
|
||||
limits['totalInstancesUsed'] = limits['maxTotalInstances']
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -3287,6 +3341,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
api.neutron: ('network_list',
|
||||
'port_list'),
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list',
|
||||
@ -3388,7 +3443,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
@helpers.create_stubs({
|
||||
api.nova: ('flavor_list', 'server_list', 'tenant_absolute_limits',
|
||||
'extension_supported',),
|
||||
'extension_supported', 'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',
|
||||
@ -3398,9 +3453,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
servers = self.servers.list()
|
||||
server = self.servers.first()
|
||||
server.status = "VERIFY_RESIZE"
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported(
|
||||
'AdminActions', IsA(http.HttpRequest)
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -3425,6 +3483,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
self.assertContains(res, "instances__revert")
|
||||
|
||||
@helpers.create_stubs({api.nova: ('extension_supported',
|
||||
'is_feature_available',
|
||||
'flavor_list',
|
||||
'keypair_list',
|
||||
'availability_zone_list'),
|
||||
@ -3550,6 +3609,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ('server_get',
|
||||
'flavor_list',
|
||||
'tenant_absolute_limits',
|
||||
'is_feature_available',
|
||||
'extension_supported')})
|
||||
def test_instance_resize_get(self):
|
||||
server = self.servers.first()
|
||||
@ -3622,6 +3682,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
'flavor_list',
|
||||
'flavor_get',
|
||||
'tenant_absolute_limits',
|
||||
'is_feature_available',
|
||||
'extension_supported')})
|
||||
def test_instance_resize_get_current_flavor_not_found(self):
|
||||
server = self.servers.first()
|
||||
@ -3659,6 +3720,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
instance_resize_post_stubs = {
|
||||
api.nova: ('server_get', 'server_resize',
|
||||
'flavor_list', 'flavor_get',
|
||||
'is_feature_available',
|
||||
'extension_supported')}
|
||||
|
||||
@helpers.create_stubs(instance_resize_post_stubs)
|
||||
@ -3712,7 +3774,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
@helpers.create_stubs({api.glance: ('image_list_detailed',),
|
||||
api.nova: ('extension_supported',)})
|
||||
api.nova: ('extension_supported',
|
||||
'is_feature_available',)})
|
||||
def test_rebuild_instance_get(self, expect_password_fields=True):
|
||||
server = self.servers.first()
|
||||
self._mock_glance_image_list_detailed(self.images.list())
|
||||
@ -3754,7 +3817,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
|
||||
instance_rebuild_post_stubs = {
|
||||
api.nova: ('server_rebuild',
|
||||
'extension_supported'),
|
||||
'extension_supported',
|
||||
'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',)}
|
||||
|
||||
@helpers.create_stubs(instance_rebuild_post_stubs)
|
||||
@ -3879,7 +3943,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
@django.test.utils.override_settings(API_RESULT_PAGE_SIZE=2)
|
||||
@helpers.create_stubs({
|
||||
api.nova: ('flavor_list', 'server_list', 'tenant_absolute_limits',
|
||||
'extension_supported',),
|
||||
'extension_supported', 'is_feature_available',),
|
||||
api.glance: ('image_list_detailed',),
|
||||
api.network: ('floating_ip_simple_associate_supported',
|
||||
'floating_ip_supported',
|
||||
@ -3892,9 +3956,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
|
||||
servers = self.servers.list()[:3]
|
||||
|
||||
api.nova.extension_supported('AdminActions',
|
||||
IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported(
|
||||
'AdminActions', IsA(http.HttpRequest)
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.flavor_list(IsA(http.HttpRequest)) \
|
||||
@ -4032,7 +4099,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
|
||||
class InstanceAjaxTests(helpers.TestCase):
|
||||
@helpers.create_stubs({api.nova: ("server_get",
|
||||
"flavor_get",
|
||||
"extension_supported"),
|
||||
"extension_supported",
|
||||
"is_feature_available"),
|
||||
api.network: ('servers_update_addresses',),
|
||||
api.neutron: ("is_extension_supported",)})
|
||||
def test_row_update(self):
|
||||
@ -4042,8 +4110,11 @@ class InstanceAjaxTests(helpers.TestCase):
|
||||
flavors = self.flavors.list()
|
||||
full_flavors = OrderedDict([(f.id, f) for f in flavors])
|
||||
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest))\
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
@ -4066,6 +4137,7 @@ class InstanceAjaxTests(helpers.TestCase):
|
||||
|
||||
@helpers.create_stubs({api.nova: ("server_get",
|
||||
"flavor_get",
|
||||
'is_feature_available',
|
||||
"extension_supported"),
|
||||
api.neutron: ("is_extension_supported",),
|
||||
api.network: ('servers_update_addresses',)})
|
||||
@ -4089,6 +4161,9 @@ class InstanceAjaxTests(helpers.TestCase):
|
||||
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest))\
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
@ -4121,6 +4196,7 @@ class InstanceAjaxTests(helpers.TestCase):
|
||||
|
||||
@helpers.create_stubs({api.nova: ("server_get",
|
||||
"flavor_get",
|
||||
'is_feature_available',
|
||||
"extension_supported"),
|
||||
api.neutron: ("is_extension_supported",
|
||||
"servers_update_addresses",)})
|
||||
@ -4128,8 +4204,12 @@ class InstanceAjaxTests(helpers.TestCase):
|
||||
server = self.servers.first()
|
||||
instance_id = server.id
|
||||
|
||||
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest))\
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported(
|
||||
'AdminActions', IsA(http.HttpRequest)
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.is_feature_available(
|
||||
IsA(http.HttpRequest), 'locked_attribute'
|
||||
).MultipleTimes().AndReturn(True)
|
||||
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
|
||||
.MultipleTimes().AndReturn(True)
|
||||
api.neutron.is_extension_supported(IsA(http.HttpRequest),
|
||||
|
Loading…
Reference in New Issue
Block a user