def _action_create_image(self, req, id, body): """Snapshot a server instance.""" context = req.environ['patron.context'] authorize(context, action='create_image') entity = body["createImage"] image_name = entity["name"] metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) instance = self._get_server(context, req, id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) try: if self.compute_api.is_volume_backed_instance(context, instance, bdms): img = instance.image_ref if not img: properties = bdms.root_metadata( context, self.compute_api.image_api, self.compute_api.volume_api) image_meta = {'properties': properties} else: image_meta = self.compute_api.image_api.get(context, img) image = self.compute_api.snapshot_volume_backed( context, instance, image_meta, image_name, extra_properties= metadata) else: image = self.compute_api.snapshot(context, instance, image_name, extra_properties=metadata) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'createImage', id) except exception.Invalid as err: raise exc.HTTPBadRequest(explanation=err.format_message()) # build location of newly-created image entity image_id = str(image['id']) image_ref = glance.generate_image_url(image_id) resp = webob.Response(status_int=202) resp.headers['Location'] = image_ref return resp
def _action_create_image(self, req, id, body): """Snapshot a server instance.""" context = req.environ['patron.context'] authorize(context, action='create_image') entity = body["createImage"] image_name = entity["name"] metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) instance = self._get_server(context, req, id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) try: if self.compute_api.is_volume_backed_instance( context, instance, bdms): img = instance.image_ref if not img: properties = bdms.root_metadata( context, self.compute_api.image_api, self.compute_api.volume_api) image_meta = {'properties': properties} else: image_meta = self.compute_api.image_api.get(context, img) image = self.compute_api.snapshot_volume_backed( context, instance, image_meta, image_name, extra_properties=metadata) else: image = self.compute_api.snapshot(context, instance, image_name, extra_properties=metadata) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'createImage', id) except exception.Invalid as err: raise exc.HTTPBadRequest(explanation=err.format_message()) # build location of newly-created image entity image_id = str(image['id']) image_ref = glance.generate_image_url(image_id) resp = webob.Response(status_int=202) resp.headers['Location'] = image_ref return resp
def test_create_image(self): body = { 'createImage': { 'name': 'Snapshot 1', }, } response = self.controller._action_create_image(self.req, FAKE_UUID, body=body) location = response.headers['Location'] self.assertEqual(self.image_url + '123' if self.image_url else glance.generate_image_url('123'), location)
def info_from_instance(context, instance, network_info, system_metadata, **kw): """Get detailed instance information for an instance which is common to all notifications. :param:instance: patron.objects.Instance :param:network_info: network_info provided if not None :param:system_metadata: system_metadata DB entries for the instance, if not None .. note:: Currently unused here in trunk, but needed for potential custom modifications. """ def null_safe_str(s): return str(s) if s else '' def null_safe_int(s): return int(s) if s else '' def null_safe_isotime(s): if isinstance(s, datetime.datetime): return timeutils.strtime(s) else: return str(s) if s else '' image_ref_url = glance.generate_image_url(instance.image_ref) instance_type = instance.get_flavor() instance_type_name = instance_type.get('name', '') instance_flavorid = instance_type.get('flavorid', '') instance_info = dict( # Owner properties tenant_id=instance.project_id, user_id=instance.user_id, # Identity properties instance_id=instance.uuid, display_name=instance.display_name, reservation_id=instance.reservation_id, hostname=instance.hostname, # Type properties instance_type=instance_type_name, instance_type_id=instance.instance_type_id, instance_flavor_id=instance_flavorid, architecture=instance.architecture, # Capacity properties memory_mb=instance.memory_mb, disk_gb=instance.root_gb + instance.ephemeral_gb, vcpus=instance.vcpus, # Note(dhellmann): This makes the disk_gb value redundant, but # we are keeping it for backwards-compatibility with existing # users of notifications. root_gb=instance.root_gb, ephemeral_gb=instance.ephemeral_gb, # Location properties host=instance.host, node=instance.node, availability_zone=instance.availability_zone, cell_name=null_safe_str(instance.cell_name), # Date properties created_at=str(instance.created_at), # Terminated and Deleted are slightly different (although being # terminated and not deleted is a transient state), so include # both and let the recipient decide which they want to use. terminated_at=null_safe_isotime(instance.get('terminated_at', None)), deleted_at=null_safe_isotime(instance.get('deleted_at', None)), launched_at=null_safe_isotime(instance.get('launched_at', None)), # Image properties image_ref_url=image_ref_url, os_type=instance.os_type, kernel_id=instance.kernel_id, ramdisk_id=instance.ramdisk_id, # Status properties state=instance.vm_state, state_description=null_safe_str(instance.task_state), progress=null_safe_int(instance.progress), # accessIPs access_ip_v4=instance.access_ip_v4, access_ip_v6=instance.access_ip_v6, ) if network_info is not None: fixed_ips = [] for vif in network_info: for ip in vif.fixed_ips(): ip["label"] = vif["network"]["label"] ip["vif_mac"] = vif["address"] fixed_ips.append(ip) instance_info['fixed_ips'] = fixed_ips # add image metadata image_meta_props = image_meta(instance.system_metadata) instance_info["image_meta"] = image_meta_props # add instance metadata instance_info['metadata'] = instance.metadata instance_info.update(kw) return instance_info
def _do_test_create_volume_backed_image(self, extra_properties): def _fake_id(x): return '%s-%s-%s-%s' % (x * 8, x * 4, x * 4, x * 12) body = dict(createImage=dict(name='snapshot_of_volume_backed')) if extra_properties: body['createImage']['metadata'] = extra_properties image_service = glance.get_default_image_service() bdm = [dict(volume_id=_fake_id('a'), volume_size=1, device_name='vda', delete_on_termination=False)] props = dict(kernel_id=_fake_id('b'), ramdisk_id=_fake_id('c'), root_device_name='/dev/vda', block_device_mapping=bdm) original_image = dict(properties=props, container_format='ami', status='active', is_public=True) image_service.create(None, original_image) def fake_block_device_mapping_get_all_by_instance(context, inst_id, use_slave=False): return [fake_block_device.FakeDbBlockDeviceDict( {'volume_id': _fake_id('a'), 'source_type': 'snapshot', 'destination_type': 'volume', 'volume_size': 1, 'device_name': 'vda', 'snapshot_id': 1, 'boot_index': 0, 'delete_on_termination': False, 'no_device': None})] self.stubs.Set(db, 'block_device_mapping_get_all_by_instance', fake_block_device_mapping_get_all_by_instance) instance = fakes.fake_instance_get(image_ref=original_image['id'], vm_state=vm_states.ACTIVE, root_device_name='/dev/vda') self.stubs.Set(db, 'instance_get_by_uuid', instance) self.mox.StubOutWithMock(self.controller.compute_api.compute_rpcapi, 'quiesce_instance') self.controller.compute_api.compute_rpcapi.quiesce_instance( mox.IgnoreArg(), mox.IgnoreArg()).AndRaise( exception.InstanceQuiesceNotSupported(instance_id='fake', reason='test')) volume = dict(id=_fake_id('a'), size=1, host='fake', display_description='fake') snapshot = dict(id=_fake_id('d')) self.mox.StubOutWithMock(self.controller.compute_api, 'volume_api') volume_api = self.controller.compute_api.volume_api volume_api.get(mox.IgnoreArg(), volume['id']).AndReturn(volume) volume_api.create_snapshot_force(mox.IgnoreArg(), volume['id'], mox.IgnoreArg(), mox.IgnoreArg()).AndReturn(snapshot) self.mox.ReplayAll() response = self.controller._action_create_image(self.req, FAKE_UUID, body=body) location = response.headers['Location'] image_id = location.replace(self.image_url or glance.generate_image_url(''), '') image = image_service.show(None, image_id) self.assertEqual(image['name'], 'snapshot_of_volume_backed') properties = image['properties'] self.assertEqual(properties['kernel_id'], _fake_id('b')) self.assertEqual(properties['ramdisk_id'], _fake_id('c')) self.assertEqual(properties['root_device_name'], '/dev/vda') self.assertEqual(properties['bdm_v2'], True) bdms = properties['block_device_mapping'] self.assertEqual(len(bdms), 1) self.assertEqual(bdms[0]['boot_index'], 0) self.assertEqual(bdms[0]['source_type'], 'snapshot') self.assertEqual(bdms[0]['destination_type'], 'volume') self.assertEqual(bdms[0]['snapshot_id'], snapshot['id']) for fld in ('connection_info', 'id', 'instance_uuid', 'device_name'): self.assertNotIn(fld, bdms[0]) for k in extra_properties.keys(): self.assertEqual(properties[k], extra_properties[k])