api: Only check minimum API version

As noted in [1], we were passing arguments to the 'is_supported'
function inconsistently. Given we only have four easily converted users
of the 'max_version' argument, we can simplify the calls by only passing
a *minimum* API version and negating there where necessary. This is good
enough for our use cases.

[1] https://review.opendev.org/c/openstack/nova/+/936366/

Change-Id: I71a95b8b4b6b59485273f136f255811b6d57b657
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
This commit is contained in:
Stephen Finucane
2025-01-28 17:51:32 +00:00
parent d73a0861f8
commit a722640b2f
21 changed files with 121 additions and 183 deletions

View File

@@ -306,22 +306,18 @@ def max_api_version():
return APIVersionRequest(_MAX_API_VERSION) return APIVersionRequest(_MAX_API_VERSION)
def is_supported(req, min_version=_MIN_API_VERSION, def is_supported(req, version):
max_version=_MAX_API_VERSION):
"""Check if API request version satisfies version restrictions. """Check if API request version satisfies version restrictions.
:param req: request object :param req: request object
:param min_version: minimal version of API needed for correct :param version: minimal version of API needed for correct
request processing
:param max_version: maximum version of API needed for correct
request processing request processing
:returns: True if request satisfies minimal and maximum API version :returns: True if request satisfies minimal and maximum API version
requirements. False in other case. requirements. False in other case.
""" """
return (APIVersionRequest(max_version) >= req.api_version_request >= return req.api_version_request >= APIVersionRequest(version)
APIVersionRequest(min_version))
class APIVersionRequest(object): class APIVersionRequest(object):

View File

@@ -274,7 +274,7 @@ class AggregateController(wsgi.Controller):
return {"aggregate": _aggregate} return {"aggregate": _aggregate}
def _build_aggregate_items(self, req, aggregate): def _build_aggregate_items(self, req, aggregate):
show_uuid = api_version_request.is_supported(req, min_version="2.41") show_uuid = api_version_request.is_supported(req, "2.41")
keys = aggregate.obj_fields keys = aggregate.obj_fields
# NOTE(rlrossit): Within the compute API, metadata will always be # NOTE(rlrossit): Within the compute API, metadata will always be
# set on the aggregate object (at a minimum to {}). Because of this, # set on the aggregate object (at a minimum to {}). Because of this,

View File

@@ -65,9 +65,7 @@ class CreateBackupController(wsgi.Controller):
props = {} props = {}
metadata = entity.get('metadata', {}) metadata = entity.get('metadata', {})
# Starting from microversion 2.39 we don't check quotas on createBackup # Starting from microversion 2.39 we don't check quotas on createBackup
if api_version_request.is_supported( if not api_version_request.is_supported(req, '2.39'):
req, max_version=
api_version_request.MAX_IMAGE_META_PROXY_API_VERSION):
common.check_img_metadata_properties_quota(context, metadata) common.check_img_metadata_properties_quota(context, metadata)
props.update(metadata) props.update(metadata)

View File

@@ -45,7 +45,7 @@ class EvacuateController(wsgi.Controller):
self.host_api = compute.HostAPI() self.host_api = compute.HostAPI()
def _get_on_shared_storage(self, req, evacuate_body): def _get_on_shared_storage(self, req, evacuate_body):
if api_version_request.is_supported(req, min_version='2.14'): if api_version_request.is_supported(req, '2.14'):
return None return None
else: else:
return strutils.bool_from_string(evacuate_body["onSharedStorage"]) return strutils.bool_from_string(evacuate_body["onSharedStorage"])
@@ -108,7 +108,7 @@ class EvacuateController(wsgi.Controller):
force = None force = None
target_state = None target_state = None
if api_version_request.is_supported(req, min_version='2.95'): if api_version_request.is_supported(req, '2.95'):
min_ver = objects.service.get_minimum_version_all_cells( min_ver = objects.service.get_minimum_version_all_cells(
context, ['nova-compute']) context, ['nova-compute'])
if min_ver < MIN_VER_NOVA_COMPUTE_EVACUATE_STOPPED: if min_ver < MIN_VER_NOVA_COMPUTE_EVACUATE_STOPPED:
@@ -122,13 +122,13 @@ class EvacuateController(wsgi.Controller):
on_shared_storage = self._get_on_shared_storage(req, evacuate_body) on_shared_storage = self._get_on_shared_storage(req, evacuate_body)
if api_version_request.is_supported(req, min_version='2.29'): if api_version_request.is_supported(req, '2.29'):
force = body["evacuate"].get("force", False) force = body["evacuate"].get("force", False)
force = strutils.bool_from_string(force, strict=True) force = strutils.bool_from_string(force, strict=True)
if force is True and not host: if force is True and not host:
message = _("Can't force to a non-provided destination") message = _("Can't force to a non-provided destination")
raise exc.HTTPBadRequest(explanation=message) raise exc.HTTPBadRequest(explanation=message)
if api_version_request.is_supported(req, min_version='2.14'): if api_version_request.is_supported(req, '2.14'):
password = self._get_password_v214(req, evacuate_body) password = self._get_password_v214(req, evacuate_body)
else: else:
password = self._get_password(req, evacuate_body, password = self._get_password(req, evacuate_body,
@@ -151,8 +151,8 @@ class EvacuateController(wsgi.Controller):
on_shared_storage, password, force, on_shared_storage, password, force,
target_state) target_state)
except exception.InstanceInvalidState as state_error: except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(
'evacuate', id) state_error, 'evacuate', id)
except ( except (
exception.ComputeServiceInUse, exception.ComputeServiceInUse,
exception.ForbiddenPortsWithAccelerator, exception.ForbiddenPortsWithAccelerator,
@@ -163,11 +163,14 @@ class EvacuateController(wsgi.Controller):
raise exc.HTTPConflict(explanation=e.format_message()) raise exc.HTTPConflict(explanation=e.format_message())
except ( except (
exception.ForbiddenSharesNotSupported, exception.ForbiddenSharesNotSupported,
exception.ForbiddenWithShare) as e: exception.ForbiddenWithShare,
) as e:
raise exc.HTTPConflict(explanation=e.format_message()) raise exc.HTTPConflict(explanation=e.format_message())
if (not api_version_request.is_supported(req, min_version='2.14') and if (
CONF.api.enable_instance_password): not api_version_request.is_supported(req, '2.14') and
CONF.api.enable_instance_password
):
return {'adminPass': password} return {'adminPass': password}
else: else:
return None return None

View File

@@ -76,7 +76,7 @@ class FlavorActionController(wsgi.Controller):
flavor = common.get_flavor(context, id) flavor = common.get_flavor(context, id)
try: try:
if api_version_request.is_supported(req, min_version='2.7'): if api_version_request.is_supported(req, '2.7'):
if flavor.is_public: if flavor.is_public:
exp = _("Can not add access to a public flavor.") exp = _("Can not add access to a public flavor.")
raise webob.exc.HTTPConflict(explanation=exp) raise webob.exc.HTTPConflict(explanation=exp)

View File

@@ -79,8 +79,7 @@ class FlavorsController(wsgi.Controller):
is_public = vals.get('os-flavor-access:is_public', True) is_public = vals.get('os-flavor-access:is_public', True)
# The user can specify a description starting with microversion 2.55. # The user can specify a description starting with microversion 2.55.
include_description = api_version_request.is_supported( include_description = api_version_request.is_supported(req, '2.55')
req, flavors_view.FLAVOR_DESCRIPTION_MICROVERSION)
description = vals.get('description') if include_description else None description = vals.get('description') if include_description else None
try: try:
@@ -97,8 +96,7 @@ class FlavorsController(wsgi.Controller):
raise webob.exc.HTTPConflict(explanation=err.format_message()) raise webob.exc.HTTPConflict(explanation=err.format_message())
include_extra_specs = False include_extra_specs = False
if api_version_request.is_supported( if api_version_request.is_supported(req, '2.61'):
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
include_extra_specs = context.can( include_extra_specs = context.can(
fes_policies.POLICY_ROOT % 'index', fatal=False) fes_policies.POLICY_ROOT % 'index', fatal=False)
# NOTE(yikun): This empty extra_specs only for keeping consistent # NOTE(yikun): This empty extra_specs only for keeping consistent
@@ -130,8 +128,7 @@ class FlavorsController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=e.format_message()) raise webob.exc.HTTPNotFound(explanation=e.format_message())
include_extra_specs = False include_extra_specs = False
if api_version_request.is_supported( if api_version_request.is_supported(req, '2.61'):
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
include_extra_specs = context.can( include_extra_specs = context.can(
fes_policies.POLICY_ROOT % 'index', fatal=False) fes_policies.POLICY_ROOT % 'index', fatal=False)
return self._view_builder.show(req, flavor, include_description=True, return self._view_builder.show(req, flavor, include_description=True,
@@ -157,11 +154,12 @@ class FlavorsController(wsgi.Controller):
"""Return all flavors in detail.""" """Return all flavors in detail."""
context = req.environ['nova.context'] context = req.environ['nova.context']
limited_flavors = self._get_flavors(req) limited_flavors = self._get_flavors(req)
include_extra_specs = False include_extra_specs = False
if api_version_request.is_supported( if api_version_request.is_supported(req, '2.61'):
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
include_extra_specs = context.can( include_extra_specs = context.can(
fes_policies.POLICY_ROOT % 'index', fatal=False) fes_policies.POLICY_ROOT % 'index', fatal=False)
return self._view_builder.detail( return self._view_builder.detail(
req, limited_flavors, include_extra_specs=include_extra_specs) req, limited_flavors, include_extra_specs=include_extra_specs)
@@ -180,12 +178,12 @@ class FlavorsController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=e.format_message()) raise webob.exc.HTTPNotFound(explanation=e.format_message())
include_extra_specs = False include_extra_specs = False
if api_version_request.is_supported( if api_version_request.is_supported(req, '2.61'):
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
include_extra_specs = context.can( include_extra_specs = context.can(
fes_policies.POLICY_ROOT % 'index', fatal=False) fes_policies.POLICY_ROOT % 'index', fatal=False)
include_description = api_version_request.is_supported(
req, flavors_view.FLAVOR_DESCRIPTION_MICROVERSION) include_description = api_version_request.is_supported(req, '2.55')
return self._view_builder.show( return self._view_builder.show(
req, flavor, include_description=include_description, req, flavor, include_description=include_description,
include_extra_specs=include_extra_specs) include_extra_specs=include_extra_specs)

View File

@@ -35,9 +35,7 @@ class FlavorExtraSpecsController(wsgi.Controller):
return dict(extra_specs=flavor.extra_specs) return dict(extra_specs=flavor.extra_specs)
def _check_extra_specs_value(self, req, specs): def _check_extra_specs_value(self, req, specs):
validation_supported = api_version_request.is_supported( validation_supported = api_version_request.is_supported(req, '2.86')
req, min_version='2.86',
)
for name, value in specs.items(): for name, value in specs.items():
# NOTE(gmann): Max length for numeric value is being checked # NOTE(gmann): Max length for numeric value is being checked

View File

@@ -53,8 +53,7 @@ class HypervisorsController(wsgi.Controller):
): ):
alive = self.servicegroup_api.service_is_up(service) alive = self.servicegroup_api.service_is_up(service)
# The 2.53 microversion returns the compute node uuid rather than id. # The 2.53 microversion returns the compute node uuid rather than id.
uuid_for_id = api_version_request.is_supported( uuid_for_id = api_version_request.is_supported(req, "2.53")
req, min_version="2.53")
hyp_dict = { hyp_dict = {
'id': hypervisor.uuid if uuid_for_id else hypervisor.id, 'id': hypervisor.uuid if uuid_for_id else hypervisor.id,
@@ -77,9 +76,7 @@ class HypervisorsController(wsgi.Controller):
# The 2.88 microversion removed these fields, so only add them on older # The 2.88 microversion removed these fields, so only add them on older
# microversions # microversions
if detail and api_version_request.is_supported( if detail and not api_version_request.is_supported(req, '2.88'):
req, max_version='2.87',
):
for field in ( for field in (
'vcpus', 'memory_mb', 'local_gb', 'vcpus_used', 'vcpus', 'memory_mb', 'local_gb', 'vcpus_used',
'memory_mb_used', 'local_gb_used', 'free_ram_mb', 'memory_mb_used', 'local_gb_used', 'free_ram_mb',
@@ -88,18 +85,16 @@ class HypervisorsController(wsgi.Controller):
): ):
hyp_dict[field] = getattr(hypervisor, field) hyp_dict[field] = getattr(hypervisor, field)
if api_version_request.is_supported(req, max_version='2.27'): if api_version_request.is_supported(req, '2.28'):
hyp_dict['cpu_info'] = hypervisor.cpu_info
else:
if hypervisor.cpu_info: if hypervisor.cpu_info:
hyp_dict['cpu_info'] = jsonutils.loads(hypervisor.cpu_info) hyp_dict['cpu_info'] = jsonutils.loads(hypervisor.cpu_info)
else: else:
hyp_dict['cpu_info'] = {} hyp_dict['cpu_info'] = {}
else:
hyp_dict['cpu_info'] = hypervisor.cpu_info
# The 2.88 microversion also *added* the 'uptime' field to the response # The 2.88 microversion also *added* the 'uptime' field to the response
if detail and api_version_request.is_supported( if detail and api_version_request.is_supported(req, '2.88'):
req, min_version='2.88',
):
try: try:
hyp_dict['uptime'] = self.host_api.get_host_uptime( hyp_dict['uptime'] = self.host_api.get_host_uptime(
req.environ['nova.context'], hypervisor.host) req.environ['nova.context'], hypervisor.host)
@@ -121,9 +116,7 @@ class HypervisorsController(wsgi.Controller):
# The 2.75 microversion adds 'servers' field always in response. # The 2.75 microversion adds 'servers' field always in response.
# Empty list if there are no servers on hypervisors and it is # Empty list if there are no servers on hypervisors and it is
# requested in request. # requested in request.
elif with_servers and api_version_request.is_supported( elif with_servers and api_version_request.is_supported(req, '2.75'):
req, min_version='2.75',
):
hyp_dict['servers'] = [] hyp_dict['servers'] = []
return hyp_dict return hyp_dict
@@ -152,7 +145,7 @@ class HypervisorsController(wsgi.Controller):
# The 2.53 microversion moves the search and servers routes into # The 2.53 microversion moves the search and servers routes into
# GET /os-hypervisors and GET /os-hypervisors/detail with query # GET /os-hypervisors and GET /os-hypervisors/detail with query
# parameters. # parameters.
if api_version_request.is_supported(req, min_version="2.53"): if api_version_request.is_supported(req, "2.53"):
hypervisor_match = req.GET.get('hypervisor_hostname_pattern') hypervisor_match = req.GET.get('hypervisor_hostname_pattern')
with_servers = strutils.bool_from_string( with_servers = strutils.bool_from_string(
req.GET.get('with_servers', False), strict=True) req.GET.get('with_servers', False), strict=True)
@@ -295,7 +288,7 @@ class HypervisorsController(wsgi.Controller):
:raises: webob.exc.HTTPNotFound if the requested microversion is :raises: webob.exc.HTTPNotFound if the requested microversion is
less than 2.53 and the id is not an integer. less than 2.53 and the id is not an integer.
""" """
if api_version_request.is_supported(req, min_version="2.53"): if api_version_request.is_supported(req, "2.53"):
if not uuidutils.is_uuid_like(hypervisor_id): if not uuidutils.is_uuid_like(hypervisor_id):
msg = _('Invalid uuid %s') % hypervisor_id msg = _('Invalid uuid %s') % hypervisor_id
raise webob.exc.HTTPBadRequest(explanation=msg) raise webob.exc.HTTPBadRequest(explanation=msg)

View File

@@ -72,7 +72,7 @@ class InstanceActionsController(wsgi.Controller):
return event return event
def _get_instance(self, req, context, server_id): def _get_instance(self, req, context, server_id):
if not api_version_request.is_supported(req, min_version="2.21"): if not api_version_request.is_supported(req, '2.21'):
return common.get_instance(self.compute_api, context, server_id) return common.get_instance(self.compute_api, context, server_id)
with utils.temporary_mutation(context, read_deleted='yes'): with utils.temporary_mutation(context, read_deleted='yes'):
@@ -119,7 +119,7 @@ class InstanceActionsController(wsgi.Controller):
except exception.MarkerNotFound as e: except exception.MarkerNotFound as e:
raise exc.HTTPBadRequest(explanation=e.format_message()) raise exc.HTTPBadRequest(explanation=e.format_message())
if api_version_request.is_supported(req, min_version="2.58"): if api_version_request.is_supported(req, '2.58'):
actions = [self._format_action(action, ACTION_KEYS_V258) actions = [self._format_action(action, ACTION_KEYS_V258)
for action in actions_raw] for action in actions_raw]
else: else:
@@ -150,7 +150,7 @@ class InstanceActionsController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=msg) raise exc.HTTPNotFound(explanation=msg)
action_id = action['id'] action_id = action['id']
if api_version_request.is_supported(req, min_version="2.58"): if api_version_request.is_supported(req, '2.58'):
action = self._format_action(action, ACTION_KEYS_V258) action = self._format_action(action, ACTION_KEYS_V258)
else: else:
action = self._format_action(action, ACTION_KEYS) action = self._format_action(action, ACTION_KEYS)

View File

@@ -41,8 +41,10 @@ class LockServerController(wsgi.Controller):
target={'user_id': instance.user_id, target={'user_id': instance.user_id,
'project_id': instance.project_id}) 'project_id': instance.project_id})
reason = None reason = None
if (api_version_request.is_supported(req, min_version='2.73') and if (
body['lock'] is not None): api_version_request.is_supported(req, '2.73') and
body['lock'] is not None
):
reason = body['lock'].get('locked_reason') reason = body['lock'].get('locked_reason')
self.compute_api.lock(context, instance, reason=reason) self.compute_api.lock(context, instance, reason=reason)

View File

@@ -48,8 +48,10 @@ class MigrateServerController(wsgi.Controller):
instance = common.get_instance(self.compute_api, context, id, instance = common.get_instance(self.compute_api, context, id,
expected_attrs=['flavor', 'services']) expected_attrs=['flavor', 'services'])
host_name = None host_name = None
if (api_version_request.is_supported(req, min_version='2.56') and if (
body['migrate'] is not None): api_version_request.is_supported(req, '2.56') and
body['migrate'] is not None
):
host_name = body['migrate'].get('host') host_name = body['migrate'].get('host')
if host_name: if host_name:
@@ -111,10 +113,10 @@ class MigrateServerController(wsgi.Controller):
host = body["os-migrateLive"]["host"] host = body["os-migrateLive"]["host"]
block_migration = body["os-migrateLive"]["block_migration"] block_migration = body["os-migrateLive"]["block_migration"]
force = None force = None
async_ = api_version_request.is_supported(req, min_version='2.34') async_ = api_version_request.is_supported(req, '2.34')
if api_version_request.is_supported(req, min_version='2.30'): if api_version_request.is_supported(req, '2.30'):
force = self._get_force_param_for_live_migration(body, host) force = self._get_force_param_for_live_migration(body, host)
if api_version_request.is_supported(req, min_version='2.25'): if api_version_request.is_supported(req, '2.25'):
if block_migration == 'auto': if block_migration == 'auto':
block_migration = None block_migration = None
else: else:

View File

@@ -42,7 +42,7 @@ class ServerDiagnosticsController(wsgi.Controller):
target={'project_id': instance.project_id}) target={'project_id': instance.project_id})
try: try:
if api_version_request.is_supported(req, min_version='2.48'): if api_version_request.is_supported(req, '2.48'):
diagnostics = self.compute_api.get_instance_diagnostics( diagnostics = self.compute_api.get_instance_diagnostics(
context, instance) context, instance)
return self._view_builder.instance_diagnostics(diagnostics) return self._view_builder.instance_diagnostics(diagnostics)

View File

@@ -94,7 +94,7 @@ class ServerGroupController(wsgi.Controller):
server_group = {} server_group = {}
server_group['id'] = group.uuid server_group['id'] = group.uuid
server_group['name'] = group.name server_group['name'] = group.name
if api_version_request.is_supported(req, min_version='2.64'): if api_version_request.is_supported(req, '2.64'):
server_group['policy'] = group.policy server_group['policy'] = group.policy
server_group['rules'] = group.rules server_group['rules'] = group.rules
else: else:
@@ -109,7 +109,7 @@ class ServerGroupController(wsgi.Controller):
server_group['members'] = members server_group['members'] = members
# Add project id information to the response data for # Add project id information to the response data for
# API version v2.13 # API version v2.13
if api_version_request.is_supported(req, min_version="2.13"): if api_version_request.is_supported(req, "2.13"):
server_group['project_id'] = group.project_id server_group['project_id'] = group.project_id
server_group['user_id'] = group.user_id server_group['user_id'] = group.user_id
return server_group return server_group

View File

@@ -94,7 +94,7 @@ class ServerSharesController(wsgi.Controller):
@wsgi.Controller.api_version("2.97") @wsgi.Controller.api_version("2.97")
@wsgi.response(201) @wsgi.response(201)
@wsgi.expected_errors((400, 403, 404, 409)) @wsgi.expected_errors((400, 403, 404, 409))
@validation.schema(schema.create, min_version='2.97') @validation.schema(schema.create, '2.97')
@validation.response_body_schema(schema.show_response) @validation.response_body_schema(schema.show_response)
def create(self, req, server_id, body): def create(self, req, server_id, body):
def _try_create_share_mapping(context, share_mapping): def _try_create_share_mapping(context, share_mapping):

View File

@@ -146,8 +146,7 @@ class ServersController(wsgi.Controller):
@staticmethod @staticmethod
def _is_cell_down_supported(req, search_opts): def _is_cell_down_supported(req, search_opts):
cell_down_support = api_version_request.is_supported( cell_down_support = api_version_request.is_supported(req, '2.69')
req, min_version='2.69')
if cell_down_support: if cell_down_support:
# NOTE(tssurya): Minimal constructs would be returned from the down # NOTE(tssurya): Minimal constructs would be returned from the down
@@ -200,7 +199,7 @@ class ServersController(wsgi.Controller):
states = common.task_and_vm_state_from_status(statuses) states = common.task_and_vm_state_from_status(statuses)
vm_state, task_state = states vm_state, task_state = states
if not vm_state and not task_state: if not vm_state and not task_state:
if api_version_request.is_supported(req, min_version='2.38'): if api_version_request.is_supported(req, '2.38'):
msg = _('Invalid status value') msg = _('Invalid status value')
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
@@ -264,7 +263,7 @@ class ServersController(wsgi.Controller):
msg = _("Only administrators may list deleted instances") msg = _("Only administrators may list deleted instances")
raise exc.HTTPForbidden(explanation=msg) raise exc.HTTPForbidden(explanation=msg)
if api_version_request.is_supported(req, min_version='2.26'): if api_version_request.is_supported(req, '2.26'):
for tag_filter in TAG_SEARCH_FILTERS: for tag_filter in TAG_SEARCH_FILTERS:
if tag_filter in search_opts: if tag_filter in search_opts:
search_opts[tag_filter] = search_opts[ search_opts[tag_filter] = search_opts[
@@ -301,7 +300,7 @@ class ServersController(wsgi.Controller):
limit, marker = common.get_limit_and_marker(req) limit, marker = common.get_limit_and_marker(req)
sort_keys, sort_dirs = common.get_sort_params(req.params) sort_keys, sort_dirs = common.get_sort_params(req.params)
blacklist = schema.SERVER_LIST_IGNORE_SORT_KEY blacklist = schema.SERVER_LIST_IGNORE_SORT_KEY
if api_version_request.is_supported(req, min_version='2.73'): if api_version_request.is_supported(req, '2.73'):
blacklist = schema.SERVER_LIST_IGNORE_SORT_KEY_V273 blacklist = schema.SERVER_LIST_IGNORE_SORT_KEY_V273
sort_keys, sort_dirs = remove_invalid_sort_keys( sort_keys, sort_dirs = remove_invalid_sort_keys(
context, sort_keys, sort_dirs, blacklist, ('host', 'node')) context, sort_keys, sort_dirs, blacklist, ('host', 'node'))
@@ -462,10 +461,8 @@ class ServersController(wsgi.Controller):
def show(self, req, id): def show(self, req, id):
"""Returns server details by server id.""" """Returns server details by server id."""
context = req.environ['nova.context'] context = req.environ['nova.context']
cell_down_support = api_version_request.is_supported( cell_down_support = api_version_request.is_supported(req, '2.69')
req, min_version='2.69') show_server_groups = api_version_request.is_supported(req, '2.71')
show_server_groups = api_version_request.is_supported(
req, min_version='2.71')
instance = self._get_server( instance = self._get_server(
context, req, id, is_detail=True, context, req, id, is_detail=True,
@@ -687,10 +684,10 @@ class ServersController(wsgi.Controller):
password = self._get_server_admin_password(server_dict) password = self._get_server_admin_password(server_dict)
name = common.normalize_name(server_dict['name']) name = common.normalize_name(server_dict['name'])
description = name description = name
if api_version_request.is_supported(req, min_version='2.19'): if api_version_request.is_supported(req, '2.19'):
description = server_dict.get('description') description = server_dict.get('description')
hostname = None hostname = None
if api_version_request.is_supported(req, min_version='2.90'): if api_version_request.is_supported(req, '2.90'):
hostname = server_dict.get('hostname') hostname = server_dict.get('hostname')
# Arguments to be passed to instance create function # Arguments to be passed to instance create function
@@ -731,7 +728,7 @@ class ServersController(wsgi.Controller):
availability_zone = server_dict.pop("availability_zone", None) availability_zone = server_dict.pop("availability_zone", None)
if api_version_request.is_supported(req, min_version='2.52'): if api_version_request.is_supported(req, '2.52'):
create_kwargs['tags'] = server_dict.get('tags') create_kwargs['tags'] = server_dict.get('tags')
helpers.translate_attributes(helpers.CREATE, helpers.translate_attributes(helpers.CREATE,
@@ -763,7 +760,7 @@ class ServersController(wsgi.Controller):
availability_zone = self._validate_host_availability_zone( availability_zone = self._validate_host_availability_zone(
context, availability_zone, host) context, availability_zone, host)
if api_version_request.is_supported(req, min_version='2.74'): if api_version_request.is_supported(req, '2.74'):
self._process_hosts_for_create(context, target, server_dict, self._process_hosts_for_create(context, target, server_dict,
create_kwargs, host, node) create_kwargs, host, node)
@@ -919,8 +916,7 @@ class ServersController(wsgi.Controller):
ctxt.can(server_policies.SERVERS % 'update', ctxt.can(server_policies.SERVERS % 'update',
target={'user_id': instance.user_id, target={'user_id': instance.user_id,
'project_id': instance.project_id}) 'project_id': instance.project_id})
show_server_groups = api_version_request.is_supported( show_server_groups = api_version_request.is_supported(req, '2.71')
req, min_version='2.71')
server = body['server'] server = body['server']
@@ -943,8 +939,7 @@ class ServersController(wsgi.Controller):
# NOTE(gmann): Starting from microversion 2.75, PUT and Rebuild # NOTE(gmann): Starting from microversion 2.75, PUT and Rebuild
# API response will show all attributes like GET /servers API. # API response will show all attributes like GET /servers API.
show_all_attributes = api_version_request.is_supported( show_all_attributes = api_version_request.is_supported(req, '2.75')
req, min_version='2.75')
extend_address = show_all_attributes extend_address = show_all_attributes
show_AZ = show_all_attributes show_AZ = show_all_attributes
show_config_drive = show_all_attributes show_config_drive = show_all_attributes
@@ -1222,22 +1217,21 @@ class ServersController(wsgi.Controller):
helpers.translate_attributes(helpers.REBUILD, rebuild_dict, kwargs) helpers.translate_attributes(helpers.REBUILD, rebuild_dict, kwargs)
if ( if (
api_version_request.is_supported(req, min_version='2.54') and api_version_request.is_supported(req, '2.54') and
'key_name' in rebuild_dict 'key_name' in rebuild_dict
): ):
kwargs['key_name'] = rebuild_dict.get('key_name') kwargs['key_name'] = rebuild_dict.get('key_name')
# If user_data is not specified, we don't include it in kwargs because # If user_data is not specified, we don't include it in kwargs because
# we don't want to overwrite the existing user_data. # we don't want to overwrite the existing user_data.
include_user_data = api_version_request.is_supported( include_user_data = api_version_request.is_supported(req, '2.57')
req, min_version='2.57')
if include_user_data and 'user_data' in rebuild_dict: if include_user_data and 'user_data' in rebuild_dict:
kwargs['user_data'] = rebuild_dict['user_data'] kwargs['user_data'] = rebuild_dict['user_data']
# Skip policy check for 'rebuild:trusted_certs' if no trusted # Skip policy check for 'rebuild:trusted_certs' if no trusted
# certificate IDs were provided. # certificate IDs were provided.
if ( if (
api_version_request.is_supported(req, min_version='2.63') and api_version_request.is_supported(req, '2.63') and
# Note that this is different from server create since with # Note that this is different from server create since with
# rebuild a user can unset/reset the trusted certs by # rebuild a user can unset/reset the trusted certs by
# specifying trusted_image_certificates=None, similar to # specifying trusted_image_certificates=None, similar to
@@ -1250,12 +1244,12 @@ class ServersController(wsgi.Controller):
target=target) target=target)
if ( if (
api_version_request.is_supported(req, min_version='2.90') and api_version_request.is_supported(req, '2.90') and
'hostname' in rebuild_dict 'hostname' in rebuild_dict
): ):
kwargs['hostname'] = rebuild_dict['hostname'] kwargs['hostname'] = rebuild_dict['hostname']
if api_version_request.is_supported(req, min_version='2.93'): if api_version_request.is_supported(req, '2.93'):
kwargs['reimage_boot_volume'] = True kwargs['reimage_boot_volume'] = True
for request_attribute, instance_attribute in attr_map.items(): for request_attribute, instance_attribute in attr_map.items():
@@ -1307,15 +1301,12 @@ class ServersController(wsgi.Controller):
# NOTE(liuyulong): set the new key_name for the API response. # NOTE(liuyulong): set the new key_name for the API response.
# from microversion 2.54 onwards. # from microversion 2.54 onwards.
show_keypair = api_version_request.is_supported( show_keypair = api_version_request.is_supported(req, '2.54')
req, min_version='2.54') show_server_groups = api_version_request.is_supported(req, '2.71')
show_server_groups = api_version_request.is_supported(
req, min_version='2.71')
# NOTE(gmann): Starting from microversion 2.75, PUT and Rebuild # NOTE(gmann): Starting from microversion 2.75, PUT and Rebuild
# API response will show all attributes like GET /servers API. # API response will show all attributes like GET /servers API.
show_all_attributes = api_version_request.is_supported( show_all_attributes = api_version_request.is_supported(req, '2.75')
req, min_version='2.75')
extend_address = show_all_attributes extend_address = show_all_attributes
show_AZ = show_all_attributes show_AZ = show_all_attributes
show_config_drive = show_all_attributes show_config_drive = show_all_attributes
@@ -1379,9 +1370,7 @@ class ServersController(wsgi.Controller):
metadata = entity.get('metadata', {}) metadata = entity.get('metadata', {})
# Starting from microversion 2.39 we don't check quotas on createImage # Starting from microversion 2.39 we don't check quotas on createImage
if api_version_request.is_supported( if not api_version_request.is_supported(req, '2.39'):
req, max_version=
api_version_request.MAX_IMAGE_META_PROXY_API_VERSION):
common.check_img_metadata_properties_quota(context, metadata) common.check_img_metadata_properties_quota(context, metadata)
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
@@ -1443,20 +1432,20 @@ class ServersController(wsgi.Controller):
# probably not trivial. # probably not trivial.
opt_list = ('reservation_id', 'name', 'status', 'image', 'flavor', opt_list = ('reservation_id', 'name', 'status', 'image', 'flavor',
'ip', 'changes-since', 'all_tenants') 'ip', 'changes-since', 'all_tenants')
if api_version_request.is_supported(req, min_version='2.5'): if api_version_request.is_supported(req, '2.5'):
opt_list += ('ip6',) opt_list += ('ip6',)
if api_version_request.is_supported(req, min_version='2.26'): if api_version_request.is_supported(req, '2.26'):
opt_list += TAG_SEARCH_FILTERS opt_list += TAG_SEARCH_FILTERS
if api_version_request.is_supported(req, min_version='2.66'): if api_version_request.is_supported(req, '2.66'):
opt_list += ('changes-before',) opt_list += ('changes-before',)
if api_version_request.is_supported(req, min_version='2.73'): if api_version_request.is_supported(req, '2.73'):
opt_list += ('locked',) opt_list += ('locked',)
if api_version_request.is_supported(req, min_version='2.83'): if api_version_request.is_supported(req, '2.83'):
opt_list += ('availability_zone', 'config_drive', 'key_name', opt_list += ('availability_zone', 'config_drive', 'key_name',
'created_at', 'launched_at', 'terminated_at', 'created_at', 'launched_at', 'terminated_at',
'power_state', 'task_state', 'vm_state', 'progress', 'power_state', 'task_state', 'vm_state', 'progress',
'user_id',) 'user_id',)
if api_version_request.is_supported(req, min_version='2.90'): if api_version_request.is_supported(req, '2.90'):
opt_list += ('hostname',) opt_list += ('hostname',)
return opt_list return opt_list

View File

@@ -58,8 +58,7 @@ class ServiceController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
cell_down_support = api_version_request.is_supported( cell_down_support = api_version_request.is_supported(req, '2.69')
req, min_version='2.69')
_services = [ _services = [
s s
@@ -98,8 +97,7 @@ class ServiceController(wsgi.Controller):
active = 'disabled' active = 'disabled'
updated_time = self.servicegroup_api.get_updated_time(svc) updated_time = self.servicegroup_api.get_updated_time(svc)
uuid_for_id = api_version_request.is_supported( uuid_for_id = api_version_request.is_supported(req, '2.53')
req, min_version='2.53')
if 'availability_zone' not in svc: if 'availability_zone' not in svc:
# The service wasn't loaded with the AZ so we need to do it here. # The service wasn't loaded with the AZ so we need to do it here.
@@ -127,8 +125,7 @@ class ServiceController(wsgi.Controller):
def _get_services_list(self, req, additional_fields=()): def _get_services_list(self, req, additional_fields=()):
_services = self._get_services(req) _services = self._get_services(req)
cell_down_support = api_version_request.is_supported( cell_down_support = api_version_request.is_supported(req, '2.69')
req, min_version='2.69')
return [self._get_service_detail(svc, additional_fields, req, return [self._get_service_detail(svc, additional_fields, req,
cell_down_support=cell_down_support) for svc in _services] cell_down_support=cell_down_support) for svc in _services]
@@ -248,7 +245,7 @@ class ServiceController(wsgi.Controller):
context = req.environ['nova.context'] context = req.environ['nova.context']
context.can(services_policies.BASE_POLICY_NAME % 'delete', target={}) context.can(services_policies.BASE_POLICY_NAME % 'delete', target={})
if api_version_request.is_supported(req, min_version='2.53'): if api_version_request.is_supported(req, '2.53'):
if not uuidutils.is_uuid_like(id): if not uuidutils.is_uuid_like(id):
msg = _('Invalid uuid %s') % id msg = _('Invalid uuid %s') % id
raise webob.exc.HTTPBadRequest(explanation=msg) raise webob.exc.HTTPBadRequest(explanation=msg)
@@ -378,7 +375,7 @@ class ServiceController(wsgi.Controller):
""" """
context = req.environ['nova.context'] context = req.environ['nova.context']
context.can(services_policies.BASE_POLICY_NAME % 'list', target={}) context.can(services_policies.BASE_POLICY_NAME % 'list', target={})
if api_version_request.is_supported(req, min_version='2.11'): if api_version_request.is_supported(req, '2.11'):
_services = self._get_services_list(req, ['forced_down']) _services = self._get_services_list(req, ['forced_down'])
else: else:
_services = self._get_services_list(req) _services = self._get_services_list(req)
@@ -401,7 +398,7 @@ class ServiceController(wsgi.Controller):
path of the request to uniquely identify the service record on which to path of the request to uniquely identify the service record on which to
perform a given update, which is defined in the body of the request. perform a given update, which is defined in the body of the request.
""" """
if api_version_request.is_supported(req, min_version='2.53'): if api_version_request.is_supported(req, '2.53'):
return self._update_v253(req, id, body) return self._update_v253(req, id, body)
else: else:
return self._update_v21(req, id, body) return self._update_v21(req, id, body)
@@ -409,7 +406,7 @@ class ServiceController(wsgi.Controller):
def _update_v21(self, req, id, body): def _update_v21(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
context.can(services_policies.BASE_POLICY_NAME % 'update', target={}) context.can(services_policies.BASE_POLICY_NAME % 'update', target={})
if api_version_request.is_supported(req, min_version='2.11'): if api_version_request.is_supported(req, '2.11'):
actions = self.actions.copy() actions = self.actions.copy()
actions["force-down"] = self._forced_down actions["force-down"] = self._forced_down
else: else:

View File

@@ -16,9 +16,6 @@
from nova.api.openstack import api_version_request from nova.api.openstack import api_version_request
from nova.api.openstack import common from nova.api.openstack import common
FLAVOR_DESCRIPTION_MICROVERSION = '2.55'
FLAVOR_EXTRA_SPECS_MICROVERSION = '2.61'
class ViewBuilder(common.ViewBuilder): class ViewBuilder(common.ViewBuilder):
@@ -78,16 +75,14 @@ class ViewBuilder(common.ViewBuilder):
def index(self, request, flavors): def index(self, request, flavors):
"""Return the 'index' view of flavors.""" """Return the 'index' view of flavors."""
coll_name = self._collection_name coll_name = self._collection_name
include_description = api_version_request.is_supported( include_description = api_version_request.is_supported(request, '2.55')
request, FLAVOR_DESCRIPTION_MICROVERSION)
return self._list_view(self.basic, request, flavors, coll_name, return self._list_view(self.basic, request, flavors, coll_name,
include_description=include_description) include_description=include_description)
def detail(self, request, flavors, include_extra_specs=False): def detail(self, request, flavors, include_extra_specs=False):
"""Return the 'detail' view of flavors.""" """Return the 'detail' view of flavors."""
coll_name = self._collection_name + '/detail' coll_name = self._collection_name + '/detail'
include_description = api_version_request.is_supported( include_description = api_version_request.is_supported(request, '2.55')
request, FLAVOR_DESCRIPTION_MICROVERSION)
return self._list_view(self.show, request, flavors, coll_name, return self._list_view(self.show, request, flavors, coll_name,
include_description=include_description, include_description=include_description,
include_extra_specs=include_extra_specs) include_extra_specs=include_extra_specs)

View File

@@ -268,7 +268,7 @@ class ViewBuilder(common.ViewBuilder):
# detail will pre-calculate this for us. If we're doing show, # detail will pre-calculate this for us. If we're doing show,
# then figure it out here. # then figure it out here.
show_extra_specs = False show_extra_specs = False
if api_version_request.is_supported(request, min_version='2.47'): if api_version_request.is_supported(request, '2.47'):
context = request.environ['nova.context'] context = request.environ['nova.context']
show_extra_specs = context.can( show_extra_specs = context.can(
servers_policies.SERVERS % 'show:flavor-extra-specs', servers_policies.SERVERS % 'show:flavor-extra-specs',
@@ -330,11 +330,11 @@ class ViewBuilder(common.ViewBuilder):
# attributes after v2.1. They are only in v2.1 for backward compat # attributes after v2.1. They are only in v2.1 for backward compat
# with v2.0. # with v2.0.
server["server"]["OS-EXT-AZ:availability_zone"] = az or '' server["server"]["OS-EXT-AZ:availability_zone"] = az or ''
if api_version_request.is_supported(request, min_version='2.96'): if api_version_request.is_supported(request, '2.96'):
pinned_az = self._get_pinned_az(context, instance, provided_az) pinned_az = self._get_pinned_az(context, instance, provided_az)
server['server']['pinned_availability_zone'] = pinned_az server['server']['pinned_availability_zone'] = pinned_az
if api_version_request.is_supported(request, min_version='2.100'): if api_version_request.is_supported(request, '2.100'):
server['server']['scheduler_hints'] = ( server['server']['scheduler_hints'] = (
self._get_scheduler_hints( self._get_scheduler_hints(
context, instance, provided_sched_hints)) context, instance, provided_sched_hints))
@@ -364,7 +364,7 @@ class ViewBuilder(common.ViewBuilder):
if show_extended_attr: if show_extended_attr:
properties = ['host', 'name', 'node'] properties = ['host', 'name', 'node']
if api_version_request.is_supported(request, min_version='2.3'): if api_version_request.is_supported(request, '2.3'):
# NOTE(mriedem): These will use the OS-EXT-SRV-ATTR prefix # NOTE(mriedem): These will use the OS-EXT-SRV-ATTR prefix
# below and that's OK for microversion 2.3 which is being # below and that's OK for microversion 2.3 which is being
# compatible with v2.0 for the ec2 API split out from Nova. # compatible with v2.0 for the ec2 API split out from Nova.
@@ -408,7 +408,7 @@ class ViewBuilder(common.ViewBuilder):
# for new attributes after v2.1. They are only in v2.1 for backward # for new attributes after v2.1. They are only in v2.1 for backward
# compat with v2.0. # compat with v2.0.
add_delete_on_termination = api_version_request.is_supported( add_delete_on_termination = api_version_request.is_supported(
request, min_version='2.3') request, '2.3')
if bdms is None: if bdms is None:
bdms = objects.BlockDeviceMappingList.bdms_by_instance_uuid( bdms = objects.BlockDeviceMappingList.bdms_by_instance_uuid(
context, [instance["uuid"]]) context, [instance["uuid"]])
@@ -416,7 +416,7 @@ class ViewBuilder(common.ViewBuilder):
bdms, bdms,
add_delete_on_termination) add_delete_on_termination)
if api_version_request.is_supported(request, min_version='2.16'): if api_version_request.is_supported(request, '2.16'):
if show_host_status is None: if show_host_status is None:
unknown_only = self._get_host_status_unknown_only( unknown_only = self._get_host_status_unknown_only(
context, instance) context, instance)
@@ -435,22 +435,22 @@ class ViewBuilder(common.ViewBuilder):
host_status == fields.HostStatus.UNKNOWN): host_status == fields.HostStatus.UNKNOWN):
server["server"]['host_status'] = host_status server["server"]['host_status'] = host_status
if api_version_request.is_supported(request, min_version="2.9"): if api_version_request.is_supported(request, "2.9"):
server["server"]["locked"] = (True if instance["locked_by"] server["server"]["locked"] = (True if instance["locked_by"]
else False) else False)
if api_version_request.is_supported(request, min_version="2.73"): if api_version_request.is_supported(request, "2.73"):
server["server"]["locked_reason"] = (instance.system_metadata.get( server["server"]["locked_reason"] = (instance.system_metadata.get(
"locked_reason")) "locked_reason"))
if api_version_request.is_supported(request, min_version="2.19"): if api_version_request.is_supported(request, "2.19"):
server["server"]["description"] = instance.get( server["server"]["description"] = instance.get(
"display_description") "display_description")
if api_version_request.is_supported(request, min_version="2.26"): if api_version_request.is_supported(request, "2.26"):
server["server"]["tags"] = [t.tag for t in instance.tags] server["server"]["tags"] = [t.tag for t in instance.tags]
if api_version_request.is_supported(request, min_version="2.63"): if api_version_request.is_supported(request, "2.63"):
trusted_certs = None trusted_certs = None
if instance.trusted_certs: if instance.trusted_certs:
trusted_certs = instance.trusted_certs.ids trusted_certs = instance.trusted_certs.ids
@@ -458,7 +458,7 @@ class ViewBuilder(common.ViewBuilder):
# TODO(stephenfin): Remove this check once we remove the # TODO(stephenfin): Remove this check once we remove the
# OS-EXT-SRV-ATTR:hostname policy checks from the policy is Y or later # OS-EXT-SRV-ATTR:hostname policy checks from the policy is Y or later
if api_version_request.is_supported(request, min_version='2.90'): if api_version_request.is_supported(request, '2.90'):
# API 2.90 made this field visible to non-admins, but we only show # API 2.90 made this field visible to non-admins, but we only show
# it if it's not already added # it if it's not already added
if not show_extended_attr: if not show_extended_attr:
@@ -482,7 +482,7 @@ class ViewBuilder(common.ViewBuilder):
coll_name = self._collection_name + '/detail' coll_name = self._collection_name + '/detail'
context = request.environ['nova.context'] context = request.environ['nova.context']
if api_version_request.is_supported(request, min_version='2.47'): if api_version_request.is_supported(request, '2.47'):
# Determine if we should show extra_specs in the inlined flavor # Determine if we should show extra_specs in the inlined flavor
# once before we iterate the list of instances # once before we iterate the list of instances
show_extra_specs = context.can( show_extra_specs = context.can(
@@ -510,7 +510,7 @@ class ViewBuilder(common.ViewBuilder):
bdms=bdms, bdms=bdms,
cell_down_support=cell_down_support) cell_down_support=cell_down_support)
if api_version_request.is_supported(request, min_version='2.16'): if api_version_request.is_supported(request, '2.16'):
unknown_only = self._get_host_status_unknown_only(context) unknown_only = self._get_host_status_unknown_only(context)
# If we're not allowed by policy to show host status at all, don't # If we're not allowed by policy to show host status at all, don't
# bother requesting instance host status from the compute API. # bother requesting instance host status from the compute API.
@@ -548,7 +548,7 @@ class ViewBuilder(common.ViewBuilder):
req_specs = None req_specs = None
req_specs_dict = {} req_specs_dict = {}
sched_hints_dict = {} sched_hints_dict = {}
if api_version_request.is_supported(request, min_version='2.96'): if api_version_request.is_supported(request, '2.96'):
context = request.environ['nova.context'] context = request.environ['nova.context']
instance_uuids = [s.uuid for s in servers] instance_uuids = [s.uuid for s in servers]
req_specs = objects.RequestSpec.get_by_instance_uuids( req_specs = objects.RequestSpec.get_by_instance_uuids(
@@ -556,7 +556,7 @@ class ViewBuilder(common.ViewBuilder):
req_specs_dict.update({req.instance_uuid: req.availability_zone req_specs_dict.update({req.instance_uuid: req.availability_zone
for req in req_specs for req in req_specs
if req.availability_zone is not None}) if req.availability_zone is not None})
if api_version_request.is_supported(request, min_version='2.100'): if api_version_request.is_supported(request, '2.100'):
sched_hints_dict.update({ sched_hints_dict.update({
req.instance_uuid: req.scheduler_hints req.instance_uuid: req.scheduler_hints
for req in req_specs for req in req_specs
@@ -633,7 +633,7 @@ class ViewBuilder(common.ViewBuilder):
}], }],
} }
if api_version_request.is_supported(request, min_version='2.98'): if api_version_request.is_supported(request, '2.98'):
image_props = {} image_props = {}
for key, value in instance.system_metadata.items(): for key, value in instance.system_metadata.items():
if key.startswith(utils.SM_IMAGE_PROP_PREFIX): if key.startswith(utils.SM_IMAGE_PROP_PREFIX):
@@ -668,7 +668,7 @@ class ViewBuilder(common.ViewBuilder):
"from the DB", instance=instance) "from the DB", instance=instance)
return {} return {}
if api_version_request.is_supported(request, min_version="2.47"): if api_version_request.is_supported(request, "2.47"):
return self._get_flavor_dict(request, flavor, show_extra_specs) return self._get_flavor_dict(request, flavor, show_extra_specs)
flavor_id = flavor["flavorid"] flavor_id = flavor["flavorid"]

View File

@@ -271,7 +271,7 @@ def _translate_attachment_detail_view(
def _check_request_version(req, min_version, method, server_id, server_state): def _check_request_version(req, min_version, method, server_id, server_state):
if not api_version_request.is_supported(req, min_version=min_version): if not api_version_request.is_supported(req, min_version):
exc_inv = exception.InstanceInvalidState( exc_inv = exception.InstanceInvalidState(
attr='vm_state', attr='vm_state',
instance_uuid=server_id, instance_uuid=server_id,
@@ -496,8 +496,7 @@ class VolumeAttachmentController(wsgi.Controller):
@wsgi.response(202) @wsgi.response(202)
@wsgi.expected_errors((400, 404, 409)) @wsgi.expected_errors((400, 404, 409))
@validation.schema(volumes_schema.update_volume_attachment, '2.0', '2.84') @validation.schema(volumes_schema.update_volume_attachment, '2.0', '2.84')
@validation.schema(volumes_schema.update_volume_attachment_v285, @validation.schema(volumes_schema.update_volume_attachment_v285, '2.85')
min_version='2.85')
def update(self, req, server_id, id, body): def update(self, req, server_id, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
instance = common.get_instance(self.compute_api, context, server_id) instance = common.get_instance(self.compute_api, context, server_id)

View File

@@ -8104,10 +8104,9 @@ class ServersViewBuilderTestV269(_ServersViewBuilderTest):
self.view_builder = views.servers.ViewBuilder() self.view_builder = views.servers.ViewBuilder()
self.ctxt = context.RequestContext('fake', self.project_id) self.ctxt = context.RequestContext('fake', self.project_id)
def fake_is_supported(req, min_version="2.1", max_version="2.69"): def fake_is_supported(req, version="2.1"):
return (fakes.api_version.APIVersionRequest(max_version) >= return (req.api_version_request >=
req.api_version_request >= fakes.api_version.APIVersionRequest(version))
fakes.api_version.APIVersionRequest(min_version))
self.stub_out('nova.api.openstack.api_version_request.is_supported', self.stub_out('nova.api.openstack.api_version_request.is_supported',
fake_is_supported) fake_is_supported)

View File

@@ -127,40 +127,9 @@ class APIVersionRequestTests(test.NoDBTestCase):
self.assertRaises(ValueError, self.assertRaises(ValueError,
api_version_request.APIVersionRequest().get_string) api_version_request.APIVersionRequest().get_string)
def test_is_supported_min_version(self): def test_is_supported(self):
req = fakes.HTTPRequest.blank(self.base_path, version='2.5') req = fakes.HTTPRequest.blank(self.base_path, version='2.5')
self.assertTrue(api_version_request.is_supported( self.assertTrue(api_version_request.is_supported(req, '2.4'))
req, min_version='2.4')) self.assertTrue(api_version_request.is_supported(req, '2.5'))
self.assertTrue(api_version_request.is_supported( self.assertFalse(api_version_request.is_supported(req, '2.6'))
req, min_version='2.5'))
self.assertFalse(api_version_request.is_supported(
req, min_version='2.6'))
def test_is_supported_max_version(self):
req = fakes.HTTPRequest.blank(self.base_path, version='2.5')
self.assertFalse(api_version_request.is_supported(
req, max_version='2.4'))
self.assertTrue(api_version_request.is_supported(
req, max_version='2.5'))
self.assertTrue(api_version_request.is_supported(
req, max_version='2.6'))
def test_is_supported_min_and_max_version(self):
req = fakes.HTTPRequest.blank(self.base_path, version='2.5')
self.assertFalse(api_version_request.is_supported(
req, min_version='2.3', max_version='2.4'))
self.assertTrue(api_version_request.is_supported(
req, min_version='2.3', max_version='2.5'))
self.assertTrue(api_version_request.is_supported(
req, min_version='2.3', max_version='2.7'))
self.assertTrue(api_version_request.is_supported(
req, min_version='2.5', max_version='2.7'))
self.assertFalse(api_version_request.is_supported(
req, min_version='2.6', max_version='2.7'))
self.assertTrue(api_version_request.is_supported(
req, min_version='2.5', max_version='2.5'))
self.assertFalse(api_version_request.is_supported(
req, min_version='2.10', max_version='2.1'))