[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v11 12/12] migration: introduce snapshot-{save, load, delete}
From: |
Dr. David Alan Gilbert |
Subject: |
Re: [PATCH v11 12/12] migration: introduce snapshot-{save, load, delete} QMP commands |
Date: |
Thu, 4 Feb 2021 15:34:33 +0000 |
User-agent: |
Mutt/1.14.6 (2020-07-11) |
This is (intermittently?) failing for me because of ordering issues:
---
/home/dgilbert/git/migpull/tests/qemu-iotests/tests/internal-snapshots-qapi.out
+++ internal-snapshots-qapi.out.bad
@@ -344,8 +344,8 @@
"vmstate": "diskfmt0",
"devices": ["diskfmt0"]}}
{"return": {}}
+qemu-system-x86_64: Unknown savevm section or instance
'0000:00:02.0/virtio-rng' 0. Make sure that your current VM setup matches your
saved VM setup, including any hotplugged devices
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
"JOB_STATUS_CHANGE", "data": {"status": "created", "id": "load-err-stderr"}}
-qemu-system-x86_64: Unknown savevm section or instance
'0000:00:02.0/virtio-rng' 0. Make sure that your current VM setup matches your
saved VM setup, including any hotplugged devices
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
"JOB_STATUS_CHANGE", "data": {"status": "running", "id": "load-err-stderr"}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
"STOP"}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
"JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "load-err-stderr"}}
Not run: 259
Failures: internal-snapshots-qapi
Failed 1 of 124 iotests
I'll disable the test for now.
Dave
* Daniel P. Berrangé (berrange@redhat.com) wrote:
> savevm, loadvm and delvm are some of the few HMP commands that have never
> been converted to use QMP. The reasons for the lack of conversion are
> that they blocked execution of the event thread, and the semantics
> around choice of disks were ill-defined.
>
> Despite this downside, however, libvirt and applications using libvirt
> have used these commands for as long as QMP has existed, via the
> "human-monitor-command" passthrough command. IOW, while it is clearly
> desirable to be able to fix the problems, they are not a blocker to
> all real world usage.
>
> Meanwhile there is a need for other features which involve adding new
> parameters to the commands. This is possible with HMP passthrough, but
> it provides no reliable way for apps to introspect features, so using
> QAPI modelling is highly desirable.
>
> This patch thus introduces new snapshot-{load,save,delete} commands to
> QMP that are intended to replace the old HMP counterparts. The new
> commands are given different names, because they will be using the new
> QEMU job framework and thus will have diverging behaviour from the HMP
> originals. It would thus be misleading to keep the same name.
>
> While this design uses the generic job framework, the current impl is
> still blocking. The intention that the blocking problem is fixed later.
> None the less applications using these new commands should assume that
> they are asynchronous and thus wait for the job status change event to
> indicate completion.
>
> In addition to using the job framework, the new commands require the
> caller to be explicit about all the block device nodes used in the
> snapshot operations, with no built-in default heuristics in use.
>
> Note that the existing "query-named-block-nodes" can be used to query
> what snapshots currently exist for block nodes.
>
> Acked-by: Markus Armbruster <armbru@redhat.com>
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
> migration/savevm.c | 184 +++++++
> qapi/job.json | 9 +-
> qapi/migration.json | 173 ++++++
> .../tests/internal-snapshots-qapi | 386 +++++++++++++
> .../tests/internal-snapshots-qapi.out | 520 ++++++++++++++++++
> 5 files changed, 1271 insertions(+), 1 deletion(-)
> create mode 100755 tests/qemu-iotests/tests/internal-snapshots-qapi
> create mode 100644 tests/qemu-iotests/tests/internal-snapshots-qapi.out
>
> diff --git a/migration/savevm.c b/migration/savevm.c
> index 48186918a3..6b320423c7 100644
> --- a/migration/savevm.c
> +++ b/migration/savevm.c
> @@ -3077,3 +3077,187 @@ bool vmstate_check_only_migratable(const
> VMStateDescription *vmsd)
>
> return !(vmsd && vmsd->unmigratable);
> }
> +
> +typedef struct SnapshotJob {
> + Job common;
> + char *tag;
> + char *vmstate;
> + strList *devices;
> + Coroutine *co;
> + Error **errp;
> + bool ret;
> +} SnapshotJob;
> +
> +static void qmp_snapshot_job_free(SnapshotJob *s)
> +{
> + g_free(s->tag);
> + g_free(s->vmstate);
> + qapi_free_strList(s->devices);
> +}
> +
> +
> +static void snapshot_load_job_bh(void *opaque)
> +{
> + Job *job = opaque;
> + SnapshotJob *s = container_of(job, SnapshotJob, common);
> + int orig_vm_running;
> +
> + job_progress_set_remaining(&s->common, 1);
> +
> + orig_vm_running = runstate_is_running();
> + vm_stop(RUN_STATE_RESTORE_VM);
> +
> + s->ret = load_snapshot(s->tag, s->vmstate, true, s->devices, s->errp);
> + if (s->ret && orig_vm_running) {
> + vm_start();
> + }
> +
> + job_progress_update(&s->common, 1);
> +
> + qmp_snapshot_job_free(s);
> + aio_co_wake(s->co);
> +}
> +
> +static void snapshot_save_job_bh(void *opaque)
> +{
> + Job *job = opaque;
> + SnapshotJob *s = container_of(job, SnapshotJob, common);
> +
> + job_progress_set_remaining(&s->common, 1);
> + s->ret = save_snapshot(s->tag, false, s->vmstate,
> + true, s->devices, s->errp);
> + job_progress_update(&s->common, 1);
> +
> + qmp_snapshot_job_free(s);
> + aio_co_wake(s->co);
> +}
> +
> +static void snapshot_delete_job_bh(void *opaque)
> +{
> + Job *job = opaque;
> + SnapshotJob *s = container_of(job, SnapshotJob, common);
> +
> + job_progress_set_remaining(&s->common, 1);
> + s->ret = delete_snapshot(s->tag, true, s->devices, s->errp);
> + job_progress_update(&s->common, 1);
> +
> + qmp_snapshot_job_free(s);
> + aio_co_wake(s->co);
> +}
> +
> +static int coroutine_fn snapshot_save_job_run(Job *job, Error **errp)
> +{
> + SnapshotJob *s = container_of(job, SnapshotJob, common);
> + s->errp = errp;
> + s->co = qemu_coroutine_self();
> + aio_bh_schedule_oneshot(qemu_get_aio_context(),
> + snapshot_save_job_bh, job);
> + qemu_coroutine_yield();
> + return s->ret ? 0 : -1;
> +}
> +
> +static int coroutine_fn snapshot_load_job_run(Job *job, Error **errp)
> +{
> + SnapshotJob *s = container_of(job, SnapshotJob, common);
> + s->errp = errp;
> + s->co = qemu_coroutine_self();
> + aio_bh_schedule_oneshot(qemu_get_aio_context(),
> + snapshot_load_job_bh, job);
> + qemu_coroutine_yield();
> + return s->ret ? 0 : -1;
> +}
> +
> +static int coroutine_fn snapshot_delete_job_run(Job *job, Error **errp)
> +{
> + SnapshotJob *s = container_of(job, SnapshotJob, common);
> + s->errp = errp;
> + s->co = qemu_coroutine_self();
> + aio_bh_schedule_oneshot(qemu_get_aio_context(),
> + snapshot_delete_job_bh, job);
> + qemu_coroutine_yield();
> + return s->ret ? 0 : -1;
> +}
> +
> +
> +static const JobDriver snapshot_load_job_driver = {
> + .instance_size = sizeof(SnapshotJob),
> + .job_type = JOB_TYPE_SNAPSHOT_LOAD,
> + .run = snapshot_load_job_run,
> +};
> +
> +static const JobDriver snapshot_save_job_driver = {
> + .instance_size = sizeof(SnapshotJob),
> + .job_type = JOB_TYPE_SNAPSHOT_SAVE,
> + .run = snapshot_save_job_run,
> +};
> +
> +static const JobDriver snapshot_delete_job_driver = {
> + .instance_size = sizeof(SnapshotJob),
> + .job_type = JOB_TYPE_SNAPSHOT_DELETE,
> + .run = snapshot_delete_job_run,
> +};
> +
> +
> +void qmp_snapshot_save(const char *job_id,
> + const char *tag,
> + const char *vmstate,
> + strList *devices,
> + Error **errp)
> +{
> + SnapshotJob *s;
> +
> + s = job_create(job_id, &snapshot_save_job_driver, NULL,
> + qemu_get_aio_context(), JOB_MANUAL_DISMISS,
> + NULL, NULL, errp);
> + if (!s) {
> + return;
> + }
> +
> + s->tag = g_strdup(tag);
> + s->vmstate = g_strdup(vmstate);
> + s->devices = QAPI_CLONE(strList, devices);
> +
> + job_start(&s->common);
> +}
> +
> +void qmp_snapshot_load(const char *job_id,
> + const char *tag,
> + const char *vmstate,
> + strList *devices,
> + Error **errp)
> +{
> + SnapshotJob *s;
> +
> + s = job_create(job_id, &snapshot_load_job_driver, NULL,
> + qemu_get_aio_context(), JOB_MANUAL_DISMISS,
> + NULL, NULL, errp);
> + if (!s) {
> + return;
> + }
> +
> + s->tag = g_strdup(tag);
> + s->vmstate = g_strdup(vmstate);
> + s->devices = QAPI_CLONE(strList, devices);
> +
> + job_start(&s->common);
> +}
> +
> +void qmp_snapshot_delete(const char *job_id,
> + const char *tag,
> + strList *devices,
> + Error **errp)
> +{
> + SnapshotJob *s;
> +
> + s = job_create(job_id, &snapshot_delete_job_driver, NULL,
> + qemu_get_aio_context(), JOB_MANUAL_DISMISS,
> + NULL, NULL, errp);
> + if (!s) {
> + return;
> + }
> +
> + s->tag = g_strdup(tag);
> + s->devices = QAPI_CLONE(strList, devices);
> +
> + job_start(&s->common);
> +}
> diff --git a/qapi/job.json b/qapi/job.json
> index 280c2f76f1..1a6ef03451 100644
> --- a/qapi/job.json
> +++ b/qapi/job.json
> @@ -22,10 +22,17 @@
> #
> # @amend: image options amend job type, see "x-blockdev-amend" (since 5.1)
> #
> +# @snapshot-load: snapshot load job type, see "snapshot-load" (since 6.0)
> +#
> +# @snapshot-save: snapshot save job type, see "snapshot-save" (since 6.0)
> +#
> +# @snapshot-delete: snapshot delete job type, see "snapshot-delete" (since
> 6.0)
> +#
> # Since: 1.7
> ##
> { 'enum': 'JobType',
> - 'data': ['commit', 'stream', 'mirror', 'backup', 'create', 'amend'] }
> + 'data': ['commit', 'stream', 'mirror', 'backup', 'create', 'amend',
> + 'snapshot-load', 'snapshot-save', 'snapshot-delete'] }
>
> ##
> # @JobStatus:
> diff --git a/qapi/migration.json b/qapi/migration.json
> index d1d9632c2a..5ca0ff9bed 100644
> --- a/qapi/migration.json
> +++ b/qapi/migration.json
> @@ -1843,3 +1843,176 @@
> # Since: 5.2
> ##
> { 'command': 'query-dirty-rate', 'returns': 'DirtyRateInfo' }
> +
> +##
> +# @snapshot-save:
> +#
> +# Save a VM snapshot
> +#
> +# @job-id: identifier for the newly created job
> +# @tag: name of the snapshot to create
> +# @vmstate: block device node name to save vmstate to
> +# @devices: list of block device node names to save a snapshot to
> +#
> +# Applications should not assume that the snapshot save is complete
> +# when this command returns. The job commands / events must be used
> +# to determine completion and to fetch details of any errors that arise.
> +#
> +# Note that execution of the guest CPUs may be stopped during the
> +# time it takes to save the snapshot. A future version of QEMU
> +# may ensure CPUs are executing continuously.
> +#
> +# It is strongly recommended that @devices contain all writable
> +# block device nodes if a consistent snapshot is required.
> +#
> +# If @tag already exists, an error will be reported
> +#
> +# Returns: nothing
> +#
> +# Example:
> +#
> +# -> { "execute": "snapshot-save",
> +# "data": {
> +# "job-id": "snapsave0",
> +# "tag": "my-snap",
> +# "vmstate": "disk0",
> +# "devices": ["disk0", "disk1"]
> +# }
> +# }
> +# <- { "return": { } }
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "created", "id": "snapsave0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "running", "id": "snapsave0"}}
> +# <- {"event": "STOP"}
> +# <- {"event": "RESUME"}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "waiting", "id": "snapsave0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "pending", "id": "snapsave0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "concluded", "id": "snapsave0"}}
> +# -> {"execute": "query-jobs"}
> +# <- {"return": [{"current-progress": 1,
> +# "status": "concluded",
> +# "total-progress": 1,
> +# "type": "snapshot-save",
> +# "id": "snapsave0"}]}
> +#
> +# Since: 6.0
> +##
> +{ 'command': 'snapshot-save',
> + 'data': { 'job-id': 'str',
> + 'tag': 'str',
> + 'vmstate': 'str',
> + 'devices': ['str'] } }
> +
> +##
> +# @snapshot-load:
> +#
> +# Load a VM snapshot
> +#
> +# @job-id: identifier for the newly created job
> +# @tag: name of the snapshot to load.
> +# @vmstate: block device node name to load vmstate from
> +# @devices: list of block device node names to load a snapshot from
> +#
> +# Applications should not assume that the snapshot load is complete
> +# when this command returns. The job commands / events must be used
> +# to determine completion and to fetch details of any errors that arise.
> +#
> +# Note that execution of the guest CPUs will be stopped during the
> +# time it takes to load the snapshot.
> +#
> +# It is strongly recommended that @devices contain all writable
> +# block device nodes that can have changed since the original
> +# @snapshot-save command execution.
> +#
> +# Returns: nothing
> +#
> +# Example:
> +#
> +# -> { "execute": "snapshot-load",
> +# "data": {
> +# "job-id": "snapload0",
> +# "tag": "my-snap",
> +# "vmstate": "disk0",
> +# "devices": ["disk0", "disk1"]
> +# }
> +# }
> +# <- { "return": { } }
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "created", "id": "snapload0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "running", "id": "snapload0"}}
> +# <- {"event": "STOP"}
> +# <- {"event": "RESUME"}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "waiting", "id": "snapload0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "pending", "id": "snapload0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "concluded", "id": "snapload0"}}
> +# -> {"execute": "query-jobs"}
> +# <- {"return": [{"current-progress": 1,
> +# "status": "concluded",
> +# "total-progress": 1,
> +# "type": "snapshot-load",
> +# "id": "snapload0"}]}
> +#
> +# Since: 6.0
> +##
> +{ 'command': 'snapshot-load',
> + 'data': { 'job-id': 'str',
> + 'tag': 'str',
> + 'vmstate': 'str',
> + 'devices': ['str'] } }
> +
> +##
> +# @snapshot-delete:
> +#
> +# Delete a VM snapshot
> +#
> +# @job-id: identifier for the newly created job
> +# @tag: name of the snapshot to delete.
> +# @devices: list of block device node names to delete a snapshot from
> +#
> +# Applications should not assume that the snapshot delete is complete
> +# when this command returns. The job commands / events must be used
> +# to determine completion and to fetch details of any errors that arise.
> +#
> +# Returns: nothing
> +#
> +# Example:
> +#
> +# -> { "execute": "snapshot-delete",
> +# "data": {
> +# "job-id": "snapdelete0",
> +# "tag": "my-snap",
> +# "devices": ["disk0", "disk1"]
> +# }
> +# }
> +# <- { "return": { } }
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "created", "id": "snapdelete0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "running", "id": "snapdelete0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "waiting", "id": "snapdelete0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "pending", "id": "snapdelete0"}}
> +# <- {"event": "JOB_STATUS_CHANGE",
> +# "data": {"status": "concluded", "id": "snapdelete0"}}
> +# -> {"execute": "query-jobs"}
> +# <- {"return": [{"current-progress": 1,
> +# "status": "concluded",
> +# "total-progress": 1,
> +# "type": "snapshot-delete",
> +# "id": "snapdelete0"}]}
> +#
> +# Since: 6.0
> +##
> +{ 'command': 'snapshot-delete',
> + 'data': { 'job-id': 'str',
> + 'tag': 'str',
> + 'devices': ['str'] } }
> diff --git a/tests/qemu-iotests/tests/internal-snapshots-qapi
> b/tests/qemu-iotests/tests/internal-snapshots-qapi
> new file mode 100755
> index 0000000000..6467eaaac0
> --- /dev/null
> +++ b/tests/qemu-iotests/tests/internal-snapshots-qapi
> @@ -0,0 +1,386 @@
> +#!/usr/bin/env bash
> +# group: rw auto quick snapshot
> +#
> +# Test which nodes are involved in internal snapshots
> +#
> +# Copyright (C) 2020-2021 Red Hat, Inc.
> +#
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 2 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +#
> +
> +# creator
> +owner=berrange@redhat.com
> +
> +seq=`basename $0`
> +echo "QA output created by $seq"
> +
> +status=1 # failure is the default!
> +
> +_cleanup()
> +{
> + _cleanup_qemu
> + _cleanup_test_img
> + TEST_IMG="$TEST_IMG.alt1" _cleanup_test_img
> + TEST_IMG="$TEST_IMG.alt2" _cleanup_test_img
> + rm -f "$SOCK_DIR/nbd"
> +}
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +# get standard environment, filters and checks
> +. ../common.rc
> +. ../common.filter
> +. ../common.qemu
> +
> +_supported_fmt qcow2
> +_supported_proto file
> +_supported_os Linux
> +_require_drivers copy-on-read
> +
> +# Internal snapshots are (currently) impossible with refcount_bits=1,
> +# and generally impossible with external data files
> +_unsupported_imgopts 'refcount_bits=1[^0-9]' data_file
> +
> +_require_devices virtio-blk
> +
> +
> +size=128M
> +
> +if [ -n "$BACKING_FILE" ]; then
> + _make_test_img -b "$BACKING_FILE" -F $IMGFMT $size
> +else
> + _make_test_img $size
> +fi
> +TEST_IMG="$TEST_IMG.alt1" _make_test_img $size
> +IMGOPTS= IMGFMT=raw TEST_IMG="$TEST_IMG.alt2" _make_test_img $size
> +
> +export capture_events="JOB_STATUS_CHANGE STOP RESUME"
> +
> +wait_job()
> +{
> + local job=$1
> + shift
> +
> + # All jobs start with two events...
> + #
> + # created
> + _wait_event $QEMU_HANDLE "JOB_STATUS_CHANGE"
> + # running
> + _wait_event $QEMU_HANDLE "JOB_STATUS_CHANGE"
> +
> + # Next events vary depending on job type and
> + # whether it succeeds or not.
> + for evname in $@
> + do
> + _wait_event $QEMU_HANDLE $evname
> + done
> +
> + # All jobs finish off with two more events...
> + # concluded
> + _wait_event $QEMU_HANDLE "JOB_STATUS_CHANGE"
> + _send_qemu_cmd $QEMU_HANDLE "{\"execute\": \"query-jobs\"}" "return"
> + _send_qemu_cmd $QEMU_HANDLE "{\"execute\": \"job-dismiss\",
> \"arguments\": {\"id\": \"$job\"}}" "return"
> + # null
> + _wait_event $QEMU_HANDLE "JOB_STATUS_CHANGE"
> +}
> +
> +run_save()
> +{
> + local job=$1
> + local vmstate=$2
> + local devices=$3
> + local fail=$4
> +
> + _send_qemu_cmd $QEMU_HANDLE "{\"execute\": \"snapshot-save\",
> + \"arguments\": {
> + \"job-id\": \"$job\",
> + \"tag\": \"snap0\",
> + \"vmstate\": \"$vmstate\",
> + \"devices\": $devices}}" "return"
> +
> + if [ $fail = 0 ]; then
> + # job status: waiting, pending
> + wait_job $job "STOP" "RESUME" "JOB_STATUS_CHANGE" "JOB_STATUS_CHANGE"
> + else
> + # job status: aborting
> + wait_job $job "JOB_STATUS_CHANGE"
> + fi
> +}
> +
> +run_load()
> +{
> + local job=$1
> + local vmstate=$2
> + local devices=$3
> + local fail=$4
> +
> + _send_qemu_cmd $QEMU_HANDLE "{\"execute\": \"snapshot-load\",
> + \"arguments\": {
> + \"job-id\": \"$job\",
> + \"tag\": \"snap0\",
> + \"vmstate\": \"$vmstate\",
> + \"devices\": $devices}}" "return"
> + if [ $fail = 0 ]; then
> + # job status: waiting, pending
> + wait_job $job "STOP" "RESUME" "JOB_STATUS_CHANGE" "JOB_STATUS_CHANGE"
> + else
> + # job status: aborting
> + wait_job $job "STOP" "JOB_STATUS_CHANGE"
> + fi
> +}
> +
> +run_delete()
> +{
> + local job=$1
> + local devices=$2
> + local fail=$3
> +
> + _send_qemu_cmd $QEMU_HANDLE "{\"execute\": \"snapshot-delete\",
> + \"arguments\": {
> + \"job-id\": \"$job\",
> + \"tag\": \"snap0\",
> + \"devices\": $devices}}" "return"
> + if [ $fail = 0 ]; then
> + # job status: waiting, pending
> + wait_job $job "JOB_STATUS_CHANGE" "JOB_STATUS_CHANGE"
> + else
> + # job status: aborting
> + wait_job $job "JOB_STATUS_CHANGE"
> + fi
> +}
> +
> +start_qemu()
> +{
> + keep_stderr=y
> + _launch_qemu -nodefaults -nographic "$@"
> +
> + _send_qemu_cmd $QEMU_HANDLE '{"execute": "qmp_capabilities"}' 'return'
> +}
> +
> +stop_qemu()
> +{
> + _send_qemu_cmd $QEMU_HANDLE '{"execute": "quit"}' 'return'
> +
> + wait=1 _cleanup_qemu
> +}
> +
> +
> +echo
> +echo "===== Snapshot single qcow2 image ====="
> +echo
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +run_save "save-simple" "diskfmt0" "[\"diskfmt0\"]" 0
> +run_load "load-simple" "diskfmt0" "[\"diskfmt0\"]" 0
> +run_delete "delete-simple" "[\"diskfmt0\"]" 0
> +stop_qemu
> +
> +
> +echo
> +echo "===== Snapshot no image ====="
> +echo
> +
> +# When snapshotting we need to pass at least one writable disk
> +# otherwise there's no work to do
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +run_save "save-no-image" "diskfmt0" "[]" 1
> +stop_qemu
> +
> +
> +echo
> +echo "===== Snapshot missing image ====="
> +echo
> +
> +# The block node names we pass need to actually exist
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +run_save "save-missing-image" "diskfmt1729" "[\"diskfmt1729\"]" 1
> +stop_qemu
> +
> +echo
> +echo "===== Snapshot vmstate not in devices list ====="
> +echo
> +
> +# The node name referred to for vmstate must be one of the nodes
> +# being included in the snapshot, otherwise the vmstate that is
> +# captured is liable to be overwritten making subsequent load
> +# impossible
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}" \
> + -blockdev
> "{'driver':'file','filename':'$TEST_IMG.alt1','node-name':'disk1'}" \
> + -blockdev "{'driver':'qcow2','file':'disk1','node-name':'diskfmt1'}"
> +run_save "save-excluded-vmstate" "diskfmt0" "[\"diskfmt1\"]" 1
> +stop_qemu
> +
> +
> +echo
> +echo "===== Snapshot protocol instead of format ====="
> +echo
> +
> +# The snapshot has to be done against the qcow2 format layer
> +# not the underlying file protocol layer
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +run_save "save-proto-not-fmt" "disk0" "[\"disk0\"]" 1
> +stop_qemu
> +
> +
> +echo
> +echo "===== Snapshot dual qcow2 image ====="
> +echo
> +
> +# We can snapshot multiple qcow2 disks at the same time
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}" \
> + -blockdev
> "{'driver':'file','filename':'$TEST_IMG.alt1','node-name':'disk1'}" \
> + -blockdev "{'driver':'qcow2','file':'disk1','node-name':'diskfmt1'}"
> +run_save "save-dual-image" "diskfmt0" "[\"diskfmt0\", \"diskfmt1\"]" 0
> +run_load "load-dual-image" "diskfmt0" "[\"diskfmt0\", \"diskfmt1\"]" 0
> +run_delete "delete-dual-image" "[\"diskfmt0\", \"diskfmt1\"]" 0
> +stop_qemu
> +
> +
> +echo
> +echo "===== Snapshot error with raw image ====="
> +echo
> +
> +# If we're snapshotting multiple disks, all must be capable
> +# of supporting snapshots. A raw disk in the list must cause
> +# an error.
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}" \
> + -blockdev
> "{'driver':'file','filename':'$TEST_IMG.alt1','node-name':'disk1'}" \
> + -blockdev "{'driver':'qcow2','file':'disk1','node-name':'diskfmt1'}" \
> + -blockdev
> "{'driver':'file','filename':'$TEST_IMG.alt2','node-name':'disk2'}" \
> + -blockdev "{'driver':'raw','file':'disk2','node-name':'diskfmt2'}"
> +run_save "save-raw-fmt" "diskfmt0" "[\"diskfmt0\", \"diskfmt1\",
> \"diskfmt2\"]" 1
> +stop_qemu
> +
> +
> +echo
> +echo "===== Snapshot with raw image excluded ====="
> +echo
> +
> +# If we're snapshotting multiple disks, all must be capable
> +# of supporting snapshots. A writable raw disk can be excluded
> +# from the snapshot, though it means its data won't be restored
> +# by later snapshot load operation.
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}" \
> + -blockdev
> "{'driver':'file','filename':'$TEST_IMG.alt1','node-name':'disk1'}" \
> + -blockdev "{'driver':'qcow2','file':'disk1','node-name':'diskfmt1'}" \
> + -blockdev
> "{'driver':'file','filename':'$TEST_IMG.alt2','node-name':'disk2'}" \
> + -blockdev "{'driver':'raw','file':'disk2','node-name':'diskfmt2'}"
> +run_save "save-skip-raw" "diskfmt0" "[\"diskfmt0\", \"diskfmt1\"]" 0
> +run_load "load-skip-raw" "diskfmt0" "[\"diskfmt0\", \"diskfmt1\"]" 0
> +run_delete "delete-skip-raw" "[\"diskfmt0\", \"diskfmt1\"]" 0
> +stop_qemu
> +
> +echo
> +echo "===== Snapshot bad error reporting to stderr ====="
> +echo
> +
> +# This demonstrates that we're not capturing vmstate loading failures
> +# into QMP errors, they're ending up in stderr instead. vmstate needs
> +# to report errors via Error object but that is a major piece of work
> +# for the future. This test case's expected output log will need
> +# adjusting when that is done.
> +
> +start_qemu \
> + -device virtio-rng \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +
> +run_save "save-err-stderr" "diskfmt0" "[\"diskfmt0\"]" 0
> +stop_qemu
> +
> +# leave off virtio-rng to provoke vmstate failure
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +
> +run_load "load-err-stderr" "diskfmt0" "[\"diskfmt0\"]" 1
> +run_delete "delete-err-stderr" "[\"diskfmt0\"]" 0
> +
> +stop_qemu
> +
> +
> +echo
> +echo "===== Snapshot reuse same tag ====="
> +echo
> +
> +# Validates that we get an error when reusing a snapshot tag that
> +# already exists
> +
> +start_qemu \
> + -device virtio-rng \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +
> +run_save "save-err-stderr-initial" "diskfmt0" "[\"diskfmt0\"]" 0
> +run_save "save-err-stderr-repeat1" "diskfmt0" "[\"diskfmt0\"]" 1
> +run_delete "delete-err-stderr" "[\"diskfmt0\"]" 0
> +run_save "save-err-stderr-repeat2" "diskfmt0" "[\"diskfmt0\"]" 0
> +run_delete "delete-err-stderr-repeat2" "[\"diskfmt0\"]" 0
> +
> +stop_qemu
> +
> +echo
> +echo "===== Snapshot load does not exist ====="
> +echo
> +
> +# Validates that we get an error when loading a snapshot that does
> +# not exist
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +run_load "load-missing-snapshot" "diskfmt0" "[\"diskfmt0\"]" 1
> +stop_qemu
> +
> +
> +echo
> +echo "===== Snapshot delete does not exist ====="
> +echo
> +
> +# Validates that we don't get an error when deleting a snapshot that
> +# does not exist
> +
> +start_qemu \
> + -blockdev "{'driver':'file','filename':'$TEST_IMG','node-name':'disk0'}"
> \
> + -blockdev "{'driver':'qcow2','file':'disk0','node-name':'diskfmt0'}"
> +run_delete "delete-missing-snapshot" "[\"diskfmt0\"]" 0
> +stop_qemu
> +
> +
> +# success, all done
> +echo "*** done"
> +rm -f $seq.full
> +status=0
> diff --git a/tests/qemu-iotests/tests/internal-snapshots-qapi.out
> b/tests/qemu-iotests/tests/internal-snapshots-qapi.out
> new file mode 100644
> index 0000000000..26ff4a838c
> --- /dev/null
> +++ b/tests/qemu-iotests/tests/internal-snapshots-qapi.out
> @@ -0,0 +1,520 @@
> +QA output created by internal-snapshots-qapi
> +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
> +Formatting 'TEST_DIR/t.IMGFMT.alt1', fmt=IMGFMT size=134217728
> +Formatting 'TEST_DIR/t.qcow2.alt2', fmt=IMGFMT size=134217728
> +
> +===== Snapshot single qcow2 image =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-simple",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "save-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "save-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "save-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "save-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "save-simple"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-simple"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-simple"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "save-simple"}}
> +{"execute": "snapshot-load",
> + "arguments": {
> + "job-id": "load-simple",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "load-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "load-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "load-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "load-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "load-simple"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-load", "id": "load-simple"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "load-simple"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "load-simple"}}
> +{"execute": "snapshot-delete",
> + "arguments": {
> + "job-id": "delete-simple",
> + "tag": "snap0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "delete-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "delete-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "delete-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "delete-simple"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "delete-simple"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-delete", "id": "delete-simple"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "delete-simple"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "delete-simple"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot no image =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-no-image",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": []}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "save-no-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "save-no-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "save-no-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "save-no-image"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-no-image", "error": "At least one
> device is required for snapshot"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-no-image"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "save-no-image"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot missing image =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-missing-image",
> + "tag": "snap0",
> + "vmstate": "diskfmt1729",
> + "devices": ["diskfmt1729"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "save-missing-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "save-missing-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id":
> "save-missing-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "save-missing-image"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-missing-image", "error": "No block
> device node 'diskfmt1729'"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-missing-image"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "save-missing-image"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot vmstate not in devices list =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-excluded-vmstate",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt1"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "save-excluded-vmstate"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "save-excluded-vmstate"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id":
> "save-excluded-vmstate"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "save-excluded-vmstate"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-excluded-vmstate", "error": "vmstate
> block device 'diskfmt0' does not exist"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-excluded-vmstate"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id":
> "save-excluded-vmstate"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot protocol instead of format =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-proto-not-fmt",
> + "tag": "snap0",
> + "vmstate": "disk0",
> + "devices": ["disk0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "save-proto-not-fmt"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "save-proto-not-fmt"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id":
> "save-proto-not-fmt"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "save-proto-not-fmt"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-proto-not-fmt", "error": "Device
> 'disk0' is writable but does not support snapshots"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-proto-not-fmt"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "save-proto-not-fmt"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot dual qcow2 image =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-dual-image",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0", "diskfmt1"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "save-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "save-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "save-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "save-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "save-dual-image"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-dual-image"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-dual-image"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "save-dual-image"}}
> +{"execute": "snapshot-load",
> + "arguments": {
> + "job-id": "load-dual-image",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0", "diskfmt1"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "load-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "load-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "load-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "load-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "load-dual-image"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-load", "id": "load-dual-image"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "load-dual-image"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "load-dual-image"}}
> +{"execute": "snapshot-delete",
> + "arguments": {
> + "job-id": "delete-dual-image",
> + "tag": "snap0",
> + "devices": ["diskfmt0", "diskfmt1"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "delete-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "delete-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "delete-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "delete-dual-image"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "delete-dual-image"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-delete", "id": "delete-dual-image"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "delete-dual-image"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "delete-dual-image"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot error with raw image =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-raw-fmt",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0", "diskfmt1",
> "diskfmt2"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "save-raw-fmt"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "save-raw-fmt"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "save-raw-fmt"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "save-raw-fmt"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-raw-fmt", "error": "Device 'diskfmt2'
> is writable but does not support snapshots"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-raw-fmt"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "save-raw-fmt"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot with raw image excluded =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-skip-raw",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0", "diskfmt1"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "save-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "save-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "save-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "save-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "save-skip-raw"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-skip-raw"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-skip-raw"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "save-skip-raw"}}
> +{"execute": "snapshot-load",
> + "arguments": {
> + "job-id": "load-skip-raw",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0", "diskfmt1"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "load-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "load-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "load-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "load-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "load-skip-raw"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-load", "id": "load-skip-raw"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "load-skip-raw"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "load-skip-raw"}}
> +{"execute": "snapshot-delete",
> + "arguments": {
> + "job-id": "delete-skip-raw",
> + "tag": "snap0",
> + "devices": ["diskfmt0", "diskfmt1"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "delete-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "delete-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "delete-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "delete-skip-raw"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "delete-skip-raw"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-delete", "id": "delete-skip-raw"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "delete-skip-raw"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "delete-skip-raw"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot bad error reporting to stderr =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-err-stderr",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "save-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "save-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "save-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "save-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "save-err-stderr"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-err-stderr"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-err-stderr"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "save-err-stderr"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-load",
> + "arguments": {
> + "job-id": "load-err-stderr",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "load-err-stderr"}}
> +qemu-system-x86_64: Unknown savevm section or instance
> '0000:00:02.0/virtio-rng' 0. Make sure that your current VM setup matches
> your saved VM setup, including any hotplugged devices
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "load-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id": "load-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "load-err-stderr"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-load", "id": "load-err-stderr", "error": "Error -22
> while loading VM state"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "load-err-stderr"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "load-err-stderr"}}
> +{"execute": "snapshot-delete",
> + "arguments": {
> + "job-id": "delete-err-stderr",
> + "tag": "snap0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "delete-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "delete-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "delete-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "delete-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "delete-err-stderr"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-delete", "id": "delete-err-stderr"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "delete-err-stderr"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "delete-err-stderr"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot reuse same tag =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-err-stderr-initial",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "save-err-stderr-initial"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "save-err-stderr-initial"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id":
> "save-err-stderr-initial"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id":
> "save-err-stderr-initial"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "save-err-stderr-initial"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-err-stderr-initial"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-err-stderr-initial"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id":
> "save-err-stderr-initial"}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-err-stderr-repeat1",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "save-err-stderr-repeat1"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "save-err-stderr-repeat1"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id":
> "save-err-stderr-repeat1"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "save-err-stderr-repeat1"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-err-stderr-repeat1", "error":
> "Snapshot 'snap0' already exists in one or more devices"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-err-stderr-repeat1"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id":
> "save-err-stderr-repeat1"}}
> +{"execute": "snapshot-delete",
> + "arguments": {
> + "job-id": "delete-err-stderr",
> + "tag": "snap0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "delete-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "delete-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "delete-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "delete-err-stderr"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "delete-err-stderr"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-delete", "id": "delete-err-stderr"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "delete-err-stderr"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "delete-err-stderr"}}
> +{"execute": "snapshot-save",
> + "arguments": {
> + "job-id": "save-err-stderr-repeat2",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "save-err-stderr-repeat2"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "save-err-stderr-repeat2"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "RESUME"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id":
> "save-err-stderr-repeat2"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id":
> "save-err-stderr-repeat2"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "save-err-stderr-repeat2"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-save", "id": "save-err-stderr-repeat2"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "save-err-stderr-repeat2"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id":
> "save-err-stderr-repeat2"}}
> +{"execute": "snapshot-delete",
> + "arguments": {
> + "job-id": "delete-err-stderr-repeat2",
> + "tag": "snap0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "delete-err-stderr-repeat2"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "delete-err-stderr-repeat2"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id":
> "delete-err-stderr-repeat2"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id":
> "delete-err-stderr-repeat2"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "delete-err-stderr-repeat2"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-delete", "id": "delete-err-stderr-repeat2"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "delete-err-stderr-repeat2"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id":
> "delete-err-stderr-repeat2"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot load does not exist =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-load",
> + "arguments": {
> + "job-id": "load-missing-snapshot",
> + "tag": "snap0",
> + "vmstate": "diskfmt0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "load-missing-snapshot"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "load-missing-snapshot"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "STOP"}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "aborting", "id":
> "load-missing-snapshot"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "load-missing-snapshot"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-load", "id": "load-missing-snapshot", "error": "Snapshot
> 'snap0' does not exist in one or more devices"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "load-missing-snapshot"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id":
> "load-missing-snapshot"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +
> +===== Snapshot delete does not exist =====
> +
> +{"execute": "qmp_capabilities"}
> +{"return": {}}
> +{"execute": "snapshot-delete",
> + "arguments": {
> + "job-id": "delete-missing-snapshot",
> + "tag": "snap0",
> + "devices": ["diskfmt0"]}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "created", "id":
> "delete-missing-snapshot"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "running", "id":
> "delete-missing-snapshot"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id":
> "delete-missing-snapshot"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "pending", "id":
> "delete-missing-snapshot"}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id":
> "delete-missing-snapshot"}}
> +{"execute": "query-jobs"}
> +{"return": [{"current-progress": 1, "status": "concluded", "total-progress":
> 1, "type": "snapshot-delete", "id": "delete-missing-snapshot"}]}
> +{"execute": "job-dismiss", "arguments": {"id": "delete-missing-snapshot"}}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "JOB_STATUS_CHANGE", "data": {"status": "null", "id":
> "delete-missing-snapshot"}}
> +{"execute": "quit"}
> +{"return": {}}
> +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event":
> "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
> +*** done
> --
> 2.29.2
>
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
- [PATCH v11 03/12] migration: stop returning errno from load_snapshot(), (continued)
- [PATCH v11 03/12] migration: stop returning errno from load_snapshot(), Daniel P . Berrangé, 2021/02/04
- [PATCH v11 04/12] block: add ability to specify list of blockdevs during snapshot, Daniel P . Berrangé, 2021/02/04
- [PATCH v11 05/12] block: allow specifying name of block device for vmstate storage, Daniel P . Berrangé, 2021/02/04
- [PATCH v11 06/12] block: rename and alter bdrv_all_find_snapshot semantics, Daniel P . Berrangé, 2021/02/04
- [PATCH v11 07/12] migration: control whether snapshots are ovewritten, Daniel P . Berrangé, 2021/02/04
- [PATCH v11 09/12] migration: introduce a delete_snapshot wrapper, Daniel P . Berrangé, 2021/02/04
- [PATCH v11 08/12] migration: wire up support for snapshot device selection, Daniel P . Berrangé, 2021/02/04
- [PATCH v11 10/12] iotests: add support for capturing and matching QMP events, Daniel P . Berrangé, 2021/02/04
- [PATCH v11 11/12] iotests: fix loading of common.config from tests/ subdir, Daniel P . Berrangé, 2021/02/04
- [PATCH v11 12/12] migration: introduce snapshot-{save, load, delete} QMP commands, Daniel P . Berrangé, 2021/02/04
- Re: [PATCH v11 12/12] migration: introduce snapshot-{save, load, delete} QMP commands,
Dr. David Alan Gilbert <=
- Re: [PATCH v11 12/12] migration: introduce snapshot-{save,load,delete} QMP commands, Eric Blake, 2021/02/04
- Re: [PATCH v11 12/12] migration: introduce snapshot-{save,load,delete} QMP commands, John Snow, 2021/02/16
- Re: [PATCH v11 00/12] migration: bring improved savevm/loadvm/delvm to QMP, Dr. David Alan Gilbert, 2021/02/04