Merge "Boot from volume without image supplied"
This commit is contained in:
commit
255692feea
@ -743,8 +743,7 @@ class Controller(wsgi.Controller):
|
||||
self._validate_server_name(name)
|
||||
name = name.strip()
|
||||
|
||||
image_href = self._image_ref_from_req_data(body)
|
||||
image_href = self._image_uuid_from_href(image_href)
|
||||
image_uuid = self._image_from_req_data(body)
|
||||
|
||||
personality = server_dict.get('personality')
|
||||
config_drive = None
|
||||
@ -855,7 +854,7 @@ class Controller(wsgi.Controller):
|
||||
|
||||
(instances, resv_id) = self.compute_api.create(context,
|
||||
inst_type,
|
||||
image_href,
|
||||
image_uuid,
|
||||
display_name=name,
|
||||
display_description=name,
|
||||
key_name=key_name,
|
||||
@ -1108,6 +1107,24 @@ class Controller(wsgi.Controller):
|
||||
|
||||
return image_uuid
|
||||
|
||||
def _image_from_req_data(self, data):
|
||||
"""
|
||||
Get image data from the request or raise appropriate
|
||||
exceptions
|
||||
|
||||
If no image is supplied - checks to see if there is
|
||||
block devices set and proper extesions loaded.
|
||||
"""
|
||||
image_ref = data['server'].get('imageRef')
|
||||
bdm = data['server'].get('block_device_mapping')
|
||||
|
||||
if not image_ref and bdm and self.ext_mgr.is_loaded('os-volumes'):
|
||||
return ''
|
||||
else:
|
||||
image_href = self._image_ref_from_req_data(data)
|
||||
image_uuid = self._image_uuid_from_href(image_href)
|
||||
return image_uuid
|
||||
|
||||
def _flavor_id_from_req_data(self, data):
|
||||
try:
|
||||
flavor_ref = data['server']['flavorRef']
|
||||
|
@ -164,17 +164,20 @@ class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
def _get_image(self, request, instance):
|
||||
image_ref = instance["image_ref"]
|
||||
image_id = str(common.get_id_from_href(image_ref))
|
||||
bookmark = self._image_builder._get_bookmark_link(request,
|
||||
image_id,
|
||||
"images")
|
||||
return {
|
||||
"id": image_id,
|
||||
"links": [{
|
||||
"rel": "bookmark",
|
||||
"href": bookmark,
|
||||
}],
|
||||
}
|
||||
if image_ref:
|
||||
image_id = str(common.get_id_from_href(image_ref))
|
||||
bookmark = self._image_builder._get_bookmark_link(request,
|
||||
image_id,
|
||||
"images")
|
||||
return {
|
||||
"id": image_id,
|
||||
"links": [{
|
||||
"rel": "bookmark",
|
||||
"href": bookmark,
|
||||
}],
|
||||
}
|
||||
else:
|
||||
return ""
|
||||
|
||||
def _get_flavor(self, request, instance):
|
||||
instance_type = instance["instance_type"]
|
||||
|
@ -317,8 +317,7 @@ class API(base.Base):
|
||||
self.network_api.validate_networks(context, requested_networks)
|
||||
|
||||
@staticmethod
|
||||
def _handle_kernel_and_ramdisk(context, kernel_id, ramdisk_id, image,
|
||||
image_service):
|
||||
def _handle_kernel_and_ramdisk(context, kernel_id, ramdisk_id, image):
|
||||
"""Choose kernel and ramdisk appropriate for the instance.
|
||||
|
||||
The kernel and ramdisk can be chosen in one of three ways:
|
||||
@ -330,11 +329,13 @@ class API(base.Base):
|
||||
3. Forced to None by using `null_kernel` FLAG.
|
||||
"""
|
||||
# Inherit from image if not specified
|
||||
image_properties = image.get('properties', {})
|
||||
|
||||
if kernel_id is None:
|
||||
kernel_id = image['properties'].get('kernel_id')
|
||||
kernel_id = image_properties.get('kernel_id')
|
||||
|
||||
if ramdisk_id is None:
|
||||
ramdisk_id = image['properties'].get('ramdisk_id')
|
||||
ramdisk_id = image_properties.get('ramdisk_id')
|
||||
|
||||
# Force to None if using null_kernel
|
||||
if kernel_id == str(CONF.null_kernel):
|
||||
@ -343,9 +344,13 @@ class API(base.Base):
|
||||
|
||||
# Verify kernel and ramdisk exist (fail-fast)
|
||||
if kernel_id is not None:
|
||||
image_service, kernel_id = glance.get_remote_image_service(
|
||||
context, kernel_id)
|
||||
image_service.show(context, kernel_id)
|
||||
|
||||
if ramdisk_id is not None:
|
||||
image_service, ramdisk_id = glance.get_remote_image_service(
|
||||
context, ramdisk_id)
|
||||
image_service.show(context, ramdisk_id)
|
||||
|
||||
return kernel_id, ramdisk_id
|
||||
@ -367,9 +372,11 @@ class API(base.Base):
|
||||
|
||||
@staticmethod
|
||||
def _inherit_properties_from_image(image, auto_disk_config):
|
||||
image_properties = image.get('properties', {})
|
||||
|
||||
def prop(prop_, prop_type=None):
|
||||
"""Return the value of an image property."""
|
||||
value = image['properties'].get(prop_)
|
||||
value = image_properties.get(prop_)
|
||||
|
||||
if value is not None:
|
||||
if prop_type == 'bool':
|
||||
@ -435,17 +442,23 @@ class API(base.Base):
|
||||
self._check_injected_file_quota(context, injected_files)
|
||||
self._check_requested_networks(context, requested_networks)
|
||||
|
||||
(image_service, image_id) = glance.get_remote_image_service(
|
||||
context, image_href)
|
||||
image = image_service.show(context, image_id)
|
||||
if image['status'] != 'active':
|
||||
raise exception.ImageNotActive(image_id=image_id)
|
||||
if image_href:
|
||||
(image_service, image_id) = glance.get_remote_image_service(
|
||||
context, image_href)
|
||||
image = image_service.show(context, image_id)
|
||||
if image['status'] != 'active':
|
||||
raise exception.ImageNotActive(image_id=image_id)
|
||||
else:
|
||||
image = {}
|
||||
|
||||
if instance_type['memory_mb'] < int(image.get('min_ram') or 0):
|
||||
raise exception.InstanceTypeMemoryTooSmall()
|
||||
if instance_type['root_gb'] < int(image.get('min_disk') or 0):
|
||||
raise exception.InstanceTypeDiskTooSmall()
|
||||
|
||||
kernel_id, ramdisk_id = self._handle_kernel_and_ramdisk(
|
||||
context, kernel_id, ramdisk_id, image)
|
||||
|
||||
# Handle config_drive
|
||||
config_drive_id = None
|
||||
if config_drive and config_drive is not True:
|
||||
@ -454,10 +467,9 @@ class API(base.Base):
|
||||
config_drive = None
|
||||
|
||||
# Ensure config_drive image exists
|
||||
image_service.show(context, config_drive_id)
|
||||
|
||||
kernel_id, ramdisk_id = self._handle_kernel_and_ramdisk(
|
||||
context, kernel_id, ramdisk_id, image, image_service)
|
||||
cd_image_service, config_drive_id = \
|
||||
glance.get_remote_image_service(context, config_drive_id)
|
||||
cd_image_service.show(context, config_drive_id)
|
||||
|
||||
if key_data is None and key_name:
|
||||
key_pair = self.db.key_pair_get(context, context.user_id,
|
||||
@ -467,11 +479,8 @@ class API(base.Base):
|
||||
if reservation_id is None:
|
||||
reservation_id = utils.generate_uid('r')
|
||||
|
||||
# grab the architecture from glance
|
||||
architecture = image['properties'].get('architecture', 'Unknown')
|
||||
|
||||
root_device_name = block_device.properties_root_device_name(
|
||||
image['properties'])
|
||||
image.get('properties', {}))
|
||||
|
||||
availability_zone, forced_host = self._handle_availability_zone(
|
||||
availability_zone)
|
||||
@ -505,7 +514,6 @@ class API(base.Base):
|
||||
'access_ip_v6': access_ip_v6,
|
||||
'availability_zone': availability_zone,
|
||||
'root_device_name': root_device_name,
|
||||
'architecture': architecture,
|
||||
'progress': 0}
|
||||
|
||||
if user_data:
|
||||
@ -663,12 +671,13 @@ class API(base.Base):
|
||||
# require elevated context?
|
||||
elevated = context.elevated()
|
||||
instance_uuid = instance['uuid']
|
||||
mappings = image['properties'].get('mappings', [])
|
||||
image_properties = image.get('properties', {})
|
||||
mappings = image_properties.get('mappings', [])
|
||||
if mappings:
|
||||
self._update_image_block_device_mapping(elevated,
|
||||
instance_type, instance_uuid, mappings)
|
||||
|
||||
image_bdm = image['properties'].get('block_device_mapping', [])
|
||||
image_bdm = image_properties.get('block_device_mapping', [])
|
||||
for mapping in (image_bdm, block_device_mapping):
|
||||
if not mapping:
|
||||
continue
|
||||
@ -678,9 +687,10 @@ class API(base.Base):
|
||||
def _populate_instance_shutdown_terminate(self, instance, image,
|
||||
block_device_mapping):
|
||||
"""Populate instance shutdown_terminate information."""
|
||||
image_properties = image.get('properties', {})
|
||||
if (block_device_mapping or
|
||||
image['properties'].get('mappings') or
|
||||
image['properties'].get('block_device_mapping')):
|
||||
image_properties.get('mappings') or
|
||||
image_properties.get('block_device_mapping')):
|
||||
instance['shutdown_terminate'] = False
|
||||
|
||||
def _populate_instance_names(self, instance):
|
||||
@ -701,6 +711,7 @@ class API(base.Base):
|
||||
def _populate_instance_for_create(self, base_options, image,
|
||||
security_groups):
|
||||
"""Build the beginning of a new instance."""
|
||||
image_properties = image.get('properties', {})
|
||||
|
||||
instance = base_options
|
||||
if not instance.get('uuid'):
|
||||
@ -716,13 +727,13 @@ class API(base.Base):
|
||||
# Store image properties so we can use them later
|
||||
# (for notifications, etc). Only store what we can.
|
||||
instance.setdefault('system_metadata', {})
|
||||
for key, value in image['properties'].iteritems():
|
||||
for key, value in image_properties.iteritems():
|
||||
new_value = str(value)[:255]
|
||||
instance['system_metadata']['image_%s' % key] = new_value
|
||||
|
||||
# Keep a record of the original base image that this
|
||||
# image's instance is derived from:
|
||||
base_image_ref = image['properties'].get('base_image_ref')
|
||||
base_image_ref = image_properties.get('base_image_ref')
|
||||
if not base_image_ref:
|
||||
# base image ref property not previously set through a snapshot.
|
||||
# default to using the image ref as the base:
|
||||
@ -1509,8 +1520,12 @@ class API(base.Base):
|
||||
def rebuild(self, context, instance, image_href, admin_password, **kwargs):
|
||||
"""Rebuild the given instance with the provided attributes."""
|
||||
|
||||
orig_image_ref = instance['image_ref']
|
||||
image = self._get_image(context, image_href)
|
||||
if instance['image_ref']:
|
||||
orig_image_ref = instance['image_ref']
|
||||
image = self._get_image(context, image_href)
|
||||
else:
|
||||
orig_image_ref = ''
|
||||
image = {}
|
||||
|
||||
files_to_inject = kwargs.pop('files_to_inject', [])
|
||||
self._check_injected_file_quota(context, files_to_inject)
|
||||
@ -1524,11 +1539,14 @@ class API(base.Base):
|
||||
if instance_type['root_gb'] < int(image.get('min_disk') or 0):
|
||||
raise exception.InstanceTypeDiskTooSmall()
|
||||
|
||||
(image_service, image_id) = glance.get_remote_image_service(context,
|
||||
image_href)
|
||||
image = image_service.show(context, image_id)
|
||||
if image_href:
|
||||
(image_service, image_id) = glance.get_remote_image_service(
|
||||
context, image_href)
|
||||
image = image_service.show(context, image_id)
|
||||
else:
|
||||
image = {}
|
||||
kernel_id, ramdisk_id = self._handle_kernel_and_ramdisk(
|
||||
context, None, None, image, image_service)
|
||||
context, None, None, image)
|
||||
|
||||
def _reset_image_metadata():
|
||||
"""
|
||||
@ -1551,7 +1569,7 @@ class API(base.Base):
|
||||
if key.startswith('image_'):
|
||||
del sys_metadata[key]
|
||||
# Add the new ones
|
||||
for key, value in image['properties'].iteritems():
|
||||
for key, value in image.get('properties', {}).iteritems():
|
||||
new_value = str(value)[:255]
|
||||
sys_metadata['image_%s' % key] = new_value
|
||||
self.db.instance_system_metadata_update(context,
|
||||
|
@ -589,7 +589,11 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
LOG.debug(_("No node specified, defaulting to %(node)s") %
|
||||
locals())
|
||||
|
||||
extra_usage_info = {"image_name": image_meta['name']}
|
||||
if image_meta:
|
||||
extra_usage_info = {"image_name": image_meta['name']}
|
||||
else:
|
||||
extra_usage_info = {}
|
||||
|
||||
self._start_building(context, instance)
|
||||
self._notify_about_instance_usage(
|
||||
context, instance, "create.start",
|
||||
@ -770,7 +774,10 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
image, but is accurate because it reflects the image's
|
||||
actual size.
|
||||
"""
|
||||
image_meta = _get_image_meta(context, instance['image_ref'])
|
||||
if instance['image_ref']:
|
||||
image_meta = _get_image_meta(context, instance['image_ref'])
|
||||
else: # Instance was started from volume - so no image ref
|
||||
return {}
|
||||
|
||||
try:
|
||||
size_bytes = image_meta['size']
|
||||
@ -1205,7 +1212,10 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
LOG.audit(_("Rebuilding instance"), context=context,
|
||||
instance=instance)
|
||||
|
||||
image_meta = _get_image_meta(context, image_ref)
|
||||
if image_ref:
|
||||
image_meta = _get_image_meta(context, image_ref)
|
||||
else:
|
||||
image_meta = {}
|
||||
|
||||
# This instance.exists message should contain the original
|
||||
# image_ref, not the new one. Since the DB has been updated
|
||||
@ -1217,7 +1227,7 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
extra_usage_info=extra_usage_info)
|
||||
|
||||
# This message should contain the new image_ref
|
||||
extra_usage_info = {'image_name': image_meta['name']}
|
||||
extra_usage_info = {'image_name': image_meta.get('name', '')}
|
||||
self._notify_about_instance_usage(context, instance,
|
||||
"rebuild.start", extra_usage_info=extra_usage_info)
|
||||
|
||||
@ -1558,10 +1568,12 @@ class ComputeManager(manager.SchedulerDependentManager):
|
||||
|
||||
network_info = self._get_instance_nw_info(context, instance)
|
||||
|
||||
# Boot the instance using the 'base' image instead of the user's
|
||||
# current (possibly broken) image
|
||||
rescue_image_ref = self._get_rescue_image_ref(context, instance)
|
||||
rescue_image_meta = _get_image_meta(context, rescue_image_ref)
|
||||
|
||||
if rescue_image_ref:
|
||||
rescue_image_meta = _get_image_meta(context, rescue_image_ref)
|
||||
else:
|
||||
rescue_image_meta = {}
|
||||
|
||||
with self._error_out_instance_on_exception(context, instance['uuid']):
|
||||
self.driver.rescue(context, instance,
|
||||
|
@ -2006,9 +2006,11 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
fakes.stub_out_key_pair_funcs(self.stubs, have_key_pair=False)
|
||||
self._test_create_instance()
|
||||
|
||||
def _test_create_extra(self, params):
|
||||
def _test_create_extra(self, params, no_image=False):
|
||||
image_uuid = 'c905cedb-7281-47e4-8a62-f26bc5fc4c77'
|
||||
server = dict(name='server_test', imageRef=image_uuid, flavorRef=2)
|
||||
if no_image:
|
||||
server.pop('imageRef', None)
|
||||
server.update(params)
|
||||
body = dict(server=server)
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/servers')
|
||||
@ -2109,6 +2111,40 @@ class ServersControllerCreateTest(test.TestCase):
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self._test_create_extra(params)
|
||||
|
||||
def test_create_instance_with_volumes_enabled_no_image(self):
|
||||
"""
|
||||
Test that the create will fail if there is no image
|
||||
and no bdms supplied in the request
|
||||
"""
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake'}
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertNotIn('imageRef', kwargs)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self._test_create_extra, {}, no_image=True)
|
||||
|
||||
def test_create_instance_with_volumes_enabled_and_bdms_no_image(self):
|
||||
"""
|
||||
Test that the create works if there is no image supplied but
|
||||
os-volumes extension is enabled and bdms are supplied
|
||||
"""
|
||||
self.ext_mgr.extensions = {'os-volumes': 'fake'}
|
||||
bdm = [{'device_name': 'foo'}]
|
||||
params = {'block_device_mapping': bdm}
|
||||
old_create = compute_api.API.create
|
||||
|
||||
def create(*args, **kwargs):
|
||||
self.assertEqual(kwargs['block_device_mapping'], bdm)
|
||||
self.assertNotIn('imageRef', kwargs)
|
||||
return old_create(*args, **kwargs)
|
||||
|
||||
self.stubs.Set(compute_api.API, 'create', create)
|
||||
self._test_create_extra(params, no_image=True)
|
||||
|
||||
def test_create_instance_with_volumes_disabled(self):
|
||||
bdm = [{'device_name': 'foo'}]
|
||||
params = {'block_device_mapping': bdm}
|
||||
@ -3801,6 +3837,11 @@ class ServersViewBuilderTest(test.TestCase):
|
||||
output = self.view_builder.show(self.request, self.instance)
|
||||
self.assertThat(output, matchers.DictMatches(expected_server))
|
||||
|
||||
def test_build_server_no_image(self):
|
||||
self.instance["image_ref"] = ""
|
||||
output = self.view_builder.show(self.request, self.instance)
|
||||
self.assertEqual(output['server']['image'], "")
|
||||
|
||||
def test_build_server_detail_with_fault(self):
|
||||
self.instance['vm_state'] = vm_states.ERROR
|
||||
self.instance['fault'] = {
|
||||
|
@ -124,12 +124,15 @@ class BaseTestCase(test.TestCase):
|
||||
test_notifier.NOTIFICATIONS = []
|
||||
|
||||
def fake_show(meh, context, id):
|
||||
return {'id': id, 'min_disk': None, 'min_ram': None,
|
||||
'name': 'fake_name',
|
||||
'status': 'active',
|
||||
'properties': {'kernel_id': 'fake_kernel_id',
|
||||
'ramdisk_id': 'fake_ramdisk_id',
|
||||
'something_else': 'meow'}}
|
||||
if id:
|
||||
return {'id': id, 'min_disk': None, 'min_ram': None,
|
||||
'name': 'fake_name',
|
||||
'status': 'active',
|
||||
'properties': {'kernel_id': 'fake_kernel_id',
|
||||
'ramdisk_id': 'fake_ramdisk_id',
|
||||
'something_else': 'meow'}}
|
||||
else:
|
||||
raise exception.ImageNotFound(image_id=id)
|
||||
|
||||
fake_image.stub_out_image_service(self.stubs)
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
@ -520,6 +523,14 @@ class ComputeTestCase(BaseTestCase):
|
||||
|
||||
self.assertEqual(NODENAME, instance['node'])
|
||||
|
||||
def test_create_instance_no_image(self):
|
||||
"""Create instance with no image provided"""
|
||||
params = {'image_ref': ''}
|
||||
instance = self._create_fake_instance(params)
|
||||
self.compute.run_instance(self.context, instance=instance)
|
||||
self._assert_state({'vm_state': vm_states.ACTIVE,
|
||||
'task_state': None})
|
||||
|
||||
def test_default_access_ip(self):
|
||||
self.flags(default_access_ip_network_name='test1')
|
||||
fake_network.unset_stub_network_methods(self.stubs)
|
||||
@ -681,6 +692,21 @@ class ComputeTestCase(BaseTestCase):
|
||||
instance['uuid'])
|
||||
self.assertEqual(len(bdms), 0)
|
||||
|
||||
def test_run_terminate_no_image(self):
|
||||
"""
|
||||
Make sure instance started without image (from volume)
|
||||
can be termintad without issues
|
||||
"""
|
||||
params = {'image_ref': ''}
|
||||
instance = self._create_fake_instance(params)
|
||||
self.compute.run_instance(self.context, instance=instance)
|
||||
self._assert_state({'vm_state': vm_states.ACTIVE,
|
||||
'task_state': None})
|
||||
|
||||
self.compute.terminate_instance(self.context, instance=instance)
|
||||
instances = db.instance_get_all(self.context)
|
||||
self.assertEqual(len(instances), 0)
|
||||
|
||||
def test_terminate_no_network(self):
|
||||
# This is as reported in LP bug 1008875
|
||||
instance = jsonutils.to_primitive(self._create_fake_instance())
|
||||
@ -774,6 +800,18 @@ class ComputeTestCase(BaseTestCase):
|
||||
self.compute.start_instance(self.context, instance=instance)
|
||||
self.compute.terminate_instance(self.context, instance=instance)
|
||||
|
||||
def test_stop_start_no_image(self):
|
||||
params = {'image_ref': ''}
|
||||
instance = self._create_fake_instance(params)
|
||||
self.compute.run_instance(self.context, instance=instance)
|
||||
db.instance_update(self.context, instance['uuid'],
|
||||
{"task_state": task_states.POWERING_OFF})
|
||||
self.compute.stop_instance(self.context, instance=instance)
|
||||
db.instance_update(self.context, instance['uuid'],
|
||||
{"task_state": task_states.POWERING_ON})
|
||||
self.compute.start_instance(self.context, instance=instance)
|
||||
self.compute.terminate_instance(self.context, instance=instance)
|
||||
|
||||
def test_rescue(self):
|
||||
"""Ensure instance can be rescued and unrescued"""
|
||||
|
||||
@ -807,6 +845,18 @@ class ComputeTestCase(BaseTestCase):
|
||||
|
||||
self.compute.terminate_instance(self.context, instance=instance)
|
||||
|
||||
def test_rescue_no_image(self):
|
||||
params = {'image_ref': ''}
|
||||
instance = self._create_fake_instance(params)
|
||||
instance_uuid = instance['uuid']
|
||||
self.compute.run_instance(self.context, instance=instance)
|
||||
db.instance_update(self.context, instance_uuid,
|
||||
{"task_state": task_states.RESCUING})
|
||||
self.compute.rescue_instance(self.context, instance=instance)
|
||||
db.instance_update(self.context, instance_uuid,
|
||||
{"task_state": task_states.UNRESCUING})
|
||||
self.compute.unrescue_instance(self.context, instance=instance)
|
||||
|
||||
def test_power_on(self):
|
||||
"""Ensure instance can be powered on"""
|
||||
|
||||
@ -903,6 +953,21 @@ class ComputeTestCase(BaseTestCase):
|
||||
bdms=[])
|
||||
self.compute.terminate_instance(self.context, instance=instance)
|
||||
|
||||
def test_rebuild_no_image(self):
|
||||
"""Ensure instance can be rebuilt when started with no image"""
|
||||
params = {'image_ref': ''}
|
||||
instance = self._create_fake_instance(params)
|
||||
sys_metadata = db.instance_system_metadata_get(self.context,
|
||||
instance['uuid'])
|
||||
self.compute.run_instance(self.context, instance=instance)
|
||||
db.instance_update(self.context, instance['uuid'],
|
||||
{"task_state": task_states.REBUILDING})
|
||||
self.compute.rebuild_instance(self.context, instance,
|
||||
'', '', injected_files=[],
|
||||
new_pass="new_password",
|
||||
orig_sys_metadata=sys_metadata)
|
||||
self.compute.terminate_instance(self.context, instance=instance)
|
||||
|
||||
def test_rebuild_launch_time(self):
|
||||
"""Ensure instance can be rebuilt"""
|
||||
old_time = datetime.datetime(2012, 4, 1)
|
||||
@ -1189,6 +1254,16 @@ class ComputeTestCase(BaseTestCase):
|
||||
self.compute.snapshot_instance(self.context, name, instance=instance)
|
||||
self.compute.terminate_instance(self.context, instance=instance)
|
||||
|
||||
def test_snapshot_no_image(self):
|
||||
params = {'image_ref': ''}
|
||||
name = "myfakesnapshot"
|
||||
instance = self._create_fake_instance(params)
|
||||
self.compute.run_instance(self.context, instance=instance)
|
||||
db.instance_update(self.context, instance['uuid'],
|
||||
{"task_state": task_states.IMAGE_SNAPSHOT})
|
||||
self.compute.snapshot_instance(self.context, name, instance=instance)
|
||||
self.compute.terminate_instance(self.context, instance=instance)
|
||||
|
||||
def test_snapshot_fails(self):
|
||||
"""Ensure task_state is set to None if snapshot fails"""
|
||||
def fake_snapshot(*args, **kwargs):
|
||||
@ -2919,6 +2994,14 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
'ramdisk_id': 'fake_ramdisk_id'},
|
||||
}
|
||||
|
||||
def fake_show(obj, context, image_id):
|
||||
if image_id:
|
||||
return self.fake_image
|
||||
else:
|
||||
raise exception.ImageNotFound(image_id=image_id)
|
||||
|
||||
self.fake_show = fake_show
|
||||
|
||||
def _run_instance(self, params=None):
|
||||
instance = jsonutils.to_primitive(self._create_fake_instance(params))
|
||||
instance_uuid = instance['uuid']
|
||||
@ -2934,19 +3017,17 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
inst_type = instance_types.get_default_instance_type()
|
||||
inst_type['memory_mb'] = 1
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_ram'] = 2
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['min_ram'] = 2
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
self.assertRaises(exception.InstanceTypeMemoryTooSmall,
|
||||
self.compute_api.create, self.context, inst_type, None)
|
||||
self.compute_api.create, self.context,
|
||||
inst_type, self.fake_image['id'])
|
||||
|
||||
# Now increase the inst_type memory and make sure all is fine.
|
||||
inst_type['memory_mb'] = 2
|
||||
(refs, resv_id) = self.compute_api.create(self.context,
|
||||
inst_type, None)
|
||||
inst_type, self.fake_image['id'])
|
||||
db.instance_destroy(self.context, refs[0]['uuid'])
|
||||
|
||||
def test_create_with_too_little_disk(self):
|
||||
@ -2955,19 +3036,17 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
inst_type = instance_types.get_default_instance_type()
|
||||
inst_type['root_gb'] = 1
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_disk'] = 2
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['min_disk'] = 2
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
self.assertRaises(exception.InstanceTypeDiskTooSmall,
|
||||
self.compute_api.create, self.context, inst_type, None)
|
||||
self.compute_api.create, self.context,
|
||||
inst_type, self.fake_image['id'])
|
||||
|
||||
# Now increase the inst_type disk space and make sure all is fine.
|
||||
inst_type['root_gb'] = 2
|
||||
(refs, resv_id) = self.compute_api.create(self.context,
|
||||
inst_type, None)
|
||||
inst_type, self.fake_image['id'])
|
||||
db.instance_destroy(self.context, refs[0]['uuid'])
|
||||
|
||||
def test_create_just_enough_ram_and_disk(self):
|
||||
@ -2977,16 +3056,13 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
inst_type['root_gb'] = 2
|
||||
inst_type['memory_mb'] = 2
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_ram'] = 2
|
||||
img['min_disk'] = 2
|
||||
img['name'] = 'fake_name'
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['min_ram'] = 2
|
||||
self.fake_image['min_disk'] = 2
|
||||
self.fake_image['name'] = 'fake_name'
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
(refs, resv_id) = self.compute_api.create(self.context,
|
||||
inst_type, None)
|
||||
inst_type, self.fake_image['id'])
|
||||
db.instance_destroy(self.context, refs[0]['uuid'])
|
||||
|
||||
def test_create_with_no_ram_and_disk_reqs(self):
|
||||
@ -2996,12 +3072,10 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
inst_type['root_gb'] = 1
|
||||
inst_type['memory_mb'] = 1
|
||||
|
||||
def fake_show(*args):
|
||||
return copy.copy(self.fake_image)
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
(refs, resv_id) = self.compute_api.create(self.context,
|
||||
inst_type, None)
|
||||
inst_type, self.fake_image['id'])
|
||||
db.instance_destroy(self.context, refs[0]['uuid'])
|
||||
|
||||
def test_create_instance_defaults_display_name(self):
|
||||
@ -3009,7 +3083,8 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
cases = [dict(), dict(display_name=None)]
|
||||
for instance in cases:
|
||||
(ref, resv_id) = self.compute_api.create(self.context,
|
||||
instance_types.get_default_instance_type(), None, **instance)
|
||||
instance_types.get_default_instance_type(),
|
||||
'fake-image-uuid', **instance)
|
||||
try:
|
||||
self.assertNotEqual(ref[0]['display_name'], None)
|
||||
finally:
|
||||
@ -3020,7 +3095,7 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
(ref, resv_id) = self.compute_api.create(
|
||||
self.context,
|
||||
instance_type=instance_types.get_default_instance_type(),
|
||||
image_href=None)
|
||||
image_href='fake-image-uuid')
|
||||
try:
|
||||
sys_metadata = db.instance_system_metadata_get(self.context,
|
||||
ref[0]['uuid'])
|
||||
@ -3070,46 +3145,37 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
|
||||
inst_type = instance_types.get_default_instance_type()
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_ram'] = 2
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['min_ram'] = 2
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
self.assertRaises(exception.InstanceUserDataTooLarge,
|
||||
self.compute_api.create, self.context, inst_type, None,
|
||||
user_data=('1' * 65536))
|
||||
self.compute_api.create, self.context, inst_type,
|
||||
self.fake_image['id'], user_data=('1' * 65536))
|
||||
|
||||
def test_create_with_malformed_user_data(self):
|
||||
"""Test an instance type with malformed user data."""
|
||||
|
||||
inst_type = instance_types.get_default_instance_type()
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_ram'] = 2
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['min_ram'] = 2
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
self.assertRaises(exception.InstanceUserDataMalformed,
|
||||
self.compute_api.create, self.context, inst_type, None,
|
||||
user_data='banana')
|
||||
self.compute_api.create, self.context, inst_type,
|
||||
self.fake_image['id'], user_data='banana')
|
||||
|
||||
def test_create_with_base64_user_data(self):
|
||||
"""Test an instance type with ok much user data."""
|
||||
|
||||
inst_type = instance_types.get_default_instance_type()
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['min_ram'] = 2
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['min_ram'] = 2
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
# NOTE(mikal): a string of length 48510 encodes to 65532 characters of
|
||||
# base64
|
||||
(refs, resv_id) = self.compute_api.create(
|
||||
self.context, inst_type, None,
|
||||
self.context, inst_type, self.fake_image['id'],
|
||||
user_data=base64.encodestring('1' * 48510))
|
||||
db.instance_destroy(self.context, refs[0]['uuid'])
|
||||
|
||||
@ -3563,6 +3629,17 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
'preserved': 'preserve this!'})
|
||||
db.instance_destroy(self.context, instance['uuid'])
|
||||
|
||||
def test_rebuild_no_image(self):
|
||||
instance = jsonutils.to_primitive(
|
||||
self._create_fake_instance(params={'image_ref': ''}))
|
||||
instance_uuid = instance['uuid']
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
self.compute.run_instance(self.context, instance=instance)
|
||||
self.compute_api.rebuild(self.context, instance, '', 'new_password')
|
||||
|
||||
instance = db.instance_get_by_uuid(self.context, instance_uuid)
|
||||
self.assertEqual(instance['task_state'], task_states.REBUILDING)
|
||||
|
||||
def _stub_out_reboot(self, device_name):
|
||||
def fake_reboot_instance(rpcapi, context, instance,
|
||||
block_device_info,
|
||||
@ -3751,11 +3828,8 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
and min_disk set to that of the original instances flavor.
|
||||
"""
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['disk_format'] = 'vhd'
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['disk_format'] = 'vhd'
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
instance = self._create_fake_instance()
|
||||
inst_params = {'root_gb': 2, 'memory_mb': 256}
|
||||
@ -3783,13 +3857,10 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
image had a disk format of vhd.
|
||||
"""
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['disk_format'] = 'raw'
|
||||
img['min_ram'] = 512
|
||||
img['min_disk'] = 1
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['disk_format'] = 'raw'
|
||||
self.fake_image['min_ram'] = 512
|
||||
self.fake_image['min_disk'] = 1
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
instance = self._create_fake_instance()
|
||||
|
||||
@ -3813,12 +3884,9 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
Do not show an attribute that the orig img did not have.
|
||||
"""
|
||||
|
||||
def fake_show(*args):
|
||||
img = copy.copy(self.fake_image)
|
||||
img['disk_format'] = 'raw'
|
||||
img['min_disk'] = 1
|
||||
return img
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', fake_show)
|
||||
self.fake_image['disk_format'] = 'raw'
|
||||
self.fake_image['min_disk'] = 1
|
||||
self.stubs.Set(fake_image._FakeImageService, 'show', self.fake_show)
|
||||
|
||||
instance = self._create_fake_instance()
|
||||
|
||||
@ -5642,7 +5710,7 @@ class DisabledInstanceTypesTestCase(BaseTestCase):
|
||||
|
||||
def test_can_rebuild_instance_from_visible_instance_type(self):
|
||||
instance = self._create_fake_instance()
|
||||
image_href = None
|
||||
image_href = 'fake-image-id'
|
||||
admin_password = 'blah'
|
||||
|
||||
instance['instance_type']['disabled'] = True
|
||||
@ -5658,7 +5726,7 @@ class DisabledInstanceTypesTestCase(BaseTestCase):
|
||||
when the slice is on disabled type already.
|
||||
"""
|
||||
instance = self._create_fake_instance()
|
||||
image_href = None
|
||||
image_href = 'fake-image-id'
|
||||
admin_password = 'blah'
|
||||
|
||||
instance['instance_type']['disabled'] = True
|
||||
@ -6056,4 +6124,4 @@ class ComputeInactiveImageTestCase(BaseTestCase):
|
||||
inst_type = instance_types.get_instance_type_by_name('m1.tiny')
|
||||
self.assertRaises(exception.ImageNotActive,
|
||||
self.compute_api.create,
|
||||
self.context, inst_type, None)
|
||||
self.context, inst_type, 'fake-image-uuid')
|
||||
|
Loading…
x
Reference in New Issue
Block a user