diff options
-rw-r--r-- | nova/api/openstack/compute/servers.py | 23 | ||||
-rw-r--r-- | nova/api/openstack/compute/views/servers.py | 25 | ||||
-rw-r--r-- | nova/compute/api.py | 82 | ||||
-rw-r--r-- | nova/compute/manager.py | 26 | ||||
-rw-r--r-- | nova/tests/api/openstack/compute/test_servers.py | 43 | ||||
-rw-r--r-- | nova/tests/compute/test_compute.py | 218 |
6 files changed, 288 insertions, 129 deletions
diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index 9c019f78f..68c5372c3 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -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'] diff --git a/nova/api/openstack/compute/views/servers.py b/nova/api/openstack/compute/views/servers.py index b423b37d4..d281f6a61 100644 --- a/nova/api/openstack/compute/views/servers.py +++ b/nova/api/openstack/compute/views/servers.py @@ -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"] diff --git a/nova/compute/api.py b/nova/compute/api.py index 42db85a66..07a3a3afe 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -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, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 4baeab255..87b500689 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -585,7 +585,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", @@ -766,7 +770,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'] @@ -1201,7 +1208,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 @@ -1213,7 +1223,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) @@ -1554,10 +1564,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, diff --git a/nova/tests/api/openstack/compute/test_servers.py b/nova/tests/api/openstack/compute/test_servers.py index e7f4d08a0..d8c388865 100644 --- a/nova/tests/api/openstack/compute/test_servers.py +++ b/nova/tests/api/openstack/compute/test_servers.py @@ -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'] = { diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index c4be414da..f99dc5281 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -125,12 +125,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) @@ -521,6 +524,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) @@ -682,6 +693,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()) @@ -775,6 +801,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""" @@ -808,6 +846,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""" @@ -904,6 +954,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) @@ -1190,6 +1255,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): @@ -2920,6 +2995,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'] @@ -2935,19 +3018,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): @@ -2956,19 +3037,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): @@ -2978,16 +3057,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): @@ -2997,12 +3073,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): @@ -3010,7 +3084,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: @@ -3021,7 +3096,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']) @@ -3071,46 +3146,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']) @@ -3564,6 +3630,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, @@ -3752,11 +3829,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} @@ -3784,13 +3858,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() @@ -3814,12 +3885,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() @@ -5654,7 +5722,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 @@ -5670,7 +5738,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 @@ -6068,4 +6136,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') |