Consolidate image_href to image uuid validation code

The server rebuild and rescue APIs were using very similar
helper methods for parsing the image uuid out of the image_href
request parameter and also validating an image uuid was provided.

This moves that into a common utility method so we don't have
the copy/paste everywhere.

Change-Id: I7c38d576bbfc459f40eba75452cdfc97bdd9e724
This commit is contained in:
Matt Riedemann
2016-04-19 15:46:53 -04:00
parent 8a93fd1378
commit 938b71ce32
5 changed files with 48 additions and 56 deletions

View File

@@ -21,6 +21,7 @@ import re
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import strutils from oslo_utils import strutils
from oslo_utils import uuidutils
import six import six
import six.moves.urllib.parse as urlparse import six.moves.urllib.parse as urlparse
import webob import webob
@@ -567,3 +568,41 @@ def is_all_tenants(search_opts):
# The empty string is considered enabling all_tenants # The empty string is considered enabling all_tenants
all_tenants = 'all_tenants' in search_opts all_tenants = 'all_tenants' in search_opts
return all_tenants return all_tenants
def image_uuid_from_href(image_href, key):
"""If the image href was generated by nova api, strip image_href down to an
id and use the default glance connection params
:param image_href: URL or UUID for an image.
:param key: The request body key for the image_href value. This is used in
error messages.
:returns: The parsed image UUID.
:raises: webob.exc.HTTPBadRequest if the image_href does not have a valid
image UUID in it.
"""
if not image_href:
# NOTE(mriedem): This error message is copied from how our jsonschema
# validation error looks.
msg = _("Invalid input for field/attribute %(path)s. "
"Value: %(value)s. %(message)s") % {
'path': key, 'value': image_href,
'message': (
'Invalid image reference format. Specify the image '
'reference by UUID or full URL.')
}
raise exc.HTTPBadRequest(explanation=msg)
image_uuid = image_href.split('/').pop()
if not uuidutils.is_uuid_like(image_uuid):
msg = _("Invalid input for field/attribute %(path)s. "
"Value: %(value)s. %(message)s") % {
'path': key, 'value': image_href,
'message': (
'Invalid image reference format. Specify the image '
'reference by UUID or full URL.')
}
raise exc.HTTPBadRequest(explanation=msg)
return image_uuid

View File

@@ -14,7 +14,6 @@
"""The rescue mode extension.""" """The rescue mode extension."""
from oslo_utils import uuidutils
import webob import webob
from webob import exc from webob import exc
@@ -23,7 +22,6 @@ from nova.api.openstack import extensions as exts
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _
from nova import utils from nova import utils
@@ -36,15 +34,6 @@ class RescueController(wsgi.Controller):
self.compute_api = compute.API() self.compute_api = compute.API()
self.ext_mgr = ext_mgr self.ext_mgr = ext_mgr
def _rescue_image_validation(self, image_ref):
image_uuid = image_ref.split('/').pop()
if not uuidutils.is_uuid_like(image_uuid):
msg = _("Invalid rescue_image_ref provided.")
raise exc.HTTPBadRequest(explanation=msg)
return image_uuid
@wsgi.action('rescue') @wsgi.action('rescue')
def _rescue(self, req, id, body): def _rescue(self, req, id, body):
"""Rescue an instance.""" """Rescue an instance."""
@@ -61,8 +50,8 @@ class RescueController(wsgi.Controller):
rescue_image_ref = None rescue_image_ref = None
if self.ext_mgr.is_loaded("os-extended-rescue-with-image"): if self.ext_mgr.is_loaded("os-extended-rescue-with-image"):
if body['rescue'] and 'rescue_image_ref' in body['rescue']: if body['rescue'] and 'rescue_image_ref' in body['rescue']:
rescue_image_ref = self._rescue_image_validation( rescue_image_ref = common.image_uuid_from_href(
body['rescue']['rescue_image_ref']) body['rescue']['rescue_image_ref'], 'rescue_image_ref')
self.compute_api.rescue(context, instance, self.compute_api.rescue(context, instance,
rescue_password=password, rescue_image_ref=rescue_image_ref) rescue_password=password, rescue_image_ref=rescue_image_ref)
except exception.InstanceIsLocked as e: except exception.InstanceIsLocked as e:

View File

@@ -864,21 +864,6 @@ class Controller(wsgi.Controller):
msg = _("Missing imageRef attribute") msg = _("Missing imageRef attribute")
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
def _image_uuid_from_href(self, image_href):
if not image_href:
msg = _("Invalid imageRef provided.")
raise exc.HTTPBadRequest(explanation=msg)
# If the image href was generated by nova api, strip image_href
# down to an id and use the default glance connection params
image_uuid = image_href.split('/').pop()
if not uuidutils.is_uuid_like(image_uuid):
msg = _("Invalid imageRef provided.")
raise exc.HTTPBadRequest(explanation=msg)
return image_uuid
def _image_from_req_data(self, data): def _image_from_req_data(self, data):
"""Get image data from the request or raise appropriate """Get image data from the request or raise appropriate
exceptions exceptions
@@ -897,7 +882,7 @@ class Controller(wsgi.Controller):
return '' return ''
else: else:
image_href = self._image_ref_from_req_data(data) image_href = self._image_ref_from_req_data(data)
image_uuid = self._image_uuid_from_href(image_href) image_uuid = common.image_uuid_from_href(image_href, 'imageRef')
return image_uuid return image_uuid
def _flavor_id_from_req_data(self, data): def _flavor_id_from_req_data(self, data):
@@ -975,7 +960,7 @@ class Controller(wsgi.Controller):
msg = _("Could not parse imageRef from request.") msg = _("Could not parse imageRef from request.")
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
image_href = self._image_uuid_from_href(image_href) image_href = common.image_uuid_from_href(image_href, 'imageRef')
password = self._get_server_admin_password(body) password = self._get_server_admin_password(body)

View File

@@ -15,7 +15,6 @@
"""The rescue mode extension.""" """The rescue mode extension."""
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import uuidutils
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@@ -25,7 +24,6 @@ from nova.api.openstack import wsgi
from nova.api import validation from nova.api import validation
from nova import compute from nova import compute
from nova import exception from nova import exception
from nova.i18n import _
from nova import utils from nova import utils
@@ -42,15 +40,6 @@ class RescueController(wsgi.Controller):
super(RescueController, self).__init__(*args, **kwargs) super(RescueController, self).__init__(*args, **kwargs)
self.compute_api = compute.API(skip_policy_check=True) self.compute_api = compute.API(skip_policy_check=True)
def _rescue_image_validation(self, image_ref):
image_uuid = image_ref.split('/').pop()
if not uuidutils.is_uuid_like(image_uuid):
msg = _("Invalid rescue_image_ref provided.")
raise exc.HTTPBadRequest(explanation=msg)
return image_uuid
# TODO(cyeoh): Should be responding here with 202 Accept # TODO(cyeoh): Should be responding here with 202 Accept
# because rescue is an async call, but keep to 200 # because rescue is an async call, but keep to 200
# for backwards compatibility reasons. # for backwards compatibility reasons.
@@ -70,8 +59,8 @@ class RescueController(wsgi.Controller):
instance = common.get_instance(self.compute_api, context, id) instance = common.get_instance(self.compute_api, context, id)
rescue_image_ref = None rescue_image_ref = None
if body['rescue'] and 'rescue_image_ref' in body['rescue']: if body['rescue'] and 'rescue_image_ref' in body['rescue']:
rescue_image_ref = self._rescue_image_validation( rescue_image_ref = common.image_uuid_from_href(
body['rescue']['rescue_image_ref']) body['rescue']['rescue_image_ref'], 'rescue_image_ref')
try: try:
self.compute_api.rescue(context, instance, self.compute_api.rescue(context, instance,

View File

@@ -952,17 +952,6 @@ class ServersController(wsgi.Controller):
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'delete', id) 'delete', id)
def _image_uuid_from_href(self, image_href):
# If the image href was generated by nova api, strip image_href
# down to an id and use the default glance connection params
image_uuid = image_href.split('/').pop()
if not uuidutils.is_uuid_like(image_uuid):
msg = _("Invalid imageRef provided.")
raise exc.HTTPBadRequest(explanation=msg)
return image_uuid
def _image_from_req_data(self, server_dict, create_kwargs): def _image_from_req_data(self, server_dict, create_kwargs):
"""Get image data from the request or raise appropriate """Get image data from the request or raise appropriate
exceptions. exceptions.
@@ -975,7 +964,8 @@ class ServersController(wsgi.Controller):
if not image_href and create_kwargs.get('block_device_mapping'): if not image_href and create_kwargs.get('block_device_mapping'):
return '' return ''
elif image_href: elif image_href:
return self._image_uuid_from_href(six.text_type(image_href)) return common.image_uuid_from_href(six.text_type(image_href),
'imageRef')
else: else:
msg = _("Missing imageRef attribute") msg = _("Missing imageRef attribute")
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
@@ -1012,7 +1002,7 @@ class ServersController(wsgi.Controller):
rebuild_dict = body['rebuild'] rebuild_dict = body['rebuild']
image_href = rebuild_dict["imageRef"] image_href = rebuild_dict["imageRef"]
image_href = self._image_uuid_from_href(image_href) image_href = common.image_uuid_from_href(image_href, 'imageRef')
password = self._get_server_admin_password(rebuild_dict) password = self._get_server_admin_password(rebuild_dict)