From: Marc-André Lureau <marcandre.lur...@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.lur...@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

Reply via email to