def _get_snapshot_metadata(self, virt_dom, context, instance, snapshot_id): _image_service = glance.get_remote_image_service(context, snapshot_id) snapshot_image_service, snapshot_image_id = _image_service snapshot = snapshot_image_service.show(context, snapshot_image_id) metadata = {'is_public': True, 'status': 'active', 'name': snapshot['name'], 'properties': { 'kernel_id': instance['kernel_id'], 'image_location': 'snapshot', 'image_state': 'available', 'owner_id': instance['project_id'], 'ramdisk_id': instance['ramdisk_id'], } } (image_service, image_id) = glance.get_remote_image_service( context, instance['image_ref']) try: base = image_service.show(context, image_id) except exception.ImageNotFound: base = {} if 'architecture' in base.get('properties', {}): arch = base['properties']['architecture'] metadata['properties']['architecture'] = arch metadata['disk_format'] = 'raw' metadata['container_format'] = base.get('container_format', 'bare') return metadata
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: 1. Passed in with create-instance request. 2. Inherited from image. 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') if ramdisk_id is None: ramdisk_id = image_properties.get('ramdisk_id') # Force to None if using null_kernel if kernel_id == str(CONF.null_kernel): kernel_id = None ramdisk_id = None # 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
def _get_snapshot_metadata(self, virt_dom, context, instance, snapshot_id): _image_service = glance.get_remote_image_service(context, snapshot_id) snapshot_image_service, snapshot_image_id = _image_service snapshot = snapshot_image_service.show(context, snapshot_image_id) metadata = { "is_public": True, "status": "active", "name": snapshot["name"], "properties": { "kernel_id": instance["kernel_id"], "image_location": "snapshot", "image_state": "available", "owner_id": instance["project_id"], "ramdisk_id": instance["ramdisk_id"], }, } (image_service, image_id) = glance.get_remote_image_service(context, instance["image_ref"]) try: base = image_service.show(context, image_id) except exception.ImageNotFound: base = {} if "architecture" in base.get("properties", {}): arch = base["properties"]["architecture"] metadata["properties"]["architecture"] = arch metadata["disk_format"] = "raw" metadata["container_format"] = base.get("container_format", "bare") return metadata
def test_start(self): consumer = glance.UpdateGlanceImage("context", "id", "metadata", "stream") image_service = self.mox.CreateMock(glance.GlanceImageService) self.mox.StubOutWithMock(glance, "get_remote_image_service") glance.get_remote_image_service("context", "id").AndReturn((image_service, "image_id")) image_service.update("context", "image_id", "metadata", "stream", purge_props=False) self.mox.ReplayAll() consumer.start()
def create_overlay_vm(self, context, instance, overlay_name, overlay_id, update_task_state): try: if hasattr(self, "_lookup_by_name"): # icehouse virt_dom = self._lookup_by_name(instance['name']) else: # kilo virt_dom = self._host.get_domain(instance) except exception.InstanceNotFound: raise exception.InstanceNotRunning(instance_id=instance['uuid']) # make sure base vm is cached (image_service, image_id) = glance.get_remote_image_service( context, instance['image_ref']) image_meta = image_service.show(context, image_id) base_sha256_uuid, memory_snap_id, diskhash_snap_id, memhash_snap_id = \ self._get_basevm_meta_info(image_meta) self._get_cache_image(context, instance, image_meta['id']) self._get_cache_image(context, instance, memory_snap_id) self._get_cache_image(context, instance, diskhash_snap_id) self._get_cache_image(context, instance, memhash_snap_id) # pause VM self.pause(instance) # create VM overlay (image_service, image_id) = glance.get_remote_image_service( context, instance['image_ref']) meta_metadata = self._get_snapshot_metadata(virt_dom, context, instance, overlay_id) update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD, expected_state=None) vm_overlay = self.resumed_vm_dict.get(instance['uuid'], None) if vm_overlay is None: raise exception.InstanceNotRunning(instance_id=instance['uuid']) del self.resumed_vm_dict[instance['uuid']] vm_overlay.create_overlay() overlay_zip = vm_overlay.overlay_zipfile LOG.info("overlay : %s" % str(overlay_zip)) update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD) # export to glance self._update_to_glance(context, image_service, overlay_zip, overlay_id, meta_metadata) LOG.info(_("overlay_vm upload complete"), instance=instance) if os.path.exists(overlay_zip): os.remove(overlay_zip)
def test_start(self): consumer = glance.UpdateGlanceImage( 'context', 'id', 'metadata', 'stream') image_service = self.mox.CreateMock(glance.GlanceImageService) self.mox.StubOutWithMock(glance, 'get_remote_image_service') glance.get_remote_image_service( 'context', 'id').AndReturn((image_service, 'image_id')) image_service.update( 'context', 'image_id', 'metadata', 'stream', purge_props=False) self.mox.ReplayAll() consumer.start()
def _get_image(self, context, image_id): if not image_id: return None (image_service, image_id) = glance.get_remote_image_service(context, image_id) return image_service.show(context, image_id)
def upload_image(context, image, instance, **kwargs): """Upload the snapshotted vm disk file to Glance image server.""" LOG.debug(_("Uploading image %s to the Glance image server") % image, instance=instance) read_file_handle = read_write_util.VmWareHTTPReadFile( kwargs.get("host"), kwargs.get("data_center_name"), kwargs.get("datastore_name"), kwargs.get("cookies"), kwargs.get("file_path")) file_size = read_file_handle.get_size() (image_service, image_id) = glance.get_remote_image_service(context, image) # The properties and other fields that we need to set for the image. image_metadata = {"is_public": True, "disk_format": "vmdk", "container_format": "bare", "type": "vmdk", "properties": {"vmware_adaptertype": kwargs.get("adapter_type"), "vmware_ostype": kwargs.get("os_type"), "vmware_image_version": kwargs.get("image_version")}} start_transfer(context, read_file_handle, file_size, image_service=image_service, image_id=image_id, image_meta=image_metadata) LOG.debug(_("Uploaded image %s to the Glance image server") % image, instance=instance)
def get_test_image_info(context, instance_ref): if not context: context = get_test_admin_context() image_ref = instance_ref["image_ref"] image_service, image_id = glance.get_remote_image_service(context, image_ref) return image_service.show(context, image_id)
def test_glance_client_image_ref(self): fixture = self._make_fixture(name="test image") image_id = self.service.create(self.context, fixture)["id"] image_url = "http://something-less-likely/%s" % image_id (service, same_id) = glance.get_remote_image_service(self.context, image_url) self.assertEqual(same_id, image_id) self.assertEqual(service._client.host, "something-less-likely")
def create_image_from_volume(self, device_name, context, image_id, image_meta): """Capture the contents of a volume and upload to glance :param device_name: device in /dev/ to capture :param context: nova context for operation :param image_id: image reference to pre-created image in glance :param image_meta: metadata for new image """ # do the disk copy dest_file_path = common.aix_path_join(CONF.powervm_img_remote_path, image_id) self._copy_device_to_file(device_name, dest_file_path) # compress and copy the file back to the nova-compute host snapshot_file_path = self._copy_image_file_from_host(dest_file_path, CONF.powervm_img_local_path, compress=True) # get glance service glance_service, image_id = glance.get_remote_image_service(context, image_id) # upload snapshot file to glance with open(snapshot_file_path, "r") as img_file: glance_service.update(context, image_id, image_meta, img_file) LOG.debug(_("Snapshot added to glance.")) # clean up local image file try: os.remove(snapshot_file_path) except OSError as ose: LOG.warn(_("Failed to clean up snapshot file " "%(snapshot_file_path)s") % locals())
def _snapshot_ve(self, context, instance, image_id, update_task_state, ve): def upload(context, image_service, image_id, metadata, f): LOG.info("Start uploading image %s ..." % image_id) image_service.update(context, image_id, metadata, f) LOG.info("Image %s uploading complete." % image_id) _image_service = glance.get_remote_image_service(context, image_id) snapshot_image_service, snapshot_image_id = _image_service snapshot = snapshot_image_service.show(context, snapshot_image_id) disk_format = CONF.pcs_snapshot_disk_format metadata = {'is_public': False, 'status': 'active', 'name': snapshot['name'], 'container_format': 'bare', 'disk_format': disk_format, } props = {} metadata['properties'] = props if ve.get_vm_type() == pc.PVT_VM: props['vm_mode'] = 'hvm' else: props['vm_mode'] = 'exe' update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD) hdd = pcsutils.get_boot_disk(ve) hdd_path = hdd.get_image_path() props['pcs_ostemplate'] = ve.get_os_template() if disk_format == 'ploop': xml_path = os.path.join(hdd_path, "DiskDescriptor.xml") cmd = ['ploop', 'snapshot-list', '-H', '-o', 'fname', xml_path] out, err = utils.execute(*cmd, run_as_root=True) image_path = out.strip() with open(xml_path) as f: props['pcs_disk_descriptor'] = f.read().replace('\n', '') with open(image_path) as f: upload(context, snapshot_image_service, image_id, metadata, f) elif disk_format == 'cploop': uploader = pcsutils.CPloopUploader(hdd_path) f = uploader.start() try: upload(context, snapshot_image_service, image_id, metadata, f) finally: uploader.wait() else: dst = tempfile.mktemp(dir=os.path.dirname(hdd_path)) LOG.info("Convert image %s to %s format ..." % (image_id, disk_format)) pcsutils.convert_image(hdd_path, dst, disk_format, root_helper=utils._get_root_helper()) with open(dst) as f: upload(context, snapshot_image_service, image_id, metadata, f) os.unlink(dst)
def fetch_image(context, instance, host, dc_name, ds_name, file_path, cookies=None): """Download image from the glance image server.""" image_ref = instance['image_ref'] LOG.debug("Downloading image file data %(image_ref)s to the " "data store %(data_store_name)s", {'image_ref': image_ref, 'data_store_name': ds_name}, instance=instance) (image_service, image_id) = glance.get_remote_image_service(context, image_ref) metadata = image_service.show(context, image_id) file_size = int(metadata['size']) read_iter = image_service.download(context, image_id) read_file_handle = read_write_util.GlanceFileRead(read_iter) write_file_handle = read_write_util.VMwareHTTPWriteFile( host, dc_name, ds_name, cookies, file_path, file_size) start_transfer(context, read_file_handle, file_size, write_file_handle=write_file_handle) LOG.debug("Downloaded image file data %(image_ref)s to " "%(upload_name)s on the data store " "%(data_store_name)s", {'image_ref': image_ref, 'upload_name': 'n/a' if file_path is None else file_path, 'data_store_name': 'n/a' if ds_name is None else ds_name}, instance=instance)
def apply(self, context, resource, **kwargs): if resource.image_href: (image_service, image_id) = glance.get_remote_image_service( context, resource.image_href) resource.image = jsonutils.to_primitive(image_service.show( context, image_id)) if resource.image['status'] != 'active': raise exception.ImageNotActive(image_id=image_id) else: resource.image = {} if resource.instance_type['memory_mb'] < int( resource.image.get('min_ram') or 0): raise exception.InstanceTypeMemoryTooSmall() if resource.instance_type['root_gb'] < int( resource.image.get('min_disk') or 0): raise exception.InstanceTypeDiskTooSmall() resource.kernel_id, resource.ramdisk_id = \ self._handle_kernel_and_ramdisk(context, resource.kernel_id, resource.ramdisk_id, resource.image) return orc_utils.DictableObject(details='image_validated', resource=resource)
def get_by_image_id(cls, image_id): (image_service, image_id) = glance.get_remote_image_service( context, image_id) image_meta = image_service.show(context, image_id) obj = cls() obj.from_image_props(image_meta.get('properties', {})) return obj
def _retrieve_and_inject_jar_in_container(self, context, container_id, jar_image_id, jar_image_path, jar_image_name): (image_service, image_id) = glance.get_remote_image_service( context, jar_image_id) try: image_service.show(context, image_id) except exception.ImageNotFound: LOG.audit("Sorry jar image does not found") #Here I can re-raise the exception to avoid creation of instance without jar file return #Now I obtain the absolute path where copy jar image inside container LOG.audit('Container ID: "%s"', container_id['Id']) info = self.docker.inspect_container(container_id) if not info: LOG.audit("Container does not exist") return rel_path = "/var/lib/docker/aufs/mnt/{0}".format(info['Id']) abs_path = rel_path + jar_image_path + "/" + jar_image_name LOG.audit('The absolute path of file to inject in this container is: "%s"', abs_path) p_dir = os.path.dirname(abs_path) LOG.audit('The absolute path is: "%s"', p_dir) utils.execute('mkdir', '-p', p_dir, run_as_root=True) LOG.audit('Path created') #Now i can download image and save it in the path create (inside the container) image_chunks = image_service.download(context, jar_image_id) for chunk in image_chunks: self._write_file(abs_path, chunk) LOG.audit("Injection success")
def _save_glance_image(self, context, image_id, image_vhd_path): (glance_image_service, image_id) = glance.get_remote_image_service(context, image_id) image_metadata = {"disk_format": "vhd", "container_format": "bare"} with self._pathutils.open(image_vhd_path, 'rb') as f: glance_image_service.update(context, image_id, image_metadata, f, purge_props=False)
def fetch(context, image_href, path, _user_id, _project_id, max_size=0): # TODO(vish): Improve context handling and add owner and auth data # when it is added to glance. Right now there is no # auth checking in glance, so we assume that access was # checked before we got here. (image_service, image_id) = glance.get_remote_image_service(context, image_href) with fileutils.remove_path_on_error(path): image_service.download(context, image_id, dst_path=path)
def perform_vmhandoff(self, context, instance, handoff_url, update_task_state, residue_glance_id=None): try: if hasattr(self, "_lookup_by_name"): # icehouse virt_dom = self._lookup_by_name(instance["name"]) else: # kilo virt_dom = self._host.get_domain(instance) except exception.InstanceNotFound: raise exception.InstanceNotRunning(instance_id=instance["uuid"]) synthesized_vm = self.synthesized_vm_dics.get(instance["uuid"], None) if synthesized_vm is None: raise exception.InstanceNotRunning(instance_id=instance["uuid"]) # get the file path for Base VM and VM overlay (image_service, image_id) = glance.get_remote_image_service(context, instance["image_ref"]) image_meta = image_service.show(context, image_id) base_sha256_uuid, memory_snap_id, diskhash_snap_id, memhash_snap_id = self._get_basevm_meta_info(image_meta) basedisk_path = self._get_cache_image(context, instance, image_meta["id"]) basemem_path = self._get_cache_image(context, instance, memory_snap_id) diskhash_path = self._get_cache_image(context, instance, diskhash_snap_id) memhash_path = self._get_cache_image(context, instance, memhash_snap_id) base_vm_paths = [basedisk_path, basemem_path, diskhash_path, memhash_path] update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD, expected_state=None) try: residue_filepath = self._handoff_send(base_vm_paths, base_sha256_uuid, synthesized_vm, handoff_url) except handoff.HandoffError as e: msg = "failed to perform VM handoff:\n" msg += str(e) raise exception.ImageNotFound(msg) del self.synthesized_vm_dics[instance["uuid"]] if residue_filepath: LOG.info("residue saved at %s" % residue_filepath) if residue_filepath and residue_glance_id: # export to glance (image_service, image_id) = glance.get_remote_image_service(context, instance["image_ref"]) meta_metadata = self._get_snapshot_metadata(virt_dom, context, instance, residue_glance_id) update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD) self._update_to_glance(context, image_service, residue_filepath, residue_glance_id, meta_metadata) # clean up LOG.info(_("VM residue upload complete"), instance=instance) if residue_filepath and os.path.exists(residue_filepath): os.remove(residue_filepath)
def _save_glance_image(self, context, image_id, image_vhd_path): (glance_image_service, image_id) = glance.get_remote_image_service(context, image_id) image_metadata = {"is_public": False, "disk_format": "vhd", "container_format": "bare", "properties": {}} with self._pathutils.open(image_vhd_path, 'rb') as f: glance_image_service.update(context, image_id, image_metadata, f)
def test_glance_client_image_ref(self): fixture = self._make_fixture(name='test image') image_id = self.service.create(self.context, fixture)['id'] image_url = 'http://something-less-likely/%s' % image_id (service, same_id) = glance.get_remote_image_service( self.context, image_url) self.assertEquals(same_id, image_id) self.assertEquals(service._client.host, 'something-less-likely')
def get_test_image_object(context, instance_ref): if not context: context = get_test_admin_context() image_ref = instance_ref['image_ref'] image_service, image_id = glance.get_remote_image_service(context, image_ref) return objects.ImageMeta.from_dict( image_service.show(context, image_id))
def test_get_remote_service_from_href(self, gcwi_mocked): id_or_uri = 'http://127.0.0.1/123' _ignored, image_id = glance.get_remote_image_service( mock.sentinel.ctx, id_or_uri) self.assertEqual('123', image_id) gcwi_mocked.assert_called_once_with(context=mock.sentinel.ctx, host='127.0.0.1', port=80, use_ssl=False)
def create_volume(self, context, volume_id, snapshot_id=None, image_id=None, reservations=None): """Creates and exports the volume.""" context = context.elevated() volume_ref = self.db.volume_get(context, volume_id) self._notify_about_volume_usage(context, volume_ref, "create.start") LOG.info(_("volume %s: creating"), volume_ref["name"]) self.db.volume_update(context, volume_id, {"host": self.host}) # NOTE(vish): so we don't have to get volume from db again # before passing it to the driver. volume_ref["host"] = self.host status = "available" model_update = False try: vol_name = volume_ref["name"] vol_size = volume_ref["size"] LOG.debug(_("volume %(vol_name)s: creating lv of" " size %(vol_size)sG") % locals()) if snapshot_id is None and image_id is None: model_update = self.driver.create_volume(volume_ref) elif snapshot_id is not None: snapshot_ref = self.db.snapshot_get(context, snapshot_id) model_update = self.driver.create_volume_from_snapshot(volume_ref, snapshot_ref) else: # create the volume from an image image_service, image_id = glance.get_remote_image_service(context, image_id) image_location = image_service.get_location(context, image_id) cloned = self.driver.clone_image(volume_ref, image_location) if not cloned: model_update = self.driver.create_volume(volume_ref) status = "downloading" if model_update: self.db.volume_update(context, volume_ref["id"], model_update) LOG.debug(_("volume %s: creating export"), volume_ref["name"]) model_update = self.driver.create_export(context, volume_ref) if model_update: self.db.volume_update(context, volume_ref["id"], model_update) except Exception: with excutils.save_and_reraise_exception(): self.db.volume_update(context, volume_ref["id"], {"status": "error"}) now = timeutils.utcnow() volume_ref = self.db.volume_update(context, volume_ref["id"], {"status": status, "launched_at": now}) LOG.debug(_("volume %s: created successfully"), volume_ref["name"]) self._reset_stats() self._notify_about_volume_usage(context, volume_ref, "create.end") if image_id and not cloned: # copy the image onto the volume. self._copy_image_to_volume(context, volume_ref, image_id) return volume_id
def fetch(context, image_href, path, _user_id, _project_id): # TODO(vish): Improve context handling and add owner and auth data # when it is added to glance. Right now there is no # auth checking in glance, so we assume that access was # checked before we got here. (image_service, image_id) = glance.get_remote_image_service(context, image_href) with utils.remove_path_on_error(path): with open(path, "wb") as image_file: metadata = image_service.get(context, image_id, image_file) return metadata
def copy_volume_to_image(self, context, volume_id, image_id): """Uploads the specified volume to Glance.""" payload = {"volume_id": volume_id, "image_id": image_id} try: volume = self.db.volume_get(context, volume_id) self.driver.ensure_export(context.elevated(), volume) image_service, image_id = glance.get_remote_image_service(context, image_id) self.driver.copy_volume_to_image(context, volume, image_service, image_id) LOG.debug(_("Uploaded volume %(volume_id)s to " "image (%(image_id)s) successfully") % locals()) except Exception, error: with excutils.save_and_reraise_exception(): payload["message"] = unicode(error)
def _fetch_image(self, context, image_id, image_meta, path, user_id=None, project_id=None, location=None, **kwargs): # TODO(vish): Improve context handling and add owner and auth data # when it is added to glance. Right now there is no # auth checking in glance, so we assume that access was # checked before we got here. (image_service, _image_id) = glance.get_remote_image_service(context, image_id) with fileutils.remove_path_on_error(path): image_service.download(context, image_id, dst_path=path) return os.path.exists(path)
def _get_image_size_glance(self, context, image_href): (image_service, image_id) = glance.get_remote_image_service( context, image_href) try: image_meta = image_service.show(context, image_href) except nova_exception.ImageNotFound: image_meta = {} return 0 size_byte = image_meta['size'] return float(size_byte) / 1024 / 1024 / 1024
def _get_session_and_image_id(self, context, id_or_uri): """Returns a tuple of (session, image_id). If the supplied `id_or_uri` is an image ID, then the default client session will be returned for the context's user, along with the image ID. If the supplied `id_or_uri` parameter is a URI, then a client session connecting to the URI's image service endpoint will be returned along with a parsed image ID from that URI. :param context: The `nova.context.Context` object for the request :param id_or_uri: A UUID identifier or an image URI to look up image information for. """ return glance.get_remote_image_service(context, id_or_uri)
def fetch_image(context, target, image_id, user_id, project_id, max_size=0): """Grab image.""" path_dir = os.path.dirname(target) (image_service, image_id) = glance.get_remote_image_service(context, image_id) image = image_service.show(context, image_id) parent_id = image.get('parent_id', None) if parent_id is None: images.fetch_to_raw(context, image_id, target, user_id, project_id, max_size, False) else: images.fetch_with_backing_file(context, image_id, target, path_dir, user_id, project_id, max_size)
def _delete_image(self, context, image_id): (image_service, image_id) = glance.get_remote_image_service(context, image_id) return image_service.delete(context, image_id)
def snapshot(self, context, instance, image_id, update_task_state): """Create snapshot from a running VM instance. :param context: security context :param instance: nova.objects.instance.Instance :param image_id: Reference to a pre-created image that will hold the snapshot. :param update_task_state: Callback function to update the task_state on the instance while the snapshot operation progresses. The function takes a task_state argument and an optional expected_task_state kwarg which defaults to nova.compute.task_states.IMAGE_SNAPSHOT. See nova.objects.instance.Instance.save for expected_task_state usage. """ # Check the image status (image_service, image_id) = glance.get_remote_image_service(context, image_id) # Update the instance task_state to image_pending_upload update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD) # Call zvmsdk guest_capture to generate the image try: self._reqh.call('guest_capture', instance['name'], image_id) except Exception as err: with excutils.save_and_reraise_exception(): LOG.error(_("Failed to capture the instance %(instance)s " "to generate an image with reason: %(err)s"), { 'instance': instance['name'], 'err': err }, instance=instance) # Clean up the image from glance image_service.delete(context, image_id) # Export the image to nova-compute server temporary image_path = os.path.join(os.path.normpath(CONF.zvm_image_tmp_path), image_id) dest_path = "file://" + image_path try: resp = self._reqh.call('image_export', image_id, dest_path, remote_host=self._get_host()) except Exception as err: LOG.error( _("Failed to export image %s from SDK server to nova " "compute server") % image_id) self._reqh.call('image_delete', image_id) # Save image to glance new_image_meta = { 'is_public': False, 'status': 'active', 'properties': { 'image_location': 'snapshot', 'image_state': 'available', 'owner_id': instance['project_id'], 'os_distro': resp['os_version'], 'architecture': const.ARCHITECTURE, 'hypervisor_type': const.HYPERVISOR_TYPE }, 'disk_format': 'raw', 'container_format': 'bare', } update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD) # Save the image to glance try: with open(image_path, 'r') as image_file: image_service.update(context, image_id, new_image_meta, image_file, purge_props=False) except Exception: with excutils.save_and_reraise_exception(): image_service.delete(context, image_id) finally: self._pathutils.clean_up_file(image_path) self._reqh.call('image_delete', image_id) LOG.debug("Snapshot image upload complete", instance=instance)
def snapshot(self, context, instance, name): """Create snapshot from a running VM instance.""" instance_name = instance["name"] vm = self._vmutils.lookup(self._conn, instance_name) if vm is None: raise exception.InstanceNotFound(instance=instance_name) vm = self._conn.Msvm_ComputerSystem(ElementName=instance_name)[0] vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] LOG.debug(_("Creating snapshot for instance %s"), instance_name) (job_path, ret_val, snap_setting_data) = \ vs_man_svc.CreateVirtualSystemSnapshot(vm.path_()) if ret_val == constants.WMI_JOB_STATUS_STARTED: success = self._vmutils.check_job_status(job_path) if success: job_wmi_path = job_path.replace('\\', '/') job = wmi.WMI(moniker=job_wmi_path) snap_setting_data = job.associators( wmi_result_class='Msvm_VirtualSystemSettingData')[0] else: success = (ret_val == 0) if not success: raise vmutils.HyperVException( _('Failed to create snapshot for VM %s') % instance_name) export_folder = None f = None try: src_vhd_path = os.path.join(FLAGS.instances_path, instance_name, instance_name + ".vhd") image_man_svc = self._conn.Msvm_ImageManagementService()[0] LOG.debug(_("Getting info for VHD %s"), src_vhd_path) (src_vhd_info, job_path, ret_val) = \ image_man_svc.GetVirtualHardDiskInfo(src_vhd_path) if ret_val == constants.WMI_JOB_STATUS_STARTED: success = self._vmutils.check_job_status(job_path) else: success = (ret_val == 0) if not success: raise vmutils.HyperVException( _("Failed to get info for disk %s") % (src_vhd_path)) src_base_disk_path = None et = ElementTree.fromstring(src_vhd_info) for item in et.findall("PROPERTY"): if item.attrib["NAME"] == "ParentPath": src_base_disk_path = item.find("VALUE").text break export_folder = self._vmutils.make_export_path(instance_name) dest_vhd_path = os.path.join(export_folder, os.path.basename(src_vhd_path)) LOG.debug(_('Copying VHD %(src_vhd_path)s to %(dest_vhd_path)s'), locals()) shutil.copyfile(src_vhd_path, dest_vhd_path) image_vhd_path = None if not src_base_disk_path: image_vhd_path = dest_vhd_path else: dest_base_disk_path = os.path.join( export_folder, os.path.basename(src_base_disk_path)) LOG.debug( _('Copying base disk %(src_vhd_path)s to ' '%(dest_base_disk_path)s'), locals()) shutil.copyfile(src_base_disk_path, dest_base_disk_path) LOG.debug( _("Reconnecting copied base VHD " "%(dest_base_disk_path)s and diff VHD %(dest_vhd_path)s" ), locals()) (job_path, ret_val) = \ image_man_svc.ReconnectParentVirtualHardDisk( ChildPath=dest_vhd_path, ParentPath=dest_base_disk_path, Force=True) if ret_val == constants.WMI_JOB_STATUS_STARTED: success = self._vmutils.check_job_status(job_path) else: success = (ret_val == 0) if not success: raise vmutils.HyperVException( _("Failed to reconnect base disk " "%(dest_base_disk_path)s and diff disk " "%(dest_vhd_path)s") % locals()) LOG.debug( _("Merging base disk %(dest_base_disk_path)s and " "diff disk %(dest_vhd_path)s"), locals()) (job_path, ret_val) = image_man_svc.MergeVirtualHardDisk( SourcePath=dest_vhd_path, DestinationPath=dest_base_disk_path) if ret_val == constants.WMI_JOB_STATUS_STARTED: success = self._vmutils.check_job_status(job_path) else: success = (ret_val == 0) if not success: raise vmutils.HyperVException( _("Failed to merge base disk %(dest_base_disk_path)s " "and diff disk %(dest_vhd_path)s") % locals()) image_vhd_path = dest_base_disk_path (glance_image_service, image_id) = \ glance.get_remote_image_service(context, name) image_metadata = { "is_public": False, "disk_format": "vhd", "container_format": "bare", "properties": {} } f = ioutils.open(image_vhd_path, 'rb') LOG.debug( _("Updating Glance image %(image_id)s with content from " "merged disk %(image_vhd_path)s"), locals()) glance_image_service.update(context, image_id, image_metadata, f) LOG.debug( _("Snapshot image %(image_id)s updated for VM " "%(instance_name)s"), locals()) finally: LOG.debug(_("Removing snapshot %s"), name) (job_path, ret_val) = vs_man_svc.RemoveVirtualSystemSnapshot( snap_setting_data.path_()) if ret_val == constants.WMI_JOB_STATUS_STARTED: success = self._vmutils.check_job_status(job_path) else: success = (ret_val == 0) if not success: raise vmutils.HyperVException( _('Failed to remove snapshot for VM %s') % instance_name) if f: f.close() if export_folder: LOG.debug(_('Removing folder %s '), export_folder) shutil.rmtree(export_folder)
def perform_vmhandoff(self, context, instance, handoff_url, update_task_state, residue_glance_id=None): try: if hasattr(self, "_lookup_by_name"): # icehouse virt_dom = self._lookup_by_name(instance['name']) else: # kilo virt_dom = self._host.get_domain(instance) except exception.InstanceNotFound: raise exception.InstanceNotRunning(instance_id=instance['uuid']) synthesized_vm = self.synthesized_vm_dics.get(instance['uuid'], None) if synthesized_vm is None: raise exception.InstanceNotRunning(instance_id=instance['uuid']) # get the file path for Base VM and VM overlay (image_service, image_id) = glance.get_remote_image_service(context, instance['image_ref']) image_meta = image_service.show(context, image_id) base_sha256_uuid, memory_snap_id, diskhash_snap_id, memhash_snap_id = \ self._get_basevm_meta_info(image_meta) basedisk_path = self._get_cache_image(context, instance, image_meta['id']) basemem_path = self._get_cache_image(context, instance, memory_snap_id) diskhash_path = self._get_cache_image(context, instance, diskhash_snap_id) memhash_path = self._get_cache_image(context, instance, memhash_snap_id) base_vm_paths = [ basedisk_path, basemem_path, diskhash_path, memhash_path ] update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD, expected_state=None) try: residue_filepath = self._handoff_send(base_vm_paths, base_sha256_uuid, synthesized_vm, handoff_url) except handoff.HandoffError as e: msg = "failed to perform VM handoff:\n" msg += str(e) raise exception.ImageNotFound(msg) del self.synthesized_vm_dics[instance['uuid']] if residue_filepath: LOG.info("residue saved at %s" % residue_filepath) if residue_filepath and residue_glance_id: # export to glance (image_service, image_id) = glance.get_remote_image_service( context, instance['image_ref']) meta_metadata = self._get_snapshot_metadata( virt_dom, context, instance, residue_glance_id) update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD) self._update_to_glance(context, image_service, residue_filepath, residue_glance_id, meta_metadata) # clean up LOG.info(_("VM residue upload complete"), instance=instance) if residue_filepath and os.path.exists(residue_filepath): os.remove(residue_filepath)
def cloudlet_base(self, context, instance, vm_name, disk_meta_id, memory_meta_id, diskhash_meta_id, memoryhash_meta_id, update_task_state): """create base vm and save it to glance """ try: if hasattr(self, "_lookup_by_name"): # icehouse virt_dom = self._lookup_by_name(instance['name']) else: # kilo virt_dom = self._host.get_domain(instance) except exception.InstanceNotFound: raise exception.InstanceNotRunning(instance_id=instance['uuid']) # pause VM self.pause(instance) (image_service, image_id) = glance.get_remote_image_service(context, instance['image_ref']) disk_metadata = self._get_snapshot_metadata(virt_dom, context, instance, disk_meta_id) mem_metadata = self._get_snapshot_metadata(virt_dom, context, instance, memory_meta_id) diskhash_metadata = self._get_snapshot_metadata( virt_dom, context, instance, diskhash_meta_id) memhash_metadata = self._get_snapshot_metadata(virt_dom, context, instance, memoryhash_meta_id) disk_path = libvirt_utils.find_disk(virt_dom) source_format = libvirt_utils.get_disk_type(disk_path) snapshot_name = uuid.uuid4().hex (state, _max_mem, _mem, _cpus, _t) = virt_dom.info() state = libvirt_driver.LIBVIRT_POWER_STATE[state] # creating base vm requires cold snapshotting snapshot_backend = self.image_backend.snapshot( disk_path, image_type=source_format) LOG.info(_("Beginning cold snapshot process"), instance=instance) # not available at icehouse # snapshot_backend.snapshot_create() update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD, expected_state=None) snapshot_directory = libvirt_driver.CONF.libvirt.snapshots_directory fileutils.ensure_tree(snapshot_directory) with utils.tempdir(dir=snapshot_directory) as tmpdir: try: out_path = os.path.join(tmpdir, snapshot_name) # At this point, base vm should be "raw" format snapshot_backend.snapshot_extract(out_path, "raw") finally: # snapshotting logic is changed since icehouse. # : cannot find snapshot_create and snapshot_delete. # snapshot_extract is replacing these two operations. # snapshot_backend.snapshot_delete() LOG.info(_("Snapshot extracted, beginning image upload"), instance=instance) # generate memory snapshop and hashlist basemem_path = os.path.join(tmpdir, snapshot_name + "-mem") diskhash_path = os.path.join(tmpdir, snapshot_name + "-disk_hash") memhash_path = os.path.join(tmpdir, snapshot_name + "-mem_hash") update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD) synthesis._create_baseVM(self._conn, virt_dom, out_path, basemem_path, diskhash_path, memhash_path, nova_util=libvirt_utils) self._update_to_glance(context, image_service, out_path, disk_meta_id, disk_metadata) LOG.info(_("Base disk upload complete"), instance=instance) self._update_to_glance(context, image_service, basemem_path, memory_meta_id, mem_metadata) LOG.info(_("Base memory image upload complete"), instance=instance) self._update_to_glance(context, image_service, diskhash_path, diskhash_meta_id, diskhash_metadata) LOG.info(_("Base disk upload complete"), instance=instance) self._update_to_glance(context, image_service, memhash_path, memoryhash_meta_id, memhash_metadata) LOG.info(_("Base memory image upload complete"), instance=instance)
def snapshot(self, context, instance, image_id, update_task_state): (image_service, image_id) = glance.get_remote_image_service(context, image_id) update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD) try: self._hypervisor.guest_capture(instance.name, image_id) except Exception as err: with excutils.save_and_reraise_exception(): LOG.error( "Failed to capture the instance " "to generate an image with reason: %(err)s", {'err': err}, instance=instance) # Clean up the image from glance image_service.delete(context, image_id) # Export the image to nova-compute server temporary image_path = os.path.join(os.path.normpath(CONF.zvm.image_tmp_path), image_id) dest_path = "file://" + image_path try: resp = self._hypervisor.image_export(image_id, dest_path) except Exception: with excutils.save_and_reraise_exception(): LOG.error( "Failed to export image %s from SDK server to " "nova compute server", image_id) image_service.delete(context, image_id) self._hypervisor.image_delete(image_id) # Save image to glance new_image_meta = { 'status': 'active', 'properties': { 'image_location': 'snapshot', 'image_state': 'available', 'owner_id': instance['project_id'], 'os_distro': resp['os_version'], 'architecture': obj_fields.Architecture.S390X, 'hypervisor_type': obj_fields.HVType.ZVM, }, 'disk_format': 'raw', 'container_format': 'bare', } update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD) # Save the image to glance try: with open(image_path, 'r') as image_file: image_service.update(context, image_id, new_image_meta, image_file, purge_props=False) except Exception: with excutils.save_and_reraise_exception(): image_service.delete(context, image_id) finally: zvmutils.clean_up_file(image_path) self._hypervisor.image_delete(image_id) LOG.debug("Snapshot image upload complete", instance=instance)
def test_get_remote_service_from_id(self, gcwi_mocked): id_or_uri = '123' _ignored, image_id = glance.get_remote_image_service( mock.sentinel.ctx, id_or_uri) self.assertEqual(id_or_uri, image_id) gcwi_mocked.assert_called_once_with()
def setUp(self, mock_register): super(ConfigDriveTestCase, self).setUp() vm_util.vm_refs_cache_reset() self.context = context.RequestContext('fake', 'fake', is_admin=False) self.flags(cluster_name='test_cluster', host_ip='test_url', host_username='******', host_password='******', use_linked_clone=False, group='vmware') self.flags(enabled=False, group='vnc') vmwareapi_fake.reset() stubs.set_stubs(self.stubs) nova.tests.unit.image.fake.stub_out_image_service(self.stubs) self.conn = driver.VMwareVCDriver(fake.FakeVirtAPI) self.network_info = utils.get_test_network_info() self.node_name = self.conn._nodename image_ref = nova.tests.unit.image.fake.get_valid_image_id() instance_values = { 'vm_state': 'building', 'project_id': 'fake', 'user_id': 'fake', 'name': '1', 'kernel_id': '1', 'ramdisk_id': '1', 'mac_addresses': [{'address': 'de:ad:be:ef:be:ef'}], 'memory_mb': 8192, 'flavor': objects.Flavor(vcpus=4, extra_specs={}), 'instance_type_id': 0, 'vcpus': 4, 'root_gb': 80, 'image_ref': image_ref, 'host': 'fake_host', 'task_state': 'scheduling', 'reservation_id': 'r-3t8muvr0', 'id': 1, 'uuid': 'fake-uuid', 'node': self.node_name, 'metadata': [], 'expected_attrs': ['system_metadata'], } self.test_instance = fake_instance.fake_instance_obj(self.context, **instance_values) self.test_instance.flavor = objects.Flavor(vcpus=4, memory_mb=8192, ephemeral_gb=0, swap=0, extra_specs={}) (image_service, image_id) = glance.get_remote_image_service(context, image_ref) metadata = image_service.show(context, image_id) self.image = { 'id': image_ref, 'disk_format': 'vmdk', 'size': int(metadata['size']), } class FakeInstanceMetadata(object): def __init__(self, instance, content=None, extra_md=None, network_info=None): pass def metadata_for_config_drive(self): return [] self.useFixture(fixtures.MonkeyPatch( 'nova.api.metadata.base.InstanceMetadata', FakeInstanceMetadata)) def fake_make_drive(_self, _path): pass # We can't actually make a config drive v2 because ensure_tree has # been faked out self.stubs.Set(nova.virt.configdrive.ConfigDriveBuilder, 'make_drive', fake_make_drive) def fake_upload_iso_to_datastore(iso_path, instance, **kwargs): pass self.stubs.Set(images, 'upload_iso_to_datastore', fake_upload_iso_to_datastore)
def test_glance_client_image_id(self): fixture = self._make_fixture(name='test image') image_id = self.service.create(self.context, fixture)['id'] (service, same_id) = glance.get_remote_image_service(self.context, image_id) self.assertEquals(same_id, image_id)