1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2025-01-11 09:17:52 +03:00

qemu_agent: add qemuAgentGetDisks

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@redhat.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Tested-by: Han Han <hhan@redhat.com>
This commit is contained in:
Marc-André Lureau 2020-11-20 22:09:45 +04:00 committed by Michal Privoznik
parent 3169db81f6
commit 8401a586a2
3 changed files with 218 additions and 0 deletions

View File

@ -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)
{
@ -2639,3 +2654,80 @@ 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;
int rc;
if (!(cmd = qemuAgentMakeCommand("guest-get-disks", NULL)))
return -1;
if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
report_unsupported)) < 0)
return rc;
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;
}

View File

@ -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);

View File

@ -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 */