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 | 86 ++++++++++++++++++
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 | 89 +++++++++++++++++++
9 files changed, 285 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 398d3b4d8b..7d061a48ab 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4505,3 +4505,26 @@ qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon,
virHashFree(info);
return ret;
}
+
+
+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 7feed8a427..e51177bf44 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -109,6 +109,49 @@ struct _qemuMonitorEventPanicInfo {
} data;
};
+
+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);
@@ -1217,4 +1260,10 @@ struct _qemuMonitorPRManagerInfo {
int qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon,
virHashTablePtr *retinfo);
+void qemuMonitorJobInfoFree(qemuMonitorJobInfoPtr job);
+
+int qemuMonitorGetJobInfo(qemuMonitorPtr mon,
+ qemuMonitorJobInfoPtr **jobs,
+ size_t *njobs);
+
#endif /* QEMU_MONITOR_H */
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 0a63cff7e2..101e6ec7cd 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -58,6 +58,12 @@ 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);
@@ -8567,3 +8573,83 @@ qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
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;
+ qemuMonitorJobInfoPtr 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)
+ goto cleanup;
+
+ VIR_STEAL_PTR(ret, job);
+
+ cleanup:
+ qemuMonitorJobInfoFree(job);
+ return ret;
+}
+
+
+int
+qemuMonitorJSONGetJobInfo(qemuMonitorPtr mon,
+ qemuMonitorJobInfoPtr **jobs,
+ size_t *njobs)
+{
+ virJSONValuePtr data;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+ size_t i;
+ int ret = -1;
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("query-jobs", NULL)))
+ return -1;
+
+ if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+ goto cleanup;
+
+ if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
+ goto cleanup;
+
+ data = virJSONValueObjectGetArray(reply, "return");
+
+ for (i = 0; i < virJSONValueArraySize(data); i++) {
+ qemuMonitorJobInfoPtr job = NULL;
+
+ if (!(job = qemuMonitorJSONGetJobInfoOne(virJSONValueArrayGet(data, i))))
+ goto cleanup;
+
+ if (VIR_APPEND_ELEMENT(*jobs, *njobs, job) < 0)
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 8de1d8d547..7e2ac422dd 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -324,6 +324,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 5284fe60c6..ce3ae2d31b 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -2879,6 +2879,83 @@ testQAPISchema(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(true, data->xmlopt);
+ char *filenameJSON = NULL;
+ char *fileJSON = NULL;
+ char *filenameResult = NULL;
+ 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);
+ VIR_FREE(filenameJSON);
+ VIR_FREE(fileJSON);
+ VIR_FREE(filenameResult);
+ VIR_FREE(actual);
+ return ret;
+}
+
+
static int
mymain(void)
{
@@ -3113,6 +3190,18 @@ mymain(void)
#undef DO_TEST_QAPI_SCHEMA
+#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.19.2