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)
def is_supported(req, min_version=_MIN_API_VERSION,
max_version=_MAX_API_VERSION):
def is_supported(req, version):
"""Check if API request version satisfies version restrictions.
:param req: request object
:param min_version: minimal version of API needed for correct
request processing
:param max_version: maximum version of API needed for correct
request processing
:param version: minimal version of API needed for correct
request processing
: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 >=
APIVersionRequest(min_version))
return req.api_version_request >= APIVersionRequest(version)
class APIVersionRequest(object):

View File

@@ -274,7 +274,7 @@ class AggregateController(wsgi.Controller):
return {"aggregate": _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
# NOTE(rlrossit): Within the compute API, metadata will always be
# set on the aggregate object (at a minimum to {}). Because of this,

View File

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

View File

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

View File

@@ -76,7 +76,7 @@ class FlavorActionController(wsgi.Controller):
flavor = common.get_flavor(context, id)
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:
exp = _("Can not add access to a public flavor.")
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)
# The user can specify a description starting with microversion 2.55.
include_description = api_version_request.is_supported(
req, flavors_view.FLAVOR_DESCRIPTION_MICROVERSION)
include_description = api_version_request.is_supported(req, '2.55')
description = vals.get('description') if include_description else None
try:
@@ -97,8 +96,7 @@ class FlavorsController(wsgi.Controller):
raise webob.exc.HTTPConflict(explanation=err.format_message())
include_extra_specs = False
if api_version_request.is_supported(
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
if api_version_request.is_supported(req, '2.61'):
include_extra_specs = context.can(
fes_policies.POLICY_ROOT % 'index', fatal=False)
# 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())
include_extra_specs = False
if api_version_request.is_supported(
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
if api_version_request.is_supported(req, '2.61'):
include_extra_specs = context.can(
fes_policies.POLICY_ROOT % 'index', fatal=False)
return self._view_builder.show(req, flavor, include_description=True,
@@ -157,11 +154,12 @@ class FlavorsController(wsgi.Controller):
"""Return all flavors in detail."""
context = req.environ['nova.context']
limited_flavors = self._get_flavors(req)
include_extra_specs = False
if api_version_request.is_supported(
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
if api_version_request.is_supported(req, '2.61'):
include_extra_specs = context.can(
fes_policies.POLICY_ROOT % 'index', fatal=False)
return self._view_builder.detail(
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())
include_extra_specs = False
if api_version_request.is_supported(
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
if api_version_request.is_supported(req, '2.61'):
include_extra_specs = context.can(
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(
req, flavor, include_description=include_description,
include_extra_specs=include_extra_specs)

View File

@@ -35,9 +35,7 @@ class FlavorExtraSpecsController(wsgi.Controller):
return dict(extra_specs=flavor.extra_specs)
def _check_extra_specs_value(self, req, specs):
validation_supported = api_version_request.is_supported(
req, min_version='2.86',
)
validation_supported = api_version_request.is_supported(req, '2.86')
for name, value in specs.items():
# 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)
# The 2.53 microversion returns the compute node uuid rather than id.
uuid_for_id = api_version_request.is_supported(
req, min_version="2.53")
uuid_for_id = api_version_request.is_supported(req, "2.53")
hyp_dict = {
'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
# microversions
if detail and api_version_request.is_supported(
req, max_version='2.87',
):
if detail and not api_version_request.is_supported(req, '2.88'):
for field in (
'vcpus', 'memory_mb', 'local_gb', 'vcpus_used',
'memory_mb_used', 'local_gb_used', 'free_ram_mb',
@@ -88,18 +85,16 @@ class HypervisorsController(wsgi.Controller):
):
hyp_dict[field] = getattr(hypervisor, field)
if api_version_request.is_supported(req, max_version='2.27'):
hyp_dict['cpu_info'] = hypervisor.cpu_info
else:
if api_version_request.is_supported(req, '2.28'):
if hypervisor.cpu_info:
hyp_dict['cpu_info'] = jsonutils.loads(hypervisor.cpu_info)
else:
hyp_dict['cpu_info'] = {}
else:
hyp_dict['cpu_info'] = hypervisor.cpu_info
# The 2.88 microversion also *added* the 'uptime' field to the response
if detail and api_version_request.is_supported(
req, min_version='2.88',
):
if detail and api_version_request.is_supported(req, '2.88'):
try:
hyp_dict['uptime'] = self.host_api.get_host_uptime(
req.environ['nova.context'], hypervisor.host)
@@ -121,9 +116,7 @@ class HypervisorsController(wsgi.Controller):
# The 2.75 microversion adds 'servers' field always in response.
# Empty list if there are no servers on hypervisors and it is
# requested in request.
elif with_servers and api_version_request.is_supported(
req, min_version='2.75',
):
elif with_servers and api_version_request.is_supported(req, '2.75'):
hyp_dict['servers'] = []
return hyp_dict
@@ -152,7 +145,7 @@ class HypervisorsController(wsgi.Controller):
# The 2.53 microversion moves the search and servers routes into
# GET /os-hypervisors and GET /os-hypervisors/detail with query
# 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')
with_servers = strutils.bool_from_string(
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
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):
msg = _('Invalid uuid %s') % hypervisor_id
raise webob.exc.HTTPBadRequest(explanation=msg)

View File

@@ -72,7 +72,7 @@ class InstanceActionsController(wsgi.Controller):
return event
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)
with utils.temporary_mutation(context, read_deleted='yes'):
@@ -119,7 +119,7 @@ class InstanceActionsController(wsgi.Controller):
except exception.MarkerNotFound as e:
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)
for action in actions_raw]
else:
@@ -150,7 +150,7 @@ class InstanceActionsController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=msg)
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)
else:
action = self._format_action(action, ACTION_KEYS)

View File

@@ -41,8 +41,10 @@ class LockServerController(wsgi.Controller):
target={'user_id': instance.user_id,
'project_id': instance.project_id})
reason = None
if (api_version_request.is_supported(req, min_version='2.73') and
body['lock'] is not None):
if (
api_version_request.is_supported(req, '2.73') and
body['lock'] is not None
):
reason = body['lock'].get('locked_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,
expected_attrs=['flavor', 'services'])
host_name = None
if (api_version_request.is_supported(req, min_version='2.56') and
body['migrate'] is not None):
if (
api_version_request.is_supported(req, '2.56') and
body['migrate'] is not None
):
host_name = body['migrate'].get('host')
if host_name:
@@ -111,10 +113,10 @@ class MigrateServerController(wsgi.Controller):
host = body["os-migrateLive"]["host"]
block_migration = body["os-migrateLive"]["block_migration"]
force = None
async_ = api_version_request.is_supported(req, min_version='2.34')
if api_version_request.is_supported(req, min_version='2.30'):
async_ = api_version_request.is_supported(req, '2.34')
if api_version_request.is_supported(req, '2.30'):
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':
block_migration = None
else:

View File

@@ -42,7 +42,7 @@ class ServerDiagnosticsController(wsgi.Controller):
target={'project_id': instance.project_id})
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(
context, instance)
return self._view_builder.instance_diagnostics(diagnostics)

View File

@@ -94,7 +94,7 @@ class ServerGroupController(wsgi.Controller):
server_group = {}
server_group['id'] = group.uuid
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['rules'] = group.rules
else:
@@ -109,7 +109,7 @@ class ServerGroupController(wsgi.Controller):
server_group['members'] = members
# Add project id information to the response data for
# 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['user_id'] = group.user_id
return server_group

View File

@@ -94,7 +94,7 @@ class ServerSharesController(wsgi.Controller):
@wsgi.Controller.api_version("2.97")
@wsgi.response(201)
@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)
def create(self, req, server_id, body):
def _try_create_share_mapping(context, share_mapping):

View File

@@ -146,8 +146,7 @@ class ServersController(wsgi.Controller):
@staticmethod
def _is_cell_down_supported(req, search_opts):
cell_down_support = api_version_request.is_supported(
req, min_version='2.69')
cell_down_support = api_version_request.is_supported(req, '2.69')
if cell_down_support:
# 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)
vm_state, task_state = states
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')
raise exc.HTTPBadRequest(explanation=msg)
@@ -264,7 +263,7 @@ class ServersController(wsgi.Controller):
msg = _("Only administrators may list deleted instances")
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:
if tag_filter in search_opts:
search_opts[tag_filter] = search_opts[
@@ -301,7 +300,7 @@ class ServersController(wsgi.Controller):
limit, marker = common.get_limit_and_marker(req)
sort_keys, sort_dirs = common.get_sort_params(req.params)
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
sort_keys, sort_dirs = remove_invalid_sort_keys(
context, sort_keys, sort_dirs, blacklist, ('host', 'node'))
@@ -462,10 +461,8 @@ class ServersController(wsgi.Controller):
def show(self, req, id):
"""Returns server details by server id."""
context = req.environ['nova.context']
cell_down_support = api_version_request.is_supported(
req, min_version='2.69')
show_server_groups = api_version_request.is_supported(
req, min_version='2.71')
cell_down_support = api_version_request.is_supported(req, '2.69')
show_server_groups = api_version_request.is_supported(req, '2.71')
instance = self._get_server(
context, req, id, is_detail=True,
@@ -687,10 +684,10 @@ class ServersController(wsgi.Controller):
password = self._get_server_admin_password(server_dict)
name = common.normalize_name(server_dict['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')
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')
# Arguments to be passed to instance create function
@@ -731,7 +728,7 @@ class ServersController(wsgi.Controller):
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')
helpers.translate_attributes(helpers.CREATE,
@@ -763,7 +760,7 @@ class ServersController(wsgi.Controller):
availability_zone = self._validate_host_availability_zone(
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,
create_kwargs, host, node)
@@ -919,8 +916,7 @@ class ServersController(wsgi.Controller):
ctxt.can(server_policies.SERVERS % 'update',
target={'user_id': instance.user_id,
'project_id': instance.project_id})
show_server_groups = api_version_request.is_supported(
req, min_version='2.71')
show_server_groups = api_version_request.is_supported(req, '2.71')
server = body['server']
@@ -943,8 +939,7 @@ class ServersController(wsgi.Controller):
# NOTE(gmann): Starting from microversion 2.75, PUT and Rebuild
# API response will show all attributes like GET /servers API.
show_all_attributes = api_version_request.is_supported(
req, min_version='2.75')
show_all_attributes = api_version_request.is_supported(req, '2.75')
extend_address = show_all_attributes
show_AZ = 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)
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
):
kwargs['key_name'] = rebuild_dict.get('key_name')
# If user_data is not specified, we don't include it in kwargs because
# we don't want to overwrite the existing user_data.
include_user_data = api_version_request.is_supported(
req, min_version='2.57')
include_user_data = api_version_request.is_supported(req, '2.57')
if include_user_data and 'user_data' in rebuild_dict:
kwargs['user_data'] = rebuild_dict['user_data']
# Skip policy check for 'rebuild:trusted_certs' if no trusted
# certificate IDs were provided.
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
# rebuild a user can unset/reset the trusted certs by
# specifying trusted_image_certificates=None, similar to
@@ -1250,12 +1244,12 @@ class ServersController(wsgi.Controller):
target=target)
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
):
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
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.
# from microversion 2.54 onwards.
show_keypair = api_version_request.is_supported(
req, min_version='2.54')
show_server_groups = api_version_request.is_supported(
req, min_version='2.71')
show_keypair = api_version_request.is_supported(req, '2.54')
show_server_groups = api_version_request.is_supported(req, '2.71')
# NOTE(gmann): Starting from microversion 2.75, PUT and Rebuild
# API response will show all attributes like GET /servers API.
show_all_attributes = api_version_request.is_supported(
req, min_version='2.75')
show_all_attributes = api_version_request.is_supported(req, '2.75')
extend_address = show_all_attributes
show_AZ = show_all_attributes
show_config_drive = show_all_attributes
@@ -1379,9 +1370,7 @@ class ServersController(wsgi.Controller):
metadata = entity.get('metadata', {})
# Starting from microversion 2.39 we don't check quotas on createImage
if api_version_request.is_supported(
req, max_version=
api_version_request.MAX_IMAGE_META_PROXY_API_VERSION):
if not api_version_request.is_supported(req, '2.39'):
common.check_img_metadata_properties_quota(context, metadata)
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
@@ -1443,20 +1432,20 @@ class ServersController(wsgi.Controller):
# probably not trivial.
opt_list = ('reservation_id', 'name', 'status', 'image', 'flavor',
'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',)
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
if api_version_request.is_supported(req, min_version='2.66'):
if api_version_request.is_supported(req, '2.66'):
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',)
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',
'created_at', 'launched_at', 'terminated_at',
'power_state', 'task_state', 'vm_state', 'progress',
'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',)
return opt_list

View File

@@ -58,8 +58,7 @@ class ServiceController(wsgi.Controller):
context = req.environ['nova.context']
cell_down_support = api_version_request.is_supported(
req, min_version='2.69')
cell_down_support = api_version_request.is_supported(req, '2.69')
_services = [
s
@@ -98,8 +97,7 @@ class ServiceController(wsgi.Controller):
active = 'disabled'
updated_time = self.servicegroup_api.get_updated_time(svc)
uuid_for_id = api_version_request.is_supported(
req, min_version='2.53')
uuid_for_id = api_version_request.is_supported(req, '2.53')
if 'availability_zone' not in svc:
# 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=()):
_services = self._get_services(req)
cell_down_support = api_version_request.is_supported(
req, min_version='2.69')
cell_down_support = api_version_request.is_supported(req, '2.69')
return [self._get_service_detail(svc, additional_fields, req,
cell_down_support=cell_down_support) for svc in _services]
@@ -248,7 +245,7 @@ class ServiceController(wsgi.Controller):
context = req.environ['nova.context']
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):
msg = _('Invalid uuid %s') % id
raise webob.exc.HTTPBadRequest(explanation=msg)
@@ -378,7 +375,7 @@ class ServiceController(wsgi.Controller):
"""
context = req.environ['nova.context']
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'])
else:
_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
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)
else:
return self._update_v21(req, id, body)
@@ -409,7 +406,7 @@ class ServiceController(wsgi.Controller):
def _update_v21(self, req, id, body):
context = req.environ['nova.context']
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["force-down"] = self._forced_down
else:

View File

@@ -16,9 +16,6 @@
from nova.api.openstack import api_version_request
from nova.api.openstack import common
FLAVOR_DESCRIPTION_MICROVERSION = '2.55'
FLAVOR_EXTRA_SPECS_MICROVERSION = '2.61'
class ViewBuilder(common.ViewBuilder):
@@ -78,16 +75,14 @@ class ViewBuilder(common.ViewBuilder):
def index(self, request, flavors):
"""Return the 'index' view of flavors."""
coll_name = self._collection_name
include_description = api_version_request.is_supported(
request, FLAVOR_DESCRIPTION_MICROVERSION)
include_description = api_version_request.is_supported(request, '2.55')
return self._list_view(self.basic, request, flavors, coll_name,
include_description=include_description)
def detail(self, request, flavors, include_extra_specs=False):
"""Return the 'detail' view of flavors."""
coll_name = self._collection_name + '/detail'
include_description = api_version_request.is_supported(
request, FLAVOR_DESCRIPTION_MICROVERSION)
include_description = api_version_request.is_supported(request, '2.55')
return self._list_view(self.show, request, flavors, coll_name,
include_description=include_description,
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,
# then figure it out here.
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']
show_extra_specs = context.can(
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
# with v2.0.
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)
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'] = (
self._get_scheduler_hints(
context, instance, provided_sched_hints))
@@ -364,7 +364,7 @@ class ViewBuilder(common.ViewBuilder):
if show_extended_attr:
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
# below and that's OK for microversion 2.3 which is being
# 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
# compat with v2.0.
add_delete_on_termination = api_version_request.is_supported(
request, min_version='2.3')
request, '2.3')
if bdms is None:
bdms = objects.BlockDeviceMappingList.bdms_by_instance_uuid(
context, [instance["uuid"]])
@@ -416,7 +416,7 @@ class ViewBuilder(common.ViewBuilder):
bdms,
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:
unknown_only = self._get_host_status_unknown_only(
context, instance)
@@ -435,22 +435,22 @@ class ViewBuilder(common.ViewBuilder):
host_status == fields.HostStatus.UNKNOWN):
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"]
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(
"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(
"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]
if api_version_request.is_supported(request, min_version="2.63"):
if api_version_request.is_supported(request, "2.63"):
trusted_certs = None
if instance.trusted_certs:
trusted_certs = instance.trusted_certs.ids
@@ -458,7 +458,7 @@ class ViewBuilder(common.ViewBuilder):
# TODO(stephenfin): Remove this check once we remove the
# 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
# it if it's not already added
if not show_extended_attr:
@@ -482,7 +482,7 @@ class ViewBuilder(common.ViewBuilder):
coll_name = self._collection_name + '/detail'
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
# once before we iterate the list of instances
show_extra_specs = context.can(
@@ -510,7 +510,7 @@ class ViewBuilder(common.ViewBuilder):
bdms=bdms,
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)
# If we're not allowed by policy to show host status at all, don't
# bother requesting instance host status from the compute API.
@@ -548,7 +548,7 @@ class ViewBuilder(common.ViewBuilder):
req_specs = None
req_specs_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']
instance_uuids = [s.uuid for s in servers]
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
for req in req_specs
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({
req.instance_uuid: req.scheduler_hints
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 = {}
for key, value in instance.system_metadata.items():
if key.startswith(utils.SM_IMAGE_PROP_PREFIX):
@@ -668,7 +668,7 @@ class ViewBuilder(common.ViewBuilder):
"from the DB", instance=instance)
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)
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):
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(
attr='vm_state',
instance_uuid=server_id,
@@ -496,8 +496,7 @@ class VolumeAttachmentController(wsgi.Controller):
@wsgi.response(202)
@wsgi.expected_errors((400, 404, 409))
@validation.schema(volumes_schema.update_volume_attachment, '2.0', '2.84')
@validation.schema(volumes_schema.update_volume_attachment_v285,
min_version='2.85')
@validation.schema(volumes_schema.update_volume_attachment_v285, '2.85')
def update(self, req, server_id, id, body):
context = req.environ['nova.context']
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.ctxt = context.RequestContext('fake', self.project_id)
def fake_is_supported(req, min_version="2.1", max_version="2.69"):
return (fakes.api_version.APIVersionRequest(max_version) >=
req.api_version_request >=
fakes.api_version.APIVersionRequest(min_version))
def fake_is_supported(req, version="2.1"):
return (req.api_version_request >=
fakes.api_version.APIVersionRequest(version))
self.stub_out('nova.api.openstack.api_version_request.is_supported',
fake_is_supported)

View File

@@ -127,40 +127,9 @@ class APIVersionRequestTests(test.NoDBTestCase):
self.assertRaises(ValueError,
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')
self.assertTrue(api_version_request.is_supported(
req, min_version='2.4'))
self.assertTrue(api_version_request.is_supported(
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'))
self.assertTrue(api_version_request.is_supported(req, '2.4'))
self.assertTrue(api_version_request.is_supported(req, '2.5'))
self.assertFalse(api_version_request.is_supported(req, '2.6'))