2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* virsh-domain.c: Commands to manage domain
|
|
|
|
*
|
2016-01-09 13:36:24 +00:00
|
|
|
* Copyright (C) 2005, 2007-2016 Red Hat, Inc.
|
2012-07-25 15:37:18 +00:00
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-25 15:37:18 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2012-08-18 04:00:42 +00:00
|
|
|
#include <config.h>
|
|
|
|
#include "virsh-domain.h"
|
2017-04-10 15:06:15 +00:00
|
|
|
#include "virsh-util.h"
|
2012-08-18 04:00:42 +00:00
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
|
|
|
|
#include <libxml/parser.h>
|
|
|
|
#include <libxml/xpath.h>
|
|
|
|
|
|
|
|
#include "internal.h"
|
2012-12-04 11:56:32 +00:00
|
|
|
#include "virbitmap.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-08-18 04:00:42 +00:00
|
|
|
#include "conf/domain_conf.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-21 16:51:33 +00:00
|
|
|
#include "vircommand.h"
|
2012-08-18 04:00:42 +00:00
|
|
|
#include "virfile.h"
|
2012-12-21 14:26:27 +00:00
|
|
|
#include "virjson.h"
|
2012-08-18 04:00:42 +00:00
|
|
|
#include "virkeycode.h"
|
|
|
|
#include "virmacaddr.h"
|
2015-04-01 15:09:04 +00:00
|
|
|
#include "virnetdevbandwidth.h"
|
2012-12-21 16:51:33 +00:00
|
|
|
#include "virprocess.h"
|
2012-11-30 15:30:05 +00:00
|
|
|
#include "virstring.h"
|
2013-08-26 09:53:43 +00:00
|
|
|
#include "virsh-console.h"
|
2012-08-20 13:46:38 +00:00
|
|
|
#include "virsh-domain-monitor.h"
|
2021-06-15 00:38:24 +00:00
|
|
|
#include "virsh-host.h"
|
2015-07-13 15:04:49 +00:00
|
|
|
#include "virtime.h"
|
2012-08-18 04:00:42 +00:00
|
|
|
#include "virtypedparam.h"
|
2012-12-13 18:13:21 +00:00
|
|
|
#include "virxml.h"
|
2016-05-30 14:35:17 +00:00
|
|
|
#include "viruri.h"
|
2018-09-21 14:17:21 +00:00
|
|
|
#include "vsh-table.h"
|
2019-04-01 10:14:26 +00:00
|
|
|
#include "virenum.h"
|
2020-02-16 21:59:28 +00:00
|
|
|
#include "virutil.h"
|
2012-08-18 04:00:42 +00:00
|
|
|
|
2020-11-19 13:17:21 +00:00
|
|
|
enum virshAddressType {
|
|
|
|
VIRSH_ADDRESS_TYPE_PCI,
|
|
|
|
VIRSH_ADDRESS_TYPE_SCSI,
|
|
|
|
VIRSH_ADDRESS_TYPE_IDE,
|
|
|
|
VIRSH_ADDRESS_TYPE_CCW,
|
|
|
|
VIRSH_ADDRESS_TYPE_USB,
|
|
|
|
VIRSH_ADDRESS_TYPE_SATA,
|
|
|
|
|
|
|
|
VIRSH_ADDRESS_TYPE_LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
VIR_ENUM_DECL(virshAddress);
|
|
|
|
VIR_ENUM_IMPL(virshAddress,
|
|
|
|
VIRSH_ADDRESS_TYPE_LAST,
|
|
|
|
"pci",
|
|
|
|
"scsi",
|
|
|
|
"ide",
|
|
|
|
"ccw",
|
|
|
|
"usb",
|
|
|
|
"sata");
|
|
|
|
|
|
|
|
struct virshAddressPCI {
|
|
|
|
unsigned int domain;
|
|
|
|
unsigned int bus;
|
|
|
|
unsigned int slot;
|
|
|
|
unsigned int function;
|
|
|
|
bool multifunction;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct virshAddressDrive {
|
|
|
|
unsigned int controller;
|
|
|
|
unsigned int bus;
|
|
|
|
unsigned long long unit;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct virshAddressCCW {
|
|
|
|
unsigned int cssid;
|
|
|
|
unsigned int ssid;
|
|
|
|
unsigned int devno;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct virshAddressUSB {
|
|
|
|
unsigned int bus;
|
|
|
|
unsigned int port;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct virshAddress {
|
|
|
|
int type; /* enum virshAddressType */
|
|
|
|
union {
|
|
|
|
struct virshAddressPCI pci;
|
|
|
|
struct virshAddressDrive drive;
|
|
|
|
struct virshAddressCCW ccw;
|
|
|
|
struct virshAddressUSB usb;
|
|
|
|
} addr;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* pci address pci:0000.00.0x0a.0 (domain:bus:slot:function)
|
|
|
|
* ide disk address: ide:00.00.0 (controller:bus:unit)
|
|
|
|
* scsi disk address: scsi:00.00.0 (controller:bus:unit)
|
|
|
|
* ccw disk address: ccw:0xfe.0.0000 (cssid:ssid:devno)
|
|
|
|
* usb disk address: usb:00.00 (bus:port)
|
|
|
|
* sata disk address: sata:00.00.0 (controller:bus:unit)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virshAddressParse(const char *str,
|
|
|
|
bool multifunction,
|
|
|
|
struct virshAddress *addr)
|
|
|
|
{
|
|
|
|
g_autofree char *type = g_strdup(str);
|
|
|
|
char *a = strchr(type, ':');
|
|
|
|
|
2020-12-10 08:42:43 +00:00
|
|
|
if (!a)
|
2020-11-19 13:17:21 +00:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
*a = '\0';
|
|
|
|
|
|
|
|
addr->type = virshAddressTypeFromString(type);
|
|
|
|
|
|
|
|
switch ((enum virshAddressType) addr->type) {
|
|
|
|
case VIRSH_ADDRESS_TYPE_PCI:
|
|
|
|
addr->addr.pci.multifunction = multifunction;
|
|
|
|
|
|
|
|
if (virStrToLong_uip(++a, &a, 16, &addr->addr.pci.domain) < 0 ||
|
|
|
|
virStrToLong_uip(++a, &a, 16, &addr->addr.pci.bus) < 0 ||
|
|
|
|
virStrToLong_uip(++a, &a, 16, &addr->addr.pci.slot) < 0 ||
|
|
|
|
virStrToLong_uip(++a, &a, 16, &addr->addr.pci.function) < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ADDRESS_TYPE_SATA:
|
|
|
|
case VIRSH_ADDRESS_TYPE_IDE:
|
|
|
|
case VIRSH_ADDRESS_TYPE_SCSI:
|
|
|
|
if (virStrToLong_uip(++a, &a, 10, &addr->addr.drive.controller) < 0 ||
|
|
|
|
virStrToLong_uip(++a, &a, 10, &addr->addr.drive.bus) < 0 ||
|
|
|
|
virStrToLong_ullp(++a, &a, 10, &addr->addr.drive.unit) < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ADDRESS_TYPE_CCW:
|
|
|
|
if (virStrToLong_uip(++a, &a, 16, &addr->addr.ccw.cssid) < 0 ||
|
|
|
|
virStrToLong_uip(++a, &a, 16, &addr->addr.ccw.ssid) < 0 ||
|
|
|
|
virStrToLong_uip(++a, &a, 16, &addr->addr.ccw.devno) < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ADDRESS_TYPE_USB:
|
|
|
|
if (virStrToLong_uip(++a, &a, 10, &addr->addr.usb.bus) < 0 ||
|
|
|
|
virStrToLong_uip(++a, &a, 10, &addr->addr.usb.port) < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ADDRESS_TYPE_LAST:
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virshAddressFormat(virBuffer *buf,
|
2020-11-19 13:17:21 +00:00
|
|
|
struct virshAddress *addr)
|
|
|
|
{
|
|
|
|
switch ((enum virshAddressType) addr->type) {
|
|
|
|
case VIRSH_ADDRESS_TYPE_PCI:
|
|
|
|
virBufferAsprintf(buf,
|
|
|
|
"<address type='pci' domain='0x%04x' bus='0x%02x' slot='0x%02x' function='0x%0x'",
|
|
|
|
addr->addr.pci.domain,
|
|
|
|
addr->addr.pci.bus,
|
|
|
|
addr->addr.pci.slot,
|
|
|
|
addr->addr.pci.function);
|
|
|
|
|
|
|
|
if (addr->addr.pci.multifunction)
|
|
|
|
virBufferAddLit(buf, " multifunction='on'");
|
|
|
|
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ADDRESS_TYPE_SATA:
|
|
|
|
case VIRSH_ADDRESS_TYPE_IDE:
|
|
|
|
case VIRSH_ADDRESS_TYPE_SCSI:
|
|
|
|
virBufferAsprintf(buf,
|
|
|
|
"<address type='drive' controller='%u' bus='%u' unit='%llu'/>\n",
|
|
|
|
addr->addr.drive.controller,
|
|
|
|
addr->addr.drive.bus,
|
|
|
|
addr->addr.drive.unit);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ADDRESS_TYPE_CCW:
|
|
|
|
virBufferAsprintf(buf,
|
|
|
|
"<address type='ccw' cssid='0x%02x' ssid='0x%01x' devno='0x%04x'/>\n",
|
|
|
|
addr->addr.ccw.cssid,
|
|
|
|
addr->addr.ccw.ssid,
|
|
|
|
addr->addr.ccw.devno);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ADDRESS_TYPE_USB:
|
|
|
|
virBufferAsprintf(buf,
|
|
|
|
"<address type='usb' bus='%u' port='%u'/>\n",
|
|
|
|
addr->addr.usb.bus,
|
|
|
|
addr->addr.usb.port);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ADDRESS_TYPE_LAST:
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-27 16:22:04 +00:00
|
|
|
/**
|
|
|
|
* virshFetchPassFdsList
|
|
|
|
*
|
|
|
|
* Helper to process the 'pass-fds' argument.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
virshFetchPassFdsList(vshControl *ctl,
|
|
|
|
const vshCmd *cmd,
|
|
|
|
size_t *nfdsret,
|
|
|
|
int **fdsret)
|
|
|
|
{
|
|
|
|
const char *fdopt;
|
|
|
|
g_auto(GStrv) fdlist = NULL;
|
|
|
|
g_autofree int *fds = NULL;
|
|
|
|
size_t nfds = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
*nfdsret = 0;
|
|
|
|
*fdsret = NULL;
|
|
|
|
|
|
|
|
if (vshCommandOptStringQuiet(ctl, cmd, "pass-fds", &fdopt) <= 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(fdlist = g_strsplit(fdopt, ",", -1))) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unable to split FD list '%1$s'"), fdopt);
|
2022-01-27 16:22:04 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
nfds = g_strv_length(fdlist);
|
|
|
|
fds = g_new0(int, nfds);
|
|
|
|
|
|
|
|
for (i = 0; i < nfds; i++) {
|
|
|
|
if (virStrToLong_i(fdlist[i], NULL, 10, fds + i) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unable to parse FD number '%1$s'"), fdlist[i]);
|
2022-01-27 16:22:04 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*fdsret = g_steal_pointer(&fds);
|
|
|
|
*nfdsret = nfds;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define VIRSH_COMMON_OPT_DOMAIN_PERSISTENT \
|
|
|
|
{.name = "persistent", \
|
|
|
|
.type = VSH_OT_BOOL, \
|
|
|
|
.help = N_("make live change persistent") \
|
2017-10-31 10:47:36 +00:00
|
|
|
}
|
2016-01-09 13:36:25 +00:00
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define VIRSH_COMMON_OPT_DOMAIN_CONFIG \
|
2017-10-31 10:47:36 +00:00
|
|
|
VIRSH_COMMON_OPT_CONFIG(N_("affect next boot"))
|
2016-01-09 13:36:26 +00:00
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define VIRSH_COMMON_OPT_DOMAIN_LIVE \
|
2017-10-31 10:47:36 +00:00
|
|
|
VIRSH_COMMON_OPT_LIVE(N_("affect running domain"))
|
2016-01-09 13:36:27 +00:00
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define VIRSH_COMMON_OPT_DOMAIN_CURRENT \
|
2017-10-31 10:47:36 +00:00
|
|
|
VIRSH_COMMON_OPT_CURRENT(N_("affect current domain"))
|
2016-01-09 13:36:28 +00:00
|
|
|
|
2014-08-26 12:16:01 +00:00
|
|
|
|
2015-01-08 15:26:50 +00:00
|
|
|
static virDomainPtr
|
2015-06-15 16:53:58 +00:00
|
|
|
virshDomainDefine(virConnectPtr conn, const char *xml, unsigned int flags)
|
2015-01-08 15:26:50 +00:00
|
|
|
{
|
|
|
|
virDomainPtr dom;
|
2021-09-24 15:17:44 +00:00
|
|
|
|
|
|
|
if (!flags)
|
|
|
|
return virDomainDefineXML(conn, xml);
|
|
|
|
|
|
|
|
dom = virDomainDefineXMLFlags(conn, xml, flags);
|
|
|
|
/* If validate is the only flag, just drop it and
|
|
|
|
* try again.
|
|
|
|
*/
|
|
|
|
if (!dom) {
|
|
|
|
if ((virGetLastErrorCode() == VIR_ERR_NO_SUPPORT) &&
|
|
|
|
(flags == VIR_DOMAIN_DEFINE_VALIDATE))
|
|
|
|
dom = virDomainDefineXML(conn, xml);
|
2015-01-08 15:26:50 +00:00
|
|
|
}
|
|
|
|
return dom;
|
|
|
|
}
|
|
|
|
|
2019-01-20 16:04:56 +00:00
|
|
|
VIR_ENUM_DECL(virshDomainVcpuState);
|
2015-06-15 16:53:58 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainVcpuState,
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
VIR_VCPU_LAST,
|
|
|
|
N_("offline"),
|
|
|
|
N_("running"),
|
2019-01-20 16:30:15 +00:00
|
|
|
N_("blocked"));
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static const char *
|
2015-06-15 16:53:58 +00:00
|
|
|
virshDomainVcpuStateToString(int state)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2015-06-15 16:53:58 +00:00
|
|
|
const char *str = virshDomainVcpuStateTypeToString(state);
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
return str ? _(str) : _("no state");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2012-11-13 12:54:39 +00:00
|
|
|
/*
|
|
|
|
* Determine number of CPU nodes present by trying
|
|
|
|
* virNodeGetCPUMap and falling back to virNodeGetInfo
|
|
|
|
* if needed.
|
|
|
|
*/
|
|
|
|
static int
|
2015-06-15 16:53:58 +00:00
|
|
|
virshNodeGetCPUCount(virConnectPtr conn)
|
2012-11-13 12:54:39 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
virNodeInfo nodeinfo;
|
|
|
|
|
|
|
|
if ((ret = virNodeGetCPUMap(conn, NULL, NULL, 0)) < 0) {
|
|
|
|
/* fall back to nodeinfo */
|
|
|
|
vshResetLibvirtError();
|
2014-11-13 14:20:51 +00:00
|
|
|
if (virNodeGetInfo(conn, &nodeinfo) == 0)
|
2012-11-13 12:54:39 +00:00
|
|
|
ret = VIR_NODEINFO_MAXCPUS(nodeinfo);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "attach-device" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_attach_device[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("attach device from an XML file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Attach device from an XML <file>.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_attach_device[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2016-01-09 13:36:29 +00:00
|
|
|
VIRSH_COMMON_OPT_FILE(N_("XML file")),
|
2016-01-09 13:36:25 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_PERSISTENT,
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdAttachDevice(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *from = NULL;
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char *buffer = NULL;
|
2013-01-21 14:39:18 +00:00
|
|
|
int rv;
|
2013-05-28 09:07:33 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool persistent = vshCommandOptBool(cmd, "persistent");
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(persistent, current);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config || persistent)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-05-28 09:07:33 +00:00
|
|
|
if (persistent &&
|
|
|
|
virDomainIsActive(dom) == 1)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
|
|
|
|
vshReportError(ctl);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2014-01-07 15:44:02 +00:00
|
|
|
if (flags || current)
|
2013-01-21 14:39:18 +00:00
|
|
|
rv = virDomainAttachDeviceFlags(dom, buffer, flags);
|
2013-05-28 09:07:33 +00:00
|
|
|
else
|
2013-01-21 14:39:18 +00:00
|
|
|
rv = virDomainAttachDevice(dom, buffer);
|
2013-05-28 09:07:33 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (rv < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to attach device from %1$s"), from);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Device attached successfully\n"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "attach-disk" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_attach_disk[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("attach disk device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Attach new disk device.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_attach_disk[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "source",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ | VSH_OFLAG_EMPTY_OK,
|
2020-11-18 23:48:13 +00:00
|
|
|
.help = N_("source of disk device or name of network disk")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "target",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("target of disk device")
|
|
|
|
},
|
2014-07-01 10:02:03 +00:00
|
|
|
{.name = "targetbus",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("target bus of disk device")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "driver",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("driver of disk device")
|
|
|
|
},
|
|
|
|
{.name = "subdriver",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("subdriver of disk device")
|
|
|
|
},
|
2014-09-02 15:20:41 +00:00
|
|
|
{.name = "iothread",
|
|
|
|
.type = VSH_OT_STRING,
|
2020-09-11 07:13:10 +00:00
|
|
|
.completer = virshDomainIOThreadIdCompleter,
|
2014-09-02 15:20:41 +00:00
|
|
|
.help = N_("IOThread to be used by supported device")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "cache",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("cache mode of disk device")
|
|
|
|
},
|
2017-05-12 21:27:27 +00:00
|
|
|
{.name = "io",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("io policy of disk device")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "type",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("target device type")
|
|
|
|
},
|
2013-10-24 07:15:56 +00:00
|
|
|
{.name = "shareable",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "mode=shareable"
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "mode",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("mode of device reading and writing")
|
|
|
|
},
|
|
|
|
{.name = "sourcetype",
|
|
|
|
.type = VSH_OT_STRING,
|
2020-11-18 23:48:13 +00:00
|
|
|
.help = N_("type of source (block|file|network)")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "serial",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("serial of disk device")
|
|
|
|
},
|
2013-06-04 03:27:04 +00:00
|
|
|
{.name = "wwn",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-06-04 03:27:04 +00:00
|
|
|
.help = N_("wwn of disk device")
|
|
|
|
},
|
2018-07-15 10:08:16 +00:00
|
|
|
{.name = "alias",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2018-07-15 10:08:16 +00:00
|
|
|
.help = N_("custom alias name of disk device")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "rawio",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("needs rawio capability")
|
|
|
|
},
|
|
|
|
{.name = "address",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("address of disk device")
|
|
|
|
},
|
|
|
|
{.name = "multifunction",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("use multifunction pci under specified address")
|
|
|
|
},
|
2013-01-25 12:21:23 +00:00
|
|
|
{.name = "print-xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print XML document rather than attach the disk")
|
|
|
|
},
|
2020-11-18 23:48:13 +00:00
|
|
|
{.name = "source-protocol",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("protocol used by disk device source")
|
|
|
|
},
|
|
|
|
{.name = "source-host-name",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2020-11-18 23:48:13 +00:00
|
|
|
.help = N_("host name for source of disk device")
|
|
|
|
},
|
|
|
|
{.name = "source-host-transport",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("host transport for source of disk device")
|
|
|
|
},
|
|
|
|
{.name = "source-host-socket",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.help = N_("host socket for source of disk device")
|
|
|
|
},
|
2016-01-09 13:36:25 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_PERSISTENT,
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2020-11-19 11:07:32 +00:00
|
|
|
|
2020-11-19 10:45:11 +00:00
|
|
|
static int
|
|
|
|
cmdAttachDiskFormatAddress(vshControl *ctl,
|
2021-03-11 07:16:13 +00:00
|
|
|
virBuffer *buf,
|
2020-11-19 10:45:11 +00:00
|
|
|
const char *straddr,
|
|
|
|
const char *target,
|
|
|
|
bool multifunction)
|
|
|
|
{
|
2020-11-19 13:09:33 +00:00
|
|
|
struct virshAddress diskAddr;
|
2020-11-19 10:45:11 +00:00
|
|
|
|
2020-11-19 11:33:48 +00:00
|
|
|
if (virshAddressParse(straddr, multifunction, &diskAddr) < 0) {
|
2020-11-19 10:45:11 +00:00
|
|
|
vshError(ctl, _("Invalid address."));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STRPREFIX((const char *)target, "vd")) {
|
2020-11-19 13:09:33 +00:00
|
|
|
if (diskAddr.type != VIRSH_ADDRESS_TYPE_PCI &&
|
|
|
|
diskAddr.type != VIRSH_ADDRESS_TYPE_CCW) {
|
2020-11-19 10:45:11 +00:00
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("expecting a pci:0000.00.00.00 or ccw:00.0.0000 address."));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (STRPREFIX((const char *)target, "sd")) {
|
2020-11-19 13:09:33 +00:00
|
|
|
if (diskAddr.type != VIRSH_ADDRESS_TYPE_SCSI &&
|
|
|
|
diskAddr.type != VIRSH_ADDRESS_TYPE_USB &&
|
|
|
|
diskAddr.type != VIRSH_ADDRESS_TYPE_SATA) {
|
2020-11-19 10:45:11 +00:00
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("expecting a scsi:00.00.00 or usb:00.00 or sata:00.00.00 address."));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (STRPREFIX((const char *)target, "hd")) {
|
2020-11-19 13:09:33 +00:00
|
|
|
if (diskAddr.type != VIRSH_ADDRESS_TYPE_IDE) {
|
2020-11-19 10:45:11 +00:00
|
|
|
vshError(ctl, "%s", _("expecting an ide:00.00.00 address."));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-19 11:07:32 +00:00
|
|
|
virshAddressFormat(buf, &diskAddr);
|
2020-11-19 10:45:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-19 11:55:00 +00:00
|
|
|
enum virshAttachDiskSourceType {
|
|
|
|
VIRSH_ATTACH_DISK_SOURCE_TYPE_NONE,
|
|
|
|
VIRSH_ATTACH_DISK_SOURCE_TYPE_FILE,
|
|
|
|
VIRSH_ATTACH_DISK_SOURCE_TYPE_BLOCK,
|
2020-11-18 23:48:13 +00:00
|
|
|
VIRSH_ATTACH_DISK_SOURCE_TYPE_NETWORK,
|
2020-11-19 11:55:00 +00:00
|
|
|
|
|
|
|
VIRSH_ATTACH_DISK_SOURCE_TYPE_LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
VIR_ENUM_DECL(virshAttachDiskSource);
|
|
|
|
VIR_ENUM_IMPL(virshAttachDiskSource,
|
|
|
|
VIRSH_ATTACH_DISK_SOURCE_TYPE_LAST,
|
|
|
|
"",
|
|
|
|
"file",
|
2020-11-18 23:48:13 +00:00
|
|
|
"block",
|
|
|
|
"network");
|
2020-11-19 11:55:00 +00:00
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdAttachDisk(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2020-11-19 09:39:45 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2020-11-19 09:38:10 +00:00
|
|
|
const char *source = NULL;
|
|
|
|
const char *target = NULL;
|
|
|
|
const char *driver = NULL;
|
|
|
|
const char *subdriver = NULL;
|
2020-11-19 11:55:00 +00:00
|
|
|
const char *device = NULL;
|
2020-11-19 09:38:10 +00:00
|
|
|
const char *mode = NULL;
|
|
|
|
const char *iothread = NULL;
|
|
|
|
const char *cache = NULL;
|
|
|
|
const char *io = NULL;
|
|
|
|
const char *serial = NULL;
|
|
|
|
const char *straddr = NULL;
|
|
|
|
const char *wwn = NULL;
|
|
|
|
const char *targetbus = NULL;
|
|
|
|
const char *alias = NULL;
|
2020-11-18 23:48:13 +00:00
|
|
|
const char *source_protocol = NULL;
|
|
|
|
const char *host_name = NULL;
|
|
|
|
const char *host_transport = NULL;
|
|
|
|
const char *host_socket = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
int ret;
|
2013-05-28 09:07:33 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *stype = NULL;
|
2020-11-19 11:55:00 +00:00
|
|
|
int type = VIR_STORAGE_TYPE_NONE;
|
2020-07-02 23:40:16 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2020-11-19 12:05:05 +00:00
|
|
|
g_auto(virBuffer) diskAttrBuf = VIR_BUFFER_INITIALIZER;
|
|
|
|
g_auto(virBuffer) diskChildBuf = VIR_BUFFER_INIT_CHILD(&buf);
|
|
|
|
g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER;
|
|
|
|
g_auto(virBuffer) sourceAttrBuf = VIR_BUFFER_INITIALIZER;
|
2020-11-18 23:48:13 +00:00
|
|
|
g_auto(virBuffer) sourceChildBuf = VIR_BUFFER_INIT_CHILD(&diskChildBuf);
|
|
|
|
g_auto(virBuffer) hostAttrBuf = VIR_BUFFER_INITIALIZER;
|
2020-11-19 09:39:45 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
struct stat st;
|
2013-05-28 09:07:33 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool persistent = vshCommandOptBool(cmd, "persistent");
|
2020-11-19 10:45:11 +00:00
|
|
|
bool multifunction = vshCommandOptBool(cmd, "multifunction");
|
2013-05-28 09:07:33 +00:00
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(persistent, current);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
2020-11-18 23:48:13 +00:00
|
|
|
VSH_REQUIRE_OPTION("source-host-name", "source-protocol");
|
|
|
|
VSH_REQUIRE_OPTION("source-host-transport", "source-protocol");
|
|
|
|
VSH_REQUIRE_OPTION("source-host-socket", "source-protocol");
|
|
|
|
VSH_REQUIRE_OPTION("source-host-socket", "source-host-transport");
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("source-host-name", "source-host-socket");
|
|
|
|
|
2013-05-28 09:07:33 +00:00
|
|
|
if (config || persistent)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "source", &source) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "target", &target) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "driver", &driver) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "subdriver", &subdriver) < 0 ||
|
2020-11-19 11:55:00 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "type", &device) < 0 ||
|
2013-01-21 14:39:18 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "mode", &mode) < 0 ||
|
2014-09-02 15:20:41 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "iothread", &iothread) < 0 ||
|
2013-01-21 14:39:18 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "cache", &cache) < 0 ||
|
2017-05-12 21:27:27 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "io", &io) < 0 ||
|
2013-01-21 14:39:18 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "serial", &serial) < 0 ||
|
2013-06-04 03:27:04 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "wwn", &wwn) < 0 ||
|
2013-01-21 14:39:18 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "address", &straddr) < 0 ||
|
2014-07-01 10:02:03 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "targetbus", &targetbus) < 0 ||
|
2018-07-15 10:08:16 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "alias", &alias) < 0 ||
|
2020-11-18 23:48:13 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "sourcetype", &stype) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "source-protocol", &source_protocol) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "source-host-name", &host_name) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "source-host-transport", &host_transport) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "source-host-socket", &host_socket) < 0)
|
2020-11-19 09:44:12 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-11-19 11:55:00 +00:00
|
|
|
if (stype &&
|
|
|
|
(type = virshAttachDiskSourceTypeFromString(stype)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unknown source type: '%1$s'"), stype);
|
2020-11-19 11:55:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type == VIRSH_ATTACH_DISK_SOURCE_TYPE_NONE) {
|
2020-11-18 23:48:13 +00:00
|
|
|
if (source_protocol) {
|
|
|
|
type = VIRSH_ATTACH_DISK_SOURCE_TYPE_NETWORK;
|
|
|
|
} else if (STRNEQ_NULLABLE(driver, "file") &&
|
|
|
|
STRNEQ_NULLABLE(driver, "tap") &&
|
|
|
|
source &&
|
|
|
|
stat(source, &st) == 0 &&
|
|
|
|
S_ISBLK(st.st_mode)) {
|
2020-11-19 11:55:00 +00:00
|
|
|
type = VIRSH_ATTACH_DISK_SOURCE_TYPE_BLOCK;
|
|
|
|
} else {
|
|
|
|
type = VIRSH_ATTACH_DISK_SOURCE_TYPE_FILE;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2020-11-18 23:48:13 +00:00
|
|
|
if ((type == VIRSH_ATTACH_DISK_SOURCE_TYPE_NETWORK) != !!source_protocol) {
|
|
|
|
vshError(ctl, _("--source-protocol option requires --sourcetype network"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-09-24 15:17:45 +00:00
|
|
|
if (mode && STRNEQ(mode, "readonly") && STRNEQ(mode, "shareable")) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("No support for %1$s in command 'attach-disk'"), mode);
|
2021-09-24 15:17:45 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2013-06-04 03:27:04 +00:00
|
|
|
if (wwn && !virValidateWWN(wwn))
|
2020-11-19 09:44:12 +00:00
|
|
|
return false;
|
2013-06-04 03:27:04 +00:00
|
|
|
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferAsprintf(&diskAttrBuf, " type='%s'", virshAttachDiskSourceTypeToString(type));
|
|
|
|
virBufferEscapeString(&diskAttrBuf, " device='%s'", device);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (vshCommandOptBool(cmd, "rawio"))
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferAddLit(&diskAttrBuf, " rawio='yes'");
|
|
|
|
|
|
|
|
virBufferEscapeString(&driverAttrBuf, " name='%s'", driver);
|
|
|
|
virBufferEscapeString(&driverAttrBuf, " type='%s'", subdriver);
|
|
|
|
virBufferEscapeString(&driverAttrBuf, " iothread='%s'", iothread);
|
|
|
|
virBufferEscapeString(&driverAttrBuf, " cache='%s'", cache);
|
|
|
|
virBufferEscapeString(&driverAttrBuf, " io='%s'", io);
|
|
|
|
|
|
|
|
virXMLFormatElement(&diskChildBuf, "driver", &driverAttrBuf, NULL);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-11-19 11:55:00 +00:00
|
|
|
switch ((enum virshAttachDiskSourceType) type) {
|
|
|
|
case VIRSH_ATTACH_DISK_SOURCE_TYPE_FILE:
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferEscapeString(&sourceAttrBuf, " file='%s'", source);
|
2020-11-19 11:55:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_ATTACH_DISK_SOURCE_TYPE_BLOCK:
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferEscapeString(&sourceAttrBuf, " dev='%s'", source);
|
2020-11-19 11:55:00 +00:00
|
|
|
break;
|
|
|
|
|
2020-11-18 23:48:13 +00:00
|
|
|
case VIRSH_ATTACH_DISK_SOURCE_TYPE_NETWORK:
|
|
|
|
virBufferEscapeString(&sourceAttrBuf, " protocol='%s'", source_protocol);
|
|
|
|
virBufferEscapeString(&sourceAttrBuf, " name='%s'", source);
|
|
|
|
|
|
|
|
virBufferEscapeString(&hostAttrBuf, " transport='%s'", host_transport);
|
|
|
|
virBufferEscapeString(&hostAttrBuf, " socket='%s'", host_socket);
|
|
|
|
|
|
|
|
if (host_name) {
|
|
|
|
g_autofree char *host_name_copy = g_strdup(host_name);
|
|
|
|
char *host_port = strchr(host_name_copy, ':');
|
|
|
|
|
|
|
|
if (host_port) {
|
|
|
|
*host_port = '\0';
|
|
|
|
host_port++;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferEscapeString(&hostAttrBuf, " name='%s'", host_name_copy);
|
|
|
|
virBufferEscapeString(&hostAttrBuf, " port='%s'", host_port);
|
|
|
|
}
|
|
|
|
virXMLFormatElement(&sourceChildBuf, "host", &hostAttrBuf, NULL);
|
|
|
|
break;
|
|
|
|
|
2020-11-19 11:55:00 +00:00
|
|
|
case VIRSH_ATTACH_DISK_SOURCE_TYPE_NONE:
|
|
|
|
case VIRSH_ATTACH_DISK_SOURCE_TYPE_LAST:
|
|
|
|
break;
|
|
|
|
}
|
2020-11-18 23:48:13 +00:00
|
|
|
virXMLFormatElement(&diskChildBuf, "source", &sourceAttrBuf, &sourceChildBuf);
|
2020-11-19 11:55:00 +00:00
|
|
|
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferAsprintf(&diskChildBuf, "<target dev='%s'", target);
|
2014-07-01 10:02:03 +00:00
|
|
|
if (targetbus)
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferAsprintf(&diskChildBuf, " bus='%s'", targetbus);
|
|
|
|
virBufferAddLit(&diskChildBuf, "/>\n");
|
2014-07-01 10:02:03 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (mode)
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferAsprintf(&diskChildBuf, "<%s/>\n", mode);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (serial)
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferAsprintf(&diskChildBuf, "<serial>%s</serial>\n", serial);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2018-07-15 10:08:16 +00:00
|
|
|
if (alias)
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferAsprintf(&diskChildBuf, "<alias name='%s'/>\n", alias);
|
2018-07-15 10:08:16 +00:00
|
|
|
|
2013-06-04 03:27:04 +00:00
|
|
|
if (wwn)
|
2020-11-19 12:05:05 +00:00
|
|
|
virBufferAsprintf(&diskChildBuf, "<wwn>%s</wwn>\n", wwn);
|
2013-06-04 03:27:04 +00:00
|
|
|
|
2020-11-19 10:45:11 +00:00
|
|
|
if (straddr &&
|
2020-11-19 12:05:05 +00:00
|
|
|
cmdAttachDiskFormatAddress(ctl, &diskChildBuf, straddr, target, multifunction) < 0)
|
2020-11-19 10:45:11 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-11-19 12:05:05 +00:00
|
|
|
virXMLFormatElement(&buf, "disk", &diskAttrBuf, &diskChildBuf);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
xml = virBufferContentAndReset(&buf);
|
|
|
|
|
2013-01-25 12:21:23 +00:00
|
|
|
if (vshCommandOptBool(cmd, "print-xml")) {
|
|
|
|
vshPrint(ctl, "%s", xml);
|
2020-11-19 09:44:12 +00:00
|
|
|
return true;
|
2013-01-25 12:21:23 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2020-11-19 09:44:12 +00:00
|
|
|
return false;
|
2013-10-17 04:05:21 +00:00
|
|
|
|
|
|
|
if (persistent &&
|
|
|
|
virDomainIsActive(dom) == 1)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2014-01-07 15:44:02 +00:00
|
|
|
if (flags || current)
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = virDomainAttachDeviceFlags(dom, xml, flags);
|
2013-05-28 09:07:33 +00:00
|
|
|
else
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = virDomainAttachDevice(dom, xml);
|
|
|
|
|
2020-11-19 09:44:12 +00:00
|
|
|
if (ret < 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, "%s", _("Failed to attach disk"));
|
2020-11-19 09:44:12 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2020-11-19 09:44:12 +00:00
|
|
|
|
|
|
|
vshPrintExtra(ctl, "%s", _("Disk attached successfully\n"));
|
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "attach-interface" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_attach_interface[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("attach network interface")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Attach new network interface.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_attach_interface[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "type",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("network interface type")
|
|
|
|
},
|
|
|
|
{.name = "source",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("source of network interface")
|
|
|
|
},
|
|
|
|
{.name = "target",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("target network name")
|
|
|
|
},
|
|
|
|
{.name = "mac",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("MAC address")
|
|
|
|
},
|
|
|
|
{.name = "script",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("script used to bridge network interface")
|
|
|
|
},
|
|
|
|
{.name = "model",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("model type")
|
|
|
|
},
|
2018-07-15 10:08:17 +00:00
|
|
|
{.name = "alias",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2018-07-15 10:08:17 +00:00
|
|
|
.help = N_("custom alias name of interface device")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "inbound",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("control domain's incoming traffics")
|
|
|
|
},
|
|
|
|
{.name = "outbound",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("control domain's outgoing traffics")
|
|
|
|
},
|
2016-01-09 13:36:25 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_PERSISTENT,
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2015-09-07 10:13:47 +00:00
|
|
|
{.name = "print-xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print XML document rather than attach the interface")
|
|
|
|
},
|
2015-10-21 10:59:41 +00:00
|
|
|
{.name = "managed",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("libvirt will automatically detach/attach the device from/to host")
|
|
|
|
},
|
2021-08-17 11:03:04 +00:00
|
|
|
{.name = "source-mode",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.completer = virshDomainInterfaceSourceModeCompleter,
|
|
|
|
.help = N_("mode attribute of <source/> element")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2021-08-17 11:03:04 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainInterfaceSourceMode,
|
|
|
|
VIRSH_DOMAIN_INTERFACE_SOURCE_MODE_LAST,
|
|
|
|
"server",
|
|
|
|
"client");
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* parse inbound and outbound which are in the format of
|
2015-08-12 05:31:33 +00:00
|
|
|
* 'average,peak,burst,floor', in which peak and burst are optional,
|
2012-07-25 15:37:18 +00:00
|
|
|
* thus 'average,,burst' and 'average,peak' are also legal. */
|
2015-08-12 05:31:33 +00:00
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define VIRSH_PARSE_RATE_FIELD(index, name) \
|
|
|
|
do { \
|
|
|
|
if (index < ntok && \
|
|
|
|
*tok[index] != '\0' && \
|
|
|
|
virStrToLong_ullp(tok[index], NULL, 10, &rate->name) < 0) { \
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("field '%1$s' is malformed"), #name); \
|
2021-03-23 07:35:42 +00:00
|
|
|
return -1; \
|
2017-11-03 12:09:47 +00:00
|
|
|
} \
|
2015-08-12 05:31:33 +00:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static int
|
2015-06-15 16:53:58 +00:00
|
|
|
virshParseRateStr(vshControl *ctl,
|
|
|
|
const char *rateStr,
|
2021-03-11 07:16:13 +00:00
|
|
|
virNetDevBandwidthRate *rate)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2021-03-23 07:35:42 +00:00
|
|
|
g_auto(GStrv) tok = NULL;
|
2015-08-12 05:31:33 +00:00
|
|
|
size_t ntok;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-03-23 08:10:18 +00:00
|
|
|
if (!(tok = g_strsplit(rateStr, ",", 0)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return -1;
|
|
|
|
|
2021-03-23 08:10:18 +00:00
|
|
|
if ((ntok = g_strv_length(tok)) > 4) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Rate string '%1$s' has too many fields"), rateStr);
|
2021-03-23 07:35:42 +00:00
|
|
|
return -1;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
VIRSH_PARSE_RATE_FIELD(0, average);
|
|
|
|
VIRSH_PARSE_RATE_FIELD(1, peak);
|
|
|
|
VIRSH_PARSE_RATE_FIELD(2, burst);
|
|
|
|
VIRSH_PARSE_RATE_FIELD(3, floor);
|
2015-08-12 05:31:33 +00:00
|
|
|
|
2021-03-23 07:35:42 +00:00
|
|
|
return 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
#undef VIRSH_PARSE_RATE_FIELD
|
2015-08-12 05:31:33 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdAttachInterface(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *mac = NULL, *target = NULL, *script = NULL,
|
2015-06-15 16:53:58 +00:00
|
|
|
*type = NULL, *source = NULL, *model = NULL,
|
2018-07-15 10:08:17 +00:00
|
|
|
*inboundStr = NULL, *outboundStr = NULL, *alias = NULL;
|
2021-08-17 11:03:04 +00:00
|
|
|
const char *sourceModeStr = NULL;
|
|
|
|
int sourceMode = -1;
|
2012-07-25 15:37:18 +00:00
|
|
|
virNetDevBandwidthRate inbound, outbound;
|
2015-02-09 14:53:54 +00:00
|
|
|
virDomainNetType typ;
|
2012-07-25 15:37:18 +00:00
|
|
|
int ret;
|
2020-07-02 23:40:16 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2013-05-28 09:07:33 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool persistent = vshCommandOptBool(cmd, "persistent");
|
2015-10-21 10:59:41 +00:00
|
|
|
bool managed = vshCommandOptBool(cmd, "managed");
|
2013-05-28 09:07:33 +00:00
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(persistent, current);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config || persistent)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "source", &source) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "target", &target) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "mac", &mac) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "script", &script) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "model", &model) < 0 ||
|
2018-07-15 10:08:17 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "alias", &alias) < 0 ||
|
2013-01-21 14:39:18 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "inbound", &inboundStr) < 0 ||
|
2021-08-17 11:03:04 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "outbound", &outboundStr) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "source-mode", &sourceModeStr) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* check interface type */
|
2015-02-09 15:04:58 +00:00
|
|
|
if ((int)(typ = virDomainNetTypeFromString(type)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("No support for %1$s in command 'attach-interface'"),
|
2012-07-25 15:37:18 +00:00
|
|
|
type);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-08-17 11:03:04 +00:00
|
|
|
if (sourceModeStr &&
|
|
|
|
(sourceMode = virshDomainInterfaceSourceModeTypeFromString(sourceModeStr)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid source mode: %1$s"), sourceModeStr);
|
2021-08-17 11:03:04 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (inboundStr) {
|
|
|
|
memset(&inbound, 0, sizeof(inbound));
|
2015-06-15 16:53:58 +00:00
|
|
|
if (virshParseRateStr(ctl, inboundStr, &inbound) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-08-01 07:48:04 +00:00
|
|
|
if (!inbound.average && !inbound.floor) {
|
|
|
|
vshError(ctl, _("either inbound average or floor is mandatory"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (outboundStr) {
|
|
|
|
memset(&outbound, 0, sizeof(outbound));
|
2015-06-15 16:53:58 +00:00
|
|
|
if (virshParseRateStr(ctl, outboundStr, &outbound) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
if (outbound.average == 0) {
|
|
|
|
vshError(ctl, _("outbound average is mandatory"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2015-08-01 07:48:04 +00:00
|
|
|
if (outbound.floor) {
|
|
|
|
vshError(ctl, _("outbound floor is unsupported yet"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-08-01 07:48:04 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Make XML of interface */
|
2015-10-21 10:59:41 +00:00
|
|
|
virBufferAsprintf(&buf, "<interface type='%s'", type);
|
|
|
|
|
|
|
|
if (managed)
|
|
|
|
virBufferAddLit(&buf, " managed='yes'>\n");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&buf, ">\n");
|
2014-03-12 23:52:07 +00:00
|
|
|
virBufferAdjustIndent(&buf, 2);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-02-09 15:04:58 +00:00
|
|
|
switch (typ) {
|
|
|
|
case VIR_DOMAIN_NET_TYPE_NETWORK:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_BRIDGE:
|
|
|
|
virBufferAsprintf(&buf, "<source %s='%s'/>\n",
|
|
|
|
virDomainNetTypeToString(typ), source);
|
|
|
|
break;
|
2015-02-09 15:17:51 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_DIRECT:
|
|
|
|
virBufferAsprintf(&buf, "<source dev='%s'/>\n", source);
|
|
|
|
break;
|
2015-10-21 10:59:41 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_HOSTDEV:
|
|
|
|
{
|
2020-11-19 11:33:48 +00:00
|
|
|
g_autofree char *pciaddrstr = g_strdup_printf("pci:%s", source);
|
2020-11-19 13:09:33 +00:00
|
|
|
struct virshAddress addr = { 0 };
|
2015-10-21 10:59:41 +00:00
|
|
|
|
2020-11-19 11:33:48 +00:00
|
|
|
if (virshAddressParse(pciaddrstr, false, &addr) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("cannot parse pci address '%1$s' for network interface"),
|
2020-11-19 11:33:48 +00:00
|
|
|
source);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-10-21 10:59:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<source>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
2020-11-19 11:33:48 +00:00
|
|
|
virshAddressFormat(&buf, &addr);
|
2015-10-21 10:59:41 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</source>\n");
|
|
|
|
break;
|
|
|
|
}
|
2015-02-09 15:04:58 +00:00
|
|
|
|
2021-08-17 11:03:04 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
|
|
|
|
if (sourceMode < 0) {
|
|
|
|
vshError(ctl, _("source-mode is mandatory"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
virBufferAsprintf(&buf, "<source type='unix' path='%s' mode='%s'/>\n",
|
|
|
|
source,
|
|
|
|
virshDomainInterfaceSourceModeTypeToString(sourceMode));
|
|
|
|
break;
|
|
|
|
|
2015-02-09 15:04:58 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_USER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_SERVER:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
|
|
|
case VIR_DOMAIN_NET_TYPE_MCAST:
|
2015-08-29 20:19:10 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_UDP:
|
2020-10-14 17:08:25 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_VDPA:
|
2015-02-09 15:04:58 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_INTERNAL:
|
2022-08-24 20:46:05 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_NULL:
|
2022-08-17 12:35:17 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_VDS:
|
2015-02-09 15:04:58 +00:00
|
|
|
case VIR_DOMAIN_NET_TYPE_LAST:
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("No support for %1$s in command 'attach-interface'"),
|
2015-02-09 15:04:58 +00:00
|
|
|
type);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-02-09 15:04:58 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (target != NULL)
|
2014-03-12 23:52:07 +00:00
|
|
|
virBufferAsprintf(&buf, "<target dev='%s'/>\n", target);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (mac != NULL)
|
2014-03-12 23:52:07 +00:00
|
|
|
virBufferAsprintf(&buf, "<mac address='%s'/>\n", mac);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (script != NULL)
|
2014-03-12 23:52:07 +00:00
|
|
|
virBufferAsprintf(&buf, "<script path='%s'/>\n", script);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (model != NULL)
|
2014-03-12 23:52:07 +00:00
|
|
|
virBufferAsprintf(&buf, "<model type='%s'/>\n", model);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2018-07-15 10:08:17 +00:00
|
|
|
if (alias != NULL)
|
|
|
|
virBufferAsprintf(&buf, "<alias name='%s'/>\n", alias);
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (inboundStr || outboundStr) {
|
2014-03-12 23:52:07 +00:00
|
|
|
virBufferAddLit(&buf, "<bandwidth>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
2015-08-12 08:38:12 +00:00
|
|
|
if (inboundStr && (inbound.average || inbound.floor)) {
|
|
|
|
virBufferAddLit(&buf, "<inbound");
|
|
|
|
if (inbound.average > 0)
|
|
|
|
virBufferAsprintf(&buf, " average='%llu'", inbound.average);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (inbound.peak > 0)
|
|
|
|
virBufferAsprintf(&buf, " peak='%llu'", inbound.peak);
|
|
|
|
if (inbound.burst > 0)
|
|
|
|
virBufferAsprintf(&buf, " burst='%llu'", inbound.burst);
|
2015-08-12 08:38:12 +00:00
|
|
|
if (inbound.floor > 0)
|
|
|
|
virBufferAsprintf(&buf, " floor='%llu'", inbound.floor);
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, "/>\n");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
if (outboundStr && outbound.average > 0) {
|
2014-03-12 23:52:07 +00:00
|
|
|
virBufferAsprintf(&buf, "<outbound average='%llu'", outbound.average);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (outbound.peak > 0)
|
|
|
|
virBufferAsprintf(&buf, " peak='%llu'", outbound.peak);
|
|
|
|
if (outbound.burst > 0)
|
|
|
|
virBufferAsprintf(&buf, " burst='%llu'", outbound.burst);
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(&buf, "/>\n");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2014-03-12 23:52:07 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</bandwidth>\n");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-09-07 10:13:47 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
2012-07-25 15:37:18 +00:00
|
|
|
virBufferAddLit(&buf, "</interface>\n");
|
|
|
|
|
|
|
|
xml = virBufferContentAndReset(&buf);
|
|
|
|
|
2015-09-07 10:13:47 +00:00
|
|
|
if (vshCommandOptBool(cmd, "print-xml")) {
|
|
|
|
vshPrint(ctl, "%s", xml);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2015-09-07 10:13:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-09-07 10:13:47 +00:00
|
|
|
|
|
|
|
if (persistent &&
|
|
|
|
virDomainIsActive(dom) == 1)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2014-01-07 15:44:02 +00:00
|
|
|
if (flags || current)
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = virDomainAttachDeviceFlags(dom, xml, flags);
|
2013-05-28 09:07:33 +00:00
|
|
|
else
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = virDomainAttachDevice(dom, xml);
|
|
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to attach interface"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Interface attached successfully\n"));
|
|
|
|
|
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "autostart" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_autostart[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("autostart a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Configure a domain to be automatically started at boot.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_autostart[] = {
|
2018-01-25 13:50:32 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_PERSISTENT),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "disable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("disable autostarting")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdAutostart(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
int autostart;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
autostart = !vshCommandOptBool(cmd, "disable");
|
|
|
|
|
|
|
|
if (virDomainSetAutostart(dom, autostart) < 0) {
|
|
|
|
if (autostart)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to mark domain '%1$s' as autostarted"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
else
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to unmark domain '%1$s' as autostarted"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (autostart)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' marked as autostarted\n"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
else
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' unmarked as autostarted\n"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "blkdeviotune" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_blkdeviotune[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Set or query a block device I/O tuning parameters.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Set or query disk I/O parameters such as block throttling.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_blkdeviotune[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-05-15 11:18:24 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("block device")
|
|
|
|
},
|
|
|
|
{.name = "total_bytes_sec",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "total-bytes-sec"
|
|
|
|
},
|
|
|
|
{.name = "total-bytes-sec",
|
|
|
|
.type = VSH_OT_INT,
|
2016-05-04 14:25:10 +00:00
|
|
|
.help = N_("total throughput limit, as scaled integer (default bytes)")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "read_bytes_sec",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "read-bytes-sec"
|
|
|
|
},
|
|
|
|
{.name = "read-bytes-sec",
|
|
|
|
.type = VSH_OT_INT,
|
2016-05-04 14:25:10 +00:00
|
|
|
.help = N_("read throughput limit, as scaled integer (default bytes)")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "write_bytes_sec",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "write-bytes-sec"
|
|
|
|
},
|
|
|
|
{.name = "write-bytes-sec",
|
|
|
|
.type = VSH_OT_INT,
|
2016-05-04 14:25:10 +00:00
|
|
|
.help = N_("write throughput limit, as scaled integer (default bytes)")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "total_iops_sec",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "total-iops-sec"
|
|
|
|
},
|
|
|
|
{.name = "total-iops-sec",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("total I/O operations limit per second")
|
|
|
|
},
|
|
|
|
{.name = "read_iops_sec",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "read-iops-sec"
|
|
|
|
},
|
|
|
|
{.name = "read-iops-sec",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("read I/O operations limit per second")
|
|
|
|
},
|
|
|
|
{.name = "write_iops_sec",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "write-iops-sec"
|
|
|
|
},
|
|
|
|
{.name = "write-iops-sec",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("write I/O operations limit per second")
|
|
|
|
},
|
2014-10-29 12:16:05 +00:00
|
|
|
{.name = "total_bytes_sec_max",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "total-bytes-sec-max"
|
|
|
|
},
|
|
|
|
{.name = "total-bytes-sec-max",
|
|
|
|
.type = VSH_OT_INT,
|
2016-05-04 14:25:10 +00:00
|
|
|
.help = N_("total max, as scaled integer (default bytes)")
|
2014-10-29 12:16:05 +00:00
|
|
|
},
|
|
|
|
{.name = "read_bytes_sec_max",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "read-bytes-sec-max"
|
|
|
|
},
|
|
|
|
{.name = "read-bytes-sec-max",
|
|
|
|
.type = VSH_OT_INT,
|
2016-05-04 14:25:10 +00:00
|
|
|
.help = N_("read max, as scaled integer (default bytes)")
|
2014-10-29 12:16:05 +00:00
|
|
|
},
|
|
|
|
{.name = "write_bytes_sec_max",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "write-bytes-sec-max"
|
|
|
|
},
|
|
|
|
{.name = "write-bytes-sec-max",
|
|
|
|
.type = VSH_OT_INT,
|
2016-05-04 14:25:10 +00:00
|
|
|
.help = N_("write max, as scaled integer (default bytes)")
|
2014-10-29 12:16:05 +00:00
|
|
|
},
|
|
|
|
{.name = "total_iops_sec_max",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "total-iops-sec-max"
|
|
|
|
},
|
|
|
|
{.name = "total-iops-sec-max",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("total I/O operations max")
|
|
|
|
},
|
|
|
|
{.name = "read_iops_sec_max",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "read-iops-sec-max"
|
|
|
|
},
|
|
|
|
{.name = "read-iops-sec-max",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("read I/O operations max")
|
|
|
|
},
|
|
|
|
{.name = "write_iops_sec_max",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "write-iops-sec-max"
|
|
|
|
},
|
|
|
|
{.name = "write-iops-sec-max",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("write I/O operations max")
|
|
|
|
},
|
|
|
|
{.name = "size_iops_sec",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "size-iops-sec"
|
|
|
|
},
|
|
|
|
{.name = "size-iops-sec",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("I/O size in bytes")
|
|
|
|
},
|
2016-10-02 12:42:31 +00:00
|
|
|
{.name = "group_name",
|
2017-01-25 08:38:09 +00:00
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "group-name"
|
|
|
|
},
|
|
|
|
{.name = "group-name",
|
2016-10-02 12:42:31 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2016-10-02 12:42:31 +00:00
|
|
|
.help = N_("group name to share I/O quota between multiple drives")
|
|
|
|
},
|
2016-10-02 12:24:31 +00:00
|
|
|
{.name = "total_bytes_sec_max_length",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "total-bytes-sec-max-length"
|
|
|
|
},
|
|
|
|
{.name = "total-bytes-sec-max-length",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("duration in seconds to allow total max bytes")
|
|
|
|
},
|
|
|
|
{.name = "read_bytes_sec_max_length",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "read-bytes-sec-max-length"
|
|
|
|
},
|
|
|
|
{.name = "read-bytes-sec-max-length",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("duration in seconds to allow read max bytes")
|
|
|
|
},
|
|
|
|
{.name = "write_bytes_sec_max_length",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "write-bytes-sec-max-length"
|
|
|
|
},
|
|
|
|
{.name = "write-bytes-sec-max-length",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("duration in seconds to allow write max bytes")
|
|
|
|
},
|
|
|
|
{.name = "total_iops_sec_max_length",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "total-iops-sec-max-length"
|
|
|
|
},
|
|
|
|
{.name = "total-iops-sec-max-length",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("duration in seconds to allow total I/O operations max")
|
|
|
|
},
|
|
|
|
{.name = "read_iops_sec_max_length",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "read-iops-sec-max-length"
|
|
|
|
},
|
|
|
|
{.name = "read-iops-sec-max-length",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("duration in seconds to allow read I/O operations max")
|
|
|
|
},
|
|
|
|
{.name = "write_iops_sec_max_length",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "write-iops-sec-max-length"
|
|
|
|
},
|
|
|
|
{.name = "write-iops-sec-max-length",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("duration in seconds to allow write I/O operations max")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdBlkdeviotune(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name, *disk;
|
2016-10-02 12:42:31 +00:00
|
|
|
const char *group_name = NULL;
|
2013-01-15 23:01:54 +00:00
|
|
|
unsigned long long value;
|
2012-07-25 15:37:18 +00:00
|
|
|
int nparams = 0;
|
2013-01-15 23:01:54 +00:00
|
|
|
int maxparams = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-07-25 15:37:18 +00:00
|
|
|
int rv = 0;
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool ret = false;
|
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &disk) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define VSH_ADD_IOTUNE_SCALED(PARAM, CONST) \
|
|
|
|
if ((rv = vshCommandOptScaledInt(ctl, cmd, #PARAM, &value, \
|
|
|
|
1, ULLONG_MAX)) < 0) { \
|
|
|
|
goto interror; \
|
|
|
|
} else if (rv > 0) { \
|
|
|
|
if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams, \
|
|
|
|
VIR_DOMAIN_BLOCK_IOTUNE_##CONST, \
|
|
|
|
value) < 0) \
|
|
|
|
goto save_error; \
|
2017-10-31 10:47:36 +00:00
|
|
|
}
|
2016-10-02 11:55:32 +00:00
|
|
|
|
|
|
|
VSH_ADD_IOTUNE_SCALED(total-bytes-sec, TOTAL_BYTES_SEC);
|
|
|
|
VSH_ADD_IOTUNE_SCALED(read-bytes-sec, READ_BYTES_SEC);
|
|
|
|
VSH_ADD_IOTUNE_SCALED(write-bytes-sec, WRITE_BYTES_SEC);
|
|
|
|
VSH_ADD_IOTUNE_SCALED(total-bytes-sec-max, TOTAL_BYTES_SEC_MAX);
|
|
|
|
VSH_ADD_IOTUNE_SCALED(read-bytes-sec-max, READ_BYTES_SEC_MAX);
|
|
|
|
VSH_ADD_IOTUNE_SCALED(write-bytes-sec-max, WRITE_BYTES_SEC_MAX);
|
|
|
|
#undef VSH_ADD_IOTUNE_SCALED
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define VSH_ADD_IOTUNE(PARAM, CONST) \
|
|
|
|
if ((rv = vshCommandOptULongLong(ctl, cmd, #PARAM, &value)) < 0) { \
|
|
|
|
goto interror; \
|
|
|
|
} else if (rv > 0) { \
|
|
|
|
if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams, \
|
|
|
|
VIR_DOMAIN_BLOCK_IOTUNE_##CONST, \
|
|
|
|
value) < 0) \
|
|
|
|
goto save_error; \
|
2017-10-31 10:47:36 +00:00
|
|
|
}
|
2016-10-02 11:55:32 +00:00
|
|
|
|
|
|
|
VSH_ADD_IOTUNE(total-iops-sec, TOTAL_IOPS_SEC);
|
|
|
|
VSH_ADD_IOTUNE(read-iops-sec, READ_IOPS_SEC);
|
|
|
|
VSH_ADD_IOTUNE(write-iops-sec, WRITE_IOPS_SEC);
|
|
|
|
VSH_ADD_IOTUNE(total-iops-sec-max, TOTAL_IOPS_SEC_MAX);
|
|
|
|
VSH_ADD_IOTUNE(read-iops-sec-max, READ_IOPS_SEC_MAX);
|
|
|
|
VSH_ADD_IOTUNE(write-iops-sec-max, WRITE_IOPS_SEC_MAX);
|
|
|
|
VSH_ADD_IOTUNE(size-iops-sec, SIZE_IOPS_SEC);
|
2016-10-02 12:24:31 +00:00
|
|
|
|
|
|
|
VSH_ADD_IOTUNE(total-bytes-sec-max-length, TOTAL_BYTES_SEC_MAX_LENGTH);
|
|
|
|
VSH_ADD_IOTUNE(read-bytes-sec-max-length, READ_BYTES_SEC_MAX_LENGTH);
|
|
|
|
VSH_ADD_IOTUNE(write-bytes-sec-max-length, WRITE_BYTES_SEC_MAX_LENGTH);
|
|
|
|
VSH_ADD_IOTUNE(total-iops-sec-max-length, TOTAL_IOPS_SEC_MAX_LENGTH);
|
|
|
|
VSH_ADD_IOTUNE(read-iops-sec-max-length, READ_IOPS_SEC_MAX_LENGTH);
|
|
|
|
VSH_ADD_IOTUNE(write-iops-sec-max-length, WRITE_IOPS_SEC_MAX_LENGTH);
|
2016-10-02 11:55:32 +00:00
|
|
|
#undef VSH_ADD_IOTUNE
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2017-01-25 08:38:09 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "group-name", &group_name) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to parse group-name parameter"));
|
2016-10-02 12:42:31 +00:00
|
|
|
goto cleanup;
|
2017-01-25 08:35:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (group_name) {
|
2016-10-02 12:42:31 +00:00
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME,
|
|
|
|
group_name) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (nparams == 0) {
|
|
|
|
if (virDomainGetBlockIoTune(dom, NULL, NULL, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Unable to get number of block I/O throttle parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nparams == 0) {
|
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-10-05 16:50:09 +00:00
|
|
|
params = g_new0(virTypedParameter, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (virDomainGetBlockIoTune(dom, disk, params, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Unable to get block I/O throttle parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
2012-07-25 15:37:18 +00:00
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virDomainSetBlockIoTune(dom, disk, params, nparams, flags) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-01-15 23:01:54 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
save_error:
|
2013-01-15 23:01:54 +00:00
|
|
|
vshSaveLibvirtError();
|
2014-03-25 06:53:59 +00:00
|
|
|
error:
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to change block I/O throttle"));
|
|
|
|
goto cleanup;
|
2013-01-15 23:01:54 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
interror:
|
2013-01-15 23:01:54 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to parse integer parameter"));
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "blkiotune" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_blkiotune[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Get or set blkio parameters")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get or set the current blkio parameters for a guest"
|
2012-07-25 15:37:18 +00:00
|
|
|
" domain.\n"
|
|
|
|
" To get the blkio parameters use following command: \n\n"
|
2013-02-07 15:25:10 +00:00
|
|
|
" virsh # blkiotune <domain>")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_blkiotune[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "weight",
|
|
|
|
.type = VSH_OT_INT,
|
2014-07-24 11:43:47 +00:00
|
|
|
.help = N_("IO Weight")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "device-weights",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("per-device IO Weights, in the form of /path/to/device,weight,...")
|
|
|
|
},
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
{.name = "device-read-iops-sec",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
.help = N_("per-device read I/O limit per second, in the form of /path/to/device,read_iops_sec,...")
|
|
|
|
},
|
|
|
|
{.name = "device-write-iops-sec",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
.help = N_("per-device write I/O limit per second, in the form of /path/to/device,write_iops_sec,...")
|
|
|
|
},
|
|
|
|
{.name = "device-read-bytes-sec",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
.help = N_("per-device bytes read per second, in the form of /path/to/device,read_bytes_sec,...")
|
|
|
|
},
|
|
|
|
{.name = "device-write-bytes-sec",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
.help = N_("per-device bytes wrote per second, in the form of /path/to/device,write_bytes_sec,...")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdBlkiotune(vshControl * ctl, const vshCmd * cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *device_weight = NULL;
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
const char *device_riops = NULL;
|
|
|
|
const char *device_wiops = NULL;
|
|
|
|
const char *device_rbps = NULL;
|
|
|
|
const char *device_wbps = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
int weight = 0;
|
|
|
|
int nparams = 0;
|
2013-01-15 23:03:07 +00:00
|
|
|
int maxparams = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
int rv = 0;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-01-15 23:03:07 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool ret = false;
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "weight", &weight)) < 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
2013-01-15 23:03:07 +00:00
|
|
|
} else if (rv > 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
if (weight <= 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid value of %1$d for I/O weight"), weight);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-01-15 23:03:07 +00:00
|
|
|
if (virTypedParamsAddUInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BLKIO_WEIGHT, weight) < 0)
|
|
|
|
goto save_error;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
rv = vshCommandOptStringQuiet(ctl, cmd, "device-weights", &device_weight);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (rv < 0) {
|
2013-01-15 23:03:07 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to parse string parameter"));
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
2013-01-15 23:03:07 +00:00
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
|
|
|
|
device_weight) < 0)
|
|
|
|
goto save_error;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
rv = vshCommandOptStringQuiet(ctl, cmd, "device-read-iops-sec", &device_riops);
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
if (rv < 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to parse string parameter"));
|
|
|
|
goto cleanup;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
|
|
|
|
device_riops) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
rv = vshCommandOptStringQuiet(ctl, cmd, "device-write-iops-sec", &device_wiops);
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
if (rv < 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to parse string parameter"));
|
|
|
|
goto cleanup;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
|
|
|
|
device_wiops) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
rv = vshCommandOptStringQuiet(ctl, cmd, "device-read-bytes-sec", &device_rbps);
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
if (rv < 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to parse string parameter"));
|
|
|
|
goto cleanup;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
|
|
|
|
device_rbps) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
rv = vshCommandOptStringQuiet(ctl, cmd, "device-write-bytes-sec", &device_wbps);
|
virsh: add setting throttle blkio cgroup option to blkiotune
With this patch, user can setup the throttle blkio cgorup
for domain through the virsh cmd, such as:
virsh blkiotune domain1 --device-read-bytes-sec /dev/sda1,1000000,/dev/sda2,2000000
--device-write-bytes-sec /dev/sda1,1000000 --device-read-iops-sec /dev/sda1,10000
--device-write-iops-sec /dev/sda1,10000,/dev/sda2,0
This patch also add manpage for these new options.
Signed-off-by: Guan Qiang <hzguanqiang@corp.netease.com>
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
2013-12-11 08:29:51 +00:00
|
|
|
if (rv < 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to parse string parameter"));
|
|
|
|
goto cleanup;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
|
|
|
|
device_wbps) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (nparams == 0) {
|
|
|
|
/* get the number of blkio parameters */
|
|
|
|
if (virDomainGetBlkioParameters(dom, NULL, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Unable to get number of blkio parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nparams == 0) {
|
|
|
|
/* nothing to output */
|
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now go get all the blkio parameters */
|
2020-10-05 16:50:09 +00:00
|
|
|
params = g_new0(virTypedParameter, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (virDomainGetBlkioParameters(dom, params, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to get blkio parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
2012-07-25 15:37:18 +00:00
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* set the blkio parameters */
|
2013-01-15 23:03:07 +00:00
|
|
|
if (virDomainSetBlkioParameters(dom, params, nparams, flags) < 0)
|
|
|
|
goto error;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-01-15 23:03:07 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
2013-01-15 23:03:07 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
save_error:
|
2013-01-15 23:03:07 +00:00
|
|
|
vshSaveLibvirtError();
|
2014-03-25 06:53:59 +00:00
|
|
|
error:
|
2013-01-15 23:03:07 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to change blkio parameters"));
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2015-06-15 16:53:58 +00:00
|
|
|
virshPrintJobProgress(const char *label, unsigned long long remaining,
|
|
|
|
unsigned long long total)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2023-04-26 11:28:33 +00:00
|
|
|
double progress = 100.00;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2023-04-26 11:28:32 +00:00
|
|
|
/* if remaining == 0 migration has completed */
|
|
|
|
if (remaining != 0) {
|
2023-04-26 11:28:33 +00:00
|
|
|
/* use double to avoid overflow */
|
|
|
|
progress = 100.00 - remaining * 100.00 / total;
|
|
|
|
if (progress >= 100.00) {
|
2012-07-25 15:37:18 +00:00
|
|
|
/* migration has not completed, do not print [100 %] */
|
2023-04-26 11:28:33 +00:00
|
|
|
progress = 99.99;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* see comments in vshError about why we must flush */
|
|
|
|
fflush(stdout);
|
2023-04-26 11:28:33 +00:00
|
|
|
/* avoid auto-round-off of double by keeping only 2 decimals */
|
|
|
|
fprintf(stderr, "\r%s: [%5.2f %%]", label, (int)(progress*100)/100.0);
|
2012-07-25 15:37:18 +00:00
|
|
|
fflush(stderr);
|
|
|
|
}
|
|
|
|
|
2014-10-28 18:38:04 +00:00
|
|
|
static volatile sig_atomic_t intCaught;
|
2012-08-18 04:00:42 +00:00
|
|
|
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2019-10-14 12:44:29 +00:00
|
|
|
static void virshCatchInt(int sig G_GNUC_UNUSED,
|
|
|
|
siginfo_t *siginfo G_GNUC_UNUSED,
|
|
|
|
void *context G_GNUC_UNUSED)
|
2012-08-18 04:00:42 +00:00
|
|
|
{
|
|
|
|
intCaught = 1;
|
|
|
|
}
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2012-08-18 04:00:42 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
typedef struct _virshBlockJobWaitData virshBlockJobWaitData;
|
|
|
|
struct _virshBlockJobWaitData {
|
2015-07-13 15:04:49 +00:00
|
|
|
vshControl *ctl;
|
|
|
|
virDomainPtr dom;
|
|
|
|
const char *dev;
|
|
|
|
const char *job_name;
|
|
|
|
|
|
|
|
bool verbose;
|
|
|
|
unsigned int timeout;
|
|
|
|
bool async_abort;
|
|
|
|
|
|
|
|
int cb_id;
|
|
|
|
int cb_id2;
|
|
|
|
int status;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
virsh: Fix msg: blockjob is aborted from another client
When a block{pull, copy, commit} is aborted via keyboard interrupt,
the job is properly canceled followed by proper error message.
However, when the job receives an abort from another client connected
to the same domain, the error message incorrectly indicates that
a blockjob has been finished successfully, though the abort request
took effect. This patch introduces a new blockjob abort handler, which
is registered when the client calls block{copy,commit,pull} routine,
providing its caller the status of the finished blockjob.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1135442
2014-11-20 11:52:57 +00:00
|
|
|
static void
|
2019-10-14 12:44:29 +00:00
|
|
|
virshBlockJobStatusHandler(virConnectPtr conn G_GNUC_UNUSED,
|
|
|
|
virDomainPtr dom G_GNUC_UNUSED,
|
2015-06-15 16:53:58 +00:00
|
|
|
const char *disk,
|
2019-10-14 12:44:29 +00:00
|
|
|
int type G_GNUC_UNUSED,
|
2015-06-15 16:53:58 +00:00
|
|
|
int status,
|
|
|
|
void *opaque)
|
virsh: Fix msg: blockjob is aborted from another client
When a block{pull, copy, commit} is aborted via keyboard interrupt,
the job is properly canceled followed by proper error message.
However, when the job receives an abort from another client connected
to the same domain, the error message incorrectly indicates that
a blockjob has been finished successfully, though the abort request
took effect. This patch introduces a new blockjob abort handler, which
is registered when the client calls block{copy,commit,pull} routine,
providing its caller the status of the finished blockjob.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1135442
2014-11-20 11:52:57 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virshBlockJobWaitData *data = opaque;
|
2015-07-13 15:04:49 +00:00
|
|
|
|
|
|
|
if (STREQ_NULLABLE(disk, data->dev))
|
|
|
|
data->status = status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-06-15 16:53:58 +00:00
|
|
|
* virshBlockJobWaitInit:
|
2015-07-13 15:04:49 +00:00
|
|
|
* @ctl: vsh control structure
|
|
|
|
* @dom: domain object
|
|
|
|
* @dev: block device name to wait for
|
|
|
|
* @job_name: block job name to display in user-facing messages
|
|
|
|
* @verbose: enable progress reporting
|
|
|
|
* @timeout: number of milliseconds to wait before aborting the job
|
|
|
|
* @async_abort: abort the job asynchronously
|
|
|
|
*
|
|
|
|
* Prepares virsh for waiting for completion of a block job. This function
|
|
|
|
* registers event handlers for block job events and prepares the data structures
|
2015-06-15 16:53:58 +00:00
|
|
|
* for them. A call to virshBlockJobWait then waits for completion of the given
|
2015-07-13 15:04:49 +00:00
|
|
|
* block job. This function should be tolerant to different versions of daemon
|
|
|
|
* and the reporting capabilities of those.
|
|
|
|
*
|
|
|
|
* Returns the data structure that holds data needed for block job waiting or
|
|
|
|
* NULL in case of error.
|
|
|
|
*/
|
2021-03-11 07:16:13 +00:00
|
|
|
static virshBlockJobWaitData *
|
2015-06-15 16:53:58 +00:00
|
|
|
virshBlockJobWaitInit(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
const char *dev,
|
|
|
|
const char *job_name,
|
|
|
|
bool verbose,
|
|
|
|
unsigned int timeout,
|
|
|
|
bool async_abort)
|
2015-07-13 15:04:49 +00:00
|
|
|
{
|
2020-07-28 17:50:28 +00:00
|
|
|
virConnectDomainEventGenericCallback cb;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshBlockJobWaitData *ret;
|
|
|
|
virshControl *priv = ctl->privData;
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2020-09-23 20:06:18 +00:00
|
|
|
ret = g_new0(virshBlockJobWaitData, 1);
|
2015-07-13 15:04:49 +00:00
|
|
|
|
|
|
|
ret->ctl = ctl;
|
|
|
|
ret->dom = dom;
|
|
|
|
ret->dev = dev;
|
|
|
|
ret->job_name = job_name;
|
|
|
|
|
|
|
|
ret->async_abort = async_abort;
|
|
|
|
ret->timeout = timeout;
|
|
|
|
ret->verbose = verbose;
|
|
|
|
|
|
|
|
ret->status = -1;
|
|
|
|
|
2020-07-28 17:50:28 +00:00
|
|
|
cb = VIR_DOMAIN_EVENT_CALLBACK(virshBlockJobStatusHandler);
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((ret->cb_id = virConnectDomainEventRegisterAny(priv->conn, dom,
|
2015-07-13 15:04:49 +00:00
|
|
|
VIR_DOMAIN_EVENT_ID_BLOCK_JOB,
|
|
|
|
cb, ret, NULL)) < 0)
|
|
|
|
vshResetLibvirtError();
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((ret->cb_id2 = virConnectDomainEventRegisterAny(priv->conn, dom,
|
2015-07-13 15:04:49 +00:00
|
|
|
VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2,
|
|
|
|
cb, ret, NULL)) < 0)
|
|
|
|
vshResetLibvirtError();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2021-03-11 07:16:13 +00:00
|
|
|
virshBlockJobWaitFree(virshBlockJobWaitData *data)
|
2015-07-13 15:04:49 +00:00
|
|
|
{
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = NULL;
|
2015-06-15 16:53:58 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
if (!data)
|
|
|
|
return;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
priv = data->ctl->privData;
|
2015-07-13 15:04:49 +00:00
|
|
|
if (data->cb_id >= 0)
|
2015-06-15 16:53:58 +00:00
|
|
|
virConnectDomainEventDeregisterAny(priv->conn, data->cb_id);
|
2015-07-13 15:04:49 +00:00
|
|
|
if (data->cb_id2 >= 0)
|
2015-06-15 16:53:58 +00:00
|
|
|
virConnectDomainEventDeregisterAny(priv->conn, data->cb_id2);
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2021-02-03 19:32:55 +00:00
|
|
|
g_free(data);
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2015-06-15 16:53:58 +00:00
|
|
|
* virshBlockJobWait:
|
|
|
|
* @data: private data initialized by virshBlockJobWaitInit
|
2015-07-13 15:04:49 +00:00
|
|
|
*
|
2016-01-27 02:24:54 +00:00
|
|
|
* Waits for the block job to complete. This function prefers to wait for a
|
|
|
|
* matching VIR_DOMAIN_EVENT_ID_BLOCK_JOB or VIR_DOMAIN_EVENT_ID_BLOCK_JOB_2
|
|
|
|
* event from libvirt; however, it has a fallback mode should either of these
|
|
|
|
* events not be available.
|
2015-07-13 15:04:49 +00:00
|
|
|
*
|
2016-01-27 02:24:54 +00:00
|
|
|
* This function returns values from the virConnectDomainEventBlockJobStatus
|
|
|
|
* enum or -1 in case of an internal error.
|
|
|
|
*
|
|
|
|
* If the fallback mode is activated the returned event is
|
|
|
|
* VIR_DOMAIN_BLOCK_JOB_COMPLETED if the block job vanishes or
|
|
|
|
* VIR_DOMAIN_BLOCK_JOB_READY if the block job reaches 100%.
|
2015-07-13 15:04:49 +00:00
|
|
|
*/
|
|
|
|
static int
|
2021-03-11 07:16:13 +00:00
|
|
|
virshBlockJobWait(virshBlockJobWaitData *data)
|
2015-07-13 15:04:49 +00:00
|
|
|
{
|
|
|
|
/* For two phase jobs like active commit or block copy, the marker reaches
|
|
|
|
* 100% and an event fires. In case where virsh would not be able to match
|
|
|
|
* the event to the given block job we will wait for the number of retries
|
|
|
|
* before claiming that we entered synchronised phase */
|
|
|
|
unsigned int retries = 5;
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2015-07-13 15:04:49 +00:00
|
|
|
struct sigaction sig_action;
|
|
|
|
struct sigaction old_sig_action;
|
|
|
|
sigset_t sigmask, oldsigmask;
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2015-07-13 15:04:49 +00:00
|
|
|
unsigned long long start = 0;
|
|
|
|
unsigned long long curr = 0;
|
|
|
|
|
|
|
|
unsigned int abort_flags = 0;
|
|
|
|
int ret = -1;
|
2016-01-27 02:24:51 +00:00
|
|
|
virDomainBlockJobInfo info, last;
|
2015-07-13 15:04:49 +00:00
|
|
|
int result;
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (data->async_abort)
|
|
|
|
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC;
|
|
|
|
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2015-07-13 15:04:49 +00:00
|
|
|
sigemptyset(&sigmask);
|
|
|
|
sigaddset(&sigmask, SIGINT);
|
|
|
|
|
|
|
|
intCaught = 0;
|
2015-06-15 16:53:58 +00:00
|
|
|
sig_action.sa_sigaction = virshCatchInt;
|
2015-07-13 15:04:49 +00:00
|
|
|
sig_action.sa_flags = SA_SIGINFO;
|
|
|
|
sigemptyset(&sig_action.sa_mask);
|
|
|
|
sigaction(SIGINT, &sig_action, &old_sig_action);
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2015-07-13 15:04:49 +00:00
|
|
|
|
|
|
|
if (data->timeout && virTimeMillisNow(&start) < 0) {
|
|
|
|
vshSaveLibvirtError();
|
2016-01-27 02:24:53 +00:00
|
|
|
goto cleanup;
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
|
|
|
|
2016-01-27 02:24:51 +00:00
|
|
|
last.cur = last.end = 0;
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
while (true) {
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2015-07-13 15:04:49 +00:00
|
|
|
pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask);
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2015-07-13 15:04:49 +00:00
|
|
|
result = virDomainGetBlockJobInfo(data->dom, data->dev, &info, 0);
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2015-07-13 15:04:49 +00:00
|
|
|
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2015-07-13 15:04:49 +00:00
|
|
|
|
|
|
|
if (result < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(data->ctl, _("failed to query job for disk %1$s"), data->dev);
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-01-27 02:24:54 +00:00
|
|
|
/* If either callback could be registered and we've got an event, we can
|
|
|
|
* can end the waiting loop */
|
2015-07-13 15:04:49 +00:00
|
|
|
if ((data->cb_id >= 0 || data->cb_id2 >= 0) && data->status != -1) {
|
|
|
|
ret = data->status;
|
2016-01-27 02:24:52 +00:00
|
|
|
break;
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
|
|
|
|
2016-01-27 02:24:54 +00:00
|
|
|
/* Fallback behaviour is only needed if one or both callbacks could not
|
|
|
|
* be registered */
|
|
|
|
if (data->cb_id < 0 || data->cb_id2 < 0) {
|
|
|
|
/* If the block job vanishes, synthesize a COMPLETED event */
|
|
|
|
if (result == 0) {
|
|
|
|
ret = VIR_DOMAIN_BLOCK_JOB_COMPLETED;
|
|
|
|
break;
|
|
|
|
}
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2016-01-27 02:24:54 +00:00
|
|
|
/* If the block job hits 100%, wait a little while for a possible
|
|
|
|
* event from libvirt unless both callbacks could not be registered
|
|
|
|
* in order to synthesize our own READY event */
|
|
|
|
if (info.end == info.cur &&
|
|
|
|
((data->cb_id < 0 && data->cb_id2 < 0) || --retries == 0)) {
|
|
|
|
ret = VIR_DOMAIN_BLOCK_JOB_READY;
|
|
|
|
break;
|
|
|
|
}
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
|
|
|
|
2016-01-27 02:24:51 +00:00
|
|
|
if (data->verbose && (info.cur != last.cur || info.end != last.end))
|
2015-06-15 16:53:58 +00:00
|
|
|
virshPrintJobProgress(data->job_name, info.end - info.cur,
|
|
|
|
info.end);
|
2016-01-27 02:24:51 +00:00
|
|
|
last = info;
|
2015-07-13 15:04:49 +00:00
|
|
|
|
|
|
|
if (data->timeout && virTimeMillisNow(&curr) < 0) {
|
|
|
|
vshSaveLibvirtError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (intCaught || (data->timeout && (curr - start > data->timeout))) {
|
|
|
|
if (virDomainBlockJobAbort(data->dom, data->dev, abort_flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(data->ctl, _("failed to abort job for disk '%1$s'"),
|
2015-07-13 15:04:49 +00:00
|
|
|
data->dev);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = VIR_DOMAIN_BLOCK_JOB_CANCELED;
|
2016-01-27 02:24:52 +00:00
|
|
|
break;
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
|
|
|
|
2019-10-02 17:01:11 +00:00
|
|
|
g_usleep(500 * 1000);
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* print 100% completed */
|
|
|
|
if (data->verbose &&
|
|
|
|
(ret == VIR_DOMAIN_BLOCK_JOB_COMPLETED ||
|
|
|
|
ret == VIR_DOMAIN_BLOCK_JOB_READY))
|
2015-06-15 16:53:58 +00:00
|
|
|
virshPrintJobProgress(data->job_name, 0, 1);
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2016-01-27 02:24:52 +00:00
|
|
|
cleanup:
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2015-07-13 15:04:49 +00:00
|
|
|
sigaction(SIGINT, &old_sig_action, NULL);
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2015-07-13 15:04:49 +00:00
|
|
|
return ret;
|
virsh: Fix msg: blockjob is aborted from another client
When a block{pull, copy, commit} is aborted via keyboard interrupt,
the job is properly canceled followed by proper error message.
However, when the job receives an abort from another client connected
to the same domain, the error message incorrectly indicates that
a blockjob has been finished successfully, though the abort request
took effect. This patch introduces a new blockjob abort handler, which
is registered when the client calls block{copy,commit,pull} routine,
providing its caller the status of the finished blockjob.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1135442
2014-11-20 11:52:57 +00:00
|
|
|
}
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2012-09-17 20:56:01 +00:00
|
|
|
/*
|
|
|
|
* "blockcommit" command
|
|
|
|
*/
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdInfo info_blockcommit[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Start a block commit operation.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Commit changes from a snapshot down to its backing image.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-09-17 20:56:01 +00:00
|
|
|
};
|
|
|
|
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdOptDef opts_blockcommit[] = {
|
2018-05-15 11:10:34 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "path",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-05-15 11:18:24 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("fully-qualified path of disk")
|
|
|
|
},
|
|
|
|
{.name = "bandwidth",
|
2014-11-06 08:01:00 +00:00
|
|
|
.type = VSH_OT_INT,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("bandwidth limit in MiB/s")
|
|
|
|
},
|
|
|
|
{.name = "base",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-16 15:49:50 +00:00
|
|
|
.completer = virshDomainBlockjobBaseTopCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("path of base file to commit into (default bottom of chain)")
|
|
|
|
},
|
|
|
|
{.name = "shallow",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("use backing file of top as base")
|
|
|
|
},
|
|
|
|
{.name = "top",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-16 15:49:50 +00:00
|
|
|
.completer = virshDomainBlockjobBaseTopCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("path of top file to commit from (default top of chain)")
|
|
|
|
},
|
2014-05-21 04:11:29 +00:00
|
|
|
{.name = "active",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("trigger two-stage active commit of top file")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "delete",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("delete files that were successfully committed")
|
|
|
|
},
|
|
|
|
{.name = "wait",
|
|
|
|
.type = VSH_OT_BOOL,
|
2014-05-21 04:11:29 +00:00
|
|
|
.help = N_("wait for job to complete "
|
|
|
|
"(with --active, wait for job to sync)")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "verbose",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("with --wait, display the progress")
|
|
|
|
},
|
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
2014-05-21 04:11:29 +00:00
|
|
|
.help = N_("implies --wait, abort if copy exceeds timeout (in seconds)")
|
|
|
|
},
|
|
|
|
{.name = "pivot",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("implies --active --wait, pivot when commit is synced")
|
|
|
|
},
|
|
|
|
{.name = "keep-overlay",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("implies --active --wait, quit when commit is synced")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
2013-09-19 13:08:29 +00:00
|
|
|
{.name = "async",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("with --wait, don't wait for cancel to finish")
|
|
|
|
},
|
2014-05-13 15:59:32 +00:00
|
|
|
{.name = "keep-relative",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("keep the backing chain relatively referenced")
|
|
|
|
},
|
2016-03-17 12:40:04 +00:00
|
|
|
{.name = "bytes",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("the bandwidth limit is in bytes/s rather than MiB/s")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-09-17 20:56:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2018-02-19 06:19:47 +00:00
|
|
|
cmdBlockcommit(vshControl *ctl, const vshCmd *cmd)
|
2012-09-17 20:56:01 +00:00
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-09-17 20:56:01 +00:00
|
|
|
bool ret = false;
|
|
|
|
bool verbose = vshCommandOptBool(cmd, "verbose");
|
2014-05-21 04:11:29 +00:00
|
|
|
bool pivot = vshCommandOptBool(cmd, "pivot");
|
|
|
|
bool finish = vshCommandOptBool(cmd, "keep-overlay");
|
|
|
|
bool active = vshCommandOptBool(cmd, "active") || pivot || finish;
|
2015-07-13 14:23:59 +00:00
|
|
|
bool blocking = vshCommandOptBool(cmd, "wait") || pivot || finish;
|
|
|
|
bool async = vshCommandOptBool(cmd, "async");
|
2016-03-17 12:40:04 +00:00
|
|
|
bool bytes = vshCommandOptBool(cmd, "bytes");
|
2012-09-17 20:56:01 +00:00
|
|
|
int timeout = 0;
|
|
|
|
const char *path = NULL;
|
2015-04-30 14:31:36 +00:00
|
|
|
const char *base = NULL;
|
|
|
|
const char *top = NULL;
|
2012-09-17 20:56:01 +00:00
|
|
|
int abort_flags = 0;
|
2015-04-30 14:31:36 +00:00
|
|
|
unsigned int flags = 0;
|
|
|
|
unsigned long bandwidth = 0;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshBlockJobWaitData *bjWait = NULL;
|
2015-04-30 14:31:36 +00:00
|
|
|
|
2015-07-13 14:23:59 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("pivot", "keep-overlay");
|
|
|
|
|
2015-04-30 14:31:36 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "base", &base) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "top", &top) < 0)
|
|
|
|
return false;
|
|
|
|
|
2016-03-17 12:40:04 +00:00
|
|
|
if (vshBlockJobOptionBandwidth(ctl, cmd, bytes, &bandwidth) < 0)
|
2015-04-30 14:31:36 +00:00
|
|
|
return false;
|
|
|
|
|
2016-03-17 12:40:04 +00:00
|
|
|
if (bytes)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES;
|
|
|
|
|
2015-04-30 14:31:36 +00:00
|
|
|
if (vshCommandOptBool(cmd, "shallow"))
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_COMMIT_SHALLOW;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "delete"))
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_COMMIT_DELETE;
|
|
|
|
|
|
|
|
if (active)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_COMMIT_ACTIVE;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "keep-relative"))
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_COMMIT_RELATIVE;
|
2012-09-17 20:56:01 +00:00
|
|
|
|
2015-07-13 14:23:59 +00:00
|
|
|
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (timeout)
|
|
|
|
blocking = true;
|
|
|
|
|
|
|
|
if (!blocking) {
|
|
|
|
if (verbose) {
|
|
|
|
vshError(ctl, "%s", _("--verbose requires at least one of --timeout, "
|
|
|
|
"--wait, --pivot, or --keep-overlay"));
|
2014-05-21 04:11:29 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-07-13 14:23:59 +00:00
|
|
|
|
|
|
|
if (async) {
|
|
|
|
vshError(ctl, "%s", _("--async requires at least one of --timeout, "
|
|
|
|
"--wait, --pivot, or --keep-overlay"));
|
2013-03-26 15:41:06 +00:00
|
|
|
return false;
|
2015-07-13 14:23:59 +00:00
|
|
|
}
|
|
|
|
}
|
2012-09-17 20:56:01 +00:00
|
|
|
|
2015-07-13 14:23:59 +00:00
|
|
|
if (async)
|
|
|
|
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2015-04-30 14:31:36 +00:00
|
|
|
return false;
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
if (blocking &&
|
2015-06-15 16:53:58 +00:00
|
|
|
!(bjWait = virshBlockJobWaitInit(ctl, dom, path, _("Block commit"),
|
|
|
|
verbose, timeout, async)))
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
virsh: Fix msg: blockjob is aborted from another client
When a block{pull, copy, commit} is aborted via keyboard interrupt,
the job is properly canceled followed by proper error message.
However, when the job receives an abort from another client connected
to the same domain, the error message incorrectly indicates that
a blockjob has been finished successfully, though the abort request
took effect. This patch introduces a new blockjob abort handler, which
is registered when the client calls block{copy,commit,pull} routine,
providing its caller the status of the finished blockjob.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1135442
2014-11-20 11:52:57 +00:00
|
|
|
|
2015-04-30 14:31:36 +00:00
|
|
|
if (virDomainBlockCommit(dom, path, base, top, bandwidth, flags) < 0)
|
2012-09-17 20:56:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!blocking) {
|
2015-07-13 15:04:49 +00:00
|
|
|
if (active)
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Active Block Commit started"));
|
2015-07-13 15:04:49 +00:00
|
|
|
else
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Block Commit started"));
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2012-09-17 20:56:01 +00:00
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
/* Execution continues here only if --wait or friends were specified */
|
2015-06-15 16:53:58 +00:00
|
|
|
switch (virshBlockJobWait(bjWait)) {
|
2015-07-13 15:04:49 +00:00
|
|
|
case -1:
|
|
|
|
goto cleanup;
|
2012-10-11 15:12:13 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_CANCELED:
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Commit aborted"));
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
2012-09-17 20:56:01 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_FAILED:
|
2020-06-17 12:08:22 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Commit failed"));
|
2012-09-17 20:56:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_READY:
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
|
2014-05-21 04:11:29 +00:00
|
|
|
break;
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
2012-09-17 20:56:01 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
if (active) {
|
|
|
|
if (pivot) {
|
|
|
|
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
|
2012-09-17 20:56:01 +00:00
|
|
|
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("failed to pivot job for disk %1$s"), path);
|
2012-09-17 20:56:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Successfully pivoted"));
|
2015-07-13 15:04:49 +00:00
|
|
|
} else if (finish) {
|
|
|
|
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("failed to finish job for disk %1$s"), path);
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
virsh: Fix msg: blockjob is aborted from another client
When a block{pull, copy, commit} is aborted via keyboard interrupt,
the job is properly canceled followed by proper error message.
However, when the job receives an abort from another client connected
to the same domain, the error message incorrectly indicates that
a blockjob has been finished successfully, though the abort request
took effect. This patch introduces a new blockjob abort handler, which
is registered when the client calls block{copy,commit,pull} routine,
providing its caller the status of the finished blockjob.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1135442
2014-11-20 11:52:57 +00:00
|
|
|
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Commit complete, overlay "
|
|
|
|
"image kept"));
|
2015-07-13 15:04:49 +00:00
|
|
|
} else {
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Now in synchronized phase"));
|
2014-05-21 04:11:29 +00:00
|
|
|
}
|
2015-07-13 15:04:49 +00:00
|
|
|
} else {
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Commit complete"));
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
2012-09-17 20:56:01 +00:00
|
|
|
|
|
|
|
ret = true;
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2015-06-15 16:53:58 +00:00
|
|
|
virshBlockJobWaitFree(bjWait);
|
2012-09-17 20:56:01 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "blockcopy" command
|
|
|
|
*/
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdInfo info_blockcopy[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Start a block copy operation.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
2013-03-26 16:46:28 +00:00
|
|
|
.data = N_("Copy a disk backing image chain to dest.")
|
2013-02-07 15:25:10 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdOptDef opts_blockcopy[] = {
|
2018-05-15 11:10:34 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "path",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-05-15 11:18:24 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
.help = N_("fully-qualified path of source disk")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "dest",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("path of the copy to create")
|
|
|
|
},
|
|
|
|
{.name = "bandwidth",
|
2014-11-06 08:01:00 +00:00
|
|
|
.type = VSH_OT_INT,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("bandwidth limit in MiB/s")
|
|
|
|
},
|
|
|
|
{.name = "shallow",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("make the copy share a backing chain")
|
|
|
|
},
|
|
|
|
{.name = "reuse-external",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("reuse existing destination")
|
|
|
|
},
|
|
|
|
{.name = "raw",
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "format=raw"
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
2014-08-28 04:03:04 +00:00
|
|
|
{.name = "blockdev",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("copy destination is block device instead of regular file")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "wait",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("wait for job to reach mirroring phase")
|
|
|
|
},
|
|
|
|
{.name = "verbose",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("with --wait, display the progress")
|
|
|
|
},
|
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
2014-06-11 15:36:49 +00:00
|
|
|
.help = N_("implies --wait, abort if copy exceeds timeout (in seconds)")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "pivot",
|
|
|
|
.type = VSH_OT_BOOL,
|
2014-06-11 15:36:49 +00:00
|
|
|
.help = N_("implies --wait, pivot when mirroring starts")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "finish",
|
|
|
|
.type = VSH_OT_BOOL,
|
2014-06-11 15:36:49 +00:00
|
|
|
.help = N_("implies --wait, quit when mirroring starts")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "async",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("with --wait, don't wait for cancel to finish")
|
|
|
|
},
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
{.name = "xml",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
.help = N_("filename containing XML description of the copy destination")
|
|
|
|
},
|
|
|
|
{.name = "format",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-06-15 00:38:26 +00:00
|
|
|
.flags = VSH_OFLAG_NONE,
|
|
|
|
.completer = virshDomainStorageFileFormatCompleter,
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
.help = N_("format of the destination file")
|
|
|
|
},
|
|
|
|
{.name = "granularity",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("power-of-two granularity to use during the copy")
|
|
|
|
},
|
|
|
|
{.name = "buf-size",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("maximum amount of in-flight data during the copy")
|
|
|
|
},
|
2016-03-17 12:40:30 +00:00
|
|
|
{.name = "bytes",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("the bandwidth limit is in bytes/s rather than MiB/s")
|
|
|
|
},
|
2017-06-06 13:32:49 +00:00
|
|
|
{.name = "transient-job",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("the copy job is not persisted if VM is turned off")
|
|
|
|
},
|
2021-12-01 14:09:45 +00:00
|
|
|
{.name = "synchronous-writes",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("the copy job forces guest writes to be synchronously written to the destination")
|
|
|
|
},
|
2022-04-25 07:47:26 +00:00
|
|
|
{.name = "print-xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print the XML used to start the copy job instead of starting the job")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2018-02-19 06:19:47 +00:00
|
|
|
cmdBlockcopy(vshControl *ctl, const vshCmd *cmd)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
const char *dest = NULL;
|
|
|
|
const char *format = NULL;
|
2014-08-29 21:20:30 +00:00
|
|
|
unsigned long bandwidth = 0;
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
unsigned int granularity = 0;
|
|
|
|
unsigned long long buf_size = 0;
|
|
|
|
unsigned int flags = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool ret = false;
|
|
|
|
bool verbose = vshCommandOptBool(cmd, "verbose");
|
|
|
|
bool pivot = vshCommandOptBool(cmd, "pivot");
|
|
|
|
bool finish = vshCommandOptBool(cmd, "finish");
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
bool blockdev = vshCommandOptBool(cmd, "blockdev");
|
2015-07-14 10:56:27 +00:00
|
|
|
bool blocking = vshCommandOptBool(cmd, "wait") || finish || pivot;
|
|
|
|
bool async = vshCommandOptBool(cmd, "async");
|
2016-03-17 12:40:30 +00:00
|
|
|
bool bytes = vshCommandOptBool(cmd, "bytes");
|
2017-06-06 13:32:49 +00:00
|
|
|
bool transientjob = vshCommandOptBool(cmd, "transient-job");
|
2021-12-01 14:09:45 +00:00
|
|
|
bool syncWrites = vshCommandOptBool(cmd, "synchronous-writes");
|
2012-07-25 15:37:18 +00:00
|
|
|
int timeout = 0;
|
|
|
|
const char *path = NULL;
|
|
|
|
int abort_flags = 0;
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
const char *xml = NULL;
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char *xmlstr = NULL;
|
2022-04-25 07:47:26 +00:00
|
|
|
bool print_xml = vshCommandOptBool(cmd, "print-xml");
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshBlockJobWaitData *bjWait = NULL;
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
int nparams = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-08-29 21:20:30 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
|
|
|
|
return false;
|
2015-12-03 12:42:35 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "dest", &dest) < 0)
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
return false;
|
2015-12-03 12:42:35 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "xml", &xml) < 0)
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
return false;
|
2015-12-03 12:42:35 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "format", &format) < 0)
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
return false;
|
2016-03-17 12:40:30 +00:00
|
|
|
if (vshBlockJobOptionBandwidth(ctl, cmd, bytes, &bandwidth) < 0)
|
2015-07-14 10:56:27 +00:00
|
|
|
return false;
|
|
|
|
if (vshCommandOptUInt(ctl, cmd, "granularity", &granularity) < 0)
|
|
|
|
return false;
|
|
|
|
if (vshCommandOptULongLong(ctl, cmd, "buf-size", &buf_size) < 0)
|
|
|
|
return false;
|
|
|
|
/* Exploit that some VIR_DOMAIN_BLOCK_REBASE_* and
|
|
|
|
* VIR_DOMAIN_BLOCK_COPY_* flags have the same values. */
|
|
|
|
if (vshCommandOptBool(cmd, "shallow"))
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_REBASE_SHALLOW;
|
|
|
|
if (vshCommandOptBool(cmd, "reuse-external"))
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT;
|
2017-06-06 13:32:49 +00:00
|
|
|
if (transientjob)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_COPY_TRANSIENT_JOB;
|
2021-12-01 14:09:45 +00:00
|
|
|
if (syncWrites)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_COPY_SYNCHRONOUS_WRITES;
|
2015-07-14 10:56:27 +00:00
|
|
|
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (timeout)
|
|
|
|
blocking = true;
|
|
|
|
|
|
|
|
if (async)
|
|
|
|
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC;
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(dest, xml);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(format, xml);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(blockdev, xml);
|
2015-07-14 10:56:27 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(pivot, finish);
|
2014-08-29 21:20:30 +00:00
|
|
|
|
2015-07-14 10:56:27 +00:00
|
|
|
if (!dest && !xml) {
|
|
|
|
vshError(ctl, "%s", _("need either --dest or --xml"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!blocking) {
|
|
|
|
if (verbose) {
|
|
|
|
vshError(ctl, "%s", _("--verbose requires at least one of --timeout, "
|
|
|
|
"--wait, --pivot, or --finish"));
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
}
|
2015-07-14 10:56:27 +00:00
|
|
|
|
|
|
|
if (async) {
|
|
|
|
vshError(ctl, "%s", _("--async requires at least one of --timeout, "
|
|
|
|
"--wait, --pivot, or --finish"));
|
2013-03-26 15:41:06 +00:00
|
|
|
return false;
|
2015-07-14 10:56:27 +00:00
|
|
|
}
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2014-08-29 21:20:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
if (blocking &&
|
2015-06-15 16:53:58 +00:00
|
|
|
!(bjWait = virshBlockJobWaitInit(ctl, dom, path, _("Block Copy"),
|
|
|
|
verbose, timeout, async)))
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
if (xml) {
|
2014-10-14 08:04:31 +00:00
|
|
|
if (virFileReadAll(xml, VSH_MAX_XML_FILE, &xmlstr) < 0) {
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
vshReportError(ctl);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2014-08-29 21:20:30 +00:00
|
|
|
|
2017-06-06 13:32:49 +00:00
|
|
|
if (granularity || buf_size || (format && STRNEQ(format, "raw")) || xml ||
|
2022-04-25 07:47:26 +00:00
|
|
|
transientjob || syncWrites || print_xml) {
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
/* New API */
|
|
|
|
if (bandwidth || granularity || buf_size) {
|
2020-10-05 16:50:09 +00:00
|
|
|
params = g_new0(virTypedParameter, 3);
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
if (bandwidth) {
|
2016-03-17 12:40:30 +00:00
|
|
|
if (!bytes) {
|
|
|
|
/* bandwidth is ulong MiB/s, but the typed parameter is
|
|
|
|
* ullong bytes/s; make sure we don't overflow */
|
|
|
|
unsigned long long limit = MIN(ULONG_MAX, ULLONG_MAX >> 20);
|
|
|
|
if (bandwidth > limit) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("bandwidth must be less than %1$llu"), limit);
|
2016-03-17 12:40:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
bandwidth <<= 20ULL;
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
}
|
|
|
|
if (virTypedParameterAssign(¶ms[nparams++],
|
|
|
|
VIR_DOMAIN_BLOCK_COPY_BANDWIDTH,
|
|
|
|
VIR_TYPED_PARAM_ULLONG,
|
2016-03-17 12:40:30 +00:00
|
|
|
bandwidth) < 0)
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (granularity &&
|
|
|
|
virTypedParameterAssign(¶ms[nparams++],
|
|
|
|
VIR_DOMAIN_BLOCK_COPY_GRANULARITY,
|
|
|
|
VIR_TYPED_PARAM_UINT,
|
|
|
|
granularity) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (buf_size &&
|
|
|
|
virTypedParameterAssign(¶ms[nparams++],
|
|
|
|
VIR_DOMAIN_BLOCK_COPY_BUF_SIZE,
|
|
|
|
VIR_TYPED_PARAM_ULLONG,
|
|
|
|
buf_size) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!xmlstr) {
|
2020-07-02 23:40:16 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2022-02-28 13:48:37 +00:00
|
|
|
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
|
2022-04-25 08:16:13 +00:00
|
|
|
g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(&buf);
|
2022-02-28 13:48:37 +00:00
|
|
|
|
|
|
|
if (blockdev) {
|
|
|
|
virBufferAddLit(&attrBuf, " type='block'");
|
2022-04-25 08:16:13 +00:00
|
|
|
virBufferEscapeString(&childBuf, "<source dev='%s'/>\n", dest);
|
2022-02-28 13:48:37 +00:00
|
|
|
} else {
|
2022-04-25 08:16:13 +00:00
|
|
|
virBufferAddLit(&attrBuf, " type='file'");
|
|
|
|
virBufferEscapeString(&childBuf, "<source file='%s'/>\n", dest);
|
2022-02-28 13:48:37 +00:00
|
|
|
}
|
|
|
|
|
2022-04-25 08:16:13 +00:00
|
|
|
virBufferEscapeString(&childBuf, "<driver type='%s'/>\n", format);
|
2022-02-28 13:48:37 +00:00
|
|
|
virXMLFormatElement(&buf, "disk", &attrBuf, &childBuf);
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
xmlstr = virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
2022-04-25 07:47:26 +00:00
|
|
|
if (print_xml) {
|
|
|
|
vshPrint(ctl, "%s", xmlstr);
|
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
if (virDomainBlockCopy(dom, path, xmlstr, params, nparams, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
/* Old API */
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_REBASE_COPY;
|
2015-07-14 10:56:27 +00:00
|
|
|
if (blockdev)
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
flags |= VIR_DOMAIN_BLOCK_REBASE_COPY_DEV;
|
|
|
|
if (STREQ_NULLABLE(format, "raw"))
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_REBASE_COPY_RAW;
|
2016-03-17 12:40:30 +00:00
|
|
|
if (bytes)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_REBASE_BANDWIDTH_BYTES;
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
|
|
|
|
if (virDomainBlockRebase(dom, path, dest, bandwidth, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (!blocking) {
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Block Copy started"));
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
/* Execution continues here only if --wait or friends were specified */
|
2015-06-15 16:53:58 +00:00
|
|
|
switch (virshBlockJobWait(bjWait)) {
|
2015-07-13 15:04:49 +00:00
|
|
|
case -1:
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
2015-06-19 13:43:02 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_CANCELED:
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Copy aborted"));
|
2015-06-19 13:43:02 +00:00
|
|
|
goto cleanup;
|
2015-07-13 15:04:49 +00:00
|
|
|
break;
|
2013-08-09 20:52:11 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_FAILED:
|
2020-06-17 12:08:22 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Copy failed"));
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
break;
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_READY:
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
|
|
|
|
break;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
if (pivot) {
|
2012-07-25 15:37:18 +00:00
|
|
|
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
|
|
|
|
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("failed to pivot job for disk %1$s"), path);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Successfully pivoted"));
|
2015-07-13 15:04:49 +00:00
|
|
|
} else if (finish) {
|
|
|
|
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("failed to finish job for disk %1$s"), path);
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Successfully copied"));
|
2015-07-13 15:04:49 +00:00
|
|
|
} else {
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Now in mirroring phase"));
|
2015-07-13 15:04:49 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
ret = true;
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
blockcopy: expose new API in virsh
Expose the new power of virDomainBlockCopy through virsh (well,
all but the finer-grained bandwidth, as that is its own can of
worms for a later patch). Continue to use the older API where
possible, for maximum compatibility.
The command now requires either --dest (with optional --format
and --blockdev), to directly describe the file destination, or
--xml, to name a file that contains an XML description such as:
<disk type='network'>
<driver type='raw'/>
<source protocol='gluster' name='vol1/img'>
<host name='red'/>
</source>
</disk>
[well, it may be a while before the qemu driver is actually patched
to act on that particular xml beyond just parsing it, but the virsh
interface won't need changing at that time]
Non-zero option parameters are converted into virTypedParameters,
and if anything requires the new API, the command can synthesize
appropriate XML even if the --dest option was used instead of --xml.
The existing --raw flag remains for back-compat, but the preferred
spelling is now --format=raw, since the new API now allows us
to specify all formats rather than just a boolean raw to suppress
probing.
I hope I did justice in describing the effects of granularity and
buf-size on how they get passed through to qemu.
* tools/virsh-domain.c (cmdBlockCopy): Add new options --xml,
--granularity, --buf-size, --format. Make --raw an alias for
--format=raw. Call new API if new parameters are in use.
* tools/virsh.pod (blockcopy): Document new options.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-29 21:47:28 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2015-06-15 16:53:58 +00:00
|
|
|
virshBlockJobWaitFree(bjWait);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "blockjob" command
|
|
|
|
*/
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdInfo info_blockjob[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Manage active block operations")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Query, adjust speed, or cancel active block operations.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdOptDef opts_blockjob[] = {
|
2018-05-15 11:10:34 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "path",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-05-15 11:18:24 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("fully-qualified path of disk")
|
|
|
|
},
|
|
|
|
{.name = "abort",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("abort the active job on the specified disk")
|
|
|
|
},
|
|
|
|
{.name = "async",
|
|
|
|
.type = VSH_OT_BOOL,
|
blockjob: add new --raw flag to virsh blockjob
The current output of 'blockjob [--info]' is a single line
designed for human consumption; it's not very nice for machine
parsing. Furthermore, I have plans to modify the line in
response to the new flag for controlling bandwidth units.
Solve that by adding a --raw parameter, which outputs
information closer to the C struct.
$ virsh blockjob testvm1 vda --raw
type=Block Copy
bandwidth=1
cur=197120
end=197120
The information is indented, because I'd like for a later patch
to add a mode that iterates over all the vm's disks with status
for each; in that mode, each block name would be listed unindented
before information (if any) about that block.
Now that we have a raw mode, we can guarantee that it won't change
format over time. Any app that cares about parsing the output can
try --raw, and if it fails, know that it was talking to an older
virsh and fall back to parsing the human-readable format which had
not changed until now; meanwhile, when not using --raw, we have
freed future virsh to change the output to whatever makes sense.
My first change to human mode: this command now guarantees a line
is printed on successful use of the API, even when the API did
not find a current block job (consistent with the rest of virsh).
Bonus: https://bugzilla.redhat.com/show_bug.cgi?id=1135441
complained that this message was confusing:
$ virsh blockjob test1 hda --async --bandwidth 10
error: conflict between --abort, --info, and --bandwidth modes
even though the man page already documents that --async implies
abort mode, all because '--abort' wasn't present in the command
line. Since I'm adding another case where options are tied
to or imply a mode, I changed that error to:
error: conflict between abort, info, and bandwidth modes
* tools/virsh-domain.c (cmdBlockJob): Add --raw parameter; tweak
error wording.
* tools/virsh.pod (blockjob): Document it.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-28 23:23:49 +00:00
|
|
|
.help = N_("implies --abort; request but don't wait for job end")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "pivot",
|
|
|
|
.type = VSH_OT_BOOL,
|
blockjob: add new --raw flag to virsh blockjob
The current output of 'blockjob [--info]' is a single line
designed for human consumption; it's not very nice for machine
parsing. Furthermore, I have plans to modify the line in
response to the new flag for controlling bandwidth units.
Solve that by adding a --raw parameter, which outputs
information closer to the C struct.
$ virsh blockjob testvm1 vda --raw
type=Block Copy
bandwidth=1
cur=197120
end=197120
The information is indented, because I'd like for a later patch
to add a mode that iterates over all the vm's disks with status
for each; in that mode, each block name would be listed unindented
before information (if any) about that block.
Now that we have a raw mode, we can guarantee that it won't change
format over time. Any app that cares about parsing the output can
try --raw, and if it fails, know that it was talking to an older
virsh and fall back to parsing the human-readable format which had
not changed until now; meanwhile, when not using --raw, we have
freed future virsh to change the output to whatever makes sense.
My first change to human mode: this command now guarantees a line
is printed on successful use of the API, even when the API did
not find a current block job (consistent with the rest of virsh).
Bonus: https://bugzilla.redhat.com/show_bug.cgi?id=1135441
complained that this message was confusing:
$ virsh blockjob test1 hda --async --bandwidth 10
error: conflict between --abort, --info, and --bandwidth modes
even though the man page already documents that --async implies
abort mode, all because '--abort' wasn't present in the command
line. Since I'm adding another case where options are tied
to or imply a mode, I changed that error to:
error: conflict between abort, info, and bandwidth modes
* tools/virsh-domain.c (cmdBlockJob): Add --raw parameter; tweak
error wording.
* tools/virsh.pod (blockjob): Document it.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-28 23:23:49 +00:00
|
|
|
.help = N_("implies --abort; conclude and pivot a copy or commit job")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "info",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("get active job information for the specified disk")
|
|
|
|
},
|
2014-08-28 23:39:25 +00:00
|
|
|
{.name = "bytes",
|
|
|
|
.type = VSH_OT_BOOL,
|
2016-03-29 13:52:10 +00:00
|
|
|
.help = N_("get/set bandwidth in bytes rather than MiB/s")
|
2014-08-28 23:39:25 +00:00
|
|
|
},
|
blockjob: add new --raw flag to virsh blockjob
The current output of 'blockjob [--info]' is a single line
designed for human consumption; it's not very nice for machine
parsing. Furthermore, I have plans to modify the line in
response to the new flag for controlling bandwidth units.
Solve that by adding a --raw parameter, which outputs
information closer to the C struct.
$ virsh blockjob testvm1 vda --raw
type=Block Copy
bandwidth=1
cur=197120
end=197120
The information is indented, because I'd like for a later patch
to add a mode that iterates over all the vm's disks with status
for each; in that mode, each block name would be listed unindented
before information (if any) about that block.
Now that we have a raw mode, we can guarantee that it won't change
format over time. Any app that cares about parsing the output can
try --raw, and if it fails, know that it was talking to an older
virsh and fall back to parsing the human-readable format which had
not changed until now; meanwhile, when not using --raw, we have
freed future virsh to change the output to whatever makes sense.
My first change to human mode: this command now guarantees a line
is printed on successful use of the API, even when the API did
not find a current block job (consistent with the rest of virsh).
Bonus: https://bugzilla.redhat.com/show_bug.cgi?id=1135441
complained that this message was confusing:
$ virsh blockjob test1 hda --async --bandwidth 10
error: conflict between --abort, --info, and --bandwidth modes
even though the man page already documents that --async implies
abort mode, all because '--abort' wasn't present in the command
line. Since I'm adding another case where options are tied
to or imply a mode, I changed that error to:
error: conflict between abort, info, and bandwidth modes
* tools/virsh-domain.c (cmdBlockJob): Add --raw parameter; tweak
error wording.
* tools/virsh.pod (blockjob): Document it.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-28 23:23:49 +00:00
|
|
|
{.name = "raw",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("implies --info; output details rather than human summary")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "bandwidth",
|
2014-11-06 08:01:00 +00:00
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("set the bandwidth limit in MiB/s")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2015-06-15 16:53:58 +00:00
|
|
|
virshBlockJobInfo(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
const char *path,
|
|
|
|
bool raw,
|
|
|
|
bool bytes)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
|
|
|
virDomainBlockJobInfo info;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2015-04-01 12:54:10 +00:00
|
|
|
unsigned long long speed;
|
|
|
|
unsigned int flags = 0;
|
2014-08-28 23:39:25 +00:00
|
|
|
int rc = -1;
|
2014-08-28 19:18:22 +00:00
|
|
|
|
2014-08-28 23:39:25 +00:00
|
|
|
/* If bytes were requested, or if raw mode is not forcing a MiB/s
|
|
|
|
* query and cache can't prove failure, then query bytes/sec. */
|
2015-06-15 16:53:58 +00:00
|
|
|
if (bytes || !(raw || priv->blockJobNoBytes)) {
|
2014-08-28 23:39:25 +00:00
|
|
|
flags |= VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES;
|
|
|
|
rc = virDomainGetBlockJobInfo(dom, path, &info, flags);
|
|
|
|
if (rc < 0) {
|
|
|
|
/* Check for particular errors, let all the rest be fatal. */
|
|
|
|
switch (last_error->code) {
|
|
|
|
case VIR_ERR_INVALID_ARG:
|
2015-06-15 16:53:58 +00:00
|
|
|
priv->blockJobNoBytes = true;
|
2019-10-15 11:38:21 +00:00
|
|
|
G_GNUC_FALLTHROUGH;
|
2014-08-28 23:39:25 +00:00
|
|
|
case VIR_ERR_OVERFLOW:
|
|
|
|
if (!bytes && !raw) {
|
|
|
|
/* try again with MiB/s, unless forcing bytes */
|
|
|
|
vshResetLibvirtError();
|
|
|
|
break;
|
|
|
|
}
|
2019-10-15 11:38:21 +00:00
|
|
|
G_GNUC_FALLTHROUGH;
|
2014-08-28 23:39:25 +00:00
|
|
|
default:
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2014-08-28 23:39:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
speed = info.bandwidth;
|
|
|
|
}
|
|
|
|
/* If we don't already have a query result, query for MiB/s */
|
|
|
|
if (rc < 0) {
|
|
|
|
flags &= ~VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES;
|
|
|
|
if ((rc = virDomainGetBlockJobInfo(dom, path, &info, flags)) < 0)
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2014-08-28 23:39:25 +00:00
|
|
|
speed = info.bandwidth;
|
|
|
|
/* Scale to bytes/s unless in raw mode */
|
|
|
|
if (!raw) {
|
|
|
|
speed <<= 20;
|
|
|
|
if (speed >> 20 != info.bandwidth) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("overflow in converting %1$ld MiB/s to bytes\n"),
|
2014-08-28 23:39:25 +00:00
|
|
|
info.bandwidth);
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2014-08-28 23:39:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-28 19:18:22 +00:00
|
|
|
if (rc == 0) {
|
blockjob: add new --raw flag to virsh blockjob
The current output of 'blockjob [--info]' is a single line
designed for human consumption; it's not very nice for machine
parsing. Furthermore, I have plans to modify the line in
response to the new flag for controlling bandwidth units.
Solve that by adding a --raw parameter, which outputs
information closer to the C struct.
$ virsh blockjob testvm1 vda --raw
type=Block Copy
bandwidth=1
cur=197120
end=197120
The information is indented, because I'd like for a later patch
to add a mode that iterates over all the vm's disks with status
for each; in that mode, each block name would be listed unindented
before information (if any) about that block.
Now that we have a raw mode, we can guarantee that it won't change
format over time. Any app that cares about parsing the output can
try --raw, and if it fails, know that it was talking to an older
virsh and fall back to parsing the human-readable format which had
not changed until now; meanwhile, when not using --raw, we have
freed future virsh to change the output to whatever makes sense.
My first change to human mode: this command now guarantees a line
is printed on successful use of the API, even when the API did
not find a current block job (consistent with the rest of virsh).
Bonus: https://bugzilla.redhat.com/show_bug.cgi?id=1135441
complained that this message was confusing:
$ virsh blockjob test1 hda --async --bandwidth 10
error: conflict between --abort, --info, and --bandwidth modes
even though the man page already documents that --async implies
abort mode, all because '--abort' wasn't present in the command
line. Since I'm adding another case where options are tied
to or imply a mode, I changed that error to:
error: conflict between abort, info, and bandwidth modes
* tools/virsh-domain.c (cmdBlockJob): Add --raw parameter; tweak
error wording.
* tools/virsh.pod (blockjob): Document it.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-28 23:23:49 +00:00
|
|
|
if (!raw)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("No current block job for %1$s"), path);
|
2019-10-21 18:19:09 +00:00
|
|
|
return true;
|
2014-08-28 19:18:22 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
blockjob: add new --raw flag to virsh blockjob
The current output of 'blockjob [--info]' is a single line
designed for human consumption; it's not very nice for machine
parsing. Furthermore, I have plans to modify the line in
response to the new flag for controlling bandwidth units.
Solve that by adding a --raw parameter, which outputs
information closer to the C struct.
$ virsh blockjob testvm1 vda --raw
type=Block Copy
bandwidth=1
cur=197120
end=197120
The information is indented, because I'd like for a later patch
to add a mode that iterates over all the vm's disks with status
for each; in that mode, each block name would be listed unindented
before information (if any) about that block.
Now that we have a raw mode, we can guarantee that it won't change
format over time. Any app that cares about parsing the output can
try --raw, and if it fails, know that it was talking to an older
virsh and fall back to parsing the human-readable format which had
not changed until now; meanwhile, when not using --raw, we have
freed future virsh to change the output to whatever makes sense.
My first change to human mode: this command now guarantees a line
is printed on successful use of the API, even when the API did
not find a current block job (consistent with the rest of virsh).
Bonus: https://bugzilla.redhat.com/show_bug.cgi?id=1135441
complained that this message was confusing:
$ virsh blockjob test1 hda --async --bandwidth 10
error: conflict between --abort, --info, and --bandwidth modes
even though the man page already documents that --async implies
abort mode, all because '--abort' wasn't present in the command
line. Since I'm adding another case where options are tied
to or imply a mode, I changed that error to:
error: conflict between abort, info, and bandwidth modes
* tools/virsh-domain.c (cmdBlockJob): Add --raw parameter; tweak
error wording.
* tools/virsh.pod (blockjob): Document it.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-28 23:23:49 +00:00
|
|
|
if (raw) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrint(ctl, _(" type=%1$s\n bandwidth=%2$lu\n cur=%3$llu\n end=%4$llu\n"),
|
2015-06-15 16:53:58 +00:00
|
|
|
virshDomainBlockJobTypeToString(info.type),
|
blockjob: add new --raw flag to virsh blockjob
The current output of 'blockjob [--info]' is a single line
designed for human consumption; it's not very nice for machine
parsing. Furthermore, I have plans to modify the line in
response to the new flag for controlling bandwidth units.
Solve that by adding a --raw parameter, which outputs
information closer to the C struct.
$ virsh blockjob testvm1 vda --raw
type=Block Copy
bandwidth=1
cur=197120
end=197120
The information is indented, because I'd like for a later patch
to add a mode that iterates over all the vm's disks with status
for each; in that mode, each block name would be listed unindented
before information (if any) about that block.
Now that we have a raw mode, we can guarantee that it won't change
format over time. Any app that cares about parsing the output can
try --raw, and if it fails, know that it was talking to an older
virsh and fall back to parsing the human-readable format which had
not changed until now; meanwhile, when not using --raw, we have
freed future virsh to change the output to whatever makes sense.
My first change to human mode: this command now guarantees a line
is printed on successful use of the API, even when the API did
not find a current block job (consistent with the rest of virsh).
Bonus: https://bugzilla.redhat.com/show_bug.cgi?id=1135441
complained that this message was confusing:
$ virsh blockjob test1 hda --async --bandwidth 10
error: conflict between --abort, --info, and --bandwidth modes
even though the man page already documents that --async implies
abort mode, all because '--abort' wasn't present in the command
line. Since I'm adding another case where options are tied
to or imply a mode, I changed that error to:
error: conflict between abort, info, and bandwidth modes
* tools/virsh-domain.c (cmdBlockJob): Add --raw parameter; tweak
error wording.
* tools/virsh.pod (blockjob): Document it.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-28 23:23:49 +00:00
|
|
|
info.bandwidth, info.cur, info.end);
|
|
|
|
} else {
|
2015-06-15 16:53:58 +00:00
|
|
|
virshPrintJobProgress(virshDomainBlockJobToString(info.type),
|
|
|
|
info.end - info.cur, info.end);
|
2014-08-28 23:39:25 +00:00
|
|
|
if (speed) {
|
|
|
|
const char *unit;
|
|
|
|
double val = vshPrettyCapacity(speed, &unit);
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrint(ctl, _(" Bandwidth limit: %1$llu bytes/s (%2$-.3lf %3$s/s)"),
|
2014-08-28 23:39:25 +00:00
|
|
|
speed, val, unit);
|
|
|
|
}
|
blockjob: add new --raw flag to virsh blockjob
The current output of 'blockjob [--info]' is a single line
designed for human consumption; it's not very nice for machine
parsing. Furthermore, I have plans to modify the line in
response to the new flag for controlling bandwidth units.
Solve that by adding a --raw parameter, which outputs
information closer to the C struct.
$ virsh blockjob testvm1 vda --raw
type=Block Copy
bandwidth=1
cur=197120
end=197120
The information is indented, because I'd like for a later patch
to add a mode that iterates over all the vm's disks with status
for each; in that mode, each block name would be listed unindented
before information (if any) about that block.
Now that we have a raw mode, we can guarantee that it won't change
format over time. Any app that cares about parsing the output can
try --raw, and if it fails, know that it was talking to an older
virsh and fall back to parsing the human-readable format which had
not changed until now; meanwhile, when not using --raw, we have
freed future virsh to change the output to whatever makes sense.
My first change to human mode: this command now guarantees a line
is printed on successful use of the API, even when the API did
not find a current block job (consistent with the rest of virsh).
Bonus: https://bugzilla.redhat.com/show_bug.cgi?id=1135441
complained that this message was confusing:
$ virsh blockjob test1 hda --async --bandwidth 10
error: conflict between --abort, --info, and --bandwidth modes
even though the man page already documents that --async implies
abort mode, all because '--abort' wasn't present in the command
line. Since I'm adding another case where options are tied
to or imply a mode, I changed that error to:
error: conflict between abort, info, and bandwidth modes
* tools/virsh-domain.c (cmdBlockJob): Add --raw parameter; tweak
error wording.
* tools/virsh.pod (blockjob): Document it.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-08-28 23:23:49 +00:00
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
}
|
2015-04-01 12:54:10 +00:00
|
|
|
|
2019-10-21 18:19:09 +00:00
|
|
|
return true;
|
2015-04-01 12:54:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-01 14:45:19 +00:00
|
|
|
static bool
|
2015-06-15 16:53:58 +00:00
|
|
|
virshBlockJobSetSpeed(vshControl *ctl,
|
|
|
|
const vshCmd *cmd,
|
|
|
|
virDomainPtr dom,
|
2016-03-29 13:52:10 +00:00
|
|
|
const char *path,
|
|
|
|
bool bytes)
|
2015-04-01 14:45:19 +00:00
|
|
|
{
|
|
|
|
unsigned long bandwidth;
|
2016-03-29 13:52:10 +00:00
|
|
|
unsigned int flags = 0;
|
2015-04-01 14:45:19 +00:00
|
|
|
|
2016-03-29 13:52:10 +00:00
|
|
|
if (bytes)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_JOB_SPEED_BANDWIDTH_BYTES;
|
|
|
|
|
|
|
|
if (vshBlockJobOptionBandwidth(ctl, cmd, bytes, &bandwidth) < 0)
|
2015-04-01 14:45:19 +00:00
|
|
|
return false;
|
|
|
|
|
2016-03-29 13:52:10 +00:00
|
|
|
if (virDomainBlockJobSetSpeed(dom, path, bandwidth, flags) < 0)
|
2015-04-01 14:45:19 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-02 12:55:09 +00:00
|
|
|
static bool
|
2015-06-15 16:53:58 +00:00
|
|
|
virshBlockJobAbort(virDomainPtr dom,
|
|
|
|
const char *path,
|
|
|
|
bool pivot,
|
|
|
|
bool async)
|
2015-04-02 12:55:09 +00:00
|
|
|
{
|
|
|
|
unsigned int flags = 0;
|
|
|
|
|
|
|
|
if (async)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC;
|
|
|
|
if (pivot)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
|
|
|
|
|
|
|
|
if (virDomainBlockJobAbort(dom, path, flags) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-01 12:54:10 +00:00
|
|
|
static bool
|
2018-02-19 06:19:47 +00:00
|
|
|
cmdBlockjob(vshControl *ctl, const vshCmd *cmd)
|
2015-04-01 12:54:10 +00:00
|
|
|
{
|
|
|
|
bool raw = vshCommandOptBool(cmd, "raw");
|
|
|
|
bool bytes = vshCommandOptBool(cmd, "bytes");
|
2015-04-01 13:05:33 +00:00
|
|
|
bool abortMode = vshCommandOptBool(cmd, "abort");
|
|
|
|
bool pivot = vshCommandOptBool(cmd, "pivot");
|
|
|
|
bool async = vshCommandOptBool(cmd, "async");
|
|
|
|
bool info = vshCommandOptBool(cmd, "info");
|
2015-04-01 12:54:10 +00:00
|
|
|
bool bandwidth = vshCommandOptBool(cmd, "bandwidth");
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-04-01 12:54:10 +00:00
|
|
|
const char *path;
|
|
|
|
|
2015-04-01 13:05:33 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("raw", "abort");
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(raw, pivot);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(raw, async);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(raw, bandwidth);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("info", "abort");
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(info, pivot);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(info, async);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(info, bandwidth);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("bytes", "abort");
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(bytes, pivot);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(bytes, async);
|
2015-04-01 12:54:10 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-04-01 12:54:10 +00:00
|
|
|
|
|
|
|
/* XXX Allow path to be optional to list info on all devices at once */
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-04-01 12:54:10 +00:00
|
|
|
|
2015-04-01 14:45:19 +00:00
|
|
|
if (bandwidth)
|
2021-09-24 15:17:46 +00:00
|
|
|
return virshBlockJobSetSpeed(ctl, cmd, dom, path, bytes);
|
|
|
|
if (abortMode || pivot || async)
|
|
|
|
return virshBlockJobAbort(dom, path, pivot, async);
|
|
|
|
return virshBlockJobInfo(ctl, dom, path, raw, bytes);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "blockpull" command
|
|
|
|
*/
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdInfo info_blockpull[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Populate a disk from its backing image.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Populate a disk from its backing image.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdOptDef opts_blockpull[] = {
|
2018-05-15 11:10:34 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "path",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-05-15 11:18:24 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("fully-qualified path of disk")
|
|
|
|
},
|
|
|
|
{.name = "bandwidth",
|
2014-11-06 08:01:00 +00:00
|
|
|
.type = VSH_OT_INT,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("bandwidth limit in MiB/s")
|
|
|
|
},
|
|
|
|
{.name = "base",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-16 15:49:50 +00:00
|
|
|
.completer = virshDomainBlockjobBaseTopCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("path of backing file in chain for a partial pull")
|
|
|
|
},
|
|
|
|
{.name = "wait",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("wait for job to finish")
|
|
|
|
},
|
|
|
|
{.name = "verbose",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("with --wait, display the progress")
|
|
|
|
},
|
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("with --wait, abort if pull exceeds timeout (in seconds)")
|
|
|
|
},
|
|
|
|
{.name = "async",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("with --wait, don't wait for cancel to finish")
|
|
|
|
},
|
2014-05-16 13:40:06 +00:00
|
|
|
{.name = "keep-relative",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("keep the backing chain relatively referenced")
|
|
|
|
},
|
2016-03-17 12:41:00 +00:00
|
|
|
{.name = "bytes",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("the bandwidth limit is in bytes/s rather than MiB/s")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2018-02-19 06:19:47 +00:00
|
|
|
cmdBlockpull(vshControl *ctl, const vshCmd *cmd)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool ret = false;
|
|
|
|
bool blocking = vshCommandOptBool(cmd, "wait");
|
|
|
|
bool verbose = vshCommandOptBool(cmd, "verbose");
|
2015-07-14 10:56:27 +00:00
|
|
|
bool async = vshCommandOptBool(cmd, "async");
|
2016-03-17 12:41:00 +00:00
|
|
|
bool bytes = vshCommandOptBool(cmd, "bytes");
|
2012-07-25 15:37:18 +00:00
|
|
|
int timeout = 0;
|
|
|
|
const char *path = NULL;
|
2015-04-30 14:22:04 +00:00
|
|
|
const char *base = NULL;
|
|
|
|
unsigned long bandwidth = 0;
|
|
|
|
unsigned int flags = 0;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshBlockJobWaitData *bjWait = NULL;
|
2015-04-30 14:22:04 +00:00
|
|
|
|
2015-07-14 10:56:27 +00:00
|
|
|
VSH_REQUIRE_OPTION("verbose", "wait");
|
|
|
|
VSH_REQUIRE_OPTION("async", "wait");
|
|
|
|
|
2015-04-30 14:22:04 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "base", &base) < 0)
|
|
|
|
return false;
|
|
|
|
|
2016-03-17 12:41:00 +00:00
|
|
|
if (vshBlockJobOptionBandwidth(ctl, cmd, bytes, &bandwidth) < 0)
|
2015-04-30 14:22:04 +00:00
|
|
|
return false;
|
|
|
|
|
2015-07-14 10:56:27 +00:00
|
|
|
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
|
|
|
|
return false;
|
|
|
|
|
2015-04-30 14:22:04 +00:00
|
|
|
if (vshCommandOptBool(cmd, "keep-relative"))
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_REBASE_RELATIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2015-04-30 14:22:04 +00:00
|
|
|
return false;
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
if (blocking &&
|
2015-06-15 16:53:58 +00:00
|
|
|
!(bjWait = virshBlockJobWaitInit(ctl, dom, path, _("Block Pull"),
|
|
|
|
verbose, timeout, async)))
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
virsh: Fix msg: blockjob is aborted from another client
When a block{pull, copy, commit} is aborted via keyboard interrupt,
the job is properly canceled followed by proper error message.
However, when the job receives an abort from another client connected
to the same domain, the error message incorrectly indicates that
a blockjob has been finished successfully, though the abort request
took effect. This patch introduces a new blockjob abort handler, which
is registered when the client calls block{copy,commit,pull} routine,
providing its caller the status of the finished blockjob.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1135442
2014-11-20 11:52:57 +00:00
|
|
|
|
2015-04-30 14:22:04 +00:00
|
|
|
if (base || flags) {
|
2016-03-17 12:41:00 +00:00
|
|
|
if (bytes)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_REBASE_BANDWIDTH_BYTES;
|
|
|
|
|
2015-04-30 14:22:04 +00:00
|
|
|
if (virDomainBlockRebase(dom, path, base, bandwidth, flags) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
2016-03-17 12:41:00 +00:00
|
|
|
if (bytes)
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES;
|
|
|
|
|
|
|
|
if (virDomainBlockPull(dom, path, bandwidth, flags) < 0)
|
2015-04-30 14:22:04 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (!blocking) {
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Block Pull started"));
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
/* Execution continues here only if --wait or friends were specified */
|
2015-06-15 16:53:58 +00:00
|
|
|
switch (virshBlockJobWait(bjWait)) {
|
2015-07-13 15:04:49 +00:00
|
|
|
case -1:
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_CANCELED:
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Pull aborted"));
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_FAILED:
|
2020-06-17 12:08:22 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Pull failed"));
|
2015-07-13 15:04:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
break;
|
virsh: Fix msg: blockjob is aborted from another client
When a block{pull, copy, commit} is aborted via keyboard interrupt,
the job is properly canceled followed by proper error message.
However, when the job receives an abort from another client connected
to the same domain, the error message incorrectly indicates that
a blockjob has been finished successfully, though the abort request
took effect. This patch introduces a new blockjob abort handler, which
is registered when the client calls block{copy,commit,pull} routine,
providing its caller the status of the finished blockjob.
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1135442
2014-11-20 11:52:57 +00:00
|
|
|
|
2015-07-13 15:04:49 +00:00
|
|
|
case VIR_DOMAIN_BLOCK_JOB_READY:
|
|
|
|
case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
|
2016-11-04 14:22:26 +00:00
|
|
|
vshPrintExtra(ctl, "\n%s", _("Pull complete"));
|
2015-07-13 15:04:49 +00:00
|
|
|
break;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
2015-07-13 15:04:49 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2015-06-15 16:53:58 +00:00
|
|
|
virshBlockJobWaitFree(bjWait);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "blockresize" command
|
|
|
|
*/
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdInfo info_blockresize[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Resize block device of domain.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Resize block device of domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2018-02-19 06:19:47 +00:00
|
|
|
static const vshCmdOptDef opts_blockresize[] = {
|
2018-05-15 11:10:34 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "path",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-05-15 11:18:24 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("Fully-qualified path of block device")
|
|
|
|
},
|
|
|
|
{.name = "size",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("New size of the block device, as scaled integer (default KiB)")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2018-02-19 06:19:47 +00:00
|
|
|
cmdBlockresize(vshControl *ctl, const vshCmd *cmd)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *path = NULL;
|
|
|
|
unsigned long long size = 0;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "path", (const char **) &path) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptScaledInt(ctl, cmd, "size", &size, 1024, ULLONG_MAX) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Prefer the older interface of KiB. */
|
|
|
|
if (size % 1024 == 0)
|
|
|
|
size /= 1024;
|
|
|
|
else
|
|
|
|
flags |= VIR_DOMAIN_BLOCK_RESIZE_BYTES;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainBlockResize(dom, path, size, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to resize block device '%1$s'"), path);
|
2021-09-24 15:17:47 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Block device '%1$s' is resized"), path);
|
2021-09-24 15:17:47 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
/*
|
|
|
|
* "console" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_console[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("connect to the guest console")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Connect the virtual serial console for the guest")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_console[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2014-10-01 14:07:46 +00:00
|
|
|
{.name = "devname", /* sc_prohibit_devname */
|
2013-01-14 11:26:54 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2020-11-10 09:50:54 +00:00
|
|
|
.completer = virshDomainConsoleCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("character device name")
|
|
|
|
},
|
|
|
|
{.name = "force",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("force console connection (disconnect already connected sessions)")
|
|
|
|
},
|
|
|
|
{.name = "safe",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("only connect if safe console handling is supported")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdRunConsole(vshControl *ctl, virDomainPtr dom,
|
|
|
|
const char *name,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
int state;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((state = virshDomainState(ctl, dom, NULL)) < 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to get domain status"));
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (state == VIR_DOMAIN_SHUTOFF) {
|
|
|
|
vshError(ctl, "%s", _("The domain is not running"));
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!isatty(STDIN_FILENO)) {
|
|
|
|
vshError(ctl, "%s", _("Cannot run interactive console without a controlling TTY"));
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Connected to domain '%1$s'\n"), virDomainGetName(dom));
|
|
|
|
vshPrintExtra(ctl, _("Escape character is %1$s"), priv->escapeChar);
|
2020-03-27 15:10:44 +00:00
|
|
|
if (priv->escapeChar[0] == '^')
|
|
|
|
vshPrintExtra(ctl, " (Ctrl + %c)", priv->escapeChar[1]);
|
|
|
|
vshPrintExtra(ctl, "\n");
|
2012-07-25 15:37:18 +00:00
|
|
|
fflush(stdout);
|
2015-06-15 16:53:58 +00:00
|
|
|
if (virshRunConsole(ctl, dom, name, flags) == 0)
|
2019-10-21 18:19:09 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdConsole(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool force = vshCommandOptBool(cmd, "force");
|
|
|
|
bool safe = vshCommandOptBool(cmd, "safe");
|
|
|
|
unsigned int flags = 0;
|
|
|
|
const char *name = NULL;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2014-10-01 14:07:46 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "devname", &name) < 0) /* sc_prohibit_devname */
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (force)
|
|
|
|
flags |= VIR_DOMAIN_CONSOLE_FORCE;
|
|
|
|
if (safe)
|
|
|
|
flags |= VIR_DOMAIN_CONSOLE_SAFE;
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return cmdRunConsole(ctl, dom, name, flags);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2012-08-15 20:43:01 +00:00
|
|
|
#endif /* WIN32 */
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* "domif-setlink" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domif_setlink[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("set link state of a virtual interface")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Set link state of a domain's virtual interface. This command "
|
|
|
|
"wraps usage of update-device command.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domif_setlink[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "interface",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2017-11-06 14:48:01 +00:00
|
|
|
.completer = virshDomainInterfaceCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("interface device (MAC Address)")
|
|
|
|
},
|
|
|
|
{.name = "state",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-07-12 14:07:59 +00:00
|
|
|
.completer = virshDomainInterfaceStateCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("new state of the device")
|
|
|
|
},
|
|
|
|
{.name = "persistent",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "config"
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2022-11-30 15:04:03 +00:00
|
|
|
{.name = "print-xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print XML document rather than set the interface link state")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomIfSetLink(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *iface;
|
|
|
|
const char *state;
|
|
|
|
unsigned int flags = 0;
|
2017-04-11 15:33:53 +00:00
|
|
|
unsigned int xmlflags = 0;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2021-08-11 11:57:15 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2021-08-11 11:21:18 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *xml_buf = NULL;
|
2022-10-19 08:39:33 +00:00
|
|
|
g_autofree xmlNodePtr *nodes = NULL;
|
|
|
|
ssize_t nnodes;
|
|
|
|
xmlNodePtr ifaceNode = NULL;
|
|
|
|
xmlNodePtr linkNode = NULL;
|
|
|
|
xmlAttrPtr stateAttr;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "interface", &iface) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "state", &state) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (STRNEQ(state, "up") && STRNEQ(state, "down")) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("invalid link state '%1$s'"), state);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
if (vshCommandOptBool(cmd, "config")) {
|
2012-07-25 15:37:18 +00:00
|
|
|
flags = VIR_DOMAIN_AFFECT_CONFIG;
|
2017-04-11 15:33:53 +00:00
|
|
|
xmlflags |= VIR_DOMAIN_XML_INACTIVE;
|
|
|
|
} else {
|
2012-07-25 15:37:18 +00:00
|
|
|
flags = VIR_DOMAIN_AFFECT_LIVE;
|
2017-04-11 15:33:53 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (virDomainIsActive(dom) == 0)
|
|
|
|
flags = VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
|
2017-04-11 15:33:53 +00:00
|
|
|
if (virshDomainGetXMLFromDom(ctl, dom, xmlflags, &xml, &ctxt) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
if ((nnodes = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes)) <= 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, _("Failed to extract interface information or no interfaces found"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
for (i = 0; i < nnodes; i++) {
|
|
|
|
g_autofree char *macaddr = NULL;
|
|
|
|
g_autofree char *target = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
ctxt->node = nodes[i];
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
if ((macaddr = virXPathString("string(./mac/@address)", ctxt)) &&
|
|
|
|
STRCASEEQ(macaddr, iface)) {
|
|
|
|
ifaceNode = nodes[i];
|
|
|
|
break;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
if ((target = virXPathString("string(./target/@dev)", ctxt)) &&
|
|
|
|
STRCASEEQ(target, iface)) {
|
|
|
|
ifaceNode = nodes[i];
|
|
|
|
break;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
if (!ifaceNode) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("interface '%1$s' not found"), iface);
|
2022-10-19 08:39:33 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
ctxt->node = ifaceNode;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
/* try to find <link> element or create new one */
|
|
|
|
if (!(linkNode = virXPathNode("./link", ctxt))) {
|
|
|
|
if (!(linkNode = xmlNewChild(ifaceNode, NULL, BAD_CAST "link", NULL))) {
|
|
|
|
vshError(ctl, _("failed to create XML node"));
|
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-30 09:55:22 +00:00
|
|
|
if (xmlHasProp(linkNode, BAD_CAST "state"))
|
2022-10-19 08:39:33 +00:00
|
|
|
stateAttr = xmlSetProp(linkNode, BAD_CAST "state", BAD_CAST state);
|
|
|
|
else
|
|
|
|
stateAttr = xmlNewProp(linkNode, BAD_CAST "state", BAD_CAST state);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
if (!stateAttr) {
|
|
|
|
vshError(ctl, _("Failed to create or modify the state XML attribute"));
|
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-10-19 08:39:33 +00:00
|
|
|
if (!(xml_buf = virXMLNodeToString(xml, ifaceNode))) {
|
2013-09-04 15:27:27 +00:00
|
|
|
vshSaveLibvirtError();
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, _("Failed to create XML"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-11-30 15:04:03 +00:00
|
|
|
if (vshCommandOptBool(cmd, "print-xml")) {
|
|
|
|
vshPrint(ctl, "%s", xml_buf);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-04 15:27:27 +00:00
|
|
|
if (virDomainUpdateDeviceFlags(dom, xml_buf, flags) < 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, _("Failed to update interface link state"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Device updated successfully\n"));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* "domiftune" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domiftune[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("get/set parameters of a virtual interface")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get/set parameters of a domain's virtual interface.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domiftune[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "interface",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2017-11-06 14:48:01 +00:00
|
|
|
.completer = virshDomainInterfaceCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("interface device (MAC Address)")
|
|
|
|
},
|
|
|
|
{.name = "inbound",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("control domain's incoming traffics")
|
|
|
|
},
|
|
|
|
{.name = "outbound",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("control domain's outgoing traffics")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomIftune(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name = NULL, *device = NULL,
|
|
|
|
*inboundStr = NULL, *outboundStr = NULL;
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
int nparams = 0;
|
2013-01-15 23:04:33 +00:00
|
|
|
int maxparams = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
virNetDevBandwidthRate inbound, outbound;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "interface", &device) < 0)
|
2013-01-15 23:04:33 +00:00
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "inbound", &inboundStr) < 0 ||
|
2013-11-19 22:50:56 +00:00
|
|
|
vshCommandOptStringReq(ctl, cmd, "outbound", &outboundStr) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
memset(&inbound, 0, sizeof(inbound));
|
|
|
|
memset(&outbound, 0, sizeof(outbound));
|
|
|
|
|
|
|
|
if (inboundStr) {
|
2015-06-15 16:53:58 +00:00
|
|
|
if (virshParseRateStr(ctl, inboundStr, &inbound) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
2014-06-26 08:06:57 +00:00
|
|
|
/* we parse the rate as unsigned long long, but the API
|
|
|
|
* only accepts UINT */
|
|
|
|
if (inbound.average > UINT_MAX || inbound.peak > UINT_MAX ||
|
|
|
|
inbound.burst > UINT_MAX) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("inbound rate larger than maximum %1$u"),
|
2014-06-26 08:06:57 +00:00
|
|
|
UINT_MAX);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-08-01 07:48:04 +00:00
|
|
|
|
|
|
|
if ((!inbound.average && (inbound.burst || inbound.peak)) &&
|
|
|
|
!inbound.floor) {
|
|
|
|
vshError(ctl, _("either inbound average or floor is mandatory"));
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-01-15 23:04:33 +00:00
|
|
|
|
|
|
|
if (virTypedParamsAddUInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
|
|
|
|
inbound.average) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
|
|
|
if (inbound.peak &&
|
|
|
|
virTypedParamsAddUInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BANDWIDTH_IN_PEAK,
|
|
|
|
inbound.peak) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
|
|
|
if (inbound.burst &&
|
|
|
|
virTypedParamsAddUInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BANDWIDTH_IN_BURST,
|
|
|
|
inbound.burst) < 0)
|
|
|
|
goto save_error;
|
2015-08-01 07:48:04 +00:00
|
|
|
|
|
|
|
if (inbound.floor &&
|
|
|
|
virTypedParamsAddUInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BANDWIDTH_IN_FLOOR,
|
|
|
|
inbound.floor) < 0)
|
|
|
|
goto save_error;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2013-01-15 23:04:33 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (outboundStr) {
|
2015-06-15 16:53:58 +00:00
|
|
|
if (virshParseRateStr(ctl, outboundStr, &outbound) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
2014-06-26 08:06:57 +00:00
|
|
|
if (outbound.average > UINT_MAX || outbound.peak > UINT_MAX ||
|
|
|
|
outbound.burst > UINT_MAX) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("outbound rate larger than maximum %1$u"),
|
2014-06-26 08:06:57 +00:00
|
|
|
UINT_MAX);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2014-03-18 09:50:02 +00:00
|
|
|
if (outbound.average == 0 && (outbound.burst || outbound.peak)) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, _("outbound average is mandatory"));
|
|
|
|
goto cleanup;
|
2015-08-01 07:48:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (outbound.floor) {
|
|
|
|
vshError(ctl, _("outbound floor is unsupported yet"));
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2013-01-15 23:04:33 +00:00
|
|
|
|
|
|
|
if (virTypedParamsAddUInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
|
|
|
|
outbound.average) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
|
|
|
if (outbound.peak &&
|
|
|
|
virTypedParamsAddUInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
|
|
|
|
outbound.peak) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
|
|
|
if (outbound.burst &&
|
|
|
|
virTypedParamsAddUInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_BANDWIDTH_OUT_BURST,
|
|
|
|
outbound.burst) < 0)
|
|
|
|
goto save_error;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (nparams == 0) {
|
|
|
|
/* get the number of interface parameters */
|
|
|
|
if (virDomainGetInterfaceParameters(dom, device, NULL, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Unable to get number of interface parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nparams == 0) {
|
|
|
|
/* nothing to output */
|
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get all interface parameters */
|
2020-10-05 16:50:09 +00:00
|
|
|
params = g_new0(virTypedParameter, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (virDomainGetInterfaceParameters(dom, device, params, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to get interface parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
2012-07-25 15:37:18 +00:00
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
|
|
|
|
}
|
|
|
|
} else {
|
2013-01-15 23:04:33 +00:00
|
|
|
if (virDomainSetInterfaceParameters(dom, device, params,
|
|
|
|
nparams, flags) != 0)
|
|
|
|
goto error;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-01-15 23:04:33 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
2013-01-15 23:04:33 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
save_error:
|
2013-01-15 23:04:33 +00:00
|
|
|
vshSaveLibvirtError();
|
2014-03-25 06:53:59 +00:00
|
|
|
error:
|
2013-01-15 23:04:33 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to set interface parameters"));
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "suspend" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_suspend[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("suspend a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Suspend a running domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_suspend[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_RUNNING),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSuspend(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2021-09-24 15:17:47 +00:00
|
|
|
if (virDomainSuspend(dom) != 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to suspend domain '%1$s'"), name);
|
2021-09-24 15:17:47 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' suspended\n"), name);
|
2021-09-24 15:17:47 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "dompmsuspend" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_dom_pm_suspend[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("suspend a domain gracefully using power management "
|
|
|
|
"functions")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Suspends a running domain using guest OS's power management. "
|
2012-07-25 15:37:18 +00:00
|
|
|
"(Note: This requires a guest agent configured and running in "
|
2013-02-07 15:25:10 +00:00
|
|
|
"the guest OS).")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_dom_pm_suspend[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_RUNNING),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "target",
|
2014-11-11 02:12:20 +00:00
|
|
|
.type = VSH_OT_DATA,
|
2013-01-14 11:26:54 +00:00
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-06-15 00:38:25 +00:00
|
|
|
.completer = virshNodeSuspendTargetCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("mem(Suspend-to-RAM), "
|
|
|
|
"disk(Suspend-to-Disk), "
|
|
|
|
"hybrid(Hybrid-Suspend)")
|
|
|
|
},
|
2014-11-11 09:45:24 +00:00
|
|
|
{.name = "duration",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
|
|
|
.help = N_("duration in seconds")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomPMSuspend(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
const char *target = NULL;
|
2021-06-15 00:38:24 +00:00
|
|
|
int suspendTarget;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned long long duration = 0;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptULongLong(ctl, cmd, "duration", &duration) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "target", &target) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-07-19 11:23:29 +00:00
|
|
|
if ((suspendTarget = virshNodeSuspendTargetTypeFromString(target)) < 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, "%s", _("Invalid target"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainPMSuspendForDuration(dom, suspendTarget, duration, 0) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Domain '%1$s' could not be suspended"),
|
2012-07-25 15:37:18 +00:00
|
|
|
virDomainGetName(dom));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' successfully suspended"),
|
2012-07-25 15:37:18 +00:00
|
|
|
virDomainGetName(dom));
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "dompmwakeup" command
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const vshCmdInfo info_dom_pm_wakeup[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("wakeup a domain from pmsuspended state")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Wakeup a domain that was previously suspended "
|
|
|
|
"by power management.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_dom_pm_wakeup[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_OTHER),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomPMWakeup(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainPMWakeup(dom, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Domain '%1$s' could not be woken up"),
|
2012-07-25 15:37:18 +00:00
|
|
|
virDomainGetName(dom));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' successfully woken up"),
|
2016-08-24 14:14:23 +00:00
|
|
|
virDomainGetName(dom));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "undefine" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_undefine[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("undefine a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Undefine an inactive domain, or convert persistent to transient.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_undefine[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_PERSISTENT),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "managed-save",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("remove domain managed state file")
|
|
|
|
},
|
|
|
|
{.name = "storage",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-16 13:11:03 +00:00
|
|
|
.completer = virshDomainUndefineStorageDisksCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("remove associated storage volumes (comma separated list of "
|
|
|
|
"targets or source paths) (see domblklist)")
|
|
|
|
},
|
|
|
|
{.name = "remove-all-storage",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("remove all associated storage volumes (use with caution)")
|
|
|
|
},
|
2015-12-02 23:04:04 +00:00
|
|
|
{.name = "delete-snapshots",
|
2019-06-05 11:06:58 +00:00
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "delete-storage-volume-snapshots"
|
|
|
|
},
|
|
|
|
{.name = "delete-storage-volume-snapshots",
|
2015-12-02 23:04:04 +00:00
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("delete snapshots associated with volume(s), requires "
|
|
|
|
"--remove-all-storage (must be supported by storage driver)")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "wipe-storage",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("wipe data on the removed volumes")
|
|
|
|
},
|
|
|
|
{.name = "snapshots-metadata",
|
|
|
|
.type = VSH_OT_BOOL,
|
2019-06-05 10:57:42 +00:00
|
|
|
.help = N_("remove all domain snapshot metadata (vm must be inactive)")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
2019-03-13 21:04:51 +00:00
|
|
|
{.name = "checkpoints-metadata",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("remove all domain checkpoint metadata (vm must be inactive)")
|
|
|
|
},
|
2014-09-11 11:17:11 +00:00
|
|
|
{.name = "nvram",
|
|
|
|
.type = VSH_OT_BOOL,
|
2021-09-30 14:32:19 +00:00
|
|
|
.help = N_("remove nvram file")
|
2014-09-11 11:17:11 +00:00
|
|
|
},
|
2016-05-27 08:05:16 +00:00
|
|
|
{.name = "keep-nvram",
|
|
|
|
.type = VSH_OT_BOOL,
|
2021-09-30 14:32:19 +00:00
|
|
|
.help = N_("keep nvram file")
|
2016-05-27 08:05:16 +00:00
|
|
|
},
|
2022-10-04 13:38:13 +00:00
|
|
|
{.name = "tpm",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("remove TPM state")
|
|
|
|
},
|
|
|
|
{.name = "keep-tpm",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("keep TPM state")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2012-06-22 12:16:24 +00:00
|
|
|
typedef struct {
|
|
|
|
virStorageVolPtr vol;
|
|
|
|
char *source;
|
|
|
|
char *target;
|
2015-06-15 16:53:58 +00:00
|
|
|
} virshUndefineVolume;
|
2012-06-22 12:16:24 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdUndefine(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool ret = false;
|
|
|
|
const char *name = NULL;
|
|
|
|
/* Flags to attempt. */
|
|
|
|
unsigned int flags = 0;
|
2015-12-02 23:04:04 +00:00
|
|
|
unsigned int vol_flags = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
/* User-requested actions. */
|
|
|
|
bool managed_save = vshCommandOptBool(cmd, "managed-save");
|
|
|
|
bool snapshots_metadata = vshCommandOptBool(cmd, "snapshots-metadata");
|
2019-03-13 21:04:51 +00:00
|
|
|
bool checkpoints_metadata = vshCommandOptBool(cmd, "checkpoints-metadata");
|
2012-07-25 15:37:18 +00:00
|
|
|
bool wipe_storage = vshCommandOptBool(cmd, "wipe-storage");
|
|
|
|
bool remove_all_storage = vshCommandOptBool(cmd, "remove-all-storage");
|
2020-04-09 13:25:35 +00:00
|
|
|
bool delete_snapshots = vshCommandOptBool(cmd, "delete-storage-volume-snapshots");
|
2014-09-11 11:17:11 +00:00
|
|
|
bool nvram = vshCommandOptBool(cmd, "nvram");
|
2016-05-27 08:05:16 +00:00
|
|
|
bool keep_nvram = vshCommandOptBool(cmd, "keep-nvram");
|
2022-10-04 13:38:13 +00:00
|
|
|
bool tpm = vshCommandOptBool(cmd, "tpm");
|
|
|
|
bool keep_tpm = vshCommandOptBool(cmd, "keep-tpm");
|
2012-07-25 15:37:18 +00:00
|
|
|
/* Positive if these items exist. */
|
|
|
|
int has_managed_save = 0;
|
|
|
|
int has_snapshots_metadata = 0;
|
|
|
|
int has_snapshots = 0;
|
|
|
|
/* True if undefine will not strand data, even on older servers. */
|
|
|
|
bool managed_save_safe = false;
|
|
|
|
bool snapshots_safe = false;
|
|
|
|
int rc = -1;
|
|
|
|
int running;
|
|
|
|
/* list of volumes to remove along with this domain */
|
2013-08-15 14:48:20 +00:00
|
|
|
const char *vol_string = NULL; /* string containing volumes to delete */
|
|
|
|
char **vol_list = NULL; /* tokenized vol_string */
|
|
|
|
int nvol_list = 0;
|
2020-01-24 20:30:04 +00:00
|
|
|
virshUndefineVolume *vols = NULL; /* info about the volumes to delete */
|
2013-08-15 14:48:20 +00:00
|
|
|
size_t nvols = 0;
|
2021-08-11 11:57:15 +00:00
|
|
|
g_autoptr(xmlDoc) doc = NULL;
|
2021-08-11 11:21:18 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2013-08-15 14:48:20 +00:00
|
|
|
xmlNodePtr *vol_nodes = NULL; /* XML nodes of volumes of the guest */
|
|
|
|
int nvol_nodes;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
|
|
|
size_t j;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-06-22 12:16:24 +00:00
|
|
|
|
2020-04-09 13:25:35 +00:00
|
|
|
VSH_REQUIRE_OPTION("delete-storage-volume-snapshots", "remove-all-storage");
|
2016-05-27 08:05:16 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("nvram", "keep-nvram");
|
2022-10-04 13:38:13 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("tpm", "keep-tpm");
|
2015-12-02 23:04:04 +00:00
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
ignore_value(vshCommandOptStringQuiet(ctl, cmd, "storage", &vol_string));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-05-14 06:15:37 +00:00
|
|
|
if (!(vol_string || remove_all_storage) && wipe_storage) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("'--wipe-storage' requires '--storage <string>' or "
|
|
|
|
"'--remove-all-storage'"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-12-02 23:04:04 +00:00
|
|
|
if (delete_snapshots)
|
|
|
|
vol_flags |= VIR_STORAGE_VOL_DELETE_WITH_SNAPSHOTS;
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (managed_save) {
|
|
|
|
flags |= VIR_DOMAIN_UNDEFINE_MANAGED_SAVE;
|
|
|
|
managed_save_safe = true;
|
|
|
|
}
|
|
|
|
if (snapshots_metadata) {
|
|
|
|
flags |= VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA;
|
|
|
|
snapshots_safe = true;
|
|
|
|
}
|
2019-03-13 21:04:51 +00:00
|
|
|
if (checkpoints_metadata)
|
|
|
|
flags |= VIR_DOMAIN_UNDEFINE_CHECKPOINTS_METADATA;
|
2014-11-13 14:20:51 +00:00
|
|
|
if (nvram)
|
2014-09-11 11:17:11 +00:00
|
|
|
flags |= VIR_DOMAIN_UNDEFINE_NVRAM;
|
2016-05-27 08:05:16 +00:00
|
|
|
if (keep_nvram)
|
|
|
|
flags |= VIR_DOMAIN_UNDEFINE_KEEP_NVRAM;
|
2022-10-04 13:38:13 +00:00
|
|
|
if (tpm)
|
|
|
|
flags |= VIR_DOMAIN_UNDEFINE_TPM;
|
|
|
|
if (keep_tpm)
|
|
|
|
flags |= VIR_DOMAIN_UNDEFINE_KEEP_TPM;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Do some flag manipulation. The goal here is to disable bits
|
|
|
|
* from flags to reduce the likelihood of a server rejecting
|
|
|
|
* unknown flag bits, as well as to track conditions which are
|
|
|
|
* safe by default for the given hypervisor and server version. */
|
2012-06-22 12:16:24 +00:00
|
|
|
if ((running = virDomainIsActive(dom)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (!running) {
|
|
|
|
/* Undefine with snapshots only fails for inactive domains,
|
|
|
|
* and managed save only exists on inactive domains; if
|
|
|
|
* running, then we don't want to remove anything. */
|
|
|
|
has_managed_save = virDomainHasManagedSaveImage(dom, 0);
|
|
|
|
if (has_managed_save < 0) {
|
2012-06-22 12:16:24 +00:00
|
|
|
if (last_error->code != VIR_ERR_NO_SUPPORT)
|
|
|
|
goto error;
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2012-07-25 15:37:18 +00:00
|
|
|
has_managed_save = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
has_snapshots = virDomainSnapshotNum(dom, 0);
|
|
|
|
if (has_snapshots < 0) {
|
2012-06-22 12:16:24 +00:00
|
|
|
if (last_error->code != VIR_ERR_NO_SUPPORT)
|
|
|
|
goto error;
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2012-07-25 15:37:18 +00:00
|
|
|
has_snapshots = 0;
|
|
|
|
}
|
|
|
|
if (has_snapshots) {
|
|
|
|
has_snapshots_metadata
|
|
|
|
= virDomainSnapshotNum(dom, VIR_DOMAIN_SNAPSHOT_LIST_METADATA);
|
|
|
|
if (has_snapshots_metadata < 0) {
|
|
|
|
/* The server did not know the new flag, assume that all
|
|
|
|
snapshots have metadata. */
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2012-07-25 15:37:18 +00:00
|
|
|
has_snapshots_metadata = has_snapshots;
|
|
|
|
} else {
|
|
|
|
/* The server knew the new flag, all aspects of
|
|
|
|
* undefineFlags are safe. */
|
|
|
|
managed_save_safe = snapshots_safe = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!has_managed_save) {
|
|
|
|
flags &= ~VIR_DOMAIN_UNDEFINE_MANAGED_SAVE;
|
|
|
|
managed_save_safe = true;
|
|
|
|
}
|
2014-11-13 14:20:51 +00:00
|
|
|
if (has_snapshots == 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
snapshots_safe = true;
|
|
|
|
if (has_snapshots_metadata == 0) {
|
|
|
|
flags &= ~VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA;
|
|
|
|
snapshots_safe = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Stash domain description for later use */
|
2013-08-15 14:48:20 +00:00
|
|
|
if (vol_string || remove_all_storage) {
|
2012-07-25 15:37:18 +00:00
|
|
|
if (running) {
|
2013-08-15 14:48:20 +00:00
|
|
|
vshError(ctl,
|
|
|
|
_("Storage volume deletion is supported only on "
|
|
|
|
"stopped domains"));
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-08-15 14:48:20 +00:00
|
|
|
if (vol_string && remove_all_storage) {
|
|
|
|
vshError(ctl,
|
|
|
|
_("Specified both --storage and --remove-all-storage"));
|
2012-06-22 12:16:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-04-11 15:33:53 +00:00
|
|
|
if (virshDomainGetXMLFromDom(ctl, dom, 0, &doc, &ctxt) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
2012-06-22 12:16:24 +00:00
|
|
|
|
2013-10-17 01:42:25 +00:00
|
|
|
/* tokenize the string from user and save its parts into an array */
|
2013-08-15 14:48:20 +00:00
|
|
|
if (vol_string &&
|
|
|
|
(nvol_list = vshStringToArray(vol_string, &vol_list)) < 0)
|
2012-06-22 12:16:24 +00:00
|
|
|
goto error;
|
|
|
|
|
2013-08-15 14:48:20 +00:00
|
|
|
if ((nvol_nodes = virXPathNodeSet("./devices/disk", ctxt,
|
|
|
|
&vol_nodes)) < 0)
|
|
|
|
goto error;
|
2012-06-22 12:16:24 +00:00
|
|
|
|
2013-08-15 14:48:20 +00:00
|
|
|
for (i = 0; i < nvol_nodes; i++) {
|
2021-08-11 13:25:20 +00:00
|
|
|
g_autofree char *source = NULL;
|
|
|
|
g_autofree char *target = NULL;
|
|
|
|
g_autofree char *pool = NULL;
|
2015-06-15 16:53:58 +00:00
|
|
|
virshUndefineVolume vol;
|
2020-08-03 15:27:58 +00:00
|
|
|
|
|
|
|
ctxt->node = vol_nodes[i];
|
|
|
|
|
2012-06-22 12:16:24 +00:00
|
|
|
/* get volume source and target paths */
|
|
|
|
if (!(target = virXPathString("string(./target/@dev)", ctxt)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(source = virXPathString("string("
|
|
|
|
"./source/@file|"
|
|
|
|
"./source/@dir|"
|
|
|
|
"./source/@name|"
|
2013-12-18 13:54:07 +00:00
|
|
|
"./source/@dev|"
|
|
|
|
"./source/@volume)", ctxt)))
|
2013-08-15 14:48:20 +00:00
|
|
|
continue;
|
2012-06-22 12:16:24 +00:00
|
|
|
|
2013-12-18 13:54:07 +00:00
|
|
|
pool = virXPathString("string(./source/@pool)", ctxt);
|
|
|
|
|
2012-06-22 12:16:24 +00:00
|
|
|
/* lookup if volume was selected by user */
|
2013-08-15 14:48:20 +00:00
|
|
|
if (vol_list) {
|
|
|
|
bool found = false;
|
|
|
|
for (j = 0; j < nvol_list; j++) {
|
|
|
|
if (STREQ_NULLABLE(vol_list[j], target) ||
|
|
|
|
STREQ_NULLABLE(vol_list[j], source)) {
|
|
|
|
VIR_FREE(vol_list[j]);
|
|
|
|
found = true;
|
2012-06-22 12:16:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-08-15 14:48:20 +00:00
|
|
|
if (!found)
|
2012-06-22 12:16:24 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-12-18 13:54:07 +00:00
|
|
|
if (pool) {
|
2021-09-26 07:25:41 +00:00
|
|
|
g_autoptr(virshStoragePool) storagepool = NULL;
|
2013-12-18 13:54:07 +00:00
|
|
|
|
|
|
|
if (!source) {
|
2016-11-04 14:21:31 +00:00
|
|
|
vshError(ctl,
|
2023-03-09 14:54:42 +00:00
|
|
|
_("Missing storage volume name for disk '%1$s'"),
|
2013-12-18 13:54:07 +00:00
|
|
|
target);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(storagepool = virStoragePoolLookupByName(priv->conn,
|
2013-12-18 13:54:07 +00:00
|
|
|
pool))) {
|
2016-11-04 14:21:31 +00:00
|
|
|
vshError(ctl,
|
2023-03-09 14:54:42 +00:00
|
|
|
_("Storage pool '%1$s' for volume '%2$s' not found."),
|
2013-12-18 13:54:07 +00:00
|
|
|
pool, target);
|
|
|
|
vshResetLibvirtError();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
vol.vol = virStorageVolLookupByName(storagepool, source);
|
|
|
|
|
|
|
|
} else {
|
2015-06-15 16:53:58 +00:00
|
|
|
vol.vol = virStorageVolLookupByPath(priv->conn, source);
|
2013-12-18 13:54:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!vol.vol) {
|
2016-11-04 14:21:31 +00:00
|
|
|
vshError(ctl,
|
2023-03-09 14:54:42 +00:00
|
|
|
_("Storage volume '%1$s'(%2$s) is not managed by libvirt. Remove it manually.\n"),
|
|
|
|
target, source);
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2012-06-22 12:16:24 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-08-15 14:48:20 +00:00
|
|
|
|
2021-03-24 09:32:58 +00:00
|
|
|
vol.source = g_steal_pointer(&source);
|
|
|
|
vol.target = g_steal_pointer(&target);
|
2021-08-03 12:14:20 +00:00
|
|
|
VIR_APPEND_ELEMENT(vols, nvols, vol);
|
2012-06-22 12:16:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* print volumes specified by user that were not found in domain definition */
|
2013-08-15 14:48:20 +00:00
|
|
|
if (vol_list) {
|
|
|
|
bool found = false;
|
|
|
|
for (i = 0; i < nvol_list; i++) {
|
|
|
|
if (vol_list[i]) {
|
|
|
|
vshError(ctl,
|
2023-03-09 14:54:42 +00:00
|
|
|
_("Volume '%1$s' was not found in domain's definition.\n"),
|
|
|
|
vol_list[i]);
|
2013-08-15 14:48:20 +00:00
|
|
|
found = true;
|
2012-06-22 12:16:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-15 14:48:20 +00:00
|
|
|
if (found)
|
2012-06-22 12:16:24 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Generally we want to try the new API first. However, while
|
|
|
|
* virDomainUndefineFlags was introduced at the same time as
|
|
|
|
* VIR_DOMAIN_UNDEFINE_MANAGED_SAVE in 0.9.4, the
|
|
|
|
* VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA flag was not present
|
|
|
|
* until 0.9.5; skip to piecewise emulation if we couldn't prove
|
2014-09-11 11:17:11 +00:00
|
|
|
* above that the new API is safe.
|
|
|
|
* Moreover, only the newer UndefineFlags() API understands
|
|
|
|
* the VIR_DOMAIN_UNDEFINE_NVRAM flag. So if user has
|
|
|
|
* specified --nvram we must use the Flags() API. */
|
|
|
|
if ((managed_save_safe && snapshots_safe) || nvram) {
|
2012-07-25 15:37:18 +00:00
|
|
|
rc = virDomainUndefineFlags(dom, flags);
|
2014-09-11 11:17:11 +00:00
|
|
|
if (rc == 0 || nvram ||
|
|
|
|
(last_error->code != VIR_ERR_NO_SUPPORT &&
|
|
|
|
last_error->code != VIR_ERR_INVALID_ARG))
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The new API is unsupported or unsafe; fall back to doing things
|
|
|
|
* piecewise. */
|
|
|
|
if (has_managed_save) {
|
|
|
|
if (!managed_save) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Refusing to undefine while domain managed save "
|
|
|
|
"image exists"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (virDomainManagedSaveRemove(dom, 0) < 0) {
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No way to emulate deletion of just snapshot metadata
|
|
|
|
* without support for the newer flags. Oh well. */
|
|
|
|
if (has_snapshots_metadata) {
|
2022-02-28 17:40:01 +00:00
|
|
|
if (snapshots_metadata)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unable to remove metadata of %1$d snapshots"),
|
2022-02-28 17:40:01 +00:00
|
|
|
has_snapshots_metadata);
|
|
|
|
else
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Refusing to undefine while %1$d snapshots exist"),
|
2022-02-28 17:40:01 +00:00
|
|
|
has_snapshots_metadata);
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = virDomainUndefine(dom);
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
out:
|
2012-07-25 15:37:18 +00:00
|
|
|
if (rc == 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' has been undefined\n"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = true;
|
|
|
|
} else {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to undefine domain '%1$s'"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try to undefine storage volumes associated with this domain, if it's requested */
|
2012-06-22 12:16:24 +00:00
|
|
|
if (nvols) {
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
for (i = 0; i < nvols; i++) {
|
2012-07-25 15:37:18 +00:00
|
|
|
if (wipe_storage) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Wiping volume '%1$s'(%2$s) ... "),
|
2016-08-24 14:14:23 +00:00
|
|
|
vols[i].target, vols[i].source);
|
2012-07-25 15:37:18 +00:00
|
|
|
fflush(stdout);
|
2013-08-15 14:48:20 +00:00
|
|
|
if (virStorageVolWipe(vols[i].vol, 0) < 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, _("Failed! Volume not removed."));
|
2012-06-22 12:16:24 +00:00
|
|
|
ret = false;
|
2012-07-25 15:37:18 +00:00
|
|
|
continue;
|
|
|
|
} else {
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, _("Done.\n"));
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete the volume */
|
2015-12-02 23:04:04 +00:00
|
|
|
if (virStorageVolDelete(vols[i].vol, vol_flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to remove storage volume '%1$s'(%2$s)"),
|
2013-08-15 14:48:20 +00:00
|
|
|
vols[i].target, vols[i].source);
|
2012-06-22 12:16:24 +00:00
|
|
|
ret = false;
|
|
|
|
} else {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Volume '%1$s'(%2$s) removed.\n"),
|
2016-08-24 14:14:23 +00:00
|
|
|
vols[i].target, vols[i].source);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
for (i = 0; i < nvols; i++) {
|
2013-08-15 14:48:20 +00:00
|
|
|
VIR_FREE(vols[i].source);
|
|
|
|
VIR_FREE(vols[i].target);
|
2021-09-26 08:28:06 +00:00
|
|
|
virshStorageVolFree(vols[i].vol);
|
2012-06-22 12:16:24 +00:00
|
|
|
}
|
2013-08-15 14:48:20 +00:00
|
|
|
VIR_FREE(vols);
|
|
|
|
|
|
|
|
for (i = 0; i < nvol_list; i++)
|
|
|
|
VIR_FREE(vol_list[i]);
|
|
|
|
VIR_FREE(vol_list);
|
2012-06-22 12:16:24 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
VIR_FREE(vol_nodes);
|
|
|
|
return ret;
|
2012-06-22 12:16:24 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
error:
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
2012-06-22 12:16:24 +00:00
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "start" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_start[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("start a (previously defined) inactive domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Start a domain, either from the last managedsave\n"
|
2012-07-25 15:37:18 +00:00
|
|
|
" state, or via a fresh boot if no managedsave state\n"
|
2013-02-07 15:25:10 +00:00
|
|
|
" is present.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_start[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN(N_("name of the inactive domain"),
|
|
|
|
VIR_CONNECT_LIST_DOMAINS_SHUTOFF),
|
2012-07-25 15:37:18 +00:00
|
|
|
#ifndef WIN32
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "console",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("attach to console after creation")
|
|
|
|
},
|
2012-07-25 15:37:18 +00:00
|
|
|
#endif
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("leave the guest paused after creation")
|
|
|
|
},
|
|
|
|
{.name = "autodestroy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("automatically destroy the guest when virsh disconnects")
|
|
|
|
},
|
|
|
|
{.name = "bypass-cache",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("avoid file system cache when loading")
|
|
|
|
},
|
|
|
|
{.name = "force-boot",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("force fresh boot by discarding any managed save")
|
|
|
|
},
|
2013-07-11 15:32:14 +00:00
|
|
|
{.name = "pass-fds",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-07-11 15:32:14 +00:00
|
|
|
.help = N_("pass file descriptors N,M,... to the guest")
|
|
|
|
},
|
2022-02-03 16:42:28 +00:00
|
|
|
{.name = "reset-nvram",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("re-initialize NVRAM from its pristine template")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdStart(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
bool console = vshCommandOptBool(cmd, "console");
|
|
|
|
#endif
|
|
|
|
unsigned int flags = VIR_DOMAIN_NONE;
|
|
|
|
int rc;
|
2013-07-11 15:32:14 +00:00
|
|
|
size_t nfds = 0;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree int *fds = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomainBy(ctl, cmd, NULL,
|
|
|
|
VIRSH_BYNAME | VIRSH_BYUUID)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainGetID(dom) != (unsigned int)-1) {
|
|
|
|
vshError(ctl, "%s", _("Domain is already active"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-01-27 16:22:04 +00:00
|
|
|
if (virshFetchPassFdsList(ctl, cmd, &nfds, &fds) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-07-11 15:32:14 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
flags |= VIR_DOMAIN_START_PAUSED;
|
|
|
|
if (vshCommandOptBool(cmd, "autodestroy"))
|
|
|
|
flags |= VIR_DOMAIN_START_AUTODESTROY;
|
|
|
|
if (vshCommandOptBool(cmd, "bypass-cache"))
|
|
|
|
flags |= VIR_DOMAIN_START_BYPASS_CACHE;
|
|
|
|
if (vshCommandOptBool(cmd, "force-boot"))
|
|
|
|
flags |= VIR_DOMAIN_START_FORCE_BOOT;
|
2022-02-03 16:42:28 +00:00
|
|
|
if (vshCommandOptBool(cmd, "reset-nvram"))
|
|
|
|
flags |= VIR_DOMAIN_START_RESET_NVRAM;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* We can emulate force boot, even for older servers that reject it. */
|
|
|
|
if (flags & VIR_DOMAIN_START_FORCE_BOOT) {
|
2022-02-28 13:50:19 +00:00
|
|
|
if (nfds > 0) {
|
|
|
|
rc = virDomainCreateWithFiles(dom, nfds, fds, flags);
|
|
|
|
} else {
|
|
|
|
rc = virDomainCreateWithFlags(dom, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto started;
|
2022-02-28 13:50:19 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (last_error->code != VIR_ERR_NO_SUPPORT &&
|
|
|
|
last_error->code != VIR_ERR_INVALID_ARG) {
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2012-07-25 15:37:18 +00:00
|
|
|
rc = virDomainHasManagedSaveImage(dom, 0);
|
|
|
|
if (rc < 0) {
|
|
|
|
/* No managed save image to remove */
|
2012-07-25 11:41:49 +00:00
|
|
|
vshResetLibvirtError();
|
2012-07-25 15:37:18 +00:00
|
|
|
} else if (rc > 0) {
|
|
|
|
if (virDomainManagedSaveRemove(dom, 0) < 0) {
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
vshReportError(ctl);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
flags &= ~VIR_DOMAIN_START_FORCE_BOOT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prefer older API unless we have to pass a flag. */
|
2022-02-28 13:50:19 +00:00
|
|
|
if (nfds > 0) {
|
|
|
|
rc = virDomainCreateWithFiles(dom, nfds, fds, flags);
|
|
|
|
} else if (flags != 0) {
|
|
|
|
rc = virDomainCreateWithFlags(dom, flags);
|
|
|
|
} else {
|
|
|
|
rc = virDomainCreate(dom);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to start domain '%1$s'"), virDomainGetName(dom));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
started:
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' started\n"),
|
2016-08-24 14:14:23 +00:00
|
|
|
virDomainGetName(dom));
|
2012-07-25 15:37:18 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
if (console && !cmdRunConsole(ctl, dom, NULL, 0))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
#endif
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "save" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_save[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("save a domain state to a file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Save the RAM state of a running domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_save[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2021-09-16 11:03:02 +00:00
|
|
|
{.name = "file",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("where to save the data")
|
|
|
|
},
|
2014-11-11 09:45:24 +00:00
|
|
|
{.name = "bypass-cache",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("avoid file system cache when saving")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "xml",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("filename containing updated XML for the target")
|
|
|
|
},
|
|
|
|
{.name = "running",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be running on restore")
|
|
|
|
},
|
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be paused on restore")
|
|
|
|
},
|
|
|
|
{.name = "verbose",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("display the progress of save")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
doSave(void *opaque)
|
|
|
|
{
|
2015-06-15 16:53:58 +00:00
|
|
|
virshCtrlData *data = opaque;
|
2012-07-25 15:37:18 +00:00
|
|
|
vshControl *ctl = data->ctl;
|
|
|
|
const vshCmd *cmd = data->cmd;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name = NULL;
|
|
|
|
const char *to = NULL;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
const char *xmlfile = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2022-02-28 14:00:00 +00:00
|
|
|
int rc;
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-07-25 15:37:18 +00:00
|
|
|
sigset_t sigmask, oldsigmask;
|
|
|
|
|
|
|
|
sigemptyset(&sigmask);
|
|
|
|
sigaddset(&sigmask, SIGINT);
|
2021-02-01 12:42:01 +00:00
|
|
|
if (pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask) != 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out_sig;
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &to) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "bypass-cache"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_BYPASS_CACHE;
|
|
|
|
if (vshCommandOptBool(cmd, "running"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_RUNNING;
|
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_PAUSED;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "xml", &xmlfile) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (xmlfile &&
|
2014-10-14 08:04:31 +00:00
|
|
|
virFileReadAll(xmlfile, VSH_MAX_XML_FILE, &xml) < 0) {
|
2012-11-15 13:25:09 +00:00
|
|
|
vshReportError(ctl);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
2012-11-15 13:25:09 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 14:00:00 +00:00
|
|
|
if (flags || xml) {
|
|
|
|
rc = virDomainSaveFlags(dom, to, xml, flags);
|
|
|
|
} else {
|
|
|
|
rc = virDomainSave(dom, to);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to save domain '%1$s' to %2$s"), name, to);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
data->ret = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
out:
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-07-25 15:37:18 +00:00
|
|
|
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
|
2014-03-25 06:53:59 +00:00
|
|
|
out_sig:
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2020-02-05 14:16:16 +00:00
|
|
|
g_main_loop_quit(data->eventLoop);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2012-10-17 09:23:12 +00:00
|
|
|
typedef void (*jobWatchTimeoutFunc)(vshControl *ctl, virDomainPtr dom,
|
|
|
|
void *opaque);
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
struct virshWatchData {
|
|
|
|
vshControl *ctl;
|
|
|
|
virDomainPtr dom;
|
|
|
|
jobWatchTimeoutFunc timeout_func;
|
|
|
|
void *opaque;
|
|
|
|
const char *label;
|
|
|
|
GIOChannel *stdin_ioc;
|
|
|
|
bool jobStarted;
|
|
|
|
bool verbose;
|
|
|
|
};
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
virshWatchTimeout(gpointer opaque)
|
|
|
|
{
|
|
|
|
struct virshWatchData *data = opaque;
|
|
|
|
|
|
|
|
/* suspend the domain when migration timeouts. */
|
|
|
|
vshDebug(data->ctl, VSH_ERR_DEBUG, "watchJob: timeout\n");
|
|
|
|
if (data->timeout_func)
|
|
|
|
(data->timeout_func)(data->ctl, data->dom, data->opaque);
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
virshWatchProgress(gpointer opaque)
|
|
|
|
{
|
|
|
|
struct virshWatchData *data = opaque;
|
|
|
|
virDomainJobInfo jobinfo;
|
|
|
|
int ret;
|
|
|
|
#ifndef WIN32
|
|
|
|
sigset_t sigmask, oldsigmask;
|
|
|
|
|
|
|
|
sigemptyset(&sigmask);
|
|
|
|
sigaddset(&sigmask, SIGINT);
|
|
|
|
|
|
|
|
pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask);
|
|
|
|
#endif /* !WIN32 */
|
|
|
|
vshDebug(data->ctl, VSH_ERR_DEBUG, "%s",
|
|
|
|
"watchJob: progress update\n");
|
|
|
|
ret = virDomainGetJobInfo(data->dom, &jobinfo);
|
|
|
|
#ifndef WIN32
|
|
|
|
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
|
|
|
|
#endif /* !WIN32 */
|
|
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
if (data->verbose && jobinfo.dataTotal > 0)
|
|
|
|
virshPrintJobProgress(data->label, jobinfo.dataRemaining,
|
|
|
|
jobinfo.dataTotal);
|
|
|
|
|
|
|
|
if (!data->jobStarted &&
|
|
|
|
(jobinfo.type == VIR_DOMAIN_JOB_BOUNDED ||
|
|
|
|
jobinfo.type == VIR_DOMAIN_JOB_UNBOUNDED)) {
|
|
|
|
vshTTYDisableInterrupt(data->ctl);
|
|
|
|
data->jobStarted = true;
|
|
|
|
|
|
|
|
if (!data->verbose) {
|
|
|
|
vshDebug(data->ctl, VSH_ERR_DEBUG,
|
|
|
|
"watchJob: job started, disabling callback\n");
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
vshResetLibvirtError();
|
|
|
|
}
|
|
|
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
virshWatchInterrupt(GIOChannel *source G_GNUC_UNUSED,
|
|
|
|
GIOCondition condition,
|
|
|
|
gpointer opaque)
|
|
|
|
{
|
|
|
|
struct virshWatchData *data = opaque;
|
|
|
|
char retchar;
|
|
|
|
gsize nread = 0;
|
|
|
|
|
|
|
|
vshDebug(data->ctl, VSH_ERR_DEBUG,
|
|
|
|
"watchJob: stdin data %d\n", condition);
|
|
|
|
if (condition & G_IO_IN) {
|
|
|
|
g_io_channel_read_chars(data->stdin_ioc,
|
|
|
|
&retchar,
|
|
|
|
sizeof(retchar),
|
|
|
|
&nread,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
vshDebug(data->ctl, VSH_ERR_DEBUG,
|
|
|
|
"watchJob: got %zu characters\n", nread);
|
|
|
|
if (nread == 1 &&
|
|
|
|
vshTTYIsInterruptCharacter(data->ctl, retchar)) {
|
|
|
|
virDomainAbortJob(data->dom);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (condition & (G_IO_ERR | G_IO_HUP)) {
|
|
|
|
virDomainAbortJob(data->dom);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2015-06-15 16:53:58 +00:00
|
|
|
virshWatchJob(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
bool verbose,
|
2020-02-05 14:16:16 +00:00
|
|
|
GMainLoop *eventLoop,
|
|
|
|
int *job_err,
|
|
|
|
int timeout_secs,
|
2015-06-15 16:53:58 +00:00
|
|
|
jobWatchTimeoutFunc timeout_func,
|
|
|
|
void *opaque,
|
|
|
|
const char *label)
|
2012-08-18 03:23:07 +00:00
|
|
|
{
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-08-18 03:23:07 +00:00
|
|
|
struct sigaction sig_action;
|
|
|
|
struct sigaction old_sig_action;
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2020-02-05 14:16:16 +00:00
|
|
|
g_autoptr(GSource) timeout_src = NULL;
|
|
|
|
g_autoptr(GSource) progress_src = NULL;
|
|
|
|
g_autoptr(GSource) stdin_src = NULL;
|
|
|
|
struct virshWatchData data = {
|
|
|
|
.ctl = ctl,
|
|
|
|
.dom = dom,
|
|
|
|
.timeout_func = timeout_func,
|
|
|
|
.opaque = opaque,
|
|
|
|
.label = label,
|
|
|
|
.stdin_ioc = NULL,
|
|
|
|
.jobStarted = false,
|
|
|
|
.verbose = verbose,
|
|
|
|
};
|
2012-08-18 03:23:07 +00:00
|
|
|
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-08-18 03:23:07 +00:00
|
|
|
intCaught = 0;
|
2015-06-15 16:53:58 +00:00
|
|
|
sig_action.sa_sigaction = virshCatchInt;
|
2012-08-18 03:23:07 +00:00
|
|
|
sig_action.sa_flags = SA_SIGINFO;
|
|
|
|
sigemptyset(&sig_action.sa_mask);
|
|
|
|
sigaction(SIGINT, &sig_action, &old_sig_action);
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2012-08-18 03:23:07 +00:00
|
|
|
|
2013-10-22 14:01:26 +00:00
|
|
|
/* don't poll on STDIN if we are not using a terminal */
|
2020-02-05 14:16:16 +00:00
|
|
|
if (vshTTYAvailable(ctl)) {
|
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG, "%s",
|
|
|
|
"watchJob: on TTY, enabling Ctrl-c processing\n");
|
|
|
|
#ifdef WIN32
|
|
|
|
data.stdin_ioc = g_io_channel_win32_new_fd(STDIN_FILENO);
|
|
|
|
#else
|
|
|
|
data.stdin_ioc = g_io_channel_unix_new(STDIN_FILENO);
|
|
|
|
#endif
|
|
|
|
stdin_src = g_io_create_watch(data.stdin_ioc, G_IO_IN);
|
|
|
|
g_source_set_callback(stdin_src,
|
|
|
|
(GSourceFunc)virshWatchInterrupt,
|
|
|
|
&data, NULL);
|
|
|
|
g_source_attach(stdin_src,
|
|
|
|
g_main_loop_get_context(eventLoop));
|
2012-08-18 03:23:07 +00:00
|
|
|
}
|
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
if (timeout_secs) {
|
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG,
|
|
|
|
"watchJob: setting timeout of %d secs\n", timeout_secs);
|
|
|
|
timeout_src = g_timeout_source_new_seconds(timeout_secs);
|
|
|
|
g_source_set_callback(timeout_src,
|
|
|
|
virshWatchTimeout,
|
|
|
|
&data, NULL);
|
|
|
|
g_source_attach(timeout_src,
|
|
|
|
g_main_loop_get_context(eventLoop));
|
|
|
|
}
|
|
|
|
|
|
|
|
progress_src = g_timeout_source_new(500);
|
|
|
|
g_source_set_callback(progress_src,
|
|
|
|
virshWatchProgress,
|
|
|
|
&data, NULL);
|
|
|
|
g_source_attach(progress_src,
|
|
|
|
g_main_loop_get_context(eventLoop));
|
|
|
|
|
|
|
|
g_main_loop_run(eventLoop);
|
|
|
|
|
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG,
|
|
|
|
"watchJob: job done, status %d\n", *job_err);
|
|
|
|
if (*job_err == 0 && verbose) /* print [100 %] */
|
|
|
|
virshPrintJobProgress(label, 0, 1);
|
|
|
|
|
|
|
|
if (timeout_src)
|
|
|
|
g_source_destroy(timeout_src);
|
|
|
|
g_source_destroy(progress_src);
|
|
|
|
if (stdin_src)
|
|
|
|
g_source_destroy(stdin_src);
|
2012-08-18 03:23:07 +00:00
|
|
|
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-08-18 03:23:07 +00:00
|
|
|
sigaction(SIGINT, &old_sig_action, NULL);
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2013-08-29 13:18:20 +00:00
|
|
|
vshTTYRestore(ctl);
|
2020-02-05 14:16:16 +00:00
|
|
|
if (data.stdin_ioc)
|
|
|
|
g_io_channel_unref(data.stdin_ioc);
|
2012-08-18 03:23:07 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdSave(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
virThread workerThread;
|
|
|
|
bool verbose = false;
|
|
|
|
const char *to = NULL;
|
|
|
|
const char *name = NULL;
|
2020-02-05 14:16:16 +00:00
|
|
|
g_autoptr(GMainContext) eventCtxt = g_main_context_new();
|
|
|
|
g_autoptr(GMainLoop) eventLoop = g_main_loop_new(eventCtxt, FALSE);
|
|
|
|
virshCtrlData data = {
|
|
|
|
.ctl = ctl,
|
|
|
|
.cmd = cmd,
|
|
|
|
.eventLoop = eventLoop,
|
|
|
|
.ret = -1,
|
|
|
|
};
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &to) < 0)
|
2021-11-04 14:26:07 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "verbose"))
|
|
|
|
verbose = true;
|
|
|
|
|
|
|
|
if (virThreadCreate(&workerThread,
|
|
|
|
true,
|
|
|
|
doSave,
|
|
|
|
&data) < 0)
|
2021-11-04 14:26:07 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
virshWatchJob(ctl, dom, verbose, eventLoop,
|
|
|
|
&data.ret, 0, NULL, NULL, _("Save"));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
virThreadJoin(&workerThread);
|
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
if (!data.ret)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("\nDomain '%1$s' saved to %2$s\n"), name, to);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
return !data.ret;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "save-image-dumpxml" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_save_image_dumpxml[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("saved state domain information in XML")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Dump XML of domain information for a saved state file to stdout.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_save_image_dumpxml[] = {
|
2021-09-16 11:03:02 +00:00
|
|
|
{.name = "file",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("saved state file to read")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "security-info",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("include security sensitive information in XML dump")
|
|
|
|
},
|
2022-06-16 15:29:54 +00:00
|
|
|
{.name = "xpath",
|
|
|
|
.type = VSH_OT_STRING,
|
virsh: Require --xpath for *dumpxml
Historically, the dumpxml command reject any unknown arguments,
for instance:
virsh dumpxml fedora xxx
However, after v8.5.0-rc1~31 the second argument ('xxx') is
treated as an XPath, but it's not that clearly visible.
Therefore, require the --xpath switch, like this:
virsh dumpxml fedora --xpath xxx
Yes, this breaks already released virsh, but I think we can argue
that the pool of users of this particular function is very small.
We also document the argument being mandatory:
dumpxml [--inactive] [--security-info] [--update-cpu] [--migratable]
[--xpath EXPRESSION] [--wrap] domain
The sooner we do this change, the better.
The same applies for other *dumpxml functions (net-dumpxml,
pool-dumpxml, vol-dumpxl to name a few).
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2103524
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2022-07-08 10:45:42 +00:00
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
2022-06-16 15:29:54 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
|
|
|
.help = N_("xpath expression to filter the XML document")
|
|
|
|
},
|
|
|
|
{.name = "wrap",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("wrap xpath results in an common root element"),
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSaveImageDumpxml(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *file = NULL;
|
|
|
|
unsigned int flags = 0;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2022-06-16 15:29:54 +00:00
|
|
|
bool wrap = vshCommandOptBool(cmd, "wrap");
|
|
|
|
const char *xpath = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "security-info"))
|
|
|
|
flags |= VIR_DOMAIN_XML_SECURE;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &file) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2022-06-16 15:29:54 +00:00
|
|
|
if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0)
|
|
|
|
return false;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
xml = virDomainSaveImageGetXMLDesc(priv->conn, file, flags);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (!xml)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-06-16 15:29:54 +00:00
|
|
|
return virshDumpXML(ctl, xml, "domain-save-image", xpath, wrap);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "save-image-define" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_save_image_define[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("redefine the XML for a domain's saved state file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Replace the domain XML associated with a saved state file")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_save_image_define[] = {
|
2021-09-16 11:03:02 +00:00
|
|
|
{.name = "file",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("saved state file to modify")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "xml",
|
2014-11-11 02:12:20 +00:00
|
|
|
.type = VSH_OT_DATA,
|
2013-01-14 11:26:54 +00:00
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("filename containing updated XML for the target")
|
|
|
|
},
|
|
|
|
{.name = "running",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be running on restore")
|
|
|
|
},
|
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be paused on restore")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSaveImageDefine(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *file = NULL;
|
|
|
|
const char *xmlfile = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned int flags = 0;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "running"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_RUNNING;
|
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_PAUSED;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &file) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "xml", &xmlfile) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2014-10-14 08:04:31 +00:00
|
|
|
if (virFileReadAll(xmlfile, VSH_MAX_XML_FILE, &xml) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (virDomainSaveImageDefineXML(priv->conn, file, xml, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to update %1$s"), file);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("State file %1$s updated.\n"), file);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "save-image-edit" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_save_image_edit[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("edit XML for a domain's saved state file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Edit the domain XML associated with a saved state file")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_save_image_edit[] = {
|
2021-09-16 11:03:02 +00:00
|
|
|
{.name = "file",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("saved state file to edit")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "running",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be running on restore")
|
|
|
|
},
|
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be paused on restore")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSaveImageEdit(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *file = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
unsigned int getxml_flags = VIR_DOMAIN_XML_SECURE;
|
|
|
|
unsigned int define_flags = 0;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "running"))
|
|
|
|
define_flags |= VIR_DOMAIN_SAVE_RUNNING;
|
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
define_flags |= VIR_DOMAIN_SAVE_PAUSED;
|
|
|
|
|
|
|
|
/* Normally, we let the API reject mutually exclusive flags.
|
|
|
|
* However, in the edit cycle, we let the user retry if the define
|
|
|
|
* step fails, but the define step will always fail on invalid
|
|
|
|
* flags, so we reject it up front to avoid looping. */
|
2016-02-22 12:45:53 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("running", "paused");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &file) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
#define EDIT_GET_XML \
|
2015-06-15 16:53:58 +00:00
|
|
|
virDomainSaveImageGetXMLDesc(priv->conn, file, getxml_flags)
|
2017-11-03 12:09:47 +00:00
|
|
|
#define EDIT_NOT_CHANGED \
|
|
|
|
do { \
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Saved image %1$s XML configuration not changed.\n"), \
|
|
|
|
file); \
|
2017-11-03 12:09:47 +00:00
|
|
|
ret = true; \
|
|
|
|
goto edit_cleanup; \
|
2014-11-14 14:57:17 +00:00
|
|
|
} while (0)
|
2012-07-25 15:37:18 +00:00
|
|
|
#define EDIT_DEFINE \
|
2015-06-15 16:53:58 +00:00
|
|
|
(virDomainSaveImageDefineXML(priv->conn, file, doc_edited, define_flags) == 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
#include "virsh-edit.c"
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("State file %1$s edited.\n"), file);
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "managedsave" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_managedsave[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("managed save of a domain state")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Save and destroy a running domain, so it can be restarted from\n"
|
2012-07-25 15:37:18 +00:00
|
|
|
" the same state at a later time. When the virsh 'start'\n"
|
|
|
|
" command is next run for the domain, it will automatically\n"
|
2013-02-07 15:25:10 +00:00
|
|
|
" be started from this saved state.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_managedsave[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2014-11-11 09:45:24 +00:00
|
|
|
{.name = "bypass-cache",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("avoid file system cache when saving")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "running",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be running on next start")
|
|
|
|
},
|
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be paused on next start")
|
|
|
|
},
|
|
|
|
{.name = "verbose",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("display the progress of save")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
doManagedsave(void *opaque)
|
|
|
|
{
|
2015-06-15 16:53:58 +00:00
|
|
|
virshCtrlData *data = opaque;
|
2012-07-25 15:37:18 +00:00
|
|
|
vshControl *ctl = data->ctl;
|
|
|
|
const vshCmd *cmd = data->cmd;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
unsigned int flags = 0;
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-07-25 15:37:18 +00:00
|
|
|
sigset_t sigmask, oldsigmask;
|
|
|
|
|
|
|
|
sigemptyset(&sigmask);
|
|
|
|
sigaddset(&sigmask, SIGINT);
|
2021-02-01 12:42:01 +00:00
|
|
|
if (pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask) != 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out_sig;
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "bypass-cache"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_BYPASS_CACHE;
|
|
|
|
if (vshCommandOptBool(cmd, "running"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_RUNNING;
|
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_PAUSED;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (virDomainManagedSave(dom, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to save domain '%1$s' state"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
data->ret = 0;
|
2014-03-25 06:53:59 +00:00
|
|
|
out:
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-07-25 15:37:18 +00:00
|
|
|
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
|
2014-03-25 06:53:59 +00:00
|
|
|
out_sig:
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2020-02-05 14:16:16 +00:00
|
|
|
g_main_loop_quit(data->eventLoop);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdManagedSave(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool verbose = false;
|
|
|
|
const char *name = NULL;
|
|
|
|
virThread workerThread;
|
2020-02-05 14:16:16 +00:00
|
|
|
g_autoptr(GMainContext) eventCtxt = g_main_context_new();
|
|
|
|
g_autoptr(GMainLoop) eventLoop = g_main_loop_new(eventCtxt, FALSE);
|
|
|
|
virshCtrlData data = {
|
|
|
|
.ctl = ctl,
|
|
|
|
.cmd = cmd,
|
|
|
|
.eventLoop = eventLoop,
|
|
|
|
.ret = -1,
|
|
|
|
};
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "verbose"))
|
|
|
|
verbose = true;
|
|
|
|
|
|
|
|
if (virThreadCreate(&workerThread,
|
|
|
|
true,
|
|
|
|
doManagedsave,
|
|
|
|
&data) < 0)
|
2021-11-04 14:26:07 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
virshWatchJob(ctl, dom, verbose, eventLoop,
|
|
|
|
&data.ret, 0, NULL, NULL, _("Managedsave"));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
virThreadJoin(&workerThread);
|
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
if (!data.ret)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("\nDomain '%1$s' state saved by libvirt\n"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
return !data.ret;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "managedsave-remove" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_managedsaveremove[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Remove managed save of a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Remove an existing managed save state file from a domain")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_managedsaveremove[] = {
|
2020-09-11 07:13:04 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdManagedSaveRemove(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
int hassave;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
hassave = virDomainHasManagedSaveImage(dom, 0);
|
|
|
|
if (hassave < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to check for domain managed save image"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 14:15:11 +00:00
|
|
|
if (hassave == 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' has no manage save image; removal skipped"),
|
2016-08-24 14:14:23 +00:00
|
|
|
name);
|
2021-09-15 14:15:11 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainManagedSaveRemove(dom, 0) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to remove managed save image for domain '%1$s'"),
|
2021-09-15 14:15:11 +00:00
|
|
|
name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Removed managedsave image for domain '%1$s'"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 08:02:55 +00:00
|
|
|
/*
|
|
|
|
* "managedsave-edit" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_managed_save_edit[] = {
|
2019-03-31 18:16:29 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("edit XML for a domain's managed save state file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Edit the domain XML associated with the managed save state file")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2017-08-08 08:02:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_managed_save_edit[] = {
|
2020-09-11 07:13:04 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE),
|
2017-08-08 08:02:55 +00:00
|
|
|
{.name = "running",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be running on start")
|
|
|
|
},
|
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be paused on start")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdManagedSaveEdit(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2017-08-08 08:02:55 +00:00
|
|
|
unsigned int getxml_flags = VIR_DOMAIN_XML_SECURE;
|
|
|
|
unsigned int define_flags = 0;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "running"))
|
|
|
|
define_flags |= VIR_DOMAIN_SAVE_RUNNING;
|
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
define_flags |= VIR_DOMAIN_SAVE_PAUSED;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("running", "paused");
|
|
|
|
|
|
|
|
dom = virshCommandOptDomain(ctl, cmd, NULL);
|
|
|
|
if (dom == NULL)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-08-08 08:02:55 +00:00
|
|
|
|
|
|
|
#define EDIT_GET_XML virDomainManagedSaveGetXMLDesc(dom, getxml_flags)
|
2017-11-03 12:09:47 +00:00
|
|
|
#define EDIT_NOT_CHANGED \
|
|
|
|
do { \
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Managed save image of domain '%1$s' XML configuration not changed.\n"), \
|
|
|
|
virDomainGetName(dom)); \
|
2017-11-03 12:09:47 +00:00
|
|
|
ret = true; \
|
|
|
|
goto edit_cleanup; \
|
2017-08-08 08:02:55 +00:00
|
|
|
} while (0)
|
|
|
|
#define EDIT_DEFINE \
|
|
|
|
(virDomainManagedSaveDefineXML(dom, doc_edited, define_flags) == 0)
|
|
|
|
#include "virsh-edit.c"
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Managed save image of Domain '%1$s' XML configuration edited.\n"),
|
2017-08-08 08:02:55 +00:00
|
|
|
virDomainGetName(dom));
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-08 08:02:54 +00:00
|
|
|
/*
|
|
|
|
* "managedsave-dumpxml" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_managed_save_dumpxml[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Domain information of managed save state file in XML")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Dump XML of domain information for a managed save state file to stdout.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_managed_save_dumpxml[] = {
|
2020-09-11 07:13:04 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE),
|
2017-08-08 08:02:54 +00:00
|
|
|
{.name = "security-info",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("include security sensitive information in XML dump")
|
|
|
|
},
|
2022-06-16 15:29:54 +00:00
|
|
|
{.name = "xpath",
|
|
|
|
.type = VSH_OT_STRING,
|
virsh: Require --xpath for *dumpxml
Historically, the dumpxml command reject any unknown arguments,
for instance:
virsh dumpxml fedora xxx
However, after v8.5.0-rc1~31 the second argument ('xxx') is
treated as an XPath, but it's not that clearly visible.
Therefore, require the --xpath switch, like this:
virsh dumpxml fedora --xpath xxx
Yes, this breaks already released virsh, but I think we can argue
that the pool of users of this particular function is very small.
We also document the argument being mandatory:
dumpxml [--inactive] [--security-info] [--update-cpu] [--migratable]
[--xpath EXPRESSION] [--wrap] domain
The sooner we do this change, the better.
The same applies for other *dumpxml functions (net-dumpxml,
pool-dumpxml, vol-dumpxl to name a few).
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2103524
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2022-07-08 10:45:42 +00:00
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
2022-06-16 15:29:54 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
|
|
|
.help = N_("xpath expression to filter the XML document")
|
|
|
|
},
|
|
|
|
{.name = "wrap",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("wrap xpath results in an common root element"),
|
|
|
|
},
|
2017-08-08 08:02:54 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdManagedSaveDumpxml(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2017-08-08 08:02:54 +00:00
|
|
|
unsigned int flags = 0;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2022-06-16 15:29:54 +00:00
|
|
|
bool wrap = vshCommandOptBool(cmd, "wrap");
|
|
|
|
const char *xpath = NULL;
|
2017-08-08 08:02:54 +00:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "security-info"))
|
|
|
|
flags |= VIR_DOMAIN_XML_SECURE;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-08-08 08:02:54 +00:00
|
|
|
|
2022-06-16 15:29:54 +00:00
|
|
|
if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0)
|
|
|
|
return false;
|
|
|
|
|
2017-08-08 08:02:54 +00:00
|
|
|
if (!(xml = virDomainManagedSaveGetXMLDesc(dom, flags)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-08-08 08:02:54 +00:00
|
|
|
|
2022-06-16 15:29:54 +00:00
|
|
|
return virshDumpXML(ctl, xml, "domain-save-image", xpath, wrap);
|
2017-08-08 08:02:54 +00:00
|
|
|
}
|
|
|
|
|
2017-08-08 08:02:53 +00:00
|
|
|
/*
|
|
|
|
* "managedsave-define" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_managed_save_define[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("redefine the XML for a domain's managed save state file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Replace the domain XML associated with a managed save state file")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_managed_save_define[] = {
|
2020-09-11 07:13:04 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE),
|
2017-08-08 08:02:53 +00:00
|
|
|
{.name = "xml",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2017-08-08 08:02:53 +00:00
|
|
|
.help = N_("filename containing updated XML for the target")
|
|
|
|
},
|
|
|
|
{.name = "running",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be running on start")
|
|
|
|
},
|
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set domain to be paused on start")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdManagedSaveDefine(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2017-08-08 08:02:53 +00:00
|
|
|
const char *xmlfile = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2017-08-08 08:02:53 +00:00
|
|
|
unsigned int flags = 0;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "running"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_RUNNING;
|
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_PAUSED;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("running", "paused");
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "xml", &xmlfile) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virFileReadAll(xmlfile, VSH_MAX_XML_FILE, &xml) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-08-08 08:02:53 +00:00
|
|
|
|
|
|
|
if (virDomainManagedSaveDefineXML(dom, xml, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to update %1$s XML configuration"),
|
2017-08-08 08:02:53 +00:00
|
|
|
virDomainGetName(dom));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-08-08 08:02:53 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Managed save state file of domain '%1$s' updated.\n"),
|
2017-08-08 08:02:53 +00:00
|
|
|
virDomainGetName(dom));
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2017-08-08 08:02:53 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "schedinfo" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_schedinfo[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("show/set scheduler parameters")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Show/Set scheduler parameters.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_schedinfo[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "weight",
|
|
|
|
.type = VSH_OT_INT,
|
2013-03-15 13:42:42 +00:00
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("weight for XEN_CREDIT")
|
|
|
|
},
|
|
|
|
{.name = "cap",
|
|
|
|
.type = VSH_OT_INT,
|
2013-03-15 13:42:42 +00:00
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("cap for XEN_CREDIT")
|
|
|
|
},
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_CURRENT(N_("get/set current scheduler info")),
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_CONFIG(N_("get/set value to be used on next boot")),
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_LIVE(N_("get/set value from running domain")),
|
2013-03-15 13:42:42 +00:00
|
|
|
{.name = "set",
|
|
|
|
.type = VSH_OT_ARGV,
|
|
|
|
.flags = VSH_OFLAG_NONE,
|
|
|
|
.help = N_("parameter=value")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2013-03-15 13:42:42 +00:00
|
|
|
static int
|
|
|
|
cmdSchedInfoUpdateOne(vshControl *ctl,
|
|
|
|
virTypedParameterPtr src_params, int nsrc_params,
|
|
|
|
virTypedParameterPtr *params,
|
|
|
|
int *nparams, int *maxparams,
|
|
|
|
const char *field, const char *value)
|
|
|
|
{
|
|
|
|
virTypedParameterPtr param;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-03-15 13:42:42 +00:00
|
|
|
|
|
|
|
for (i = 0; i < nsrc_params; i++) {
|
|
|
|
param = &(src_params[i]);
|
|
|
|
|
|
|
|
if (STRNEQ(field, param->field))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (virTypedParamsAddFromString(params, nparams, maxparams,
|
|
|
|
field, param->type,
|
|
|
|
value) < 0) {
|
|
|
|
vshSaveLibvirtError();
|
2019-10-21 18:19:09 +00:00
|
|
|
return -1;
|
2013-03-15 13:42:42 +00:00
|
|
|
}
|
2021-09-24 15:17:46 +00:00
|
|
|
return 0;
|
2013-03-15 13:42:42 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("invalid scheduler option: %1$s"), field);
|
2021-09-24 15:17:46 +00:00
|
|
|
return -1;
|
2013-03-15 13:42:42 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static int
|
|
|
|
cmdSchedInfoUpdate(vshControl *ctl, const vshCmd *cmd,
|
2012-09-05 12:41:25 +00:00
|
|
|
virTypedParameterPtr src_params, int nsrc_params,
|
|
|
|
virTypedParameterPtr *update_params)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2012-09-05 12:41:25 +00:00
|
|
|
char *set_val = NULL;
|
2013-03-15 13:42:42 +00:00
|
|
|
const char *val = NULL;
|
|
|
|
const vshCmdOpt *opt = NULL;
|
2012-09-05 12:41:25 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
int nparams = 0;
|
2013-01-15 23:06:20 +00:00
|
|
|
int maxparams = 0;
|
2012-09-05 12:41:25 +00:00
|
|
|
int ret = -1;
|
|
|
|
int rv;
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
|
2021-08-11 13:25:20 +00:00
|
|
|
g_autofree char *set_field = g_strdup(opt->data);
|
|
|
|
|
2012-09-05 12:41:25 +00:00
|
|
|
if (!(set_val = strchr(set_field, '='))) {
|
2013-03-15 13:42:42 +00:00
|
|
|
vshError(ctl, "%s", _("Invalid syntax for --set, "
|
|
|
|
"expecting name=value"));
|
2012-09-05 12:41:25 +00:00
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2012-09-05 12:41:25 +00:00
|
|
|
|
|
|
|
*set_val = '\0';
|
|
|
|
set_val++;
|
|
|
|
|
2013-03-15 13:42:42 +00:00
|
|
|
if (cmdSchedInfoUpdateOne(ctl, src_params, nsrc_params,
|
|
|
|
¶ms, &nparams, &maxparams,
|
|
|
|
set_field, set_val) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-15 13:42:42 +00:00
|
|
|
rv = vshCommandOptStringReq(ctl, cmd, "cap", &val);
|
|
|
|
if (rv < 0 ||
|
|
|
|
(val &&
|
|
|
|
cmdSchedInfoUpdateOne(ctl, src_params, nsrc_params,
|
|
|
|
¶ms, &nparams, &maxparams,
|
|
|
|
"cap", val) < 0))
|
|
|
|
goto cleanup;
|
2012-09-05 12:41:25 +00:00
|
|
|
|
2013-03-15 13:42:42 +00:00
|
|
|
rv = vshCommandOptStringReq(ctl, cmd, "weight", &val);
|
|
|
|
if (rv < 0 ||
|
|
|
|
(val &&
|
|
|
|
cmdSchedInfoUpdateOne(ctl, src_params, nsrc_params,
|
|
|
|
¶ms, &nparams, &maxparams,
|
|
|
|
"weight", val) < 0))
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2012-09-05 12:41:25 +00:00
|
|
|
ret = nparams;
|
2021-02-23 13:58:29 +00:00
|
|
|
*update_params = g_steal_pointer(¶ms);
|
2012-09-05 12:41:25 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-01-15 23:06:20 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2012-09-05 12:41:25 +00:00
|
|
|
return ret;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSchedinfo(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-09-23 23:25:07 +00:00
|
|
|
g_autofree char *schedulertype = NULL;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
2012-09-05 12:41:25 +00:00
|
|
|
virTypedParameterPtr updates = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
int nparams = 0;
|
2012-09-05 12:41:25 +00:00
|
|
|
int nupdates = 0;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool ret_val = false;
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2022-02-28 17:21:48 +00:00
|
|
|
unsigned int queryflags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 17:21:48 +00:00
|
|
|
/* We cannot query both live and config at once, so settle
|
|
|
|
on current in that case. If we are setting, then the two values should
|
|
|
|
match when we re-query; otherwise, we report the error later. */
|
|
|
|
if (config && live)
|
|
|
|
queryflags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
else
|
|
|
|
queryflags = flags;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Print SchedulerType */
|
2021-09-23 23:25:07 +00:00
|
|
|
if (!(schedulertype = virDomainGetSchedulerType(dom, &nparams))) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshPrint(ctl, "%-15s: %s\n", _("Scheduler"), _("Unknown"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2021-09-23 23:25:07 +00:00
|
|
|
vshPrint(ctl, "%-15s: %s\n", _("Scheduler"), schedulertype);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-09-23 23:25:07 +00:00
|
|
|
if (!nparams)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
params = g_new0(virTypedParameter, nparams);
|
|
|
|
memset(params, 0, sizeof(*params) * nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-09-23 23:25:07 +00:00
|
|
|
if (flags || current) {
|
2022-02-28 17:21:48 +00:00
|
|
|
if (virDomainGetSchedulerParametersFlags(dom, params, &nparams, queryflags) == -1)
|
2021-09-23 23:25:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (virDomainGetSchedulerParameters(dom, params, &nparams) == -1)
|
2012-09-05 12:41:25 +00:00
|
|
|
goto cleanup;
|
2021-09-23 23:25:07 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-09-23 23:25:07 +00:00
|
|
|
/* See if any params are being set */
|
|
|
|
if ((nupdates = cmdSchedInfoUpdate(ctl, cmd, params, nparams,
|
|
|
|
&updates)) < 0)
|
|
|
|
goto cleanup;
|
2012-09-05 12:41:25 +00:00
|
|
|
|
2021-09-23 23:25:07 +00:00
|
|
|
/* Update parameters & refresh data */
|
|
|
|
if (nupdates > 0) {
|
|
|
|
if (flags || current) {
|
|
|
|
if (virDomainSetSchedulerParametersFlags(dom, updates,
|
|
|
|
nupdates, flags) == -1)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2022-02-28 17:21:48 +00:00
|
|
|
if (virDomainGetSchedulerParametersFlags(dom, params, &nparams, queryflags) == -1)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
2021-09-23 23:25:07 +00:00
|
|
|
if (virDomainSetSchedulerParameters(dom, updates, nupdates) == -1)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2021-09-23 23:25:07 +00:00
|
|
|
if (virDomainGetSchedulerParameters(dom, params, &nparams) == -1)
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2021-09-23 23:25:07 +00:00
|
|
|
} else {
|
|
|
|
/* When not doing --set, --live and --config do not mix. */
|
|
|
|
if (live && config) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("cannot query both live and config at once"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret_val = true;
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
2013-01-15 23:06:20 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
|
|
|
virTypedParamsFree(updates, nupdates);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret_val;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "restore" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_restore[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("restore a domain from a saved state in a file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Restore a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_restore[] = {
|
2021-09-16 11:03:02 +00:00
|
|
|
{.name = "file",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("the state to restore")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "bypass-cache",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("avoid file system cache when restoring")
|
|
|
|
},
|
|
|
|
{.name = "xml",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("filename containing updated XML for the target")
|
|
|
|
},
|
|
|
|
{.name = "running",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("restore domain into running state")
|
|
|
|
},
|
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("restore domain into paused state")
|
|
|
|
},
|
2022-02-03 16:42:28 +00:00
|
|
|
{.name = "reset-nvram",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("re-initialize NVRAM from its pristine template")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdRestore(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *from = NULL;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
const char *xmlfile = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2022-02-28 14:00:00 +00:00
|
|
|
int rc;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "bypass-cache"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_BYPASS_CACHE;
|
|
|
|
if (vshCommandOptBool(cmd, "running"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_RUNNING;
|
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_PAUSED;
|
2022-02-03 16:42:28 +00:00
|
|
|
if (vshCommandOptBool(cmd, "reset-nvram"))
|
|
|
|
flags |= VIR_DOMAIN_SAVE_RESET_NVRAM;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "xml", &xmlfile) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (xmlfile &&
|
2014-10-14 08:04:31 +00:00
|
|
|
virFileReadAll(xmlfile, VSH_MAX_XML_FILE, &xml) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 14:00:00 +00:00
|
|
|
if (flags || xml) {
|
|
|
|
rc = virDomainRestoreFlags(priv->conn, from, xml, flags);
|
|
|
|
} else {
|
|
|
|
rc = virDomainRestore(priv->conn, from);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to restore domain from %1$s"), from);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain restored from %1$s\n"), from);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "dump" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_dump[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("dump the core of a domain to a file for analysis")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Core dump a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_dump[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2021-09-16 11:03:02 +00:00
|
|
|
{.name = "file",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("where to dump the core")
|
|
|
|
},
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_LIVE(N_("perform a live core dump if supported")),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "crash",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("crash the domain after core dump")
|
|
|
|
},
|
|
|
|
{.name = "bypass-cache",
|
|
|
|
.type = VSH_OT_BOOL,
|
2013-03-15 07:40:18 +00:00
|
|
|
.help = N_("avoid file system cache when dumping")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "reset",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("reset the domain after core dump")
|
|
|
|
},
|
|
|
|
{.name = "verbose",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("display the progress of dump")
|
|
|
|
},
|
|
|
|
{.name = "memory-only",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("dump domain's memory only")
|
|
|
|
},
|
2014-03-23 03:51:15 +00:00
|
|
|
{.name = "format",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-06-07 03:14:18 +00:00
|
|
|
.flags = VSH_OFLAG_NONE,
|
|
|
|
.completer = virshDomainCoreDumpFormatCompleter,
|
2014-03-23 03:51:15 +00:00
|
|
|
.help = N_("specify the format of memory-only dump")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2021-07-19 11:23:29 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainCoreDumpFormat,
|
2021-06-07 03:14:17 +00:00
|
|
|
VIR_DOMAIN_CORE_DUMP_FORMAT_LAST,
|
2021-07-13 08:04:12 +00:00
|
|
|
"elf",
|
2021-06-07 03:14:17 +00:00
|
|
|
"kdump-zlib",
|
|
|
|
"kdump-lzo",
|
|
|
|
"kdump-snappy",
|
|
|
|
"win-dmp");
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static void
|
|
|
|
doDump(void *opaque)
|
|
|
|
{
|
2015-06-15 16:53:58 +00:00
|
|
|
virshCtrlData *data = opaque;
|
2012-07-25 15:37:18 +00:00
|
|
|
vshControl *ctl = data->ctl;
|
|
|
|
const vshCmd *cmd = data->cmd;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name = NULL;
|
|
|
|
const char *to = NULL;
|
|
|
|
unsigned int flags = 0;
|
2014-03-23 03:51:15 +00:00
|
|
|
const char *format = NULL;
|
2021-06-07 03:14:17 +00:00
|
|
|
int dumpformat = VIR_DOMAIN_CORE_DUMP_FORMAT_RAW;
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
sigset_t sigmask, oldsigmask;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
sigemptyset(&sigmask);
|
|
|
|
sigaddset(&sigmask, SIGINT);
|
2021-02-01 12:42:01 +00:00
|
|
|
if (pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask) != 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out_sig;
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &to) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "live"))
|
|
|
|
flags |= VIR_DUMP_LIVE;
|
|
|
|
if (vshCommandOptBool(cmd, "crash"))
|
|
|
|
flags |= VIR_DUMP_CRASH;
|
|
|
|
if (vshCommandOptBool(cmd, "bypass-cache"))
|
|
|
|
flags |= VIR_DUMP_BYPASS_CACHE;
|
|
|
|
if (vshCommandOptBool(cmd, "reset"))
|
|
|
|
flags |= VIR_DUMP_RESET;
|
|
|
|
if (vshCommandOptBool(cmd, "memory-only"))
|
|
|
|
flags |= VIR_DUMP_MEMORY_ONLY;
|
|
|
|
|
2014-03-23 03:51:15 +00:00
|
|
|
if (vshCommandOptBool(cmd, "format")) {
|
|
|
|
if (!(flags & VIR_DUMP_MEMORY_ONLY)) {
|
|
|
|
vshError(ctl, "%s", _("--format only works with --memory-only"));
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
if (vshCommandOptStringQuiet(ctl, cmd, "format", &format) > 0) {
|
2021-07-19 11:23:29 +00:00
|
|
|
if ((dumpformat = virshDomainCoreDumpFormatTypeFromString(format)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("format '%1$s' is not supported, expecting 'kdump-zlib', 'kdump-lzo', 'kdump-snappy', 'win-dmp' or 'elf'"),
|
|
|
|
format);
|
2014-03-23 03:51:15 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dumpformat != VIR_DOMAIN_CORE_DUMP_FORMAT_RAW) {
|
|
|
|
if (virDomainCoreDumpWithFormat(dom, to, dumpformat, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to core dump domain '%1$s' to %2$s"), name, to);
|
2014-03-23 03:51:15 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virDomainCoreDump(dom, to, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to core dump domain '%1$s' to %2$s"), name, to);
|
2014-03-23 03:51:15 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2020-04-21 17:06:16 +00:00
|
|
|
data->ret = 0;
|
2014-03-25 06:53:59 +00:00
|
|
|
out:
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-07-25 15:37:18 +00:00
|
|
|
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
|
2014-03-25 06:53:59 +00:00
|
|
|
out_sig:
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2020-02-05 14:16:16 +00:00
|
|
|
g_main_loop_quit(data->eventLoop);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDump(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool verbose = false;
|
|
|
|
const char *name = NULL;
|
|
|
|
const char *to = NULL;
|
|
|
|
virThread workerThread;
|
2020-02-05 14:16:16 +00:00
|
|
|
g_autoptr(GMainContext) eventCtxt = g_main_context_new();
|
|
|
|
g_autoptr(GMainLoop) eventLoop = g_main_loop_new(eventCtxt, FALSE);
|
|
|
|
virshCtrlData data = {
|
|
|
|
.ctl = ctl,
|
|
|
|
.cmd = cmd,
|
|
|
|
.eventLoop = eventLoop,
|
|
|
|
.ret = -1,
|
|
|
|
};
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &to) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "verbose"))
|
|
|
|
verbose = true;
|
|
|
|
|
|
|
|
if (virThreadCreate(&workerThread,
|
|
|
|
true,
|
|
|
|
doDump,
|
|
|
|
&data) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-02-05 14:16:16 +00:00
|
|
|
virshWatchJob(ctl, dom, verbose, eventLoop,
|
|
|
|
&data.ret, 0, NULL, NULL, _("Dump"));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
virThreadJoin(&workerThread);
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
if (data.ret)
|
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("\nDomain '%1$s' dumped to %2$s\n"), name, to);
|
2021-08-12 07:59:20 +00:00
|
|
|
|
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const vshCmdInfo info_screenshot[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("take a screenshot of a current domain console and store it "
|
|
|
|
"into a file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("screenshot of a current domain console")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_screenshot[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "file",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-17 07:50:09 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("where to store the screenshot")
|
|
|
|
},
|
|
|
|
{.name = "screen",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("ID of a screen to take screenshot of")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate string: '<domain name>-<timestamp>[<extension>]'
|
|
|
|
*/
|
|
|
|
static char *
|
2015-06-15 16:53:58 +00:00
|
|
|
virshGenFileName(vshControl *ctl, virDomainPtr dom, const char *mime)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2020-01-09 14:07:15 +00:00
|
|
|
g_autoptr(GDateTime) now = g_date_time_new_now_local();
|
|
|
|
g_autofree char *nowstr = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *ext = NULL;
|
|
|
|
|
|
|
|
if (!dom) {
|
|
|
|
vshError(ctl, "%s", _("Invalid domain supplied"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ(mime, "image/x-portable-pixmap"))
|
|
|
|
ext = ".ppm";
|
|
|
|
else if (STREQ(mime, "image/png"))
|
|
|
|
ext = ".png";
|
|
|
|
/* add mime type here */
|
|
|
|
|
2020-01-09 14:07:15 +00:00
|
|
|
nowstr = g_date_time_format(now, "%Y-%m-%d-%H:%M:%S");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-09-24 15:17:46 +00:00
|
|
|
return g_strdup_printf("%s-%s%s", virDomainGetName(dom),
|
|
|
|
nowstr, NULLSTR_EMPTY(ext));
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdScreenshot(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name = NULL;
|
|
|
|
char *file = NULL;
|
2021-09-26 10:54:10 +00:00
|
|
|
VIR_AUTOCLOSE fd = -1;
|
2021-09-26 11:27:26 +00:00
|
|
|
g_autoptr(virshStream) st = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned int screen = 0;
|
|
|
|
unsigned int flags = 0; /* currently unused */
|
2014-11-17 23:39:48 +00:00
|
|
|
bool ret = false;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool created = false;
|
|
|
|
bool generated = false;
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char *mime = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2020-09-09 08:55:40 +00:00
|
|
|
virshStreamCallbackData cbdata;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", (const char **) &file) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptUInt(ctl, cmd, "screen", &screen) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(st = virStreamNew(priv->conn, 0)))
|
2013-09-25 14:54:24 +00:00
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
mime = virDomainScreenshot(dom, st, screen, flags);
|
|
|
|
if (!mime) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("could not take a screenshot of %1$s"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!file) {
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(file = virshGenFileName(ctl, dom, mime)))
|
2013-09-25 14:54:24 +00:00
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
generated = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) {
|
|
|
|
if (errno != EEXIST ||
|
|
|
|
(fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("cannot create file %1$s"), file);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
created = true;
|
|
|
|
}
|
|
|
|
|
2020-09-09 08:55:40 +00:00
|
|
|
cbdata.ctl = ctl;
|
|
|
|
cbdata.fd = fd;
|
|
|
|
|
|
|
|
if (virStreamRecvAll(st, virshStreamSink, &cbdata) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("could not receive data from domain '%1$s'"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_CLOSE(fd) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("cannot close file %1$s"), file);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virStreamFinish(st) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("cannot close stream on domain '%1$s'"), name);
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Screenshot saved to %1$s, with type of %2$s"), file, mime);
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2012-07-25 15:37:18 +00:00
|
|
|
if (!ret && created)
|
|
|
|
unlink(file);
|
|
|
|
if (generated)
|
|
|
|
VIR_FREE(file);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-10-12 14:25:43 +00:00
|
|
|
/*
|
|
|
|
* "set-lifecycle-action" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_setLifecycleAction[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("change lifecycle actions")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Change lifecycle actions for the guest domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_setLifecycleAction[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2017-10-12 14:25:43 +00:00
|
|
|
{.name = "type",
|
2017-11-16 03:01:54 +00:00
|
|
|
.type = VSH_OT_DATA,
|
2017-10-12 14:25:43 +00:00
|
|
|
.flags = VSH_OFLAG_REQ,
|
2020-11-10 09:51:03 +00:00
|
|
|
.completer = virshDomainLifecycleCompleter,
|
2017-10-12 14:25:43 +00:00
|
|
|
.help = N_("lifecycle type to modify")
|
|
|
|
},
|
|
|
|
{.name = "action",
|
2017-11-16 03:01:54 +00:00
|
|
|
.type = VSH_OT_DATA,
|
2017-10-12 14:25:43 +00:00
|
|
|
.flags = VSH_OFLAG_REQ,
|
2020-11-10 09:51:04 +00:00
|
|
|
.completer = virshDomainLifecycleActionCompleter,
|
2017-10-12 14:25:43 +00:00
|
|
|
.help = N_("lifecycle action to set")
|
|
|
|
},
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
2021-07-19 11:23:29 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainLifecycle,
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_DOMAIN_LIFECYCLE_LAST,
|
2017-10-12 14:25:43 +00:00
|
|
|
"poweroff",
|
|
|
|
"reboot",
|
2019-01-20 16:30:15 +00:00
|
|
|
"crash");
|
2017-10-12 14:25:43 +00:00
|
|
|
|
2021-07-19 11:23:29 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainLifecycleAction,
|
2019-03-16 18:20:32 +00:00
|
|
|
VIR_DOMAIN_LIFECYCLE_ACTION_LAST,
|
2017-10-12 14:25:43 +00:00
|
|
|
"destroy",
|
|
|
|
"restart",
|
|
|
|
"rename-restart",
|
|
|
|
"preserve",
|
|
|
|
"coredump-destroy",
|
2019-01-20 16:30:15 +00:00
|
|
|
"coredump-restart");
|
2017-10-12 14:25:43 +00:00
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSetLifecycleAction(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2017-10-12 14:25:43 +00:00
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
const char *typeStr;
|
|
|
|
const char *actionStr;
|
|
|
|
unsigned int type;
|
|
|
|
unsigned int action;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
int tmpVal;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "type", &typeStr) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "action", &actionStr) < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-07-19 11:23:29 +00:00
|
|
|
if ((tmpVal = virshDomainLifecycleTypeFromString(typeStr)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid lifecycle type '%1$s'."), typeStr);
|
2017-10-12 14:25:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
type = tmpVal;
|
|
|
|
|
2021-07-19 11:23:29 +00:00
|
|
|
if ((tmpVal = virshDomainLifecycleActionTypeFromString(actionStr)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid lifecycle action '%1$s'."), actionStr);
|
2017-10-12 14:25:43 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
action = tmpVal;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainSetLifecycleAction(dom, type, action, flags) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to change lifecycle action."));
|
2021-09-24 15:17:46 +00:00
|
|
|
return false;
|
2017-10-12 14:25:43 +00:00
|
|
|
}
|
2021-09-24 15:17:46 +00:00
|
|
|
return true;
|
2017-10-12 14:25:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-18 10:37:38 +00:00
|
|
|
/*
|
|
|
|
* "set-user-password" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_set_user_password[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("set the user password inside the domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("changes the password of the specified user inside the domain")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_set_user_password[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2015-05-18 10:37:38 +00:00
|
|
|
{.name = "user",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("the username")
|
|
|
|
},
|
|
|
|
{.name = "password",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2015-05-18 10:37:38 +00:00
|
|
|
.help = N_("the new password")
|
|
|
|
},
|
|
|
|
{.name = "encrypted",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("the password is already encrypted")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSetUserPassword(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-05-18 10:37:38 +00:00
|
|
|
const char *name;
|
|
|
|
const char *password = NULL;
|
|
|
|
const char *user = NULL;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "encrypted"))
|
|
|
|
flags = VIR_DOMAIN_PASSWORD_ENCRYPTED;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "user", &user) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "password", &password) < 0)
|
|
|
|
return false;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2015-05-18 10:37:38 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainSetUserPassword(dom, user, password, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-05-18 10:37:38 +00:00
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Password set successfully for %1$s in %2$s"), user, name);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2015-05-18 10:37:38 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "resume" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_resume[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("resume a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Resume a previously suspended domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_resume[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_PAUSED),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdResume(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2021-09-24 15:17:47 +00:00
|
|
|
if (virDomainResume(dom) != 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to resume domain '%1$s'"), name);
|
2021-09-24 15:17:47 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' resumed\n"), name);
|
2021-09-24 15:17:47 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "shutdown" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_shutdown[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("gracefully shutdown a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Run shutdown in the target domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_shutdown[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "mode",
|
|
|
|
.type = VSH_OT_STRING,
|
2018-12-30 04:28:04 +00:00
|
|
|
.completer = virshDomainShutdownModeCompleter,
|
2014-05-01 17:42:54 +00:00
|
|
|
.help = N_("shutdown mode: acpi|agent|initctl|signal|paravirt")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdShutdown(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
const char *mode = NULL;
|
|
|
|
int flags = 0;
|
|
|
|
int rv;
|
2021-08-11 13:45:02 +00:00
|
|
|
g_auto(GStrv) modes = NULL;
|
2021-08-11 13:45:59 +00:00
|
|
|
char **tmp;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "mode", &mode) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2021-02-05 17:35:07 +00:00
|
|
|
if (mode && !(modes = g_strsplit(mode, ",", 0))) {
|
2012-11-30 15:30:05 +00:00
|
|
|
vshError(ctl, "%s", _("Cannot parse mode string"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = modes;
|
2012-11-30 21:48:24 +00:00
|
|
|
while (tmp && *tmp) {
|
2012-11-30 15:30:05 +00:00
|
|
|
mode = *tmp;
|
2012-07-25 15:37:18 +00:00
|
|
|
if (STREQ(mode, "acpi")) {
|
|
|
|
flags |= VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN;
|
|
|
|
} else if (STREQ(mode, "agent")) {
|
|
|
|
flags |= VIR_DOMAIN_SHUTDOWN_GUEST_AGENT;
|
2012-11-28 13:24:23 +00:00
|
|
|
} else if (STREQ(mode, "initctl")) {
|
|
|
|
flags |= VIR_DOMAIN_SHUTDOWN_INITCTL;
|
|
|
|
} else if (STREQ(mode, "signal")) {
|
|
|
|
flags |= VIR_DOMAIN_SHUTDOWN_SIGNAL;
|
2014-05-01 17:42:54 +00:00
|
|
|
} else if (STREQ(mode, "paravirt")) {
|
|
|
|
flags |= VIR_DOMAIN_SHUTDOWN_PARAVIRT;
|
2012-07-25 15:37:18 +00:00
|
|
|
} else {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unknown mode %1$s value, expecting 'acpi', 'agent', 'initctl', 'signal', or 'paravirt'"),
|
|
|
|
mode);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2012-11-30 15:30:05 +00:00
|
|
|
tmp++;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (flags)
|
|
|
|
rv = virDomainShutdownFlags(dom, flags);
|
|
|
|
else
|
|
|
|
rv = virDomainShutdown(dom);
|
2021-09-24 15:17:48 +00:00
|
|
|
|
|
|
|
if (rv != 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to shutdown domain '%1$s'"), name);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' is being shutdown\n"), name);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "reboot" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_reboot[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("reboot a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Run a reboot command in the target domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_reboot[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "mode",
|
|
|
|
.type = VSH_OT_STRING,
|
2018-12-30 04:28:04 +00:00
|
|
|
.completer = virshDomainShutdownModeCompleter,
|
2014-05-01 17:42:54 +00:00
|
|
|
.help = N_("shutdown mode: acpi|agent|initctl|signal|paravirt")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdReboot(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
const char *mode = NULL;
|
|
|
|
int flags = 0;
|
2021-08-11 13:45:02 +00:00
|
|
|
g_auto(GStrv) modes = NULL;
|
2021-08-11 13:45:59 +00:00
|
|
|
char **tmp;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "mode", &mode) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2021-02-05 17:35:07 +00:00
|
|
|
if (mode && !(modes = g_strsplit(mode, ",", 0))) {
|
2012-11-30 15:30:05 +00:00
|
|
|
vshError(ctl, "%s", _("Cannot parse mode string"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = modes;
|
2012-11-30 21:48:24 +00:00
|
|
|
while (tmp && *tmp) {
|
2012-11-30 15:30:05 +00:00
|
|
|
mode = *tmp;
|
2012-07-25 15:37:18 +00:00
|
|
|
if (STREQ(mode, "acpi")) {
|
2012-11-28 16:31:14 +00:00
|
|
|
flags |= VIR_DOMAIN_REBOOT_ACPI_POWER_BTN;
|
2012-07-25 15:37:18 +00:00
|
|
|
} else if (STREQ(mode, "agent")) {
|
2012-11-28 16:31:14 +00:00
|
|
|
flags |= VIR_DOMAIN_REBOOT_GUEST_AGENT;
|
2012-11-28 13:24:23 +00:00
|
|
|
} else if (STREQ(mode, "initctl")) {
|
|
|
|
flags |= VIR_DOMAIN_REBOOT_INITCTL;
|
|
|
|
} else if (STREQ(mode, "signal")) {
|
|
|
|
flags |= VIR_DOMAIN_REBOOT_SIGNAL;
|
2014-05-01 17:42:54 +00:00
|
|
|
} else if (STREQ(mode, "paravirt")) {
|
|
|
|
flags |= VIR_DOMAIN_REBOOT_PARAVIRT;
|
2012-07-25 15:37:18 +00:00
|
|
|
} else {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unknown mode %1$s value, expecting 'acpi', 'agent', 'initctl', 'signal' or 'paravirt'"),
|
|
|
|
mode);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2012-11-30 15:30:05 +00:00
|
|
|
tmp++;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-09-24 15:17:48 +00:00
|
|
|
if (virDomainReboot(dom, flags) != 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to reboot domain '%1$s'"), name);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' is being rebooted\n"), name);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "reset" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_reset[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("reset a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Reset the target domain as if by power button")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_reset[] = {
|
2018-05-15 11:10:33 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdReset(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2021-09-24 15:17:47 +00:00
|
|
|
if (virDomainReset(dom, 0) != 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to reset domain '%1$s'"), name);
|
2021-09-24 15:17:47 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' was reset\n"), name);
|
2021-09-24 15:17:47 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "domjobinfo" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domjobinfo[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("domain job information")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Returns information about jobs running on a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domjobinfo[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2014-09-12 08:05:32 +00:00
|
|
|
{.name = "completed",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("return statistics of a recently completed job")
|
|
|
|
},
|
2019-11-22 13:26:56 +00:00
|
|
|
{.name = "keep-completed",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("don't destroy statistics of a recently completed job when reading")
|
|
|
|
},
|
2019-11-21 16:44:00 +00:00
|
|
|
{.name = "anystats",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print statistics for any kind of job (even failed ones)")
|
|
|
|
},
|
2019-11-25 14:06:17 +00:00
|
|
|
{.name = "rawstats",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print the raw data returned by libvirt")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2019-01-20 16:04:56 +00:00
|
|
|
VIR_ENUM_DECL(virshDomainJob);
|
2015-06-15 16:53:58 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainJob,
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
VIR_DOMAIN_JOB_LAST,
|
|
|
|
N_("None"),
|
|
|
|
N_("Bounded"),
|
|
|
|
N_("Unbounded"),
|
|
|
|
N_("Completed"),
|
|
|
|
N_("Failed"),
|
2019-01-20 16:30:15 +00:00
|
|
|
N_("Cancelled"));
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
|
|
|
|
static const char *
|
2015-06-15 16:53:58 +00:00
|
|
|
virshDomainJobToString(int type)
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
{
|
2015-06-15 16:53:58 +00:00
|
|
|
const char *str = virshDomainJobTypeToString(type);
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
return str ? _(str) : _("unknown");
|
|
|
|
}
|
|
|
|
|
2017-04-26 09:59:59 +00:00
|
|
|
VIR_ENUM_DECL(virshDomainJobOperation);
|
|
|
|
VIR_ENUM_IMPL(virshDomainJobOperation,
|
|
|
|
VIR_DOMAIN_JOB_OPERATION_LAST,
|
|
|
|
N_("Unknown"),
|
|
|
|
N_("Start"),
|
|
|
|
N_("Save"),
|
|
|
|
N_("Restore"),
|
|
|
|
N_("Incoming migration"),
|
|
|
|
N_("Outgoing migration"),
|
|
|
|
N_("Snapshot"),
|
|
|
|
N_("Snapshot revert"),
|
2019-11-22 15:35:27 +00:00
|
|
|
N_("Dump"),
|
|
|
|
N_("Backup"),
|
2022-12-05 11:44:28 +00:00
|
|
|
N_("Snapshot delete"),
|
2019-11-22 15:35:27 +00:00
|
|
|
);
|
2017-04-26 09:59:59 +00:00
|
|
|
|
|
|
|
static const char *
|
|
|
|
virshDomainJobOperationToString(int op)
|
|
|
|
{
|
|
|
|
const char *str = virshDomainJobOperationTypeToString(op);
|
|
|
|
return str ? _(str) : _("unknown");
|
|
|
|
}
|
|
|
|
|
2019-11-22 14:06:08 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virshDomainJobStatsToDomainJobInfo(virTypedParameterPtr params,
|
|
|
|
int nparams,
|
|
|
|
virDomainJobInfo *info)
|
|
|
|
{
|
|
|
|
if (virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_TIME_ELAPSED,
|
|
|
|
&info->timeElapsed) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_TIME_REMAINING,
|
|
|
|
&info->timeRemaining) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_DATA_TOTAL,
|
|
|
|
&info->dataTotal) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_DATA_PROCESSED,
|
|
|
|
&info->dataProcessed) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_DATA_REMAINING,
|
|
|
|
&info->dataRemaining) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_MEMORY_TOTAL,
|
|
|
|
&info->memTotal) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_MEMORY_PROCESSED,
|
|
|
|
&info->memProcessed) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_MEMORY_REMAINING,
|
|
|
|
&info->memRemaining) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_DISK_TOTAL,
|
|
|
|
&info->fileTotal) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_DISK_PROCESSED,
|
|
|
|
&info->fileProcessed) < 0 ||
|
|
|
|
virTypedParamsGetULLong(params, nparams, VIR_DOMAIN_JOB_DISK_REMAINING,
|
|
|
|
&info->fileRemaining) < 0) {
|
|
|
|
vshSaveLibvirtError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdDomjobinfo(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virDomainJobInfo info;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2013-02-08 08:55:17 +00:00
|
|
|
bool ret = false;
|
|
|
|
const char *unit;
|
|
|
|
double val;
|
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
int nparams = 0;
|
|
|
|
unsigned long long value;
|
2014-08-22 12:29:41 +00:00
|
|
|
unsigned int flags = 0;
|
2016-06-21 11:40:33 +00:00
|
|
|
int ivalue;
|
2020-04-15 10:27:53 +00:00
|
|
|
const char *svalue;
|
2017-04-26 09:59:59 +00:00
|
|
|
int op;
|
2013-02-08 08:55:17 +00:00
|
|
|
int rc;
|
2019-11-25 14:06:17 +00:00
|
|
|
size_t i;
|
|
|
|
bool rawstats = vshCommandOptBool(cmd, "rawstats");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2019-11-22 13:26:56 +00:00
|
|
|
VSH_REQUIRE_OPTION("keep-completed", "completed");
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2014-08-22 12:29:41 +00:00
|
|
|
if (vshCommandOptBool(cmd, "completed"))
|
|
|
|
flags |= VIR_DOMAIN_JOB_STATS_COMPLETED;
|
|
|
|
|
2019-11-22 13:26:56 +00:00
|
|
|
if (vshCommandOptBool(cmd, "keep-completed"))
|
|
|
|
flags |= VIR_DOMAIN_JOB_STATS_KEEP_COMPLETED;
|
|
|
|
|
2013-02-08 08:55:17 +00:00
|
|
|
memset(&info, 0, sizeof(info));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-08-22 12:29:41 +00:00
|
|
|
rc = virDomainGetJobStats(dom, &info.type, ¶ms, &nparams, flags);
|
2013-02-08 08:55:17 +00:00
|
|
|
if (rc == 0) {
|
2019-11-22 14:06:08 +00:00
|
|
|
if (virshDomainJobStatsToDomainJobInfo(params, nparams, &info) < 0)
|
|
|
|
goto cleanup;
|
2013-02-08 08:55:17 +00:00
|
|
|
} else if (last_error->code == VIR_ERR_NO_SUPPORT) {
|
2019-11-25 14:06:17 +00:00
|
|
|
if (flags != 0 || rawstats) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Optional flags or --rawstats are not supported by the daemon"));
|
2014-08-22 12:29:41 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-02-08 08:55:17 +00:00
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG, "detailed statistics not supported\n");
|
|
|
|
vshResetLibvirtError();
|
|
|
|
rc = virDomainGetJobInfo(dom, &info);
|
|
|
|
}
|
|
|
|
if (rc < 0)
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2019-11-25 14:06:17 +00:00
|
|
|
if (rawstats) {
|
|
|
|
vshPrint(ctl, "Job type: %d\n\n", info.type);
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
g_autofree char *par = virTypedParameterToString(¶ms[i]);
|
|
|
|
vshPrint(ctl, "%s: %s\n", params[i].field, NULLSTR(par));
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
vshPrint(ctl, "%-17s %-12s\n", _("Job type:"),
|
2015-06-15 16:53:58 +00:00
|
|
|
virshDomainJobToString(info.type));
|
2019-11-21 16:36:18 +00:00
|
|
|
|
|
|
|
if (info.type == VIR_DOMAIN_JOB_NONE) {
|
2013-09-11 13:49:48 +00:00
|
|
|
ret = true;
|
2013-02-08 08:55:17 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-04-26 09:59:59 +00:00
|
|
|
op = VIR_DOMAIN_JOB_OPERATION_UNKNOWN;
|
|
|
|
if ((rc = virTypedParamsGetInt(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_OPERATION, &op)) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
|
|
|
vshPrint(ctl, "%-17s %-12s\n", _("Operation:"),
|
|
|
|
virshDomainJobOperationToString(op));
|
|
|
|
|
2019-11-21 16:44:00 +00:00
|
|
|
if (!vshCommandOptBool(cmd, "anystats") &&
|
|
|
|
info.type != VIR_DOMAIN_JOB_BOUNDED &&
|
2019-11-21 16:36:18 +00:00
|
|
|
info.type != VIR_DOMAIN_JOB_UNBOUNDED &&
|
|
|
|
(!(flags & VIR_DOMAIN_JOB_STATS_COMPLETED) ||
|
|
|
|
info.type != VIR_DOMAIN_JOB_COMPLETED)) {
|
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-02-08 08:55:17 +00:00
|
|
|
vshPrint(ctl, "%-17s %-12llu ms\n", _("Time elapsed:"), info.timeElapsed);
|
2015-04-23 07:19:12 +00:00
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_TIME_ELAPSED_NET,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu ms\n", _("Time elapsed w/o network:"),
|
|
|
|
value);
|
|
|
|
}
|
|
|
|
|
2013-02-08 08:55:17 +00:00
|
|
|
if (info.type == VIR_DOMAIN_JOB_BOUNDED)
|
virsh: use more compact VIR_ENUM_IMPL
Dan Berrange suggested that using VIR_ENUM_IMPL is more compact
than open-coding switch statements, and still just as forceful
at making us remember to update lists if we add enum values
in the future. Make this change throughout virsh.
Sure enough, doing this change caught that we missed at least
VIR_STORAGE_VOL_NETDIR.
* tools/virsh-domain-monitor.c (vshDomainIOErrorToString)
(vshDomainControlStateToString, vshDomainStateToString)
(vshDomainStateReasonToString): Change switch to enum lookup.
(cmdDomControl, cmdDominfo): Update caller.
* tools/virsh-domain.c (vshDomainVcpuStateToString)
(vshDomainEventToString, vshDomainEventDetailToString): Change
switch to enum lookup.
(vshDomainBlockJobToString, vshDomainJobToString): New functions.
(cmdVcpuinfo, cmdBlockJob, cmdDomjobinfo, cmdEvent): Update
callers.
* tools/virsh-network.c (vshNetworkEventToString): Change switch
to enum lookup.
* tools/virsh-pool.c (vshStoragePoolStateToString): New function.
(cmdPoolList, cmdPoolInfo): Update callers.
* tools/virsh-volume.c (vshVolumeTypeToString): Change switch to
enum lookup.
(cmdVolInfo, cmdVolList): Update callers.
Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-21 19:55:06 +00:00
|
|
|
vshPrint(ctl, "%-17s %-12llu ms\n", _("Time remaining:"),
|
|
|
|
info.timeRemaining);
|
2013-02-08 08:55:17 +00:00
|
|
|
|
|
|
|
if (info.dataTotal || info.dataRemaining || info.dataProcessed) {
|
|
|
|
val = vshPrettyCapacity(info.dataProcessed, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data processed:"), val, unit);
|
|
|
|
val = vshPrettyCapacity(info.dataRemaining, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data remaining:"), val, unit);
|
|
|
|
val = vshPrettyCapacity(info.dataTotal, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Data total:"), val, unit);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info.memTotal || info.memRemaining || info.memProcessed) {
|
|
|
|
val = vshPrettyCapacity(info.memProcessed, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory processed:"), val, unit);
|
|
|
|
val = vshPrettyCapacity(info.memRemaining, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory remaining:"), val, unit);
|
|
|
|
val = vshPrettyCapacity(info.memTotal, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Memory total:"), val, unit);
|
2014-01-13 06:28:10 +00:00
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_MEMORY_BPS,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc && value) {
|
|
|
|
val = vshPrettyCapacity(value, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s/s\n",
|
|
|
|
_("Memory bandwidth:"), val, unit);
|
|
|
|
}
|
2015-11-27 11:30:09 +00:00
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_MEMORY_DIRTY_RATE,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu pages/s\n", _("Dirty rate:"), value);
|
|
|
|
}
|
|
|
|
|
2017-10-09 02:00:03 +00:00
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_MEMORY_PAGE_SIZE,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu bytes\n", _("Page size:"), value);
|
|
|
|
}
|
|
|
|
|
2015-11-27 11:30:09 +00:00
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_MEMORY_ITERATION,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu\n", _("Iteration:"), value);
|
|
|
|
}
|
2018-11-15 14:25:46 +00:00
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_MEMORY_POSTCOPY_REQS,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu\n", _("Postcopy requests:"), value);
|
|
|
|
}
|
2013-02-08 08:55:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info.fileTotal || info.fileRemaining || info.fileProcessed) {
|
|
|
|
val = vshPrettyCapacity(info.fileProcessed, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("File processed:"), val, unit);
|
|
|
|
val = vshPrettyCapacity(info.fileRemaining, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("File remaining:"), val, unit);
|
|
|
|
val = vshPrettyCapacity(info.fileTotal, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("File total:"), val, unit);
|
2014-01-13 06:28:10 +00:00
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_DISK_BPS,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc && value) {
|
|
|
|
val = vshPrettyCapacity(value, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s/s\n",
|
|
|
|
_("File bandwidth:"), val, unit);
|
|
|
|
}
|
2013-02-08 08:55:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_MEMORY_CONSTANT,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu\n", _("Constant pages:"), value);
|
|
|
|
}
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_MEMORY_NORMAL,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu\n", _("Normal pages:"), value);
|
|
|
|
}
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
val = vshPrettyCapacity(value, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Normal data:"), val, unit);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_DOWNTIME,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
2014-08-22 12:29:41 +00:00
|
|
|
if (info.type == VIR_DOMAIN_JOB_COMPLETED) {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu ms\n",
|
|
|
|
_("Total downtime:"), value);
|
|
|
|
} else {
|
|
|
|
vshPrint(ctl, "%-17s %-12llu ms\n",
|
|
|
|
_("Expected downtime:"), value);
|
|
|
|
}
|
2013-02-08 08:55:17 +00:00
|
|
|
}
|
|
|
|
|
2015-04-23 07:19:12 +00:00
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_DOWNTIME_NET,
|
|
|
|
&value)) < 0)
|
|
|
|
goto save_error;
|
|
|
|
else if (rc)
|
|
|
|
vshPrint(ctl, "%-17s %-12llu ms\n", _("Downtime w/o network:"), value);
|
|
|
|
|
2014-01-13 06:28:10 +00:00
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_SETUP_TIME,
|
|
|
|
&value)) < 0)
|
|
|
|
goto save_error;
|
|
|
|
else if (rc)
|
|
|
|
vshPrint(ctl, "%-17s %-12llu ms\n", _("Setup time:"), value);
|
|
|
|
|
2013-02-08 08:55:17 +00:00
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_COMPRESSION_CACHE,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
val = vshPrettyCapacity(value, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Compression cache:"), val, unit);
|
|
|
|
}
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_COMPRESSION_BYTES,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
val = vshPrettyCapacity(value, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Compressed data:"), val, unit);
|
|
|
|
}
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_COMPRESSION_PAGES,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-13llu\n", _("Compressed pages:"), value);
|
|
|
|
}
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-13llu\n", _("Compression cache misses:"), value);
|
|
|
|
}
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-13llu\n", _("Compression overflows:"), value);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2013-02-08 08:55:17 +00:00
|
|
|
|
2016-06-21 11:40:33 +00:00
|
|
|
if ((rc = virTypedParamsGetInt(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_AUTO_CONVERGE_THROTTLE,
|
|
|
|
&ivalue)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
vshPrint(ctl, "%-17s %-13d\n", _("Auto converge throttle:"), ivalue);
|
|
|
|
}
|
|
|
|
|
2019-11-25 16:24:42 +00:00
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_DISK_TEMP_USED,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
val = vshPrettyCapacity(value, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Temporary disk space use:"), val, unit);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rc = virTypedParamsGetULLong(params, nparams,
|
|
|
|
VIR_DOMAIN_JOB_DISK_TEMP_TOTAL,
|
|
|
|
&value)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc) {
|
|
|
|
val = vshPrettyCapacity(value, &unit);
|
|
|
|
vshPrint(ctl, "%-17s %-.3lf %s\n", _("Temporary disk space total:"), val, unit);
|
|
|
|
}
|
|
|
|
|
2020-04-15 10:27:53 +00:00
|
|
|
if ((rc = virTypedParamsGetString(params, nparams, VIR_DOMAIN_JOB_ERRMSG,
|
|
|
|
&svalue)) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
} else if (rc == 1) {
|
|
|
|
vshPrint(ctl, "%-17s %s\n", _("Error message:"), svalue);
|
|
|
|
}
|
|
|
|
|
2013-02-08 08:55:17 +00:00
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-02-08 08:55:17 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
2013-02-08 08:55:17 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
save_error:
|
2013-02-08 08:55:17 +00:00
|
|
|
vshSaveLibvirtError();
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "domjobabort" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domjobabort[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("abort active domain job")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Aborts the currently running domain job")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domjobabort[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2022-05-10 13:20:25 +00:00
|
|
|
{.name = "postcopy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("interrupt post-copy migration")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomjobabort(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2022-05-10 13:20:25 +00:00
|
|
|
unsigned int flags = 0;
|
|
|
|
int rc;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2022-05-10 13:20:25 +00:00
|
|
|
if (vshCommandOptBool(cmd, "postcopy"))
|
|
|
|
flags |= VIR_DOMAIN_ABORT_JOB_POSTCOPY;
|
|
|
|
|
|
|
|
if (flags == 0)
|
|
|
|
rc = virDomainAbortJob(dom);
|
|
|
|
else
|
|
|
|
rc = virDomainAbortJobFlags(dom, flags);
|
|
|
|
|
|
|
|
if (rc < 0)
|
2021-09-24 15:17:46 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-09-24 15:17:46 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "vcpucount" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_vcpucount[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("domain vcpu counts")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Returns the number of virtual CPUs used by the domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_vcpucount[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "maximum",
|
|
|
|
.type = VSH_OT_BOOL,
|
2013-04-15 09:07:23 +00:00
|
|
|
.help = N_("get maximum count of vcpus")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "active",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("get number of currently active vcpus")
|
|
|
|
},
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_LIVE(N_("get value from running domain")),
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_CONFIG(N_("get value to be used on next boot")),
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_CURRENT(N_("get value according to current domain state")),
|
2013-06-07 15:12:47 +00:00
|
|
|
{.name = "guest",
|
2013-04-12 12:30:41 +00:00
|
|
|
.type = VSH_OT_BOOL,
|
2013-06-07 15:12:47 +00:00
|
|
|
.help = N_("retrieve vcpu count from the guest instead of the hypervisor")
|
2013-04-12 12:30:41 +00:00
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2013-04-15 09:07:23 +00:00
|
|
|
/**
|
|
|
|
* Collect the number of vCPUs for a guest possibly with fallback means.
|
|
|
|
*
|
|
|
|
* Returns the count of vCPUs for a domain and certain flags. Returns -2 in case
|
|
|
|
* of error. If @checkState is true, in case live stats can't be collected when
|
|
|
|
* the domain is inactive or persistent stats can't be collected if domain is
|
|
|
|
* transient -1 is returned and no error is reported.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
2015-06-15 16:53:58 +00:00
|
|
|
virshCPUCountCollect(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
unsigned int flags,
|
|
|
|
bool checkState)
|
2013-04-15 09:07:23 +00:00
|
|
|
{
|
|
|
|
virDomainInfo info;
|
|
|
|
int count;
|
2021-08-11 11:57:15 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2021-08-11 11:21:18 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2013-04-15 09:07:23 +00:00
|
|
|
|
|
|
|
if (checkState &&
|
|
|
|
((flags & VIR_DOMAIN_AFFECT_LIVE && virDomainIsActive(dom) < 1) ||
|
|
|
|
(flags & VIR_DOMAIN_AFFECT_CONFIG && virDomainIsPersistent(dom) < 1)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* In all cases, try the new API first; if it fails because we are talking
|
|
|
|
* to an older daemon, generally we try a fallback API before giving up.
|
|
|
|
* --current requires the new API, since we don't know whether the domain is
|
|
|
|
* running or inactive. */
|
|
|
|
if ((count = virDomainGetVcpusFlags(dom, flags)) >= 0)
|
|
|
|
return count;
|
|
|
|
|
|
|
|
/* fallback code */
|
2016-10-03 14:46:11 +00:00
|
|
|
if (!(last_error->code == VIR_ERR_NO_SUPPORT ||
|
|
|
|
last_error->code == VIR_ERR_INVALID_ARG))
|
2021-09-23 23:25:08 +00:00
|
|
|
return -2;
|
2013-04-15 09:07:23 +00:00
|
|
|
|
2016-10-03 14:46:11 +00:00
|
|
|
if (flags & VIR_DOMAIN_VCPU_GUEST) {
|
|
|
|
vshError(ctl, "%s", _("Failed to retrieve vCPU count from the guest"));
|
2021-09-23 23:25:08 +00:00
|
|
|
return -2;
|
2016-10-03 14:46:11 +00:00
|
|
|
}
|
2013-04-12 12:30:41 +00:00
|
|
|
|
2016-10-03 14:46:11 +00:00
|
|
|
if (!(flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG)) &&
|
|
|
|
virDomainIsActive(dom) == 1)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2013-04-15 09:07:23 +00:00
|
|
|
|
2016-10-03 14:46:11 +00:00
|
|
|
vshResetLibvirtError();
|
2013-04-15 09:07:23 +00:00
|
|
|
|
2016-10-03 14:46:11 +00:00
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE) {
|
2021-09-23 23:25:08 +00:00
|
|
|
if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
|
|
|
|
return virDomainGetMaxVcpus(dom);
|
2013-04-15 09:07:23 +00:00
|
|
|
|
2021-09-23 23:25:08 +00:00
|
|
|
if (virDomainGetInfo(dom, &info) < 0)
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
return info.nrVirtCpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virshDomainGetXMLFromDom(ctl, dom, VIR_DOMAIN_XML_INACTIVE,
|
|
|
|
&xml, &ctxt) < 0)
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
|
|
|
|
if (virXPathInt("string(/domain/vcpu)", ctxt, &count) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to retrieve maximum vcpu count"));
|
|
|
|
return -2;
|
2016-10-03 14:46:11 +00:00
|
|
|
}
|
|
|
|
} else {
|
2021-09-23 23:25:08 +00:00
|
|
|
if (virXPathInt("string(/domain/vcpu/@current)", ctxt, &count) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to retrieve current vcpu count"));
|
|
|
|
return -2;
|
2016-10-03 14:46:11 +00:00
|
|
|
}
|
|
|
|
}
|
2013-04-15 09:07:23 +00:00
|
|
|
|
2021-09-23 23:25:08 +00:00
|
|
|
return count;
|
2013-04-15 09:07:23 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdVcpucount(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool maximum = vshCommandOptBool(cmd, "maximum");
|
|
|
|
bool active = vshCommandOptBool(cmd, "active");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
2013-06-07 15:12:47 +00:00
|
|
|
bool guest = vshCommandOptBool(cmd, "guest");
|
|
|
|
bool all = maximum + active + current + config + live + guest == 0;
|
2013-04-15 09:07:23 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* Backwards compatibility: prior to 0.9.4,
|
|
|
|
* VIR_DOMAIN_AFFECT_CURRENT was unsupported, and --current meant
|
|
|
|
* the opposite of --maximum. Translate the old '--current
|
|
|
|
* --live' into the new '--active --live', while treating the new
|
|
|
|
* '--maximum --current' correctly rather than rejecting it as
|
|
|
|
* '--maximum --active'. */
|
2013-04-15 09:07:23 +00:00
|
|
|
if (!maximum && !active && current)
|
2012-07-25 15:37:18 +00:00
|
|
|
current = false;
|
|
|
|
|
2013-10-30 12:58:09 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(live, config)
|
2013-04-15 09:07:23 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(active, maximum);
|
2013-06-07 15:12:47 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(guest, config);
|
2013-04-15 09:07:23 +00:00
|
|
|
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (maximum)
|
|
|
|
flags |= VIR_DOMAIN_VCPU_MAXIMUM;
|
2013-06-07 15:12:47 +00:00
|
|
|
if (guest)
|
|
|
|
flags |= VIR_DOMAIN_VCPU_GUEST;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-04-15 09:07:23 +00:00
|
|
|
if (all) {
|
2015-06-15 16:53:58 +00:00
|
|
|
int conf_max = virshCPUCountCollect(ctl, dom,
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG |
|
|
|
|
VIR_DOMAIN_VCPU_MAXIMUM, true);
|
|
|
|
int conf_cur = virshCPUCountCollect(ctl, dom,
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG, true);
|
|
|
|
int live_max = virshCPUCountCollect(ctl, dom,
|
|
|
|
VIR_DOMAIN_AFFECT_LIVE |
|
|
|
|
VIR_DOMAIN_VCPU_MAXIMUM, true);
|
|
|
|
int live_cur = virshCPUCountCollect(ctl, dom,
|
|
|
|
VIR_DOMAIN_AFFECT_LIVE, true);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-04-15 09:07:23 +00:00
|
|
|
if (conf_max == -2 || conf_cur == -2 || live_max == -2 || live_cur == -2)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-04-15 09:07:23 +00:00
|
|
|
#define PRINT_COUNT(VAR, WHICH, STATE) if (VAR > 0) \
|
|
|
|
vshPrint(ctl, "%-12s %-12s %3d\n", WHICH, STATE, VAR)
|
|
|
|
PRINT_COUNT(conf_max, _("maximum"), _("config"));
|
|
|
|
PRINT_COUNT(live_max, _("maximum"), _("live"));
|
|
|
|
PRINT_COUNT(conf_cur, _("current"), _("config"));
|
|
|
|
PRINT_COUNT(live_cur, _("current"), _("live"));
|
|
|
|
#undef PRINT_COUNT
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-04-15 09:07:23 +00:00
|
|
|
} else {
|
2015-06-15 16:53:58 +00:00
|
|
|
int count = virshCPUCountCollect(ctl, dom, flags, false);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-04-15 09:07:23 +00:00
|
|
|
if (count < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-04-15 09:07:23 +00:00
|
|
|
vshPrint(ctl, "%d\n", count);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "vcpuinfo" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_vcpuinfo[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("detailed domain vcpu information")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Returns basic information about the domain virtual CPUs.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_vcpuinfo[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2014-06-05 11:16:00 +00:00
|
|
|
{.name = "pretty",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("return human readable output")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2016-09-29 10:59:37 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virshVcpuinfoPrintAffinity(vshControl *ctl,
|
|
|
|
const unsigned char *cpumap,
|
|
|
|
int maxcpu,
|
|
|
|
bool pretty)
|
|
|
|
{
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = NULL;
|
2016-09-29 10:59:37 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
vshPrint(ctl, "%-15s ", _("CPU Affinity:"));
|
|
|
|
if (pretty) {
|
2017-08-23 07:05:41 +00:00
|
|
|
if (!(str = virBitmapDataFormat(cpumap, VIR_CPU_MAPLEN(maxcpu))))
|
2021-08-12 07:59:20 +00:00
|
|
|
return -1;
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrint(ctl, _("%1$s (out of %2$d)"), str, maxcpu);
|
2016-09-29 10:59:37 +00:00
|
|
|
} else {
|
2022-02-28 14:00:00 +00:00
|
|
|
for (i = 0; i < maxcpu; i++) {
|
|
|
|
if (VIR_CPU_USED(cpumap, i))
|
|
|
|
vshPrint(ctl, "y");
|
|
|
|
else
|
|
|
|
vshPrint(ctl, "-");
|
|
|
|
}
|
2016-09-29 10:59:37 +00:00
|
|
|
}
|
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return 0;
|
2016-09-29 10:59:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-11 07:16:13 +00:00
|
|
|
static virBitmap *
|
2016-10-11 16:03:50 +00:00
|
|
|
virshDomainGetVcpuBitmap(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
bool inactive)
|
|
|
|
{
|
|
|
|
unsigned int flags = 0;
|
2021-09-15 13:13:24 +00:00
|
|
|
g_autoptr(virBitmap) cpumap = NULL;
|
2021-08-11 11:57:15 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2021-08-11 11:21:18 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree xmlNodePtr *nodes = NULL;
|
2016-10-11 16:03:50 +00:00
|
|
|
int nnodes;
|
|
|
|
size_t i;
|
|
|
|
unsigned int curvcpus = 0;
|
|
|
|
unsigned int maxvcpus = 0;
|
|
|
|
unsigned int vcpuid;
|
|
|
|
|
|
|
|
if (inactive)
|
|
|
|
flags |= VIR_DOMAIN_XML_INACTIVE;
|
|
|
|
|
2017-04-11 15:33:53 +00:00
|
|
|
if (virshDomainGetXMLFromDom(ctl, dom, flags, &xml, &ctxt) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2016-10-11 16:03:50 +00:00
|
|
|
|
|
|
|
if (virXPathUInt("string(/domain/vcpu)", ctxt, &maxvcpus) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to retrieve maximum vcpu count"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2016-10-11 16:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ignore_value(virXPathUInt("string(/domain/vcpu/@current)", ctxt, &curvcpus));
|
|
|
|
|
|
|
|
if (curvcpus == 0)
|
|
|
|
curvcpus = maxvcpus;
|
|
|
|
|
2021-09-15 13:13:24 +00:00
|
|
|
cpumap = virBitmapNew(maxvcpus);
|
2016-10-11 16:03:50 +00:00
|
|
|
|
|
|
|
if ((nnodes = virXPathNodeSet("/domain/vcpus/vcpu", ctxt, &nodes)) <= 0) {
|
|
|
|
/* if the specific vcpu state is missing provide a fallback */
|
|
|
|
for (i = 0; i < curvcpus; i++)
|
2021-09-15 13:13:24 +00:00
|
|
|
ignore_value(virBitmapSetBit(cpumap, i));
|
2016-10-11 16:03:50 +00:00
|
|
|
|
2021-09-15 13:13:24 +00:00
|
|
|
return g_steal_pointer(&cpumap);
|
2016-10-11 16:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nnodes; i++) {
|
2021-08-11 13:25:20 +00:00
|
|
|
g_autofree char *online = NULL;
|
|
|
|
|
2016-10-11 16:03:50 +00:00
|
|
|
ctxt->node = nodes[i];
|
|
|
|
|
|
|
|
if (virXPathUInt("string(@id)", ctxt, &vcpuid) < 0 ||
|
|
|
|
!(online = virXPathString("string(@enabled)", ctxt)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (STREQ(online, "yes"))
|
2021-09-15 13:13:24 +00:00
|
|
|
ignore_value(virBitmapSetBit(cpumap, vcpuid));
|
2016-10-11 16:03:50 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 13:13:24 +00:00
|
|
|
if (virBitmapCountBits(cpumap) != curvcpus) {
|
2016-10-11 16:03:50 +00:00
|
|
|
vshError(ctl, "%s", _("Failed to retrieve vcpu state bitmap"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2016-10-11 16:03:50 +00:00
|
|
|
}
|
|
|
|
|
2021-09-15 13:13:24 +00:00
|
|
|
return g_steal_pointer(&cpumap);
|
2016-10-11 16:03:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-29 14:37:35 +00:00
|
|
|
static bool
|
|
|
|
virshVcpuinfoInactive(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
int maxcpu,
|
|
|
|
bool pretty)
|
|
|
|
{
|
2020-06-26 22:10:40 +00:00
|
|
|
g_autofree unsigned char *cpumaps = NULL;
|
2016-09-29 14:37:35 +00:00
|
|
|
size_t cpumaplen;
|
2020-06-26 22:10:40 +00:00
|
|
|
g_autoptr(virBitmap) vcpus = NULL;
|
2016-10-11 16:03:50 +00:00
|
|
|
ssize_t nextvcpu = -1;
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
if (!(vcpus = virshDomainGetVcpuBitmap(ctl, dom, true)))
|
2020-06-26 22:10:40 +00:00
|
|
|
return false;
|
2016-09-29 14:37:35 +00:00
|
|
|
|
|
|
|
cpumaplen = VIR_CPU_MAPLEN(maxcpu);
|
2020-10-05 16:50:09 +00:00
|
|
|
cpumaps = g_new0(unsigned char, virBitmapSize(vcpus) * cpumaplen);
|
2016-09-29 14:37:35 +00:00
|
|
|
|
2020-08-02 21:33:07 +00:00
|
|
|
if (virDomainGetVcpuPinInfo(dom, virBitmapSize(vcpus),
|
|
|
|
cpumaps, cpumaplen,
|
|
|
|
VIR_DOMAIN_AFFECT_CONFIG) < 0)
|
2020-06-26 22:10:40 +00:00
|
|
|
return false;
|
2016-09-29 14:37:35 +00:00
|
|
|
|
2016-10-11 16:03:50 +00:00
|
|
|
while ((nextvcpu = virBitmapNextSetBit(vcpus, nextvcpu)) >= 0) {
|
|
|
|
if (!first)
|
2016-09-29 14:37:35 +00:00
|
|
|
vshPrint(ctl, "\n");
|
2016-10-11 16:03:50 +00:00
|
|
|
first = false;
|
2016-09-29 14:37:35 +00:00
|
|
|
|
2016-10-11 16:03:50 +00:00
|
|
|
vshPrint(ctl, "%-15s %zd\n", _("VCPU:"), nextvcpu);
|
2016-09-29 14:37:35 +00:00
|
|
|
vshPrint(ctl, "%-15s %s\n", _("CPU:"), _("N/A"));
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("State:"), _("N/A"));
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("CPU time"), _("N/A"));
|
|
|
|
|
2016-10-11 16:03:50 +00:00
|
|
|
if (virshVcpuinfoPrintAffinity(ctl,
|
|
|
|
VIR_GET_CPUMAP(cpumaps, cpumaplen, nextvcpu),
|
2016-09-29 14:37:35 +00:00
|
|
|
maxcpu, pretty) < 0)
|
2020-06-26 22:10:40 +00:00
|
|
|
return false;
|
2016-09-29 14:37:35 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:10:40 +00:00
|
|
|
return true;
|
2016-09-29 14:37:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdVcpuinfo(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
virDomainInfo info;
|
2020-06-26 22:10:41 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
|
|
|
g_autofree virVcpuInfoPtr cpuinfo = NULL;
|
|
|
|
g_autofree unsigned char *cpumaps = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
int ncpus, maxcpu;
|
|
|
|
size_t cpumaplen;
|
2014-06-05 11:16:00 +00:00
|
|
|
bool pretty = vshCommandOptBool(cmd, "pretty");
|
2016-09-29 10:59:37 +00:00
|
|
|
int n;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((maxcpu = virshNodeGetCPUCount(priv->conn)) < 0)
|
2020-06-26 22:10:41 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-06-05 08:42:19 +00:00
|
|
|
if (virDomainGetInfo(dom, &info) != 0)
|
2020-06-26 22:10:41 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2020-10-05 16:50:09 +00:00
|
|
|
cpuinfo = g_new0(virVcpuInfo, info.nrVirtCpu);
|
2012-07-25 15:37:18 +00:00
|
|
|
cpumaplen = VIR_CPU_MAPLEN(maxcpu);
|
2020-10-05 16:50:09 +00:00
|
|
|
cpumaps = g_new0(unsigned char, info.nrVirtCpu * cpumaplen);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if ((ncpus = virDomainGetVcpus(dom,
|
|
|
|
cpuinfo, info.nrVirtCpu,
|
2014-06-05 08:42:23 +00:00
|
|
|
cpumaps, cpumaplen)) < 0) {
|
|
|
|
if (info.state != VIR_DOMAIN_SHUTOFF)
|
2020-06-26 22:10:41 +00:00
|
|
|
return false;
|
2014-06-05 08:42:23 +00:00
|
|
|
|
2016-10-11 16:03:50 +00:00
|
|
|
vshResetLibvirtError();
|
|
|
|
|
2016-09-29 14:37:35 +00:00
|
|
|
/* for offline VMs we can return pinning information */
|
2020-06-26 22:10:41 +00:00
|
|
|
return virshVcpuinfoInactive(ctl, dom, maxcpu, pretty);
|
2014-06-05 08:42:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (n = 0; n < ncpus; n++) {
|
2016-09-29 14:37:35 +00:00
|
|
|
vshPrint(ctl, "%-15s %d\n", _("VCPU:"), cpuinfo[n].number);
|
|
|
|
vshPrint(ctl, "%-15s %d\n", _("CPU:"), cpuinfo[n].cpu);
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("State:"),
|
|
|
|
virshDomainVcpuStateToString(cpuinfo[n].state));
|
|
|
|
if (cpuinfo[n].cpuTime != 0) {
|
|
|
|
double cpuUsed = cpuinfo[n].cpuTime;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2016-09-29 14:37:35 +00:00
|
|
|
cpuUsed /= 1000000000.0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2016-09-29 14:37:35 +00:00
|
|
|
vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2014-06-05 11:16:00 +00:00
|
|
|
|
2016-09-29 10:59:37 +00:00
|
|
|
if (virshVcpuinfoPrintAffinity(ctl, VIR_GET_CPUMAP(cpumaps, cpumaplen, n),
|
|
|
|
maxcpu, pretty) < 0)
|
2020-06-26 22:10:41 +00:00
|
|
|
return false;
|
2016-09-29 10:59:37 +00:00
|
|
|
|
2014-06-05 08:42:23 +00:00
|
|
|
if (n < (ncpus - 1))
|
|
|
|
vshPrint(ctl, "\n");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-26 22:10:41 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "vcpupin" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_vcpupin[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("control or query domain vcpu affinity")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Pin domain VCPUs to host physical CPUs.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_vcpupin[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "vcpu",
|
|
|
|
.type = VSH_OT_INT,
|
2020-09-11 07:13:12 +00:00
|
|
|
.completer = virshDomainVcpuCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("vcpu number")
|
|
|
|
},
|
|
|
|
{.name = "cpulist",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:54 +00:00
|
|
|
.flags = VSH_OFLAG_EMPTY_OK,
|
2020-09-11 07:13:14 +00:00
|
|
|
.completer = virshDomainCpulistCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("host cpu number(s) to set, or omit option to query")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2012-08-21 09:18:39 +00:00
|
|
|
/*
|
|
|
|
* Helper function to print vcpupin info.
|
|
|
|
*/
|
|
|
|
static bool
|
2016-02-12 13:09:02 +00:00
|
|
|
virshPrintPinInfo(vshControl *ctl,
|
|
|
|
unsigned char *cpumap,
|
|
|
|
size_t cpumaplen)
|
2012-08-21 09:18:39 +00:00
|
|
|
{
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = NULL;
|
2012-08-21 09:18:39 +00:00
|
|
|
|
2017-08-23 07:05:41 +00:00
|
|
|
if (!(str = virBitmapDataFormat(cpumap, cpumaplen)))
|
2012-08-21 09:18:39 +00:00
|
|
|
return false;
|
|
|
|
|
2015-03-26 14:24:09 +00:00
|
|
|
vshPrint(ctl, "%s", str);
|
2012-08-21 09:18:39 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-12 09:56:08 +00:00
|
|
|
|
|
|
|
static bool
|
|
|
|
virshVcpuPinQuery(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
unsigned int vcpu,
|
|
|
|
bool got_vcpu,
|
|
|
|
int maxcpu,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree unsigned char *cpumap = NULL;
|
2016-02-17 14:53:42 +00:00
|
|
|
unsigned int countFlags = flags | VIR_DOMAIN_VCPU_MAXIMUM;
|
2016-02-12 09:56:08 +00:00
|
|
|
int cpumaplen;
|
|
|
|
size_t i;
|
|
|
|
int ncpus;
|
2021-08-11 13:12:02 +00:00
|
|
|
g_autoptr(vshTable) table = NULL;
|
2016-02-12 09:56:08 +00:00
|
|
|
|
2016-02-17 14:53:42 +00:00
|
|
|
if ((ncpus = virshCPUCountCollect(ctl, dom, countFlags, true)) < 0) {
|
2016-02-12 09:56:08 +00:00
|
|
|
if (ncpus == -1) {
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE)
|
|
|
|
vshError(ctl, "%s", _("cannot get vcpupin for offline domain"));
|
|
|
|
else
|
|
|
|
vshError(ctl, "%s", _("cannot get vcpupin for transient domain"));
|
|
|
|
}
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2016-02-12 09:56:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (got_vcpu && vcpu >= ncpus) {
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_LIVE ||
|
|
|
|
(!(flags & VIR_DOMAIN_AFFECT_CONFIG) &&
|
|
|
|
virDomainIsActive(dom) == 1))
|
|
|
|
vshError(ctl,
|
2023-03-09 14:54:42 +00:00
|
|
|
_("vcpu %1$d is out of range of live cpu count %2$d"),
|
2016-02-12 09:56:08 +00:00
|
|
|
vcpu, ncpus);
|
|
|
|
else
|
|
|
|
vshError(ctl,
|
2023-03-09 14:54:42 +00:00
|
|
|
_("vcpu %1$d is out of range of persistent cpu count %2$d"),
|
2016-02-12 09:56:08 +00:00
|
|
|
vcpu, ncpus);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2016-02-12 09:56:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cpumaplen = VIR_CPU_MAPLEN(maxcpu);
|
2020-10-05 16:50:09 +00:00
|
|
|
cpumap = g_new0(unsigned char, ncpus * cpumaplen);
|
2016-02-12 09:56:08 +00:00
|
|
|
if ((ncpus = virDomainGetVcpuPinInfo(dom, ncpus, cpumap,
|
|
|
|
cpumaplen, flags)) >= 0) {
|
2018-09-21 14:17:21 +00:00
|
|
|
table = vshTableNew(_("VCPU"), _("CPU Affinity"), NULL);
|
|
|
|
if (!table)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2018-09-21 14:17:21 +00:00
|
|
|
|
2016-02-12 09:56:08 +00:00
|
|
|
for (i = 0; i < ncpus; i++) {
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *pinInfo = NULL;
|
|
|
|
g_autofree char *vcpuStr = NULL;
|
2016-02-12 09:56:08 +00:00
|
|
|
if (got_vcpu && i != vcpu)
|
|
|
|
continue;
|
|
|
|
|
2018-12-19 03:17:01 +00:00
|
|
|
if (!(pinInfo = virBitmapDataFormat(VIR_GET_CPUMAP(cpumap, cpumaplen, i),
|
|
|
|
cpumaplen)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2018-09-21 14:17:21 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
vcpuStr = g_strdup_printf("%zu", i);
|
2018-09-21 14:17:21 +00:00
|
|
|
|
|
|
|
if (vshTableRowAppend(table, vcpuStr, pinInfo, NULL) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2016-02-12 09:56:08 +00:00
|
|
|
}
|
2018-09-21 14:17:21 +00:00
|
|
|
|
|
|
|
vshTablePrintToStdout(table, ctl);
|
2016-02-12 09:56:08 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2016-02-12 09:56:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-28 11:36:30 +00:00
|
|
|
static unsigned char *
|
2015-06-15 16:53:58 +00:00
|
|
|
virshParseCPUList(vshControl *ctl, int *cpumaplen,
|
|
|
|
const char *cpulist, int maxcpu)
|
2013-03-28 11:36:30 +00:00
|
|
|
{
|
|
|
|
unsigned char *cpumap = NULL;
|
2021-12-07 16:22:26 +00:00
|
|
|
g_autoptr(virBitmap) map = NULL;
|
2013-03-28 11:36:30 +00:00
|
|
|
|
2015-04-01 16:46:56 +00:00
|
|
|
if (cpulist[0] == 'r') {
|
2020-10-01 15:42:11 +00:00
|
|
|
map = virBitmapNew(maxcpu);
|
2015-04-01 16:46:56 +00:00
|
|
|
virBitmapSetAll(map);
|
|
|
|
} else {
|
2020-07-28 17:50:28 +00:00
|
|
|
int lastcpu;
|
|
|
|
|
2016-06-17 12:56:45 +00:00
|
|
|
if (virBitmapParse(cpulist, &map, 1024) < 0 ||
|
2015-05-11 08:25:19 +00:00
|
|
|
virBitmapIsAllClear(map)) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid cpulist '%1$s'"), cpulist);
|
2021-12-07 16:22:26 +00:00
|
|
|
return NULL;
|
2015-05-11 08:25:19 +00:00
|
|
|
}
|
2020-07-28 17:50:28 +00:00
|
|
|
lastcpu = virBitmapLastSetBit(map);
|
2015-05-11 08:25:19 +00:00
|
|
|
if (lastcpu >= maxcpu) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("CPU %1$d in cpulist '%2$s' exceed the maxcpu %3$d"),
|
2015-05-11 08:25:19 +00:00
|
|
|
lastcpu, cpulist, maxcpu);
|
2021-12-07 16:22:26 +00:00
|
|
|
return NULL;
|
2015-05-11 08:25:19 +00:00
|
|
|
}
|
2013-03-28 11:36:30 +00:00
|
|
|
}
|
|
|
|
|
2015-04-01 16:46:56 +00:00
|
|
|
if (virBitmapToData(map, &cpumap, cpumaplen) < 0)
|
2021-12-07 16:22:26 +00:00
|
|
|
return NULL;
|
2013-03-28 11:36:30 +00:00
|
|
|
|
2015-04-01 16:46:56 +00:00
|
|
|
return cpumap;
|
2013-03-28 11:36:30 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdVcpuPin(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2014-05-29 03:34:40 +00:00
|
|
|
unsigned int vcpu = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *cpulist = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree unsigned char *cpumap = NULL;
|
2015-04-01 16:46:56 +00:00
|
|
|
int cpumaplen;
|
2016-02-12 09:56:08 +00:00
|
|
|
int maxcpu;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
2014-05-29 03:34:40 +00:00
|
|
|
int got_vcpu;
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "cpulist", &cpulist) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-02-20 07:21:05 +00:00
|
|
|
if (!cpulist)
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(live, config);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if ((got_vcpu = vshCommandOptUInt(ctl, cmd, "vcpu", &vcpu)) < 0)
|
2015-02-20 07:21:05 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-05-29 03:34:40 +00:00
|
|
|
/* In pin mode, "vcpu" is necessary */
|
2015-02-20 07:21:05 +00:00
|
|
|
if (cpulist && got_vcpu == 0) {
|
2014-05-29 03:34:40 +00:00
|
|
|
vshError(ctl, "%s", _("vcpupin: Missing vCPU number in pin mode."));
|
2015-02-20 07:21:05 +00:00
|
|
|
return false;
|
2014-05-29 03:34:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((maxcpu = virshNodeGetCPUCount(priv->conn)) < 0)
|
2015-02-20 07:21:05 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2015-02-20 07:21:05 +00:00
|
|
|
return false;
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* Query mode: show CPU affinity information then exit.*/
|
2015-02-20 07:21:05 +00:00
|
|
|
if (!cpulist) {
|
2021-08-12 07:59:20 +00:00
|
|
|
return virshVcpuPinQuery(ctl, dom, vcpu, got_vcpu, maxcpu, flags);
|
2016-02-12 09:56:08 +00:00
|
|
|
}
|
2015-06-29 02:10:15 +00:00
|
|
|
|
2020-01-24 20:30:04 +00:00
|
|
|
/* Pin mode: pinning specified vcpu to specified physical cpus */
|
2016-02-12 09:56:08 +00:00
|
|
|
if (!(cpumap = virshParseCPUList(ctl, &cpumaplen, cpulist, maxcpu)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-26 14:10:50 +00:00
|
|
|
|
2016-02-12 09:56:08 +00:00
|
|
|
/* use old API without any explicit flags */
|
|
|
|
if (flags == VIR_DOMAIN_AFFECT_CURRENT && !current) {
|
|
|
|
if (virDomainPinVcpu(dom, vcpu, cpumap, cpumaplen) != 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
} else {
|
2016-02-12 09:56:08 +00:00
|
|
|
if (virDomainPinVcpuFlags(dom, vcpu, cpumap, cpumaplen, flags) != 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2012-08-21 09:18:40 +00:00
|
|
|
/*
|
|
|
|
* "emulatorpin" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_emulatorpin[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("control or query domain emulator affinity")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Pin domain emulator threads to host physical CPUs.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-08-21 09:18:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_emulatorpin[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "cpulist",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:54 +00:00
|
|
|
.flags = VSH_OFLAG_EMPTY_OK,
|
2020-09-11 07:13:14 +00:00
|
|
|
.completer = virshDomainCpulistCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("host cpu number(s) to set, or omit option to query")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-08-21 09:18:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdEmulatorPin(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-08-21 09:18:40 +00:00
|
|
|
const char *cpulist = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree unsigned char *cpumap = NULL;
|
2015-04-01 16:46:56 +00:00
|
|
|
int cpumaplen;
|
2013-03-28 11:36:30 +00:00
|
|
|
int maxcpu;
|
2012-08-21 09:18:40 +00:00
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool query = false; /* Query mode if no cpulist */
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-08-21 09:18:40 +00:00
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
/* none of the options were specified */
|
|
|
|
if (!current && !live && !config)
|
|
|
|
flags = -1;
|
2012-08-21 09:18:40 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-08-21 09:18:40 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "cpulist", &cpulist) < 0) {
|
2012-08-21 09:18:40 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
query = !cpulist;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((maxcpu = virshNodeGetCPUCount(priv->conn)) < 0) {
|
2012-08-21 09:18:40 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Query mode: show CPU affinity information then exit.*/
|
|
|
|
if (query) {
|
2021-08-12 07:59:20 +00:00
|
|
|
bool ret = false;
|
|
|
|
|
2012-08-21 09:18:40 +00:00
|
|
|
/* When query mode and neither "live", "config" nor "current"
|
|
|
|
* is specified, set VIR_DOMAIN_AFFECT_CURRENT as flags */
|
|
|
|
if (flags == -1)
|
|
|
|
flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
|
2015-04-01 16:46:56 +00:00
|
|
|
cpumaplen = VIR_CPU_MAPLEN(maxcpu);
|
2020-10-05 16:50:09 +00:00
|
|
|
cpumap = g_new0(unsigned char, cpumaplen);
|
2015-03-26 14:24:09 +00:00
|
|
|
if (virDomainGetEmulatorPinInfo(dom, cpumap,
|
2012-08-21 09:18:40 +00:00
|
|
|
cpumaplen, flags) >= 0) {
|
2014-02-26 10:54:25 +00:00
|
|
|
vshPrintExtra(ctl, "%s %s\n", _("emulator:"), _("CPU Affinity"));
|
|
|
|
vshPrintExtra(ctl, "----------------------------------\n");
|
|
|
|
vshPrintExtra(ctl, " *: ");
|
2016-02-12 13:09:02 +00:00
|
|
|
ret = virshPrintPinInfo(ctl, cpumap, cpumaplen);
|
2012-08-21 09:18:40 +00:00
|
|
|
vshPrint(ctl, "\n");
|
|
|
|
}
|
2021-08-12 07:59:20 +00:00
|
|
|
return ret;
|
2012-08-21 09:18:40 +00:00
|
|
|
}
|
|
|
|
|
2020-01-24 20:30:04 +00:00
|
|
|
/* Pin mode: pinning emulator threads to specified physical cpus */
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(cpumap = virshParseCPUList(ctl, &cpumaplen, cpulist, maxcpu)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-08-21 09:18:40 +00:00
|
|
|
|
|
|
|
if (flags == -1)
|
|
|
|
flags = VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
|
|
|
if (virDomainPinEmulator(dom, cpumap, cpumaplen, flags) != 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-08-21 09:18:40 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-08-21 09:18:40 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "setvcpus" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_setvcpus[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("change number of virtual CPUs")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Change the number of virtual CPUs in the guest domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_setvcpus[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "count",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("number of virtual CPUs")
|
|
|
|
},
|
|
|
|
{.name = "maximum",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set maximum limit on next boot")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-06-07 15:12:47 +00:00
|
|
|
{.name = "guest",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("modify cpu state in the guest")
|
|
|
|
},
|
2016-09-20 12:08:55 +00:00
|
|
|
{.name = "hotpluggable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("make added vcpus hot(un)pluggable")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-10-22 03:27:35 +00:00
|
|
|
unsigned int count = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool maximum = vshCommandOptBool(cmd, "maximum");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
2013-06-07 15:12:47 +00:00
|
|
|
bool guest = vshCommandOptBool(cmd, "guest");
|
2016-09-20 12:08:55 +00:00
|
|
|
bool hotpluggable = vshCommandOptBool(cmd, "hotpluggable");
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
2013-06-07 15:12:47 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(guest, config);
|
2013-03-07 12:38:19 +00:00
|
|
|
|
2015-03-20 14:39:03 +00:00
|
|
|
VSH_REQUIRE_OPTION_VAR(maximum, config);
|
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2013-06-07 15:12:47 +00:00
|
|
|
if (guest)
|
|
|
|
flags |= VIR_DOMAIN_VCPU_GUEST;
|
2015-03-20 14:39:03 +00:00
|
|
|
if (maximum)
|
|
|
|
flags |= VIR_DOMAIN_VCPU_MAXIMUM;
|
2016-09-20 12:08:55 +00:00
|
|
|
if (hotpluggable)
|
|
|
|
flags |= VIR_DOMAIN_VCPU_HOTPLUGGABLE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-10-22 03:27:35 +00:00
|
|
|
if (vshCommandOptUInt(ctl, cmd, "count", &count) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-10-22 03:27:35 +00:00
|
|
|
if (count == 0) {
|
|
|
|
vshError(ctl, _("Can't set 0 processors for a VM"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-10-22 03:27:35 +00:00
|
|
|
}
|
|
|
|
|
2015-03-20 14:39:03 +00:00
|
|
|
/* none of the options were specified */
|
|
|
|
if (!current && flags == 0) {
|
2013-08-13 09:14:56 +00:00
|
|
|
if (virDomainSetVcpus(dom, count) != 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
} else {
|
2013-08-13 09:14:56 +00:00
|
|
|
if (virDomainSetVcpusFlags(dom, count, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2016-06-20 07:57:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "guestvcpus" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_guestvcpus[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("query or modify state of vcpu in the guest (via agent)")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Use the guest agent to query or set cpu state from guest's "
|
|
|
|
"point of view")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_guestvcpus[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2016-06-20 07:57:53 +00:00
|
|
|
{.name = "cpulist",
|
|
|
|
.type = VSH_OT_STRING,
|
2020-11-10 09:50:52 +00:00
|
|
|
.completer = virshDomainVcpulistViaAgentCompleter,
|
2016-06-20 07:57:53 +00:00
|
|
|
.help = N_("list of cpus to enable or disable")
|
|
|
|
},
|
|
|
|
{.name = "enable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("enable cpus specified by cpulist")
|
|
|
|
},
|
|
|
|
{.name = "disable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("disable cpus specified by cpulist")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdGuestvcpus(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2016-06-20 07:57:53 +00:00
|
|
|
bool enable = vshCommandOptBool(cmd, "enable");
|
|
|
|
bool disable = vshCommandOptBool(cmd, "disable");
|
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
unsigned int nparams = 0;
|
|
|
|
const char *cpulist = NULL;
|
|
|
|
int state = 0;
|
|
|
|
size_t i;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(enable, disable);
|
|
|
|
VSH_REQUIRE_OPTION("enable", "cpulist");
|
|
|
|
VSH_REQUIRE_OPTION("disable", "cpulist");
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "cpulist", &cpulist))
|
|
|
|
return false;
|
|
|
|
|
2018-03-06 13:13:55 +00:00
|
|
|
if (cpulist && !(enable || disable)) {
|
2016-06-20 07:57:53 +00:00
|
|
|
vshError(ctl, _("One of options --enable or --disable is required by "
|
|
|
|
"option --cpulist"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (enable)
|
|
|
|
state = 1;
|
|
|
|
|
|
|
|
if (cpulist) {
|
|
|
|
if (virDomainSetGuestVcpus(dom, cpulist, state, 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
} else {
|
|
|
|
if (virDomainGetGuestVcpus(dom, ¶ms, &nparams, 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
2016-06-20 07:57:53 +00:00
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virTypedParamsFree(params, nparams);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-06-21 08:55:30 +00:00
|
|
|
/*
|
|
|
|
* "setvcpu" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_setvcpu[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("attach/detach vcpu or groups of threads")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Add or remove vcpus")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_setvcpu[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2016-06-21 08:55:30 +00:00
|
|
|
{.name = "vcpulist",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2020-09-11 07:13:13 +00:00
|
|
|
.completer = virshDomainVcpulistCompleter,
|
2016-06-21 08:55:30 +00:00
|
|
|
.help = N_("ids of vcpus to manipulate")
|
|
|
|
},
|
|
|
|
{.name = "enable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("enable cpus specified by cpumap")
|
|
|
|
},
|
|
|
|
{.name = "disable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("disable cpus specified by cpumap")
|
|
|
|
},
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSetvcpu(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2016-06-21 08:55:30 +00:00
|
|
|
bool enable = vshCommandOptBool(cmd, "enable");
|
|
|
|
bool disable = vshCommandOptBool(cmd, "disable");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
const char *vcpulist = NULL;
|
|
|
|
int state = 0;
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(enable, disable);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("current", "live");
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("current", "config");
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
|
|
|
if (!(enable || disable)) {
|
|
|
|
vshError(ctl, "%s", _("one of --enable, --disable is required"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "vcpulist", &vcpulist))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (enable)
|
|
|
|
state = 1;
|
|
|
|
|
|
|
|
if (virDomainSetVcpu(dom, vcpulist, state, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2016-06-21 08:55:30 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2016-06-21 08:55:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-23 12:27:18 +00:00
|
|
|
/*
|
|
|
|
* "domblkthreshold" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domblkthreshold[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("set the threshold for block-threshold event for a given block "
|
|
|
|
"device or it's backing chain element")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("set threshold for block-threshold event for a block device")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domblkthreshold[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2017-02-23 12:27:18 +00:00
|
|
|
{.name = "dev",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-05-15 11:18:24 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
2017-02-23 12:27:18 +00:00
|
|
|
.help = N_("device to set threshold for")
|
|
|
|
},
|
|
|
|
{.name = "threshold",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("threshold as a scaled number (by default bytes)")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomblkthreshold(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
unsigned long long threshold;
|
|
|
|
const char *dev = NULL;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2017-02-23 12:27:18 +00:00
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "dev", &dev))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptScaledInt(ctl, cmd, "threshold",
|
|
|
|
&threshold, 1, ULLONG_MAX) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainSetBlockThreshold(dom, dev, threshold, 0) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-02-23 12:27:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2017-02-23 12:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-11 20:29:22 +00:00
|
|
|
/*
|
2015-03-25 16:15:04 +00:00
|
|
|
* "iothreadinfo" command
|
2015-02-11 20:29:22 +00:00
|
|
|
*/
|
2015-03-25 16:15:04 +00:00
|
|
|
static const vshCmdInfo info_iothreadinfo[] = {
|
2015-02-11 20:29:22 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("view domain IOThreads")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Returns basic information about the domain IOThreads.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
2015-03-25 16:15:04 +00:00
|
|
|
static const vshCmdOptDef opts_iothreadinfo[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2015-02-11 20:29:22 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2015-03-25 16:15:04 +00:00
|
|
|
cmdIOThreadInfo(vshControl *ctl, const vshCmd *cmd)
|
2015-02-11 20:29:22 +00:00
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-02-11 20:29:22 +00:00
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
2019-02-12 10:42:36 +00:00
|
|
|
size_t niothreads = 0;
|
2019-02-12 11:04:24 +00:00
|
|
|
virDomainIOThreadInfoPtr *info = NULL;
|
2015-02-11 20:29:22 +00:00
|
|
|
size_t i;
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2021-08-11 13:12:02 +00:00
|
|
|
g_autoptr(vshTable) table = NULL;
|
2019-02-12 09:35:17 +00:00
|
|
|
bool ret = false;
|
2019-02-12 10:42:36 +00:00
|
|
|
int rc;
|
2015-02-11 20:29:22 +00:00
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2015-02-11 20:29:22 +00:00
|
|
|
return false;
|
|
|
|
|
2019-02-12 10:42:36 +00:00
|
|
|
if ((rc = virDomainGetIOThreadInfo(dom, &info, flags)) < 0) {
|
2015-02-11 20:29:22 +00:00
|
|
|
vshError(ctl, _("Unable to get domain IOThreads information"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2019-02-12 10:42:36 +00:00
|
|
|
niothreads = rc;
|
2015-02-11 20:29:22 +00:00
|
|
|
|
|
|
|
if (niothreads == 0) {
|
2019-02-12 09:35:17 +00:00
|
|
|
ret = true;
|
2015-02-11 20:29:22 +00:00
|
|
|
vshPrintExtra(ctl, _("No IOThreads found for the domain"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2018-09-21 14:17:21 +00:00
|
|
|
table = vshTableNew(_("IOThread ID"), _("CPU Affinity"), NULL);
|
|
|
|
if (!table)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-02-11 20:29:22 +00:00
|
|
|
for (i = 0; i < niothreads; i++) {
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *pinInfo = NULL;
|
|
|
|
g_autofree char *iothreadIdStr = NULL;
|
2015-02-11 20:29:22 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
iothreadIdStr = g_strdup_printf("%u", info[i]->iothread_id);
|
2018-09-21 14:17:21 +00:00
|
|
|
|
|
|
|
ignore_value(pinInfo = virBitmapDataFormat(info[i]->cpumap, info[i]->cpumaplen));
|
|
|
|
|
2022-02-28 14:02:41 +00:00
|
|
|
if (vshTableRowAppend(table, iothreadIdStr, NULLSTR_EMPTY(pinInfo), NULL) < 0)
|
2018-09-21 14:17:21 +00:00
|
|
|
goto cleanup;
|
2015-02-11 20:29:22 +00:00
|
|
|
}
|
2018-09-21 14:17:21 +00:00
|
|
|
|
|
|
|
vshTablePrintToStdout(table, ctl);
|
2015-02-11 20:29:22 +00:00
|
|
|
|
2019-02-12 09:35:17 +00:00
|
|
|
ret = true;
|
|
|
|
|
2015-02-11 20:29:22 +00:00
|
|
|
cleanup:
|
2018-09-21 14:17:21 +00:00
|
|
|
for (i = 0; i < niothreads; i++)
|
|
|
|
virDomainIOThreadInfoFree(info[i]);
|
|
|
|
VIR_FREE(info);
|
2019-02-12 09:35:17 +00:00
|
|
|
return ret;
|
2015-02-11 20:29:22 +00:00
|
|
|
}
|
|
|
|
|
2015-03-06 00:08:04 +00:00
|
|
|
/*
|
|
|
|
* "iothreadpin" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_iothreadpin[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("control domain IOThread affinity")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Pin domain IOThreads to host physical CPUs.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_iothreadpin[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2015-03-06 00:08:04 +00:00
|
|
|
{.name = "iothread",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2020-09-11 07:13:10 +00:00
|
|
|
.completer = virshDomainIOThreadIdCompleter,
|
2015-03-06 00:08:04 +00:00
|
|
|
.help = N_("IOThread ID number")
|
|
|
|
},
|
|
|
|
{.name = "cpulist",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2020-09-11 07:13:14 +00:00
|
|
|
.completer = virshDomainCpulistCompleter,
|
2015-03-06 00:08:04 +00:00
|
|
|
.help = N_("host cpu number(s) to set")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2015-03-06 00:08:04 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdIOThreadPin(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-03-06 00:08:04 +00:00
|
|
|
const char *cpulist = NULL;
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
unsigned int iothread_id = 0;
|
|
|
|
int maxcpu;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree unsigned char *cpumap = NULL;
|
2015-04-01 16:46:56 +00:00
|
|
|
int cpumaplen;
|
2015-03-06 00:08:04 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2015-03-06 00:08:04 +00:00
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2015-03-06 00:08:04 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptUInt(ctl, cmd, "iothread", &iothread_id) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-06 00:08:04 +00:00
|
|
|
|
2015-12-03 12:44:43 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "cpulist", &cpulist) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-06 00:08:04 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((maxcpu = virshNodeGetCPUCount(priv->conn)) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-06 00:08:04 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(cpumap = virshParseCPUList(ctl, &cpumaplen, cpulist, maxcpu)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-06 00:08:04 +00:00
|
|
|
|
|
|
|
if (virDomainPinIOThread(dom, iothread_id,
|
|
|
|
cpumap, cpumaplen, flags) != 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-06 00:08:04 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2015-03-06 00:08:04 +00:00
|
|
|
}
|
|
|
|
|
2015-03-18 13:01:50 +00:00
|
|
|
/*
|
|
|
|
* "iothreadadd" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_iothreadadd[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("add an IOThread to the guest domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Add an IOThread to the guest domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_iothreadadd[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2015-03-18 13:01:50 +00:00
|
|
|
{.name = "id",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("iothread for the new IOThread")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2015-03-18 13:01:50 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdIOThreadAdd(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-03-18 13:01:50 +00:00
|
|
|
int iothread_id = 0;
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2015-03-18 13:01:50 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptInt(ctl, cmd, "id", &iothread_id) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-18 13:01:50 +00:00
|
|
|
if (iothread_id <= 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid IOThread id value: '%1$d'"), iothread_id);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-18 13:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainAddIOThread(dom, iothread_id, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-18 13:01:50 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2015-03-18 13:01:50 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 12:53:09 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "iothreadset" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_iothreadset[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("modifies an existing IOThread of the guest domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Modifies an existing IOThread of the guest domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_iothreadset[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
|
|
|
{.name = "id",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2020-09-11 07:13:10 +00:00
|
|
|
.completer = virshDomainIOThreadIdCompleter,
|
2018-10-05 12:53:09 +00:00
|
|
|
.help = N_("iothread id of existing IOThread")
|
|
|
|
},
|
|
|
|
{.name = "poll-max-ns",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("set the maximum IOThread polling time in ns")
|
|
|
|
},
|
|
|
|
{.name = "poll-grow",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("set the value to increase the IOThread polling time")
|
|
|
|
},
|
|
|
|
{.name = "poll-shrink",
|
|
|
|
.type = VSH_OT_INT,
|
2022-05-11 11:32:36 +00:00
|
|
|
.help = N_("set the value for reduction of the IOThread polling time")
|
|
|
|
},
|
|
|
|
{.name = "thread-pool-min",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("lower boundary for worker thread pool")
|
|
|
|
},
|
|
|
|
{.name = "thread-pool-max",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("upper boundary for worker thread pool")
|
2018-10-05 12:53:09 +00:00
|
|
|
},
|
2022-07-07 15:44:32 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2018-10-05 12:53:09 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdIOThreadSet(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2018-10-05 12:53:09 +00:00
|
|
|
int id = 0;
|
2022-07-07 15:44:32 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
2018-10-05 12:53:09 +00:00
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2023-04-18 20:51:24 +00:00
|
|
|
g_autoptr(virTypedParamList) params = virTypedParamListNew();
|
|
|
|
virTypedParameterPtr par;
|
|
|
|
size_t npar = 0;
|
2023-04-19 10:39:00 +00:00
|
|
|
unsigned long long poll_val;
|
2022-05-11 11:32:36 +00:00
|
|
|
int thread_val;
|
2018-10-05 12:53:09 +00:00
|
|
|
int rc;
|
|
|
|
|
2022-07-07 15:44:32 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
2018-10-05 12:53:09 +00:00
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2022-07-07 15:44:32 +00:00
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
2018-10-05 12:53:09 +00:00
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptInt(ctl, cmd, "id", &id) < 0)
|
2023-04-18 20:51:24 +00:00
|
|
|
return false;
|
2018-10-05 12:53:09 +00:00
|
|
|
if (id <= 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid IOThread id value: '%1$d'"), id);
|
2023-04-18 20:51:24 +00:00
|
|
|
return false;
|
2018-10-05 12:53:09 +00:00
|
|
|
}
|
|
|
|
|
2023-04-19 10:39:00 +00:00
|
|
|
if ((rc = vshCommandOptULongLong(ctl, cmd, "poll-max-ns", &poll_val)) < 0)
|
2023-04-18 20:51:24 +00:00
|
|
|
return false;
|
|
|
|
if (rc > 0)
|
2023-04-19 10:39:00 +00:00
|
|
|
virTypedParamListAddULLong(params, poll_val, VIR_DOMAIN_IOTHREAD_POLL_MAX_NS);
|
2018-10-05 12:53:09 +00:00
|
|
|
|
2023-04-19 10:39:00 +00:00
|
|
|
if ((rc = vshCommandOptULongLong(ctl, cmd, "poll-grow", &poll_val)) < 0)
|
2023-04-18 20:51:24 +00:00
|
|
|
return false;
|
|
|
|
if (rc > 0)
|
2023-04-19 10:39:00 +00:00
|
|
|
virTypedParamListAddUnsigned(params, poll_val, VIR_DOMAIN_IOTHREAD_POLL_GROW);
|
2018-10-05 12:53:09 +00:00
|
|
|
|
2023-04-19 10:39:00 +00:00
|
|
|
if ((rc = vshCommandOptULongLong(ctl, cmd, "poll-shrink", &poll_val)) < 0)
|
2023-04-18 20:51:24 +00:00
|
|
|
return false;
|
|
|
|
if (rc > 0)
|
2023-04-19 10:39:00 +00:00
|
|
|
virTypedParamListAddUnsigned(params, poll_val, VIR_DOMAIN_IOTHREAD_POLL_SHRINK);
|
2018-10-05 12:53:09 +00:00
|
|
|
|
2023-04-18 20:51:24 +00:00
|
|
|
if ((rc = vshCommandOptInt(ctl, cmd, "thread-pool-min", &thread_val)) < 0)
|
|
|
|
return false;
|
|
|
|
if (rc > 0)
|
|
|
|
virTypedParamListAddInt(params, thread_val, VIR_DOMAIN_IOTHREAD_THREAD_POOL_MIN);
|
2018-10-05 12:53:09 +00:00
|
|
|
|
2023-04-18 20:51:24 +00:00
|
|
|
if ((rc = vshCommandOptInt(ctl, cmd, "thread-pool-max", &thread_val)) < 0)
|
|
|
|
return false;
|
|
|
|
if (rc > 0)
|
|
|
|
virTypedParamListAddInt(params, thread_val, VIR_DOMAIN_IOTHREAD_THREAD_POOL_MAX);
|
2022-05-11 11:32:36 +00:00
|
|
|
|
2023-04-18 20:51:24 +00:00
|
|
|
if (virTypedParamListFetch(params, &par, &npar) < 0)
|
|
|
|
return false;
|
2022-05-11 11:32:36 +00:00
|
|
|
|
2023-04-18 20:51:24 +00:00
|
|
|
if (npar == 0) {
|
2022-06-08 13:01:00 +00:00
|
|
|
vshError(ctl, _("Not enough arguments passed, nothing to set"));
|
2023-04-18 20:51:24 +00:00
|
|
|
return false;
|
2022-06-08 13:01:00 +00:00
|
|
|
}
|
|
|
|
|
2023-04-18 20:51:24 +00:00
|
|
|
if (virDomainSetIOThreadParams(dom, id, par, npar, flags) < 0)
|
|
|
|
return false;
|
2018-10-05 12:53:09 +00:00
|
|
|
|
2023-04-18 20:51:24 +00:00
|
|
|
return true;
|
2018-10-05 12:53:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-18 13:01:50 +00:00
|
|
|
/*
|
|
|
|
* "iothreaddel" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_iothreaddel[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("delete an IOThread from the guest domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Delete an IOThread from the guest domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_iothreaddel[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2015-03-18 13:01:50 +00:00
|
|
|
{.name = "id",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2020-09-11 07:13:10 +00:00
|
|
|
.completer = virshDomainIOThreadIdCompleter,
|
2015-03-18 13:01:50 +00:00
|
|
|
.help = N_("iothread_id for the IOThread to delete")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2015-03-18 13:01:50 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdIOThreadDel(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-03-18 13:01:50 +00:00
|
|
|
int iothread_id = 0;
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2015-03-18 13:01:50 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptInt(ctl, cmd, "id", &iothread_id) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-18 13:01:50 +00:00
|
|
|
if (iothread_id <= 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid IOThread id value: '%1$d'"), iothread_id);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-18 13:01:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainDelIOThread(dom, iothread_id, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-03-18 13:01:50 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2015-03-18 13:01:50 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "cpu-stats" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_cpu_stats[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("show domain cpu statistics")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Display per-CPU and total statistics about the domain's CPUs")
|
|
|
|
},
|
2013-04-08 14:15:42 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_cpu_stats[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "total",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("Show total statistics only")
|
|
|
|
},
|
|
|
|
{.name = "start",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("Show statistics from this CPU")
|
|
|
|
},
|
|
|
|
{.name = "count",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("Number of shown CPUs at most")
|
|
|
|
},
|
2013-04-08 14:15:42 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2015-12-07 08:21:08 +00:00
|
|
|
static void
|
|
|
|
vshCPUStatsPrintField(vshControl *ctl,
|
|
|
|
virTypedParameterPtr param)
|
|
|
|
{
|
|
|
|
vshPrint(ctl, "\t%-12s ", param->field);
|
|
|
|
if ((STREQ(param->field, VIR_DOMAIN_CPU_STATS_CPUTIME) ||
|
2016-01-26 02:25:05 +00:00
|
|
|
STREQ(param->field, VIR_DOMAIN_CPU_STATS_VCPUTIME) ||
|
2015-12-07 08:21:08 +00:00
|
|
|
STREQ(param->field, VIR_DOMAIN_CPU_STATS_USERTIME) ||
|
|
|
|
STREQ(param->field, VIR_DOMAIN_CPU_STATS_SYSTEMTIME)) &&
|
|
|
|
param->type == VIR_TYPED_PARAM_ULLONG) {
|
|
|
|
vshPrint(ctl, "%9lld.%09lld seconds\n",
|
|
|
|
param->value.ul / 1000000000,
|
|
|
|
param->value.ul % 1000000000);
|
|
|
|
} else {
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *s = vshGetTypedParamValue(ctl, param);
|
2015-12-07 08:21:08 +00:00
|
|
|
vshPrint(ctl, "%s\n", s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdCPUStats(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
2015-12-07 08:21:08 +00:00
|
|
|
int max_id, cpu = 0, show_count = -1, nparams = 0, stats_per_cpu;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i, j;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool show_total = false, show_per_cpu = false;
|
2013-01-22 11:17:18 +00:00
|
|
|
bool ret = false;
|
2013-04-08 14:49:34 +00:00
|
|
|
int rv = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
show_total = vshCommandOptBool(cmd, "total");
|
2013-04-08 14:49:34 +00:00
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "start", &cpu)) < 0) {
|
2013-04-08 14:49:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (cpu < 0) {
|
|
|
|
vshError(ctl, "%s", _("Invalid value for start CPU"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
show_per_cpu = true;
|
2013-04-08 14:49:34 +00:00
|
|
|
}
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "count", &show_count)) < 0) {
|
2013-04-08 14:49:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (show_count < 0) {
|
|
|
|
vshError(ctl, "%s", _("Invalid value for number of CPUs to show"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
show_per_cpu = true;
|
2013-04-08 14:49:34 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* default show per_cpu and total */
|
|
|
|
if (!show_total && !show_per_cpu) {
|
|
|
|
show_total = true;
|
|
|
|
show_per_cpu = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!show_per_cpu) /* show total stats only */
|
|
|
|
goto do_show_total;
|
|
|
|
|
|
|
|
/* get number of cpus on the node */
|
2015-12-07 11:49:12 +00:00
|
|
|
if ((max_id = virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0)) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto failed_stats;
|
2016-04-15 07:28:53 +00:00
|
|
|
|
|
|
|
if (cpu >= max_id) {
|
|
|
|
vshError(ctl, "Start CPU %d is out of range (min: 0, max: %d)",
|
|
|
|
cpu, max_id - 1);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-04-08 14:49:34 +00:00
|
|
|
if (show_count < 0 || show_count > max_id) {
|
|
|
|
if (show_count > max_id)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrint(ctl, _("Only %1$d CPUs available to show\n"), max_id);
|
2016-04-01 06:05:04 +00:00
|
|
|
show_count = max_id - cpu;
|
2013-04-08 14:49:34 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* get percpu information */
|
2015-12-07 11:49:12 +00:00
|
|
|
if ((nparams = virDomainGetCPUStats(dom, NULL, 0, 0, 1, 0)) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto failed_stats;
|
|
|
|
|
|
|
|
if (!nparams) {
|
|
|
|
vshPrint(ctl, "%s", _("No per-CPU stats available"));
|
2013-08-23 10:17:25 +00:00
|
|
|
if (show_total)
|
|
|
|
goto do_show_total;
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2020-09-23 20:06:18 +00:00
|
|
|
params = g_new0(virTypedParameter, nparams * MIN(show_count, 128));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
while (show_count) {
|
|
|
|
int ncpus = MIN(show_count, 128);
|
|
|
|
|
2015-12-07 11:49:12 +00:00
|
|
|
if (virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, 0) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto failed_stats;
|
|
|
|
|
|
|
|
for (i = 0; i < ncpus; i++) {
|
|
|
|
if (params[i * nparams].type == 0) /* this cpu is not in the map */
|
|
|
|
continue;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
vshPrint(ctl, "CPU%zu:\n", cpu + i);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-12-07 08:21:08 +00:00
|
|
|
for (j = 0; j < nparams; j++)
|
|
|
|
vshCPUStatsPrintField(ctl, params + (i * nparams + j));
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
cpu += ncpus;
|
|
|
|
show_count -= ncpus;
|
2013-01-15 23:42:35 +00:00
|
|
|
virTypedParamsClear(params, nparams * ncpus);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(params);
|
|
|
|
|
2013-08-23 10:17:25 +00:00
|
|
|
if (!show_total) {
|
|
|
|
ret = true;
|
2012-07-25 15:37:18 +00:00
|
|
|
goto cleanup;
|
2013-08-23 10:17:25 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
do_show_total:
|
2012-07-25 15:37:18 +00:00
|
|
|
/* get supported num of parameter for total statistics */
|
2015-12-07 11:49:12 +00:00
|
|
|
if ((nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0)) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto failed_stats;
|
|
|
|
|
|
|
|
if (!nparams) {
|
|
|
|
vshPrint(ctl, "%s", _("No total stats available"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-09-23 20:06:18 +00:00
|
|
|
params = g_new0(virTypedParameter, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* passing start_cpu == -1 gives us domain's total status */
|
2014-09-04 21:08:48 +00:00
|
|
|
if ((stats_per_cpu = virDomainGetCPUStats(dom, params, nparams,
|
2015-12-07 11:49:12 +00:00
|
|
|
-1, 1, 0)) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto failed_stats;
|
|
|
|
|
|
|
|
vshPrint(ctl, _("Total:\n"));
|
2015-12-07 08:21:08 +00:00
|
|
|
for (i = 0; i < stats_per_cpu; i++)
|
|
|
|
vshCPUStatsPrintField(ctl, params + i);
|
2013-01-22 11:17:18 +00:00
|
|
|
|
|
|
|
ret = true;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-01-22 11:17:18 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
|
|
|
return ret;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
failed_stats:
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to retrieve CPU statistics for domain '%1$s'"),
|
2013-01-22 11:17:18 +00:00
|
|
|
virDomainGetName(dom));
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "create" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_create[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("create a domain from an XML file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Create a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_create[] = {
|
2016-01-09 13:36:29 +00:00
|
|
|
VIRSH_COMMON_OPT_FILE(N_("file containing an XML domain description")),
|
2012-07-25 15:37:18 +00:00
|
|
|
#ifndef WIN32
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "console",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("attach to console after creation")
|
|
|
|
},
|
2012-07-25 15:37:18 +00:00
|
|
|
#endif
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "paused",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("leave the guest paused after creation")
|
|
|
|
},
|
|
|
|
{.name = "autodestroy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("automatically destroy the guest when virsh disconnects")
|
|
|
|
},
|
2013-07-11 15:32:14 +00:00
|
|
|
{.name = "pass-fds",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-07-11 15:32:14 +00:00
|
|
|
.help = N_("pass file descriptors N,M,... to the guest")
|
|
|
|
},
|
2015-01-08 15:26:50 +00:00
|
|
|
{.name = "validate",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("validate the XML against the schema")
|
|
|
|
},
|
2022-02-03 16:42:28 +00:00
|
|
|
{.name = "reset-nvram",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("re-initialize NVRAM from its pristine template")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdCreate(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *from = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *buffer = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
bool console = vshCommandOptBool(cmd, "console");
|
|
|
|
#endif
|
2015-01-08 15:26:50 +00:00
|
|
|
unsigned int flags = 0;
|
2013-07-11 15:32:14 +00:00
|
|
|
size_t nfds = 0;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree int *fds = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2022-01-27 16:22:04 +00:00
|
|
|
if (virshFetchPassFdsList(ctl, cmd, &nfds, &fds) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-07-11 15:32:14 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (vshCommandOptBool(cmd, "paused"))
|
|
|
|
flags |= VIR_DOMAIN_START_PAUSED;
|
|
|
|
if (vshCommandOptBool(cmd, "autodestroy"))
|
|
|
|
flags |= VIR_DOMAIN_START_AUTODESTROY;
|
2015-01-08 15:26:50 +00:00
|
|
|
if (vshCommandOptBool(cmd, "validate"))
|
|
|
|
flags |= VIR_DOMAIN_START_VALIDATE;
|
2022-02-03 16:42:28 +00:00
|
|
|
if (vshCommandOptBool(cmd, "reset-nvram"))
|
|
|
|
flags |= VIR_DOMAIN_START_RESET_NVRAM;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-07-11 15:32:14 +00:00
|
|
|
if (nfds)
|
2015-06-15 16:53:58 +00:00
|
|
|
dom = virDomainCreateXMLWithFiles(priv->conn, buffer, nfds, fds, flags);
|
2013-07-11 15:32:14 +00:00
|
|
|
else
|
2015-06-15 16:53:58 +00:00
|
|
|
dom = virDomainCreateXML(priv->conn, buffer, flags);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-02-24 13:26:53 +00:00
|
|
|
if (!dom) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to create domain from %1$s"), from);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2014-02-24 13:26:53 +00:00
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' created from %2$s\n"),
|
2016-08-24 14:14:23 +00:00
|
|
|
virDomainGetName(dom), from);
|
2014-02-24 13:26:53 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
if (console)
|
|
|
|
cmdRunConsole(ctl, dom, NULL, 0);
|
|
|
|
#endif
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "define" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_define[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("define (but don't start) a domain from an XML file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Define a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_define[] = {
|
2016-01-09 13:36:29 +00:00
|
|
|
VIRSH_COMMON_OPT_FILE(N_("file containing an XML domain description")),
|
2015-01-08 15:26:50 +00:00
|
|
|
{.name = "validate",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("validate the XML against the schema")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDefine(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *from = NULL;
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char *buffer = NULL;
|
2015-01-08 15:26:50 +00:00
|
|
|
unsigned int flags = 0;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-01-08 15:26:50 +00:00
|
|
|
if (vshCommandOptBool(cmd, "validate"))
|
|
|
|
flags |= VIR_DOMAIN_DEFINE_VALIDATE;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-01-08 15:26:50 +00:00
|
|
|
if (flags)
|
2015-06-15 16:53:58 +00:00
|
|
|
dom = virDomainDefineXMLFlags(priv->conn, buffer, flags);
|
2015-01-08 15:26:50 +00:00
|
|
|
else
|
2015-06-15 16:53:58 +00:00
|
|
|
dom = virDomainDefineXML(priv->conn, buffer);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-09-24 15:17:47 +00:00
|
|
|
if (!dom) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to define domain from %1$s"), from);
|
2021-09-24 15:17:47 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2021-09-24 15:17:47 +00:00
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' defined from %2$s\n"),
|
2021-09-24 15:17:47 +00:00
|
|
|
virDomainGetName(dom), from);
|
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "destroy" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_destroy[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("destroy (stop) a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Forcefully stop a given domain, but leave its resources intact.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_destroy[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "graceful",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("terminate gracefully")
|
|
|
|
},
|
2022-02-14 12:19:53 +00:00
|
|
|
{.name = "remove-logs",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("remove domain logs")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDestroy(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *name;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
int result;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, &name)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "graceful"))
|
|
|
|
flags |= VIR_DOMAIN_DESTROY_GRACEFUL;
|
2022-02-14 12:19:53 +00:00
|
|
|
if (vshCommandOptBool(cmd, "remove-logs"))
|
|
|
|
flags |= VIR_DOMAIN_DESTROY_REMOVE_LOGS;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (flags)
|
2022-02-14 12:19:53 +00:00
|
|
|
result = virDomainDestroyFlags(dom, flags);
|
2012-07-25 15:37:18 +00:00
|
|
|
else
|
|
|
|
result = virDomainDestroy(dom);
|
|
|
|
|
2021-09-24 15:17:47 +00:00
|
|
|
if (result < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to destroy domain '%1$s'"), name);
|
2021-09-24 15:17:47 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' destroyed\n"), name);
|
2021-09-24 15:17:47 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "desc" command for managing domain description and title
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_desc[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("show or set domain's description or title")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
2019-04-12 11:16:20 +00:00
|
|
|
.data = N_("Allows setting or modifying the description or title of "
|
|
|
|
"a domain.")
|
2013-02-07 15:25:10 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_desc[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_LIVE(N_("modify/get running state")),
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_CONFIG(N_("modify/get persistent configuration")),
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_CURRENT(N_("modify/get current state configuration")),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "title",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("modify/get the title instead of description")
|
|
|
|
},
|
|
|
|
{.name = "edit",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("open an editor to modify the description")
|
|
|
|
},
|
|
|
|
{.name = "new-desc",
|
|
|
|
.type = VSH_OT_ARGV,
|
|
|
|
.help = N_("message")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2013-09-09 08:52:08 +00:00
|
|
|
cmdDesc(vshControl *ctl, const vshCmd *cmd)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
|
|
|
|
bool title = vshCommandOptBool(cmd, "title");
|
|
|
|
bool edit = vshCommandOptBool(cmd, "edit");
|
|
|
|
|
|
|
|
int state;
|
|
|
|
int type;
|
2022-03-02 12:47:09 +00:00
|
|
|
g_autofree char *descArg = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const vshCmdOpt *opt = NULL;
|
2020-07-02 23:40:16 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2022-02-28 17:32:30 +00:00
|
|
|
unsigned int queryflags = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
2022-02-28 17:32:30 +00:00
|
|
|
if (config) {
|
2013-03-07 12:38:19 +00:00
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
2022-02-28 17:32:30 +00:00
|
|
|
queryflags |= VIR_DOMAIN_XML_INACTIVE;
|
|
|
|
}
|
2013-03-07 12:38:19 +00:00
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((state = virshDomainState(ctl, dom, NULL)) < 0)
|
2022-03-01 16:31:00 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (title)
|
|
|
|
type = VIR_DOMAIN_METADATA_TITLE;
|
|
|
|
else
|
|
|
|
type = VIR_DOMAIN_METADATA_DESCRIPTION;
|
|
|
|
|
2018-05-04 09:28:51 +00:00
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
|
|
|
virBufferAsprintf(&buf, "%s ", opt->data);
|
|
|
|
|
2020-02-02 19:26:38 +00:00
|
|
|
virBufferTrim(&buf, " ");
|
2018-05-04 09:28:51 +00:00
|
|
|
|
2022-03-02 12:47:09 +00:00
|
|
|
descArg = virBufferContentAndReset(&buf);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-03-02 12:47:09 +00:00
|
|
|
if (edit || descArg) {
|
|
|
|
g_autofree char *descDom = NULL;
|
|
|
|
g_autofree char *descNew = NULL;
|
|
|
|
|
|
|
|
if (!(descDom = virshGetDomainDescription(ctl, dom, title, queryflags)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!descArg)
|
|
|
|
descArg = g_strdup(descDom);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (edit) {
|
2022-03-01 16:02:59 +00:00
|
|
|
g_autoptr(vshTempFile) tmp = NULL;
|
2022-03-01 16:29:04 +00:00
|
|
|
g_autofree char *desc_edited = NULL;
|
|
|
|
char *tmpstr;
|
2022-03-01 16:02:59 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/* Create and open the temporary file. */
|
2022-03-02 12:47:09 +00:00
|
|
|
if (!(tmp = vshEditWriteToTempFile(ctl, descArg)))
|
2022-03-01 16:31:00 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* Start the editor. */
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (vshEditFile(ctl, tmp) == -1)
|
2022-03-01 16:31:00 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* Read back the edited file. */
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (!(desc_edited = vshEditReadBackFile(ctl, tmp)))
|
2022-03-01 16:31:00 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* strip a possible newline at the end of file; some
|
|
|
|
* editors enforce a newline, this makes editing the title
|
|
|
|
* more convenient */
|
|
|
|
if (title &&
|
|
|
|
(tmpstr = strrchr(desc_edited, '\n')) &&
|
|
|
|
*(tmpstr+1) == '\0')
|
|
|
|
*tmpstr = '\0';
|
|
|
|
|
|
|
|
/* Compare original XML with edited. Has it changed at all? */
|
2022-03-02 12:47:09 +00:00
|
|
|
if (STREQ(descDom, desc_edited)) {
|
2022-02-28 17:40:01 +00:00
|
|
|
if (title)
|
|
|
|
vshPrintExtra(ctl, "%s", _("Domain title not changed\n"));
|
|
|
|
else
|
|
|
|
vshPrintExtra(ctl, "%s", _("Domain description not changed\n"));
|
|
|
|
|
2022-03-01 16:31:00 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-03-02 12:47:09 +00:00
|
|
|
descNew = g_steal_pointer(&desc_edited);
|
|
|
|
} else {
|
|
|
|
descNew = g_steal_pointer(&descArg);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-03-02 12:47:09 +00:00
|
|
|
if (virDomainSetMetadata(dom, type, descNew, NULL, NULL, flags) < 0) {
|
2022-02-28 17:40:01 +00:00
|
|
|
if (title)
|
|
|
|
vshError(ctl, "%s", _("Failed to set new domain title"));
|
|
|
|
else
|
|
|
|
vshError(ctl, "%s", _("Failed to set new domain description"));
|
|
|
|
|
2022-03-01 16:31:00 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2022-02-28 17:40:01 +00:00
|
|
|
|
|
|
|
if (title)
|
|
|
|
vshPrintExtra(ctl, "%s", _("Domain title updated successfully"));
|
|
|
|
else
|
|
|
|
vshPrintExtra(ctl, "%s", _("Domain description updated successfully"));
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
} else {
|
2022-03-02 12:47:09 +00:00
|
|
|
g_autofree char *desc = virshGetDomainDescription(ctl, dom, title, queryflags);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (!desc)
|
2022-03-01 16:31:00 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 17:40:01 +00:00
|
|
|
if (strlen(desc) > 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshPrint(ctl, "%s", desc);
|
2022-02-28 17:40:01 +00:00
|
|
|
} else {
|
|
|
|
if (title)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("No title for domain: %1$s"), virDomainGetName(dom));
|
2022-02-28 17:40:01 +00:00
|
|
|
else
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("No description for domain: %1$s"), virDomainGetName(dom));
|
2022-02-28 17:40:01 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-03-01 16:31:00 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2013-09-09 08:54:04 +00:00
|
|
|
|
|
|
|
static const vshCmdInfo info_metadata[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("show or set domain's custom XML metadata")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Shows or modifies the XML metadata of a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_metadata[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2014-11-11 09:45:24 +00:00
|
|
|
{.name = "uri",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("URI of the namespace")
|
|
|
|
},
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_LIVE(N_("modify/get running state")),
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_CONFIG(N_("modify/get persistent configuration")),
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_CURRENT(N_("modify/get current state configuration")),
|
2013-09-09 08:54:04 +00:00
|
|
|
{.name = "edit",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("use an editor to change the metadata")
|
|
|
|
},
|
|
|
|
{.name = "key",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-09-09 08:54:04 +00:00
|
|
|
.help = N_("key to be used as a namespace identifier"),
|
|
|
|
},
|
|
|
|
{.name = "set",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-09-09 08:54:04 +00:00
|
|
|
.help = N_("new metadata to set"),
|
|
|
|
},
|
|
|
|
{.name = "remove",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("remove the metadata corresponding to an uri")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/* helper to add new metadata using the --edit option */
|
|
|
|
static char *
|
2019-10-18 15:24:29 +00:00
|
|
|
virshDomainGetEditMetadata(vshControl *ctl G_GNUC_UNUSED,
|
2015-06-15 16:53:58 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *uri,
|
|
|
|
unsigned int flags)
|
2013-09-09 08:54:04 +00:00
|
|
|
{
|
|
|
|
char *ret;
|
|
|
|
|
|
|
|
if (!(ret = virDomainGetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT,
|
|
|
|
uri, flags))) {
|
|
|
|
vshResetLibvirtError();
|
2019-10-18 15:24:29 +00:00
|
|
|
ret = g_strdup("\n");
|
2013-09-09 08:54:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdMetadata(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2013-09-09 08:54:04 +00:00
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool edit = vshCommandOptBool(cmd, "edit");
|
2013-09-17 11:40:08 +00:00
|
|
|
bool rem = vshCommandOptBool(cmd, "remove");
|
2013-09-09 08:54:04 +00:00
|
|
|
const char *set = NULL;
|
|
|
|
const char *uri = NULL;
|
|
|
|
const char *key = NULL;
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("edit", "set");
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("remove", "set");
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("remove", "edit");
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2013-09-09 08:54:04 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "uri", &uri) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "key", &key) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "set", &set) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-09-09 08:54:04 +00:00
|
|
|
|
|
|
|
if ((set || edit) && !key) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("namespace key is required when modifying metadata"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-09-09 08:54:04 +00:00
|
|
|
}
|
|
|
|
|
2013-09-17 11:40:08 +00:00
|
|
|
if (set || rem) {
|
2013-09-09 08:54:04 +00:00
|
|
|
if (virDomainSetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT,
|
|
|
|
set, key, uri, flags))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-09-09 08:54:04 +00:00
|
|
|
|
2013-09-17 11:40:08 +00:00
|
|
|
if (rem)
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s\n", _("Metadata removed"));
|
2013-09-09 08:54:04 +00:00
|
|
|
else
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s\n", _("Metadata modified"));
|
2013-09-09 08:54:04 +00:00
|
|
|
} else if (edit) {
|
|
|
|
#define EDIT_GET_XML \
|
2015-06-15 16:53:58 +00:00
|
|
|
virshDomainGetEditMetadata(ctl, dom, uri, flags)
|
2017-11-03 12:09:47 +00:00
|
|
|
#define EDIT_NOT_CHANGED \
|
|
|
|
do { \
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Metadata not changed")); \
|
2017-11-03 12:09:47 +00:00
|
|
|
ret = true; \
|
|
|
|
goto edit_cleanup; \
|
2014-11-14 14:57:17 +00:00
|
|
|
} while (0)
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define EDIT_DEFINE \
|
2013-09-09 08:54:04 +00:00
|
|
|
(virDomainSetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT, doc_edited, \
|
|
|
|
key, uri, flags) == 0)
|
|
|
|
#include "virsh-edit.c"
|
|
|
|
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s\n", _("Metadata modified"));
|
2013-09-09 08:54:04 +00:00
|
|
|
} else {
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *data = NULL;
|
2013-09-09 08:54:04 +00:00
|
|
|
/* get */
|
|
|
|
if (!(data = virDomainGetMetadata(dom, VIR_DOMAIN_METADATA_ELEMENT,
|
|
|
|
uri, flags)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-09-09 08:54:04 +00:00
|
|
|
|
|
|
|
vshPrint(ctl, "%s\n", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-09-09 08:54:04 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "inject-nmi" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_inject_nmi[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Inject NMI to the guest")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Inject NMI to the guest domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_inject_nmi[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdInjectNMI(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainInjectNMI(dom, 0) < 0)
|
2019-09-09 08:41:15 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2019-09-09 08:41:15 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "send-key" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_send_key[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Send keycodes to the guest")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Send keycodes (integers or symbolic names) to the guest")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_send_key[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "codeset",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
2021-02-16 20:15:43 +00:00
|
|
|
.completer = virshCodesetNameCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("the codeset of keycodes, default:linux")
|
|
|
|
},
|
|
|
|
{.name = "holdtime",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
|
|
|
.help = N_("the time (in milliseconds) how long the keys will be held")
|
|
|
|
},
|
|
|
|
{.name = "keycode",
|
|
|
|
.type = VSH_OT_ARGV,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-02-18 18:11:22 +00:00
|
|
|
.completer = virshKeycodeNameCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("the key code")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2015-06-15 16:53:58 +00:00
|
|
|
virshKeyCodeGetInt(const char *key_name)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
|
|
|
unsigned int val;
|
|
|
|
|
2017-03-27 12:17:42 +00:00
|
|
|
if (virStrToLong_uip(key_name, NULL, 0, &val) < 0 || val > 0xffff)
|
2012-07-25 15:37:18 +00:00
|
|
|
return -1;
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSendKey(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *codeset_option;
|
|
|
|
int codeset;
|
2013-04-18 08:42:47 +00:00
|
|
|
unsigned int holdtime = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
int count = 0;
|
|
|
|
const vshCmdOpt *opt = NULL;
|
|
|
|
int keycode;
|
|
|
|
unsigned int keycodes[VIR_DOMAIN_SEND_KEY_MAX_KEYS];
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
if (vshCommandOptStringQuiet(ctl, cmd, "codeset", &codeset_option) <= 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
codeset_option = "linux";
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptUInt(ctl, cmd, "holdtime", &holdtime) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2018-03-12 11:10:47 +00:00
|
|
|
/* The qnum codeset was originally called rfb, so we need to keep
|
|
|
|
* accepting the old name for backwards compatibility reasons */
|
|
|
|
if (STREQ(codeset_option, "rfb"))
|
|
|
|
codeset_option = "qnum";
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
codeset = virKeycodeSetTypeFromString(codeset_option);
|
2013-04-18 08:40:49 +00:00
|
|
|
if (codeset < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("unknown codeset: '%1$s'"), codeset_option);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
|
2012-07-25 15:37:18 +00:00
|
|
|
if (count == VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
|
|
|
|
vshError(ctl, _("too many keycodes"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((keycode = virshKeyCodeGetInt(opt->data)) < 0) {
|
2013-12-19 15:40:16 +00:00
|
|
|
if ((keycode = virKeycodeValueFromString(codeset, opt->data)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("invalid keycode: '%1$s'"), opt->data);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
keycodes[count] = keycode;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
if (virDomainSendKey(dom, codeset, holdtime, keycodes, count, 0) < 0)
|
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2011-11-15 16:01:11 +00:00
|
|
|
/*
|
|
|
|
* "send-process-signal" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_send_process_signal[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Send signals to processes")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Send signals to processes in the guest")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2011-11-15 16:01:11 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_send_process_signal[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "pid",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("the process ID")
|
|
|
|
},
|
|
|
|
{.name = "signame",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2020-11-10 09:51:02 +00:00
|
|
|
.completer = virshDomainSignalCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("the signal number or name")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2011-11-15 16:01:11 +00:00
|
|
|
};
|
|
|
|
|
2021-07-19 11:23:29 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainProcessSignal,
|
2011-11-15 16:01:11 +00:00
|
|
|
VIR_DOMAIN_PROCESS_SIGNAL_LAST,
|
2013-09-09 09:47:20 +00:00
|
|
|
"nop", "hup", "int", "quit", "ill", /* 0-4 */
|
|
|
|
"trap", "abrt", "bus", "fpe", "kill", /* 5-9 */
|
|
|
|
"usr1", "segv", "usr2", "pipe", "alrm", /* 10-14 */
|
|
|
|
"term", "stkflt", "chld", "cont", "stop", /* 15-19 */
|
|
|
|
"tstp", "ttin", "ttou", "urg", "xcpu", /* 20-24 */
|
2011-11-15 16:01:11 +00:00
|
|
|
"xfsz", "vtalrm", "prof", "winch", "poll", /* 25-29 */
|
2013-09-09 09:47:20 +00:00
|
|
|
"pwr", "sys", "rt0", "rt1", "rt2", /* 30-34 */
|
|
|
|
"rt3", "rt4", "rt5", "rt6", "rt7", /* 35-39 */
|
|
|
|
"rt8", "rt9", "rt10", "rt11", "rt12", /* 40-44 */
|
|
|
|
"rt13", "rt14", "rt15", "rt16", "rt17", /* 45-49 */
|
|
|
|
"rt18", "rt19", "rt20", "rt21", "rt22", /* 50-54 */
|
|
|
|
"rt23", "rt24", "rt25", "rt26", "rt27", /* 55-59 */
|
2019-01-20 16:30:15 +00:00
|
|
|
"rt28", "rt29", "rt30", "rt31", "rt32"); /* 60-64 */
|
2011-11-15 16:01:11 +00:00
|
|
|
|
2019-10-18 21:35:27 +00:00
|
|
|
static int getSignalNumber(const char *signame)
|
2011-11-15 16:01:11 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
int signum;
|
2019-10-18 21:35:27 +00:00
|
|
|
g_autofree char *str = g_strdup(signame);
|
2019-10-18 21:30:27 +00:00
|
|
|
char *p = str;
|
2011-11-15 16:01:11 +00:00
|
|
|
|
2013-05-21 07:44:53 +00:00
|
|
|
for (i = 0; signame[i]; i++)
|
2019-11-18 14:15:31 +00:00
|
|
|
p[i] = g_ascii_tolower(signame[i]);
|
2011-11-15 16:01:11 +00:00
|
|
|
|
2019-10-18 21:30:27 +00:00
|
|
|
if (virStrToLong_i(p, NULL, 10, &signum) >= 0)
|
2019-10-18 21:32:12 +00:00
|
|
|
return signum;
|
2011-11-15 16:01:11 +00:00
|
|
|
|
2019-10-18 21:30:27 +00:00
|
|
|
if (STRPREFIX(p, "sig_"))
|
|
|
|
p += 4;
|
|
|
|
else if (STRPREFIX(p, "sig"))
|
|
|
|
p += 3;
|
2011-11-15 16:01:11 +00:00
|
|
|
|
2021-07-19 11:23:29 +00:00
|
|
|
return virshDomainProcessSignalTypeFromString(p);
|
2011-11-15 16:01:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSendProcessSignal(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2011-11-15 16:01:11 +00:00
|
|
|
const char *signame;
|
|
|
|
long long pid_value;
|
|
|
|
int signum;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2011-11-15 16:01:11 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptLongLong(ctl, cmd, "pid", &pid_value) < 0)
|
2019-09-09 08:39:04 +00:00
|
|
|
return false;
|
2011-11-15 16:01:11 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "signame", &signame) < 0)
|
2019-09-09 08:39:04 +00:00
|
|
|
return false;
|
2011-11-15 16:01:11 +00:00
|
|
|
|
2019-10-18 21:35:27 +00:00
|
|
|
if ((signum = getSignalNumber(signame)) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("malformed signal name: %1$s"), signame);
|
2019-09-09 08:39:04 +00:00
|
|
|
return false;
|
2011-11-15 16:01:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainSendProcessSignal(dom, pid_value, signum, 0) < 0)
|
2019-09-09 08:39:04 +00:00
|
|
|
return false;
|
2011-11-15 16:01:11 +00:00
|
|
|
|
2019-09-09 08:39:04 +00:00
|
|
|
return true;
|
2011-11-15 16:01:11 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "setmem" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_setmem[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("change memory allocation")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Change the current memory allocation in the guest domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_setmem[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "kilobytes",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "size"
|
|
|
|
},
|
|
|
|
{.name = "size",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("new memory size, as scaled integer (default KiB)")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSetmem(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned long long bytes = 0;
|
|
|
|
unsigned long long max;
|
|
|
|
unsigned long kibibytes = 0;
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
2021-05-19 09:58:27 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
2021-07-22 19:00:50 +00:00
|
|
|
if (config || live || current) {
|
2021-05-19 09:58:27 +00:00
|
|
|
flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2021-07-22 19:00:50 +00:00
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* The API expects 'unsigned long' KiB, so depending on whether we
|
|
|
|
* are 32-bit or 64-bit determines the maximum we can use. */
|
|
|
|
if (sizeof(kibibytes) < sizeof(max))
|
|
|
|
max = 1024ull * ULONG_MAX;
|
|
|
|
else
|
|
|
|
max = ULONG_MAX;
|
2021-05-19 09:58:21 +00:00
|
|
|
if (vshCommandOptScaledInt(ctl, cmd, "size", &bytes, 1024, max) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
kibibytes = VIR_DIV_UP(bytes, 1024);
|
|
|
|
|
2021-05-19 09:58:27 +00:00
|
|
|
if (virDomainSetMemoryFlags(dom, kibibytes, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "setmaxmem" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_setmaxmem[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("change maximum memory limit")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Change the maximum memory allocation limit in the guest domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_setmaxmem[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "kilobytes",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "size"
|
|
|
|
},
|
|
|
|
{.name = "size",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("new maximum memory size, as scaled integer (default KiB)")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSetmaxmem(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned long long bytes = 0;
|
|
|
|
unsigned long long max;
|
|
|
|
unsigned long kibibytes = 0;
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
2020-11-25 09:40:50 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* The API expects 'unsigned long' KiB, so depending on whether we
|
|
|
|
* are 32-bit or 64-bit determines the maximum we can use. */
|
|
|
|
if (sizeof(kibibytes) < sizeof(max))
|
|
|
|
max = 1024ull * ULONG_MAX;
|
|
|
|
else
|
|
|
|
max = ULONG_MAX;
|
2021-05-19 09:58:21 +00:00
|
|
|
if (vshCommandOptScaledInt(ctl, cmd, "size", &bytes, 1024, max) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
kibibytes = VIR_DIV_UP(bytes, 1024);
|
|
|
|
|
2021-05-19 09:58:27 +00:00
|
|
|
if (virDomainSetMemoryFlags(dom, kibibytes, flags | VIR_DOMAIN_MEM_MAXIMUM) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to change MaxMemorySize"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-01-21 16:51:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "update-memory-device" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_update_memory_device[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("update memory device of a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Update values of a memory device of a domain")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_update_memory_device[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
|
|
|
{.name = "print-xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print updated memory device XML instead of executing the change")
|
|
|
|
},
|
|
|
|
{.name = "alias",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.completer = virshDomainDeviceAliasCompleter,
|
|
|
|
.help = N_("memory device alias")
|
|
|
|
},
|
|
|
|
{.name = "node",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("memory device target node")
|
|
|
|
},
|
|
|
|
{.name = "requested-size",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("new value of <requested/> size, as scaled integer (default KiB)")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
|
|
|
virshGetUpdatedMemoryXML(char **updatedMemoryXML,
|
|
|
|
vshControl *ctl,
|
|
|
|
const vshCmd *cmd,
|
|
|
|
virDomainPtr dom,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
const char *alias = NULL;
|
|
|
|
bool nodeOpt = false;
|
|
|
|
unsigned int node = 0;
|
|
|
|
g_autoptr(xmlDoc) doc = NULL;
|
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
|
|
|
g_autofree char *xpath = NULL;
|
|
|
|
int nmems;
|
|
|
|
g_autofree xmlNodePtr *mems = NULL;
|
|
|
|
unsigned int domainXMLFlags = 0;
|
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG)
|
|
|
|
domainXMLFlags |= VIR_DOMAIN_XML_INACTIVE;
|
|
|
|
|
|
|
|
if (virshDomainGetXMLFromDom(ctl, dom, domainXMLFlags, &doc, &ctxt) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
nodeOpt = vshCommandOptBool(cmd, "node");
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "alias", &alias) < 0 ||
|
|
|
|
vshCommandOptUInt(ctl, cmd, "node", &node) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nodeOpt) {
|
|
|
|
xpath = g_strdup_printf("/domain/devices/memory[./target/node='%u']", node);
|
|
|
|
} else if (alias) {
|
|
|
|
xpath = g_strdup_printf("/domain/devices/memory[./alias/@name='%s']", alias);
|
|
|
|
} else {
|
|
|
|
xpath = g_strdup("/domain/devices/memory");
|
|
|
|
}
|
|
|
|
|
|
|
|
nmems = virXPathNodeSet(xpath, ctxt, &mems);
|
|
|
|
if (nmems < 0) {
|
|
|
|
vshSaveLibvirtError();
|
|
|
|
return -1;
|
|
|
|
} else if (nmems == 0) {
|
|
|
|
vshError(ctl, _("no memory device found"));
|
|
|
|
return -1;
|
|
|
|
} else if (nmems > 1) {
|
|
|
|
vshError(ctl, _("multiple memory devices found, use --alias or --node to select one"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = mems[0];
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "requested-size")) {
|
|
|
|
xmlNodePtr requestedSizeNode;
|
|
|
|
g_autofree char *kibibytesStr = NULL;
|
|
|
|
unsigned long long bytes = 0;
|
|
|
|
unsigned long kibibytes = 0;
|
|
|
|
|
|
|
|
if (vshCommandOptScaledInt(ctl, cmd, "requested-size", &bytes, 1024, ULLONG_MAX) < 0)
|
|
|
|
return -1;
|
|
|
|
kibibytes = VIR_DIV_UP(bytes, 1024);
|
|
|
|
|
|
|
|
requestedSizeNode = virXPathNode("./target/requested", ctxt);
|
|
|
|
|
|
|
|
if (!requestedSizeNode) {
|
|
|
|
vshError(ctl, _("virtio-mem device is missing <requested/>"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
kibibytesStr = g_strdup_printf("%lu", kibibytes);
|
|
|
|
xmlNodeSetContent(requestedSizeNode, BAD_CAST kibibytesStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(*updatedMemoryXML = virXMLNodeToString(doc, mems[0]))) {
|
|
|
|
vshSaveLibvirtError();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdUpdateMemoryDevice(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
g_autofree char *updatedMemoryXML = NULL;
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("node", "alias");
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virshGetUpdatedMemoryXML(&updatedMemoryXML, ctl, cmd, dom, flags) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "print-xml")) {
|
|
|
|
vshPrint(ctl, "%s", updatedMemoryXML);
|
|
|
|
} else {
|
|
|
|
if (virDomainUpdateDeviceFlags(dom, updatedMemoryXML, flags) < 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "memtune" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_memtune[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Get or set memory parameters")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get or set the current memory parameters for a guest"
|
2012-07-25 15:37:18 +00:00
|
|
|
" domain.\n"
|
|
|
|
" To get the memory parameters use following command: \n\n"
|
2013-02-07 15:25:10 +00:00
|
|
|
" virsh # memtune <domain>")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_memtune[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "hard-limit",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("Max memory, as scaled integer (default KiB)")
|
|
|
|
},
|
|
|
|
{.name = "soft-limit",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("Memory during contention, as scaled integer (default KiB)")
|
|
|
|
},
|
|
|
|
{.name = "swap-hard-limit",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("Max memory plus swap, as scaled integer (default KiB)")
|
|
|
|
},
|
|
|
|
{.name = "min-guarantee",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("Min guaranteed memory, as scaled integer (default KiB)")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2015-03-02 15:26:52 +00:00
|
|
|
/**
|
2015-06-15 16:53:58 +00:00
|
|
|
* virshMemtuneGetSize
|
2015-03-02 15:26:52 +00:00
|
|
|
*
|
|
|
|
* @cmd: pointer to vshCmd
|
|
|
|
* @name: name of a parameter for which we would like to get a value
|
|
|
|
* @value: pointer to variable where the value will be stored
|
|
|
|
*
|
|
|
|
* This function will parse virsh command line in order to load a value of
|
|
|
|
* specified parameter. If the value is -1 we will handle it as unlimited and
|
|
|
|
* use VIR_DOMAIN_MEMORY_PARAM_UNLIMITED instead.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* >0 if option found and valid
|
|
|
|
* 0 if option not found and not required
|
|
|
|
* <0 in all other cases
|
|
|
|
*/
|
2012-07-25 15:37:18 +00:00
|
|
|
static int
|
2015-06-15 16:53:58 +00:00
|
|
|
virshMemtuneGetSize(vshControl *ctl, const vshCmd *cmd,
|
|
|
|
const char *name, long long *value)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
unsigned long long tmp;
|
|
|
|
const char *str;
|
|
|
|
char *end;
|
|
|
|
|
2015-12-03 12:47:56 +00:00
|
|
|
ret = vshCommandOptStringQuiet(ctl, cmd, name, &str);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
if (virStrToLong_ll(str, &end, 10, value) < 0)
|
|
|
|
return -1;
|
|
|
|
if (*value < 0) {
|
|
|
|
*value = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
tmp = *value;
|
|
|
|
if (virScaleInteger(&tmp, end, 1024, LLONG_MAX) < 0)
|
|
|
|
return -1;
|
|
|
|
*value = VIR_DIV_UP(tmp, 1024);
|
2015-03-02 15:26:52 +00:00
|
|
|
return 1;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdMemtune(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-03-02 15:26:52 +00:00
|
|
|
long long tmpVal;
|
2012-07-25 15:37:18 +00:00
|
|
|
int nparams = 0;
|
2013-01-15 23:09:05 +00:00
|
|
|
int maxparams = 0;
|
2015-03-02 15:26:52 +00:00
|
|
|
int rc;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-01-15 23:09:05 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool ret = false;
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define PARSE_MEMTUNE_PARAM(NAME, FIELD) \
|
|
|
|
if ((rc = virshMemtuneGetSize(ctl, cmd, NAME, &tmpVal)) < 0) { \
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unable to parse integer parameter %1$s"), NAME); \
|
2017-11-03 12:09:47 +00:00
|
|
|
goto cleanup; \
|
|
|
|
} \
|
|
|
|
if (rc == 1) { \
|
|
|
|
if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams, \
|
|
|
|
FIELD, tmpVal) < 0) \
|
|
|
|
goto save_error; \
|
2017-10-31 10:47:36 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
|
2015-03-02 15:26:52 +00:00
|
|
|
PARSE_MEMTUNE_PARAM("hard-limit", VIR_DOMAIN_MEMORY_HARD_LIMIT);
|
|
|
|
PARSE_MEMTUNE_PARAM("soft-limit", VIR_DOMAIN_MEMORY_SOFT_LIMIT);
|
|
|
|
PARSE_MEMTUNE_PARAM("swap-hard-limit", VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT);
|
|
|
|
PARSE_MEMTUNE_PARAM("min-guarantee", VIR_DOMAIN_MEMORY_MIN_GUARANTEE);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-03-02 15:26:52 +00:00
|
|
|
#undef PARSE_MEMTUNE_PARAM
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (nparams == 0) {
|
|
|
|
/* get the number of memory parameters */
|
|
|
|
if (virDomainGetMemoryParameters(dom, NULL, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Unable to get number of memory parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nparams == 0) {
|
|
|
|
/* nothing to output */
|
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now go get all the memory parameters */
|
2020-10-05 16:50:09 +00:00
|
|
|
params = g_new0(virTypedParameter, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (virDomainGetMemoryParameters(dom, params, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to get memory parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
if (params[i].type == VIR_TYPED_PARAM_ULLONG &&
|
|
|
|
params[i].value.ul == VIR_DOMAIN_MEMORY_PARAM_UNLIMITED) {
|
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, _("unlimited"));
|
|
|
|
} else {
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
2012-07-25 15:37:18 +00:00
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virDomainSetMemoryParameters(dom, params, nparams, flags) != 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-01-15 23:09:05 +00:00
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-01-15 23:09:05 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
save_error:
|
2013-01-15 23:09:05 +00:00
|
|
|
vshSaveLibvirtError();
|
2014-03-25 06:53:59 +00:00
|
|
|
error:
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to change memory parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-03-28 13:30:32 +00:00
|
|
|
/*
|
|
|
|
* "perf" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_perf[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Get or set perf event")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get or set the current perf events for a guest"
|
|
|
|
" domain.\n"
|
|
|
|
" To get the perf events list use following command: \n\n"
|
|
|
|
" virsh # perf <domain>")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_perf[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2016-03-28 13:30:32 +00:00
|
|
|
{.name = "enable",
|
|
|
|
.type = VSH_OT_STRING,
|
2020-09-11 07:13:06 +00:00
|
|
|
.completer = virshDomainPerfEnableCompleter,
|
2016-03-28 13:30:32 +00:00
|
|
|
.help = N_("perf events which will be enabled")
|
|
|
|
},
|
|
|
|
{.name = "disable",
|
|
|
|
.type = VSH_OT_STRING,
|
2020-09-11 07:13:06 +00:00
|
|
|
.completer = virshDomainPerfDisableCompleter,
|
2016-03-28 13:30:32 +00:00
|
|
|
.help = N_("perf events which will be disabled")
|
|
|
|
},
|
2016-03-30 16:33:29 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2016-03-28 13:30:32 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
2016-03-30 15:56:02 +00:00
|
|
|
virshParseEventStr(const char *event,
|
2016-03-28 13:30:32 +00:00
|
|
|
bool state,
|
|
|
|
virTypedParameterPtr *params,
|
|
|
|
int *nparams,
|
|
|
|
int *maxparams)
|
|
|
|
{
|
2021-03-22 17:06:45 +00:00
|
|
|
g_auto(GStrv) tok = NULL;
|
|
|
|
GStrv next;
|
2016-03-28 13:30:32 +00:00
|
|
|
|
2021-03-22 17:06:45 +00:00
|
|
|
if (!(tok = g_strsplit(event, ",", 0)))
|
2016-03-28 13:30:32 +00:00
|
|
|
return -1;
|
|
|
|
|
2021-03-22 17:06:45 +00:00
|
|
|
for (next = tok; *next; next++) {
|
|
|
|
if (*next[0] == '\0')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (virTypedParamsAddBoolean(params, nparams, maxparams, *next, state) < 0)
|
|
|
|
return -1;
|
2016-03-28 13:30:32 +00:00
|
|
|
}
|
|
|
|
|
2021-03-22 17:06:45 +00:00
|
|
|
return 0;
|
2016-03-28 13:30:32 +00:00
|
|
|
}
|
|
|
|
|
2016-12-28 11:36:22 +00:00
|
|
|
static void
|
|
|
|
virshPrintPerfStatus(vshControl *ctl, virTypedParameterPtr params, int nparams)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
if (params[i].type == VIR_TYPED_PARAM_BOOLEAN &&
|
|
|
|
params[i].value.b) {
|
|
|
|
vshPrintExtra(ctl, "%-15s: %s\n", params[i].field, _("enabled"));
|
|
|
|
} else {
|
|
|
|
vshPrintExtra(ctl, "%-15s: %s\n", params[i].field, _("disabled"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-28 13:30:32 +00:00
|
|
|
static bool
|
|
|
|
cmdPerf(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2016-03-28 13:30:32 +00:00
|
|
|
int nparams = 0;
|
|
|
|
int maxparams = 0;
|
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
const char *enable = NULL, *disable = NULL;
|
2016-03-30 15:40:50 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2016-03-30 16:33:29 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2016-03-28 13:30:32 +00:00
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "enable", &enable) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "disable", &disable) < 0)
|
|
|
|
return false;
|
|
|
|
|
2016-04-21 07:51:08 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
2016-03-30 15:56:02 +00:00
|
|
|
if (enable && virshParseEventStr(enable, true, ¶ms,
|
|
|
|
&nparams, &maxparams) < 0)
|
2016-03-28 13:30:32 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2016-03-30 15:56:02 +00:00
|
|
|
if (disable && virshParseEventStr(disable, false, ¶ms,
|
|
|
|
&nparams, &maxparams) < 0)
|
2016-03-28 13:30:32 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (nparams == 0) {
|
2016-03-30 15:40:50 +00:00
|
|
|
if (virDomainGetPerfEvents(dom, ¶ms, &nparams, flags) != 0) {
|
2016-03-28 13:30:32 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to get perf events"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2016-12-28 11:36:22 +00:00
|
|
|
virshPrintPerfStatus(ctl, params, nparams);
|
2016-03-28 13:30:32 +00:00
|
|
|
} else {
|
2016-04-21 07:54:45 +00:00
|
|
|
if (virDomainSetPerfEvents(dom, params, nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to enable/disable perf events"));
|
|
|
|
goto cleanup;
|
2016-12-28 11:36:22 +00:00
|
|
|
} else {
|
|
|
|
virshPrintPerfStatus(ctl, params, nparams);
|
2016-04-21 07:54:45 +00:00
|
|
|
}
|
2016-03-28 13:30:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
cleanup:
|
|
|
|
virTypedParamsFree(params, nparams);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "numatune" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_numatune[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Get or set numa parameters")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get or set the current numa parameters for a guest"
|
2012-07-25 15:37:18 +00:00
|
|
|
" domain.\n"
|
|
|
|
" To get the numa parameters use following command: \n\n"
|
2013-02-07 15:25:10 +00:00
|
|
|
" virsh # numatune <domain>")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_numatune[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "mode",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-12-16 14:46:31 +00:00
|
|
|
.completer = virshDomainNumatuneModeCompleter,
|
2014-07-09 07:53:14 +00:00
|
|
|
.help = N_("NUMA mode, one of strict, preferred and interleave \n"
|
|
|
|
"or a number from the virDomainNumatuneMemMode enum")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "nodeset",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("NUMA node selections to set")
|
|
|
|
},
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNumatune(vshControl * ctl, const vshCmd * cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
int nparams = 0;
|
2013-01-15 23:09:55 +00:00
|
|
|
int maxparams = 0;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-01-15 23:09:55 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *nodeset = NULL;
|
|
|
|
bool ret = false;
|
2013-03-07 12:38:19 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
const char *mode = NULL;
|
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "nodeset", &nodeset) < 0)
|
2013-01-15 23:09:55 +00:00
|
|
|
goto cleanup;
|
2013-01-21 14:39:18 +00:00
|
|
|
|
2013-01-15 23:09:55 +00:00
|
|
|
if (nodeset &&
|
|
|
|
virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_NUMA_NODESET, nodeset) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "mode", &mode) < 0)
|
2013-01-15 23:09:55 +00:00
|
|
|
goto cleanup;
|
2013-01-21 14:39:18 +00:00
|
|
|
|
2013-01-15 23:09:55 +00:00
|
|
|
if (mode) {
|
|
|
|
int m;
|
|
|
|
/* Accept string or integer, in case server understands newer
|
|
|
|
* integer than what strings we were compiled with
|
|
|
|
*/
|
|
|
|
if ((m = virDomainNumatuneMemModeTypeFromString(mode)) < 0 &&
|
|
|
|
virStrToLong_i(mode, NULL, 0, &m) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Invalid mode: %1$s"), mode);
|
2013-01-15 23:09:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_NUMA_MODE, m) < 0)
|
|
|
|
goto save_error;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (nparams == 0) {
|
|
|
|
/* get the number of numa parameters */
|
|
|
|
if (virDomainGetNumaParameters(dom, NULL, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("Unable to get number of memory parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nparams == 0) {
|
|
|
|
/* nothing to output */
|
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now go get all the numa parameters */
|
2020-10-05 16:50:09 +00:00
|
|
|
params = g_new0(virTypedParameter, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (virDomainGetNumaParameters(dom, params, &nparams, flags) != 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to get numa parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
if (params[i].type == VIR_TYPED_PARAM_INT &&
|
|
|
|
STREQ(params[i].field, VIR_DOMAIN_NUMA_MODE)) {
|
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field,
|
|
|
|
virDomainNumatuneMemModeTypeToString(params[i].value.i));
|
|
|
|
} else {
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
2012-07-25 15:37:18 +00:00
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virDomainSetNumaParameters(dom, params, nparams, flags) != 0)
|
2013-01-15 23:09:55 +00:00
|
|
|
goto error;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2013-01-15 23:09:55 +00:00
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2013-01-15 23:09:55 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
2013-01-15 23:09:55 +00:00
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
save_error:
|
2013-01-15 23:09:55 +00:00
|
|
|
vshSaveLibvirtError();
|
2014-03-25 06:53:59 +00:00
|
|
|
error:
|
2013-01-15 23:09:55 +00:00
|
|
|
vshError(ctl, "%s", _("Unable to change numa parameters"));
|
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-12-08 12:53:00 +00:00
|
|
|
/*
|
|
|
|
* "domlaunchsecinfo" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domlaunchsecinfo[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Get domain launch security info")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get the launch security parameters for a guest domain")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domlaunchsecinfo[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomLaunchSecInfo(vshControl * ctl, const vshCmd * cmd)
|
|
|
|
{
|
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
|
|
|
size_t i;
|
|
|
|
int nparams = 0;
|
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainGetLaunchSecurityInfo(dom, ¶ms, &nparams, 0) != 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to get launch security parameters"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
|
|
|
vshPrint(ctl, "%-15s: %s\n", params[i].field, str);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virTypedParamsFree(params, nparams);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2021-12-15 03:15:40 +00:00
|
|
|
/*
|
|
|
|
* "domsetlaunchsecstate" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domsetlaunchsecstate[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Set domain launch security state")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Set a secret in the guest domain's memory")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domsetlaunchsecstate[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
|
|
|
{.name = "secrethdr",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
|
|
|
.help = N_("path to file containing the secret header"),
|
|
|
|
},
|
|
|
|
{.name = "secret",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
|
|
|
.help = N_("path to file containing the secret"),
|
|
|
|
},
|
|
|
|
{.name = "set-address",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("physical address within the guest domain's memory to set the secret"),
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomSetLaunchSecState(vshControl * ctl, const vshCmd * cmd)
|
|
|
|
{
|
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
|
|
|
const char *sechdrfile = NULL;
|
|
|
|
const char *secfile = NULL;
|
|
|
|
g_autofree char *sechdr = NULL;
|
|
|
|
g_autofree char *sec = NULL;
|
|
|
|
unsigned long long setaddr;
|
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
int nparams = 0;
|
|
|
|
int maxparams = 0;
|
|
|
|
int rv;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "secrethdr", &sechdrfile) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "secret", &secfile) < 0)
|
|
|
|
return false;
|
|
|
|
|
2022-01-26 12:25:44 +00:00
|
|
|
if (sechdrfile == NULL || secfile == NULL) {
|
|
|
|
vshError(ctl, "%s", _("Both secret and the secret header are required"));
|
2021-12-15 03:15:40 +00:00
|
|
|
return false;
|
2022-01-26 12:25:44 +00:00
|
|
|
}
|
2021-12-15 03:15:40 +00:00
|
|
|
|
|
|
|
if (virFileReadAll(sechdrfile, 1024*64, &sechdr) < 0) {
|
|
|
|
vshSaveLibvirtError();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virFileReadAll(secfile, 1024*64, &sec) < 0) {
|
|
|
|
vshSaveLibvirtError();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET_HEADER,
|
|
|
|
sechdr) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET,
|
|
|
|
sec) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
if ((rv = vshCommandOptULongLong(ctl, cmd, "set-address", &setaddr)) < 0) {
|
|
|
|
return false;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_DOMAIN_LAUNCH_SECURITY_SEV_SECRET_SET_ADDRESS,
|
|
|
|
setaddr) < 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainSetLaunchSecurityState(dom, params, nparams, 0) != 0) {
|
|
|
|
vshError(ctl, "%s", _("Unable to set launch security state"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virTypedParamsFree(params, nparams);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-03-23 09:12:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "dom-fd-associate" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_dom_fd_associate[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("associate a FD with a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("associate a FD with a domain")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_dom_fd_associate[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
|
|
|
{.name = "name",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.completer = virshCompleteEmpty,
|
|
|
|
.help = N_("name of the FD group")
|
|
|
|
},
|
|
|
|
{.name = "pass-fds",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.completer = virshCompleteEmpty,
|
|
|
|
.help = N_("file descriptors N,M,... to associate")
|
|
|
|
},
|
|
|
|
{.name = "seclabel-writable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("use seclabels allowing writes")
|
|
|
|
},
|
|
|
|
{.name = "seclabel-restore",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("try to restore security label after use if possible")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomFdAssociate(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
|
|
|
const char *name = NULL;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
g_autofree int *fds = NULL;
|
|
|
|
size_t nfds = 0;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "seclabel-writable"))
|
|
|
|
flags |= VIR_DOMAIN_FD_ASSOCIATE_SECLABEL_WRITABLE;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "seclabel-restore"))
|
|
|
|
flags |= VIR_DOMAIN_FD_ASSOCIATE_SECLABEL_RESTORE;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virshFetchPassFdsList(ctl, cmd, &nfds, &fds) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainFDAssociate(dom, name, nfds, fds, flags) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-21 14:26:27 +00:00
|
|
|
/*
|
|
|
|
* "qemu-monitor-command" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_qemu_monitor_command[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("QEMU Monitor Command")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("QEMU Monitor Command")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-12-21 14:26:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_qemu_monitor_command[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "hmp",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("command is in human monitor protocol")
|
|
|
|
},
|
|
|
|
{.name = "pretty",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("pretty-print any qemu monitor protocol output")
|
|
|
|
},
|
2019-12-11 13:16:22 +00:00
|
|
|
{.name = "return-value",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("extract the value of the 'return' key from the returned string")
|
|
|
|
},
|
2022-01-28 08:24:03 +00:00
|
|
|
{.name = "pass-fds",
|
|
|
|
.type = VSH_OT_STRING,
|
2022-03-01 13:12:00 +00:00
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
2022-01-28 08:24:03 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
|
|
|
.help = N_("pass file descriptors N,M,... along with the command")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "cmd",
|
|
|
|
.type = VSH_OT_ARGV,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("command")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-12-21 14:26:27 +00:00
|
|
|
};
|
|
|
|
|
2019-12-12 11:13:21 +00:00
|
|
|
|
|
|
|
static char *
|
|
|
|
cmdQemuMonitorCommandConcatCmd(vshControl *ctl,
|
|
|
|
const vshCmd *cmd,
|
|
|
|
const vshCmdOpt *opt)
|
|
|
|
{
|
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
|
|
|
virBufferAsprintf(&buf, "%s ", opt->data);
|
|
|
|
|
|
|
|
virBufferTrim(&buf, " ");
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
cmdQemuMonitorCommandQMPWrap(vshControl *ctl,
|
|
|
|
const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
g_autofree char *fullcmd = cmdQemuMonitorCommandConcatCmd(ctl, cmd, NULL);
|
2022-03-01 13:24:33 +00:00
|
|
|
g_autoptr(virJSONValue) fullcmdjson = NULL;
|
2019-12-12 11:13:21 +00:00
|
|
|
g_autofree char *fullargs = NULL;
|
|
|
|
g_autoptr(virJSONValue) fullargsjson = NULL;
|
|
|
|
const vshCmdOpt *opt = NULL;
|
|
|
|
const char *commandname = NULL;
|
|
|
|
g_autoptr(virJSONValue) command = NULL;
|
|
|
|
g_autoptr(virJSONValue) arguments = NULL;
|
|
|
|
|
2022-03-01 13:24:33 +00:00
|
|
|
if (!(fullcmdjson = virJSONValueFromString(fullcmd))) {
|
|
|
|
/* Reset the error before adding wrapping. */
|
|
|
|
vshResetLibvirtError();
|
|
|
|
}
|
|
|
|
|
2019-12-12 11:13:21 +00:00
|
|
|
/* if we've got a JSON object, pass it through */
|
|
|
|
if (virJSONValueIsObject(fullcmdjson))
|
|
|
|
return g_steal_pointer(&fullcmd);
|
|
|
|
|
|
|
|
/* we try to wrap the command and possible arguments into a JSON object, if
|
|
|
|
* we as fall back we pass through what we've got from the user */
|
|
|
|
|
|
|
|
if ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
|
|
|
commandname = opt->data;
|
|
|
|
|
|
|
|
/* now we process arguments similarly to how we've dealt with the full command */
|
2022-03-01 13:24:33 +00:00
|
|
|
if ((fullargs = cmdQemuMonitorCommandConcatCmd(ctl, cmd, opt)) &&
|
|
|
|
!(fullargsjson = virJSONValueFromString(fullargs))) {
|
|
|
|
/* Reset the error before adding wrapping. */
|
|
|
|
vshResetLibvirtError();
|
|
|
|
}
|
2019-12-12 11:13:21 +00:00
|
|
|
|
|
|
|
/* for empty args or a valid JSON object we just use that */
|
|
|
|
if (!fullargs || virJSONValueIsObject(fullargsjson)) {
|
|
|
|
arguments = g_steal_pointer(&fullargsjson);
|
|
|
|
} else {
|
|
|
|
/* for a non-object we try to concatenate individual _ARGV bits into a
|
|
|
|
* JSON object wrapper and try using that */
|
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "{");
|
|
|
|
/* opt points to the _ARGV option bit containing the command so we'll
|
|
|
|
* iterate through the arguments now */
|
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
|
|
|
virBufferAsprintf(&buf, "%s,", opt->data);
|
|
|
|
|
|
|
|
virBufferTrim(&buf, ",");
|
|
|
|
virBufferAddLit(&buf, "}");
|
|
|
|
|
|
|
|
if (!(arguments = virJSONValueFromString(virBufferCurrentContent(&buf)))) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("failed to wrap arguments '%1$s' into a QMP command wrapper"),
|
2019-12-12 11:13:21 +00:00
|
|
|
fullargs);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-08 16:24:50 +00:00
|
|
|
if (virJSONValueObjectAdd(&command,
|
|
|
|
"s:execute", commandname,
|
|
|
|
"A:arguments", &arguments,
|
|
|
|
NULL) < 0)
|
2019-12-12 11:13:21 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return virJSONValueToString(command, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-21 14:26:27 +00:00
|
|
|
static bool
|
|
|
|
cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2019-10-15 12:47:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *monitor_cmd = NULL;
|
|
|
|
g_autofree char *result = NULL;
|
2019-12-11 13:16:22 +00:00
|
|
|
g_autoptr(virJSONValue) resultjson = NULL;
|
2012-12-21 14:26:27 +00:00
|
|
|
unsigned int flags = 0;
|
2019-12-11 13:16:22 +00:00
|
|
|
bool pretty = vshCommandOptBool(cmd, "pretty");
|
|
|
|
bool returnval = vshCommandOptBool(cmd, "return-value");
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *formatjson;
|
2019-12-11 13:16:22 +00:00
|
|
|
g_autofree char *jsonstr = NULL;
|
2022-01-28 08:24:03 +00:00
|
|
|
g_autofree int *fds = NULL;
|
|
|
|
size_t nfds = 0;
|
2012-12-21 14:26:27 +00:00
|
|
|
|
2016-08-01 04:12:17 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("hmp", "pretty");
|
2019-12-11 13:16:22 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("hmp", "return-value");
|
2016-08-01 04:12:17 +00:00
|
|
|
|
2016-08-01 04:24:35 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
2019-12-12 11:13:21 +00:00
|
|
|
if (vshCommandOptBool(cmd, "hmp")) {
|
2012-12-21 14:26:27 +00:00
|
|
|
flags |= VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP;
|
2019-12-12 11:13:21 +00:00
|
|
|
monitor_cmd = cmdQemuMonitorCommandConcatCmd(ctl, cmd, NULL);
|
|
|
|
} else {
|
|
|
|
monitor_cmd = cmdQemuMonitorCommandQMPWrap(ctl, cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!monitor_cmd) {
|
|
|
|
vshSaveLibvirtError();
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-12-21 14:26:27 +00:00
|
|
|
|
2022-01-28 08:24:03 +00:00
|
|
|
if (virshFetchPassFdsList(ctl, cmd, &nfds, &fds) < 0)
|
2019-09-09 08:51:25 +00:00
|
|
|
return false;
|
2012-12-21 14:26:27 +00:00
|
|
|
|
2022-01-28 08:24:03 +00:00
|
|
|
if (fds) {
|
|
|
|
if (virDomainQemuMonitorCommandWithFiles(dom, monitor_cmd, nfds, fds,
|
|
|
|
NULL, NULL,
|
|
|
|
&result, flags) < 0)
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-12-11 13:16:22 +00:00
|
|
|
if (returnval || pretty) {
|
|
|
|
resultjson = virJSONValueFromString(result);
|
|
|
|
|
|
|
|
if (returnval && !resultjson) {
|
|
|
|
vshError(ctl, "failed to parse JSON returned by qemu");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* print raw non-prettified result */
|
|
|
|
if (!resultjson) {
|
|
|
|
vshPrint(ctl, "%s\n", result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (returnval) {
|
|
|
|
if (!(formatjson = virJSONValueObjectGet(resultjson, "return"))) {
|
|
|
|
vshError(ctl, "'return' member missing");
|
|
|
|
return false;
|
2012-12-21 14:26:27 +00:00
|
|
|
}
|
2019-12-11 13:16:22 +00:00
|
|
|
} else {
|
|
|
|
formatjson = resultjson;
|
2012-12-21 14:26:27 +00:00
|
|
|
}
|
2019-12-11 13:16:22 +00:00
|
|
|
|
|
|
|
jsonstr = virJSONValueToString(formatjson, pretty);
|
|
|
|
virTrimSpaces(jsonstr, NULL);
|
|
|
|
vshPrint(ctl, "%s", jsonstr);
|
2019-09-09 08:51:25 +00:00
|
|
|
return true;
|
2012-12-21 14:26:27 +00:00
|
|
|
}
|
|
|
|
|
2014-01-31 23:52:17 +00:00
|
|
|
/*
|
|
|
|
* "qemu-monitor-event" command
|
|
|
|
*/
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
struct virshQemuEventData {
|
2014-01-31 23:52:17 +00:00
|
|
|
vshControl *ctl;
|
|
|
|
bool loop;
|
|
|
|
bool pretty;
|
2015-12-21 15:22:58 +00:00
|
|
|
bool timestamp;
|
2014-01-31 23:52:17 +00:00
|
|
|
int count;
|
|
|
|
};
|
2015-06-15 16:53:58 +00:00
|
|
|
typedef struct virshQemuEventData virshQemuEventData;
|
2014-01-31 23:52:17 +00:00
|
|
|
|
|
|
|
static void
|
2019-10-14 12:44:29 +00:00
|
|
|
virshEventQemuPrint(virConnectPtr conn G_GNUC_UNUSED,
|
2015-12-16 16:31:39 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
const char *event,
|
|
|
|
long long seconds,
|
|
|
|
unsigned int micros,
|
|
|
|
const char *details,
|
|
|
|
void *opaque)
|
2014-01-31 23:52:17 +00:00
|
|
|
{
|
2015-06-15 16:53:58 +00:00
|
|
|
virshQemuEventData *data = opaque;
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *pretty = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = NULL;
|
2014-01-31 23:52:17 +00:00
|
|
|
|
|
|
|
if (!data->loop && data->count)
|
|
|
|
return;
|
|
|
|
if (data->pretty && details) {
|
|
|
|
pretty = virJSONValueFromString(details);
|
|
|
|
if (pretty && (str = virJSONValueToString(pretty, true)))
|
|
|
|
details = str;
|
|
|
|
}
|
2015-12-21 15:22:58 +00:00
|
|
|
|
|
|
|
if (data->timestamp) {
|
|
|
|
char timestamp[VIR_TIME_STRING_BUFLEN];
|
|
|
|
|
|
|
|
if (virTimeStringNowRaw(timestamp) < 0)
|
|
|
|
timestamp[0] = '\0';
|
|
|
|
|
2021-01-05 12:02:34 +00:00
|
|
|
vshPrint(data->ctl, "%s: event %s for domain '%s': %s\n",
|
2015-12-21 15:22:58 +00:00
|
|
|
timestamp, event, virDomainGetName(dom), NULLSTR(details));
|
|
|
|
} else {
|
2021-01-05 12:02:34 +00:00
|
|
|
vshPrint(data->ctl, "event %s at %lld.%06u for domain '%s': %s\n",
|
2015-12-21 15:22:58 +00:00
|
|
|
event, seconds, micros, virDomainGetName(dom), NULLSTR(details));
|
|
|
|
}
|
|
|
|
|
2014-01-31 23:52:17 +00:00
|
|
|
data->count++;
|
|
|
|
if (!data->loop)
|
|
|
|
vshEventDone(data->ctl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const vshCmdInfo info_qemu_monitor_event[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("QEMU Monitor Events")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Listen for QEMU Monitor Events")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_qemu_monitor_event[] = {
|
2018-05-08 14:20:33 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_OT_STRING(N_("filter by domain name, id or uuid"),
|
2018-09-26 07:59:08 +00:00
|
|
|
0, 0),
|
2014-01-31 23:52:17 +00:00
|
|
|
{.name = "event",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2014-01-31 23:52:17 +00:00
|
|
|
.help = N_("filter by event name")
|
|
|
|
},
|
|
|
|
{.name = "pretty",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("pretty-print any JSON output")
|
|
|
|
},
|
|
|
|
{.name = "loop",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("loop until timeout or interrupt, rather than one-shot")
|
|
|
|
},
|
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("timeout seconds")
|
|
|
|
},
|
2014-02-06 21:46:52 +00:00
|
|
|
{.name = "regex",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("treat event as a regex rather than literal filter")
|
|
|
|
},
|
|
|
|
{.name = "no-case",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("treat event case-insensitively")
|
|
|
|
},
|
2015-12-21 15:22:58 +00:00
|
|
|
{.name = "timestamp",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("show timestamp for each printed event")
|
|
|
|
},
|
2014-01-31 23:52:17 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdQemuMonitorEvent(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2014-01-31 23:52:17 +00:00
|
|
|
bool ret = false;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
int eventId = -1;
|
|
|
|
int timeout = 0;
|
|
|
|
const char *event = NULL;
|
2015-06-15 16:53:58 +00:00
|
|
|
virshQemuEventData data;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2014-01-31 23:52:17 +00:00
|
|
|
|
2014-02-06 21:46:52 +00:00
|
|
|
if (vshCommandOptBool(cmd, "regex"))
|
|
|
|
flags |= VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_REGEX;
|
|
|
|
if (vshCommandOptBool(cmd, "no-case"))
|
|
|
|
flags |= VIR_CONNECT_DOMAIN_QEMU_MONITOR_EVENT_REGISTER_NOCASE;
|
|
|
|
|
2014-01-31 23:52:17 +00:00
|
|
|
data.ctl = ctl;
|
|
|
|
data.loop = vshCommandOptBool(cmd, "loop");
|
|
|
|
data.pretty = vshCommandOptBool(cmd, "pretty");
|
2015-12-21 15:22:58 +00:00
|
|
|
data.timestamp = vshCommandOptBool(cmd, "timestamp");
|
2014-01-31 23:52:17 +00:00
|
|
|
data.count = 0;
|
|
|
|
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
|
|
|
|
return false;
|
2015-12-03 12:42:35 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "event", &event) < 0)
|
2014-01-31 23:52:17 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "domain"))
|
2018-05-04 09:28:48 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-31 23:52:17 +00:00
|
|
|
if (vshEventStart(ctl, timeout) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if ((eventId = virConnectDomainQemuMonitorEventRegister(priv->conn, dom,
|
2014-01-31 23:52:17 +00:00
|
|
|
event,
|
2015-12-16 16:31:39 +00:00
|
|
|
virshEventQemuPrint,
|
2014-01-31 23:52:17 +00:00
|
|
|
&data, NULL,
|
|
|
|
flags)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
switch (vshEventWait(ctl)) {
|
|
|
|
case VSH_EVENT_INTERRUPT:
|
|
|
|
vshPrint(ctl, _("event loop interrupted\n"));
|
|
|
|
break;
|
|
|
|
case VSH_EVENT_TIMEOUT:
|
|
|
|
vshPrint(ctl, _("event loop timed out\n"));
|
|
|
|
break;
|
|
|
|
case VSH_EVENT_DONE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrint(ctl, _("events received: %1$d\n"), data.count);
|
2014-01-31 23:52:17 +00:00
|
|
|
if (data.count)
|
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2014-01-31 23:52:17 +00:00
|
|
|
vshEventCleanup(ctl);
|
|
|
|
if (eventId >= 0 &&
|
2015-06-15 16:53:58 +00:00
|
|
|
virConnectDomainQemuMonitorEventDeregister(priv->conn, eventId) < 0)
|
2014-01-31 23:52:17 +00:00
|
|
|
ret = false;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-12-21 14:26:27 +00:00
|
|
|
/*
|
|
|
|
* "qemu-attach" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_qemu_attach[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("QEMU Attach")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("QEMU Attach")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-12-21 14:26:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_qemu_attach[] = {
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "pid",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("pid")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-12-21 14:26:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdQemuAttach(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-12-21 14:26:27 +00:00
|
|
|
unsigned int flags = 0;
|
|
|
|
unsigned int pid_value; /* API uses unsigned int, not pid_t */
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-12-21 14:26:27 +00:00
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptUInt(ctl, cmd, "pid", &pid_value) <= 0)
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2012-12-21 14:26:27 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virDomainQemuAttach(priv->conn, pid_value, flags))) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to attach to pid %1$u"), pid_value);
|
2019-10-21 18:19:09 +00:00
|
|
|
return false;
|
2012-12-21 14:26:27 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' attached to pid %2$u\n"),
|
2016-08-24 14:14:23 +00:00
|
|
|
virDomainGetName(dom), pid_value);
|
2019-10-21 18:19:09 +00:00
|
|
|
return true;
|
2012-12-21 14:26:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "qemu-agent-command" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_qemu_agent_command[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("QEMU Guest Agent Command")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Run an arbitrary qemu guest agent command; use at your own risk")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-12-21 14:26:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_qemu_agent_command[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
|
|
|
.help = N_("timeout seconds. must be positive.")
|
|
|
|
},
|
|
|
|
{.name = "async",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("execute command without waiting for timeout")
|
|
|
|
},
|
|
|
|
{.name = "block",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("execute command without timeout")
|
|
|
|
},
|
2013-05-14 15:32:33 +00:00
|
|
|
{.name = "pretty",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("pretty-print the output")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "cmd",
|
|
|
|
.type = VSH_OT_ARGV,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("command")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-12-21 14:26:27 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdQemuAgentCommand(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-12-21 14:26:27 +00:00
|
|
|
bool ret = false;
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char *guest_agent_cmd = NULL;
|
2012-12-21 14:26:27 +00:00
|
|
|
char *result = NULL;
|
|
|
|
int timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT;
|
|
|
|
int judge = 0;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
const vshCmdOpt *opt = NULL;
|
2020-07-02 23:40:16 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2021-03-11 07:16:13 +00:00
|
|
|
virJSONValue *pretty = NULL;
|
2012-12-21 14:26:27 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
dom = virshCommandOptDomain(ctl, cmd, NULL);
|
2012-12-21 14:26:27 +00:00
|
|
|
if (dom == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-05-04 09:28:52 +00:00
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
|
|
|
virBufferAsprintf(&buf, "%s ", opt->data);
|
|
|
|
|
2020-02-02 19:26:38 +00:00
|
|
|
virBufferTrim(&buf, " ");
|
2018-05-04 09:28:52 +00:00
|
|
|
|
2012-12-21 14:26:27 +00:00
|
|
|
guest_agent_cmd = virBufferContentAndReset(&buf);
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
judge = vshCommandOptInt(ctl, cmd, "timeout", &timeout);
|
2015-06-02 09:17:29 +00:00
|
|
|
if (judge < 0)
|
2012-12-21 14:26:27 +00:00
|
|
|
goto cleanup;
|
2015-06-02 09:17:29 +00:00
|
|
|
else if (judge > 0)
|
2012-12-21 14:26:27 +00:00
|
|
|
judge = 1;
|
|
|
|
if (judge && timeout < 1) {
|
|
|
|
vshError(ctl, "%s", _("timeout must be positive"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "async")) {
|
|
|
|
timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT;
|
|
|
|
judge++;
|
|
|
|
}
|
|
|
|
if (vshCommandOptBool(cmd, "block")) {
|
|
|
|
timeout = VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK;
|
|
|
|
judge++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (judge > 1) {
|
|
|
|
vshError(ctl, "%s", _("timeout, async and block options are exclusive"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-06-03 13:42:26 +00:00
|
|
|
|
2012-12-21 14:26:27 +00:00
|
|
|
result = virDomainQemuAgentCommand(dom, guest_agent_cmd, timeout, flags);
|
2013-06-03 13:42:26 +00:00
|
|
|
if (!result)
|
|
|
|
goto cleanup;
|
2012-12-21 14:26:27 +00:00
|
|
|
|
2013-05-14 15:32:33 +00:00
|
|
|
if (vshCommandOptBool(cmd, "pretty")) {
|
|
|
|
char *tmp;
|
|
|
|
pretty = virJSONValueFromString(result);
|
|
|
|
if (pretty && (tmp = virJSONValueToString(pretty, true))) {
|
|
|
|
VIR_FREE(result);
|
|
|
|
result = tmp;
|
|
|
|
} else {
|
|
|
|
vshResetLibvirtError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-14 15:27:01 +00:00
|
|
|
vshPrint(ctl, "%s\n", result);
|
2012-12-21 14:26:27 +00:00
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
2012-12-21 14:26:27 +00:00
|
|
|
VIR_FREE(result);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-12-21 16:51:33 +00:00
|
|
|
/*
|
|
|
|
* "lxc-enter-namespace" namespace
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_lxc_enter_namespace[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("LXC Guest Enter Namespace")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
2016-01-13 07:47:26 +00:00
|
|
|
.data = N_("Run an arbitrary command in a lxc guest namespace; use at your own risk")
|
2013-02-07 15:25:10 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-12-21 16:51:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_lxc_enter_namespace[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-08-26 12:36:52 +00:00
|
|
|
{.name = "noseclabel",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("Do not change process security label")
|
|
|
|
},
|
|
|
|
{.name = "cmd",
|
|
|
|
.type = VSH_OT_ARGV,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2016-01-13 07:47:26 +00:00
|
|
|
.help = N_("command to run")
|
2013-08-26 12:36:52 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-12-21 16:51:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdLxcEnterNamespace(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-12-21 16:51:33 +00:00
|
|
|
const vshCmdOpt *opt = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char **cmdargv = NULL;
|
2012-12-21 16:51:33 +00:00
|
|
|
size_t ncmdargv = 0;
|
|
|
|
pid_t pid;
|
|
|
|
int nfdlist;
|
|
|
|
int *fdlist;
|
|
|
|
size_t i;
|
2021-09-23 23:25:09 +00:00
|
|
|
int status;
|
2013-03-12 17:24:01 +00:00
|
|
|
bool setlabel = true;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree virSecurityModelPtr secmodel = NULL;
|
|
|
|
g_autofree virSecurityLabelPtr seclabel = NULL;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-12-21 16:51:33 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
dom = virshCommandOptDomain(ctl, cmd, NULL);
|
2012-12-21 16:51:33 +00:00
|
|
|
if (dom == NULL)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-12-21 16:51:33 +00:00
|
|
|
|
2013-03-12 17:24:01 +00:00
|
|
|
if (vshCommandOptBool(cmd, "noseclabel"))
|
|
|
|
setlabel = false;
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
|
2021-03-19 23:37:03 +00:00
|
|
|
VIR_EXPAND_N(cmdargv, ncmdargv, 1);
|
2012-12-21 16:51:33 +00:00
|
|
|
cmdargv[ncmdargv-1] = opt->data;
|
|
|
|
}
|
2021-03-19 23:37:03 +00:00
|
|
|
VIR_EXPAND_N(cmdargv, ncmdargv, 1);
|
2012-12-21 16:51:33 +00:00
|
|
|
cmdargv[ncmdargv - 1] = NULL;
|
|
|
|
|
|
|
|
if ((nfdlist = virDomainLxcOpenNamespace(dom, &fdlist, 0)) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-12-21 16:51:33 +00:00
|
|
|
|
2013-03-12 17:24:01 +00:00
|
|
|
if (setlabel) {
|
2020-09-23 20:06:18 +00:00
|
|
|
secmodel = g_new0(virSecurityModel, 1);
|
|
|
|
seclabel = g_new0(virSecurityLabel, 1);
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (virNodeGetSecurityModel(priv->conn, secmodel) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-03-12 17:24:01 +00:00
|
|
|
if (virDomainGetSecurityLabel(dom, seclabel) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-03-12 17:24:01 +00:00
|
|
|
}
|
|
|
|
|
2012-12-21 16:51:33 +00:00
|
|
|
/* Fork once because we don't want to affect
|
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 00:54:33 +00:00
|
|
|
* virsh's namespace itself, and because user namespace
|
|
|
|
* can only be changed in single-threaded process
|
2012-12-21 16:51:33 +00:00
|
|
|
*/
|
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 00:54:33 +00:00
|
|
|
if ((pid = virFork()) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2021-09-23 23:25:09 +00:00
|
|
|
|
|
|
|
if (pid != 0) {
|
2013-05-21 07:44:53 +00:00
|
|
|
for (i = 0; i < nfdlist; i++)
|
2012-12-21 16:51:33 +00:00
|
|
|
VIR_FORCE_CLOSE(fdlist[i]);
|
|
|
|
VIR_FREE(fdlist);
|
2013-12-23 16:32:45 +00:00
|
|
|
if (virProcessWait(pid, NULL, false) < 0) {
|
|
|
|
vshReportError(ctl);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-12-23 16:32:45 +00:00
|
|
|
}
|
2021-09-23 23:25:09 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setlabel &&
|
|
|
|
virDomainLxcEnterSecurityLabel(secmodel, seclabel, NULL, 0) < 0)
|
|
|
|
_exit(EXIT_CANCELED);
|
|
|
|
|
|
|
|
if (virDomainLxcEnterCGroup(dom, 0) < 0)
|
|
|
|
_exit(EXIT_CANCELED);
|
|
|
|
|
|
|
|
if (virDomainLxcEnterNamespace(dom, nfdlist, fdlist, NULL, NULL, 0) < 0)
|
|
|
|
_exit(EXIT_CANCELED);
|
|
|
|
|
|
|
|
/* Fork a second time because entering the
|
|
|
|
* pid namespace only takes effect after fork
|
|
|
|
*/
|
|
|
|
if ((pid = virFork()) < 0)
|
|
|
|
_exit(EXIT_CANCELED);
|
|
|
|
|
|
|
|
if (pid == 0) {
|
|
|
|
execv(cmdargv[0], cmdargv);
|
|
|
|
_exit(errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
|
2012-12-21 16:51:33 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 23:25:09 +00:00
|
|
|
if (virProcessWait(pid, &status, true) < 0)
|
|
|
|
_exit(EXIT_CANNOT_INVOKE);
|
|
|
|
virProcessExitWithStatus(status);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-12-21 16:51:33 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "dumpxml" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_dumpxml[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("domain information in XML")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Output the domain information as an XML dump to stdout.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_dumpxml[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "inactive",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("show inactive defined XML")
|
|
|
|
},
|
|
|
|
{.name = "security-info",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("include security sensitive information in XML dump")
|
|
|
|
},
|
|
|
|
{.name = "update-cpu",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("update guest CPU according to host CPU")
|
|
|
|
},
|
|
|
|
{.name = "migratable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("provide XML suitable for migrations")
|
|
|
|
},
|
2022-06-16 15:29:54 +00:00
|
|
|
{.name = "xpath",
|
|
|
|
.type = VSH_OT_STRING,
|
virsh: Require --xpath for *dumpxml
Historically, the dumpxml command reject any unknown arguments,
for instance:
virsh dumpxml fedora xxx
However, after v8.5.0-rc1~31 the second argument ('xxx') is
treated as an XPath, but it's not that clearly visible.
Therefore, require the --xpath switch, like this:
virsh dumpxml fedora --xpath xxx
Yes, this breaks already released virsh, but I think we can argue
that the pool of users of this particular function is very small.
We also document the argument being mandatory:
dumpxml [--inactive] [--security-info] [--update-cpu] [--migratable]
[--xpath EXPRESSION] [--wrap] domain
The sooner we do this change, the better.
The same applies for other *dumpxml functions (net-dumpxml,
pool-dumpxml, vol-dumpxl to name a few).
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2103524
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2022-07-08 10:45:42 +00:00
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
2022-06-16 15:29:54 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
|
|
|
.help = N_("xpath expression to filter the XML document")
|
|
|
|
},
|
|
|
|
{.name = "wrap",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("wrap xpath results in an common root element"),
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDumpXML(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2022-06-16 15:29:54 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned int flags = 0;
|
|
|
|
bool inactive = vshCommandOptBool(cmd, "inactive");
|
|
|
|
bool secure = vshCommandOptBool(cmd, "security-info");
|
|
|
|
bool update = vshCommandOptBool(cmd, "update-cpu");
|
2012-10-08 09:58:05 +00:00
|
|
|
bool migratable = vshCommandOptBool(cmd, "migratable");
|
2022-06-16 15:29:54 +00:00
|
|
|
bool wrap = vshCommandOptBool(cmd, "wrap");
|
|
|
|
const char *xpath = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (inactive)
|
|
|
|
flags |= VIR_DOMAIN_XML_INACTIVE;
|
|
|
|
if (secure)
|
|
|
|
flags |= VIR_DOMAIN_XML_SECURE;
|
|
|
|
if (update)
|
|
|
|
flags |= VIR_DOMAIN_XML_UPDATE_CPU;
|
2012-10-08 09:58:05 +00:00
|
|
|
if (migratable)
|
|
|
|
flags |= VIR_DOMAIN_XML_MIGRATABLE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2022-06-16 15:29:54 +00:00
|
|
|
if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0)
|
2021-09-24 15:17:47 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-06-16 15:29:54 +00:00
|
|
|
if (!(xml = virDomainGetXMLDesc(dom, flags)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return virshDumpXML(ctl, xml, "domain", xpath, wrap);
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "domxml-from-native" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domxmlfromnative[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Convert native config to domain XML")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Convert native guest configuration format to domain XML format.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domxmlfromnative[] = {
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "format",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("source config data format")
|
|
|
|
},
|
|
|
|
{.name = "config",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("config data file to import from")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomXMLFromNative(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *format = NULL;
|
|
|
|
const char *configFile = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *configData = NULL;
|
|
|
|
g_autofree char *xmlData = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned int flags = 0;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "format", &format) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "config", &configFile) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2014-10-14 08:04:31 +00:00
|
|
|
if (virFileReadAll(configFile, VSH_MAX_XML_FILE, &configData) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
xmlData = virConnectDomainXMLFromNative(priv->conn, format, configData, flags);
|
2021-09-24 15:17:47 +00:00
|
|
|
if (!xmlData)
|
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-09-24 15:17:47 +00:00
|
|
|
vshPrint(ctl, "%s", xmlData);
|
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "domxml-to-native" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domxmltonative[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Convert domain XML to native config")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Convert domain XML config to a native guest configuration format.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domxmltonative[] = {
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "format",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("target config data type format")
|
|
|
|
},
|
2018-09-26 07:59:08 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_OT_STRING_FULL(VSH_OFLAG_REQ_OPT, 0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "xml",
|
2017-10-10 15:19:10 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("xml data file to export from")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomXMLToNative(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *format = NULL;
|
|
|
|
const char *xmlFile = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *configData = NULL;
|
|
|
|
g_autofree char *xmlData = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned int flags = 0;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "format", &format) < 0 ||
|
|
|
|
vshCommandOptStringReq(ctl, cmd, "xml", &xmlFile) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2017-06-02 15:04:52 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("domain", "xml");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2017-06-02 15:04:52 +00:00
|
|
|
if (vshCommandOptBool(cmd, "domain") &&
|
|
|
|
(!(dom = virshCommandOptDomain(ctl, cmd, NULL))))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (dom) {
|
|
|
|
xmlData = virDomainGetXMLDesc(dom, flags);
|
|
|
|
} else if (xmlFile) {
|
|
|
|
if (virFileReadAll(xmlFile, VSH_MAX_XML_FILE, &xmlData) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
} else {
|
2017-06-02 15:04:52 +00:00
|
|
|
vshError(ctl, "%s", _("need either domain or domain XML"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-06-02 15:04:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!xmlData) {
|
|
|
|
vshError(ctl, "%s", _("failed to retrieve XML"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-06-02 15:04:52 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
if (!(configData = virConnectDomainXMLToNative(priv->conn, format, xmlData, flags)))
|
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
vshPrint(ctl, "%s", configData);
|
|
|
|
|
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "domname" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domname[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("convert a domain id or UUID to domain name")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = ""
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domname[] = {
|
2020-09-11 07:13:09 +00:00
|
|
|
{.name = "domain",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.completer = virshDomainUUIDCompleter,
|
|
|
|
.help = N_("domain id or uuid")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomname(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomainBy(ctl, cmd, NULL,
|
|
|
|
VIRSH_BYID|VIRSH_BYUUID)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
vshPrint(ctl, "%s\n", virDomainGetName(dom));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-08-10 19:59:15 +00:00
|
|
|
/*
|
|
|
|
* "domrename" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domrename[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("rename a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = "Rename an inactive domain."
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domrename[] = {
|
2018-05-15 11:10:32 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN(N_("domain name or uuid"),
|
|
|
|
VIR_CONNECT_LIST_DOMAINS_INACTIVE),
|
2015-08-10 19:59:15 +00:00
|
|
|
{.name = "new-name",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2015-08-10 19:59:15 +00:00
|
|
|
.help = N_("new domain name")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomrename(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2015-08-10 19:59:15 +00:00
|
|
|
const char *new_name = NULL;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-08-10 19:59:15 +00:00
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "new-name", &new_name) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-08-10 19:59:15 +00:00
|
|
|
|
|
|
|
if (virDomainRename(dom, new_name, 0) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2015-08-10 19:59:15 +00:00
|
|
|
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "Domain successfully renamed\n");
|
2015-08-10 19:59:15 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2015-08-10 19:59:15 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "domid" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domid[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("convert a domain name or UUID to domain id")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = ""
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domid[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN(N_("domain name or uuid"),
|
|
|
|
VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomid(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned int id;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomainBy(ctl, cmd, NULL,
|
|
|
|
VIRSH_BYNAME|VIRSH_BYUUID)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
id = virDomainGetID(dom);
|
|
|
|
if (id == ((unsigned int)-1))
|
|
|
|
vshPrint(ctl, "%s\n", "-");
|
|
|
|
else
|
|
|
|
vshPrint(ctl, "%d\n", id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "domuuid" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domuuid[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("convert a domain name or id to domain UUID")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = ""
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domuuid[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN(N_("domain id or name"), 0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomuuid(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomainBy(ctl, cmd, NULL,
|
|
|
|
VIRSH_BYNAME|VIRSH_BYID)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainGetUUIDString(dom, uuid) != -1)
|
|
|
|
vshPrint(ctl, "%s\n", uuid);
|
|
|
|
else
|
|
|
|
vshError(ctl, "%s", _("failed to get domain UUID"));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "migrate" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_migrate[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("migrate domain to another host")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Migrate domain to another host. Add --live for live migration.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_migrate[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2014-11-11 09:45:24 +00:00
|
|
|
{.name = "desturi",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2014-11-11 09:45:24 +00:00
|
|
|
.help = N_("connection URI of the destination host as seen from the client(normal migration) or source(p2p migration)")
|
|
|
|
},
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_LIVE(N_("live migration")),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "offline",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("offline migration")
|
|
|
|
},
|
|
|
|
{.name = "p2p",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("peer-2-peer migration")
|
|
|
|
},
|
|
|
|
{.name = "direct",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("direct migration")
|
|
|
|
},
|
|
|
|
{.name = "tunneled",
|
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "tunnelled"
|
|
|
|
},
|
|
|
|
{.name = "tunnelled",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("tunnelled migration")
|
|
|
|
},
|
|
|
|
{.name = "persistent",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("persist VM on destination")
|
|
|
|
},
|
|
|
|
{.name = "undefinesource",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("undefine VM on source")
|
|
|
|
},
|
|
|
|
{.name = "suspend",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("do not restart the domain on the destination host")
|
|
|
|
},
|
|
|
|
{.name = "copy-storage-all",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("migration with non-shared storage with full disk copy")
|
|
|
|
},
|
|
|
|
{.name = "copy-storage-inc",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("migration with non-shared storage with incremental copy (same base image shared between source and destination)")
|
|
|
|
},
|
2021-12-01 15:21:29 +00:00
|
|
|
{.name = "copy-storage-synchronous-writes",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("force guest disk writes to be synchronously written to the destination to improve storage migration convergence")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "change-protection",
|
|
|
|
.type = VSH_OT_BOOL,
|
2013-03-26 03:02:17 +00:00
|
|
|
.help = N_("prevent any configuration changes to domain until migration ends")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "unsafe",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("force migration even if it may be unsafe")
|
|
|
|
},
|
|
|
|
{.name = "verbose",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("display the progress of migration")
|
|
|
|
},
|
2013-01-10 12:39:34 +00:00
|
|
|
{.name = "compressed",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("compress repeated pages during live migration")
|
|
|
|
},
|
2014-02-06 23:44:36 +00:00
|
|
|
{.name = "auto-converge",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("force convergence during live migration")
|
|
|
|
},
|
2014-01-13 06:28:12 +00:00
|
|
|
{.name = "rdma-pin-all",
|
|
|
|
.type = VSH_OT_BOOL,
|
2016-11-22 18:26:45 +00:00
|
|
|
.help = N_("pin all memory before starting RDMA live migration")
|
2014-01-13 06:28:12 +00:00
|
|
|
},
|
2013-06-12 14:11:21 +00:00
|
|
|
{.name = "abort-on-error",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("abort on soft errors during migration")
|
|
|
|
},
|
2014-12-01 15:59:58 +00:00
|
|
|
{.name = "postcopy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("enable post-copy migration; switch to it using migrate-postcopy command")
|
|
|
|
},
|
2014-12-01 16:00:02 +00:00
|
|
|
{.name = "postcopy-after-precopy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("automatically switch to post-copy migration after one pass of pre-copy")
|
|
|
|
},
|
2022-05-10 13:20:25 +00:00
|
|
|
{.name = "postcopy-resume",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("resume failed post-copy migration")
|
|
|
|
},
|
2022-06-22 14:36:53 +00:00
|
|
|
{.name = "zerocopy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("use zero-copy mechanism for migrating memory pages")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "migrateuri",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("migration URI, usually can be omitted")
|
|
|
|
},
|
2013-06-18 07:46:49 +00:00
|
|
|
{.name = "graphicsuri",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-06-18 07:46:49 +00:00
|
|
|
.help = N_("graphics URI to be used for seamless graphics migration")
|
|
|
|
},
|
2013-10-08 11:49:25 +00:00
|
|
|
{.name = "listen-address",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-10-08 11:49:25 +00:00
|
|
|
.help = N_("listen address that destination should bind to for incoming migration")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "dname",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("rename to new name during migration (if supported)")
|
|
|
|
},
|
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
2015-12-02 14:14:41 +00:00
|
|
|
.help = N_("run action specified by --timeout-* option (suspend by "
|
|
|
|
"default) if live migration exceeds timeout (in seconds)")
|
|
|
|
},
|
|
|
|
{.name = "timeout-suspend",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("suspend the guest after timeout")
|
|
|
|
},
|
|
|
|
{.name = "timeout-postcopy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("switch to post-copy after timeout")
|
2013-01-14 11:26:54 +00:00
|
|
|
},
|
|
|
|
{.name = "xml",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("filename containing updated XML for the target")
|
|
|
|
},
|
2015-06-15 22:42:11 +00:00
|
|
|
{.name = "migrate-disks",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-16 13:11:03 +00:00
|
|
|
.completer = virshDomainMigrateDisksCompleter,
|
2015-06-15 22:42:11 +00:00
|
|
|
.help = N_("comma separated list of disks to be migrated")
|
|
|
|
},
|
2016-03-17 14:58:47 +00:00
|
|
|
{.name = "disks-port",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("port to use by target server for incoming disks migration")
|
|
|
|
},
|
2020-08-24 13:42:31 +00:00
|
|
|
{.name = "disks-uri",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2020-08-24 13:42:31 +00:00
|
|
|
.help = N_("URI to use for disks migration (overrides --disks-port)")
|
|
|
|
},
|
2016-06-20 07:26:48 +00:00
|
|
|
{.name = "comp-methods",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-06-15 00:38:21 +00:00
|
|
|
.completer = virshDomainMigrateCompMethodsCompleter,
|
2016-06-20 07:26:48 +00:00
|
|
|
.help = N_("comma separated list of compression methods to be used")
|
|
|
|
},
|
|
|
|
{.name = "comp-mt-level",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("compress level for multithread compression")
|
|
|
|
},
|
|
|
|
{.name = "comp-mt-threads",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("number of compression threads for multithread compression")
|
|
|
|
},
|
|
|
|
{.name = "comp-mt-dthreads",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("number of decompression threads for multithread compression")
|
|
|
|
},
|
|
|
|
{.name = "comp-xbzrle-cache",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("page cache size for xbzrle compression")
|
|
|
|
},
|
2016-06-20 13:45:59 +00:00
|
|
|
{.name = "auto-converge-initial",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("initial CPU throttling rate for auto-convergence")
|
|
|
|
},
|
|
|
|
{.name = "auto-converge-increment",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("CPU throttling rate increment for auto-convergence")
|
|
|
|
},
|
2016-11-22 13:06:43 +00:00
|
|
|
{.name = "persistent-xml",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2016-11-22 13:06:43 +00:00
|
|
|
.help = N_("filename containing updated persistent XML for the target")
|
|
|
|
},
|
2017-02-15 13:58:46 +00:00
|
|
|
{.name = "tls",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("use TLS for migration")
|
|
|
|
},
|
2019-01-31 09:45:35 +00:00
|
|
|
{.name = "postcopy-bandwidth",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("post-copy migration bandwidth limit in MiB/s")
|
|
|
|
},
|
2017-10-24 15:00:59 +00:00
|
|
|
{.name = "parallel",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("enable parallel migration")
|
|
|
|
},
|
|
|
|
{.name = "parallel-connections",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("number of connections for parallel migration")
|
|
|
|
},
|
2019-09-02 15:00:32 +00:00
|
|
|
{.name = "bandwidth",
|
2019-08-26 19:41:25 +00:00
|
|
|
.type = VSH_OT_INT,
|
2019-09-02 15:00:32 +00:00
|
|
|
.help = N_("migration bandwidth limit in MiB/s")
|
2019-08-26 19:41:25 +00:00
|
|
|
},
|
2019-12-03 15:20:57 +00:00
|
|
|
{.name = "tls-destination",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:42:08 +00:00
|
|
|
.completer = virshCompleteEmpty,
|
2019-12-03 15:20:57 +00:00
|
|
|
.help = N_("override the destination host name used for TLS verification")
|
|
|
|
},
|
2023-02-24 09:27:11 +00:00
|
|
|
{.name = "comp-zlib-level",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("compress level for zlib compression")
|
|
|
|
},
|
|
|
|
{.name = "comp-zstd-level",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("compress level for zstd compression")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
doMigrate(void *opaque)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *desturi = NULL;
|
2013-06-17 08:49:27 +00:00
|
|
|
const char *opt = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned int flags = 0;
|
2015-06-15 16:53:58 +00:00
|
|
|
virshCtrlData *data = opaque;
|
2012-07-25 15:37:18 +00:00
|
|
|
vshControl *ctl = data->ctl;
|
|
|
|
const vshCmd *cmd = data->cmd;
|
2013-06-17 08:49:27 +00:00
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
int nparams = 0;
|
|
|
|
int maxparams = 0;
|
2016-04-14 10:33:52 +00:00
|
|
|
int intOpt = 0;
|
|
|
|
unsigned long long ullOpt = 0;
|
|
|
|
int rv;
|
cmdMigrate: move vshConnect before vshWatchJob
A possible fix to issue:
http://www.redhat.com/archives/libvir-list/2014-August/thread.html#00227
While doing migration on KVM host, found problem sometimes:
VM is already running on the target host and disappears from source
host, but 'virsh migrate' command line hangs, cannot exit normally.
If pressing "ENTER" key, it will exit.
The code hangs at tools/virsh-domain.c: cmdMigrate
->vshWatchJob->poll():
poll() is trying to select pipe_fd, which is used to receive message
from doMigrate thread. In debugging, found that doMigrate finishes
and at the end it does call safewrite() to write the retval ('0' or
'1') to pipe_fd, and the write is completed. But cmdMigrate poll()
cannot get the event. If pressing "ENTER" key, poll() can get the
event and select pipe_fd, then command line can exit.
In current code, authentication thread which is called by vshConnect
will use stdin, and at the same time, in cmdMigrate main process,
poll() is listening to stdin, that probably affect poll() to get
pipe_fd event. Better to move authentication before vshWatchJob. With
this change, above problem does not exist.
Signed-off-by: Chunyan Liu <cyliu@suse.com>
2014-08-08 08:44:36 +00:00
|
|
|
virConnectPtr dconn = data->dconn;
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
sigset_t sigmask, oldsigmask;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
sigemptyset(&sigmask);
|
|
|
|
sigaddset(&sigmask, SIGINT);
|
2021-02-01 12:42:01 +00:00
|
|
|
if (pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask) != 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out_sig;
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
|
2013-06-17 08:49:27 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "desturi", &desturi) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
goto out;
|
|
|
|
|
2013-06-17 08:49:27 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "migrateuri", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt &&
|
|
|
|
virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_URI, opt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
2013-06-18 07:46:49 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "graphicsuri", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt &&
|
|
|
|
virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_GRAPHICS_URI, opt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
2013-10-08 11:49:25 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "listen-address", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt &&
|
|
|
|
virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_LISTEN_ADDRESS, opt) < 0)
|
|
|
|
goto save_error;
|
2016-03-17 14:58:47 +00:00
|
|
|
|
2020-08-24 13:43:50 +00:00
|
|
|
if (vshCommandOptInt(ctl, cmd, "disks-port", &intOpt) < 0)
|
2016-03-17 14:58:47 +00:00
|
|
|
goto out;
|
2020-08-24 13:43:50 +00:00
|
|
|
if (intOpt &&
|
2016-03-17 14:58:47 +00:00
|
|
|
virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
2020-08-24 13:43:50 +00:00
|
|
|
VIR_MIGRATE_PARAM_DISKS_PORT, intOpt) < 0)
|
2020-08-24 13:42:31 +00:00
|
|
|
goto save_error;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "disks-uri", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt &&
|
|
|
|
virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_DISKS_URI,
|
|
|
|
opt) < 0)
|
2016-03-17 14:58:47 +00:00
|
|
|
goto save_error;
|
2013-10-08 11:49:25 +00:00
|
|
|
|
2013-06-17 08:49:27 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "dname", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt &&
|
|
|
|
virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_DEST_NAME, opt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
2015-06-15 22:42:11 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "migrate-disks", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt) {
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char **val = NULL;
|
2015-06-15 22:42:11 +00:00
|
|
|
|
2021-02-05 17:35:07 +00:00
|
|
|
val = g_strsplit(opt, ",", 0);
|
2015-06-15 22:42:11 +00:00
|
|
|
|
|
|
|
if (virTypedParamsAddStringList(¶ms,
|
|
|
|
&nparams,
|
|
|
|
&maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_MIGRATE_DISKS,
|
|
|
|
(const char **)val) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-14 10:33:52 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "comp-methods", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt) {
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char **val = g_strsplit(opt, ",", 0);
|
2016-04-14 10:33:52 +00:00
|
|
|
|
|
|
|
if (virTypedParamsAddStringList(¶ms,
|
|
|
|
&nparams,
|
|
|
|
&maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_COMPRESSION,
|
|
|
|
(const char **)val) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "comp-mt-level", &intOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_COMPRESSION_MT_LEVEL,
|
|
|
|
intOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "comp-mt-threads", &intOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_COMPRESSION_MT_THREADS,
|
|
|
|
intOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "comp-mt-dthreads", &intOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_COMPRESSION_MT_DTHREADS,
|
|
|
|
intOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rv = vshCommandOptULongLong(ctl, cmd, "comp-xbzrle-cache", &ullOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_COMPRESSION_XBZRLE_CACHE,
|
|
|
|
ullOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2013-06-17 08:49:27 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "xml", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt) {
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2013-06-17 08:49:27 +00:00
|
|
|
|
2014-10-14 08:04:31 +00:00
|
|
|
if (virFileReadAll(opt, VSH_MAX_XML_FILE, &xml) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("cannot read file '%1$s'"), opt);
|
2013-06-17 08:49:27 +00:00
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_DEST_XML, xml) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-22 13:06:43 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "persistent-xml", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt) {
|
2023-02-01 15:08:22 +00:00
|
|
|
g_autofree char *xml = NULL;
|
2016-11-22 13:06:43 +00:00
|
|
|
|
|
|
|
if (virFileReadAll(opt, VSH_MAX_XML_FILE, &xml) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("cannot read file '%1$s'"), opt);
|
2016-11-22 13:06:43 +00:00
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_PERSIST_XML, xml) < 0) {
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-20 13:45:59 +00:00
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "auto-converge-initial", &intOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_AUTO_CONVERGE_INITIAL,
|
|
|
|
intOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "auto-converge-increment", &intOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_AUTO_CONVERGE_INCREMENT,
|
|
|
|
intOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2019-01-31 09:45:35 +00:00
|
|
|
if ((rv = vshCommandOptULongLong(ctl, cmd, "postcopy-bandwidth", &ullOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_BANDWIDTH_POSTCOPY,
|
|
|
|
ullOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2019-07-19 13:46:33 +00:00
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "parallel-connections", &intOpt)) < 0) {
|
2017-10-24 15:00:59 +00:00
|
|
|
goto out;
|
2019-07-19 13:46:33 +00:00
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_PARALLEL_CONNECTIONS,
|
|
|
|
intOpt) < 0)
|
2019-08-26 19:41:25 +00:00
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2023-02-24 09:27:11 +00:00
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "comp-zlib-level", &intOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_COMPRESSION_ZLIB_LEVEL,
|
|
|
|
intOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((rv = vshCommandOptInt(ctl, cmd, "comp-zstd-level", &intOpt)) < 0) {
|
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddInt(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_COMPRESSION_ZSTD_LEVEL,
|
|
|
|
intOpt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
}
|
|
|
|
|
2019-09-02 15:00:32 +00:00
|
|
|
if ((rv = vshCommandOptULongLong(ctl, cmd, "bandwidth", &ullOpt)) < 0) {
|
2019-08-26 19:41:25 +00:00
|
|
|
goto out;
|
|
|
|
} else if (rv > 0) {
|
|
|
|
if (virTypedParamsAddULLong(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_BANDWIDTH,
|
|
|
|
ullOpt) < 0)
|
2019-07-19 13:46:33 +00:00
|
|
|
goto save_error;
|
|
|
|
}
|
2017-10-24 15:00:59 +00:00
|
|
|
|
2019-12-03 15:20:57 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "tls-destination", &opt) < 0)
|
|
|
|
goto out;
|
|
|
|
if (opt &&
|
|
|
|
virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
|
|
VIR_MIGRATE_PARAM_TLS_DESTINATION, opt) < 0)
|
|
|
|
goto save_error;
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (vshCommandOptBool(cmd, "live"))
|
|
|
|
flags |= VIR_MIGRATE_LIVE;
|
|
|
|
if (vshCommandOptBool(cmd, "p2p"))
|
|
|
|
flags |= VIR_MIGRATE_PEER2PEER;
|
|
|
|
if (vshCommandOptBool(cmd, "tunnelled"))
|
|
|
|
flags |= VIR_MIGRATE_TUNNELLED;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "persistent"))
|
|
|
|
flags |= VIR_MIGRATE_PERSIST_DEST;
|
|
|
|
if (vshCommandOptBool(cmd, "undefinesource"))
|
|
|
|
flags |= VIR_MIGRATE_UNDEFINE_SOURCE;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "suspend"))
|
|
|
|
flags |= VIR_MIGRATE_PAUSED;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "copy-storage-all"))
|
|
|
|
flags |= VIR_MIGRATE_NON_SHARED_DISK;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "copy-storage-inc"))
|
|
|
|
flags |= VIR_MIGRATE_NON_SHARED_INC;
|
|
|
|
|
2021-12-01 15:21:29 +00:00
|
|
|
if (vshCommandOptBool(cmd, "copy-storage-synchronous-writes")) {
|
|
|
|
if (!(flags & VIR_MIGRATE_NON_SHARED_DISK) &&
|
|
|
|
!(flags & VIR_MIGRATE_NON_SHARED_INC)) {
|
|
|
|
vshError(ctl, "'--copy-storage-synchronous-writes' requires one of '--copy-storage-all', 'copy-storage-inc'");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
flags |= VIR_MIGRATE_NON_SHARED_SYNCHRONOUS_WRITES;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (vshCommandOptBool(cmd, "change-protection"))
|
|
|
|
flags |= VIR_MIGRATE_CHANGE_PROTECTION;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "unsafe"))
|
|
|
|
flags |= VIR_MIGRATE_UNSAFE;
|
|
|
|
|
2013-01-10 12:39:34 +00:00
|
|
|
if (vshCommandOptBool(cmd, "compressed"))
|
|
|
|
flags |= VIR_MIGRATE_COMPRESSED;
|
|
|
|
|
2014-02-06 23:44:36 +00:00
|
|
|
if (vshCommandOptBool(cmd, "auto-converge"))
|
|
|
|
flags |= VIR_MIGRATE_AUTO_CONVERGE;
|
|
|
|
|
2014-01-13 06:28:12 +00:00
|
|
|
if (vshCommandOptBool(cmd, "rdma-pin-all"))
|
|
|
|
flags |= VIR_MIGRATE_RDMA_PIN_ALL;
|
|
|
|
|
2014-11-13 14:20:51 +00:00
|
|
|
if (vshCommandOptBool(cmd, "offline"))
|
2012-11-21 08:28:49 +00:00
|
|
|
flags |= VIR_MIGRATE_OFFLINE;
|
|
|
|
|
2013-06-12 14:11:21 +00:00
|
|
|
if (vshCommandOptBool(cmd, "abort-on-error"))
|
|
|
|
flags |= VIR_MIGRATE_ABORT_ON_ERROR;
|
|
|
|
|
2014-12-01 15:59:58 +00:00
|
|
|
if (vshCommandOptBool(cmd, "postcopy"))
|
|
|
|
flags |= VIR_MIGRATE_POSTCOPY;
|
|
|
|
|
2022-05-10 13:20:25 +00:00
|
|
|
if (vshCommandOptBool(cmd, "postcopy-resume"))
|
|
|
|
flags |= VIR_MIGRATE_POSTCOPY_RESUME;
|
|
|
|
|
2022-06-22 14:36:53 +00:00
|
|
|
if (vshCommandOptBool(cmd, "zerocopy"))
|
|
|
|
flags |= VIR_MIGRATE_ZEROCOPY;
|
|
|
|
|
2017-02-15 13:58:46 +00:00
|
|
|
if (vshCommandOptBool(cmd, "tls"))
|
|
|
|
flags |= VIR_MIGRATE_TLS;
|
|
|
|
|
2017-10-24 15:00:59 +00:00
|
|
|
if (vshCommandOptBool(cmd, "parallel"))
|
|
|
|
flags |= VIR_MIGRATE_PARALLEL;
|
|
|
|
|
2015-04-30 12:47:46 +00:00
|
|
|
if (flags & VIR_MIGRATE_PEER2PEER || vshCommandOptBool(cmd, "direct")) {
|
2013-06-17 08:49:27 +00:00
|
|
|
if (virDomainMigrateToURI3(dom, desturi, params, nparams, flags) == 0)
|
2020-04-21 17:06:16 +00:00
|
|
|
data->ret = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
} else {
|
|
|
|
/* For traditional live migration, connect to the destination host directly. */
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) ddom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-06-17 08:49:27 +00:00
|
|
|
if ((ddom = virDomainMigrate3(dom, dconn, params, nparams, flags))) {
|
2020-04-21 17:06:16 +00:00
|
|
|
data->ret = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
out:
|
2020-01-17 11:16:48 +00:00
|
|
|
#ifndef WIN32
|
2012-07-25 15:37:18 +00:00
|
|
|
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
|
2014-03-25 06:53:59 +00:00
|
|
|
out_sig:
|
2020-01-17 11:16:48 +00:00
|
|
|
#endif /* !WIN32 */
|
2013-06-17 08:49:27 +00:00
|
|
|
virTypedParamsFree(params, nparams);
|
2020-02-05 14:16:16 +00:00
|
|
|
g_main_loop_quit(data->eventLoop);
|
2013-06-17 08:49:27 +00:00
|
|
|
return;
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
save_error:
|
2013-06-17 08:49:27 +00:00
|
|
|
vshSaveLibvirtError();
|
|
|
|
goto out;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-12-02 14:14:41 +00:00
|
|
|
typedef enum {
|
|
|
|
VIRSH_MIGRATE_TIMEOUT_DEFAULT,
|
|
|
|
VIRSH_MIGRATE_TIMEOUT_SUSPEND,
|
|
|
|
VIRSH_MIGRATE_TIMEOUT_POSTCOPY,
|
|
|
|
} virshMigrateTimeoutAction;
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static void
|
2015-12-02 14:14:41 +00:00
|
|
|
virshMigrateTimeout(vshControl *ctl,
|
|
|
|
virDomainPtr dom,
|
|
|
|
void *opaque)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2015-12-02 14:14:41 +00:00
|
|
|
virshMigrateTimeoutAction action = *(virshMigrateTimeoutAction *) opaque;
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
case VIRSH_MIGRATE_TIMEOUT_DEFAULT: /* unreachable */
|
|
|
|
case VIRSH_MIGRATE_TIMEOUT_SUSPEND:
|
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG,
|
|
|
|
"migration timed out; suspending domain\n");
|
|
|
|
if (virDomainSuspend(dom) < 0)
|
|
|
|
vshDebug(ctl, VSH_ERR_INFO, "suspending domain failed\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIRSH_MIGRATE_TIMEOUT_POSTCOPY:
|
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG,
|
|
|
|
"migration timed out; switching to post-copy\n");
|
|
|
|
if (virDomainMigrateStartPostCopy(dom, 0) < 0)
|
|
|
|
vshDebug(ctl, VSH_ERR_INFO, "switching to post-copy failed\n");
|
|
|
|
break;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2014-12-01 16:00:02 +00:00
|
|
|
static void
|
2019-10-14 12:44:29 +00:00
|
|
|
virshMigrateIteration(virConnectPtr conn G_GNUC_UNUSED,
|
2014-12-01 16:00:02 +00:00
|
|
|
virDomainPtr dom,
|
|
|
|
int iteration,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
vshControl *ctl = opaque;
|
|
|
|
|
|
|
|
if (iteration == 2) {
|
|
|
|
vshDebug(ctl, VSH_ERR_DEBUG,
|
|
|
|
"iteration %d finished; switching to post-copy\n",
|
|
|
|
iteration - 1);
|
|
|
|
if (virDomainMigrateStartPostCopy(dom, 0) < 0)
|
|
|
|
vshDebug(ctl, VSH_ERR_INFO, "switching to post-copy failed\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdMigrate(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
virThread workerThread;
|
|
|
|
bool verbose = false;
|
2020-02-05 14:16:16 +00:00
|
|
|
unsigned int timeout = 0;
|
2015-12-02 14:14:41 +00:00
|
|
|
virshMigrateTimeoutAction timeoutAction = VIRSH_MIGRATE_TIMEOUT_DEFAULT;
|
2012-07-25 15:37:18 +00:00
|
|
|
bool live_flag = false;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2014-12-01 16:00:02 +00:00
|
|
|
int iterEvent = -1;
|
2020-02-05 14:16:16 +00:00
|
|
|
g_autoptr(GMainContext) eventCtxt = g_main_context_new();
|
|
|
|
g_autoptr(GMainLoop) eventLoop = g_main_loop_new(eventCtxt, FALSE);
|
|
|
|
virshCtrlData data = {
|
|
|
|
.dconn = NULL,
|
|
|
|
.ctl = ctl,
|
|
|
|
.cmd = cmd,
|
|
|
|
.eventLoop = eventLoop,
|
|
|
|
.ret = -1,
|
|
|
|
};
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2016-02-26 11:38:23 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("live", "offline");
|
2015-12-02 14:14:41 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("timeout-suspend", "timeout-postcopy");
|
2016-10-18 17:33:11 +00:00
|
|
|
VSH_REQUIRE_OPTION("postcopy-after-precopy", "postcopy");
|
2022-05-10 13:20:25 +00:00
|
|
|
VSH_REQUIRE_OPTION("postcopy-resume", "postcopy");
|
2017-09-08 16:15:13 +00:00
|
|
|
VSH_REQUIRE_OPTION("timeout-postcopy", "postcopy");
|
2016-11-22 13:06:43 +00:00
|
|
|
VSH_REQUIRE_OPTION("persistent-xml", "persistent");
|
2019-12-17 13:31:10 +00:00
|
|
|
VSH_REQUIRE_OPTION("tls-destination", "tls");
|
2016-02-26 11:38:23 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "verbose"))
|
|
|
|
verbose = true;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "live"))
|
|
|
|
live_flag = true;
|
2020-02-05 14:16:16 +00:00
|
|
|
if (vshCommandOptUInt(ctl, cmd, "timeout", &timeout) < 0) {
|
2014-02-14 00:08:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else if (timeout > 0 && !live_flag) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("migrate: Unexpected timeout for offline migration"));
|
2013-03-26 15:41:06 +00:00
|
|
|
goto cleanup;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-12-02 14:14:41 +00:00
|
|
|
if (vshCommandOptBool(cmd, "timeout-suspend"))
|
|
|
|
timeoutAction = VIRSH_MIGRATE_TIMEOUT_SUSPEND;
|
|
|
|
if (vshCommandOptBool(cmd, "timeout-postcopy"))
|
|
|
|
timeoutAction = VIRSH_MIGRATE_TIMEOUT_POSTCOPY;
|
|
|
|
if (timeout > 0) {
|
|
|
|
if (timeoutAction == VIRSH_MIGRATE_TIMEOUT_DEFAULT)
|
|
|
|
timeoutAction = VIRSH_MIGRATE_TIMEOUT_SUSPEND;
|
|
|
|
} else if (timeoutAction) {
|
|
|
|
vshError(ctl, "%s",
|
|
|
|
_("migrate: Unexpected --timeout-* option without --timeout"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-12-01 16:00:02 +00:00
|
|
|
if (vshCommandOptBool(cmd, "postcopy-after-precopy")) {
|
|
|
|
iterEvent = virConnectDomainEventRegisterAny(
|
|
|
|
priv->conn, dom,
|
|
|
|
VIR_DOMAIN_EVENT_ID_MIGRATION_ITERATION,
|
|
|
|
VIR_DOMAIN_EVENT_CALLBACK(virshMigrateIteration),
|
|
|
|
ctl, NULL);
|
|
|
|
if (iterEvent < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
cmdMigrate: move vshConnect before vshWatchJob
A possible fix to issue:
http://www.redhat.com/archives/libvir-list/2014-August/thread.html#00227
While doing migration on KVM host, found problem sometimes:
VM is already running on the target host and disappears from source
host, but 'virsh migrate' command line hangs, cannot exit normally.
If pressing "ENTER" key, it will exit.
The code hangs at tools/virsh-domain.c: cmdMigrate
->vshWatchJob->poll():
poll() is trying to select pipe_fd, which is used to receive message
from doMigrate thread. In debugging, found that doMigrate finishes
and at the end it does call safewrite() to write the retval ('0' or
'1') to pipe_fd, and the write is completed. But cmdMigrate poll()
cannot get the event. If pressing "ENTER" key, poll() can get the
event and select pipe_fd, then command line can exit.
In current code, authentication thread which is called by vshConnect
will use stdin, and at the same time, in cmdMigrate main process,
poll() is listening to stdin, that probably affect poll() to get
pipe_fd event. Better to move authentication before vshWatchJob. With
this change, above problem does not exist.
Signed-off-by: Chunyan Liu <cyliu@suse.com>
2014-08-08 08:44:36 +00:00
|
|
|
if (vshCommandOptBool(cmd, "p2p") || vshCommandOptBool(cmd, "direct")) {
|
|
|
|
data.dconn = NULL;
|
|
|
|
} else {
|
|
|
|
/* For traditional live migration, connect to the destination host. */
|
|
|
|
virConnectPtr dconn = NULL;
|
|
|
|
const char *desturi = NULL;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "desturi", &desturi) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
dconn = virshConnect(ctl, desturi, false);
|
cmdMigrate: move vshConnect before vshWatchJob
A possible fix to issue:
http://www.redhat.com/archives/libvir-list/2014-August/thread.html#00227
While doing migration on KVM host, found problem sometimes:
VM is already running on the target host and disappears from source
host, but 'virsh migrate' command line hangs, cannot exit normally.
If pressing "ENTER" key, it will exit.
The code hangs at tools/virsh-domain.c: cmdMigrate
->vshWatchJob->poll():
poll() is trying to select pipe_fd, which is used to receive message
from doMigrate thread. In debugging, found that doMigrate finishes
and at the end it does call safewrite() to write the retval ('0' or
'1') to pipe_fd, and the write is completed. But cmdMigrate poll()
cannot get the event. If pressing "ENTER" key, poll() can get the
event and select pipe_fd, then command line can exit.
In current code, authentication thread which is called by vshConnect
will use stdin, and at the same time, in cmdMigrate main process,
poll() is listening to stdin, that probably affect poll() to get
pipe_fd event. Better to move authentication before vshWatchJob. With
this change, above problem does not exist.
Signed-off-by: Chunyan Liu <cyliu@suse.com>
2014-08-08 08:44:36 +00:00
|
|
|
if (!dconn)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
data.dconn = dconn;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (virThreadCreate(&workerThread,
|
|
|
|
true,
|
|
|
|
doMigrate,
|
|
|
|
&data) < 0)
|
|
|
|
goto cleanup;
|
2020-02-05 14:16:16 +00:00
|
|
|
virshWatchJob(ctl, dom, verbose, eventLoop,
|
|
|
|
&data.ret, timeout,
|
|
|
|
virshMigrateTimeout,
|
|
|
|
&timeoutAction, _("Migration"));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
virThreadJoin(&workerThread);
|
|
|
|
|
2014-03-25 06:53:59 +00:00
|
|
|
cleanup:
|
cmdMigrate: move vshConnect before vshWatchJob
A possible fix to issue:
http://www.redhat.com/archives/libvir-list/2014-August/thread.html#00227
While doing migration on KVM host, found problem sometimes:
VM is already running on the target host and disappears from source
host, but 'virsh migrate' command line hangs, cannot exit normally.
If pressing "ENTER" key, it will exit.
The code hangs at tools/virsh-domain.c: cmdMigrate
->vshWatchJob->poll():
poll() is trying to select pipe_fd, which is used to receive message
from doMigrate thread. In debugging, found that doMigrate finishes
and at the end it does call safewrite() to write the retval ('0' or
'1') to pipe_fd, and the write is completed. But cmdMigrate poll()
cannot get the event. If pressing "ENTER" key, poll() can get the
event and select pipe_fd, then command line can exit.
In current code, authentication thread which is called by vshConnect
will use stdin, and at the same time, in cmdMigrate main process,
poll() is listening to stdin, that probably affect poll() to get
pipe_fd event. Better to move authentication before vshWatchJob. With
this change, above problem does not exist.
Signed-off-by: Chunyan Liu <cyliu@suse.com>
2014-08-08 08:44:36 +00:00
|
|
|
if (data.dconn)
|
|
|
|
virConnectClose(data.dconn);
|
2014-12-01 16:00:02 +00:00
|
|
|
if (iterEvent != -1)
|
|
|
|
virConnectDomainEventDeregisterAny(priv->conn, iterEvent);
|
2020-02-05 14:16:16 +00:00
|
|
|
return !data.ret;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "migrate-setmaxdowntime" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_migrate_setmaxdowntime[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("set maximum tolerable downtime")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Set maximum tolerable downtime of a domain which is being live-migrated to another host.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_migrate_setmaxdowntime[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "downtime",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("maximum tolerable downtime (in milliseconds) for migration")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdMigrateSetMaxDowntime(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2017-06-27 15:19:40 +00:00
|
|
|
unsigned long long downtime = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2017-06-27 15:19:40 +00:00
|
|
|
if (vshCommandOptULongLong(ctl, cmd, "downtime", &downtime) < 0)
|
2021-09-23 23:30:49 +00:00
|
|
|
return false;
|
|
|
|
|
2015-05-15 16:14:39 +00:00
|
|
|
if (downtime < 1) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, "%s", _("migrate: Invalid downtime"));
|
2021-09-23 23:30:49 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2021-09-23 23:30:49 +00:00
|
|
|
return virDomainMigrateSetMaxDowntime(dom, downtime, 0) == 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2017-08-17 22:17:21 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "migrate-getmaxdowntime" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_migrate_getmaxdowntime[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("get maximum tolerable downtime")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get maximum tolerable downtime of a domain which is being live-migrated to another host.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_migrate_getmaxdowntime[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2017-08-17 22:17:21 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdMigrateGetMaxDowntime(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2017-08-17 22:17:21 +00:00
|
|
|
unsigned long long downtime;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainMigrateGetMaxDowntime(dom, &downtime, 0) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2017-08-17 22:17:21 +00:00
|
|
|
|
|
|
|
vshPrint(ctl, "%llu\n", downtime);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2017-08-17 22:17:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-18 20:14:49 +00:00
|
|
|
/*
|
|
|
|
* "migrate-compcache" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_migrate_compcache[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("get/set compression cache size")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get/set size of the cache (in bytes) used for compressing "
|
|
|
|
"repeatedly transferred memory pages during live migration.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_migrate_compcache[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-02-18 20:14:49 +00:00
|
|
|
{.name = "size",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
|
|
|
.help = N_("requested size of the cache (in bytes) used for compression")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdMigrateCompCache(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2013-02-18 20:14:49 +00:00
|
|
|
unsigned long long size = 0;
|
|
|
|
const char *unit;
|
|
|
|
double value;
|
|
|
|
int rc;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2013-02-18 20:14:49 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
rc = vshCommandOptULongLong(ctl, cmd, "size", &size);
|
2021-09-24 15:17:50 +00:00
|
|
|
if (rc < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (rc != 0 &&
|
|
|
|
(virDomainMigrateSetCompressionCache(dom, size, 0) < 0))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-02-18 20:14:49 +00:00
|
|
|
|
|
|
|
if (virDomainMigrateGetCompressionCache(dom, &size, 0) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2013-02-18 20:14:49 +00:00
|
|
|
|
|
|
|
value = vshPrettyCapacity(size, &unit);
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrint(ctl, _("Compression cache: %1$.3lf %2$s"), value, unit);
|
2013-02-18 20:14:49 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2013-02-18 20:14:49 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "migrate-setspeed" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_migrate_setspeed[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Set the maximum migration bandwidth")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Set the maximum migration bandwidth (in MiB/s) for a domain "
|
|
|
|
"which is being migrated to another host.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_migrate_setspeed[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "bandwidth",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("migration bandwidth limit in MiB/s")
|
|
|
|
},
|
2019-01-31 09:45:35 +00:00
|
|
|
{.name = "postcopy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("set post-copy migration bandwidth")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdMigrateSetMaxSpeed(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned long bandwidth = 0;
|
2019-01-31 09:45:35 +00:00
|
|
|
unsigned int flags = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptULWrap(ctl, cmd, "bandwidth", &bandwidth) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2019-01-31 09:45:35 +00:00
|
|
|
if (vshCommandOptBool(cmd, "postcopy"))
|
|
|
|
flags |= VIR_DOMAIN_MIGRATE_MAX_SPEED_POSTCOPY;
|
|
|
|
|
|
|
|
if (virDomainMigrateSetMaxSpeed(dom, bandwidth, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "migrate-getspeed" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_migrate_getspeed[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Get the maximum migration bandwidth")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get the maximum migration bandwidth (in MiB/s) for a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_migrate_getspeed[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2019-01-31 09:45:35 +00:00
|
|
|
{.name = "postcopy",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("get post-copy migration bandwidth")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdMigrateGetMaxSpeed(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
unsigned long bandwidth;
|
2019-01-31 09:45:35 +00:00
|
|
|
unsigned int flags = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2019-01-31 09:45:35 +00:00
|
|
|
if (vshCommandOptBool(cmd, "postcopy"))
|
|
|
|
flags |= VIR_DOMAIN_MIGRATE_MAX_SPEED_POSTCOPY;
|
|
|
|
|
|
|
|
if (virDomainMigrateGetMaxSpeed(dom, &bandwidth, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
vshPrint(ctl, "%lu\n", bandwidth);
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2014-12-01 15:59:58 +00:00
|
|
|
/*
|
|
|
|
* "migrate-postcopy" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_migrate_postcopy[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Switch running migration from pre-copy to post-copy")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Switch running migration from pre-copy to post-copy. "
|
|
|
|
"The migration must have been started with --postcopy option.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_migrate_postcopy[] = {
|
2018-05-08 14:20:30 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2014-12-01 15:59:58 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdMigratePostCopy(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2014-12-01 15:59:58 +00:00
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainMigrateStartPostCopy(dom, 0) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2014-12-01 15:59:58 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2014-12-01 15:59:58 +00:00
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "domdisplay" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domdisplay[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("domain display connection URI")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
2014-07-24 12:23:12 +00:00
|
|
|
.data = N_("Output the IP address and port number "
|
|
|
|
"for the graphical display.")
|
2013-02-07 15:25:10 +00:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domdisplay[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "include-password",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("includes the password into the connection URI if available")
|
|
|
|
},
|
2014-07-24 12:23:12 +00:00
|
|
|
{.name = "type",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2014-11-21 10:10:21 +00:00
|
|
|
.help = N_("select particular graphical display "
|
2022-05-13 18:38:14 +00:00
|
|
|
"(e.g. \"vnc\", \"spice\", \"rdp\", \"dbus\")")
|
2014-07-24 12:23:12 +00:00
|
|
|
},
|
2016-10-09 10:34:22 +00:00
|
|
|
{.name = "all",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("show all possible graphical displays")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2022-05-13 18:38:14 +00:00
|
|
|
static char *
|
|
|
|
virshGetDBusDisplay(vshControl *ctl, xmlXPathContext *ctxt)
|
|
|
|
{
|
|
|
|
g_autofree char *addr = NULL;
|
|
|
|
const char *xpath = "string(/domain/devices/graphics[@type='dbus']/@address)";
|
|
|
|
|
|
|
|
addr = virXPathString(xpath, ctxt);
|
|
|
|
if (!addr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (STRPREFIX(addr, "unix:path=")) {
|
|
|
|
return g_strdup_printf("dbus+unix://%s", addr + 10);
|
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("'%1$s' D-Bus address is not handled"), addr);
|
2022-05-13 18:38:14 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2022-02-28 15:32:50 +00:00
|
|
|
|
|
|
|
static char *
|
|
|
|
virshGetOneDisplay(vshControl *ctl,
|
|
|
|
const char *scheme,
|
|
|
|
xmlXPathContext *ctxt)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2022-02-28 15:32:50 +00:00
|
|
|
const char *xpath_fmt = "string(/domain/devices/graphics[@type='%s']/%s)";
|
2020-07-02 23:40:16 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2022-02-28 16:45:53 +00:00
|
|
|
g_autofree char *xpathPort = NULL;
|
|
|
|
g_autofree char *xpathPortTLS = NULL;
|
|
|
|
g_autofree char *xpathListen = NULL;
|
|
|
|
g_autofree char *xpathType = NULL;
|
|
|
|
g_autofree char *xpathPasswd = NULL;
|
2022-02-28 16:04:35 +00:00
|
|
|
g_autofree char *listen_addr = NULL;
|
2022-02-28 15:32:50 +00:00
|
|
|
int port = 0;
|
|
|
|
int tls_port = 0;
|
2022-02-28 16:04:35 +00:00
|
|
|
g_autofree char *type_conn = NULL;
|
|
|
|
g_autofree char *sockpath = NULL;
|
|
|
|
g_autofree char *passwd = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-05-13 18:38:14 +00:00
|
|
|
if (STREQ(scheme, "dbus"))
|
|
|
|
return virshGetDBusDisplay(ctl, ctxt);
|
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
/* Attempt to get the port number for the current graphics scheme */
|
2022-02-28 16:45:53 +00:00
|
|
|
xpathPort = g_strdup_printf(xpath_fmt, scheme, "@port");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 16:45:53 +00:00
|
|
|
if (virXPathInt(xpathPort, ctxt, &port) < 0)
|
2022-02-28 15:32:50 +00:00
|
|
|
port = 0;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
/* Attempt to get the TLS port number */
|
2022-02-28 16:45:53 +00:00
|
|
|
xpathPortTLS = g_strdup_printf(xpath_fmt, scheme, "@tlsPort");
|
2014-07-24 12:23:12 +00:00
|
|
|
|
2022-02-28 16:45:53 +00:00
|
|
|
if (virXPathInt(xpathPortTLS, ctxt, &tls_port) < 0)
|
|
|
|
tls_port = 0;
|
2014-07-24 12:23:12 +00:00
|
|
|
|
2022-02-28 16:45:53 +00:00
|
|
|
/* Attempt to get the listening addr if set for the current graphics scheme */
|
|
|
|
xpathListen = g_strdup_printf(xpath_fmt, scheme, "@listen");
|
|
|
|
listen_addr = virXPathString(xpathListen, ctxt);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
/* Attempt to get the type of spice connection */
|
2022-02-28 16:45:53 +00:00
|
|
|
xpathType = g_strdup_printf(xpath_fmt, scheme, "listen/@type");
|
|
|
|
type_conn = virXPathString(xpathType, ctxt);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
if (STREQ_NULLABLE(type_conn, "socket")) {
|
2022-02-28 16:45:53 +00:00
|
|
|
g_autofree char *xpathSockpath = g_strdup_printf(xpath_fmt, scheme, "listen/@socket");
|
2013-09-25 15:48:01 +00:00
|
|
|
|
2022-02-28 16:45:53 +00:00
|
|
|
sockpath = virXPathString(xpathSockpath, ctxt);
|
2022-02-28 15:32:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!port && !tls_port && !sockpath)
|
2022-02-28 16:45:53 +00:00
|
|
|
return NULL;
|
2013-09-25 15:48:01 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
if (!listen_addr) {
|
2022-02-28 16:45:53 +00:00
|
|
|
g_autofree char *xpathListenAddress = NULL;
|
2022-02-28 15:32:50 +00:00
|
|
|
/* The subelement address - <listen address='xyz'/> -
|
|
|
|
* *should* have been automatically backfilled into its
|
|
|
|
* parent <graphics listen='xyz'> (which we just tried to
|
|
|
|
* retrieve into listen_addr above) but in some cases it
|
|
|
|
* isn't, so we also do an explicit check for the
|
|
|
|
* subelement (which, by the way, doesn't exist on libvirt
|
|
|
|
* < 0.9.4, so we really do need to check both places)
|
|
|
|
*/
|
2022-02-28 16:45:53 +00:00
|
|
|
xpathListenAddress = g_strdup_printf(xpath_fmt, scheme, "listen/@address");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 16:45:53 +00:00
|
|
|
listen_addr = virXPathString(xpathListenAddress, ctxt);
|
2022-02-28 15:32:50 +00:00
|
|
|
} else {
|
2022-02-28 16:04:35 +00:00
|
|
|
virSocketAddr addr;
|
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
/* If listen_addr is 0.0.0.0 or [::] we should try to parse URI and set
|
2022-02-28 16:04:35 +00:00
|
|
|
* listen_addr based on current URI. If that fails we'll print
|
|
|
|
* 'localhost' as the address as INADDR_ANY won't help the user. */
|
2022-02-28 15:32:50 +00:00
|
|
|
if (virSocketAddrParse(&addr, listen_addr, AF_UNSPEC) > 0 &&
|
|
|
|
virSocketAddrIsWildcard(&addr)) {
|
|
|
|
|
|
|
|
virConnectPtr conn = ((virshControl *)(ctl->privData))->conn;
|
2022-02-28 16:04:35 +00:00
|
|
|
g_autofree char *uriStr = virConnectGetURI(conn);
|
|
|
|
g_autoptr(virURI) uri = NULL;
|
2022-02-28 15:32:50 +00:00
|
|
|
|
2022-02-28 16:04:35 +00:00
|
|
|
g_clear_pointer(&listen_addr, g_free);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 16:04:35 +00:00
|
|
|
if (uriStr && (uri = virURIParse(uriStr)))
|
2022-02-28 15:32:50 +00:00
|
|
|
listen_addr = g_strdup(uri->server);
|
|
|
|
}
|
|
|
|
}
|
2017-07-28 21:49:35 +00:00
|
|
|
|
2022-02-28 16:45:53 +00:00
|
|
|
/* Attempt to get the password.
|
|
|
|
* We can query this info for all the graphics types since we'll
|
2022-02-28 15:32:50 +00:00
|
|
|
* get nothing for the unsupported ones (just rdp for now).
|
|
|
|
* Also the parameter '--include-password' was already taken
|
|
|
|
* care of when getting the XML */
|
2022-02-28 16:45:53 +00:00
|
|
|
xpathPasswd = g_strdup_printf(xpath_fmt, scheme, "@passwd");
|
|
|
|
passwd = virXPathString(xpathPasswd, ctxt);
|
2022-02-28 15:32:50 +00:00
|
|
|
|
|
|
|
/* Build up the full URI, starting with the scheme */
|
|
|
|
if (sockpath)
|
|
|
|
virBufferAsprintf(&buf, "%s+unix://", scheme);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&buf, "%s://", scheme);
|
|
|
|
|
|
|
|
/* There is no user, so just append password if there's any */
|
|
|
|
if (STREQ(scheme, "vnc") && passwd)
|
|
|
|
virBufferAsprintf(&buf, ":%s@", passwd);
|
|
|
|
|
|
|
|
/* Then host name or IP */
|
|
|
|
if (!listen_addr && !sockpath)
|
|
|
|
virBufferAddLit(&buf, "localhost");
|
|
|
|
else if (!sockpath && strchr(listen_addr, ':'))
|
|
|
|
virBufferAsprintf(&buf, "[%s]", listen_addr);
|
|
|
|
else if (sockpath)
|
|
|
|
virBufferAsprintf(&buf, "%s", sockpath);
|
|
|
|
else
|
|
|
|
virBufferAsprintf(&buf, "%s", listen_addr);
|
|
|
|
|
|
|
|
/* Add the port */
|
|
|
|
if (port) {
|
|
|
|
if (STREQ(scheme, "vnc")) {
|
|
|
|
/* VNC protocol handlers take their port number as
|
|
|
|
* 'port' - 5900 */
|
|
|
|
port -= 5900;
|
2017-07-28 21:49:35 +00:00
|
|
|
}
|
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
virBufferAsprintf(&buf, ":%d", port);
|
|
|
|
}
|
2017-07-28 21:49:35 +00:00
|
|
|
|
2022-02-28 16:59:40 +00:00
|
|
|
/* format the parameters part of the uri */
|
|
|
|
virBufferAddLit(&buf, "?");
|
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
/* TLS Port */
|
|
|
|
if (tls_port) {
|
2022-02-28 16:59:40 +00:00
|
|
|
virBufferAsprintf(&buf, "tls-port=%d&", tls_port);
|
2022-02-28 15:32:50 +00:00
|
|
|
}
|
2016-05-30 14:35:17 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
if (STREQ(scheme, "spice") && passwd) {
|
2022-02-28 16:59:40 +00:00
|
|
|
virBufferAsprintf(&buf, "password=%s&", passwd);
|
2022-02-28 15:32:50 +00:00
|
|
|
}
|
2016-05-30 14:35:17 +00:00
|
|
|
|
2022-02-28 16:59:40 +00:00
|
|
|
virBufferTrimLen(&buf, 1);
|
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
}
|
2012-11-21 15:31:51 +00:00
|
|
|
|
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
static bool
|
|
|
|
cmdDomDisplay(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
|
|
|
bool ret = false;
|
2022-05-13 18:38:14 +00:00
|
|
|
const char *scheme[] = { "vnc", "spice", "rdp", "dbus", NULL };
|
2022-02-28 15:32:50 +00:00
|
|
|
const char *type = NULL;
|
|
|
|
int iter = 0;
|
|
|
|
int flags = 0;
|
|
|
|
bool all = vshCommandOptBool(cmd, "all");
|
2012-11-21 15:31:51 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS("all", "type");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
2017-07-28 21:49:35 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
if (!virDomainIsActive(dom)) {
|
|
|
|
vshError(ctl, _("Domain is not running"));
|
2022-02-28 15:35:09 +00:00
|
|
|
return false;
|
2022-02-28 15:32:50 +00:00
|
|
|
}
|
2014-05-13 09:26:28 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
if (vshCommandOptBool(cmd, "include-password"))
|
|
|
|
flags |= VIR_DOMAIN_XML_SECURE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
|
2022-02-28 15:35:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
if (virshDomainGetXMLFromDom(ctl, dom, flags, &xml, &ctxt) < 0)
|
2022-02-28 15:35:09 +00:00
|
|
|
return false;
|
2022-02-28 15:32:50 +00:00
|
|
|
|
|
|
|
/* Attempt to grab our display info */
|
|
|
|
for (iter = 0; scheme[iter] != NULL; iter++) {
|
|
|
|
g_autofree char *display = NULL;
|
|
|
|
|
|
|
|
/* Particular scheme requested */
|
|
|
|
if (!all && type && STRNEQ(type, scheme[iter]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(display = virshGetOneDisplay(ctl, scheme[iter], ctxt)))
|
|
|
|
continue;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-02-28 15:32:50 +00:00
|
|
|
vshPrint(ctl, "%s", display);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* We got what we came for so return successfully */
|
|
|
|
ret = true;
|
2021-09-24 15:17:50 +00:00
|
|
|
if (!all)
|
2016-10-09 10:34:22 +00:00
|
|
|
break;
|
2021-09-24 15:17:50 +00:00
|
|
|
vshPrint(ctl, "\n");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2014-07-24 12:23:12 +00:00
|
|
|
if (!ret) {
|
|
|
|
if (type)
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("No graphical display with type '%1$s' found"), type);
|
2014-07-24 12:23:12 +00:00
|
|
|
else
|
|
|
|
vshError(ctl, _("No graphical display found"));
|
|
|
|
}
|
2014-07-24 12:18:23 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "vncdisplay" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_vncdisplay[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("vnc display")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Output the IP address and port number for the VNC display.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_vncdisplay[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdVNCDisplay(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 11:57:15 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2021-08-11 11:21:18 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
int port = 0;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *listen_addr = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Check if the domain is active and don't rely on -1 for this */
|
|
|
|
if (!virDomainIsActive(dom)) {
|
|
|
|
vshError(ctl, _("Domain is not running"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2017-04-11 15:33:53 +00:00
|
|
|
if (virshDomainGetXMLFromDom(ctl, dom, 0, &xml, &ctxt) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* Get the VNC port */
|
|
|
|
if (virXPathInt("string(/domain/devices/graphics[@type='vnc']/@port)",
|
|
|
|
ctxt, &port)) {
|
|
|
|
vshError(ctl, _("Failed to get VNC port. Is this domain using VNC?"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
listen_addr = virXPathString("string(/domain/devices/graphics"
|
|
|
|
"[@type='vnc']/@listen)", ctxt);
|
2015-02-15 08:49:09 +00:00
|
|
|
if (!listen_addr) {
|
|
|
|
/* The subelement address - <listen address='xyz'/> -
|
|
|
|
* *should* have been automatically backfilled into its
|
|
|
|
* parent <graphics listen='xyz'> (which we just tried to
|
|
|
|
* retrieve into listen_addr above) but in some cases it
|
|
|
|
* isn't, so we also do an explicit check for the
|
|
|
|
* subelement (which, by the way, doesn't exist on libvirt
|
|
|
|
* < 0.9.4, so we really do need to check both places)
|
|
|
|
*/
|
|
|
|
listen_addr = virXPathString("string(/domain/devices/graphics"
|
|
|
|
"[@type='vnc']/listen/@address)", ctxt);
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
if (listen_addr == NULL || STREQ(listen_addr, "0.0.0.0"))
|
|
|
|
vshPrint(ctl, ":%d\n", port-5900);
|
|
|
|
else
|
|
|
|
vshPrint(ctl, "%s:%d\n", listen_addr, port-5900);
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "ttyconsole" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_ttyconsole[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("tty console")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Output the device for the TTY console.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_ttyconsole[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdTTYConsole(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 11:57:15 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2021-08-11 11:21:18 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *tty = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2017-04-11 14:55:31 +00:00
|
|
|
if (virshDomainGetXML(ctl, cmd, 0, &xml, &ctxt) < 0)
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2017-04-11 14:55:31 +00:00
|
|
|
if (!(tty = virXPathString("string(/domain/devices/console/@tty)", ctxt)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2017-04-11 14:55:31 +00:00
|
|
|
vshPrint(ctl, "%s\n", tty);
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "domhostname" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domhostname[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("print the domain's hostname")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = ""
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domhostname[] = {
|
2019-11-20 13:24:33 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2019-12-27 20:36:25 +00:00
|
|
|
{.name = "source",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.flags = VSH_OFLAG_NONE,
|
|
|
|
.completer = virshDomainHostnameSourceCompleter,
|
|
|
|
.help = N_("address source: 'lease' or 'agent'")},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
2019-12-27 20:36:25 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainHostnameSource,
|
|
|
|
VIRSH_DOMAIN_HOSTNAME_SOURCE_LAST,
|
|
|
|
"agent",
|
|
|
|
"lease");
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
static bool
|
|
|
|
cmdDomHostname(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2020-03-05 08:29:02 +00:00
|
|
|
g_autofree char *hostname = NULL;
|
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2019-12-27 20:36:25 +00:00
|
|
|
const char *sourcestr = NULL;
|
|
|
|
int flags = 0; /* Use default value. Drivers can have its own default. */
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2019-12-27 20:36:25 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "source", &sourcestr) < 0)
|
2020-03-05 08:29:02 +00:00
|
|
|
return false;
|
2019-12-27 20:36:25 +00:00
|
|
|
|
|
|
|
if (sourcestr) {
|
|
|
|
int source = virshDomainHostnameSourceTypeFromString(sourcestr);
|
|
|
|
|
|
|
|
if (source < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unknown data source '%1$s'"), sourcestr);
|
2020-03-05 08:29:02 +00:00
|
|
|
return false;
|
2019-12-27 20:36:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch ((virshDomainHostnameSource) source) {
|
|
|
|
case VIRSH_DOMAIN_HOSTNAME_SOURCE_AGENT:
|
|
|
|
flags |= VIR_DOMAIN_GET_HOSTNAME_AGENT;
|
|
|
|
break;
|
|
|
|
case VIRSH_DOMAIN_HOSTNAME_SOURCE_LEASE:
|
|
|
|
flags |= VIR_DOMAIN_GET_HOSTNAME_LEASE;
|
|
|
|
break;
|
|
|
|
case VIRSH_DOMAIN_HOSTNAME_SOURCE_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hostname = virDomainGetHostname(dom, flags);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (hostname == NULL) {
|
|
|
|
vshError(ctl, "%s", _("failed to get hostname"));
|
2020-03-05 08:29:02 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vshPrint(ctl, "%s\n", hostname);
|
2020-03-05 08:29:02 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "detach-device" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_detach_device[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("detach device from an XML file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Detach device from an XML <file>")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_detach_device[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2016-01-09 13:36:29 +00:00
|
|
|
VIRSH_COMMON_OPT_FILE(N_("XML file")),
|
2016-01-09 13:36:25 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_PERSISTENT,
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDetachDevice(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-01-04 12:54:37 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *from = NULL;
|
2021-01-04 12:54:37 +00:00
|
|
|
g_autofree char *buffer = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
int ret;
|
2013-03-21 15:26:23 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool persistent = vshCommandOptBool(cmd, "persistent");
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(persistent, current);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config || persistent)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-03-21 15:26:23 +00:00
|
|
|
if (persistent &&
|
|
|
|
virDomainIsActive(dom) == 1)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2021-01-04 12:54:37 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
|
|
|
|
vshReportError(ctl);
|
2021-01-04 12:54:37 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2014-01-07 15:44:02 +00:00
|
|
|
if (flags != 0 || current)
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = virDomainDetachDeviceFlags(dom, buffer, flags);
|
2013-03-21 15:26:23 +00:00
|
|
|
else
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = virDomainDetachDevice(dom, buffer);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to detach device from %1$s"), from);
|
2021-01-04 12:54:37 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Device detached successfully\n"));
|
2021-01-04 12:54:37 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2018-05-21 14:25:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "detach-device-alias" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_detach_device_alias[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("detach device from an alias")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Detach device identified by the given alias from a domain")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_detach_device_alias[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
|
|
|
{.name = "alias",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-06-26 10:41:34 +00:00
|
|
|
.completer = virshDomainDeviceAliasCompleter,
|
2018-05-21 14:25:13 +00:00
|
|
|
.help = N_("device alias")
|
|
|
|
},
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDetachDeviceAlias(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2018-05-21 14:25:13 +00:00
|
|
|
const char *alias = NULL;
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "alias", &alias) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2018-05-21 14:25:13 +00:00
|
|
|
|
|
|
|
if (virDomainDetachDeviceAlias(dom, alias, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to detach device with alias %1$s"), alias);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2018-05-21 14:25:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vshPrintExtra(ctl, "%s", _("Device detach request sent successfully\n"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2018-05-21 14:25:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "update-device" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_update_device[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("update device from an XML file")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Update device from an XML <file>.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_update_device[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2016-01-09 13:36:29 +00:00
|
|
|
VIRSH_COMMON_OPT_FILE(N_("XML file")),
|
2016-01-09 13:36:25 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_PERSISTENT,
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "force",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("force device update")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdUpdateDevice(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *from = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *buffer = NULL;
|
2013-03-15 16:11:28 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool persistent = vshCommandOptBool(cmd, "persistent");
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(persistent, current);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config || persistent)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2012-07-25 15:37:18 +00:00
|
|
|
return false;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-15 16:11:28 +00:00
|
|
|
if (persistent &&
|
|
|
|
virDomainIsActive(dom) == 1)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 04:10:17 +00:00
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
|
|
|
|
vshReportError(ctl);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "force"))
|
|
|
|
flags |= VIR_DOMAIN_DEVICE_MODIFY_FORCE;
|
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (virDomainUpdateDeviceFlags(dom, buffer, flags) < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to update device from %1$s"), from);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Device updated successfully\n"));
|
2013-01-21 14:39:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "detach-interface" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_detach_interface[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("detach network interface")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Detach network interface.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_detach_interface[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "type",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("network interface type")
|
|
|
|
},
|
|
|
|
{.name = "mac",
|
|
|
|
.type = VSH_OT_STRING,
|
2017-11-06 14:48:01 +00:00
|
|
|
.completer = virshDomainInterfaceCompleter,
|
|
|
|
.completer_flags = VIRSH_DOMAIN_INTERFACE_COMPLETER_MAC,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("MAC address")
|
|
|
|
},
|
2016-01-09 13:36:25 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_PERSISTENT,
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2022-11-30 09:49:26 +00:00
|
|
|
{.name = "print-xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print XML document rather than detach the interface")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2016-05-04 14:26:26 +00:00
|
|
|
virshDomainDetachInterface(char *doc,
|
|
|
|
unsigned int flags,
|
|
|
|
virDomainPtr dom,
|
|
|
|
vshControl *ctl,
|
|
|
|
bool current,
|
|
|
|
const char *type,
|
2022-11-30 09:49:26 +00:00
|
|
|
const char *mac,
|
|
|
|
bool printxml)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2021-08-11 11:57:15 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2021-08-11 11:21:18 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *detach_xml = NULL;
|
2022-10-18 13:00:59 +00:00
|
|
|
g_autofree char *xpath = g_strdup_printf("/domain/devices/interface[@type='%s']", type);
|
|
|
|
g_autofree xmlNodePtr *nodes = NULL;
|
|
|
|
ssize_t nnodes;
|
|
|
|
xmlNodePtr matchNode = NULL;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-21 14:03:42 +00:00
|
|
|
if (!(xml = virXMLParseStringCtxt(doc, _("(domain_definition)"), &ctxt))) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, "%s", _("Failed to get interface information"));
|
2021-09-24 15:17:46 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-10-18 13:00:59 +00:00
|
|
|
if ((nnodes = virXPathNodeSet(xpath, ctxt, &nodes)) <= 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("No interface found whose type is %1$s"), type);
|
2021-09-24 15:17:46 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-10-18 13:00:59 +00:00
|
|
|
if (mac) {
|
|
|
|
for (i = 0; i < nnodes; i++) {
|
|
|
|
g_autofree char *tmp_mac = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-18 13:00:59 +00:00
|
|
|
ctxt->node = nodes[i];
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-18 13:00:59 +00:00
|
|
|
if ((tmp_mac = virXPathString("string(./mac/@address)", ctxt))) {
|
|
|
|
|
|
|
|
if (virMacAddrCompare(tmp_mac, mac) == 0) {
|
qemu: fix attach/detach of netdevs with matching mac addrs
This resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=862515
which describes inconsistencies in dealing with duplicate mac
addresses on network devices in a domain.
(at any rate, it resolves *almost* everything, and prints out an
informative error message for the one problem that isn't solved, but
has a workaround.)
A synopsis of the problems:
1) you can't do a persistent attach-interface of a device with a mac
address that matches an existing device.
2) you *can* do a live attach-interface of such a device.
3) you *can* directly edit a domain and put in two devices with
matching mac addresses.
4) When running virsh detach-device (live or config), only MAC address
is checked when matching the device to remove, so the first device
with the desired mac address will be removed. This isn't always the
one that's wanted.
5) when running virsh detach-interface (live or config), the only two
items that can be specified to match against are mac address and model
type (virtio, etc) - if multiple netdevs match both of those
attributes, it again just finds the first one added and assumes that
is the only match.
Since it is completely valid to have multiple network devices with the
same MAC address (although it can cause problems in many cases, there
*are* valid use cases), what is needed is:
1) remove the restriction that prohibits doing a persistent add of a
netdev with a duplicate mac address.
2) enhance the backend of virDomainDetachDeviceFlags to check for
something that *is* guaranteed unique (but still work with just mac
address, as long as it yields only a single results.
This patch does three things:
1) removes the check for duplicate mac address during a persistent
netdev attach.
2) unifies the searching for both live and config detach of netdevices
in the subordinate functions of qemuDomainModifyDeviceFlags() to use the
new function virDomainNetFindIdx (which matches mac address and PCI
address if available, checking for duplicates if only mac address was
specified). This function returns -2 if multiple matches are found,
allowing the callers to print out an appropriate message.
Steps 1 & 2 are enough to fully fix the problem when using virsh
attach-device and detach-device (which require an XML description of
the device rather than a bunch of commandline args)
3) modifies the virsh detach-interface command to check for multiple
matches of mac address and show an error message suggesting use of the
detach-device command in cases where there are multiple matching mac
addresses.
Later we should decide how we want to input a PCI address on the virsh
commandline, and enhance detach-interface to take a --address option,
eliminating the need to use detach-device
* src/conf/domain_conf.c
* src/conf/domain_conf.h
* src/libvirt_private.syms
* added new virDomainNetFindIdx function
* removed now unused virDomainNetIndexByMac and
virDomainNetRemoveByMac
* src/qemu/qemu_driver.c
* remove check for duplicate max from qemuDomainAttachDeviceConfig
* use virDomainNetFindIdx/virDomainNetRemove instead
of virDomainNetRemoveByMac in qemuDomainDetachDeviceConfig
* use virDomainNetFindIdx instead of virDomainIndexByMac
in qemuDomainUpdateDeviceConfig
* src/qemu/qemu_hotplug.c
* use virDomainNetFindIdx instead of a homespun loop in
qemuDomainDetachNetDevice.
* tools/virsh-domain.c: modified detach-interface command as described
above
2012-10-25 20:03:35 +00:00
|
|
|
if (matchNode) {
|
|
|
|
/* this is the 2nd match, so it's ambiguous */
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Domain has multiple interfaces matching MAC address %1$s. "
|
|
|
|
"You must use detach-device and specify the device pci address to remove it."),
|
qemu: fix attach/detach of netdevs with matching mac addrs
This resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=862515
which describes inconsistencies in dealing with duplicate mac
addresses on network devices in a domain.
(at any rate, it resolves *almost* everything, and prints out an
informative error message for the one problem that isn't solved, but
has a workaround.)
A synopsis of the problems:
1) you can't do a persistent attach-interface of a device with a mac
address that matches an existing device.
2) you *can* do a live attach-interface of such a device.
3) you *can* directly edit a domain and put in two devices with
matching mac addresses.
4) When running virsh detach-device (live or config), only MAC address
is checked when matching the device to remove, so the first device
with the desired mac address will be removed. This isn't always the
one that's wanted.
5) when running virsh detach-interface (live or config), the only two
items that can be specified to match against are mac address and model
type (virtio, etc) - if multiple netdevs match both of those
attributes, it again just finds the first one added and assumes that
is the only match.
Since it is completely valid to have multiple network devices with the
same MAC address (although it can cause problems in many cases, there
*are* valid use cases), what is needed is:
1) remove the restriction that prohibits doing a persistent add of a
netdev with a duplicate mac address.
2) enhance the backend of virDomainDetachDeviceFlags to check for
something that *is* guaranteed unique (but still work with just mac
address, as long as it yields only a single results.
This patch does three things:
1) removes the check for duplicate mac address during a persistent
netdev attach.
2) unifies the searching for both live and config detach of netdevices
in the subordinate functions of qemuDomainModifyDeviceFlags() to use the
new function virDomainNetFindIdx (which matches mac address and PCI
address if available, checking for duplicates if only mac address was
specified). This function returns -2 if multiple matches are found,
allowing the callers to print out an appropriate message.
Steps 1 & 2 are enough to fully fix the problem when using virsh
attach-device and detach-device (which require an XML description of
the device rather than a bunch of commandline args)
3) modifies the virsh detach-interface command to check for multiple
matches of mac address and show an error message suggesting use of the
detach-device command in cases where there are multiple matching mac
addresses.
Later we should decide how we want to input a PCI address on the virsh
commandline, and enhance detach-interface to take a --address option,
eliminating the need to use detach-device
* src/conf/domain_conf.c
* src/conf/domain_conf.h
* src/libvirt_private.syms
* added new virDomainNetFindIdx function
* removed now unused virDomainNetIndexByMac and
virDomainNetRemoveByMac
* src/qemu/qemu_driver.c
* remove check for duplicate max from qemuDomainAttachDeviceConfig
* use virDomainNetFindIdx/virDomainNetRemove instead
of virDomainNetRemoveByMac in qemuDomainDetachDeviceConfig
* use virDomainNetFindIdx instead of virDomainIndexByMac
in qemuDomainUpdateDeviceConfig
* src/qemu/qemu_hotplug.c
* use virDomainNetFindIdx instead of a homespun loop in
qemuDomainDetachNetDevice.
* tools/virsh-domain.c: modified detach-interface command as described
above
2012-10-25 20:03:35 +00:00
|
|
|
mac);
|
2021-09-24 15:17:46 +00:00
|
|
|
return false;
|
qemu: fix attach/detach of netdevs with matching mac addrs
This resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=862515
which describes inconsistencies in dealing with duplicate mac
addresses on network devices in a domain.
(at any rate, it resolves *almost* everything, and prints out an
informative error message for the one problem that isn't solved, but
has a workaround.)
A synopsis of the problems:
1) you can't do a persistent attach-interface of a device with a mac
address that matches an existing device.
2) you *can* do a live attach-interface of such a device.
3) you *can* directly edit a domain and put in two devices with
matching mac addresses.
4) When running virsh detach-device (live or config), only MAC address
is checked when matching the device to remove, so the first device
with the desired mac address will be removed. This isn't always the
one that's wanted.
5) when running virsh detach-interface (live or config), the only two
items that can be specified to match against are mac address and model
type (virtio, etc) - if multiple netdevs match both of those
attributes, it again just finds the first one added and assumes that
is the only match.
Since it is completely valid to have multiple network devices with the
same MAC address (although it can cause problems in many cases, there
*are* valid use cases), what is needed is:
1) remove the restriction that prohibits doing a persistent add of a
netdev with a duplicate mac address.
2) enhance the backend of virDomainDetachDeviceFlags to check for
something that *is* guaranteed unique (but still work with just mac
address, as long as it yields only a single results.
This patch does three things:
1) removes the check for duplicate mac address during a persistent
netdev attach.
2) unifies the searching for both live and config detach of netdevices
in the subordinate functions of qemuDomainModifyDeviceFlags() to use the
new function virDomainNetFindIdx (which matches mac address and PCI
address if available, checking for duplicates if only mac address was
specified). This function returns -2 if multiple matches are found,
allowing the callers to print out an appropriate message.
Steps 1 & 2 are enough to fully fix the problem when using virsh
attach-device and detach-device (which require an XML description of
the device rather than a bunch of commandline args)
3) modifies the virsh detach-interface command to check for multiple
matches of mac address and show an error message suggesting use of the
detach-device command in cases where there are multiple matching mac
addresses.
Later we should decide how we want to input a PCI address on the virsh
commandline, and enhance detach-interface to take a --address option,
eliminating the need to use detach-device
* src/conf/domain_conf.c
* src/conf/domain_conf.h
* src/libvirt_private.syms
* added new virDomainNetFindIdx function
* removed now unused virDomainNetIndexByMac and
virDomainNetRemoveByMac
* src/qemu/qemu_driver.c
* remove check for duplicate max from qemuDomainAttachDeviceConfig
* use virDomainNetFindIdx/virDomainNetRemove instead
of virDomainNetRemoveByMac in qemuDomainDetachDeviceConfig
* use virDomainNetFindIdx instead of virDomainIndexByMac
in qemuDomainUpdateDeviceConfig
* src/qemu/qemu_hotplug.c
* use virDomainNetFindIdx instead of a homespun loop in
qemuDomainDetachNetDevice.
* tools/virsh-domain.c: modified detach-interface command as described
above
2012-10-25 20:03:35 +00:00
|
|
|
}
|
2022-10-18 13:00:59 +00:00
|
|
|
|
|
|
|
matchNode = nodes[i];
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-10-18 13:00:59 +00:00
|
|
|
} else {
|
|
|
|
if (nnodes > 1) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Domain has %1$zd interfaces. Please specify which one to detach using --mac"),
|
2022-10-18 13:00:59 +00:00
|
|
|
nnodes);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
matchNode = nodes[0];
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2022-10-18 13:00:59 +00:00
|
|
|
|
qemu: fix attach/detach of netdevs with matching mac addrs
This resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=862515
which describes inconsistencies in dealing with duplicate mac
addresses on network devices in a domain.
(at any rate, it resolves *almost* everything, and prints out an
informative error message for the one problem that isn't solved, but
has a workaround.)
A synopsis of the problems:
1) you can't do a persistent attach-interface of a device with a mac
address that matches an existing device.
2) you *can* do a live attach-interface of such a device.
3) you *can* directly edit a domain and put in two devices with
matching mac addresses.
4) When running virsh detach-device (live or config), only MAC address
is checked when matching the device to remove, so the first device
with the desired mac address will be removed. This isn't always the
one that's wanted.
5) when running virsh detach-interface (live or config), the only two
items that can be specified to match against are mac address and model
type (virtio, etc) - if multiple netdevs match both of those
attributes, it again just finds the first one added and assumes that
is the only match.
Since it is completely valid to have multiple network devices with the
same MAC address (although it can cause problems in many cases, there
*are* valid use cases), what is needed is:
1) remove the restriction that prohibits doing a persistent add of a
netdev with a duplicate mac address.
2) enhance the backend of virDomainDetachDeviceFlags to check for
something that *is* guaranteed unique (but still work with just mac
address, as long as it yields only a single results.
This patch does three things:
1) removes the check for duplicate mac address during a persistent
netdev attach.
2) unifies the searching for both live and config detach of netdevices
in the subordinate functions of qemuDomainModifyDeviceFlags() to use the
new function virDomainNetFindIdx (which matches mac address and PCI
address if available, checking for duplicates if only mac address was
specified). This function returns -2 if multiple matches are found,
allowing the callers to print out an appropriate message.
Steps 1 & 2 are enough to fully fix the problem when using virsh
attach-device and detach-device (which require an XML description of
the device rather than a bunch of commandline args)
3) modifies the virsh detach-interface command to check for multiple
matches of mac address and show an error message suggesting use of the
detach-device command in cases where there are multiple matching mac
addresses.
Later we should decide how we want to input a PCI address on the virsh
commandline, and enhance detach-interface to take a --address option,
eliminating the need to use detach-device
* src/conf/domain_conf.c
* src/conf/domain_conf.h
* src/libvirt_private.syms
* added new virDomainNetFindIdx function
* removed now unused virDomainNetIndexByMac and
virDomainNetRemoveByMac
* src/qemu/qemu_driver.c
* remove check for duplicate max from qemuDomainAttachDeviceConfig
* use virDomainNetFindIdx/virDomainNetRemove instead
of virDomainNetRemoveByMac in qemuDomainDetachDeviceConfig
* use virDomainNetFindIdx instead of virDomainIndexByMac
in qemuDomainUpdateDeviceConfig
* src/qemu/qemu_hotplug.c
* use virDomainNetFindIdx instead of a homespun loop in
qemuDomainDetachNetDevice.
* tools/virsh-domain.c: modified detach-interface command as described
above
2012-10-25 20:03:35 +00:00
|
|
|
if (!matchNode) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("No interface with MAC address %1$s was found"), mac);
|
2021-09-24 15:17:46 +00:00
|
|
|
return false;
|
qemu: fix attach/detach of netdevs with matching mac addrs
This resolves:
https://bugzilla.redhat.com/show_bug.cgi?id=862515
which describes inconsistencies in dealing with duplicate mac
addresses on network devices in a domain.
(at any rate, it resolves *almost* everything, and prints out an
informative error message for the one problem that isn't solved, but
has a workaround.)
A synopsis of the problems:
1) you can't do a persistent attach-interface of a device with a mac
address that matches an existing device.
2) you *can* do a live attach-interface of such a device.
3) you *can* directly edit a domain and put in two devices with
matching mac addresses.
4) When running virsh detach-device (live or config), only MAC address
is checked when matching the device to remove, so the first device
with the desired mac address will be removed. This isn't always the
one that's wanted.
5) when running virsh detach-interface (live or config), the only two
items that can be specified to match against are mac address and model
type (virtio, etc) - if multiple netdevs match both of those
attributes, it again just finds the first one added and assumes that
is the only match.
Since it is completely valid to have multiple network devices with the
same MAC address (although it can cause problems in many cases, there
*are* valid use cases), what is needed is:
1) remove the restriction that prohibits doing a persistent add of a
netdev with a duplicate mac address.
2) enhance the backend of virDomainDetachDeviceFlags to check for
something that *is* guaranteed unique (but still work with just mac
address, as long as it yields only a single results.
This patch does three things:
1) removes the check for duplicate mac address during a persistent
netdev attach.
2) unifies the searching for both live and config detach of netdevices
in the subordinate functions of qemuDomainModifyDeviceFlags() to use the
new function virDomainNetFindIdx (which matches mac address and PCI
address if available, checking for duplicates if only mac address was
specified). This function returns -2 if multiple matches are found,
allowing the callers to print out an appropriate message.
Steps 1 & 2 are enough to fully fix the problem when using virsh
attach-device and detach-device (which require an XML description of
the device rather than a bunch of commandline args)
3) modifies the virsh detach-interface command to check for multiple
matches of mac address and show an error message suggesting use of the
detach-device command in cases where there are multiple matching mac
addresses.
Later we should decide how we want to input a PCI address on the virsh
commandline, and enhance detach-interface to take a --address option,
eliminating the need to use detach-device
* src/conf/domain_conf.c
* src/conf/domain_conf.h
* src/libvirt_private.syms
* added new virDomainNetFindIdx function
* removed now unused virDomainNetIndexByMac and
virDomainNetRemoveByMac
* src/qemu/qemu_driver.c
* remove check for duplicate max from qemuDomainAttachDeviceConfig
* use virDomainNetFindIdx/virDomainNetRemove instead
of virDomainNetRemoveByMac in qemuDomainDetachDeviceConfig
* use virDomainNetFindIdx instead of virDomainIndexByMac
in qemuDomainUpdateDeviceConfig
* src/qemu/qemu_hotplug.c
* use virDomainNetFindIdx instead of a homespun loop in
qemuDomainDetachNetDevice.
* tools/virsh-domain.c: modified detach-interface command as described
above
2012-10-25 20:03:35 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-09-04 15:27:27 +00:00
|
|
|
if (!(detach_xml = virXMLNodeToString(xml, matchNode))) {
|
|
|
|
vshSaveLibvirtError();
|
2021-09-24 15:17:46 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-11-30 09:49:26 +00:00
|
|
|
if (printxml) {
|
|
|
|
vshPrint(ctl, "%s", detach_xml);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-07 15:44:02 +00:00
|
|
|
if (flags != 0 || current)
|
2021-09-24 15:17:46 +00:00
|
|
|
return virDomainDetachDeviceFlags(dom, detach_xml, flags) == 0;
|
|
|
|
return virDomainDetachDevice(dom, detach_xml) == 0;
|
2016-05-04 14:26:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDetachInterface(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *doc_live = NULL;
|
|
|
|
g_autofree char *doc_config = NULL;
|
2016-05-04 14:26:26 +00:00
|
|
|
const char *mac = NULL, *type = NULL;
|
2016-05-04 14:26:27 +00:00
|
|
|
int flags = 0;
|
|
|
|
bool ret = false, affect_config, affect_live;
|
2016-05-04 14:26:26 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool persistent = vshCommandOptBool(cmd, "persistent");
|
2022-11-30 09:49:26 +00:00
|
|
|
bool printxml = vshCommandOptBool(cmd, "print-xml");
|
2016-05-04 14:26:26 +00:00
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(persistent, current);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "mac", &mac) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2016-05-04 14:26:27 +00:00
|
|
|
affect_config = (config || persistent);
|
2016-05-04 14:26:26 +00:00
|
|
|
|
2016-05-04 14:26:27 +00:00
|
|
|
if (affect_config) {
|
|
|
|
if (!(doc_config = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE)))
|
|
|
|
goto cleanup;
|
|
|
|
if (!(ret = virshDomainDetachInterface(doc_config,
|
|
|
|
flags | VIR_DOMAIN_AFFECT_CONFIG,
|
2022-11-30 09:49:26 +00:00
|
|
|
dom, ctl, current, type, mac,
|
|
|
|
printxml)))
|
2016-05-04 14:26:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2016-05-04 14:26:26 +00:00
|
|
|
|
2016-05-04 14:26:27 +00:00
|
|
|
affect_live = (live || (persistent && virDomainIsActive(dom) == 1));
|
|
|
|
|
|
|
|
if (affect_live || !affect_config) {
|
|
|
|
flags = 0;
|
|
|
|
|
|
|
|
if (affect_live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
|
|
|
if (!(doc_live = virDomainGetXMLDesc(dom, 0)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = virshDomainDetachInterface(doc_live, flags,
|
2022-11-30 09:49:26 +00:00
|
|
|
dom, ctl, current, type, mac, printxml);
|
2016-05-04 14:26:27 +00:00
|
|
|
}
|
2016-05-04 14:26:26 +00:00
|
|
|
|
2022-11-30 09:49:26 +00:00
|
|
|
if (printxml)
|
|
|
|
return ret;
|
|
|
|
|
2016-05-04 14:26:26 +00:00
|
|
|
cleanup:
|
|
|
|
if (!ret) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(ctl, "%s", _("Failed to detach interface"));
|
|
|
|
} else {
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Interface detached successfully\n"));
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2016-05-04 14:26:26 +00:00
|
|
|
return ret;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2018-02-14 14:17:51 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
virshDiskDropBackingStore(xmlNodePtr disk_node)
|
|
|
|
{
|
|
|
|
xmlNodePtr tmp;
|
|
|
|
|
|
|
|
for (tmp = disk_node->children; tmp; tmp = tmp->next) {
|
|
|
|
if (tmp->type != XML_ELEMENT_NODE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (virXMLNodeNameEqual(tmp, "backingStore")) {
|
|
|
|
xmlUnlinkNode(tmp);
|
|
|
|
xmlFreeNode(tmp);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
typedef enum {
|
2015-06-15 16:53:58 +00:00
|
|
|
VIRSH_FIND_DISK_NORMAL,
|
|
|
|
VIRSH_FIND_DISK_CHANGEABLE,
|
|
|
|
} virshFindDiskType;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* Helper function to find disk device in XML doc. Returns the disk
|
|
|
|
* node on success, or NULL on failure. Caller must free the result
|
|
|
|
* @path: Fully-qualified path or target of disk device.
|
2015-06-15 16:53:58 +00:00
|
|
|
* @type: Either VIRSH_FIND_DISK_NORMAL or VIRSH_FIND_DISK_CHANGEABLE.
|
2012-07-25 15:37:18 +00:00
|
|
|
*/
|
|
|
|
static xmlNodePtr
|
2015-06-15 16:53:58 +00:00
|
|
|
virshFindDisk(const char *doc,
|
|
|
|
const char *path,
|
|
|
|
int type)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2021-08-11 11:57:15 +00:00
|
|
|
g_autoptr(xmlDoc) xml = NULL;
|
2021-08-11 11:21:18 +00:00
|
|
|
g_autoptr(xmlXPathContext) ctxt = NULL;
|
2022-10-19 11:21:23 +00:00
|
|
|
g_autofree xmlNodePtr *nodes = NULL;
|
|
|
|
ssize_t nnodes;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
xml = virXMLParseStringCtxt(doc, _("(domain_definition)"), &ctxt);
|
|
|
|
if (!xml) {
|
|
|
|
vshError(NULL, "%s", _("Failed to get disk information"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-10-19 11:21:23 +00:00
|
|
|
if ((nnodes = virXPathNodeSet("/domain/devices/disk", ctxt, &nodes)) <= 0) {
|
2012-07-25 15:37:18 +00:00
|
|
|
vshError(NULL, "%s", _("Failed to get disk information"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* search disk using @path */
|
2022-10-19 11:21:23 +00:00
|
|
|
for (i = 0; i < nnodes; i++) {
|
2022-10-19 11:59:17 +00:00
|
|
|
xmlNodePtr sourceNode;
|
|
|
|
g_autofree char *sourceFile = NULL;
|
|
|
|
g_autofree char *sourceDev = NULL;
|
|
|
|
g_autofree char *sourceDir = NULL;
|
|
|
|
g_autofree char *sourceName = NULL;
|
|
|
|
g_autofree char *targetDev = NULL;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (type == VIRSH_FIND_DISK_CHANGEABLE) {
|
2022-10-19 11:31:00 +00:00
|
|
|
g_autofree char *device = virXMLPropString(nodes[i], "device");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* Check if the disk is CDROM or floppy disk */
|
2022-10-19 11:31:00 +00:00
|
|
|
if (device &&
|
|
|
|
STRNEQ(device, "cdrom") &&
|
|
|
|
STRNEQ(device, "floppy"))
|
2012-07-25 15:37:18 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-10-19 11:59:17 +00:00
|
|
|
if ((sourceNode = virXMLNodeGetSubelement(nodes[i], "source"))) {
|
|
|
|
sourceFile = virXMLPropString(sourceNode, "file");
|
|
|
|
sourceDev = virXMLPropString(sourceNode, "dev");
|
|
|
|
sourceDir = virXMLPropString(sourceNode, "dir");
|
|
|
|
sourceName = virXMLPropString(sourceNode, "name");
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-10-19 11:59:17 +00:00
|
|
|
ctxt->node = nodes[i];
|
|
|
|
targetDev = virXPathString("string(./target/@dev)", ctxt);
|
|
|
|
|
|
|
|
if (STREQ_NULLABLE(targetDev, path) ||
|
|
|
|
STREQ_NULLABLE(sourceFile, path) ||
|
|
|
|
STREQ_NULLABLE(sourceDev, path) ||
|
|
|
|
STREQ_NULLABLE(sourceDir, path) ||
|
|
|
|
STREQ_NULLABLE(sourceName, path)) {
|
|
|
|
xmlNodePtr ret = xmlCopyNode(nodes[i], 1);
|
|
|
|
/* drop backing store since they are not needed here */
|
|
|
|
virshDiskDropBackingStore(ret);
|
|
|
|
return ret;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(NULL, _("No disk found whose source path or target is %1$s"), path);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef enum {
|
2015-06-15 16:53:58 +00:00
|
|
|
VIRSH_UPDATE_DISK_XML_EJECT,
|
|
|
|
VIRSH_UPDATE_DISK_XML_INSERT,
|
|
|
|
VIRSH_UPDATE_DISK_XML_UPDATE,
|
|
|
|
} virshUpdateDiskXMLType;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
/* Helper function to prepare disk XML. Could be used for disk
|
|
|
|
* detaching, media changing(ejecting, inserting, updating)
|
|
|
|
* for changeable disk. Returns the processed XML as string on
|
|
|
|
* success, or NULL on failure. Caller must free the result.
|
|
|
|
*/
|
|
|
|
static char *
|
2015-06-15 16:53:58 +00:00
|
|
|
virshUpdateDiskXML(xmlNodePtr disk_node,
|
|
|
|
const char *new_source,
|
|
|
|
bool source_block,
|
|
|
|
const char *target,
|
|
|
|
virshUpdateDiskXMLType type)
|
2012-07-25 15:37:18 +00:00
|
|
|
{
|
2015-11-06 14:11:36 +00:00
|
|
|
xmlNodePtr tmp = NULL;
|
2015-03-12 15:41:21 +00:00
|
|
|
xmlNodePtr source = NULL;
|
2015-11-06 14:11:36 +00:00
|
|
|
xmlNodePtr target_node = NULL;
|
|
|
|
xmlNodePtr text_node = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *device_type = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
char *ret = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *startupPolicy = NULL;
|
|
|
|
g_autofree char *source_path = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (!disk_node)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
device_type = virXMLPropString(disk_node, "device");
|
|
|
|
|
2015-03-12 15:41:21 +00:00
|
|
|
if (!(STREQ_NULLABLE(device_type, "cdrom") ||
|
|
|
|
STREQ_NULLABLE(device_type, "floppy"))) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(NULL, _("The disk device '%1$s' is not removable"), target);
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2015-03-12 15:41:21 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-03-12 15:41:21 +00:00
|
|
|
/* find the current source subelement */
|
2015-11-06 14:11:36 +00:00
|
|
|
for (tmp = disk_node->children; tmp; tmp = tmp->next) {
|
|
|
|
/*
|
|
|
|
* Save the last text node before the <target/>. The
|
|
|
|
* reasoning behind this is that the target node will be
|
|
|
|
* present in this case and also has a proper indentation.
|
|
|
|
*/
|
|
|
|
if (!target_node && tmp->type == XML_TEXT_NODE)
|
|
|
|
text_node = tmp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need only element nodes from now on.
|
|
|
|
*/
|
|
|
|
if (tmp->type != XML_ELEMENT_NODE)
|
|
|
|
continue;
|
|
|
|
|
2019-12-17 15:43:24 +00:00
|
|
|
if (!source && virXMLNodeNameEqual(tmp, "source"))
|
2015-11-06 14:11:36 +00:00
|
|
|
source = tmp;
|
2019-12-17 15:43:24 +00:00
|
|
|
else if (!target_node && virXMLNodeNameEqual(tmp, "target"))
|
2015-11-06 14:11:36 +00:00
|
|
|
target_node = tmp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We've found all we needed.
|
|
|
|
*/
|
2018-02-14 14:17:51 +00:00
|
|
|
if (source && target_node)
|
2015-03-12 15:41:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (type == VIRSH_UPDATE_DISK_XML_EJECT) {
|
2015-03-12 15:41:21 +00:00
|
|
|
if (!source) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(NULL, _("The disk device '%1$s' doesn't have media"), target);
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2015-03-12 15:41:21 +00:00
|
|
|
/* forcibly switch to empty file cdrom */
|
|
|
|
source_block = false;
|
|
|
|
new_source = NULL;
|
|
|
|
} else if (!new_source) {
|
|
|
|
vshError(NULL, _("New disk media source was not specified"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2015-03-12 15:41:21 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-03-12 15:41:21 +00:00
|
|
|
if (source) {
|
2016-01-13 16:32:05 +00:00
|
|
|
if (!(source_path = virXMLPropString(source, "file")) &&
|
|
|
|
!(source_path = virXMLPropString(source, "dev")) &&
|
|
|
|
!(source_path = virXMLPropString(source, "dir")) &&
|
|
|
|
!(source_path = virXMLPropString(source, "pool")))
|
|
|
|
source_path = virXMLPropString(source, "name");
|
|
|
|
|
|
|
|
if (source_path && type == VIRSH_UPDATE_DISK_XML_INSERT) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(NULL, _("The disk device '%1$s' already has media"), target);
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2015-09-24 16:00:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
startupPolicy = virXMLPropString(source, "startupPolicy");
|
|
|
|
|
|
|
|
/* remove current source */
|
2015-03-12 15:41:21 +00:00
|
|
|
xmlUnlinkNode(source);
|
2022-01-28 17:42:45 +00:00
|
|
|
g_clear_pointer(&source, xmlFreeNode);
|
2015-03-12 15:41:21 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-03-12 15:41:21 +00:00
|
|
|
/* set the correct disk type */
|
|
|
|
if (source_block)
|
|
|
|
xmlSetProp(disk_node, BAD_CAST "type", BAD_CAST "block");
|
|
|
|
else
|
|
|
|
xmlSetProp(disk_node, BAD_CAST "type", BAD_CAST "file");
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-03-12 15:41:21 +00:00
|
|
|
if (new_source) {
|
|
|
|
/* create new source subelement */
|
2021-02-24 08:35:05 +00:00
|
|
|
source = virXMLNewNode(NULL, "source");
|
2015-03-12 15:41:21 +00:00
|
|
|
|
|
|
|
if (source_block)
|
|
|
|
xmlNewProp(source, BAD_CAST "dev", BAD_CAST new_source);
|
|
|
|
else
|
|
|
|
xmlNewProp(source, BAD_CAST "file", BAD_CAST new_source);
|
|
|
|
|
2015-09-24 16:00:06 +00:00
|
|
|
if (startupPolicy)
|
|
|
|
xmlNewProp(source, BAD_CAST "startupPolicy", BAD_CAST startupPolicy);
|
2015-11-06 14:11:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* So that the output XML looks nice in case anyone calls
|
|
|
|
* 'change-media' with '--print-xml', let's attach the source
|
|
|
|
* before target...
|
|
|
|
*/
|
|
|
|
xmlAddPrevSibling(target_node, source);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ... and duplicate the text node doing the indentation just
|
|
|
|
* so it's more easily readable. And don't make it fatal.
|
|
|
|
*/
|
|
|
|
if ((tmp = xmlCopyNode(text_node, 0))) {
|
|
|
|
if (!xmlAddPrevSibling(target_node, tmp))
|
|
|
|
xmlFreeNode(tmp);
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2013-09-04 15:27:27 +00:00
|
|
|
if (!(ret = virXMLNodeToString(NULL, disk_node))) {
|
|
|
|
vshSaveLibvirtError();
|
2021-08-12 07:59:20 +00:00
|
|
|
return NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "detach-disk" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_detach_disk[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("detach disk device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Detach disk device.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_detach_disk[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "target",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2019-03-05 03:17:37 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("target of disk device")
|
|
|
|
},
|
2016-01-09 13:36:25 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_PERSISTENT,
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CONFIG,
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_LIVE,
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_CURRENT,
|
2018-02-14 14:13:29 +00:00
|
|
|
{.name = "print-xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
2018-06-07 07:21:14 +00:00
|
|
|
.help = N_("print XML document rather than detach the disk")
|
2018-02-14 14:13:29 +00:00
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDetachDisk(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *disk_xml = NULL;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *target = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *doc = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
int ret;
|
2022-12-02 09:14:09 +00:00
|
|
|
g_autoptr(xmlNode) disk_node = NULL;
|
2013-03-21 15:29:10 +00:00
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool persistent = vshCommandOptBool(cmd, "persistent");
|
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(persistent, current);
|
|
|
|
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
|
|
|
|
|
|
|
if (config || persistent)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2013-01-21 14:39:18 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "target", &target) < 0)
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2014-01-07 16:58:47 +00:00
|
|
|
if (flags == VIR_DOMAIN_AFFECT_CONFIG)
|
|
|
|
doc = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
|
|
|
|
else
|
|
|
|
doc = virDomainGetXMLDesc(dom, 0);
|
|
|
|
|
|
|
|
if (!doc)
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-21 15:29:10 +00:00
|
|
|
if (persistent &&
|
|
|
|
virDomainIsActive(dom) == 1)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(disk_node = virshFindDisk(doc, target, VIRSH_FIND_DISK_NORMAL)))
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-03-12 10:51:51 +00:00
|
|
|
if (!(disk_xml = virXMLNodeToString(NULL, disk_node))) {
|
|
|
|
vshSaveLibvirtError();
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2015-03-12 10:51:51 +00:00
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2018-02-14 14:13:29 +00:00
|
|
|
if (vshCommandOptBool(cmd, "print-xml")) {
|
|
|
|
vshPrint(ctl, "%s", disk_xml);
|
2022-12-02 09:14:09 +00:00
|
|
|
return true;
|
2018-02-14 14:13:29 +00:00
|
|
|
}
|
|
|
|
|
2014-01-07 15:44:02 +00:00
|
|
|
if (flags != 0 || current)
|
2013-03-21 15:29:10 +00:00
|
|
|
ret = virDomainDetachDeviceFlags(dom, disk_xml, flags);
|
|
|
|
else
|
2012-07-25 15:37:18 +00:00
|
|
|
ret = virDomainDetachDevice(dom, disk_xml);
|
|
|
|
|
|
|
|
if (ret != 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to detach disk"));
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2016-08-24 14:14:23 +00:00
|
|
|
vshPrintExtra(ctl, "%s", _("Disk detached successfully\n"));
|
2022-12-02 09:14:09 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "edit" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_edit[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("edit XML configuration for a domain")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Edit the XML configuration for a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_edit[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2015-01-08 15:26:50 +00:00
|
|
|
{.name = "skip-validate",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("skip validation of the XML against the schema")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdEdit(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
|
|
|
g_autoptr(virshDomain) dom_edited = NULL;
|
2015-01-08 15:26:50 +00:00
|
|
|
unsigned int query_flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_INACTIVE;
|
|
|
|
unsigned int define_flags = VIR_DOMAIN_DEFINE_VALIDATE;
|
2021-03-11 07:16:13 +00:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
dom = virshCommandOptDomain(ctl, cmd, NULL);
|
2012-07-25 15:37:18 +00:00
|
|
|
if (dom == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-01-08 15:26:50 +00:00
|
|
|
if (vshCommandOptBool(cmd, "skip-validate"))
|
|
|
|
define_flags &= ~VIR_DOMAIN_DEFINE_VALIDATE;
|
|
|
|
|
|
|
|
#define EDIT_GET_XML virDomainGetXMLDesc(dom, query_flags)
|
2017-11-03 12:09:47 +00:00
|
|
|
#define EDIT_NOT_CHANGED \
|
|
|
|
do { \
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' XML configuration not changed.\n"), \
|
2017-11-03 12:09:47 +00:00
|
|
|
virDomainGetName(dom)); \
|
|
|
|
ret = true; \
|
|
|
|
goto edit_cleanup; \
|
2014-11-14 14:57:17 +00:00
|
|
|
} while (0)
|
2012-07-25 15:37:18 +00:00
|
|
|
#define EDIT_DEFINE \
|
2015-06-15 16:53:58 +00:00
|
|
|
(dom_edited = virshDomainDefine(priv->conn, doc_edited, define_flags))
|
2017-11-03 12:09:47 +00:00
|
|
|
#define EDIT_RELAX \
|
|
|
|
do { \
|
|
|
|
define_flags &= ~VIR_DOMAIN_DEFINE_VALIDATE; \
|
2015-02-19 13:16:39 +00:00
|
|
|
} while (0);
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
#include "virsh-edit.c"
|
2015-02-19 13:16:39 +00:00
|
|
|
#undef EDIT_RELAX
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Domain '%1$s' XML configuration edited.\n"),
|
2016-11-04 14:22:26 +00:00
|
|
|
virDomainGetName(dom_edited));
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-14 23:59:35 +00:00
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
/*
|
|
|
|
* "change-media" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_change_media[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Change media of CD or floppy drive")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Change media of CD or floppy drive.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_change_media[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "path",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-05-15 11:18:24 +00:00
|
|
|
.completer = virshDomainDiskTargetCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("Fully-qualified path or target of disk device")
|
|
|
|
},
|
|
|
|
{.name = "source",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("source of the media")
|
|
|
|
},
|
|
|
|
{.name = "eject",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("Eject the media")
|
|
|
|
},
|
|
|
|
{.name = "insert",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("Insert the media")
|
|
|
|
},
|
|
|
|
{.name = "update",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("Update the media")
|
|
|
|
},
|
2016-01-09 13:36:28 +00:00
|
|
|
VIRSH_COMMON_OPT_CURRENT(N_("can be either or both of --live and "
|
|
|
|
"--config, depends on implementation "
|
|
|
|
"hypervisor driver")),
|
2016-01-09 13:36:27 +00:00
|
|
|
VIRSH_COMMON_OPT_LIVE(N_("alter live configuration of running domain")),
|
2016-01-09 13:36:26 +00:00
|
|
|
VIRSH_COMMON_OPT_CONFIG(N_("alter persistent configuration, effect "
|
|
|
|
"observed on next boot")),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "force",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("force media changing")
|
|
|
|
},
|
2015-03-12 15:04:00 +00:00
|
|
|
{.name = "print-xml",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("print XML document rather than change media")
|
|
|
|
},
|
2015-03-12 15:41:21 +00:00
|
|
|
{.name = "block",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("source media is a block device")
|
|
|
|
},
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = NULL}
|
2012-07-25 15:37:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdChangeMedia(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *source = NULL;
|
|
|
|
const char *path = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *doc = NULL;
|
2022-12-02 09:14:09 +00:00
|
|
|
g_autoptr(xmlNode) disk_node = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *disk_xml = NULL;
|
2015-06-15 16:53:58 +00:00
|
|
|
virshUpdateDiskXMLType update_type;
|
2012-07-25 15:37:18 +00:00
|
|
|
const char *action = NULL;
|
2015-04-06 17:59:46 +00:00
|
|
|
const char *success_msg = NULL;
|
2013-03-21 14:35:13 +00:00
|
|
|
bool config = vshCommandOptBool(cmd, "config");
|
|
|
|
bool live = vshCommandOptBool(cmd, "live");
|
|
|
|
bool current = vshCommandOptBool(cmd, "current");
|
|
|
|
bool force = vshCommandOptBool(cmd, "force");
|
|
|
|
bool eject = vshCommandOptBool(cmd, "eject");
|
|
|
|
bool insert = vshCommandOptBool(cmd, "insert");
|
|
|
|
bool update = vshCommandOptBool(cmd, "update");
|
2015-03-12 15:41:21 +00:00
|
|
|
bool block = vshCommandOptBool(cmd, "block");
|
2013-03-21 14:35:13 +00:00
|
|
|
unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-21 14:35:13 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(eject, insert);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(eject, update);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(insert, update);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-03-12 15:41:21 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(eject, block);
|
|
|
|
|
2015-06-09 11:27:42 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "source", &source) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Docs state that update without source is eject */
|
|
|
|
if (update && !source) {
|
|
|
|
update = false;
|
|
|
|
eject = true;
|
|
|
|
}
|
|
|
|
|
2012-07-25 15:37:18 +00:00
|
|
|
if (eject) {
|
2015-06-15 16:53:58 +00:00
|
|
|
update_type = VIRSH_UPDATE_DISK_XML_EJECT;
|
2012-07-25 15:37:18 +00:00
|
|
|
action = "eject";
|
2015-04-06 17:59:46 +00:00
|
|
|
success_msg = _("Successfully ejected media.");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (insert) {
|
2015-06-15 16:53:58 +00:00
|
|
|
update_type = VIRSH_UPDATE_DISK_XML_INSERT;
|
2012-07-25 15:37:18 +00:00
|
|
|
action = "insert";
|
2015-04-06 17:59:46 +00:00
|
|
|
success_msg = _("Successfully inserted media.");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (update || (!eject && !insert)) {
|
2015-06-15 16:53:58 +00:00
|
|
|
update_type = VIRSH_UPDATE_DISK_XML_UPDATE;
|
2012-07-25 15:37:18 +00:00
|
|
|
action = "update";
|
2015-04-06 17:59:46 +00:00
|
|
|
success_msg = _("Successfully updated media.");
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
|
|
|
|
VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-03-07 12:38:19 +00:00
|
|
|
if (config)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_CONFIG;
|
|
|
|
if (live)
|
|
|
|
flags |= VIR_DOMAIN_AFFECT_LIVE;
|
2012-07-25 15:37:18 +00:00
|
|
|
if (force)
|
|
|
|
flags |= VIR_DOMAIN_DEVICE_MODIFY_FORCE;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2015-03-12 15:41:21 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "path", &path) < 0)
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
|
|
|
if (flags & VIR_DOMAIN_AFFECT_CONFIG)
|
|
|
|
doc = virDomainGetXMLDesc(dom, VIR_DOMAIN_XML_INACTIVE);
|
|
|
|
else
|
|
|
|
doc = virDomainGetXMLDesc(dom, 0);
|
|
|
|
if (!doc)
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(disk_node = virshFindDisk(doc, path, VIRSH_FIND_DISK_CHANGEABLE)))
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(disk_xml = virshUpdateDiskXML(disk_node, source, block, path,
|
|
|
|
update_type)))
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2015-03-12 15:04:00 +00:00
|
|
|
if (vshCommandOptBool(cmd, "print-xml")) {
|
|
|
|
vshPrint(ctl, "%s", disk_xml);
|
2022-12-02 09:14:09 +00:00
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
|
|
|
|
2022-12-02 09:14:09 +00:00
|
|
|
if (virDomainUpdateDeviceFlags(dom, disk_xml, flags) != 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Failed to complete action %1$s on media"), action);
|
2022-12-02 09:14:09 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-07-25 15:37:18 +00:00
|
|
|
|
2022-12-02 09:14:09 +00:00
|
|
|
vshPrint(ctl, "%s", success_msg);
|
|
|
|
return true;
|
2012-07-25 15:37:18 +00:00
|
|
|
}
|
2012-07-23 07:19:04 +00:00
|
|
|
|
2012-11-20 17:23:20 +00:00
|
|
|
static const vshCmdInfo info_domfstrim[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Invoke fstrim on domain's mounted filesystems.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Invoke fstrim on domain's mounted filesystems.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-11-20 17:23:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domfstrim[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2013-01-14 11:26:54 +00:00
|
|
|
{.name = "minimum",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("Just a hint to ignore contiguous "
|
|
|
|
"free ranges smaller than this (Bytes)")
|
|
|
|
},
|
|
|
|
{.name = "mountpoint",
|
2014-12-11 02:46:15 +00:00
|
|
|
.type = VSH_OT_STRING,
|
2021-04-22 10:38:18 +00:00
|
|
|
.completer = virshDomainFSMountpointsCompleter,
|
2013-01-14 11:26:54 +00:00
|
|
|
.help = N_("which mount point to trim")
|
|
|
|
},
|
2013-08-26 12:36:52 +00:00
|
|
|
{.name = NULL}
|
2012-11-20 17:23:20 +00:00
|
|
|
};
|
|
|
|
static bool
|
|
|
|
cmdDomFSTrim(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2012-11-20 17:23:20 +00:00
|
|
|
unsigned long long minimum = 0;
|
|
|
|
const char *mountPoint = NULL;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-11-20 17:23:20 +00:00
|
|
|
|
2015-06-02 09:17:29 +00:00
|
|
|
if (vshCommandOptULongLong(ctl, cmd, "minimum", &minimum) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-11-20 17:23:20 +00:00
|
|
|
|
2013-01-21 14:39:18 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "mountpoint", &mountPoint) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-11-20 17:23:20 +00:00
|
|
|
|
|
|
|
if (virDomainFSTrim(dom, mountPoint, minimum, flags) < 0) {
|
|
|
|
vshError(ctl, _("Unable to invoke fstrim"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2012-11-20 17:23:20 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2012-11-20 17:23:20 +00:00
|
|
|
}
|
|
|
|
|
2014-05-02 00:06:13 +00:00
|
|
|
static const vshCmdInfo info_domfsfreeze[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Freeze domain's mounted filesystems.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Freeze domain's mounted filesystems.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domfsfreeze[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2014-05-02 00:06:13 +00:00
|
|
|
{.name = "mountpoint",
|
|
|
|
.type = VSH_OT_ARGV,
|
2021-04-22 10:38:18 +00:00
|
|
|
.completer = virshDomainFSMountpointsCompleter,
|
2014-05-02 00:06:13 +00:00
|
|
|
.help = N_("mountpoint path to be frozen")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
static bool
|
|
|
|
cmdDomFSFreeze(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2014-05-02 00:06:13 +00:00
|
|
|
const vshCmdOpt *opt = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree const char **mountpoints = NULL;
|
2014-05-02 00:06:13 +00:00
|
|
|
size_t nmountpoints = 0;
|
2021-09-24 15:17:49 +00:00
|
|
|
int count = 0;
|
2014-05-02 00:06:13 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2014-05-02 00:06:13 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
|
2021-03-19 23:37:03 +00:00
|
|
|
VIR_EXPAND_N(mountpoints, nmountpoints, 1);
|
2014-05-02 00:06:13 +00:00
|
|
|
mountpoints[nmountpoints-1] = opt->data;
|
|
|
|
}
|
|
|
|
|
2021-09-24 15:17:49 +00:00
|
|
|
if ((count = virDomainFSFreeze(dom, mountpoints, nmountpoints, 0)) < 0) {
|
2014-05-02 00:06:13 +00:00
|
|
|
vshError(ctl, _("Unable to freeze filesystems"));
|
2021-09-24 15:17:49 +00:00
|
|
|
return false;
|
2014-05-02 00:06:13 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Froze %1$d filesystem(s)\n"), count);
|
2021-09-24 15:17:49 +00:00
|
|
|
return true;
|
2014-05-02 00:06:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const vshCmdInfo info_domfsthaw[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Thaw domain's mounted filesystems.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Thaw domain's mounted filesystems.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domfsthaw[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2014-05-02 00:06:13 +00:00
|
|
|
{.name = "mountpoint",
|
|
|
|
.type = VSH_OT_ARGV,
|
2021-04-22 10:38:18 +00:00
|
|
|
.completer = virshDomainFSMountpointsCompleter,
|
2014-05-02 00:06:13 +00:00
|
|
|
.help = N_("mountpoint path to be thawed")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
static bool
|
|
|
|
cmdDomFSThaw(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2014-05-02 00:06:13 +00:00
|
|
|
const vshCmdOpt *opt = NULL;
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree const char **mountpoints = NULL;
|
2014-05-02 00:06:13 +00:00
|
|
|
size_t nmountpoints = 0;
|
2021-09-24 15:17:49 +00:00
|
|
|
int count = 0;
|
2014-05-02 00:06:13 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2014-05-02 00:06:13 +00:00
|
|
|
return false;
|
|
|
|
|
2015-06-02 09:17:28 +00:00
|
|
|
while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
|
2021-03-19 23:37:03 +00:00
|
|
|
VIR_EXPAND_N(mountpoints, nmountpoints, 1);
|
2014-05-02 00:06:13 +00:00
|
|
|
mountpoints[nmountpoints-1] = opt->data;
|
|
|
|
}
|
|
|
|
|
2021-09-24 15:17:49 +00:00
|
|
|
if ((count = virDomainFSThaw(dom, mountpoints, nmountpoints, 0)) < 0) {
|
2014-05-02 00:06:13 +00:00
|
|
|
vshError(ctl, _("Unable to thaw filesystems"));
|
2021-09-24 15:17:49 +00:00
|
|
|
return false;
|
2014-05-02 00:06:13 +00:00
|
|
|
}
|
|
|
|
|
2023-03-09 14:54:42 +00:00
|
|
|
vshPrintExtra(ctl, _("Thawed %1$d filesystem(s)\n"), count);
|
2021-09-24 15:17:49 +00:00
|
|
|
return true;
|
2014-05-02 00:06:13 +00:00
|
|
|
}
|
|
|
|
|
2014-11-22 01:27:52 +00:00
|
|
|
static const vshCmdInfo info_domfsinfo[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Get information of domain's mounted filesystems.")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Get information of domain's mounted filesystems.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domfsinfo[] = {
|
2017-10-31 08:24:21 +00:00
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
2014-11-22 01:27:52 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdDomFSInfo(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2019-02-12 06:48:59 +00:00
|
|
|
int rc = -1;
|
2014-11-22 01:27:52 +00:00
|
|
|
size_t i, j;
|
2019-02-12 06:51:19 +00:00
|
|
|
virDomainFSInfoPtr *info = NULL;
|
2021-08-11 13:12:02 +00:00
|
|
|
g_autoptr(vshTable) table = NULL;
|
2019-02-12 06:47:10 +00:00
|
|
|
size_t ninfos = 0;
|
2019-02-12 06:53:20 +00:00
|
|
|
bool ret = false;
|
2014-11-22 01:27:52 +00:00
|
|
|
|
2015-06-15 16:53:58 +00:00
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
2014-11-22 01:27:52 +00:00
|
|
|
return false;
|
|
|
|
|
2019-02-12 06:48:59 +00:00
|
|
|
rc = virDomainGetFSInfo(dom, &info, 0);
|
|
|
|
if (rc < 0) {
|
2014-11-22 01:27:52 +00:00
|
|
|
vshError(ctl, _("Unable to get filesystem information"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2019-02-12 06:48:59 +00:00
|
|
|
ninfos = rc;
|
2019-02-12 06:47:10 +00:00
|
|
|
|
|
|
|
if (ninfos == 0) {
|
2019-02-12 06:53:20 +00:00
|
|
|
ret = true;
|
2019-02-12 06:58:49 +00:00
|
|
|
vshPrintExtra(ctl, _("No filesystems are mounted in the domain"));
|
2014-11-22 01:27:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info) {
|
2018-09-21 14:17:21 +00:00
|
|
|
table = vshTableNew(_("Mountpoint"), _("Name"), _("Type"), _("Target"), NULL);
|
|
|
|
if (!table)
|
|
|
|
goto cleanup;
|
|
|
|
|
2019-02-12 06:47:10 +00:00
|
|
|
for (i = 0; i < ninfos; i++) {
|
2020-07-02 23:40:16 +00:00
|
|
|
g_auto(virBuffer) targetsBuff = VIR_BUFFER_INITIALIZER;
|
2019-10-15 13:16:31 +00:00
|
|
|
g_autofree char *targets = NULL;
|
2018-09-21 14:17:21 +00:00
|
|
|
|
2019-02-12 08:02:32 +00:00
|
|
|
for (j = 0; j < info[i]->ndevAlias; j++)
|
|
|
|
virBufferAsprintf(&targetsBuff, "%s,", info[i]->devAlias[j]);
|
2020-02-02 19:26:38 +00:00
|
|
|
virBufferTrim(&targetsBuff, ",");
|
2014-11-22 01:27:52 +00:00
|
|
|
|
2018-09-21 14:17:21 +00:00
|
|
|
targets = virBufferContentAndReset(&targetsBuff);
|
|
|
|
|
|
|
|
if (vshTableRowAppend(table,
|
|
|
|
info[i]->mountpoint,
|
|
|
|
info[i]->name,
|
|
|
|
info[i]->fstype,
|
2022-02-28 14:02:41 +00:00
|
|
|
NULLSTR_EMPTY(targets),
|
2018-09-21 14:17:21 +00:00
|
|
|
NULL) < 0)
|
|
|
|
goto cleanup;
|
2014-11-22 01:27:52 +00:00
|
|
|
}
|
2018-09-21 14:17:21 +00:00
|
|
|
|
|
|
|
vshTablePrintToStdout(table, ctl);
|
2014-11-22 01:27:52 +00:00
|
|
|
}
|
|
|
|
|
2019-02-12 06:53:20 +00:00
|
|
|
ret = true;
|
|
|
|
|
2014-11-22 01:27:52 +00:00
|
|
|
cleanup:
|
2018-09-21 14:17:21 +00:00
|
|
|
if (info) {
|
2019-02-12 06:47:10 +00:00
|
|
|
for (i = 0; i < ninfos; i++)
|
2018-09-21 14:17:21 +00:00
|
|
|
virDomainFSInfoFree(info[i]);
|
|
|
|
VIR_FREE(info);
|
|
|
|
}
|
2019-02-12 06:53:20 +00:00
|
|
|
return ret;
|
2014-11-22 01:27:52 +00:00
|
|
|
}
|
|
|
|
|
Add API to change qemu agent response timeout
Some layered products such as oVirt have requested a way to avoid being
blocked by guest agent commands when querying a loaded vm. For example,
many guest agent commands are polled periodically to monitor changes,
and rather than blocking the calling process, they'd prefer to simply
time out when an agent query is taking too long.
This patch adds a way for the user to specify a custom agent timeout
that is applied to all agent commands.
One special case to note here is the 'guest-sync' command. 'guest-sync'
is issued internally prior to calling any other command. (For example,
when libvirt wants to call 'guest-get-fsinfo', we first call
'guest-sync' and then call 'guest-get-fsinfo').
Previously, the 'guest-sync' command used a 5-second timeout
(VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT), whereas the actual command that
followed always blocked indefinitely
(VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK). As part of this patch, if a
custom timeout is specified that is shorter than
5 seconds, this new timeout is also used for 'guest-sync'. If there is
no custom timeout or if the custom timeout is longer than 5 seconds, we
will continue to use the 5-second timeout.
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2019-11-13 22:06:09 +00:00
|
|
|
/*
|
|
|
|
* "guest-agent-timeout" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_guest_agent_timeout[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Set the guest agent timeout")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Set the number of seconds to wait for a response from the guest agent.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_guest_agent_timeout[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
|
|
|
.help = N_("timeout seconds.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdGuestAgentTimeout(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2020-08-21 12:34:51 +00:00
|
|
|
int timeout = VIR_DOMAIN_AGENT_RESPONSE_TIMEOUT_BLOCK;
|
Add API to change qemu agent response timeout
Some layered products such as oVirt have requested a way to avoid being
blocked by guest agent commands when querying a loaded vm. For example,
many guest agent commands are polled periodically to monitor changes,
and rather than blocking the calling process, they'd prefer to simply
time out when an agent query is taking too long.
This patch adds a way for the user to specify a custom agent timeout
that is applied to all agent commands.
One special case to note here is the 'guest-sync' command. 'guest-sync'
is issued internally prior to calling any other command. (For example,
when libvirt wants to call 'guest-get-fsinfo', we first call
'guest-sync' and then call 'guest-get-fsinfo').
Previously, the 'guest-sync' command used a 5-second timeout
(VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT), whereas the actual command that
followed always blocked indefinitely
(VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK). As part of this patch, if a
custom timeout is specified that is shorter than
5 seconds, this new timeout is also used for 'guest-sync'. If there is
no custom timeout or if the custom timeout is longer than 5 seconds, we
will continue to use the 5-second timeout.
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2019-11-13 22:06:09 +00:00
|
|
|
const unsigned int flags = 0;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptInt(ctl, cmd, "timeout", &timeout) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
Add API to change qemu agent response timeout
Some layered products such as oVirt have requested a way to avoid being
blocked by guest agent commands when querying a loaded vm. For example,
many guest agent commands are polled periodically to monitor changes,
and rather than blocking the calling process, they'd prefer to simply
time out when an agent query is taking too long.
This patch adds a way for the user to specify a custom agent timeout
that is applied to all agent commands.
One special case to note here is the 'guest-sync' command. 'guest-sync'
is issued internally prior to calling any other command. (For example,
when libvirt wants to call 'guest-get-fsinfo', we first call
'guest-sync' and then call 'guest-get-fsinfo').
Previously, the 'guest-sync' command used a 5-second timeout
(VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT), whereas the actual command that
followed always blocked indefinitely
(VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK). As part of this patch, if a
custom timeout is specified that is shorter than
5 seconds, this new timeout is also used for 'guest-sync'. If there is
no custom timeout or if the custom timeout is longer than 5 seconds, we
will continue to use the 5-second timeout.
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2019-11-13 22:06:09 +00:00
|
|
|
|
|
|
|
if (virDomainAgentSetResponseTimeout(dom, timeout, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
Add API to change qemu agent response timeout
Some layered products such as oVirt have requested a way to avoid being
blocked by guest agent commands when querying a loaded vm. For example,
many guest agent commands are polled periodically to monitor changes,
and rather than blocking the calling process, they'd prefer to simply
time out when an agent query is taking too long.
This patch adds a way for the user to specify a custom agent timeout
that is applied to all agent commands.
One special case to note here is the 'guest-sync' command. 'guest-sync'
is issued internally prior to calling any other command. (For example,
when libvirt wants to call 'guest-get-fsinfo', we first call
'guest-sync' and then call 'guest-get-fsinfo').
Previously, the 'guest-sync' command used a 5-second timeout
(VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT), whereas the actual command that
followed always blocked indefinitely
(VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK). As part of this patch, if a
custom timeout is specified that is shorter than
5 seconds, this new timeout is also used for 'guest-sync'. If there is
no custom timeout or if the custom timeout is longer than 5 seconds, we
will continue to use the 5-second timeout.
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2019-11-13 22:06:09 +00:00
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
Add API to change qemu agent response timeout
Some layered products such as oVirt have requested a way to avoid being
blocked by guest agent commands when querying a loaded vm. For example,
many guest agent commands are polled periodically to monitor changes,
and rather than blocking the calling process, they'd prefer to simply
time out when an agent query is taking too long.
This patch adds a way for the user to specify a custom agent timeout
that is applied to all agent commands.
One special case to note here is the 'guest-sync' command. 'guest-sync'
is issued internally prior to calling any other command. (For example,
when libvirt wants to call 'guest-get-fsinfo', we first call
'guest-sync' and then call 'guest-get-fsinfo').
Previously, the 'guest-sync' command used a 5-second timeout
(VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT), whereas the actual command that
followed always blocked indefinitely
(VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK). As part of this patch, if a
custom timeout is specified that is shorter than
5 seconds, this new timeout is also used for 'guest-sync'. If there is
no custom timeout or if the custom timeout is longer than 5 seconds, we
will continue to use the 5-second timeout.
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2019-11-13 22:06:09 +00:00
|
|
|
}
|
|
|
|
|
2019-08-27 20:35:55 +00:00
|
|
|
/*
|
|
|
|
* "guestinfo" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_guestinfo[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("query information about the guest (via agent)")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Use the guest agent to query various information from guest's "
|
|
|
|
"point of view")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_guestinfo[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
|
|
|
{.name = "user",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("report active users"),
|
|
|
|
},
|
|
|
|
{.name = "os",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("report operating system information"),
|
|
|
|
},
|
|
|
|
{.name = "timezone",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("report timezone information"),
|
|
|
|
},
|
|
|
|
{.name = "hostname",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("report hostname"),
|
|
|
|
},
|
|
|
|
{.name = "filesystem",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("report filesystem information"),
|
|
|
|
},
|
2020-12-02 12:08:14 +00:00
|
|
|
{.name = "disk",
|
2020-11-20 18:09:48 +00:00
|
|
|
.type = VSH_OT_BOOL,
|
2020-12-02 12:08:14 +00:00
|
|
|
.help = N_("report disk information"),
|
2020-11-20 18:09:48 +00:00
|
|
|
},
|
2021-10-15 10:07:48 +00:00
|
|
|
{.name = "interface",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("report interface information"),
|
|
|
|
},
|
2019-08-27 20:35:55 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdGuestInfo(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2019-08-27 20:35:55 +00:00
|
|
|
bool ret = false;
|
|
|
|
virTypedParameterPtr params = NULL;
|
|
|
|
int nparams = 0;
|
|
|
|
size_t i;
|
|
|
|
unsigned int types = 0;
|
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "user"))
|
|
|
|
types |= VIR_DOMAIN_GUEST_INFO_USERS;
|
|
|
|
if (vshCommandOptBool(cmd, "os"))
|
|
|
|
types |= VIR_DOMAIN_GUEST_INFO_OS;
|
|
|
|
if (vshCommandOptBool(cmd, "timezone"))
|
|
|
|
types |= VIR_DOMAIN_GUEST_INFO_TIMEZONE;
|
|
|
|
if (vshCommandOptBool(cmd, "hostname"))
|
|
|
|
types |= VIR_DOMAIN_GUEST_INFO_HOSTNAME;
|
|
|
|
if (vshCommandOptBool(cmd, "filesystem"))
|
|
|
|
types |= VIR_DOMAIN_GUEST_INFO_FILESYSTEM;
|
2020-12-02 12:08:14 +00:00
|
|
|
if (vshCommandOptBool(cmd, "disk"))
|
2020-11-20 18:09:48 +00:00
|
|
|
types |= VIR_DOMAIN_GUEST_INFO_DISKS;
|
2021-10-15 10:07:48 +00:00
|
|
|
if (vshCommandOptBool(cmd, "interface"))
|
|
|
|
types |= VIR_DOMAIN_GUEST_INFO_INTERFACES;
|
2019-08-27 20:35:55 +00:00
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virDomainGetGuestInfo(dom, types, ¶ms, &nparams, 0) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
for (i = 0; i < nparams; i++) {
|
2021-08-11 13:25:15 +00:00
|
|
|
g_autofree char *str = vshGetTypedParamValue(ctl, ¶ms[i]);
|
2019-08-27 20:35:55 +00:00
|
|
|
vshPrint(ctl, "%-20s: %s\n", params[i].field, str);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
virTypedParamsFree(params, nparams);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-11-10 08:25:27 +00:00
|
|
|
/*
|
|
|
|
* "get-user-sshkeys" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_get_user_sshkeys[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("list authorized SSH keys for given user (via agent)")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Use the guest agent to query authorized SSH keys for given "
|
|
|
|
"user")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_get_user_sshkeys[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
|
|
|
{.name = "user",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("user to list authorized keys for"),
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdGetUserSSHKeys(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2020-11-10 08:25:27 +00:00
|
|
|
const char *user;
|
2020-12-01 08:21:32 +00:00
|
|
|
g_auto(GStrv) keys = NULL;
|
2020-11-10 08:25:27 +00:00
|
|
|
int nkeys = 0;
|
|
|
|
size_t i;
|
|
|
|
const unsigned int flags = 0;
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "user", &user) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-11-10 08:25:27 +00:00
|
|
|
|
|
|
|
nkeys = virDomainAuthorizedSSHKeysGet(dom, user, &keys, flags);
|
|
|
|
if (nkeys < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-11-10 08:25:27 +00:00
|
|
|
|
|
|
|
for (i = 0; i < nkeys; i++) {
|
|
|
|
vshPrint(ctl, "%s", keys[i]);
|
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2020-11-10 08:25:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "set-user-sshkeys" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_set_user_sshkeys[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("manipulate authorized SSH keys file for given user (via agent)")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Append, reset or remove specified key from the authorized "
|
|
|
|
"keys file for given user")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_set_user_sshkeys[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(VIR_CONNECT_LIST_DOMAINS_ACTIVE),
|
|
|
|
{.name = "user",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("user to set authorized keys for"),
|
|
|
|
},
|
|
|
|
{.name = "file",
|
|
|
|
.type = VSH_OT_STRING,
|
2021-09-15 15:26:35 +00:00
|
|
|
.completer = virshCompletePathLocalExisting,
|
2020-11-10 08:25:27 +00:00
|
|
|
.help = N_("optional file to read keys from"),
|
|
|
|
},
|
|
|
|
{.name = "reset",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("clear out authorized keys file before adding new keys"),
|
|
|
|
},
|
|
|
|
{.name = "remove",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("remove keys from the authorized keys file"),
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdSetUserSSHKeys(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2020-11-10 08:25:27 +00:00
|
|
|
const char *user;
|
|
|
|
const char *from;
|
|
|
|
g_autofree char *buffer = NULL;
|
2020-12-01 08:21:32 +00:00
|
|
|
g_auto(GStrv) keys = NULL;
|
2020-11-10 08:25:27 +00:00
|
|
|
int nkeys = 0;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
|
|
|
|
VSH_REQUIRE_OPTION("remove", "file");
|
|
|
|
VSH_EXCLUSIVE_OPTIONS("reset", "remove");
|
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "user", &user) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-11-10 08:25:27 +00:00
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-11-10 08:25:27 +00:00
|
|
|
|
2020-12-08 12:42:28 +00:00
|
|
|
if (vshCommandOptBool(cmd, "remove")) {
|
|
|
|
flags |= VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_REMOVE;
|
|
|
|
} else {
|
|
|
|
if (!vshCommandOptBool(cmd, "reset")) {
|
|
|
|
flags |= VIR_DOMAIN_AUTHORIZED_SSH_KEYS_SET_APPEND;
|
2020-11-10 08:25:27 +00:00
|
|
|
|
2020-12-08 12:42:28 +00:00
|
|
|
if (!from) {
|
|
|
|
vshError(ctl, _("Option --file is required"));
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-12-08 12:42:28 +00:00
|
|
|
}
|
2020-11-10 08:25:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (from) {
|
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
|
|
|
|
vshSaveLibvirtError();
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-11-10 08:25:27 +00:00
|
|
|
}
|
|
|
|
|
2021-02-05 17:35:07 +00:00
|
|
|
if (!(keys = g_strsplit(buffer, "\n", -1)))
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-11-10 08:25:27 +00:00
|
|
|
|
2021-02-05 17:03:26 +00:00
|
|
|
nkeys = g_strv_length(keys);
|
2020-12-08 12:42:40 +00:00
|
|
|
if (nkeys == 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("File %1$s contains no keys"), from);
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-12-08 12:42:40 +00:00
|
|
|
}
|
2020-11-10 08:25:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainAuthorizedSSHKeysSet(dom, user,
|
|
|
|
(const char **) keys, nkeys, flags) < 0) {
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2020-11-10 08:25:27 +00:00
|
|
|
}
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2020-11-10 08:25:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-16 12:32:47 +00:00
|
|
|
/*
|
|
|
|
* "domdirtyrate" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_domdirtyrate_calc[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Calculate a vm's memory dirty rate")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Calculate memory dirty rate of a domain in order to "
|
|
|
|
"decide whether it's proper to be migrated out or not.\n"
|
|
|
|
"The calculated dirty rate information is available by "
|
|
|
|
"calling 'domstats --dirtyrate'.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_domdirtyrate_calc[] = {
|
|
|
|
VIRSH_COMMON_OPT_DOMAIN_FULL(0),
|
|
|
|
{.name = "seconds",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("calculate memory dirty rate within specified seconds, "
|
|
|
|
"the supported value range from 1 to 60, default to 1.")
|
|
|
|
},
|
2022-02-20 13:28:14 +00:00
|
|
|
{.name = "mode",
|
|
|
|
.type = VSH_OT_STRING,
|
|
|
|
.completer = virshDomainDirtyRateCalcModeCompleter,
|
|
|
|
.help = N_("dirty page rate calculation mode, either of these 3 options "
|
|
|
|
"'page-sampling, dirty-bitmap, dirty-ring' can be specified.")
|
|
|
|
},
|
2021-03-16 12:32:47 +00:00
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
2022-02-20 13:28:14 +00:00
|
|
|
VIR_ENUM_IMPL(virshDomainDirtyRateCalcMode,
|
|
|
|
VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_LAST,
|
|
|
|
"page-sampling",
|
|
|
|
"dirty-bitmap",
|
|
|
|
"dirty-ring");
|
|
|
|
|
2021-03-16 12:32:47 +00:00
|
|
|
static bool
|
|
|
|
cmdDomDirtyRateCalc(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-08-11 09:33:50 +00:00
|
|
|
g_autoptr(virshDomain) dom = NULL;
|
2021-03-16 12:32:47 +00:00
|
|
|
int seconds = 1; /* the default value is 1 */
|
2022-02-20 13:28:14 +00:00
|
|
|
const char *modestr = NULL;
|
|
|
|
unsigned int flags = 0;
|
2021-03-16 12:32:47 +00:00
|
|
|
|
|
|
|
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (vshCommandOptInt(ctl, cmd, "seconds", &seconds) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2021-03-16 12:32:47 +00:00
|
|
|
|
2022-02-20 13:28:14 +00:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "mode", &modestr) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (modestr) {
|
|
|
|
int mode = virshDomainDirtyRateCalcModeTypeFromString(modestr);
|
|
|
|
|
|
|
|
if (mode < 0) {
|
2023-03-09 14:54:42 +00:00
|
|
|
vshError(ctl, _("Unknown calculation mode '%1$s'"), modestr);
|
2022-02-20 13:28:14 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ((virshDomainDirtyRateCalcMode) mode) {
|
|
|
|
case VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_PAGE_SAMPLING:
|
|
|
|
flags |= VIR_DOMAIN_DIRTYRATE_MODE_PAGE_SAMPLING;
|
|
|
|
break;
|
|
|
|
case VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_DIRTY_BITMAP:
|
|
|
|
flags |= VIR_DOMAIN_DIRTYRATE_MODE_DIRTY_BITMAP;
|
|
|
|
break;
|
|
|
|
case VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_DIRTY_RING:
|
|
|
|
flags |= VIR_DOMAIN_DIRTYRATE_MODE_DIRTY_RING;
|
|
|
|
break;
|
|
|
|
case VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_LAST:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virDomainStartDirtyRateCalc(dom, seconds, flags) < 0)
|
2021-08-12 07:59:20 +00:00
|
|
|
return false;
|
2021-03-16 12:32:47 +00:00
|
|
|
|
|
|
|
vshPrintExtra(ctl, _("Start to calculate domain's memory "
|
|
|
|
"dirty rate successfully.\n"));
|
|
|
|
|
2021-08-12 07:59:20 +00:00
|
|
|
return true;
|
2021-03-16 12:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-18 04:00:42 +00:00
|
|
|
const vshCmdDef domManagementCmds[] = {
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "attach-device",
|
|
|
|
.handler = cmdAttachDevice,
|
|
|
|
.opts = opts_attach_device,
|
|
|
|
.info = info_attach_device,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "attach-disk",
|
|
|
|
.handler = cmdAttachDisk,
|
|
|
|
.opts = opts_attach_disk,
|
|
|
|
.info = info_attach_disk,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "attach-interface",
|
|
|
|
.handler = cmdAttachInterface,
|
|
|
|
.opts = opts_attach_interface,
|
|
|
|
.info = info_attach_interface,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "autostart",
|
|
|
|
.handler = cmdAutostart,
|
|
|
|
.opts = opts_autostart,
|
|
|
|
.info = info_autostart,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "blkdeviotune",
|
|
|
|
.handler = cmdBlkdeviotune,
|
|
|
|
.opts = opts_blkdeviotune,
|
|
|
|
.info = info_blkdeviotune,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "blkiotune",
|
|
|
|
.handler = cmdBlkiotune,
|
|
|
|
.opts = opts_blkiotune,
|
|
|
|
.info = info_blkiotune,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "blockcommit",
|
2018-02-19 06:19:47 +00:00
|
|
|
.handler = cmdBlockcommit,
|
|
|
|
.opts = opts_blockcommit,
|
|
|
|
.info = info_blockcommit,
|
2013-02-07 15:25:10 +00:00
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "blockcopy",
|
2018-02-19 06:19:47 +00:00
|
|
|
.handler = cmdBlockcopy,
|
|
|
|
.opts = opts_blockcopy,
|
|
|
|
.info = info_blockcopy,
|
2013-02-07 15:25:10 +00:00
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "blockjob",
|
2018-02-19 06:19:47 +00:00
|
|
|
.handler = cmdBlockjob,
|
|
|
|
.opts = opts_blockjob,
|
|
|
|
.info = info_blockjob,
|
2013-02-07 15:25:10 +00:00
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "blockpull",
|
2018-02-19 06:19:47 +00:00
|
|
|
.handler = cmdBlockpull,
|
|
|
|
.opts = opts_blockpull,
|
|
|
|
.info = info_blockpull,
|
2013-02-07 15:25:10 +00:00
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "blockresize",
|
2018-02-19 06:19:47 +00:00
|
|
|
.handler = cmdBlockresize,
|
|
|
|
.opts = opts_blockresize,
|
|
|
|
.info = info_blockresize,
|
2013-02-07 15:25:10 +00:00
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "change-media",
|
|
|
|
.handler = cmdChangeMedia,
|
|
|
|
.opts = opts_change_media,
|
|
|
|
.info = info_change_media,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2012-07-23 07:19:04 +00:00
|
|
|
#ifndef WIN32
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "console",
|
|
|
|
.handler = cmdConsole,
|
|
|
|
.opts = opts_console,
|
|
|
|
.info = info_console,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2012-07-23 07:19:04 +00:00
|
|
|
#endif
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "cpu-stats",
|
|
|
|
.handler = cmdCPUStats,
|
|
|
|
.opts = opts_cpu_stats,
|
|
|
|
.info = info_cpu_stats,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "create",
|
|
|
|
.handler = cmdCreate,
|
|
|
|
.opts = opts_create,
|
|
|
|
.info = info_create,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "define",
|
|
|
|
.handler = cmdDefine,
|
|
|
|
.opts = opts_define,
|
|
|
|
.info = info_define,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.handler = cmdDesc,
|
|
|
|
.opts = opts_desc,
|
|
|
|
.info = info_desc,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "destroy",
|
|
|
|
.handler = cmdDestroy,
|
|
|
|
.opts = opts_destroy,
|
|
|
|
.info = info_destroy,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "detach-device",
|
|
|
|
.handler = cmdDetachDevice,
|
|
|
|
.opts = opts_detach_device,
|
|
|
|
.info = info_detach_device,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2018-05-21 14:25:13 +00:00
|
|
|
{.name = "detach-device-alias",
|
|
|
|
.handler = cmdDetachDeviceAlias,
|
|
|
|
.opts = opts_detach_device_alias,
|
|
|
|
.info = info_detach_device_alias,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "detach-disk",
|
|
|
|
.handler = cmdDetachDisk,
|
|
|
|
.opts = opts_detach_disk,
|
|
|
|
.info = info_detach_disk,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "detach-interface",
|
|
|
|
.handler = cmdDetachInterface,
|
|
|
|
.opts = opts_detach_interface,
|
|
|
|
.info = info_detach_interface,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domdisplay",
|
|
|
|
.handler = cmdDomDisplay,
|
|
|
|
.opts = opts_domdisplay,
|
|
|
|
.info = info_domdisplay,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2014-05-02 00:06:13 +00:00
|
|
|
{.name = "domfsfreeze",
|
|
|
|
.handler = cmdDomFSFreeze,
|
|
|
|
.opts = opts_domfsfreeze,
|
|
|
|
.info = info_domfsfreeze,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domfsthaw",
|
|
|
|
.handler = cmdDomFSThaw,
|
|
|
|
.opts = opts_domfsthaw,
|
|
|
|
.info = info_domfsthaw,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2014-11-22 01:27:52 +00:00
|
|
|
{.name = "domfsinfo",
|
|
|
|
.handler = cmdDomFSInfo,
|
|
|
|
.opts = opts_domfsinfo,
|
|
|
|
.info = info_domfsinfo,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "domfstrim",
|
|
|
|
.handler = cmdDomFSTrim,
|
|
|
|
.opts = opts_domfstrim,
|
|
|
|
.info = info_domfstrim,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domhostname",
|
|
|
|
.handler = cmdDomHostname,
|
|
|
|
.opts = opts_domhostname,
|
|
|
|
.info = info_domhostname,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domid",
|
|
|
|
.handler = cmdDomid,
|
|
|
|
.opts = opts_domid,
|
|
|
|
.info = info_domid,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domif-setlink",
|
|
|
|
.handler = cmdDomIfSetLink,
|
|
|
|
.opts = opts_domif_setlink,
|
|
|
|
.info = info_domif_setlink,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domiftune",
|
|
|
|
.handler = cmdDomIftune,
|
|
|
|
.opts = opts_domiftune,
|
|
|
|
.info = info_domiftune,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domjobabort",
|
|
|
|
.handler = cmdDomjobabort,
|
|
|
|
.opts = opts_domjobabort,
|
|
|
|
.info = info_domjobabort,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domjobinfo",
|
|
|
|
.handler = cmdDomjobinfo,
|
|
|
|
.opts = opts_domjobinfo,
|
|
|
|
.info = info_domjobinfo,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2021-12-08 12:53:00 +00:00
|
|
|
{.name = "domlaunchsecinfo",
|
|
|
|
.handler = cmdDomLaunchSecInfo,
|
|
|
|
.opts = opts_domlaunchsecinfo,
|
|
|
|
.info = info_domlaunchsecinfo,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2021-12-15 03:15:40 +00:00
|
|
|
{.name = "domsetlaunchsecstate",
|
|
|
|
.handler = cmdDomSetLaunchSecState,
|
|
|
|
.opts = opts_domsetlaunchsecstate,
|
|
|
|
.info = info_domsetlaunchsecstate,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "domname",
|
|
|
|
.handler = cmdDomname,
|
|
|
|
.opts = opts_domname,
|
|
|
|
.info = info_domname,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2015-08-10 19:59:15 +00:00
|
|
|
{.name = "domrename",
|
|
|
|
.handler = cmdDomrename,
|
|
|
|
.opts = opts_domrename,
|
|
|
|
.info = info_domrename,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "dompmsuspend",
|
|
|
|
.handler = cmdDomPMSuspend,
|
|
|
|
.opts = opts_dom_pm_suspend,
|
|
|
|
.info = info_dom_pm_suspend,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "dompmwakeup",
|
|
|
|
.handler = cmdDomPMWakeup,
|
|
|
|
.opts = opts_dom_pm_wakeup,
|
|
|
|
.info = info_dom_pm_wakeup,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domuuid",
|
|
|
|
.handler = cmdDomuuid,
|
|
|
|
.opts = opts_domuuid,
|
|
|
|
.info = info_domuuid,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domxml-from-native",
|
|
|
|
.handler = cmdDomXMLFromNative,
|
|
|
|
.opts = opts_domxmlfromnative,
|
|
|
|
.info = info_domxmlfromnative,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "domxml-to-native",
|
|
|
|
.handler = cmdDomXMLToNative,
|
|
|
|
.opts = opts_domxmltonative,
|
|
|
|
.info = info_domxmltonative,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "dump",
|
|
|
|
.handler = cmdDump,
|
|
|
|
.opts = opts_dump,
|
|
|
|
.info = info_dump,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "dumpxml",
|
|
|
|
.handler = cmdDumpXML,
|
|
|
|
.opts = opts_dumpxml,
|
|
|
|
.info = info_dumpxml,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "edit",
|
|
|
|
.handler = cmdEdit,
|
|
|
|
.opts = opts_edit,
|
|
|
|
.info = info_edit,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2020-11-10 08:25:27 +00:00
|
|
|
{.name = "get-user-sshkeys",
|
|
|
|
.handler = cmdGetUserSSHKeys,
|
|
|
|
.opts = opts_get_user_sshkeys,
|
|
|
|
.info = info_get_user_sshkeys,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "inject-nmi",
|
|
|
|
.handler = cmdInjectNMI,
|
|
|
|
.opts = opts_inject_nmi,
|
|
|
|
.info = info_inject_nmi,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2015-03-25 16:15:04 +00:00
|
|
|
{.name = "iothreadinfo",
|
|
|
|
.handler = cmdIOThreadInfo,
|
|
|
|
.opts = opts_iothreadinfo,
|
|
|
|
.info = info_iothreadinfo,
|
2015-02-11 20:29:22 +00:00
|
|
|
.flags = 0
|
|
|
|
},
|
2015-03-06 00:08:04 +00:00
|
|
|
{.name = "iothreadpin",
|
|
|
|
.handler = cmdIOThreadPin,
|
|
|
|
.opts = opts_iothreadpin,
|
|
|
|
.info = info_iothreadpin,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2015-03-18 13:01:50 +00:00
|
|
|
{.name = "iothreadadd",
|
|
|
|
.handler = cmdIOThreadAdd,
|
|
|
|
.opts = opts_iothreadadd,
|
|
|
|
.info = info_iothreadadd,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2018-10-05 12:53:09 +00:00
|
|
|
{.name = "iothreadset",
|
|
|
|
.handler = cmdIOThreadSet,
|
|
|
|
.opts = opts_iothreadset,
|
|
|
|
.info = info_iothreadset,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2015-03-18 13:01:50 +00:00
|
|
|
{.name = "iothreaddel",
|
|
|
|
.handler = cmdIOThreadDel,
|
|
|
|
.opts = opts_iothreaddel,
|
|
|
|
.info = info_iothreaddel,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "send-key",
|
|
|
|
.handler = cmdSendKey,
|
|
|
|
.opts = opts_send_key,
|
|
|
|
.info = info_send_key,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "send-process-signal",
|
|
|
|
.handler = cmdSendProcessSignal,
|
|
|
|
.opts = opts_send_process_signal,
|
|
|
|
.info = info_send_process_signal,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "lxc-enter-namespace",
|
|
|
|
.handler = cmdLxcEnterNamespace,
|
|
|
|
.opts = opts_lxc_enter_namespace,
|
|
|
|
.info = info_lxc_enter_namespace,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "managedsave",
|
|
|
|
.handler = cmdManagedSave,
|
|
|
|
.opts = opts_managedsave,
|
|
|
|
.info = info_managedsave,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "managedsave-remove",
|
|
|
|
.handler = cmdManagedSaveRemove,
|
|
|
|
.opts = opts_managedsaveremove,
|
|
|
|
.info = info_managedsaveremove,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2017-08-08 08:02:55 +00:00
|
|
|
{.name = "managedsave-edit",
|
|
|
|
.handler = cmdManagedSaveEdit,
|
|
|
|
.opts = opts_managed_save_edit,
|
|
|
|
.info = info_managed_save_edit,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2017-08-08 08:02:54 +00:00
|
|
|
{.name = "managedsave-dumpxml",
|
|
|
|
.handler = cmdManagedSaveDumpxml,
|
|
|
|
.opts = opts_managed_save_dumpxml,
|
|
|
|
.info = info_managed_save_dumpxml,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2017-08-08 08:02:53 +00:00
|
|
|
{.name = "managedsave-define",
|
|
|
|
.handler = cmdManagedSaveDefine,
|
|
|
|
.opts = opts_managed_save_define,
|
|
|
|
.info = info_managed_save_define,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "memtune",
|
|
|
|
.handler = cmdMemtune,
|
|
|
|
.opts = opts_memtune,
|
|
|
|
.info = info_memtune,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2016-03-28 13:30:32 +00:00
|
|
|
{.name = "perf",
|
|
|
|
.handler = cmdPerf,
|
|
|
|
.opts = opts_perf,
|
|
|
|
.info = info_perf,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-09-09 08:54:04 +00:00
|
|
|
{.name = "metadata",
|
|
|
|
.handler = cmdMetadata,
|
|
|
|
.opts = opts_metadata,
|
|
|
|
.info = info_metadata,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "migrate",
|
|
|
|
.handler = cmdMigrate,
|
|
|
|
.opts = opts_migrate,
|
|
|
|
.info = info_migrate,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "migrate-setmaxdowntime",
|
|
|
|
.handler = cmdMigrateSetMaxDowntime,
|
|
|
|
.opts = opts_migrate_setmaxdowntime,
|
|
|
|
.info = info_migrate_setmaxdowntime,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2017-08-17 22:17:21 +00:00
|
|
|
{.name = "migrate-getmaxdowntime",
|
|
|
|
.handler = cmdMigrateGetMaxDowntime,
|
|
|
|
.opts = opts_migrate_getmaxdowntime,
|
|
|
|
.info = info_migrate_getmaxdowntime,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-18 20:14:49 +00:00
|
|
|
{.name = "migrate-compcache",
|
|
|
|
.handler = cmdMigrateCompCache,
|
|
|
|
.opts = opts_migrate_compcache,
|
|
|
|
.info = info_migrate_compcache,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "migrate-setspeed",
|
|
|
|
.handler = cmdMigrateSetMaxSpeed,
|
|
|
|
.opts = opts_migrate_setspeed,
|
|
|
|
.info = info_migrate_setspeed,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "migrate-getspeed",
|
|
|
|
.handler = cmdMigrateGetMaxSpeed,
|
|
|
|
.opts = opts_migrate_getspeed,
|
|
|
|
.info = info_migrate_getspeed,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2014-12-01 15:59:58 +00:00
|
|
|
{.name = "migrate-postcopy",
|
|
|
|
.handler = cmdMigratePostCopy,
|
|
|
|
.opts = opts_migrate_postcopy,
|
|
|
|
.info = info_migrate_postcopy,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "numatune",
|
|
|
|
.handler = cmdNumatune,
|
|
|
|
.opts = opts_numatune,
|
|
|
|
.info = info_numatune,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "qemu-attach",
|
|
|
|
.handler = cmdQemuAttach,
|
|
|
|
.opts = opts_qemu_attach,
|
|
|
|
.info = info_qemu_attach,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "qemu-monitor-command",
|
|
|
|
.handler = cmdQemuMonitorCommand,
|
|
|
|
.opts = opts_qemu_monitor_command,
|
|
|
|
.info = info_qemu_monitor_command,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2014-01-31 23:52:17 +00:00
|
|
|
{.name = "qemu-monitor-event",
|
|
|
|
.handler = cmdQemuMonitorEvent,
|
|
|
|
.opts = opts_qemu_monitor_event,
|
|
|
|
.info = info_qemu_monitor_event,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "qemu-agent-command",
|
|
|
|
.handler = cmdQemuAgentCommand,
|
|
|
|
.opts = opts_qemu_agent_command,
|
|
|
|
.info = info_qemu_agent_command,
|
|
|
|
.flags = 0
|
|
|
|
},
|
Add API to change qemu agent response timeout
Some layered products such as oVirt have requested a way to avoid being
blocked by guest agent commands when querying a loaded vm. For example,
many guest agent commands are polled periodically to monitor changes,
and rather than blocking the calling process, they'd prefer to simply
time out when an agent query is taking too long.
This patch adds a way for the user to specify a custom agent timeout
that is applied to all agent commands.
One special case to note here is the 'guest-sync' command. 'guest-sync'
is issued internally prior to calling any other command. (For example,
when libvirt wants to call 'guest-get-fsinfo', we first call
'guest-sync' and then call 'guest-get-fsinfo').
Previously, the 'guest-sync' command used a 5-second timeout
(VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT), whereas the actual command that
followed always blocked indefinitely
(VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK). As part of this patch, if a
custom timeout is specified that is shorter than
5 seconds, this new timeout is also used for 'guest-sync'. If there is
no custom timeout or if the custom timeout is longer than 5 seconds, we
will continue to use the 5-second timeout.
Signed-off-by: Jonathon Jongsma <jjongsma@redhat.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
2019-11-13 22:06:09 +00:00
|
|
|
{.name = "guest-agent-timeout",
|
|
|
|
.handler = cmdGuestAgentTimeout,
|
|
|
|
.opts = opts_guest_agent_timeout,
|
|
|
|
.info = info_guest_agent_timeout,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "reboot",
|
|
|
|
.handler = cmdReboot,
|
|
|
|
.opts = opts_reboot,
|
|
|
|
.info = info_reboot,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "reset",
|
|
|
|
.handler = cmdReset,
|
|
|
|
.opts = opts_reset,
|
|
|
|
.info = info_reset,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "restore",
|
|
|
|
.handler = cmdRestore,
|
|
|
|
.opts = opts_restore,
|
|
|
|
.info = info_restore,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "resume",
|
|
|
|
.handler = cmdResume,
|
|
|
|
.opts = opts_resume,
|
|
|
|
.info = info_resume,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "save",
|
|
|
|
.handler = cmdSave,
|
|
|
|
.opts = opts_save,
|
|
|
|
.info = info_save,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "save-image-define",
|
|
|
|
.handler = cmdSaveImageDefine,
|
|
|
|
.opts = opts_save_image_define,
|
|
|
|
.info = info_save_image_define,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "save-image-dumpxml",
|
|
|
|
.handler = cmdSaveImageDumpxml,
|
|
|
|
.opts = opts_save_image_dumpxml,
|
|
|
|
.info = info_save_image_dumpxml,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "save-image-edit",
|
|
|
|
.handler = cmdSaveImageEdit,
|
|
|
|
.opts = opts_save_image_edit,
|
|
|
|
.info = info_save_image_edit,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "schedinfo",
|
|
|
|
.handler = cmdSchedinfo,
|
|
|
|
.opts = opts_schedinfo,
|
|
|
|
.info = info_schedinfo,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "screenshot",
|
|
|
|
.handler = cmdScreenshot,
|
|
|
|
.opts = opts_screenshot,
|
|
|
|
.info = info_screenshot,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2017-10-12 14:25:43 +00:00
|
|
|
{.name = "set-lifecycle-action",
|
|
|
|
.handler = cmdSetLifecycleAction,
|
|
|
|
.opts = opts_setLifecycleAction,
|
|
|
|
.info = info_setLifecycleAction,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2020-11-10 08:25:27 +00:00
|
|
|
{.name = "set-user-sshkeys",
|
|
|
|
.handler = cmdSetUserSSHKeys,
|
|
|
|
.opts = opts_set_user_sshkeys,
|
|
|
|
.info = info_set_user_sshkeys,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2015-05-18 10:37:38 +00:00
|
|
|
{.name = "set-user-password",
|
|
|
|
.handler = cmdSetUserPassword,
|
|
|
|
.opts = opts_set_user_password,
|
|
|
|
.info = info_set_user_password,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "setmaxmem",
|
|
|
|
.handler = cmdSetmaxmem,
|
|
|
|
.opts = opts_setmaxmem,
|
|
|
|
.info = info_setmaxmem,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "setmem",
|
|
|
|
.handler = cmdSetmem,
|
|
|
|
.opts = opts_setmem,
|
|
|
|
.info = info_setmem,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "setvcpus",
|
|
|
|
.handler = cmdSetvcpus,
|
|
|
|
.opts = opts_setvcpus,
|
|
|
|
.info = info_setvcpus,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "shutdown",
|
|
|
|
.handler = cmdShutdown,
|
|
|
|
.opts = opts_shutdown,
|
|
|
|
.info = info_shutdown,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "start",
|
|
|
|
.handler = cmdStart,
|
|
|
|
.opts = opts_start,
|
|
|
|
.info = info_start,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "suspend",
|
|
|
|
.handler = cmdSuspend,
|
|
|
|
.opts = opts_suspend,
|
|
|
|
.info = info_suspend,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "ttyconsole",
|
|
|
|
.handler = cmdTTYConsole,
|
|
|
|
.opts = opts_ttyconsole,
|
|
|
|
.info = info_ttyconsole,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "undefine",
|
|
|
|
.handler = cmdUndefine,
|
|
|
|
.opts = opts_undefine,
|
|
|
|
.info = info_undefine,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "update-device",
|
|
|
|
.handler = cmdUpdateDevice,
|
|
|
|
.opts = opts_update_device,
|
|
|
|
.info = info_update_device,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2021-01-21 16:51:31 +00:00
|
|
|
{.name = "update-memory-device",
|
|
|
|
.handler = cmdUpdateMemoryDevice,
|
|
|
|
.opts = opts_update_memory_device,
|
|
|
|
.info = info_update_memory_device,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = "vcpucount",
|
|
|
|
.handler = cmdVcpucount,
|
|
|
|
.opts = opts_vcpucount,
|
|
|
|
.info = info_vcpucount,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "vcpuinfo",
|
|
|
|
.handler = cmdVcpuinfo,
|
|
|
|
.opts = opts_vcpuinfo,
|
|
|
|
.info = info_vcpuinfo,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "vcpupin",
|
|
|
|
.handler = cmdVcpuPin,
|
|
|
|
.opts = opts_vcpupin,
|
|
|
|
.info = info_vcpupin,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "emulatorpin",
|
|
|
|
.handler = cmdEmulatorPin,
|
|
|
|
.opts = opts_emulatorpin,
|
|
|
|
.info = info_emulatorpin,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "vncdisplay",
|
|
|
|
.handler = cmdVNCDisplay,
|
|
|
|
.opts = opts_vncdisplay,
|
|
|
|
.info = info_vncdisplay,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2016-06-20 07:57:53 +00:00
|
|
|
{.name = "guestvcpus",
|
|
|
|
.handler = cmdGuestvcpus,
|
|
|
|
.opts = opts_guestvcpus,
|
|
|
|
.info = info_guestvcpus,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2016-06-21 08:55:30 +00:00
|
|
|
{.name = "setvcpu",
|
|
|
|
.handler = cmdSetvcpu,
|
|
|
|
.opts = opts_setvcpu,
|
|
|
|
.info = info_setvcpu,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2017-02-23 12:27:18 +00:00
|
|
|
{.name = "domblkthreshold",
|
|
|
|
.handler = cmdDomblkthreshold,
|
|
|
|
.opts = opts_domblkthreshold,
|
|
|
|
.info = info_domblkthreshold,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2019-08-27 20:35:55 +00:00
|
|
|
{.name = "guestinfo",
|
|
|
|
.handler = cmdGuestInfo,
|
|
|
|
.opts = opts_guestinfo,
|
|
|
|
.info = info_guestinfo,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2021-03-16 12:32:47 +00:00
|
|
|
{.name = "domdirtyrate-calc",
|
|
|
|
.handler = cmdDomDirtyRateCalc,
|
|
|
|
.opts = opts_domdirtyrate_calc,
|
|
|
|
.info = info_domdirtyrate_calc,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2022-03-23 09:12:50 +00:00
|
|
|
{.name = "dom-fd-associate",
|
|
|
|
.handler = cmdDomFdAssociate,
|
|
|
|
.opts = opts_dom_fd_associate,
|
|
|
|
.info = info_dom_fd_associate,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 15:25:10 +00:00
|
|
|
{.name = NULL}
|
2012-07-23 07:19:04 +00:00
|
|
|
};
|