mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-11-03 20:01:16 +00:00
a931486a97
When we're collecting guest information, older agents may not support all agent commands. In the case where the user requested all info types (i.e. types == 0), ignore unsupported command errors and gather as much information as possible. If the agent command failed for some other reason, or if the user explciitly requested a specific info type (i.e. types != 0), abort on the first error. Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com> Signed-off-by: Michal Privoznik <mprivozn@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
1466 lines
47 KiB
C
1466 lines
47 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;
|
|
|
|
if (virAsprintf(&domain_filename, "%s/qemuagentdata/fsinfo.xml",
|
|
abs_srcdir) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(ret_def = virDomainDefParseFile(domain_filename, driver.caps, 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;
|
|
|
|
VIR_STEAL_PTR(*test, ret_test);
|
|
VIR_STEAL_PTR(*def, 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;
|
|
virDomainFSInfoPtr *info = NULL;
|
|
int ret = -1, ninfo = 0, i;
|
|
|
|
if (testQemuAgentGetFSInfoCommon(xmlopt, &test, &def) < 0)
|
|
goto cleanup;
|
|
|
|
if ((ninfo = qemuAgentGetFSInfo(qemuMonitorTestGetAgent(test),
|
|
&info, def)) < 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]->ndevAlias != 1 ||
|
|
!info[2]->devAlias || !info[2]->devAlias[0] ||
|
|
STRNEQ(info[2]->devAlias[0], "hdc")) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"unexpected filesystems information returned for sda1 (%s,%s)",
|
|
info[2]->name, info[2]->devAlias ? info[2]->devAlias[0] : "null");
|
|
ret = -1;
|
|
goto cleanup;
|
|
}
|
|
if (STRNEQ(info[1]->name, "dm-1") ||
|
|
STRNEQ(info[1]->mountpoint, "/opt") ||
|
|
STRNEQ(info[1]->fstype, "vfat") ||
|
|
info[1]->ndevAlias != 2 ||
|
|
!info[1]->devAlias || !info[1]->devAlias[0] || !info[1]->devAlias[1] ||
|
|
STRNEQ(info[1]->devAlias[0], "vda") ||
|
|
STRNEQ(info[1]->devAlias[1], "vdb")) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"unexpected filesystems information returned for dm-1 (%s,%s)",
|
|
info[0]->name, info[0]->devAlias ? info[0]->devAlias[0] : "null");
|
|
ret = -1;
|
|
goto cleanup;
|
|
}
|
|
if (STRNEQ(info[0]->name, "sdb1") ||
|
|
STRNEQ(info[0]->mountpoint, "/mnt/disk") ||
|
|
STRNEQ(info[0]->fstype, "xfs") ||
|
|
info[0]->ndevAlias != 0 || info[0]->devAlias) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"unexpected filesystems information returned for sdb1 (%s,%s)",
|
|
info[0]->name, info[0]->devAlias ? info[0]->devAlias[0] : "null");
|
|
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, def) != -1) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
"agent get-fsinfo command should have failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
for (i = 0; i < ninfo; i++)
|
|
virDomainFSInfoFree(info[i]);
|
|
VIR_FREE(info);
|
|
virDomainDefFree(def);
|
|
qemuMonitorTestFree(test);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
testQemuAgentGetFSInfoParams(const void *data)
|
|
{
|
|
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
|
|
qemuMonitorTestPtr test = NULL;
|
|
virDomainDefPtr def = NULL;
|
|
virTypedParameterPtr params = NULL;
|
|
int nparams = 0, maxparams = 0;
|
|
int ret = -1;
|
|
unsigned int count;
|
|
const char *name, *mountpoint, *fstype, *alias, *serial;
|
|
unsigned int diskcount;
|
|
unsigned long long bytesused, bytestotal;
|
|
const char *alias2;
|
|
|
|
if (testQemuAgentGetFSInfoCommon(xmlopt, &test, &def) < 0)
|
|
goto cleanup;
|
|
|
|
if (qemuAgentGetFSInfoParams(qemuMonitorTestGetAgent(test),
|
|
¶ms, &nparams, &maxparams, def) < 0) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
"Failed to execute qemuAgentGetFSInfoParams()");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (virTypedParamsGetUInt(params, nparams, "fs.count", &count) < 0) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
"expected filesystem count");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (count != 3) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"expected 3 filesystems information, got %d", count);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (virTypedParamsGetString(params, nparams, "fs.2.name", &name) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.2.mountpoint", &mountpoint) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.2.fstype", &fstype) < 0 ||
|
|
virTypedParamsGetULLong(params, nparams, "fs.2.used-bytes", &bytesused) <= 0 ||
|
|
virTypedParamsGetULLong(params, nparams, "fs.2.total-bytes", &bytestotal) <= 0 ||
|
|
virTypedParamsGetUInt(params, nparams, "fs.2.disk.count", &diskcount) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.2.disk.0.alias", &alias) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.2.disk.0.serial", &serial) < 0) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"Missing an expected parameter for sda1 (%s,%s)",
|
|
name, alias);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (STRNEQ(name, "sda1") ||
|
|
STRNEQ(mountpoint, "/") ||
|
|
STRNEQ(fstype, "ext4") ||
|
|
bytesused != 229019648 ||
|
|
bytestotal != 952840192 ||
|
|
diskcount != 1 ||
|
|
STRNEQ(alias, "hdc") ||
|
|
STRNEQ(serial, "ARBITRARYSTRING")) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"unexpected filesystems information returned for sda1 (%s,%s)",
|
|
name, alias);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (virTypedParamsGetString(params, nparams, "fs.1.name", &name) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.1.mountpoint", &mountpoint) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.1.fstype", &fstype) < 0 ||
|
|
virTypedParamsGetULLong(params, nparams, "fs.1.used-bytes", &bytesused) == 1 ||
|
|
virTypedParamsGetULLong(params, nparams, "fs.1.total-bytes", &bytestotal) == 1 ||
|
|
virTypedParamsGetUInt(params, nparams, "fs.1.disk.count", &diskcount) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.1.disk.0.alias", &alias) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.1.disk.1.alias", &alias2) < 0) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"Incorrect parameters for dm-1 (%s,%s)",
|
|
name, alias);
|
|
goto cleanup;
|
|
}
|
|
if (STRNEQ(name, "dm-1") ||
|
|
STRNEQ(mountpoint, "/opt") ||
|
|
STRNEQ(fstype, "vfat") ||
|
|
diskcount != 2 ||
|
|
STRNEQ(alias, "vda") ||
|
|
STRNEQ(alias2, "vdb")) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"unexpected filesystems information returned for dm-1 (%s,%s)",
|
|
name, alias);
|
|
goto cleanup;
|
|
}
|
|
|
|
alias = NULL;
|
|
if (virTypedParamsGetString(params, nparams, "fs.0.name", &name) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.0.mountpoint", &mountpoint) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.0.fstype", &fstype) < 0 ||
|
|
virTypedParamsGetULLong(params, nparams, "fs.0.used-bytes", &bytesused) == 1 ||
|
|
virTypedParamsGetULLong(params, nparams, "fs.0.total-bytes", &bytestotal) == 1 ||
|
|
virTypedParamsGetUInt(params, nparams, "fs.0.disk.count", &diskcount) < 0 ||
|
|
virTypedParamsGetString(params, nparams, "fs.0.disk.0.alias", &alias) == 1) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"Incorrect parameters for sdb1 (%s,%s)",
|
|
name, alias);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (STRNEQ(name, "sdb1") ||
|
|
STRNEQ(mountpoint, "/mnt/disk") ||
|
|
STRNEQ(fstype, "xfs") ||
|
|
diskcount != 0 ||
|
|
alias != NULL) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"unexpected filesystems information returned for sdb1 (%s,%s)",
|
|
name, alias);
|
|
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 (qemuAgentGetFSInfoParams(qemuMonitorTestGetAgent(test), ¶ms,
|
|
&nparams, &maxparams, def) != -2) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
"agent get-fsinfo command should have failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virTypedParamsFree(params, nparams);
|
|
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 ATTRIBUTE_UNUSED,
|
|
qemuMonitorTestItemPtr item ATTRIBUTE_UNUSED,
|
|
const char *cmdstr ATTRIBUTE_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;
|
|
|
|
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;
|
|
}
|
|
|
|
snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
|
|
"user.%zu.domain", nth);
|
|
virTypedParamsGetString(params, nparams, param_name, &domain);
|
|
if (STRNEQ_NULLABLE(expDomain, domain)) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"Expected domain '%s', got '%s'",
|
|
NULLSTR(expDomain), NULLSTR(domain));
|
|
return -1;
|
|
}
|
|
|
|
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),
|
|
¶ms, &nparams, &maxparams) < 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),
|
|
¶ms, &nparams, &maxparams) < 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),
|
|
¶ms, &nparams, &maxparams) < 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),
|
|
¶ms, &nparams, &maxparams) < 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), \
|
|
¶ms_, &nparams_, &maxparams_) < 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 !WITH_YAJL
|
|
fputs("libvirt not compiled with JSON support, skipping this test\n", stderr);
|
|
return EXIT_AM_SKIP;
|
|
#endif
|
|
|
|
if (virThreadInitialize() < 0 ||
|
|
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(GetFSInfoParams);
|
|
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)
|