[libvirt] [PATCH RFC 44/51] qemu: monitor: Add infrastructure for 'query-jobs'

Peter Krempa pkrempa at redhat.com
Wed Dec 12 17:09:00 UTC 2018


Signed-off-by: Peter Krempa <pkrempa at 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




More information about the libvir-list mailing list