1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-22 17:34:18 +03:00
libvirt/tests/qemuagenttest.c
Peter Krempa c3a7f46fe3 qemuAgentGetFSInfo: expose 'report_unsupported' argument
Use qemuAgentCommandFull so that callers of qemuAgentGetFSInfo can
suppress error reports if the function is not supported by the guest
agent.

Since this patch removes the last use of
qemuAgentErrorCommandUnsupported the whole function is deleted as well.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2020-03-25 13:13:18 +01:00

1326 lines
41 KiB
C

/*
* Copyright (C) 2013, 2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include "testutils.h"
#include "testutilsqemu.h"
#include "qemumonitortestutils.h"
#include "qemu/qemu_conf.h"
#include "qemu/qemu_agent.h"
#include "virthread.h"
#include "virerror.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_NONE
virQEMUDriver driver;
static int
testQemuAgentFSFreeze(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
const char *mountpoints[] = {"/fs1", "/fs2", "/fs3", "/fs4", "/fs5"};
int ret = -1;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-fsfreeze-freeze-list",
"{ \"return\" : 5 }") < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-fsfreeze-freeze",
"{ \"return\" : 7 }") < 0)
goto cleanup;
if ((ret = qemuAgentFSFreeze(qemuMonitorTestGetAgent(test),
mountpoints, 5)) < 0)
goto cleanup;
if (ret != 5) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"expected 5 frozen filesystems, got %d", ret);
goto cleanup;
}
if ((ret = qemuAgentFSFreeze(qemuMonitorTestGetAgent(test), NULL, 0)) < 0)
goto cleanup;
if (ret != 7) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"expected 7 frozen filesystems, got %d", ret);
goto cleanup;
}
ret = 0;
cleanup:
qemuMonitorTestFree(test);
return ret;
}
static int
testQemuAgentFSThaw(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
int ret = -1;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-fsfreeze-thaw",
"{ \"return\" : 5 }") < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-fsfreeze-thaw",
"{ \"return\" : 7 }") < 0)
goto cleanup;
if ((ret = qemuAgentFSThaw(qemuMonitorTestGetAgent(test))) < 0)
goto cleanup;
if (ret != 5) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"expected 5 thawed filesystems, got %d", ret);
goto cleanup;
}
if ((ret = qemuAgentFSThaw(qemuMonitorTestGetAgent(test))) < 0)
goto cleanup;
if (ret != 7) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"expected 7 thawed filesystems, got %d", ret);
goto cleanup;
}
ret = 0;
cleanup:
qemuMonitorTestFree(test);
return ret;
}
static int
testQemuAgentFSTrim(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
int ret = -1;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItemParams(test, "guest-fstrim",
"{ \"return\" : {} }",
"minimum", "1337",
NULL) < 0)
goto cleanup;
if (qemuAgentFSTrim(qemuMonitorTestGetAgent(test), 1337) < 0)
goto cleanup;
ret = 0;
cleanup:
qemuMonitorTestFree(test);
return ret;
}
static int
testQemuAgentGetFSInfoCommon(virDomainXMLOptionPtr xmlopt,
qemuMonitorTestPtr *test,
virDomainDefPtr *def)
{
int ret = -1;
char *domain_filename = NULL;
qemuMonitorTestPtr ret_test = NULL;
virDomainDefPtr ret_def = NULL;
if (!test || !def)
return -1;
if (!(ret_test = qemuMonitorTestNewAgent(xmlopt)))
return -1;
domain_filename = g_strdup_printf("%s/qemuagentdata/fsinfo.xml", abs_srcdir);
if (!(ret_def = virDomainDefParseFile(domain_filename, xmlopt,
NULL, VIR_DOMAIN_DEF_PARSE_INACTIVE)))
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(ret_test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(ret_test, "guest-get-fsinfo",
"{\"return\": ["
" {\"name\": \"sda1\", \"mountpoint\": \"/\","
" \"total-bytes\":952840192,"
" \"used-bytes\":229019648,"
" \"disk\": ["
" {\"serial\": \"ARBITRARYSTRING\","
" \"bus-type\": \"ide\","
" \"bus\": 1, \"unit\": 0,"
" \"pci-controller\": {"
" \"bus\": 0, \"slot\": 1,"
" \"domain\": 0, \"function\": 1},"
" \"dev\": \"/dev/sda1\","
" \"target\": 0}],"
" \"type\": \"ext4\"},"
" {\"name\": \"dm-1\","
" \"mountpoint\": \"/opt\","
" \"disk\": ["
" {\"bus-type\": \"virtio\","
" \"bus\": 0, \"unit\": 0,"
" \"pci-controller\": {"
" \"bus\": 0, \"slot\": 6,"
" \"domain\": 0, \"function\": 0},"
" \"target\": 0},"
" {\"bus-type\": \"virtio\","
" \"bus\": 0, \"unit\": 0,"
" \"pci-controller\": {"
" \"bus\": 0, \"slot\": 7,"
" \"domain\": 0, \"function\": 0},"
" \"target\": 0}],"
" \"type\": \"vfat\"},"
" {\"name\": \"sdb1\","
" \"mountpoint\": \"/mnt/disk\","
" \"disk\": [], \"type\": \"xfs\"}]}") < 0)
goto cleanup;
*test = g_steal_pointer(&ret_test);
*def = g_steal_pointer(&ret_def);
ret = 0;
cleanup:
VIR_FREE(domain_filename);
if (ret_test)
qemuMonitorTestFree(ret_test);
virDomainDefFree(ret_def);
return ret;
}
static int
testQemuAgentGetFSInfo(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = NULL;
virDomainDefPtr def = NULL;
qemuAgentFSInfoPtr *info = NULL;
int ret = -1, ninfo = 0, i;
if (testQemuAgentGetFSInfoCommon(xmlopt, &test, &def) < 0)
goto cleanup;
if ((ninfo = qemuAgentGetFSInfo(qemuMonitorTestGetAgent(test),
&info, true)) < 0)
goto cleanup;
if (ninfo != 3) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"expected 3 filesystems information, got %d", ninfo);
ret = -1;
goto cleanup;
}
if (STRNEQ(info[2]->name, "sda1") ||
STRNEQ(info[2]->mountpoint, "/") ||
STRNEQ(info[2]->fstype, "ext4") ||
info[2]->ndisks != 1 ||
!info[2]->disks || !info[2]->disks[0]) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"unexpected filesystems information returned for sda1 (%s)",
info[2]->name);
ret = -1;
goto cleanup;
}
if (STRNEQ(info[1]->name, "dm-1") ||
STRNEQ(info[1]->mountpoint, "/opt") ||
STRNEQ(info[1]->fstype, "vfat") ||
info[1]->ndisks != 2 ||
!info[1]->disks || !info[1]->disks[0] || !info[1]->disks[1] ||
STRNEQ(info[1]->disks[0]->bus_type, "virtio") ||
info[1]->disks[0]->bus != 0 ||
info[1]->disks[0]->target != 0 ||
info[1]->disks[0]->unit != 0 ||
info[1]->disks[0]->pci_controller.domain != 0 ||
info[1]->disks[0]->pci_controller.bus != 0 ||
info[1]->disks[0]->pci_controller.slot != 6 ||
info[1]->disks[0]->pci_controller.function != 0 ||
STRNEQ(info[1]->disks[1]->bus_type, "virtio") ||
info[1]->disks[1]->bus != 0 ||
info[1]->disks[1]->target != 0 ||
info[1]->disks[1]->unit != 0 ||
info[1]->disks[1]->pci_controller.domain != 0 ||
info[1]->disks[1]->pci_controller.bus != 0 ||
info[1]->disks[1]->pci_controller.slot != 7 ||
info[1]->disks[1]->pci_controller.function != 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"unexpected filesystems information returned for dm-1 (%s)",
info[0]->name);
ret = -1;
goto cleanup;
}
if (STRNEQ(info[0]->name, "sdb1") ||
STRNEQ(info[0]->mountpoint, "/mnt/disk") ||
STRNEQ(info[0]->fstype, "xfs") ||
info[0]->ndisks != 0 || info[0]->disks) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"unexpected filesystems information returned for sdb1 (%s)",
info[0]->name);
ret = -1;
goto cleanup;
}
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-get-fsinfo",
"{\"error\":"
" {\"class\":\"CommandDisabled\","
" \"desc\":\"The command guest-get-fsinfo "
"has been disabled for "
"this instance\","
" \"data\":{\"name\":\"guest-get-fsinfo\"}"
" }"
"}") < 0)
goto cleanup;
if (qemuAgentGetFSInfo(qemuMonitorTestGetAgent(test), &info, true) >= 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"agent get-fsinfo command should have failed");
goto cleanup;
}
ret = 0;
cleanup:
for (i = 0; i < ninfo; i++)
qemuAgentFSInfoFree(info[i]);
VIR_FREE(info);
virDomainDefFree(def);
qemuMonitorTestFree(test);
return ret;
}
static int
testQemuAgentSuspend(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
int ret = -1;
size_t i;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-suspend-ram",
"{ \"return\" : {} }") < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-suspend-disk",
"{ \"return\" : {} }") < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-suspend-hybrid",
"{ \"return\" : {} }") < 0)
goto cleanup;
/* try the commands - fail if ordering changes */
for (i = 0; i < VIR_NODE_SUSPEND_TARGET_LAST; i++) {
if (qemuAgentSuspend(qemuMonitorTestGetAgent(test), i) < 0)
goto cleanup;
}
ret = 0;
cleanup:
qemuMonitorTestFree(test);
return ret;
}
struct qemuAgentShutdownTestData {
const char *mode;
qemuAgentEvent event;
};
static int
qemuAgentShutdownTestMonitorHandler(qemuMonitorTestPtr test,
qemuMonitorTestItemPtr item,
const char *cmdstr)
{
struct qemuAgentShutdownTestData *data;
virJSONValuePtr val = NULL;
virJSONValuePtr args;
const char *cmdname;
const char *mode;
int ret = -1;
data = qemuMonitorTestItemGetPrivateData(item);
if (!(val = virJSONValueFromString(cmdstr)))
return -1;
if (!(cmdname = virJSONValueObjectGetString(val, "execute"))) {
ret = qemuMonitorReportError(test, "Missing command name in %s", cmdstr);
goto cleanup;
}
if (STRNEQ(cmdname, "guest-shutdown")) {
ret = qemuMonitorTestAddInvalidCommandResponse(test, "guest-shutdown",
cmdname);
goto cleanup;
}
if (!(args = virJSONValueObjectGet(val, "arguments"))) {
ret = qemuMonitorReportError(test,
"Missing arguments section");
goto cleanup;
}
if (!(mode = virJSONValueObjectGetString(args, "mode"))) {
ret = qemuMonitorReportError(test, "Missing shutdown mode");
goto cleanup;
}
if (STRNEQ(mode, data->mode)) {
ret = qemuMonitorReportError(test,
"expected shutdown mode '%s' got '%s'",
data->mode, mode);
goto cleanup;
}
/* now don't reply but return a qemu agent event */
qemuAgentNotifyEvent(qemuMonitorTestGetAgent(test),
data->event);
ret = 0;
cleanup:
virJSONValueFree(val);
return ret;
}
static int
testQemuAgentShutdown(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
struct qemuAgentShutdownTestData priv;
int ret = -1;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
priv.event = QEMU_AGENT_EVENT_SHUTDOWN;
priv.mode = "halt";
if (qemuMonitorTestAddHandler(test, qemuAgentShutdownTestMonitorHandler,
&priv, NULL) < 0)
goto cleanup;
if (qemuAgentShutdown(qemuMonitorTestGetAgent(test),
QEMU_AGENT_SHUTDOWN_HALT) < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
priv.event = QEMU_AGENT_EVENT_SHUTDOWN;
priv.mode = "powerdown";
if (qemuMonitorTestAddHandler(test, qemuAgentShutdownTestMonitorHandler,
&priv, NULL) < 0)
goto cleanup;
if (qemuAgentShutdown(qemuMonitorTestGetAgent(test),
QEMU_AGENT_SHUTDOWN_POWERDOWN) < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
priv.event = QEMU_AGENT_EVENT_RESET;
priv.mode = "reboot";
if (qemuMonitorTestAddHandler(test, qemuAgentShutdownTestMonitorHandler,
&priv, NULL) < 0)
goto cleanup;
if (qemuAgentShutdown(qemuMonitorTestGetAgent(test),
QEMU_AGENT_SHUTDOWN_REBOOT) < 0)
goto cleanup;
/* check negative response, so that we can verify that the agent breaks
* out from sleep */
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-shutdown",
"{\"error\":"
" {\"class\":\"CommandDisabled\","
" \"desc\":\"The command guest-shutdown has "
"been disabled for this instance\","
" \"data\":{\"name\":\"guest-shutdown\"}"
" }"
"}") < 0)
goto cleanup;
if (qemuAgentShutdown(qemuMonitorTestGetAgent(test),
QEMU_AGENT_SHUTDOWN_REBOOT) != -1) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"agent shutdown command should have failed");
goto cleanup;
}
ret = 0;
cleanup:
qemuMonitorTestFree(test);
return ret;
}
static const char testQemuAgentCPUResponse[] =
"{\"return\": "
" ["
" {\"online\": true,"
" \"can-offline\": false,"
" \"logical-id\": 0"
" },"
" {\"online\": true,"
" \"can-offline\": true,"
" \"logical-id\": 1"
" },"
" {\"online\": true,"
" \"can-offline\": true,"
" \"logical-id\": 2"
" },"
" {\"online\": false,"
" \"can-offline\": true,"
" \"logical-id\": 3"
" }"
" ]"
"}";
static const char testQemuAgentCPUArguments1[] =
"[{\"logical-id\":1,\"online\":false}]";
static const char testQemuAgentCPUArguments2[] =
"[{\"logical-id\":1,\"online\":true},"
"{\"logical-id\":3,\"online\":true}]";
static const char testQemuAgentCPUArguments3[] =
"[{\"logical-id\":3,\"online\":true}]";
static int
testQemuAgentCPU(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
qemuAgentCPUInfoPtr cpuinfo = NULL;
int nvcpus;
int ret = -1;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-get-vcpus",
testQemuAgentCPUResponse) < 0)
goto cleanup;
/* get cpus */
if ((nvcpus = qemuAgentGetVCPUs(qemuMonitorTestGetAgent(test),
&cpuinfo)) < 0)
goto cleanup;
if (nvcpus != 4) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"Expected '4' cpus, got '%d'", nvcpus);
goto cleanup;
}
/* try to unplug one */
if (qemuAgentUpdateCPUInfo(2, cpuinfo, nvcpus) < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItemParams(test, "guest-set-vcpus",
"{ \"return\" : 1 }",
"vcpus", testQemuAgentCPUArguments1,
NULL) < 0)
goto cleanup;
if (qemuAgentSetVCPUs(qemuMonitorTestGetAgent(test), cpuinfo, nvcpus) < 0)
goto cleanup;
/* try to hotplug two, second one will fail */
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItemParams(test, "guest-set-vcpus",
"{ \"return\" : 1 }",
"vcpus", testQemuAgentCPUArguments2,
NULL) < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItemParams(test, "guest-set-vcpus",
"{ \"error\" : \"random error\" }",
"vcpus", testQemuAgentCPUArguments3,
NULL) < 0)
goto cleanup;
if (qemuAgentUpdateCPUInfo(4, cpuinfo, nvcpus) < 0)
goto cleanup;
/* this should fail */
if (qemuAgentSetVCPUs(qemuMonitorTestGetAgent(test), cpuinfo, nvcpus) != -1)
goto cleanup;
ret = 0;
cleanup:
VIR_FREE(cpuinfo);
qemuMonitorTestFree(test);
return ret;
}
static const char testQemuAgentArbitraryCommandResponse[] =
"{\"return\":\"bla\"}";
static int
testQemuAgentArbitraryCommand(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
int ret = -1;
char *reply = NULL;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "ble",
testQemuAgentArbitraryCommandResponse) < 0)
goto cleanup;
if (qemuAgentArbitraryCommand(qemuMonitorTestGetAgent(test),
"{\"execute\":\"ble\"}",
&reply,
VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
goto cleanup;
if (STRNEQ(reply, testQemuAgentArbitraryCommandResponse)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"invalid processing of guest agent reply: "
"got '%s' expected '%s'",
reply, testQemuAgentArbitraryCommandResponse);
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(reply);
qemuMonitorTestFree(test);
return ret;
}
static int
qemuAgentTimeoutTestMonitorHandler(qemuMonitorTestPtr test G_GNUC_UNUSED,
qemuMonitorTestItemPtr item G_GNUC_UNUSED,
const char *cmdstr G_GNUC_UNUSED)
{
return 0;
}
static int
testQemuAgentTimeout(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
char *reply = NULL;
int ret = -1;
if (!test)
return -1;
if (virTestGetExpensive() == 0) {
ret = EXIT_AM_SKIP;
goto cleanup;
}
if (qemuMonitorTestAddHandler(test, qemuAgentTimeoutTestMonitorHandler,
NULL, NULL) < 0)
goto cleanup;
if (qemuAgentFSFreeze(qemuMonitorTestGetAgent(test), NULL, 0) != -1) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"agent command should have failed");
goto cleanup;
}
/* test timeout */
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddHandler(test, qemuAgentTimeoutTestMonitorHandler,
NULL, NULL) < 0)
goto cleanup;
if (qemuAgentArbitraryCommand(qemuMonitorTestGetAgent(test),
"{\"execute\":\"ble\"}",
&reply,
1) != -2) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"agent command didn't time out");
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(reply);
qemuMonitorTestFree(test);
return ret;
}
static const char testQemuAgentGetInterfacesResponse[] =
"{\"return\": "
" ["
" {\"name\":\"eth2\","
" \"hardware-address\":\"52:54:00:36:2a:e5\""
" },"
" {\"name\":\"eth1:0\","
" \"ip-addresses\":"
" ["
" {\"ip-address-type\":\"ipv4\","
" \"ip-address\":\"192.168.10.91\","
" \"prefix\":24"
" },"
" {\"ip-address-type\":\"ipv6\","
" \"ip-address\":\"fe80::fc54:ff:fefe:4c4f\","
" \"prefix\":64"
" }"
" ],"
" \"hardware-address\":\"52:54:00:d3:39:ee\""
" },"
" {\"name\":\"eth0\","
" \"ip-addresses\":"
" ["
" {\"ip-address-type\":\"ipv6\","
" \"ip-address\":\"fe80::5054:ff:fe89:ad35\","
" \"prefix\":64"
" },"
" {\"ip-address-type\":\"ipv4\","
" \"ip-address\":\"192.168.102.142\","
" \"prefix\":24"
" },"
" {\"ip-address-type\":\"ipv4\","
" \"ip-address\":\"192.168.234.152\","
" \"prefix\":16"
" },"
" {\"ip-address-type\":\"ipv6\","
" \"ip-address\":\"fe80::5054:ff:fec3:68bb\","
" \"prefix\":64"
" }"
" ],"
" \"hardware-address\":\"52:54:00:89:ad:35\""
" },"
" {\"name\":\"eth1\","
" \"ip-addresses\":"
" ["
" {\"ip-address-type\":\"ipv4\","
" \"ip-address\":\"192.168.103.83\","
" \"prefix\":32"
" },"
" {\"ip-address-type\":\"ipv6\","
" \"ip-address\":\"fe80::5054:ff:fed3:39ee\","
" \"prefix\":64"
" }"
" ],"
" \"hardware-address\":\"52:54:00:d3:39:ee\""
" },"
" {\"name\":\"lo\","
" \"ip-addresses\":"
" ["
" {\"ip-address-type\":\"ipv4\","
" \"ip-address\":\"127.0.0.1\","
" \"prefix\":8"
" },"
" {\"ip-address-type\":\"ipv6\","
" \"ip-address\":\"::1\","
" \"prefix\":128"
" }"
" ],"
" \"hardware-address\":\"00:00:00:00:00:00\""
" }"
" ]"
"}";
static int
testQemuAgentGetInterfaces(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
size_t i;
int ret = -1;
int ifaces_count = 0;
virDomainInterfacePtr *ifaces = NULL;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-network-get-interfaces",
testQemuAgentGetInterfacesResponse) < 0)
goto cleanup;
if ((ifaces_count = qemuAgentGetInterfaces(qemuMonitorTestGetAgent(test),
&ifaces)) < 0)
goto cleanup;
if (ifaces_count != 4) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"expected 4 interfaces, got %d", ret);
goto cleanup;
}
if (STRNEQ(ifaces[0]->name, "eth2") ||
STRNEQ(ifaces[1]->name, "eth1") ||
STRNEQ(ifaces[2]->name, "eth0") ||
STRNEQ(ifaces[3]->name, "lo")) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"unexpected return values for interface names");
goto cleanup;
}
if (STRNEQ(ifaces[0]->hwaddr, "52:54:00:36:2a:e5") ||
STRNEQ(ifaces[1]->hwaddr, "52:54:00:d3:39:ee") ||
STRNEQ(ifaces[2]->hwaddr, "52:54:00:89:ad:35") ||
STRNEQ(ifaces[3]->hwaddr, "00:00:00:00:00:00")) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"unexpected return values for MAC addresses");
goto cleanup;
}
if (ifaces[0]->naddrs != 0 ||
ifaces[1]->naddrs != 4 ||
ifaces[2]->naddrs != 4 ||
ifaces[3]->naddrs != 2) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"unexpected return values for number of IP addresses");
goto cleanup;
}
if (ifaces[1]->addrs[0].type != VIR_IP_ADDR_TYPE_IPV4 ||
ifaces[1]->addrs[1].type != VIR_IP_ADDR_TYPE_IPV6 ||
ifaces[1]->addrs[2].type != VIR_IP_ADDR_TYPE_IPV4 ||
ifaces[1]->addrs[3].type != VIR_IP_ADDR_TYPE_IPV6 ||
ifaces[2]->addrs[0].type != VIR_IP_ADDR_TYPE_IPV6 ||
ifaces[2]->addrs[1].type != VIR_IP_ADDR_TYPE_IPV4 ||
ifaces[2]->addrs[2].type != VIR_IP_ADDR_TYPE_IPV4 ||
ifaces[2]->addrs[3].type != VIR_IP_ADDR_TYPE_IPV6 ||
ifaces[3]->addrs[0].type != VIR_IP_ADDR_TYPE_IPV4 ||
ifaces[3]->addrs[1].type != VIR_IP_ADDR_TYPE_IPV6) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"unexpected return values for IP address types");
goto cleanup;
}
if (ifaces[1]->addrs[0].prefix != 24 ||
ifaces[1]->addrs[1].prefix != 64 ||
ifaces[1]->addrs[2].prefix != 32 ||
ifaces[1]->addrs[3].prefix != 64 ||
ifaces[2]->addrs[0].prefix != 64 ||
ifaces[2]->addrs[1].prefix != 24 ||
ifaces[2]->addrs[2].prefix != 16 ||
ifaces[2]->addrs[3].prefix != 64 ||
ifaces[3]->addrs[0].prefix != 8 ||
ifaces[3]->addrs[1].prefix != 128) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"unexpected return values for IP address prefix");
goto cleanup;
}
if (STRNEQ(ifaces[1]->addrs[0].addr, "192.168.10.91") ||
STRNEQ(ifaces[1]->addrs[1].addr, "fe80::fc54:ff:fefe:4c4f") ||
STRNEQ(ifaces[1]->addrs[2].addr, "192.168.103.83") ||
STRNEQ(ifaces[1]->addrs[3].addr, "fe80::5054:ff:fed3:39ee") ||
STRNEQ(ifaces[2]->addrs[0].addr, "fe80::5054:ff:fe89:ad35") ||
STRNEQ(ifaces[2]->addrs[1].addr, "192.168.102.142") ||
STRNEQ(ifaces[2]->addrs[2].addr, "192.168.234.152") ||
STRNEQ(ifaces[2]->addrs[3].addr, "fe80::5054:ff:fec3:68bb") ||
STRNEQ(ifaces[3]->addrs[0].addr, "127.0.0.1") ||
STRNEQ(ifaces[3]->addrs[1].addr, "::1")) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
"unexpected return values for IP address values");
goto cleanup;
}
ret = 0;
cleanup:
qemuMonitorTestFree(test);
if (ifaces) {
for (i = 0; i < ifaces_count; i++)
virDomainInterfaceFree(ifaces[i]);
}
VIR_FREE(ifaces);
return ret;
}
static const char testQemuAgentUsersResponse[] =
"{\"return\": "
" ["
" {\"user\": \"test\","
" \"login-time\": 1561739203.584038"
" },"
" {\"user\": \"test2\","
" \"login-time\": 1561739229.190697"
" }"
" ]"
"}";
static const char testQemuAgentUsersResponse2[] =
"{\"return\": "
" ["
" {\"user\": \"test\","
" \"domain\": \"DOMAIN\","
" \"login-time\": 1561739203.584038"
" }"
" ]"
"}";
static int
checkUserInfo(virTypedParameterPtr params,
int nparams,
size_t nth,
const char *expUsername,
const char *expDomain,
unsigned long long expLogintime)
{
char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
const char *username = NULL;
const char *domain = NULL;
unsigned long long logintime = 0;
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
"user.%zu.name", nth);
if (virTypedParamsGetString(params, nparams, param_name, &username) < 0)
return -1;
if (STRNEQ_NULLABLE(expUsername, username)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"Expected user name '%s', got '%s'",
expUsername, username);
return -1;
}
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
"user.%zu.domain", nth);
if (virTypedParamsGetString(params, nparams, param_name, &domain) < 0)
return -1;
if (STRNEQ_NULLABLE(expDomain, domain)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"Expected domain '%s', got '%s'",
NULLSTR(expDomain), NULLSTR(domain));
return -1;
}
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
"user.%zu.login-time", nth);
if (virTypedParamsGetULLong(params, nparams, param_name, &logintime) < 0)
return -1;
if (expLogintime != logintime) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"Expected login time of '%llu', got '%llu'",
expLogintime, logintime);
return -1;
}
return 0;
}
static int
testQemuAgentUsers(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
virTypedParameterPtr params = NULL;
int nparams = 0;
int maxparams = 0;
int ret = -1;
unsigned int count;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-get-users",
testQemuAgentUsersResponse) < 0)
goto cleanup;
/* get users */
if (qemuAgentGetUsers(qemuMonitorTestGetAgent(test),
&params, &nparams, &maxparams, true) < 0)
goto cleanup;
if (virTypedParamsGetUInt(params, nparams, "user.count", &count) < 0)
goto cleanup;
if (count != 2) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"Expected '2' users, got '%u'", count);
goto cleanup;
}
if (checkUserInfo(params, nparams, 0, "test", NULL, 1561739203584) < 0 ||
checkUserInfo(params, nparams, 1, "test2", NULL, 1561739229190) < 0)
goto cleanup;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-get-users",
testQemuAgentUsersResponse2) < 0)
goto cleanup;
virTypedParamsFree(params, nparams);
params = NULL;
nparams = 0;
maxparams = 0;
/* get users with domain */
if (qemuAgentGetUsers(qemuMonitorTestGetAgent(test),
&params, &nparams, &maxparams, true) < 0)
goto cleanup;
if (virTypedParamsGetUInt(params, nparams, "user.count", &count) < 0)
goto cleanup;
if (count != 1) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"Expected '1' user, got '%u'", count);
goto cleanup;
}
if (checkUserInfo(params, nparams, 0, "test", "DOMAIN", 1561739203584) < 0)
goto cleanup;
ret = 0;
cleanup:
virTypedParamsFree(params, nparams);
qemuMonitorTestFree(test);
return ret;
}
static const char testQemuAgentOSInfoResponse[] =
"{\"return\": "
" {\"name\":\"CentOS Linux\", "
" \"kernel-release\":\"3.10.0-862.14.4.el7.x86_64\", "
" \"version\":\"7 (Core)\", "
" \"pretty-name\":\"CentOS Linux 7 (Core)\", "
" \"version-id\":\"7\", "
" \"kernel-version\":\"#1 SMP Wed Sep 26 15:12:11 UTC 2018\", "
" \"machine\":\"x86_64\", "
" \"id\":\"centos\"} "
"}";
static const char testQemuAgentOSInfoResponse2[] =
"{\"return\": "
" {\"name\":\"Microsoft Windows\", "
" \"kernel-release\":\"7601\", "
" \"version\":\"Microsoft Windows 77\", "
" \"variant\":\"client\", "
" \"pretty-name\":\"Windows 7 Professional\", "
" \"version-id\":\"\", "
" \"variant-id\":\"client\", "
" \"kernel-version\":\"6.1\", "
" \"machine\":\"x86_64\", "
" \"id\":\"mswindows\"} "
"}";
static int
testQemuAgentOSInfo(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
virTypedParameterPtr params = NULL;
int nparams = 0;
int maxparams = 0;
int ret = -1;
if (!test)
return -1;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-get-osinfo",
testQemuAgentOSInfoResponse) < 0)
goto cleanup;
/* get osinfo */
if (qemuAgentGetOSInfo(qemuMonitorTestGetAgent(test),
&params, &nparams, &maxparams, true) < 0)
goto cleanup;
if (nparams != 8) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"Expected 8 params, got %d", nparams);
goto cleanup;
}
#define VALIDATE_PARAM(param_name_, expected_) \
do { \
const char *value_ = NULL; \
if (virTypedParamsGetString(params, nparams, param_name_, &value_) < 0 || \
value_ == NULL) { \
virReportError(VIR_ERR_INTERNAL_ERROR, "missing param '%s'", param_name_); \
goto cleanup; \
} \
if (STRNEQ(value_, expected_)) { \
virReportError(VIR_ERR_INTERNAL_ERROR, \
"Expected name '%s', got '%s'", expected_, value_); \
goto cleanup; \
} \
} while (0)
VALIDATE_PARAM("os.id", "centos");
VALIDATE_PARAM("os.name", "CentOS Linux");
VALIDATE_PARAM("os.version", "7 (Core)");
VALIDATE_PARAM("os.version-id", "7");
VALIDATE_PARAM("os.pretty-name", "CentOS Linux 7 (Core)");
VALIDATE_PARAM("os.kernel-release", "3.10.0-862.14.4.el7.x86_64");
VALIDATE_PARAM("os.kernel-version", "#1 SMP Wed Sep 26 15:12:11 UTC 2018");
VALIDATE_PARAM("os.machine", "x86_64");
virTypedParamsFree(params, nparams);
params = NULL;
nparams = 0;
maxparams = 0;
if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
goto cleanup;
if (qemuMonitorTestAddItem(test, "guest-get-osinfo",
testQemuAgentOSInfoResponse2) < 0)
goto cleanup;
/* get users with domain */
if (qemuAgentGetOSInfo(qemuMonitorTestGetAgent(test),
&params, &nparams, &maxparams, true) < 0)
goto cleanup;
if (nparams != 10) {
virReportError(VIR_ERR_INTERNAL_ERROR,
"Expected 10 params, got %d", nparams);
goto cleanup;
}
VALIDATE_PARAM("os.id", "mswindows");
VALIDATE_PARAM("os.name", "Microsoft Windows");
VALIDATE_PARAM("os.pretty-name", "Windows 7 Professional");
VALIDATE_PARAM("os.version", "Microsoft Windows 77");
VALIDATE_PARAM("os.version-id", "");
VALIDATE_PARAM("os.variant", "client");
VALIDATE_PARAM("os.variant-id", "client");
VALIDATE_PARAM("os.kernel-release", "7601");
VALIDATE_PARAM("os.kernel-version", "6.1");
VALIDATE_PARAM("os.machine", "x86_64");
virTypedParamsFree(params, nparams);
ret = 0;
cleanup:
qemuMonitorTestFree(test);
return ret;
}
static const char testQemuAgentTimezoneResponse1[] =
"{\"return\":{\"zone\":\"IST\",\"offset\":19800}}";
static const char testQemuAgentTimezoneResponse2[] =
"{\"return\":{\"zone\":\"CEST\",\"offset\":7200}}";
static const char testQemuAgentTimezoneResponse3[] =
"{\"return\":{\"zone\":\"NDT\",\"offset\":-9000}}";
static const char testQemuAgentTimezoneResponse4[] =
"{\"return\":{\"zone\":\"PDT\",\"offset\":-25200}}";
static int
testQemuAgentTimezone(const void *data)
{
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
int ret = -1;
if (!test)
return -1;
#define VALIDATE_TIMEZONE(response_, expected_name_, expected_offset_) \
do { \
virTypedParameterPtr params_ = NULL; \
int nparams_ = 0; \
int maxparams_ = 0; \
const char *name_ = NULL; \
int offset_; \
if (qemuMonitorTestAddAgentSyncResponse(test) < 0) \
goto cleanup; \
if (qemuMonitorTestAddItem(test, "guest-get-timezone", \
response_) < 0) \
goto cleanup; \
if (qemuAgentGetTimezone(qemuMonitorTestGetAgent(test), \
&params_, &nparams_, &maxparams_, true) < 0) \
goto cleanup; \
if (nparams_ != 2) { \
virReportError(VIR_ERR_INTERNAL_ERROR, \
"Expected 2 params, got %d", nparams_); \
goto cleanup; \
} \
if (virTypedParamsGetString(params_, nparams_, \
"timezone.name", &name_) < 0) { \
virReportError(VIR_ERR_INTERNAL_ERROR, "missing param '%s'", \
"tiemzone.name"); \
goto cleanup; \
} \
if (STRNEQ(name_, expected_name_)) { \
virReportError(VIR_ERR_INTERNAL_ERROR, \
"Expected name '%s', got '%s'", expected_name_, name_); \
goto cleanup; \
} \
if (virTypedParamsGetInt(params_, nparams_, \
"timezone.offset", &offset_) < 0) { \
virReportError(VIR_ERR_INTERNAL_ERROR, "missing param '%s'", \
"tiemzone.offset"); \
goto cleanup; \
} \
if (offset_ != expected_offset_) { \
virReportError(VIR_ERR_INTERNAL_ERROR, \
"Expected offset '%i', got '%i'", offset_, \
expected_offset_); \
goto cleanup; \
} \
virTypedParamsFree(params_, nparams_); \
} while (0)
VALIDATE_TIMEZONE(testQemuAgentTimezoneResponse1, "IST", 19800);
VALIDATE_TIMEZONE(testQemuAgentTimezoneResponse2, "CEST", 7200);
VALIDATE_TIMEZONE(testQemuAgentTimezoneResponse3, "NDT", -9000);
VALIDATE_TIMEZONE(testQemuAgentTimezoneResponse4, "PDT", -25200);
ret = 0;
cleanup:
qemuMonitorTestFree(test);
return ret;
}
static int
mymain(void)
{
int ret = 0;
if (qemuTestDriverInit(&driver) < 0)
return EXIT_FAILURE;
virEventRegisterDefaultImpl();
#define DO_TEST(name) \
if (virTestRun(# name, testQemuAgent ## name, driver.xmlopt) < 0) \
ret = -1
DO_TEST(FSFreeze);
DO_TEST(FSThaw);
DO_TEST(FSTrim);
DO_TEST(GetFSInfo);
DO_TEST(Suspend);
DO_TEST(Shutdown);
DO_TEST(CPU);
DO_TEST(ArbitraryCommand);
DO_TEST(GetInterfaces);
DO_TEST(Users);
DO_TEST(OSInfo);
DO_TEST(Timezone);
DO_TEST(Timeout); /* Timeout should always be called last */
qemuTestDriverFree(&driver);
return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
VIR_TEST_MAIN(mymain)