Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list