From: Marc-André Lureau <marcandre.lureau(a)redhat.com>
guest-get-disks is available since QEMU 5.2:
https://wiki.qemu.org/ChangeLog/5.2#Guest_agent
Note that the test response was manually edited based on a reply on my
bare-metal computer. It shows partial results due to pcieport driver not
being currently supported by QGA.
Signed-off-by: Marc-André Lureau <marcandre.lureau(a)redhat.com>
---
src/qemu/qemu_agent.c | 91 ++++++++++++++++++++++++++++++++++
src/qemu/qemu_agent.h | 15 ++++++
tests/qemuagenttest.c | 111 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 217 insertions(+)
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
index 31f26eedd1..8698e5cfaf 100644
--- a/src/qemu/qemu_agent.c
+++ b/src/qemu/qemu_agent.c
@@ -1827,6 +1827,21 @@ qemuAgentDiskAddressFree(qemuAgentDiskAddressPtr info)
g_free(info);
}
+
+void
+qemuAgentDiskInfoFree(qemuAgentDiskInfoPtr info)
+{
+ if (!info)
+ return;
+
+ g_free(info->name);
+ g_strfreev(info->dependencies);
+ qemuAgentDiskAddressFree(info->address);
+ g_free(info->alias);
+ g_free(info);
+}
+
+
void
qemuAgentFSInfoFree(qemuAgentFSInfoPtr info)
{
@@ -2640,3 +2655,79 @@ qemuAgentSSHRemoveAuthorizedKeys(qemuAgentPtr agent,
return qemuAgentCommand(agent, cmd, &reply, agent->timeout);
}
+
+
+int qemuAgentGetDisks(qemuAgentPtr agent,
+ qemuAgentDiskInfoPtr **disks,
+ bool report_unsupported)
+{
+ g_autoptr(virJSONValue) cmd = NULL;
+ g_autoptr(virJSONValue) reply = NULL;
+ virJSONValuePtr data = NULL;
+ size_t ndata;
+ size_t i;
+
+ if (!(cmd = qemuAgentMakeCommand("guest-get-disks", NULL)))
+ return -1;
+
+ if (qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
+ report_unsupported) < 0)
+ return -1;
+
+ if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("qemu agent didn't return an array of disks"));
+ return -1;
+ }
+
+ ndata = virJSONValueArraySize(data);
+
+ *disks = g_new0(qemuAgentDiskInfoPtr, ndata);
+
+ for (i = 0; i < ndata; i++) {
+ virJSONValuePtr addr;
+ virJSONValuePtr entry = virJSONValueArrayGet(data, i);
+ qemuAgentDiskInfoPtr disk;
+
+ if (!entry) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("array element missing in guest-get-disks return
"
+ "value"));
+ goto error;
+ }
+
+ disk = g_new0(qemuAgentDiskInfo, 1);
+ (*disks)[i] = disk;
+
+ disk->name = g_strdup(virJSONValueObjectGetString(entry, "name"));
+ if (!disk->name) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'name' missing in reply of
guest-get-disks"));
+ goto error;
+ }
+
+ if (virJSONValueObjectGetBoolean(entry, "partition",
&disk->partition) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'partition' missing in reply of
guest-get-disks"));
+ goto error;
+ }
+
+ disk->dependencies = virJSONValueObjectGetStringArray(entry,
"dependencies");
+ disk->alias = g_strdup(virJSONValueObjectGetString(entry,
"alias"));
+ addr = virJSONValueObjectGetObject(entry, "address");
+ if (addr) {
+ disk->address = qemuAgentGetDiskAddress(addr);
+ if (!disk->address)
+ goto error;
+ }
+ }
+
+ return ndata;
+
+ error:
+ for (i = 0; i < ndata; i++) {
+ qemuAgentDiskInfoFree((*disks)[i]);
+ }
+ g_free(*disks);
+ return -1;
+}
diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h
index 62d68b165a..74f1410760 100644
--- a/src/qemu/qemu_agent.h
+++ b/src/qemu/qemu_agent.h
@@ -81,6 +81,17 @@ struct _qemuAgentDiskAddress {
void qemuAgentDiskAddressFree(qemuAgentDiskAddressPtr addr);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuAgentDiskAddress, qemuAgentDiskAddressFree);
+typedef struct _qemuAgentDiskInfo qemuAgentDiskInfo;
+typedef qemuAgentDiskInfo *qemuAgentDiskInfoPtr;
+struct _qemuAgentDiskInfo {
+ char *name;
+ bool partition;
+ char **dependencies;
+ qemuAgentDiskAddressPtr address;
+ char *alias;
+};
+void qemuAgentDiskInfoFree(qemuAgentDiskInfoPtr info);
+
typedef struct _qemuAgentFSInfo qemuAgentFSInfo;
typedef qemuAgentFSInfo *qemuAgentFSInfoPtr;
struct _qemuAgentFSInfo {
@@ -187,3 +198,7 @@ int qemuAgentSSHRemoveAuthorizedKeys(qemuAgentPtr agent,
const char *user,
const char **keys,
size_t nkeys);
+
+int qemuAgentGetDisks(qemuAgentPtr mon,
+ qemuAgentDiskInfoPtr **disks,
+ bool report_unsupported);
diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c
index 47ff92733a..bf295496e1 100644
--- a/tests/qemuagenttest.c
+++ b/tests/qemuagenttest.c
@@ -1022,6 +1022,116 @@ testQemuAgentGetInterfaces(const void *data)
return ret;
}
+
+/* this is a bit of a pathological response on a real hw */
+static const char testQemuAgentGetDisksResponse[] =
+ "{\"return\": "
+ " ["
+ " {\"alias\" : \"fedora_localhost--live-home\","
+ " \"dependencies\" : "
+ " ["
+ " \"/dev/dm-0\""
+ " ],"
+ " \"name\" : \"/dev/dm-3\","
+ " \"partition\" : false"
+ " },"
+ " {\"address\" : "
+ " {\"bus\" : 0,"
+ " \"bus-type\" : \"unknown\","
+ " \"dev\" : \"/dev/nvme0n1\","
+ " \"pci-controller\" : "
+ " {\"bus\" : -1,"
+ " \"domain\" : -1,"
+ " \"function\" : -1,"
+ " \"slot\" : -1"
+ " },"
+ " \"serial\" : \"GIGABYTE
GP-ASM2NE6100TTTD_SN202208900567\","
+ " \"target\" : 0,"
+ " \"unit\" : 0"
+ " },"
+ " \"dependencies\" : [],"
+ " \"name\" : \"/dev/nvme0n1\","
+ " \"partition\" : false"
+ " }"
+ " ]"
+ "}";
+
+static int
+testQemuAgentGetDisks(const void *data)
+{
+ virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
+ qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
+ size_t i;
+ int ret = -1;
+ int disks_count = 0;
+ qemuAgentDiskInfoPtr *disks = NULL;
+
+ if (!test)
+ return -1;
+
+ if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
+ goto cleanup;
+
+ if (qemuMonitorTestAddItem(test, "guest-get-disks",
+ testQemuAgentGetDisksResponse) < 0)
+ goto cleanup;
+
+ if ((disks_count = qemuAgentGetDisks(qemuMonitorTestGetAgent(test),
+ &disks, true)) < 0)
+ goto cleanup;
+
+ if (disks_count != 2) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "expected 2 disks, got %d", ret);
+ goto cleanup;
+ }
+
+ if (STRNEQ(disks[0]->name, "/dev/dm-3") ||
+ STRNEQ(disks[1]->name, "/dev/nvme0n1")) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ "unexpected return values for disks names");
+ goto cleanup;
+ }
+
+ if (STRNEQ(disks[0]->alias, "fedora_localhost--live-home") ||
+ disks[1]->alias != NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ "unexpected return values for disks aliases");
+ goto cleanup;
+ }
+
+ if (STRNEQ(disks[0]->dependencies[0], "/dev/dm-0") ||
+ disks[0]->dependencies[1] != NULL ||
+ disks[1]->dependencies[0] != NULL) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ "unexpected return values for disks dependencies");
+ goto cleanup;
+ }
+
+ if (disks[0]->address != NULL ||
+ disks[1]->address->bus != 0 ||
+ disks[1]->address->target != 0 ||
+ disks[1]->address->unit != 0 ||
+ STRNEQ(disks[1]->address->serial, "GIGABYTE
GP-ASM2NE6100TTTD_SN202208900567") ||
+ STRNEQ(disks[1]->address->bus_type, "unknown")) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ "unexpected return values for disks addresses");
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ qemuMonitorTestFree(test);
+ if (disks) {
+ for (i = 0; i < disks_count; i++)
+ qemuAgentDiskInfoFree(disks[i]);
+ }
+ VIR_FREE(disks);
+
+ return ret;
+}
+
+
static const char testQemuAgentUsersResponse[] =
"{\"return\": "
" ["
@@ -1394,6 +1504,7 @@ mymain(void)
DO_TEST(OSInfo);
DO_TEST(Timezone);
DO_TEST(SSHKeys);
+ DO_TEST(GetDisks);
DO_TEST(Timeout); /* Timeout should always be called last */
--
2.29.0