Merge "Strict ImageRef validation to UUID only"
This commit is contained in:
@@ -2262,8 +2262,10 @@ image_status:
|
|||||||
type: string
|
type: string
|
||||||
imageRef:
|
imageRef:
|
||||||
description: |
|
description: |
|
||||||
The image reference, as a UUID or full URL, for the image to use for your server
|
The UUID of the image to use for your server instance.
|
||||||
instance.
|
This is not required in case of boot from volume.
|
||||||
|
In all other cases it is required and must be a valid UUID
|
||||||
|
otherwise API will return 400.
|
||||||
in: body
|
in: body
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"accessIPv6": "80fe::",
|
"accessIPv6": "80fe::",
|
||||||
"name" : "new-server-test",
|
"name" : "new-server-test",
|
||||||
"description" : "new-server-description",
|
"description" : "new-server-description",
|
||||||
"imageRef" : "http://glance.openstack.example.com/images/70a599e0-31e7-49b7-b260-868f441e862b",
|
"imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b",
|
||||||
"flavorRef" : "http://openstack.example.com/flavors/1",
|
"flavorRef" : "http://openstack.example.com/flavors/1",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"My Server Name" : "Apache1"
|
"My Server Name" : "Apache1"
|
||||||
|
@@ -20,7 +20,6 @@ import re
|
|||||||
|
|
||||||
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
|
||||||
@@ -548,41 +547,3 @@ 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
|
|
||||||
|
@@ -55,9 +55,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']:
|
||||||
rescue_image_ref = common.image_uuid_from_href(
|
rescue_image_ref = body['rescue'].get('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,
|
||||||
|
@@ -22,7 +22,7 @@ rescue = {
|
|||||||
'type': ['object', 'null'],
|
'type': ['object', 'null'],
|
||||||
'properties': {
|
'properties': {
|
||||||
'adminPass': parameter_types.admin_password,
|
'adminPass': parameter_types.admin_password,
|
||||||
'rescue_image_ref': parameter_types.image_ref,
|
'rescue_image_ref': parameter_types.image_id,
|
||||||
},
|
},
|
||||||
'additionalProperties': False,
|
'additionalProperties': False,
|
||||||
},
|
},
|
||||||
|
@@ -25,7 +25,12 @@ base_create = {
|
|||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'name': parameter_types.name,
|
'name': parameter_types.name,
|
||||||
'imageRef': parameter_types.image_ref,
|
# NOTE(gmann): In case of boot from volume, imageRef was
|
||||||
|
# allowed as the empty string also So keeping the same
|
||||||
|
# behavior and allow empty string in case of boot from
|
||||||
|
# volume only. Python code make sure empty string is
|
||||||
|
# not alowed for other cases.
|
||||||
|
'imageRef': parameter_types.image_id_or_empty_string,
|
||||||
'flavorRef': parameter_types.flavor_ref,
|
'flavorRef': parameter_types.flavor_ref,
|
||||||
'adminPass': parameter_types.admin_password,
|
'adminPass': parameter_types.admin_password,
|
||||||
'metadata': parameter_types.metadata,
|
'metadata': parameter_types.metadata,
|
||||||
@@ -108,7 +113,7 @@ base_rebuild = {
|
|||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
'name': parameter_types.name,
|
'name': parameter_types.name,
|
||||||
'imageRef': parameter_types.image_ref,
|
'imageRef': parameter_types.image_id,
|
||||||
'adminPass': parameter_types.admin_password,
|
'adminPass': parameter_types.admin_password,
|
||||||
'metadata': parameter_types.metadata,
|
'metadata': parameter_types.metadata,
|
||||||
'preserve_ephemeral': parameter_types.boolean,
|
'preserve_ephemeral': parameter_types.boolean,
|
||||||
|
@@ -874,8 +874,7 @@ 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 common.image_uuid_from_href(six.text_type(image_href),
|
return image_href
|
||||||
'imageRef')
|
|
||||||
else:
|
else:
|
||||||
msg = _("Missing imageRef attribute")
|
msg = _("Missing imageRef attribute")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
@@ -909,7 +908,6 @@ class ServersController(wsgi.Controller):
|
|||||||
rebuild_dict = body['rebuild']
|
rebuild_dict = body['rebuild']
|
||||||
|
|
||||||
image_href = rebuild_dict["imageRef"]
|
image_href = rebuild_dict["imageRef"]
|
||||||
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)
|
||||||
|
|
||||||
|
@@ -269,6 +269,14 @@ image_id = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
image_id_or_empty_string = {
|
||||||
|
'oneOf': [
|
||||||
|
{'type': 'string', 'format': 'uuid'},
|
||||||
|
{'type': 'string', 'maxLength': 0}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
volume_id = {
|
volume_id = {
|
||||||
'type': 'string', 'format': 'uuid'
|
'type': 'string', 'format': 'uuid'
|
||||||
}
|
}
|
||||||
@@ -294,11 +302,6 @@ admin_password = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
image_ref = {
|
|
||||||
'type': 'string',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
flavor_ref = {
|
flavor_ref = {
|
||||||
'type': ['string', 'integer'], 'minLength': 1
|
'type': ['string', 'integer'], 'minLength': 1
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"accessIPv6": "%(access_ip_v6)s",
|
"accessIPv6": "%(access_ip_v6)s",
|
||||||
"name" : "new-server-test",
|
"name" : "new-server-test",
|
||||||
"description" : "new-server-description",
|
"description" : "new-server-description",
|
||||||
"imageRef" : "%(glance_host)s/images/%(image_id)s",
|
"imageRef" : "%(image_id)s",
|
||||||
"flavorRef" : "%(host)s/flavors/1",
|
"flavorRef" : "%(host)s/flavors/1",
|
||||||
"metadata" : {
|
"metadata" : {
|
||||||
"My Server Name" : "Apache1"
|
"My Server Name" : "Apache1"
|
||||||
|
@@ -120,24 +120,11 @@ class _IntegratedTestBase(test.TestCase):
|
|||||||
def get_invalid_image(self):
|
def get_invalid_image(self):
|
||||||
return str(uuid.uuid4())
|
return str(uuid.uuid4())
|
||||||
|
|
||||||
def _get_any_image_href(self):
|
|
||||||
image = self.api.get_images()[0]
|
|
||||||
LOG.debug("Image: %s" % image)
|
|
||||||
|
|
||||||
if self._image_ref_parameter in image:
|
|
||||||
image_href = image[self._image_ref_parameter]
|
|
||||||
else:
|
|
||||||
image_href = image['id']
|
|
||||||
image_href = 'http://fake.server/%s' % image_href
|
|
||||||
return image_href
|
|
||||||
|
|
||||||
def _build_minimal_create_server_request(self):
|
def _build_minimal_create_server_request(self):
|
||||||
server = {}
|
server = {}
|
||||||
|
|
||||||
image_href = self._get_any_image_href()
|
|
||||||
|
|
||||||
# We now have a valid imageId
|
# We now have a valid imageId
|
||||||
server[self._image_ref_parameter] = image_href
|
server[self._image_ref_parameter] = self.api.get_images()[0]['id']
|
||||||
|
|
||||||
# Set a valid flavorId
|
# Set a valid flavorId
|
||||||
flavor = self.api.get_flavors()[0]
|
flavor = self.api.get_flavors()[0]
|
||||||
@@ -181,19 +168,11 @@ class _IntegratedTestBase(test.TestCase):
|
|||||||
|
|
||||||
def _build_server(self, flavor_id):
|
def _build_server(self, flavor_id):
|
||||||
server = {}
|
server = {}
|
||||||
|
|
||||||
image_href = self._get_any_image_href()
|
|
||||||
image = self.api.get_images()[0]
|
image = self.api.get_images()[0]
|
||||||
LOG.debug("Image: %s" % image)
|
LOG.debug("Image: %s" % image)
|
||||||
|
|
||||||
if self._image_ref_parameter in image:
|
|
||||||
image_href = image[self._image_ref_parameter]
|
|
||||||
else:
|
|
||||||
image_href = image['id']
|
|
||||||
image_href = 'http://fake.server/%s' % image_href
|
|
||||||
|
|
||||||
# We now have a valid imageId
|
# We now have a valid imageId
|
||||||
server[self._image_ref_parameter] = image_href
|
server[self._image_ref_parameter] = image['id']
|
||||||
|
|
||||||
# Set a valid flavorId
|
# Set a valid flavorId
|
||||||
flavor = self.api.get_flavor(flavor_id)
|
flavor = self.api.get_flavor(flavor_id)
|
||||||
@@ -243,19 +222,8 @@ class InstanceHelperMixin(object):
|
|||||||
flavor_id=None):
|
flavor_id=None):
|
||||||
server = {}
|
server = {}
|
||||||
|
|
||||||
if image_uuid:
|
|
||||||
image_href = 'http://fake.server/%s' % image_uuid
|
|
||||||
else:
|
|
||||||
image = api.get_images()[0]
|
|
||||||
|
|
||||||
if 'imageRef' in image:
|
|
||||||
image_href = image['imageRef']
|
|
||||||
else:
|
|
||||||
image_href = image['id']
|
|
||||||
image_href = 'http://fake.server/%s' % image_href
|
|
||||||
|
|
||||||
# We now have a valid imageId
|
# We now have a valid imageId
|
||||||
server['imageRef'] = image_href
|
server['imageRef'] = image_uuid or api.get_images()[0]['id']
|
||||||
|
|
||||||
if not flavor_id:
|
if not flavor_id:
|
||||||
# Set a valid flavorId
|
# Set a valid flavorId
|
||||||
|
@@ -148,6 +148,44 @@ class BlockDeviceMappingTestV21(test.TestCase):
|
|||||||
params = {block_device_mapping.ATTRIBUTE_NAME: self.bdm}
|
params = {block_device_mapping.ATTRIBUTE_NAME: self.bdm}
|
||||||
self._test_create(params, no_image=True)
|
self._test_create(params, no_image=True)
|
||||||
|
|
||||||
|
@mock.patch.object(compute_api.API, '_validate_bdm')
|
||||||
|
@mock.patch.object(compute_api.API, '_get_bdm_image_metadata')
|
||||||
|
def test_create_instance_with_bdms_and_empty_imageRef(
|
||||||
|
self, mock_bdm_image_metadata, mock_validate_bdm):
|
||||||
|
mock_bdm_image_metadata.return_value = {}
|
||||||
|
mock_validate_bdm.return_value = True
|
||||||
|
old_create = compute_api.API.create
|
||||||
|
|
||||||
|
def create(*args, **kwargs):
|
||||||
|
self.assertThat(
|
||||||
|
block_device.BlockDeviceDict(self.bdm[0]),
|
||||||
|
matchers.DictMatches(kwargs['block_device_mapping'][0])
|
||||||
|
)
|
||||||
|
return old_create(*args, **kwargs)
|
||||||
|
|
||||||
|
self.stub_out('nova.compute.api.API.create', create)
|
||||||
|
|
||||||
|
params = {block_device_mapping.ATTRIBUTE_NAME: self.bdm,
|
||||||
|
'imageRef': ''}
|
||||||
|
self._test_create(params)
|
||||||
|
|
||||||
|
def test_create_instance_with_imageRef_as_full_url(self):
|
||||||
|
bdm = [{'device_name': 'foo'}]
|
||||||
|
image_href = ('http://localhost/v2/fake/images/'
|
||||||
|
'76fa36fc-c930-4bf3-8c8a-ea2a2420deb6')
|
||||||
|
params = {block_device_mapping.ATTRIBUTE_NAME: bdm,
|
||||||
|
'imageRef': image_href}
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self._test_create, params)
|
||||||
|
|
||||||
|
def test_create_instance_with_non_uuid_imageRef(self):
|
||||||
|
bdm = [{'device_name': 'foo'}]
|
||||||
|
|
||||||
|
params = {block_device_mapping.ATTRIBUTE_NAME: bdm,
|
||||||
|
'imageRef': '123123abcd'}
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self._test_create, params)
|
||||||
|
|
||||||
def test_create_instance_with_device_name_not_string(self):
|
def test_create_instance_with_device_name_not_string(self):
|
||||||
self.bdm[0]['device_name'] = 123
|
self.bdm[0]['device_name'] = 123
|
||||||
old_create = compute_api.API.create
|
old_create = compute_api.API.create
|
||||||
|
@@ -140,6 +140,51 @@ class BlockDeviceMappingTestV21(test.TestCase):
|
|||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
self._test_create(params, no_image=True)
|
self._test_create(params, no_image=True)
|
||||||
|
|
||||||
|
@mock.patch.object(compute_api.API, '_validate_bdm')
|
||||||
|
@mock.patch.object(compute_api.API, '_get_bdm_image_metadata')
|
||||||
|
def test_create_instance_with_imageRef_as_empty_string(
|
||||||
|
self, mock_bdm_image_metadata, mock_validate_bdm):
|
||||||
|
volume = {
|
||||||
|
'id': uuids.volume_id,
|
||||||
|
'status': 'active',
|
||||||
|
'volume_image_metadata':
|
||||||
|
{'test_key': 'test_value'}
|
||||||
|
}
|
||||||
|
mock_bdm_image_metadata.return_value = volume
|
||||||
|
mock_validate_bdm.return_value = True
|
||||||
|
params = {'block_device_mapping': self.bdm,
|
||||||
|
'imageRef': ''}
|
||||||
|
old_create = compute_api.API.create
|
||||||
|
|
||||||
|
def create(*args, **kwargs):
|
||||||
|
self.assertEqual(kwargs['block_device_mapping'], self.bdm)
|
||||||
|
return old_create(*args, **kwargs)
|
||||||
|
|
||||||
|
self.stub_out('nova.compute.api.API.create', create)
|
||||||
|
self._test_create(params)
|
||||||
|
|
||||||
|
def test_create_instance_with_imageRef_as_full_url(self):
|
||||||
|
bdm = [{
|
||||||
|
'volume_id': self.volume_id,
|
||||||
|
'device_name': 'vda'
|
||||||
|
}]
|
||||||
|
image_href = ('http://localhost/v2/fake/images/'
|
||||||
|
'76fa36fc-c930-4bf3-8c8a-ea2a2420deb6')
|
||||||
|
params = {'block_device_mapping': bdm,
|
||||||
|
'imageRef': image_href}
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self._test_create, params)
|
||||||
|
|
||||||
|
def test_create_instance_with_non_uuid_imageRef(self):
|
||||||
|
bdm = [{
|
||||||
|
'volume_id': self.volume_id,
|
||||||
|
'device_name': 'vda'
|
||||||
|
}]
|
||||||
|
params = {'block_device_mapping': bdm,
|
||||||
|
'imageRef': 'bad-format'}
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self._test_create, params)
|
||||||
|
|
||||||
def test_create_instance_with_volumes_disabled(self):
|
def test_create_instance_with_volumes_disabled(self):
|
||||||
bdm = [{'device_name': 'foo'}]
|
bdm = [{'device_name': 'foo'}]
|
||||||
params = {'block_device_mapping': bdm}
|
params = {'block_device_mapping': bdm}
|
||||||
|
@@ -43,7 +43,6 @@ def fake_compute_get(*args, **kwargs):
|
|||||||
class RescueTestV21(test.NoDBTestCase):
|
class RescueTestV21(test.NoDBTestCase):
|
||||||
|
|
||||||
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||||
image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(RescueTestV21, self).setUp()
|
super(RescueTestV21, self).setUp()
|
||||||
@@ -139,11 +138,26 @@ class RescueTestV21(test.NoDBTestCase):
|
|||||||
self.controller._rescue,
|
self.controller._rescue,
|
||||||
self.fake_req, UUID, body=body)
|
self.fake_req, UUID, body=body)
|
||||||
|
|
||||||
@mock.patch('nova.compute.api.API.rescue')
|
def test_rescue_with_bad_image_specified(self):
|
||||||
def test_rescue_with_bad_image_specified(self, mock_compute_api_rescue):
|
|
||||||
body = {"rescue": {"adminPass": "ABC123",
|
body = {"rescue": {"adminPass": "ABC123",
|
||||||
"rescue_image_ref": "img-id"}}
|
"rescue_image_ref": "img-id"}}
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self.controller._rescue,
|
||||||
|
self.fake_req, UUID, body=body)
|
||||||
|
|
||||||
|
def test_rescue_with_imageRef_as_full_url(self):
|
||||||
|
image_href = ('http://localhost/v2/fake/images/'
|
||||||
|
'76fa36fc-c930-4bf3-8c8a-ea2a2420deb6')
|
||||||
|
body = {"rescue": {"adminPass": "ABC123",
|
||||||
|
"rescue_image_ref": image_href}}
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self.controller._rescue,
|
||||||
|
self.fake_req, UUID, body=body)
|
||||||
|
|
||||||
|
def test_rescue_with_imageRef_as_empty_string(self):
|
||||||
|
body = {"rescue": {"adminPass": "ABC123",
|
||||||
|
"rescue_image_ref": ''}}
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
self.controller._rescue,
|
self.controller._rescue,
|
||||||
self.fake_req, UUID, body=body)
|
self.fake_req, UUID, body=body)
|
||||||
|
|
||||||
@@ -151,7 +165,7 @@ class RescueTestV21(test.NoDBTestCase):
|
|||||||
def test_rescue_with_image_specified(self, mock_compute_api_rescue):
|
def test_rescue_with_image_specified(self, mock_compute_api_rescue):
|
||||||
instance = fake_compute_get()
|
instance = fake_compute_get()
|
||||||
body = {"rescue": {"adminPass": "ABC123",
|
body = {"rescue": {"adminPass": "ABC123",
|
||||||
"rescue_image_ref": self.image_href}}
|
"rescue_image_ref": self.image_uuid}}
|
||||||
resp_json = self.controller._rescue(self.fake_req, UUID, body=body)
|
resp_json = self.controller._rescue(self.fake_req, UUID, body=body)
|
||||||
self.assertEqual("ABC123", resp_json['adminPass'])
|
self.assertEqual("ABC123", resp_json['adminPass'])
|
||||||
|
|
||||||
|
@@ -338,15 +338,6 @@ class ServerActionsControllerTestV21(test.TestCase):
|
|||||||
self.assertEqual(info['image_href_in_call'], self.image_uuid)
|
self.assertEqual(info['image_href_in_call'], self.image_uuid)
|
||||||
|
|
||||||
def test_rebuild_instance_with_image_href_uses_uuid(self):
|
def test_rebuild_instance_with_image_href_uses_uuid(self):
|
||||||
info = dict(image_href_in_call=None)
|
|
||||||
|
|
||||||
def rebuild(self2, context, instance, image_href, *args, **kwargs):
|
|
||||||
info['image_href_in_call'] = image_href
|
|
||||||
|
|
||||||
self.stub_out('nova.db.instance_get',
|
|
||||||
fakes.fake_instance_get(vm_state=vm_states.ACTIVE))
|
|
||||||
self.stubs.Set(compute_api.API, 'rebuild', rebuild)
|
|
||||||
|
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
# proper local hrefs must start with 'http://localhost/v2/'
|
||||||
body = {
|
body = {
|
||||||
'rebuild': {
|
'rebuild': {
|
||||||
@@ -354,8 +345,9 @@ class ServerActionsControllerTestV21(test.TestCase):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self.controller._action_rebuild(self.req, FAKE_UUID, body=body)
|
self.assertRaises(exception.ValidationError,
|
||||||
self.assertEqual(info['image_href_in_call'], self.image_uuid)
|
self.controller._action_rebuild,
|
||||||
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
def test_rebuild_accepted_minimum_pass_disabled(self):
|
def test_rebuild_accepted_minimum_pass_disabled(self):
|
||||||
# run with enable_instance_password disabled to verify adminPass
|
# run with enable_instance_password disabled to verify adminPass
|
||||||
@@ -517,7 +509,7 @@ class ServerActionsControllerTestV21(test.TestCase):
|
|||||||
"imageRef": "foo",
|
"imageRef": "foo",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(exception.ValidationError,
|
||||||
self.controller._action_rebuild,
|
self.controller._action_rebuild,
|
||||||
self.req, FAKE_UUID, body=body)
|
self.req, FAKE_UUID, body=body)
|
||||||
|
|
||||||
|
@@ -1576,7 +1576,6 @@ class ServersControllerDeleteTest(ControllerTest):
|
|||||||
class ServersControllerRebuildInstanceTest(ControllerTest):
|
class ServersControllerRebuildInstanceTest(ControllerTest):
|
||||||
|
|
||||||
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||||
image_href = 'http://localhost/v2/fake/images/%s' % image_uuid
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(ServersControllerRebuildInstanceTest, self).setUp()
|
super(ServersControllerRebuildInstanceTest, self).setUp()
|
||||||
@@ -1599,7 +1598,7 @@ class ServersControllerRebuildInstanceTest(ControllerTest):
|
|||||||
self.body = {
|
self.body = {
|
||||||
'rebuild': {
|
'rebuild': {
|
||||||
'name': 'new_name',
|
'name': 'new_name',
|
||||||
'imageRef': self.image_href,
|
'imageRef': self.image_uuid,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'open': 'stack',
|
'open': 'stack',
|
||||||
},
|
},
|
||||||
@@ -1609,6 +1608,29 @@ class ServersControllerRebuildInstanceTest(ControllerTest):
|
|||||||
self.req.method = 'POST'
|
self.req.method = 'POST'
|
||||||
self.req.headers["content-type"] = "application/json"
|
self.req.headers["content-type"] = "application/json"
|
||||||
|
|
||||||
|
def test_rebuild_server_with_image_not_uuid(self):
|
||||||
|
self.body['rebuild']['imageRef'] = 'not-uuid'
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self.controller._action_rebuild,
|
||||||
|
self.req, FAKE_UUID,
|
||||||
|
body=self.body)
|
||||||
|
|
||||||
|
def test_rebuild_server_with_image_as_full_url(self):
|
||||||
|
image_href = ('http://localhost/v2/fake/images/'
|
||||||
|
'76fa36fc-c930-4bf3-8c8a-ea2a2420deb6')
|
||||||
|
self.body['rebuild']['imageRef'] = image_href
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self.controller._action_rebuild,
|
||||||
|
self.req, FAKE_UUID,
|
||||||
|
body=self.body)
|
||||||
|
|
||||||
|
def test_rebuild_server_with_image_as_empty_string(self):
|
||||||
|
self.body['rebuild']['imageRef'] = ''
|
||||||
|
self.assertRaises(exception.ValidationError,
|
||||||
|
self.controller._action_rebuild,
|
||||||
|
self.req, FAKE_UUID,
|
||||||
|
body=self.body)
|
||||||
|
|
||||||
def test_rebuild_instance_name_with_spaces_in_the_middle(self):
|
def test_rebuild_instance_name_with_spaces_in_the_middle(self):
|
||||||
self.body['rebuild']['name'] = 'abc def'
|
self.body['rebuild']['name'] = 'abc def'
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
@@ -1756,7 +1778,7 @@ class ServersControllerRebuildInstanceTest(ControllerTest):
|
|||||||
def test_rebuild_bad_personality(self):
|
def test_rebuild_bad_personality(self):
|
||||||
body = {
|
body = {
|
||||||
"rebuild": {
|
"rebuild": {
|
||||||
"imageRef": self.image_href,
|
"imageRef": self.image_uuid,
|
||||||
"personality": [{
|
"personality": [{
|
||||||
"path": "/path/to/file",
|
"path": "/path/to/file",
|
||||||
"contents": "INVALID b64",
|
"contents": "INVALID b64",
|
||||||
@@ -1771,7 +1793,7 @@ class ServersControllerRebuildInstanceTest(ControllerTest):
|
|||||||
def test_rebuild_personality(self):
|
def test_rebuild_personality(self):
|
||||||
body = {
|
body = {
|
||||||
"rebuild": {
|
"rebuild": {
|
||||||
"imageRef": self.image_href,
|
"imageRef": self.image_uuid,
|
||||||
"personality": [{
|
"personality": [{
|
||||||
"path": "/path/to/file",
|
"path": "/path/to/file",
|
||||||
"contents": base64.b64encode("Test String"),
|
"contents": base64.b64encode("Test String"),
|
||||||
@@ -2442,10 +2464,9 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self.assertRaises(webob.exc.HTTPBadRequest, self._test_create_instance,
|
self.assertRaises(webob.exc.HTTPBadRequest, self._test_create_instance,
|
||||||
flavor=1324)
|
flavor=1324)
|
||||||
|
|
||||||
def test_create_server_bad_image_href(self):
|
def test_create_server_bad_image_uuid(self):
|
||||||
image_href = 1
|
|
||||||
self.body['server']['min_count'] = 1
|
self.body['server']['min_count'] = 1
|
||||||
self.body['server']['imageRef'] = image_href,
|
self.body['server']['imageRef'] = 1,
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError,
|
self.assertRaises(exception.ValidationError,
|
||||||
self.controller.create,
|
self.controller.create,
|
||||||
@@ -2510,23 +2531,24 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
"Flavor's disk is too small for requested image."):
|
"Flavor's disk is too small for requested image."):
|
||||||
self.controller.create(self.req, body=self.body)
|
self.controller.create(self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_image_ref_is_bookmark(self):
|
def test_create_instance_with_image_non_uuid(self):
|
||||||
image_href = 'http://localhost/fake/images/%s' % self.image_uuid
|
self.body['server']['imageRef'] = 'not-uuid'
|
||||||
self.body['server']['imageRef'] = image_href
|
self.assertRaises(exception.ValidationError,
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.controller.create,
|
||||||
res = self.controller.create(self.req, body=self.body).obj
|
self.req, body=self.body)
|
||||||
|
|
||||||
server = res['server']
|
def test_create_instance_with_image_as_full_url(self):
|
||||||
self.assertEqual(FAKE_UUID, server['id'])
|
image_href = ('http://localhost/v2/fake/images/'
|
||||||
|
'76fa36fc-c930-4bf3-8c8a-ea2a2420deb6')
|
||||||
def test_create_instance_image_ref_is_invalid(self):
|
|
||||||
image_uuid = 'this_is_not_a_valid_uuid'
|
|
||||||
image_href = 'http://localhost/fake/images/%s' % image_uuid
|
|
||||||
flavor_ref = 'http://localhost/fake/flavors/3'
|
|
||||||
self.body['server']['imageRef'] = image_href
|
self.body['server']['imageRef'] = image_href
|
||||||
self.body['server']['flavorRef'] = flavor_ref
|
self.assertRaises(exception.ValidationError,
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.controller.create,
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create,
|
self.req, body=self.body)
|
||||||
|
|
||||||
|
def test_create_instance_with_image_as_empty_string(self):
|
||||||
|
self.body['server']['imageRef'] = ''
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
|
self.controller.create,
|
||||||
self.req, body=self.body)
|
self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_no_key_pair(self):
|
def test_create_instance_no_key_pair(self):
|
||||||
@@ -2687,10 +2709,7 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
# test with admin passwords disabled See lp bug 921814
|
# test with admin passwords disabled See lp bug 921814
|
||||||
self.flags(enable_instance_password=False)
|
self.flags(enable_instance_password=False)
|
||||||
|
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
self.flags(enable_instance_password=False)
|
self.flags(enable_instance_password=False)
|
||||||
image_href = 'http://localhost/v2/fake/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
res = self.controller.create(self.req, body=self.body).obj
|
res = self.controller.create(self.req, body=self.body).obj
|
||||||
|
|
||||||
@@ -2699,50 +2718,36 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self.assertEqual(FAKE_UUID, server['id'])
|
self.assertEqual(FAKE_UUID, server['id'])
|
||||||
|
|
||||||
def test_create_instance_name_too_long(self):
|
def test_create_instance_name_too_long(self):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['name'] = 'X' * 256
|
self.body['server']['name'] = 'X' * 256
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError, self.controller.create,
|
self.assertRaises(exception.ValidationError, self.controller.create,
|
||||||
self.req, body=self.body)
|
self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_name_with_spaces_in_the_middle(self):
|
def test_create_instance_name_with_spaces_in_the_middle(self):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['name'] = 'abc def'
|
self.body['server']['name'] = 'abc def'
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.controller.create(self.req, body=self.body)
|
self.controller.create(self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_name_with_leading_trailing_spaces(self):
|
def test_create_instance_name_with_leading_trailing_spaces(self):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['name'] = ' abc def '
|
self.body['server']['name'] = ' abc def '
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError,
|
self.assertRaises(exception.ValidationError,
|
||||||
self.controller.create, self.req, body=self.body)
|
self.controller.create, self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_name_with_leading_trailing_spaces_in_compat_mode(
|
def test_create_instance_name_with_leading_trailing_spaces_in_compat_mode(
|
||||||
self):
|
self):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['name'] = ' abc def '
|
self.body['server']['name'] = ' abc def '
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.req.set_legacy_v2()
|
self.req.set_legacy_v2()
|
||||||
self.controller.create(self.req, body=self.body)
|
self.controller.create(self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_name_all_blank_spaces(self):
|
def test_create_instance_name_all_blank_spaces(self):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||||
image_href = 'http://localhost/v2/images/%s' % image_uuid
|
|
||||||
flavor_ref = 'http://localhost/fake/flavors/3'
|
flavor_ref = 'http://localhost/fake/flavors/3'
|
||||||
body = {
|
body = {
|
||||||
'server': {
|
'server': {
|
||||||
'name': ' ' * 64,
|
'name': ' ' * 64,
|
||||||
'imageRef': image_href,
|
'imageRef': image_uuid,
|
||||||
'flavorRef': flavor_ref,
|
'flavorRef': flavor_ref,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'hello': 'world',
|
'hello': 'world',
|
||||||
@@ -2759,9 +2764,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self.controller.create, req, body=body)
|
self.controller.create, req, body=body)
|
||||||
|
|
||||||
def test_create_az_with_leading_trailing_spaces(self):
|
def test_create_az_with_leading_trailing_spaces(self):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['availability_zone'] = ' zone1 '
|
self.body['server']['availability_zone'] = ' zone1 '
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError,
|
self.assertRaises(exception.ValidationError,
|
||||||
@@ -2769,10 +2771,7 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_az_with_leading_trailing_spaces_in_compat_mode(
|
def test_create_az_with_leading_trailing_spaces_in_compat_mode(
|
||||||
self):
|
self):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['name'] = ' abc def '
|
self.body['server']['name'] = ' abc def '
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['availability_zones'] = ' zone1 '
|
self.body['server']['availability_zones'] = ' zone1 '
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.req.set_legacy_v2()
|
self.req.set_legacy_v2()
|
||||||
@@ -2781,9 +2780,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self.controller.create(self.req, body=self.body)
|
self.controller.create(self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance(self):
|
def test_create_instance(self):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
res = self.controller.create(self.req, body=self.body).obj
|
res = self.controller.create(self.req, body=self.body).obj
|
||||||
|
|
||||||
@@ -2798,14 +2794,12 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
self.stubs.Set(keypairs.Keypairs, 'server_create',
|
self.stubs.Set(keypairs.Keypairs, 'server_create',
|
||||||
fake_keypair_server_create)
|
fake_keypair_server_create)
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
image_uuid = '76fa36fc-c930-4bf3-8c8a-ea2a2420deb6'
|
||||||
image_href = 'http://localhost/v2/images/%s' % image_uuid
|
|
||||||
flavor_ref = 'http://localhost/123/flavors/3'
|
flavor_ref = 'http://localhost/123/flavors/3'
|
||||||
body = {
|
body = {
|
||||||
'server': {
|
'server': {
|
||||||
'name': 'server_test',
|
'name': 'server_test',
|
||||||
'imageRef': image_href,
|
'imageRef': image_uuid,
|
||||||
'flavorRef': flavor_ref,
|
'flavorRef': flavor_ref,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'hello': 'world',
|
'hello': 'world',
|
||||||
@@ -2823,9 +2817,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_instance_pass_disabled(self):
|
def test_create_instance_pass_disabled(self):
|
||||||
self.flags(enable_instance_password=False)
|
self.flags(enable_instance_password=False)
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
res = self.controller.create(self.req, body=self.body).obj
|
res = self.controller.create(self.req, body=self.body).obj
|
||||||
|
|
||||||
@@ -2842,8 +2833,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
'cpuset': None,
|
'cpuset': None,
|
||||||
'memsize': 0,
|
'memsize': 0,
|
||||||
'memtotal': 0})
|
'memtotal': 0})
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
self.controller.create, self.req, body=self.body)
|
self.controller.create, self.req, body=self.body)
|
||||||
@@ -2860,8 +2849,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_instance_too_much_metadata(self):
|
def test_create_instance_too_much_metadata(self):
|
||||||
self.flags(quota_metadata_items=1)
|
self.flags(quota_metadata_items=1)
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['metadata']['vote'] = 'fiddletown'
|
self.body['server']['metadata']['vote'] = 'fiddletown'
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(webob.exc.HTTPForbidden,
|
self.assertRaises(webob.exc.HTTPForbidden,
|
||||||
@@ -2869,8 +2856,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_instance_metadata_key_too_long(self):
|
def test_create_instance_metadata_key_too_long(self):
|
||||||
self.flags(quota_metadata_items=1)
|
self.flags(quota_metadata_items=1)
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['metadata'] = {('a' * 260): '12345'}
|
self.body['server']['metadata'] = {('a' * 260): '12345'}
|
||||||
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
@@ -2879,8 +2864,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_instance_metadata_value_too_long(self):
|
def test_create_instance_metadata_value_too_long(self):
|
||||||
self.flags(quota_metadata_items=1)
|
self.flags(quota_metadata_items=1)
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['metadata'] = {'key1': ('a' * 260)}
|
self.body['server']['metadata'] = {'key1': ('a' * 260)}
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError,
|
self.assertRaises(exception.ValidationError,
|
||||||
@@ -2888,8 +2871,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_instance_metadata_key_blank(self):
|
def test_create_instance_metadata_key_blank(self):
|
||||||
self.flags(quota_metadata_items=1)
|
self.flags(quota_metadata_items=1)
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['metadata'] = {'': 'abcd'}
|
self.body['server']['metadata'] = {'': 'abcd'}
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError,
|
self.assertRaises(exception.ValidationError,
|
||||||
@@ -2897,8 +2878,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_instance_metadata_not_dict(self):
|
def test_create_instance_metadata_not_dict(self):
|
||||||
self.flags(quota_metadata_items=1)
|
self.flags(quota_metadata_items=1)
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['metadata'] = 'string'
|
self.body['server']['metadata'] = 'string'
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError,
|
self.assertRaises(exception.ValidationError,
|
||||||
@@ -2906,8 +2885,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_instance_metadata_key_not_string(self):
|
def test_create_instance_metadata_key_not_string(self):
|
||||||
self.flags(quota_metadata_items=1)
|
self.flags(quota_metadata_items=1)
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['metadata'] = {1: 'test'}
|
self.body['server']['metadata'] = {1: 'test'}
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError,
|
self.assertRaises(exception.ValidationError,
|
||||||
@@ -2915,8 +2892,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
def test_create_instance_metadata_value_not_string(self):
|
def test_create_instance_metadata_value_not_string(self):
|
||||||
self.flags(quota_metadata_items=1)
|
self.flags(quota_metadata_items=1)
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['metadata'] = {'test': ['a', 'list']}
|
self.body['server']['metadata'] = {'test': ['a', 'list']}
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(exception.ValidationError,
|
self.assertRaises(exception.ValidationError,
|
||||||
@@ -2928,8 +2903,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self._test_create_extra, params)
|
self._test_create_extra, params)
|
||||||
|
|
||||||
def test_create_instance_invalid_key_name(self):
|
def test_create_instance_invalid_key_name(self):
|
||||||
image_href = 'http://localhost/v2/images/2'
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['key_name'] = 'nonexistentkey'
|
self.body['server']['key_name'] = 'nonexistentkey'
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
@@ -2944,18 +2917,14 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self._check_admin_password_len(res["server"])
|
self._check_admin_password_len(res["server"])
|
||||||
|
|
||||||
def test_create_instance_invalid_flavor_href(self):
|
def test_create_instance_invalid_flavor_href(self):
|
||||||
image_href = 'http://localhost/v2/images/2'
|
|
||||||
flavor_ref = 'http://localhost/v2/flavors/asdf'
|
flavor_ref = 'http://localhost/v2/flavors/asdf'
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['flavorRef'] = flavor_ref
|
self.body['server']['flavorRef'] = flavor_ref
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
self.controller.create, self.req, body=self.body)
|
self.controller.create, self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_invalid_flavor_id_int(self):
|
def test_create_instance_invalid_flavor_id_int(self):
|
||||||
image_href = 'http://localhost/v2/images/2'
|
|
||||||
flavor_ref = -1
|
flavor_ref = -1
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['flavorRef'] = flavor_ref
|
self.body['server']['flavorRef'] = flavor_ref
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
@@ -2969,22 +2938,12 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
self.controller.create, self.req, body=self.body)
|
self.controller.create, self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_bad_flavor_href(self):
|
def test_create_instance_bad_flavor_href(self):
|
||||||
image_href = 'http://localhost/v2/images/2'
|
|
||||||
flavor_ref = 'http://localhost/v2/flavors/17'
|
flavor_ref = 'http://localhost/v2/flavors/17'
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.body['server']['flavorRef'] = flavor_ref
|
self.body['server']['flavorRef'] = flavor_ref
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
self.controller.create, self.req, body=self.body)
|
self.controller.create, self.req, body=self.body)
|
||||||
|
|
||||||
def test_create_instance_bad_href(self):
|
|
||||||
image_href = 'asdf'
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
|
||||||
|
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
|
||||||
self.controller.create, self.req, body=self.body)
|
|
||||||
|
|
||||||
def test_create_instance_local_href(self):
|
def test_create_instance_local_href(self):
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
res = self.controller.create(self.req, body=self.body).obj
|
res = self.controller.create(self.req, body=self.body).obj
|
||||||
@@ -3345,9 +3304,6 @@ class ServersControllerCreateTest(test.TestCase):
|
|||||||
|
|
||||||
class ServersControllerCreateTestV219(ServersControllerCreateTest):
|
class ServersControllerCreateTestV219(ServersControllerCreateTest):
|
||||||
def _create_instance_req(self, set_desc, desc=None):
|
def _create_instance_req(self, set_desc, desc=None):
|
||||||
# proper local hrefs must start with 'http://localhost/v2/'
|
|
||||||
image_href = 'http://localhost/v2/images/%s' % self.image_uuid
|
|
||||||
self.body['server']['imageRef'] = image_href
|
|
||||||
if set_desc:
|
if set_desc:
|
||||||
self.body['server']['description'] = desc
|
self.body['server']['description'] = desc
|
||||||
self.req.body = jsonutils.dump_as_bytes(self.body)
|
self.req.body = jsonutils.dump_as_bytes(self.body)
|
||||||
|
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- imageRef input to the REST API is now restricted
|
||||||
|
to be UUID or an empty string only. imageRef
|
||||||
|
input while create, rebuild and rescue server etc
|
||||||
|
must be a valid UUID now. Previously, a random
|
||||||
|
image ref url containing image UUID was accepted.
|
||||||
|
But now all the reference of imageRef must be a
|
||||||
|
valid UUID (with below exception) otherwise API
|
||||||
|
will return 400.
|
||||||
|
|
||||||
|
Exception- In case boot server from volume.
|
||||||
|
Previously empty string was allowed in imageRef
|
||||||
|
and which is ok in case of boot from volume.
|
||||||
|
Nova will keep the same behavior and allow empty
|
||||||
|
string in case of boot from volume only and 400
|
||||||
|
in all other case.
|
Reference in New Issue
Block a user