'Create snapshot from a running VM instance.
This command only works with qemu 0.14+'

def snapshot(self, context, instance, image_id, update_task_state):

    try:
        guest = self._host.get_guest(instance)
        virt_dom = guest._domain
    except exception.InstanceNotFound:
        raise exception.InstanceNotRunning(instance_id=instance.uuid)
    snapshot = self._image_api.get(context, image_id)
    (disk_path, source_format) = libvirt_utils.find_disk(guest)
    source_type = libvirt_utils.get_disk_type_from_path(disk_path)
    if (source_type is None):
        source_type = source_format
    image_format = (CONF.libvirt.snapshot_image_format or source_type)
    if ((image_format == 'lvm') or (image_format == 'rbd')):
        image_format = 'raw'
    metadata = self._create_snapshot_metadata(instance.image_meta, instance, image_format, snapshot['name'])
    snapshot_name = uuid.uuid4().hex
    state = guest.get_power_state(self._host)
    if (self._host.has_min_version(hv_type=host.HV_DRIVER_QEMU) and (source_type not in 'lvm') and (not CONF.ephemeral_storage_encryption.enabled) and (not CONF.workarounds.disable_libvirt_livesnapshot)):
        live_snapshot = True
        try:
            guest.get_block_device(disk_path).abort_job()
        except libvirt.libvirtError as ex:
            error_code = ex.get_error_code()
            if (error_code == libvirt.VIR_ERR_CONFIG_UNSUPPORTED):
                live_snapshot = False
            else:
                pass
    else:
        live_snapshot = False
    if (state == power_state.SHUTDOWN):
        live_snapshot = False
    self._prepare_domain_for_snapshot(context, live_snapshot, state, instance)
    root_disk = self.image_backend.by_libvirt_path(instance, disk_path, image_type=source_type)
    if live_snapshot:
        LOG.info('Beginning    live    snapshot    process', instance=instance)
    else:
        LOG.info('Beginning    cold    snapshot    process', instance=instance)
    update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD)
    try:
        update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD)
        metadata['location'] = root_disk.direct_snapshot(context, snapshot_name, image_format, image_id, instance.image_ref)
        self._snapshot_domain(context, live_snapshot, virt_dom, state, instance)
        self._image_api.update(context, image_id, metadata, purge_props=False)
    except (NotImplementedError, exception.ImageUnacceptable, exception.Forbidden) as e:
        if (type(e) != NotImplementedError):
            LOG.warning('Performing    standard    snapshot    because    direct    snapshot    failed:    %(error)s', {'error': e})
        failed_snap = metadata.pop('location', None)
        if failed_snap:
            failed_snap = {'url': str(failed_snap)}
        root_disk.cleanup_direct_snapshot(failed_snap, also_destroy_volume=True, ignore_errors=True)
        update_task_state(task_state=task_states.IMAGE_PENDING_UPLOAD, expected_state=task_states.IMAGE_UPLOADING)
        if ((source_type == 'rbd') and live_snapshot):
            live_snapshot = False
            self._prepare_domain_for_snapshot(context, live_snapshot, state, instance)
        snapshot_directory = 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)
                if live_snapshot:
                    os.chmod(tmpdir, 449)
                    self._live_snapshot(context, instance, guest, disk_path, out_path, source_format, image_format, instance.image_meta)
                else:
                    root_disk.snapshot_extract(out_path, image_format)
            finally:
                self._snapshot_domain(context, live_snapshot, virt_dom, state, instance)
                LOG.info('Snapshot    extracted,    beginning    image    upload', instance=instance)
            update_task_state(task_state=task_states.IMAGE_UPLOADING, expected_state=task_states.IMAGE_PENDING_UPLOAD)
            with libvirt_utils.file_open(out_path, 'rb') as image_file:
                self._image_api.update(context, image_id, metadata, image_file)
    except Exception:
        with excutils.save_and_reraise_exception():
            LOG.exception(_('Failed    to    snapshot    image'))
            failed_snap = metadata.pop('location', None)
            if failed_snap:
                failed_snap = {'url': str(failed_snap)}
            root_disk.cleanup_direct_snapshot(failed_snap, also_destroy_volume=True, ignore_errors=True)
    LOG.info('Snapshot    image    upload    complete', instance=instance)
