Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
src/qemu/qemu_monitor.c | 23 +++++
src/qemu/qemu_monitor.h | 49 +++++++++++
src/qemu/qemu_monitor_json.c | 79 +++++++++++++++++
src/qemu/qemu_monitor_json.h | 6 ++
.../query-jobs-create.json | 20 +++++
.../query-jobs-create.result | 11 +++
.../qemumonitorjsondata/query-jobs-empty.json | 1 +
.../query-jobs-empty.result | 0
tests/qemumonitorjsontest.c | 85 +++++++++++++++++++
9 files changed, 274 insertions(+)
create mode 100644 tests/qemumonitorjsondata/query-jobs-create.json
create mode 100644 tests/qemumonitorjsondata/query-jobs-create.result
create mode 100644 tests/qemumonitorjsondata/query-jobs-empty.json
create mode 100644 tests/qemumonitorjsondata/query-jobs-empty.result
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 3cd037fdba..c9dbc67f53 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4584,3 +4584,26 @@ qemuMonitorDeleteBitmap(qemuMonitorPtr mon,
return qemuMonitorJSONDeleteBitmap(mon, node, bitmap);
}
+
+
+void
+qemuMonitorJobInfoFree(qemuMonitorJobInfoPtr job)
+{
+ if (!job)
+ return;
+
+ VIR_FREE(job->id);
+ VIR_FREE(job->error);
+ VIR_FREE(job);
+}
+
+
+int
+qemuMonitorGetJobInfo(qemuMonitorPtr mon,
+ qemuMonitorJobInfoPtr **jobs,
+ size_t *njobs)
+{
+ QEMU_CHECK_MONITOR(mon);
+
+ return qemuMonitorJSONGetJobInfo(mon, jobs, njobs);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index e3a3c212fd..4cbe185c5c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -117,6 +117,48 @@ struct _qemuMonitorRdmaGidStatus {
};
+typedef enum {
+ QEMU_MONITOR_JOB_TYPE_UNKNOWN, /* internal value, not exposed by qemu */
+ QEMU_MONITOR_JOB_TYPE_COMMIT,
+ QEMU_MONITOR_JOB_TYPE_STREAM,
+ QEMU_MONITOR_JOB_TYPE_MIRROR,
+ QEMU_MONITOR_JOB_TYPE_BACKUP,
+ QEMU_MONITOR_JOB_TYPE_CREATE,
+ QEMU_MONITOR_JOB_TYPE_LAST
+} qemuMonitorJobType;
+
+VIR_ENUM_DECL(qemuMonitorJob);
+
+typedef enum {
+ QEMU_MONITOR_JOB_STATUS_UNKNOWN, /* internal value, not exposed by qemu */
+ QEMU_MONITOR_JOB_STATUS_CREATED,
+ QEMU_MONITOR_JOB_STATUS_RUNNING,
+ QEMU_MONITOR_JOB_STATUS_PAUSED,
+ QEMU_MONITOR_JOB_STATUS_READY,
+ QEMU_MONITOR_JOB_STATUS_STANDBY,
+ QEMU_MONITOR_JOB_STATUS_WAITING,
+ QEMU_MONITOR_JOB_STATUS_PENDING,
+ QEMU_MONITOR_JOB_STATUS_ABORTING,
+ QEMU_MONITOR_JOB_STATUS_CONCLUDED,
+ QEMU_MONITOR_JOB_STATUS_UNDEFINED, /* the job states below should not be visible
outside of qemu */
+ QEMU_MONITOR_JOB_STATUS_NULL,
+ QEMU_MONITOR_JOB_STATUS_LAST
+} qemuMonitorJobStatus;
+
+VIR_ENUM_DECL(qemuMonitorJobStatus);
+
+typedef struct _qemuMonitorJobInfo qemuMonitorJobInfo;
+typedef qemuMonitorJobInfo *qemuMonitorJobInfoPtr;
+struct _qemuMonitorJobInfo {
+ char *id;
+ qemuMonitorJobType type;
+ qemuMonitorJobStatus status;
+ char *error;
+ long long progressCurrent;
+ long long progressTotal;
+};
+
+
char *qemuMonitorGuestPanicEventInfoFormatMsg(qemuMonitorEventPanicInfoPtr info);
void qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfoPtr info);
void qemuMonitorEventRdmaGidStatusFree(qemuMonitorRdmaGidStatusPtr info);
@@ -1278,3 +1320,10 @@ struct _qemuMonitorCurrentMachineInfo {
int qemuMonitorGetCurrentMachineInfo(qemuMonitorPtr mon,
qemuMonitorCurrentMachineInfoPtr info);
+void qemuMonitorJobInfoFree(qemuMonitorJobInfoPtr job);
+
+VIR_DEFINE_AUTOPTR_FUNC(qemuMonitorJobInfo, qemuMonitorJobInfoFree);
+
+int qemuMonitorGetJobInfo(qemuMonitorPtr mon,
+ qemuMonitorJobInfoPtr **jobs,
+ size_t *njobs);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 33ee026fe1..68780a5a4f 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -56,6 +56,14 @@ VIR_LOG_INIT("qemu.qemu_monitor_json");
#define LINE_ENDING "\r\n"
+VIR_ENUM_IMPL(qemuMonitorJob,
+ QEMU_MONITOR_JOB_TYPE_LAST,
+ "", "commit", "stream", "mirror",
"backup", "create");
+VIR_ENUM_IMPL(qemuMonitorJobStatus,
+ QEMU_MONITOR_JOB_STATUS_LAST,
+ "", "created", "running", "paused",
"ready", "standby", "waiting",
+ "pending", "aborting", "concluded",
"undefined", "null");
+
static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr data);
@@ -9038,3 +9046,74 @@ qemuMonitorJSONDeleteBitmap(qemuMonitorPtr mon,
virJSONValueFree(reply);
return ret;
}
+
+
+static qemuMonitorJobInfoPtr
+qemuMonitorJSONGetJobInfoOne(virJSONValuePtr data)
+{
+ const char *id = virJSONValueObjectGetString(data, "id");
+ const char *type = virJSONValueObjectGetString(data, "type");
+ const char *status = virJSONValueObjectGetString(data, "status");
+ const char *errmsg = virJSONValueObjectGetString(data, "error");
+ int tmp;
+ VIR_AUTOPTR(qemuMonitorJobInfo) job = NULL;
+ qemuMonitorJobInfoPtr ret = NULL;
+
+ if (!data)
+ return NULL;
+
+ if (VIR_ALLOC(job) < 0)
+ return NULL;
+
+ if ((tmp = qemuMonitorJobTypeFromString(type)) < 0)
+ tmp = QEMU_MONITOR_JOB_TYPE_UNKNOWN;
+
+ job->type = tmp;
+
+ if ((tmp = qemuMonitorJobStatusTypeFromString(status)) < 0)
+ tmp = QEMU_MONITOR_JOB_STATUS_UNKNOWN;
+
+ job->status = tmp;
+
+ if (VIR_STRDUP(job->id, id) < 0 ||
+ VIR_STRDUP(job->error, errmsg) < 0)
+ return NULL;
+
+ VIR_STEAL_PTR(ret, job);
+ return ret;
+}
+
+
+int
+qemuMonitorJSONGetJobInfo(qemuMonitorPtr mon,
+ qemuMonitorJobInfoPtr **jobs,
+ size_t *njobs)
+{
+ virJSONValuePtr data;
+ VIR_AUTOPTR(virJSONValue) cmd = NULL;
+ VIR_AUTOPTR(virJSONValue) reply = NULL;
+ size_t i;
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("query-jobs", NULL)))
+ return -1;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ return -1;
+
+ if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
+ return -1;
+
+ data = virJSONValueObjectGetArray(reply, "return");
+
+ for (i = 0; i < virJSONValueArraySize(data); i++) {
+ qemuMonitorJobInfoPtr job = NULL;
+
+ if (!(job = qemuMonitorJSONGetJobInfoOne(virJSONValueArrayGet(data, i))))
+ return -1;
+
+ if (VIR_APPEND_ELEMENT(*jobs, *njobs, job) < 0)
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index c2b47e6129..a50d4d7b23 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -319,6 +319,12 @@ int qemuMonitorJSONBlockJobCancel(qemuMonitorPtr mon,
const char *jobname)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int
+qemuMonitorJSONGetJobInfo(qemuMonitorPtr mon,
+ qemuMonitorJobInfoPtr **jobs,
+ size_t *njobs);
+
+
int qemuMonitorJSONBlockJobSetSpeed(qemuMonitorPtr mon,
const char *jobname,
unsigned long long speed)
diff --git a/tests/qemumonitorjsondata/query-jobs-create.json
b/tests/qemumonitorjsondata/query-jobs-create.json
new file mode 100644
index 0000000000..fbc7c4b15d
--- /dev/null
+++ b/tests/qemumonitorjsondata/query-jobs-create.json
@@ -0,0 +1,20 @@
+{
+ "return": [
+ {
+ "current-progress": 1,
+ "status": "concluded",
+ "total-progress": 1,
+ "type": "create",
+ "id": "createjob-fail",
+ "error": "Image size must be a multiple of 512 bytes"
+ },
+ {
+ "current-progress": 1,
+ "status": "concluded",
+ "total-progress": 1,
+ "type": "create",
+ "id": "createjob"
+ }
+ ],
+ "id": "libvirt-24"
+}
diff --git a/tests/qemumonitorjsondata/query-jobs-create.result
b/tests/qemumonitorjsondata/query-jobs-create.result
new file mode 100644
index 0000000000..a43282fe67
--- /dev/null
+++ b/tests/qemumonitorjsondata/query-jobs-create.result
@@ -0,0 +1,11 @@
+[job]
+id=createjob-fail
+type=create
+status=concluded
+error=Image size must be a multiple of 512 bytes
+
+[job]
+id=createjob
+type=create
+status=concluded
+error=<null>
diff --git a/tests/qemumonitorjsondata/query-jobs-empty.json
b/tests/qemumonitorjsondata/query-jobs-empty.json
new file mode 100644
index 0000000000..c1ede999e5
--- /dev/null
+++ b/tests/qemumonitorjsondata/query-jobs-empty.json
@@ -0,0 +1 @@
+{ "return": [] }
diff --git a/tests/qemumonitorjsondata/query-jobs-empty.result
b/tests/qemumonitorjsondata/query-jobs-empty.result
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index 798b7beca3..171a7cc104 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -2925,6 +2925,79 @@ testQAPISchemaValidate(const void *opaque)
}
+static void
+testQueryJobsPrintJob(virBufferPtr buf,
+ qemuMonitorJobInfoPtr job)
+{
+ virBufferAddLit(buf, "[job]\n");
+ virBufferAsprintf(buf, "id=%s\n", NULLSTR(job->id));
+ virBufferAsprintf(buf, "type=%s\n",
NULLSTR(qemuMonitorJobTypeToString(job->type)));
+ virBufferAsprintf(buf, "status=%s\n",
NULLSTR(qemuMonitorJobStatusTypeToString(job->status)));
+ virBufferAsprintf(buf, "error=%s\n", NULLSTR(job->error));
+ virBufferAddLit(buf, "\n");
+}
+
+
+struct testQueryJobsData {
+ const char *name;
+ virDomainXMLOptionPtr xmlopt;
+};
+
+
+static int
+testQueryJobs(const void *opaque)
+{
+ const struct testQueryJobsData *data = opaque;
+ qemuMonitorTestPtr test = qemuMonitorTestNewSimple(data->xmlopt);
+ VIR_AUTOFREE(char *) filenameJSON = NULL;
+ VIR_AUTOFREE(char *) fileJSON = NULL;
+ VIR_AUTOFREE(char *) filenameResult = NULL;
+ VIR_AUTOFREE(char *) actual = NULL;
+ qemuMonitorJobInfoPtr *jobs = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ size_t njobs = 0;
+ size_t i;
+ int ret = -1;
+
+ if (virAsprintf(&filenameJSON,
+ abs_srcdir "/qemumonitorjsondata/query-jobs-%s.json",
+ data->name) < 0 ||
+ virAsprintf(&filenameResult,
+ abs_srcdir "/qemumonitorjsondata/query-jobs-%s.result",
+ data->name) < 0)
+ goto cleanup;
+
+ if (virTestLoadFile(filenameJSON, &fileJSON) < 0)
+ goto cleanup;
+
+ if (qemuMonitorTestAddItem(test, "query-jobs", fileJSON) < 0)
+ goto cleanup;
+
+ if (qemuMonitorJSONGetJobInfo(qemuMonitorTestGetMonitor(test),
+ &jobs, &njobs) < 0)
+ goto cleanup;
+
+ for (i = 0; i < njobs; i++)
+ testQueryJobsPrintJob(&buf, jobs[i]);
+
+ virBufferTrim(&buf, "\n", -1);
+
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
+
+ actual = virBufferContentAndReset(&buf);
+
+ if (virTestCompareToFile(actual, filenameResult) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ qemuMonitorTestFree(test);
+ return ret;
+}
+
+
static int
mymain(void)
{
@@ -3199,6 +3272,18 @@ mymain(void)
#undef DO_TEST_QAPI_VALIDATE
+#define DO_TEST_QUERY_JOBS(name) \
+ do { \
+ struct testQueryJobsData data = { name, driver.xmlopt}; \
+ if (virTestRun("query-jobs-" name, testQueryJobs, &data) < 0) \
+ ret = -1; \
+ } while (0)
+
+ DO_TEST_QUERY_JOBS("empty");
+ DO_TEST_QUERY_JOBS("create");
+
+#undef DO_TEST_QUERY_JOBS
+
cleanup:
VIR_FREE(metaschemastr);
virJSONValueFree(metaschema);
--
2.21.0