mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-27 08:05:24 +00:00
66d4fd7009
This fixes commit bf9d812956
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
4179 lines
114 KiB
C
4179 lines
114 KiB
C
/*
|
|
* vz_driver.c: core driver functions for managing
|
|
* Parallels Cloud Server hosts
|
|
*
|
|
* Copyright (C) 2014-2015 Red Hat, Inc.
|
|
* Copyright (C) 2012 Parallels, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/poll.h>
|
|
#include <stdarg.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <pwd.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/time.h>
|
|
#include <sys/statvfs.h>
|
|
|
|
#include "datatypes.h"
|
|
#include "virerror.h"
|
|
#include "viralloc.h"
|
|
#include "virlog.h"
|
|
#include "vircommand.h"
|
|
#include "configmake.h"
|
|
#include "virfile.h"
|
|
#include "virpidfile.h"
|
|
#include "virstoragefile.h"
|
|
#include "virstring.h"
|
|
#include "cpu/cpu.h"
|
|
#include "virtypedparam.h"
|
|
#include "virhostmem.h"
|
|
#include "virhostcpu.h"
|
|
#include "viraccessapicheck.h"
|
|
|
|
#include "vz_driver.h"
|
|
#include "vz_utils.h"
|
|
#include "vz_sdk.h"
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_PARALLELS
|
|
|
|
VIR_LOG_INIT("parallels.parallels_driver");
|
|
|
|
#define PRLCTL "prlctl"
|
|
|
|
#define VZ_STATEDIR RUNSTATEDIR "/libvirt/vz"
|
|
|
|
static virClassPtr vzDriverClass;
|
|
|
|
static bool vz_driver_privileged;
|
|
/* pid file FD, ensures two copies of the driver can't use the same root */
|
|
static int vz_driver_lock_fd = -1;
|
|
static virMutex vz_driver_lock;
|
|
static vzDriverPtr vz_driver;
|
|
static vzConnPtr vz_conn_list;
|
|
|
|
static vzDriverPtr
|
|
vzDriverObjNew(void);
|
|
|
|
static int
|
|
vzCapsAddGuestDomain(virCapsPtr caps,
|
|
virDomainOSType ostype,
|
|
virArch arch,
|
|
const char * emulator,
|
|
virDomainVirtType virt_type)
|
|
{
|
|
virCapsGuestPtr guest;
|
|
|
|
if ((guest = virCapabilitiesAddGuest(caps, ostype, arch, emulator,
|
|
NULL, 0, NULL)) == NULL)
|
|
return -1;
|
|
|
|
|
|
if (virCapabilitiesAddGuestDomain(guest, virt_type,
|
|
NULL, NULL, 0, NULL) == NULL)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static virCapsPtr
|
|
vzBuildCapabilities(void)
|
|
{
|
|
virCapsPtr caps = NULL;
|
|
virNodeInfo nodeinfo;
|
|
virDomainOSType ostypes[] = {
|
|
VIR_DOMAIN_OSTYPE_HVM,
|
|
VIR_DOMAIN_OSTYPE_EXE
|
|
};
|
|
virArch archs[] = { VIR_ARCH_I686, VIR_ARCH_X86_64 };
|
|
const char *const emulators[] = { "vz", "parallels"};
|
|
virDomainVirtType virt_types[] = {
|
|
VIR_DOMAIN_VIRT_VZ,
|
|
VIR_DOMAIN_VIRT_PARALLELS
|
|
};
|
|
size_t i, j, k;
|
|
|
|
if ((caps = virCapabilitiesNew(virArchFromHost(),
|
|
false, false)) == NULL)
|
|
return NULL;
|
|
|
|
if (!(caps->host.numa = virCapabilitiesHostNUMANewHost()))
|
|
goto error;
|
|
|
|
if (virCapabilitiesInitCaches(caps) < 0)
|
|
goto error;
|
|
|
|
verify(G_N_ELEMENTS(archs) == G_N_ELEMENTS(emulators));
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(ostypes); i++)
|
|
for (j = 0; j < G_N_ELEMENTS(archs); j++)
|
|
for (k = 0; k < G_N_ELEMENTS(emulators); k++)
|
|
if (vzCapsAddGuestDomain(caps, ostypes[i], archs[j],
|
|
emulators[k], virt_types[k]) < 0)
|
|
goto error;
|
|
|
|
if (virCapabilitiesGetNodeInfo(&nodeinfo))
|
|
goto error;
|
|
|
|
if (!(caps->host.cpu = virCPUGetHost(caps->host.arch, VIR_CPU_TYPE_HOST,
|
|
&nodeinfo, NULL)))
|
|
goto error;
|
|
|
|
if (virCapabilitiesAddHostMigrateTransport(caps, "vzmigr") < 0)
|
|
goto error;
|
|
|
|
return caps;
|
|
|
|
error:
|
|
virObjectUnref(caps);
|
|
return NULL;
|
|
}
|
|
|
|
static void vzDriverDispose(void * obj)
|
|
{
|
|
vzDriverPtr driver = obj;
|
|
|
|
prlsdkDisconnect(driver);
|
|
virObjectUnref(driver->domains);
|
|
virObjectUnref(driver->caps);
|
|
virObjectUnref(driver->xmlopt);
|
|
virObjectUnref(driver->domainEventState);
|
|
virSysinfoDefFree(driver->hostsysinfo);
|
|
}
|
|
|
|
static int vzDriverOnceInit(void)
|
|
{
|
|
if (!VIR_CLASS_NEW(vzDriver, virClassForObjectLockable()))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
VIR_ONCE_GLOBAL_INIT(vzDriver);
|
|
|
|
vzDriverPtr
|
|
vzGetDriverConnection(void)
|
|
{
|
|
if (!vz_driver_privileged) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
"%s", _("vz state driver is not active"));
|
|
return NULL;
|
|
}
|
|
virMutexLock(&vz_driver_lock);
|
|
if (!vz_driver)
|
|
vz_driver = vzDriverObjNew();
|
|
virObjectRef(vz_driver);
|
|
virMutexUnlock(&vz_driver_lock);
|
|
|
|
return vz_driver;
|
|
}
|
|
|
|
void
|
|
vzDestroyDriverConnection(void)
|
|
{
|
|
vzDriverPtr driver;
|
|
vzConnPtr privconn_list;
|
|
|
|
virMutexLock(&vz_driver_lock);
|
|
driver = g_steal_pointer(&vz_driver);
|
|
privconn_list = g_steal_pointer(&vz_conn_list);
|
|
virMutexUnlock(&vz_driver_lock);
|
|
|
|
while (privconn_list) {
|
|
vzConnPtr privconn = privconn_list;
|
|
privconn_list = privconn->next;
|
|
virConnectCloseCallbackDataCall(privconn->closeCallback,
|
|
VIR_CONNECT_CLOSE_REASON_EOF);
|
|
}
|
|
virObjectUnref(driver);
|
|
}
|
|
|
|
static char *
|
|
vzConnectGetCapabilities(virConnectPtr conn)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
|
|
return NULL;
|
|
|
|
return virCapabilitiesFormatXML(privconn->driver->caps);
|
|
}
|
|
|
|
static int
|
|
vzDomainDefAddDefaultInputDevices(virDomainDefPtr def)
|
|
{
|
|
if (def->ngraphics == 0)
|
|
return 0;
|
|
|
|
int bus = IS_CT(def) ? VIR_DOMAIN_INPUT_BUS_PARALLELS :
|
|
VIR_DOMAIN_INPUT_BUS_PS2;
|
|
|
|
if (virDomainDefMaybeAddInput(def,
|
|
VIR_DOMAIN_INPUT_TYPE_MOUSE,
|
|
bus) < 0)
|
|
return -1;
|
|
|
|
if (virDomainDefMaybeAddInput(def,
|
|
VIR_DOMAIN_INPUT_TYPE_KBD,
|
|
bus) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainDefPostParse(virDomainDefPtr def,
|
|
unsigned int parseFlags G_GNUC_UNUSED,
|
|
void *opaque,
|
|
void *parseOpaque G_GNUC_UNUSED)
|
|
{
|
|
vzDriverPtr driver = opaque;
|
|
if (!virCapabilitiesDomainSupported(driver->caps, def->os.type,
|
|
def->os.arch,
|
|
def->virtType))
|
|
return -1;
|
|
|
|
if (vzDomainDefAddDefaultInputDevices(def) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainDefValidate(const virDomainDef *def,
|
|
void *opaque)
|
|
{
|
|
if (vzCheckUnsupportedControllers(def, opaque) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
|
const virDomainDef *def,
|
|
unsigned int parseFlags G_GNUC_UNUSED,
|
|
void *opaque G_GNUC_UNUSED,
|
|
void *parseOpaque G_GNUC_UNUSED)
|
|
{
|
|
if (dev->type == VIR_DOMAIN_DEVICE_NET &&
|
|
(dev->data.net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
|
|
dev->data.net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
|
|
dev->data.net->model == VIR_DOMAIN_NET_MODEL_UNKNOWN &&
|
|
def->os.type == VIR_DOMAIN_OSTYPE_HVM)
|
|
dev->data.net->model = VIR_DOMAIN_NET_MODEL_E1000;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainDeviceDefValidate(const virDomainDeviceDef *dev,
|
|
const virDomainDef *def,
|
|
void *opaque)
|
|
{
|
|
vzDriverPtr driver = opaque;
|
|
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK)
|
|
return vzCheckUnsupportedDisk(def, dev->data.disk, &driver->vzCaps);
|
|
else if (dev->type == VIR_DOMAIN_DEVICE_GRAPHICS)
|
|
return vzCheckUnsupportedGraphics(dev->data.graphics);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static virDomainXMLPrivateDataCallbacks vzDomainXMLPrivateDataCallbacksPtr = {
|
|
.alloc = vzDomObjAlloc,
|
|
.free = vzDomObjFree,
|
|
};
|
|
|
|
static virDomainDefParserConfig vzDomainDefParserConfig = {
|
|
.macPrefix = {0x42, 0x1C, 0x00},
|
|
.domainPostParseCallback = vzDomainDefPostParse,
|
|
.devicesPostParseCallback = vzDomainDeviceDefPostParse,
|
|
.domainValidateCallback = vzDomainDefValidate,
|
|
.deviceValidateCallback = vzDomainDeviceDefValidate,
|
|
};
|
|
|
|
static vzDriverPtr
|
|
vzDriverObjNew(void)
|
|
{
|
|
vzDriverPtr driver;
|
|
|
|
if (vzDriverInitialize() < 0)
|
|
return NULL;
|
|
|
|
if (!(driver = virObjectLockableNew(vzDriverClass)))
|
|
return NULL;
|
|
|
|
vzDomainDefParserConfig.priv = driver;
|
|
|
|
if (!(driver->caps = vzBuildCapabilities()) ||
|
|
!(driver->xmlopt = virDomainXMLOptionNew(&vzDomainDefParserConfig,
|
|
&vzDomainXMLPrivateDataCallbacksPtr,
|
|
NULL, NULL, NULL)) ||
|
|
!(driver->domains = virDomainObjListNew()) ||
|
|
!(driver->domainEventState = virObjectEventStateNew()) ||
|
|
(vzInitVersion(driver) < 0) ||
|
|
(prlsdkConnect(driver) < 0)) {
|
|
virObjectUnref(driver);
|
|
return NULL;
|
|
}
|
|
|
|
driver->hostsysinfo = virSysinfoRead();
|
|
ignore_value(prlsdkLoadDomains(driver));
|
|
|
|
/* As far as waitDomainJob finally calls virReportErrorHelper
|
|
* and we are not going to report it, reset it expicitly*/
|
|
virResetLastError();
|
|
|
|
return driver;
|
|
}
|
|
|
|
static virDrvOpenStatus
|
|
vzConnectOpen(virConnectPtr conn,
|
|
virConnectAuthPtr auth G_GNUC_UNUSED,
|
|
virConfPtr conf G_GNUC_UNUSED,
|
|
unsigned int flags)
|
|
{
|
|
vzDriverPtr driver = NULL;
|
|
vzConnPtr privconn = NULL;
|
|
|
|
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
|
|
|
|
/* From this point on, the connection is for us. */
|
|
if (STRNEQ(conn->uri->path, "/system")) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
_("Unexpected Virtuozzo URI path '%s', try vz:///system"),
|
|
conn->uri->path);
|
|
return VIR_DRV_OPEN_ERROR;
|
|
}
|
|
|
|
if (virConnectOpenEnsureACL(conn) < 0)
|
|
return VIR_DRV_OPEN_ERROR;
|
|
|
|
if (!(driver = vzGetDriverConnection()))
|
|
return VIR_DRV_OPEN_ERROR;
|
|
|
|
if (VIR_ALLOC(privconn) < 0)
|
|
goto error;
|
|
|
|
conn->privateData = privconn;
|
|
privconn->driver = driver;
|
|
|
|
if (!(privconn->closeCallback = virNewConnectCloseCallbackData()))
|
|
goto error;
|
|
|
|
virMutexLock(&vz_driver_lock);
|
|
privconn->next = vz_conn_list;
|
|
vz_conn_list = privconn;
|
|
virMutexUnlock(&vz_driver_lock);
|
|
|
|
return VIR_DRV_OPEN_SUCCESS;
|
|
|
|
error:
|
|
|
|
conn->privateData = NULL;
|
|
virObjectUnref(driver);
|
|
VIR_FREE(privconn);
|
|
return VIR_DRV_OPEN_ERROR;
|
|
}
|
|
|
|
static int
|
|
vzConnectClose(virConnectPtr conn)
|
|
{
|
|
vzConnPtr curr, *prev = &vz_conn_list;
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (!privconn)
|
|
return 0;
|
|
|
|
virMutexLock(&vz_driver_lock);
|
|
for (curr = vz_conn_list; curr; prev = &curr->next, curr = curr->next) {
|
|
if (curr == privconn) {
|
|
*prev = curr->next;
|
|
break;
|
|
}
|
|
}
|
|
|
|
virMutexUnlock(&vz_driver_lock);
|
|
|
|
virObjectUnref(privconn->closeCallback);
|
|
virObjectUnref(privconn->driver);
|
|
VIR_FREE(privconn);
|
|
conn->privateData = NULL;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzConnectGetVersion(virConnectPtr conn, unsigned long *hvVer)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (virConnectGetVersionEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
*hvVer = privconn->driver->vzVersion;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static char *vzConnectGetHostname(virConnectPtr conn)
|
|
{
|
|
if (virConnectGetHostnameEnsureACL(conn) < 0)
|
|
return NULL;
|
|
|
|
return virGetHostname();
|
|
}
|
|
|
|
static char *
|
|
vzConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
vzDriverPtr driver = privconn->driver;
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
if (virConnectGetSysinfoEnsureACL(conn) < 0)
|
|
return NULL;
|
|
|
|
if (!driver->hostsysinfo) {
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
_("Host SMBIOS information is not available"));
|
|
return NULL;
|
|
}
|
|
|
|
if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
|
|
return NULL;
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
}
|
|
|
|
static int
|
|
vzConnectListDomains(virConnectPtr conn, int *ids, int maxids)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (virConnectListDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virDomainObjListGetActiveIDs(privconn->driver->domains, ids,
|
|
maxids, virConnectListDomainsCheckACL,
|
|
conn);
|
|
}
|
|
|
|
static int
|
|
vzConnectNumOfDomains(virConnectPtr conn)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (virConnectNumOfDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virDomainObjListNumOfDomains(privconn->driver->domains, true,
|
|
virConnectNumOfDomainsCheckACL, conn);
|
|
}
|
|
|
|
static int
|
|
vzConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
memset(names, 0, sizeof(*names) * maxnames);
|
|
return virDomainObjListGetInactiveNames(privconn->driver->domains, names,
|
|
maxnames,
|
|
virConnectListDefinedDomainsCheckACL,
|
|
conn);
|
|
}
|
|
|
|
static int
|
|
vzConnectNumOfDefinedDomains(virConnectPtr conn)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virDomainObjListNumOfDomains(privconn->driver->domains, false,
|
|
virConnectNumOfDefinedDomainsCheckACL,
|
|
conn);
|
|
}
|
|
|
|
static int
|
|
vzConnectListAllDomains(virConnectPtr conn,
|
|
virDomainPtr **domains,
|
|
unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
|
|
|
|
if (virConnectListAllDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virDomainObjListExport(privconn->driver->domains, conn, domains,
|
|
virConnectListAllDomainsCheckACL, flags);
|
|
}
|
|
|
|
static virDomainPtr
|
|
vzDomainLookupByID(virConnectPtr conn, int id)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
virDomainPtr ret = NULL;
|
|
virDomainObjPtr dom;
|
|
|
|
dom = virDomainObjListFindByID(privconn->driver->domains, id);
|
|
|
|
if (dom == NULL) {
|
|
virReportError(VIR_ERR_NO_DOMAIN, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
if (virDomainLookupByIDEnsureACL(conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = virGetDomain(conn, dom->def->name, dom->def->uuid, dom->def->id);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static virDomainPtr
|
|
vzDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
virDomainPtr ret = NULL;
|
|
virDomainObjPtr dom;
|
|
|
|
dom = virDomainObjListFindByUUID(privconn->driver->domains, uuid);
|
|
|
|
if (dom == NULL) {
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
virUUIDFormat(uuid, uuidstr);
|
|
virReportError(VIR_ERR_NO_DOMAIN,
|
|
_("no domain with matching uuid '%s'"), uuidstr);
|
|
return NULL;
|
|
}
|
|
|
|
if (virDomainLookupByUUIDEnsureACL(conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = virGetDomain(conn, dom->def->name, dom->def->uuid, dom->def->id);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static virDomainPtr
|
|
vzDomainLookupByName(virConnectPtr conn, const char *name)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
virDomainPtr ret = NULL;
|
|
virDomainObjPtr dom;
|
|
|
|
dom = virDomainObjListFindByName(privconn->driver->domains, name);
|
|
|
|
if (dom == NULL) {
|
|
virReportError(VIR_ERR_NO_DOMAIN,
|
|
_("no domain with matching name '%s'"), name);
|
|
return NULL;
|
|
}
|
|
|
|
if (virDomainLookupByNameEnsureACL(conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = virGetDomain(conn, dom->def->name, dom->def->uuid, dom->def->id);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
|
|
{
|
|
virDomainObjPtr dom;
|
|
vzDomObjPtr privdom;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
goto cleanup;
|
|
|
|
if (virDomainGetInfoEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
info->state = virDomainObjGetState(dom, NULL);
|
|
info->memory = dom->def->mem.cur_balloon;
|
|
info->maxMem = virDomainDefGetMemoryTotal(dom->def);
|
|
info->nrVirtCpu = virDomainDefGetVcpus(dom->def);
|
|
info->cpuTime = 0;
|
|
|
|
privdom = dom->privateData;
|
|
|
|
if (PRL_INVALID_HANDLE != privdom->stats && virDomainObjIsActive(dom)) {
|
|
unsigned long long vtime;
|
|
size_t i;
|
|
|
|
for (i = 0; i < virDomainDefGetVcpus(dom->def); ++i) {
|
|
if (prlsdkGetVcpuStats(privdom->stats, i, &vtime) < 0) {
|
|
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
_("cannot read cputime for domain"));
|
|
goto cleanup;
|
|
}
|
|
info->cpuTime += vtime;
|
|
}
|
|
}
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static char *
|
|
vzDomainGetOSType(virDomainPtr domain)
|
|
{
|
|
virDomainObjPtr dom;
|
|
char *ret = NULL;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return NULL;
|
|
|
|
if (virDomainGetOSTypeEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = g_strdup(virDomainOSTypeToString(dom->def->os.type));
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainIsPersistent(virDomainPtr domain)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainIsPersistentEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 1;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetState(virDomainPtr domain,
|
|
int *state, int *reason, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainGetStateEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
*state = virDomainObjGetState(dom, reason);
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static char *
|
|
vzDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
vzDriverPtr driver = privconn->driver;
|
|
virDomainDefPtr def;
|
|
virDomainObjPtr dom;
|
|
char *ret = NULL;
|
|
|
|
virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return NULL;
|
|
|
|
if (virDomainGetXMLDescEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
def = (flags & VIR_DOMAIN_XML_INACTIVE) &&
|
|
dom->newDef ? dom->newDef : dom->def;
|
|
|
|
ret = virDomainDefFormat(def, driver->xmlopt, flags);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetAutostart(virDomainPtr domain, int *autostart)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainGetAutostartEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
*autostart = dom->autostart;
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzEnsureDomainExists(virDomainObjPtr dom)
|
|
{
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
if (!dom->removing)
|
|
return 0;
|
|
|
|
virUUIDFormat(dom->def->uuid, uuidstr);
|
|
virReportError(VIR_ERR_NO_DOMAIN,
|
|
_("no domain with matching uuid '%s' (%s)"),
|
|
uuidstr, dom->def->name);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static virDomainPtr
|
|
vzDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
virDomainPtr retdom = NULL;
|
|
virDomainDefPtr def;
|
|
virDomainObjPtr dom = NULL;
|
|
unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
|
|
vzDriverPtr driver = privconn->driver;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
|
|
|
|
if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
|
|
parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
|
|
|
|
if ((def = virDomainDefParseString(xml, driver->xmlopt,
|
|
NULL, parse_flags)) == NULL)
|
|
goto cleanup;
|
|
|
|
if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
|
|
goto cleanup;
|
|
|
|
if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
|
|
goto cleanup;
|
|
|
|
dom = virDomainObjListFindByUUID(driver->domains, def->uuid);
|
|
if (dom == NULL) {
|
|
virResetLastError();
|
|
if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
|
|
if (prlsdkCreateVm(driver, def))
|
|
goto cleanup;
|
|
} else if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) {
|
|
if (prlsdkCreateCt(conn, def))
|
|
goto cleanup;
|
|
} else {
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
_("Unsupported OS type: %s"),
|
|
virDomainOSTypeToString(def->os.type));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!(dom = prlsdkAddDomainByUUID(driver, def->uuid)))
|
|
goto cleanup;
|
|
} else {
|
|
int state, reason;
|
|
|
|
state = virDomainObjGetState(dom, &reason);
|
|
|
|
if (state == VIR_DOMAIN_SHUTOFF &&
|
|
reason == VIR_DOMAIN_SHUTOFF_SAVED) {
|
|
|
|
/* PCS doesn't store domain config in managed save state file.
|
|
* It's forbidden to change config for VMs in this state.
|
|
* It's possible to change config for containers, but after
|
|
* restoring domain will have that new config, not a config,
|
|
* which domain had at the moment of virDomainManagedSave.
|
|
*
|
|
* So forbid this operation, if config is changed. If it's
|
|
* not changed - just do nothing. */
|
|
|
|
if (!virDomainDefCheckABIStability(dom->def, def, driver->xmlopt)) {
|
|
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
|
|
_("Can't change domain configuration "
|
|
"in managed save state"));
|
|
goto cleanup;
|
|
}
|
|
} else {
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkApplyConfig(driver, dom, def))
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(driver, dom))
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
retdom = virGetDomain(conn, def->name, def->uuid, def->id);
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
virDomainDefFree(def);
|
|
return retdom;
|
|
}
|
|
|
|
static virDomainPtr
|
|
vzDomainDefineXML(virConnectPtr conn, const char *xml)
|
|
{
|
|
return vzDomainDefineXMLFlags(conn, xml, 0);
|
|
}
|
|
|
|
|
|
static int
|
|
vzNodeGetInfo(virConnectPtr conn,
|
|
virNodeInfoPtr nodeinfo)
|
|
{
|
|
if (virNodeGetInfoEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virCapabilitiesGetNodeInfo(nodeinfo);
|
|
}
|
|
|
|
static int vzConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)
|
|
{
|
|
/* Encryption is not relevant / applicable to way we talk to PCS */
|
|
return 0;
|
|
}
|
|
|
|
static int vzConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)
|
|
{
|
|
/* We run CLI tools directly so this is secure */
|
|
return 1;
|
|
}
|
|
|
|
static int vzConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
static char *
|
|
vzConnectBaselineCPU(virConnectPtr conn,
|
|
const char **xmlCPUs,
|
|
unsigned int ncpus,
|
|
unsigned int flags)
|
|
{
|
|
virCPUDefPtr *cpus = NULL;
|
|
virCPUDefPtr cpu = NULL;
|
|
char *cpustr = NULL;
|
|
|
|
virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
|
|
|
|
if (virConnectBaselineCPUEnsureACL(conn) < 0)
|
|
return NULL;
|
|
|
|
if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST)))
|
|
goto cleanup;
|
|
|
|
if (!(cpu = virCPUBaseline(VIR_ARCH_NONE, cpus, ncpus, NULL, NULL, false)))
|
|
goto cleanup;
|
|
|
|
if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) &&
|
|
virCPUExpandFeatures(cpus[0]->arch, cpu) < 0)
|
|
goto cleanup;
|
|
|
|
cpustr = virCPUDefFormat(cpu, NULL);
|
|
|
|
cleanup:
|
|
virCPUDefListFree(cpus);
|
|
virCPUDefFree(cpu);
|
|
|
|
return cpustr;
|
|
}
|
|
|
|
|
|
static int
|
|
vzDomainGetVcpus(virDomainPtr domain,
|
|
virVcpuInfoPtr info,
|
|
int maxinfo,
|
|
unsigned char *cpumaps,
|
|
int maplen)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
size_t i;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainGetVcpusEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!virDomainObjIsActive(dom)) {
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
"%s",
|
|
_("cannot list vcpu pinning for an inactive domain"));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (maxinfo >= 1) {
|
|
if (info != NULL) {
|
|
vzDomObjPtr privdom;
|
|
|
|
memset(info, 0, sizeof(*info) * maxinfo);
|
|
privdom = dom->privateData;
|
|
|
|
for (i = 0; i < maxinfo; i++) {
|
|
info[i].number = i;
|
|
info[i].state = VIR_VCPU_RUNNING;
|
|
if (prlsdkGetVcpuStats(privdom->stats, i, &info[i].cpuTime) < 0)
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (cpumaps != NULL) {
|
|
memset(cpumaps, 0, maplen * maxinfo);
|
|
for (i = 0; i < maxinfo; i++)
|
|
virBitmapToDataBuf(dom->def->cpumask,
|
|
VIR_GET_CPUMAP(cpumaps, maplen, i),
|
|
maplen);
|
|
}
|
|
}
|
|
ret = maxinfo;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
vzNodeGetCPUMap(virConnectPtr conn,
|
|
unsigned char **cpumap,
|
|
unsigned int *online,
|
|
unsigned int flags)
|
|
{
|
|
if (virNodeGetCPUMapEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virHostCPUGetMap(cpumap, online, flags);
|
|
}
|
|
|
|
static int
|
|
vzConnectDomainEventRegisterAny(virConnectPtr conn,
|
|
virDomainPtr domain,
|
|
int eventID,
|
|
virConnectDomainEventGenericCallback callback,
|
|
void *opaque,
|
|
virFreeCallback freecb)
|
|
{
|
|
int ret = -1;
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
if (virDomainEventStateRegisterID(conn,
|
|
privconn->driver->domainEventState,
|
|
domain, eventID,
|
|
callback, opaque, freecb, &ret) < 0)
|
|
ret = -1;
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzConnectDomainEventDeregisterAny(virConnectPtr conn,
|
|
int callbackID)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
|
|
if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
if (virObjectEventStateDeregisterID(conn,
|
|
privconn->driver->domainEventState,
|
|
callbackID, true) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainSuspend(virDomainPtr domain)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainSuspendEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkPause(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(privconn->driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainResume(virDomainPtr domain)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainResumeEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkResume(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(privconn->driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainCreateWithFlagsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkStart(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(privconn->driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainDestroyFlags(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainDestroyFlagsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkKill(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(privconn->driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainDestroy(virDomainPtr dom)
|
|
{
|
|
return vzDomainDestroyFlags(dom, 0);
|
|
}
|
|
|
|
static int
|
|
vzDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainShutdownFlagsEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkStop(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(privconn->driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainShutdown(virDomainPtr dom)
|
|
{
|
|
return vzDomainShutdownFlags(dom, 0);
|
|
}
|
|
|
|
static int
|
|
vzDomainReboot(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainRebootEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkRestart(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(privconn->driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainIsActive(virDomainPtr domain)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainIsActiveEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = virDomainObjIsActive(dom);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainCreate(virDomainPtr domain)
|
|
{
|
|
return vzDomainCreateWithFlags(domain, 0);
|
|
}
|
|
|
|
static int
|
|
vzDomainUndefineFlags(virDomainPtr domain,
|
|
unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom = NULL;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
|
|
VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainUndefineFlagsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkUnregisterDomain(privconn->driver, dom, flags);
|
|
|
|
cleanup:
|
|
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainUndefine(virDomainPtr domain)
|
|
{
|
|
return vzDomainUndefineFlags(domain, 0);
|
|
}
|
|
|
|
static int
|
|
vzDomainHasManagedSaveImage(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int state, reason;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainHasManagedSaveImageEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
state = virDomainObjGetState(dom, &reason);
|
|
if (state == VIR_DOMAIN_SHUTOFF && reason == VIR_DOMAIN_SHUTOFF_SAVED)
|
|
ret = 1;
|
|
else
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainManagedSave(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom = NULL;
|
|
int state, reason;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
|
|
VIR_DOMAIN_SAVE_PAUSED, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainManagedSaveEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
state = virDomainObjGetState(dom, &reason);
|
|
|
|
if (state == VIR_DOMAIN_RUNNING && (flags & VIR_DOMAIN_SAVE_PAUSED) &&
|
|
prlsdkPause(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkSuspend(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(privconn->driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainManagedSaveRemove(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int state, reason;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainManagedSaveRemoveEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
state = virDomainObjGetState(dom, &reason);
|
|
|
|
if (!(state == VIR_DOMAIN_SHUTOFF && reason == VIR_DOMAIN_SHUTOFF_SAVED))
|
|
goto cleanup;
|
|
|
|
ret = prlsdkDomainManagedSaveRemove(dom);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int vzCheckConfigUpdateFlags(virDomainObjPtr dom, unsigned int *flags)
|
|
{
|
|
if (virDomainObjUpdateModificationImpact(dom, flags) < 0)
|
|
return -1;
|
|
|
|
if (!(*flags & VIR_DOMAIN_AFFECT_CONFIG)) {
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
_("domain config update needs VIR_DOMAIN_AFFECT_CONFIG "
|
|
"flag to be set"));
|
|
return -1;
|
|
}
|
|
|
|
if (virDomainObjIsActive(dom) && !(*flags & VIR_DOMAIN_AFFECT_LIVE)) {
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
_("Updates on a running domain need "
|
|
"VIR_DOMAIN_AFFECT_LIVE flag"));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int vzDomainAttachDeviceFlags(virDomainPtr domain, const char *xml,
|
|
unsigned int flags)
|
|
{
|
|
int ret = -1;
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainDeviceDefPtr dev = NULL;
|
|
virDomainObjPtr dom = NULL;
|
|
vzDriverPtr driver = privconn->driver;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (vzCheckConfigUpdateFlags(dom, &flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (virDomainAttachDeviceFlagsEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
dev = virDomainDeviceDefParse(xml, dom->def,
|
|
driver->xmlopt, NULL, VIR_DOMAIN_XML_INACTIVE);
|
|
if (dev == NULL)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkAttachDevice(driver, dom, dev) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
cleanup:
|
|
virDomainDeviceDefFree(dev);
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainAttachDevice(virDomainPtr domain, const char *xml)
|
|
{
|
|
return vzDomainAttachDeviceFlags(domain, xml,
|
|
VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_LIVE);
|
|
}
|
|
|
|
static int vzDomainDetachDeviceFlags(virDomainPtr domain, const char *xml,
|
|
unsigned int flags)
|
|
{
|
|
int ret = -1;
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainDeviceDefPtr dev = NULL;
|
|
virDomainObjPtr dom = NULL;
|
|
vzDriverPtr driver = privconn->driver;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
|
|
|
dom = vzDomObjFromDomain(domain);
|
|
if (dom == NULL)
|
|
return -1;
|
|
|
|
if (vzCheckConfigUpdateFlags(dom, &flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (virDomainDetachDeviceFlagsEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
dev = virDomainDeviceDefParse(xml, dom->def,
|
|
driver->xmlopt, NULL,
|
|
VIR_DOMAIN_XML_INACTIVE |
|
|
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
|
|
if (dev == NULL)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkDetachDevice(driver, dom, dev) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
cleanup:
|
|
virDomainDeviceDefFree(dev);
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainDetachDevice(virDomainPtr domain, const char *xml)
|
|
{
|
|
return vzDomainDetachDeviceFlags(domain, xml,
|
|
VIR_DOMAIN_AFFECT_CONFIG | VIR_DOMAIN_AFFECT_LIVE);
|
|
}
|
|
|
|
static int
|
|
vzDomainSetUserPassword(virDomainPtr domain,
|
|
const char *user,
|
|
const char *password,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(0, -1);
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainSetUserPasswordEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkDomainSetUserPassword(dom, user, password);
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainUpdateDeviceFlags(virDomainPtr domain,
|
|
const char *xml,
|
|
unsigned int flags)
|
|
{
|
|
int ret = -1;
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
virDomainObjPtr dom = NULL;
|
|
virDomainDeviceDefPtr dev = NULL;
|
|
vzDriverPtr driver = privconn->driver;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainUpdateDeviceFlagsEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzCheckConfigUpdateFlags(dom, &flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(dev = virDomainDeviceDefParse(xml, dom->def,
|
|
driver->xmlopt, NULL,
|
|
VIR_DOMAIN_XML_INACTIVE)))
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDevice(driver, dom, dev) < 0)
|
|
goto cleanup;
|
|
|
|
if (prlsdkUpdateDomain(driver, dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
cleanup:
|
|
|
|
virDomainDeviceDefFree(dev);
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static unsigned long long
|
|
vzDomainGetMaxMemory(virDomainPtr domain)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainGetMaxMemoryEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = virDomainDefGetMemoryTotal(dom->def);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainBlockStatsImpl(virDomainObjPtr dom,
|
|
const char *path,
|
|
virDomainBlockStatsPtr stats)
|
|
{
|
|
vzDomObjPtr privdom = dom->privateData;
|
|
size_t i;
|
|
int idx;
|
|
|
|
if (*path) {
|
|
if ((idx = virDomainDiskIndexByName(dom->def, path, false)) < 0) {
|
|
virReportError(VIR_ERR_INVALID_ARG, _("invalid path: %s"), path);
|
|
return -1;
|
|
}
|
|
if (prlsdkGetBlockStats(privdom->stats,
|
|
dom->def->disks[idx],
|
|
stats,
|
|
IS_CT(dom->def)) < 0)
|
|
return -1;
|
|
} else {
|
|
virDomainBlockStatsStruct s;
|
|
|
|
#define PARALLELS_ZERO_STATS(VAR, TYPE, NAME) \
|
|
stats->VAR = 0;
|
|
|
|
PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_ZERO_STATS)
|
|
|
|
#undef PARALLELS_ZERO_STATS
|
|
|
|
for (i = 0; i < dom->def->ndisks; i++) {
|
|
if (prlsdkGetBlockStats(privdom->stats,
|
|
dom->def->disks[i],
|
|
&s,
|
|
IS_CT(dom->def)) < 0)
|
|
return -1;
|
|
|
|
#define PARALLELS_SUM_STATS(VAR, TYPE, NAME) \
|
|
if (s.VAR != -1) \
|
|
stats->VAR += s.VAR;
|
|
|
|
PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_SUM_STATS)
|
|
|
|
#undef PARALLELS_SUM_STATS
|
|
}
|
|
}
|
|
stats->errs = -1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainBlockStats(virDomainPtr domain,
|
|
const char *path,
|
|
virDomainBlockStatsPtr stats)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainBlockStatsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainBlockStatsImpl(dom, path, stats) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainBlockStatsToParams(virDomainBlockStatsPtr stats,
|
|
virTypedParameterPtr params,
|
|
int *nparams)
|
|
{
|
|
size_t i;
|
|
|
|
if (*nparams == 0) {
|
|
#define PARALLELS_COUNT_STATS(VAR, TYPE, NAME) \
|
|
if ((stats->VAR) != -1) \
|
|
++*nparams;
|
|
|
|
PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_COUNT_STATS)
|
|
|
|
#undef PARALLELS_COUNT_STATS
|
|
return 0;
|
|
}
|
|
|
|
i = 0;
|
|
#define PARALLELS_BLOCK_STATS_ASSIGN_PARAM(VAR, TYPE, NAME) \
|
|
if (i < *nparams && (stats->VAR) != -1) { \
|
|
if (virTypedParameterAssign(params + i, TYPE, \
|
|
VIR_TYPED_PARAM_LLONG, (stats->VAR)) < 0) \
|
|
return -1; \
|
|
i++; \
|
|
}
|
|
|
|
PARALLELS_BLOCK_STATS_FOREACH(PARALLELS_BLOCK_STATS_ASSIGN_PARAM)
|
|
|
|
#undef PARALLELS_BLOCK_STATS_ASSIGN_PARAM
|
|
|
|
*nparams = i;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainBlockStatsFlags(virDomainPtr domain,
|
|
const char *path,
|
|
virTypedParameterPtr params,
|
|
int *nparams,
|
|
unsigned int flags)
|
|
{
|
|
virDomainBlockStatsStruct stats;
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);
|
|
/* We don't return strings, and thus trivially support this flag. */
|
|
flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainBlockStatsFlagsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainBlockStatsImpl(dom, path, &stats) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainBlockStatsToParams(&stats, params, nparams) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainInterfaceStats(virDomainPtr domain,
|
|
const char *device,
|
|
virDomainInterfaceStatsPtr stats)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
vzDomObjPtr privdom;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainInterfaceStatsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
privdom = dom->privateData;
|
|
|
|
ret = prlsdkGetNetStats(privdom->stats, privdom->sdkdom, device, stats);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainMemoryStats(virDomainPtr domain,
|
|
virDomainMemoryStatPtr stats,
|
|
unsigned int nr_stats,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
vzDomObjPtr privdom;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(0, -1);
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainMemoryStatsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
privdom = dom->privateData;
|
|
|
|
ret = prlsdkGetMemoryStats(privdom->stats, stats, nr_stats);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetVcpusFlags(virDomainPtr domain,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
VIR_DOMAIN_AFFECT_CONFIG |
|
|
VIR_DOMAIN_VCPU_MAXIMUM, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainGetVcpusFlagsEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
|
|
ret = virDomainDefGetVcpusMax(dom->def);
|
|
else
|
|
ret = virDomainDefGetVcpus(dom->def);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainGetMaxVcpus(virDomainPtr domain)
|
|
{
|
|
return vzDomainGetVcpusFlags(domain, (VIR_DOMAIN_AFFECT_LIVE |
|
|
VIR_DOMAIN_VCPU_MAXIMUM));
|
|
}
|
|
|
|
static int vzDomainIsUpdated(virDomainPtr domain)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
/* As far as VZ domains are always updated (e.g. current==persistent),
|
|
* we just check for domain existence */
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainIsUpdatedEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int vzConnectGetMaxVcpus(virConnectPtr conn,
|
|
const char *type)
|
|
{
|
|
if (virConnectGetMaxVcpusEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
/* As far as we have no limitation for containers
|
|
* we report maximum */
|
|
if (type == NULL || STRCASEEQ(type, "vz") || STRCASEEQ(type, "parallels"))
|
|
return 1028;
|
|
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
_("unknown type '%s'"), type);
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
vzNodeGetCPUStats(virConnectPtr conn,
|
|
int cpuNum,
|
|
virNodeCPUStatsPtr params,
|
|
int *nparams,
|
|
unsigned int flags)
|
|
{
|
|
if (virNodeGetCPUStatsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virHostCPUGetStats(cpuNum, params, nparams, flags);
|
|
}
|
|
|
|
static int
|
|
vzNodeGetMemoryStats(virConnectPtr conn,
|
|
int cellNum,
|
|
virNodeMemoryStatsPtr params,
|
|
int *nparams,
|
|
unsigned int flags)
|
|
{
|
|
if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virHostMemGetStats(cellNum, params, nparams, flags);
|
|
}
|
|
|
|
static int
|
|
vzNodeGetCellsFreeMemory(virConnectPtr conn,
|
|
unsigned long long *freeMems,
|
|
int startCell,
|
|
int maxCells)
|
|
{
|
|
if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
return virHostMemGetCellsFree(freeMems, startCell, maxCells);
|
|
}
|
|
|
|
static unsigned long long
|
|
vzNodeGetFreeMemory(virConnectPtr conn)
|
|
{
|
|
unsigned long long freeMem;
|
|
|
|
if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
if (virHostMemGetInfo(NULL, &freeMem) < 0)
|
|
return 0;
|
|
return freeMem;
|
|
}
|
|
|
|
static int
|
|
vzConnectRegisterCloseCallback(virConnectPtr conn,
|
|
virConnectCloseFunc cb,
|
|
void *opaque,
|
|
virFreeCallback freecb)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
int ret = -1;
|
|
|
|
if (virConnectRegisterCloseCallbackEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
virObjectLock(privconn->driver);
|
|
|
|
if (virConnectCloseCallbackDataGetCallback(privconn->closeCallback) != NULL) {
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
_("A close callback is already registered"));
|
|
goto cleanup;
|
|
}
|
|
|
|
virConnectCloseCallbackDataRegister(privconn->closeCallback, conn, cb,
|
|
opaque, freecb);
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virObjectUnlock(privconn->driver);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzConnectUnregisterCloseCallback(virConnectPtr conn, virConnectCloseFunc cb)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
int ret = -1;
|
|
|
|
if (virConnectUnregisterCloseCallbackEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
virObjectLock(privconn->driver);
|
|
|
|
if (virConnectCloseCallbackDataGetCallback(privconn->closeCallback) != cb) {
|
|
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
|
|
_("A different callback was requested"));
|
|
goto cleanup;
|
|
}
|
|
|
|
virConnectCloseCallbackDataUnregister(privconn->closeCallback, cb);
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virObjectUnlock(privconn->driver);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainSetMemoryFlags(virDomainPtr domain, unsigned long memory,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (vzCheckConfigUpdateFlags(dom, &flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (virDomainSetMemoryFlagsEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkSetMemsize(dom, memory >> 10);
|
|
|
|
cleanup:
|
|
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainSetMemory(virDomainPtr domain, unsigned long memory)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainSetMemoryEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkSetMemsize(dom, memory >> 10);
|
|
|
|
cleanup:
|
|
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static virDomainMomentObjPtr
|
|
vzSnapObjFromName(virDomainSnapshotObjListPtr snapshots, const char *name)
|
|
{
|
|
virDomainMomentObjPtr snap = NULL;
|
|
snap = virDomainSnapshotFindByName(snapshots, name);
|
|
if (!snap)
|
|
virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
|
|
_("no domain snapshot with matching name '%s'"), name);
|
|
|
|
return snap;
|
|
}
|
|
|
|
static virDomainMomentObjPtr
|
|
vzSnapObjFromSnapshot(virDomainSnapshotObjListPtr snapshots,
|
|
virDomainSnapshotPtr snapshot)
|
|
{
|
|
return vzSnapObjFromName(snapshots, snapshot->name);
|
|
}
|
|
|
|
static int
|
|
vzDomainSnapshotNum(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
int n = -1;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainSnapshotNumEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
n = virDomainSnapshotObjListNum(snapshots, NULL, flags);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
vzDomainSnapshotListNames(virDomainPtr domain,
|
|
char **names,
|
|
int nameslen,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
int n = -1;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainSnapshotListNamesEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
n = virDomainSnapshotObjListGetNames(snapshots, NULL, names, nameslen, flags);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
vzDomainListAllSnapshots(virDomainPtr domain,
|
|
virDomainSnapshotPtr **snaps,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
int n = -1;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainListAllSnapshotsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
n = virDomainListSnapshots(snapshots, NULL, domain, snaps, flags);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return n;
|
|
}
|
|
|
|
static char *
|
|
vzDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
char *xml = NULL;
|
|
virDomainMomentObjPtr snap;
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
vzConnPtr privconn = snapshot->domain->conn->privateData;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_XML_SECURE, NULL);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return NULL;
|
|
|
|
if (virDomainSnapshotGetXMLDescEnsureACL(snapshot->domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
|
|
goto cleanup;
|
|
|
|
virUUIDFormat(snapshot->domain->uuid, uuidstr);
|
|
|
|
xml = virDomainSnapshotDefFormat(uuidstr, virDomainSnapshotObjGetDef(snap),
|
|
privconn->driver->xmlopt,
|
|
virDomainSnapshotFormatConvertXMLFlags(flags));
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return xml;
|
|
}
|
|
|
|
static int
|
|
vzDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainMomentObjPtr snap;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
int n = -1;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return -1;
|
|
|
|
if (virDomainSnapshotNumChildrenEnsureACL(snapshot->domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
|
|
goto cleanup;
|
|
|
|
n = virDomainSnapshotObjListNum(snapshots, snap, flags);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
vzDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
|
|
char **names,
|
|
int nameslen,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainMomentObjPtr snap;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
int n = -1;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return -1;
|
|
|
|
if (virDomainSnapshotListChildrenNamesEnsureACL(snapshot->domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
|
|
goto cleanup;
|
|
|
|
n = virDomainSnapshotObjListGetNames(snapshots, snap, names, nameslen, flags);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
vzDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
|
|
virDomainSnapshotPtr **snaps,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainMomentObjPtr snap;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
int n = -1;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
|
|
VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return -1;
|
|
|
|
if (virDomainSnapshotListAllChildrenEnsureACL(snapshot->domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
|
|
goto cleanup;
|
|
|
|
n = virDomainListSnapshots(snapshots, snap, snapshot->domain, snaps, flags);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return n;
|
|
}
|
|
|
|
static virDomainSnapshotPtr
|
|
vzDomainSnapshotLookupByName(virDomainPtr domain,
|
|
const char *name,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainMomentObjPtr snap;
|
|
virDomainSnapshotPtr snapshot = NULL;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return NULL;
|
|
|
|
if (virDomainSnapshotLookupByNameEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(snap = vzSnapObjFromName(snapshots, name)))
|
|
goto cleanup;
|
|
|
|
snapshot = virGetDomainSnapshot(domain, snap->def->name);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
|
|
return snapshot;
|
|
}
|
|
|
|
static int
|
|
vzDomainHasCurrentSnapshot(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainHasCurrentSnapshotEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
ret = virDomainSnapshotGetCurrent(snapshots) != NULL;
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static virDomainSnapshotPtr
|
|
vzDomainSnapshotGetParent(virDomainSnapshotPtr snapshot, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainMomentObjPtr snap;
|
|
virDomainSnapshotPtr parent = NULL;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return NULL;
|
|
|
|
if (virDomainSnapshotGetParentEnsureACL(snapshot->domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
|
|
goto cleanup;
|
|
|
|
if (!snap->def->parent_name) {
|
|
virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
|
|
_("snapshot '%s' does not have a parent"),
|
|
snap->def->name);
|
|
goto cleanup;
|
|
}
|
|
|
|
parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent_name);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return parent;
|
|
}
|
|
|
|
static virDomainSnapshotPtr
|
|
vzDomainSnapshotCurrent(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
virDomainSnapshotPtr snapshot = NULL;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
virDomainMomentObjPtr current;
|
|
|
|
virCheckFlags(0, NULL);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return NULL;
|
|
|
|
if (virDomainSnapshotCurrentEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(current = virDomainSnapshotGetCurrent(snapshots))) {
|
|
virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
|
|
_("the domain does not have a current snapshot"));
|
|
goto cleanup;
|
|
}
|
|
|
|
snapshot = virGetDomainSnapshot(domain, current->def->name);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return snapshot;
|
|
}
|
|
|
|
static int
|
|
vzDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
virDomainMomentObjPtr current;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return -1;
|
|
|
|
if (virDomainSnapshotIsCurrentEnsureACL(snapshot->domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
current = virDomainSnapshotGetCurrent(snapshots);
|
|
ret = current && STREQ(snapshot->name, current->def->name);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
virDomainMomentObjPtr snap;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return -1;
|
|
|
|
if (virDomainSnapshotHasMetadataEnsureACL(snapshot->domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(snap = vzSnapObjFromSnapshot(snapshots, snapshot)))
|
|
goto cleanup;
|
|
|
|
ret = 1;
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static virDomainSnapshotPtr
|
|
vzDomainSnapshotCreateXML(virDomainPtr domain,
|
|
const char *xmlDesc,
|
|
unsigned int flags)
|
|
{
|
|
virDomainSnapshotPtr snapshot = NULL;
|
|
virDomainObjPtr dom;
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
vzDriverPtr driver = privconn->driver;
|
|
unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
|
|
virDomainSnapshotObjListPtr snapshots = NULL;
|
|
virDomainMomentObjPtr current;
|
|
bool job = false;
|
|
g_autoptr(virDomainSnapshotDef) def = NULL;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE, NULL);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return NULL;
|
|
|
|
if (virDomainSnapshotCreateXMLEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE)
|
|
parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_VALIDATE;
|
|
|
|
if (!(def = virDomainSnapshotDefParseString(xmlDesc,
|
|
driver->xmlopt, NULL, NULL,
|
|
parse_flags)))
|
|
goto cleanup;
|
|
|
|
if (def->ndisks > 0) {
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
_("configuring disks is not supported for vz snapshots"));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (def->memory) {
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
_("configuring memory location is not supported"));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
/* snaphot name is ignored, it will be set to auto generated by sdk uuid */
|
|
if (prlsdkCreateSnapshot(dom, def->parent.description) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(snapshots = prlsdkLoadSnapshots(dom)))
|
|
goto cleanup;
|
|
|
|
if (!(current = virDomainSnapshotGetCurrent(snapshots))) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
_("can't find created snapshot"));
|
|
goto cleanup;
|
|
}
|
|
|
|
/* hopefully new current snapshot is newly created one */
|
|
snapshot = virGetDomainSnapshot(domain, current->def->name);
|
|
|
|
cleanup:
|
|
virDomainSnapshotObjListFree(snapshots);
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return snapshot;
|
|
}
|
|
|
|
static int
|
|
vzDomainSnapshotDelete(virDomainSnapshotPtr snapshot, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return -1;
|
|
|
|
if (virDomainSnapshotDeleteEnsureACL(snapshot->domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkDeleteSnapshot(dom, snapshot->name,
|
|
flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(snapshot->domain)))
|
|
return -1;
|
|
|
|
if (virDomainRevertToSnapshotEnsureACL(snapshot->domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkSwitchToSnapshot(dom, snapshot->name,
|
|
flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED);
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
enum vzMigrationCookieFeatures {
|
|
VZ_MIGRATION_COOKIE_SESSION_UUID = (1 << 0),
|
|
VZ_MIGRATION_COOKIE_DOMAIN_UUID = (1 << 1),
|
|
VZ_MIGRATION_COOKIE_DOMAIN_NAME = (1 << 1),
|
|
};
|
|
|
|
typedef struct _vzMigrationCookie vzMigrationCookie;
|
|
typedef vzMigrationCookie *vzMigrationCookiePtr;
|
|
struct _vzMigrationCookie {
|
|
unsigned char *session_uuid;
|
|
unsigned char *uuid;
|
|
char *name;
|
|
};
|
|
|
|
static void
|
|
vzMigrationCookieFree(vzMigrationCookiePtr mig)
|
|
{
|
|
if (!mig)
|
|
return;
|
|
|
|
VIR_FREE(mig->session_uuid);
|
|
VIR_FREE(mig->uuid);
|
|
VIR_FREE(mig->name);
|
|
VIR_FREE(mig);
|
|
}
|
|
|
|
static int
|
|
vzBakeCookie(vzDriverPtr driver,
|
|
virDomainObjPtr dom,
|
|
char **cookieout, int *cookieoutlen,
|
|
unsigned int flags)
|
|
{
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
if (!cookieout || !cookieoutlen) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
_("Migration cookie parameters are not provided."));
|
|
return -1;
|
|
}
|
|
|
|
*cookieout = NULL;
|
|
*cookieoutlen = 0;
|
|
|
|
virBufferAddLit(&buf, "<vz-migration>\n");
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
if (flags & VZ_MIGRATION_COOKIE_SESSION_UUID) {
|
|
virUUIDFormat(driver->session_uuid, uuidstr);
|
|
virBufferAsprintf(&buf, "<session-uuid>%s</session-uuid>\n", uuidstr);
|
|
}
|
|
|
|
if (flags & VZ_MIGRATION_COOKIE_DOMAIN_UUID) {
|
|
unsigned char fakeuuid[VIR_UUID_BUFLEN] = { 0 };
|
|
|
|
/* if dom is NULL just pass some parsable uuid for backward compat.
|
|
* It is not used by peer */
|
|
virUUIDFormat(dom ? dom->def->uuid : fakeuuid, uuidstr);
|
|
virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", uuidstr);
|
|
}
|
|
|
|
if (flags & VZ_MIGRATION_COOKIE_DOMAIN_NAME) {
|
|
/* if dom is NULL just pass some name for backward compat.
|
|
* It is not used by peer */
|
|
virBufferAsprintf(&buf, "<name>%s</name>\n", dom ? dom->def->name :
|
|
"__fakename__");
|
|
}
|
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
virBufferAddLit(&buf, "</vz-migration>\n");
|
|
|
|
*cookieout = virBufferContentAndReset(&buf);
|
|
*cookieoutlen = strlen(*cookieout) + 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static vzMigrationCookiePtr
|
|
vzEatCookie(const char *cookiein, int cookieinlen, unsigned int flags)
|
|
{
|
|
xmlDocPtr doc = NULL;
|
|
xmlXPathContextPtr ctx = NULL;
|
|
char *tmp = NULL;
|
|
vzMigrationCookiePtr mig = NULL;
|
|
|
|
if (VIR_ALLOC(mig) < 0)
|
|
return NULL;
|
|
|
|
if (!cookiein || cookieinlen <= 0 || cookiein[cookieinlen - 1] != '\0') {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
_("Invalid migration cookie"));
|
|
goto error;
|
|
}
|
|
|
|
if (!(doc = virXMLParseStringCtxt(cookiein,
|
|
_("(_migration_cookie)"), &ctx)))
|
|
goto error;
|
|
|
|
if ((flags & VZ_MIGRATION_COOKIE_SESSION_UUID)
|
|
&& (!(tmp = virXPathString("string(./session-uuid[1])", ctx))
|
|
|| (VIR_ALLOC_N(mig->session_uuid, VIR_UUID_BUFLEN) < 0)
|
|
|| (virUUIDParse(tmp, mig->session_uuid) < 0))) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
_("missing or malformed session-uuid element "
|
|
"in migration data"));
|
|
VIR_FREE(tmp);
|
|
goto error;
|
|
}
|
|
VIR_FREE(tmp);
|
|
|
|
if ((flags & VZ_MIGRATION_COOKIE_DOMAIN_UUID)
|
|
&& (!(tmp = virXPathString("string(./uuid[1])", ctx))
|
|
|| (VIR_ALLOC_N(mig->uuid, VIR_UUID_BUFLEN) < 0)
|
|
|| (virUUIDParse(tmp, mig->uuid) < 0))) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
_("missing or malformed uuid element in migration data"));
|
|
VIR_FREE(tmp);
|
|
goto error;
|
|
}
|
|
VIR_FREE(tmp);
|
|
|
|
if ((flags & VZ_MIGRATION_COOKIE_DOMAIN_NAME)
|
|
&& !(mig->name = virXPathString("string(./name[1])", ctx))) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
_("missing name element in migration data"));
|
|
goto error;
|
|
}
|
|
|
|
cleanup:
|
|
xmlXPathFreeContext(ctx);
|
|
xmlFreeDoc(doc);
|
|
return mig;
|
|
|
|
error:
|
|
vzMigrationCookieFree(mig);
|
|
mig = NULL;
|
|
goto cleanup;
|
|
}
|
|
|
|
#define VZ_MIGRATION_FLAGS (VIR_MIGRATE_PAUSED | \
|
|
VIR_MIGRATE_PEER2PEER | \
|
|
VIR_MIGRATE_LIVE | \
|
|
VIR_MIGRATE_UNDEFINE_SOURCE | \
|
|
VIR_MIGRATE_PERSIST_DEST | \
|
|
VIR_MIGRATE_NON_SHARED_INC)
|
|
|
|
#define VZ_MIGRATION_PARAMETERS \
|
|
VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \
|
|
VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \
|
|
VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \
|
|
VIR_MIGRATE_PARAM_BANDWIDTH, VIR_TYPED_PARAM_ULLONG, \
|
|
NULL
|
|
|
|
static char *
|
|
vzDomainMigrateBeginStep(virDomainObjPtr dom,
|
|
vzDriverPtr driver,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
char **cookieout,
|
|
int *cookieoutlen)
|
|
{
|
|
/* we can't do this check via VZ_MIGRATION_PARAMETERS as on preparation
|
|
* step domain xml will be passed via this parameter and it is a common
|
|
* style to use single allowed parameter list definition in all steps */
|
|
if (virTypedParamsGet(params, nparams, VIR_MIGRATE_PARAM_DEST_XML)) {
|
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
|
_("Changing destination XML is not supported"));
|
|
return NULL;
|
|
}
|
|
|
|
/* session uuid, domain uuid and domain name are for backward compat */
|
|
if (vzBakeCookie(driver, dom, cookieout, cookieoutlen,
|
|
VZ_MIGRATION_COOKIE_SESSION_UUID
|
|
| VZ_MIGRATION_COOKIE_DOMAIN_UUID
|
|
| VZ_MIGRATION_COOKIE_DOMAIN_NAME) < 0)
|
|
return NULL;
|
|
|
|
return virDomainDefFormat(dom->def, driver->xmlopt,
|
|
VIR_DOMAIN_XML_MIGRATABLE);
|
|
}
|
|
|
|
static char *
|
|
vzDomainMigrateBegin3Params(virDomainPtr domain,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
char **cookieout,
|
|
int *cookieoutlen,
|
|
unsigned int flags)
|
|
{
|
|
char *xml = NULL;
|
|
virDomainObjPtr dom = NULL;
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
unsigned long long bandwidth = 0;
|
|
|
|
virCheckFlags(VZ_MIGRATION_FLAGS, NULL);
|
|
|
|
if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0)
|
|
goto cleanup;
|
|
|
|
if (virTypedParamsGetULLong(params, nparams, VIR_MIGRATE_PARAM_BANDWIDTH,
|
|
&bandwidth) < 0)
|
|
goto cleanup;
|
|
|
|
if (bandwidth > 0) {
|
|
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
|
|
_("Bandwidth rate limiting is not supported"));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
goto cleanup;
|
|
|
|
if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
xml = vzDomainMigrateBeginStep(dom, privconn->driver, params, nparams,
|
|
cookieout, cookieoutlen);
|
|
|
|
cleanup:
|
|
|
|
virDomainObjEndAPI(&dom);
|
|
return xml;
|
|
}
|
|
|
|
static char*
|
|
vzMigrationCreateURI(void)
|
|
{
|
|
char *hostname = NULL;
|
|
char *uri = NULL;
|
|
|
|
if (!(hostname = virGetHostname()))
|
|
goto cleanup;
|
|
|
|
if (STRPREFIX(hostname, "localhost")) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
_("hostname on destination resolved to localhost,"
|
|
" but migration requires an FQDN"));
|
|
goto cleanup;
|
|
}
|
|
|
|
uri = g_strdup_printf("vzmigr://%s", hostname);
|
|
|
|
cleanup:
|
|
VIR_FREE(hostname);
|
|
return uri;
|
|
}
|
|
|
|
static int
|
|
vzDomainMigratePrepare3Params(virConnectPtr conn,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
const char *cookiein G_GNUC_UNUSED,
|
|
int cookieinlen G_GNUC_UNUSED,
|
|
char **cookieout,
|
|
int *cookieoutlen,
|
|
char **uri_out,
|
|
unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
vzDriverPtr driver = privconn->driver;
|
|
const char *miguri = NULL;
|
|
const char *dname = NULL;
|
|
const char *dom_xml = NULL;
|
|
virDomainDefPtr def = NULL;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(VZ_MIGRATION_FLAGS, -1);
|
|
|
|
if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0)
|
|
goto cleanup;
|
|
|
|
if (virTypedParamsGetString(params, nparams,
|
|
VIR_MIGRATE_PARAM_URI, &miguri) < 0 ||
|
|
virTypedParamsGetString(params, nparams,
|
|
VIR_MIGRATE_PARAM_DEST_XML, &dom_xml) < 0 ||
|
|
virTypedParamsGetString(params, nparams,
|
|
VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0)
|
|
goto cleanup;
|
|
|
|
/* We must set uri_out if miguri is not set. This is direct
|
|
* managed migration requirement */
|
|
if (!miguri && !(*uri_out = vzMigrationCreateURI()))
|
|
goto cleanup;
|
|
|
|
/* domain uuid and domain name are for backward compat */
|
|
if (vzBakeCookie(privconn->driver, NULL,
|
|
cookieout, cookieoutlen,
|
|
VZ_MIGRATION_COOKIE_SESSION_UUID
|
|
| VZ_MIGRATION_COOKIE_DOMAIN_UUID
|
|
| VZ_MIGRATION_COOKIE_DOMAIN_NAME) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(def = virDomainDefParseString(dom_xml, driver->xmlopt,
|
|
NULL,
|
|
VIR_DOMAIN_DEF_PARSE_INACTIVE)))
|
|
goto cleanup;
|
|
|
|
if (dname) {
|
|
VIR_FREE(def->name);
|
|
def->name = g_strdup(dname);
|
|
}
|
|
|
|
if (virDomainMigratePrepare3ParamsEnsureACL(conn, def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainDefFree(def);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzConnectSupportsFeature(virConnectPtr conn G_GNUC_UNUSED, int feature)
|
|
{
|
|
if (virConnectSupportsFeatureEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
switch ((virDrvFeature) feature) {
|
|
case VIR_DRV_FEATURE_MIGRATION_PARAMS:
|
|
case VIR_DRV_FEATURE_MIGRATION_P2P:
|
|
return 1;
|
|
case VIR_DRV_FEATURE_FD_PASSING:
|
|
case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
|
|
case VIR_DRV_FEATURE_MIGRATION_DIRECT:
|
|
case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
|
|
case VIR_DRV_FEATURE_MIGRATION_V1:
|
|
case VIR_DRV_FEATURE_MIGRATION_V2:
|
|
case VIR_DRV_FEATURE_MIGRATION_V3:
|
|
case VIR_DRV_FEATURE_PROGRAM_KEEPALIVE:
|
|
case VIR_DRV_FEATURE_REMOTE:
|
|
case VIR_DRV_FEATURE_REMOTE_CLOSE_CALLBACK:
|
|
case VIR_DRV_FEATURE_REMOTE_EVENT_CALLBACK:
|
|
case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
|
|
case VIR_DRV_FEATURE_XML_MIGRATABLE:
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static virURIPtr
|
|
vzParseVzURI(const char *uri_str)
|
|
{
|
|
virURIPtr uri = NULL;
|
|
|
|
if (!(uri = virURIParse(uri_str)))
|
|
goto error;
|
|
|
|
if (!uri->scheme || !uri->server) {
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
_("scheme and host are mandatory vz migration URI: %s"),
|
|
uri_str);
|
|
goto error;
|
|
}
|
|
|
|
if (uri->user || uri->path || uri->query || uri->fragment) {
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
_("only scheme, host and port are supported in "
|
|
"vz migration URI: %s"), uri_str);
|
|
goto error;
|
|
}
|
|
|
|
if (STRNEQ(uri->scheme, "vzmigr")) {
|
|
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
|
|
_("unsupported scheme %s in migration URI %s"),
|
|
uri->scheme, uri_str);
|
|
goto error;
|
|
}
|
|
|
|
return uri;
|
|
|
|
error:
|
|
virURIFree(uri);
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
vzDomainMigratePerformStep(virDomainObjPtr dom,
|
|
vzDriverPtr driver,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
const char *cookiein,
|
|
int cookieinlen,
|
|
unsigned int flags)
|
|
{
|
|
int ret = -1;
|
|
vzDomObjPtr privdom = dom->privateData;
|
|
virURIPtr vzuri = NULL;
|
|
const char *miguri = NULL;
|
|
const char *dname = NULL;
|
|
vzMigrationCookiePtr mig = NULL;
|
|
bool job = false;
|
|
|
|
if (virTypedParamsGetString(params, nparams,
|
|
VIR_MIGRATE_PARAM_URI, &miguri) < 0 ||
|
|
virTypedParamsGetString(params, nparams,
|
|
VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0)
|
|
goto cleanup;
|
|
|
|
if (!miguri) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
_("migrate uri is not set"));
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!(mig = vzEatCookie(cookiein, cookieinlen,
|
|
VZ_MIGRATION_COOKIE_SESSION_UUID)))
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
privdom->job.hasProgress = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(vzuri = vzParseVzURI(miguri)))
|
|
goto cleanup;
|
|
|
|
if (prlsdkMigrate(dom, vzuri, mig->session_uuid, dname, flags) < 0)
|
|
goto cleanup;
|
|
|
|
virDomainObjListRemove(driver->domains, dom);
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virURIFree(vzuri);
|
|
vzMigrationCookieFree(mig);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainMigratePerformP2P(virDomainObjPtr dom,
|
|
vzDriverPtr driver,
|
|
const char *dconnuri,
|
|
virTypedParameterPtr orig_params,
|
|
int nparams,
|
|
unsigned int flags)
|
|
{
|
|
virDomainPtr ddomain = NULL;
|
|
char *uri = NULL;
|
|
char *cookiein = NULL;
|
|
char *cookieout = NULL;
|
|
char *dom_xml = NULL;
|
|
int cookieinlen = 0;
|
|
int cookieoutlen = 0;
|
|
virErrorPtr orig_err = NULL;
|
|
int cancelled = 1;
|
|
virConnectPtr dconn = NULL;
|
|
virTypedParameterPtr params = NULL;
|
|
int ret = -1;
|
|
int maxparams = nparams;
|
|
|
|
if (virTypedParamsCopy(¶ms, orig_params, nparams) < 0)
|
|
return -1;
|
|
|
|
if (!(dconn = virConnectOpen(dconnuri)))
|
|
goto done;
|
|
|
|
if (!(dom_xml = vzDomainMigrateBeginStep(dom, driver, params, nparams,
|
|
&cookieout, &cookieoutlen)))
|
|
goto done;
|
|
|
|
if (virTypedParamsAddString(¶ms, &nparams, &maxparams,
|
|
VIR_MIGRATE_PARAM_DEST_XML, dom_xml) < 0)
|
|
goto done;
|
|
|
|
cookiein = g_steal_pointer(&cookieout);
|
|
cookieinlen = cookieoutlen;
|
|
cookieoutlen = 0;
|
|
virObjectUnlock(dom);
|
|
ret = dconn->driver->domainMigratePrepare3Params
|
|
(dconn, params, nparams, cookiein, cookieinlen,
|
|
&cookieout, &cookieoutlen, &uri, flags);
|
|
virObjectLock(dom);
|
|
if (ret < 0)
|
|
goto done;
|
|
ret = -1;
|
|
|
|
/* preparation step was successful, thus on any error we must perform
|
|
* finish step to finalize migration on target
|
|
*/
|
|
if (uri && virTypedParamsReplaceString(¶ms, &nparams,
|
|
VIR_MIGRATE_PARAM_URI, uri) < 0) {
|
|
virErrorPreserveLast(&orig_err);
|
|
goto finish;
|
|
}
|
|
|
|
VIR_FREE(cookiein);
|
|
cookiein = g_steal_pointer(&cookieout);
|
|
cookieinlen = cookieoutlen;
|
|
cookieoutlen = 0;
|
|
if (vzDomainMigratePerformStep(dom, driver, params, nparams, cookiein,
|
|
cookieinlen, flags) < 0) {
|
|
virErrorPreserveLast(&orig_err);
|
|
goto finish;
|
|
}
|
|
|
|
cancelled = 0;
|
|
|
|
finish:
|
|
if (virTypedParamsGetString(params, nparams,
|
|
VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 &&
|
|
virTypedParamsReplaceString(¶ms, &nparams,
|
|
VIR_MIGRATE_PARAM_DEST_NAME,
|
|
dom->def->name) < 0)
|
|
goto done;
|
|
|
|
virObjectUnlock(dom);
|
|
ddomain = dconn->driver->domainMigrateFinish3Params(dconn, params, nparams,
|
|
NULL, 0, NULL, NULL,
|
|
flags, cancelled);
|
|
virObjectLock(dom);
|
|
if (ddomain)
|
|
ret = 0;
|
|
virObjectUnref(ddomain);
|
|
|
|
/* confirm step is NOOP thus no need to call it */
|
|
|
|
done:
|
|
virErrorRestore(&orig_err);
|
|
VIR_FREE(dom_xml);
|
|
VIR_FREE(uri);
|
|
VIR_FREE(cookiein);
|
|
VIR_FREE(cookieout);
|
|
virTypedParamsFree(params, nparams);
|
|
virObjectUnref(dconn);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainMigratePerform3Params(virDomainPtr domain,
|
|
const char *dconnuri,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
const char *cookiein,
|
|
int cookieinlen,
|
|
char **cookieout G_GNUC_UNUSED,
|
|
int *cookieoutlen G_GNUC_UNUSED,
|
|
unsigned int flags)
|
|
{
|
|
int ret = -1;
|
|
virDomainObjPtr dom;
|
|
vzConnPtr privconn = domain->conn->privateData;
|
|
|
|
virCheckFlags(VZ_MIGRATION_FLAGS, -1);
|
|
|
|
if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0)
|
|
return -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainMigratePerform3ParamsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (flags & VIR_MIGRATE_PEER2PEER)
|
|
ret = vzDomainMigratePerformP2P(dom, privconn->driver, dconnuri,
|
|
params, nparams, flags);
|
|
else
|
|
ret = vzDomainMigratePerformStep(dom, privconn->driver, params, nparams,
|
|
cookiein, cookieinlen, flags);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static virDomainPtr
|
|
vzDomainMigrateFinish3Params(virConnectPtr dconn,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
const char *cookiein G_GNUC_UNUSED,
|
|
int cookieinlen G_GNUC_UNUSED,
|
|
char **cookieout G_GNUC_UNUSED,
|
|
int *cookieoutlen G_GNUC_UNUSED,
|
|
unsigned int flags,
|
|
int cancelled)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
virDomainPtr domain = NULL;
|
|
vzConnPtr privconn = dconn->privateData;
|
|
vzDriverPtr driver = privconn->driver;
|
|
const char *name = NULL;
|
|
|
|
virCheckFlags(VZ_MIGRATION_FLAGS, NULL);
|
|
|
|
if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0)
|
|
return NULL;
|
|
|
|
if (cancelled)
|
|
return NULL;
|
|
|
|
if (virTypedParamsGetString(params, nparams,
|
|
VIR_MIGRATE_PARAM_DEST_NAME, &name) < 0)
|
|
return NULL;
|
|
|
|
|
|
if (!(dom = prlsdkAddDomainByName(driver, name)))
|
|
goto cleanup;
|
|
|
|
/* At first glace at may look strange that we add domain and
|
|
* then check ACL but we touch only cache and not real system state */
|
|
if (virDomainMigrateFinish3ParamsEnsureACL(dconn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
domain = virGetDomain(dconn, dom->def->name, dom->def->uuid, dom->def->id);
|
|
|
|
cleanup:
|
|
/* In this situation we have to restore domain on source. But the migration
|
|
* is already finished. */
|
|
if (!domain)
|
|
VIR_WARN("Can't provide domain '%s' after successful migration.", name);
|
|
virDomainObjEndAPI(&dom);
|
|
return domain;
|
|
}
|
|
|
|
static int
|
|
vzDomainMigrateConfirm3Params(virDomainPtr domain G_GNUC_UNUSED,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
const char *cookiein G_GNUC_UNUSED,
|
|
int cookieinlen G_GNUC_UNUSED,
|
|
unsigned int flags,
|
|
int cancelled G_GNUC_UNUSED)
|
|
{
|
|
virCheckFlags(VZ_MIGRATION_FLAGS, -1);
|
|
|
|
if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetJobInfoImpl(virDomainObjPtr dom, virDomainJobInfoPtr info)
|
|
{
|
|
vzDomObjPtr privdom = dom->privateData;
|
|
vzDomainJobObjPtr job = &privdom->job;
|
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
if (!job->active || !job->hasProgress)
|
|
return 0;
|
|
|
|
if (vzDomainJobUpdateTime(job) < 0)
|
|
return -1;
|
|
|
|
info->type = VIR_DOMAIN_JOB_UNBOUNDED;
|
|
info->dataTotal = 100;
|
|
info->dataProcessed = job->progress;
|
|
info->dataRemaining = 100 - job->progress;
|
|
info->timeElapsed = job->elapsed;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetJobInfo(virDomainPtr domain, virDomainJobInfoPtr info)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainGetJobInfoEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = vzDomainGetJobInfoImpl(dom, info);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainJobInfoToParams(virDomainJobInfoPtr info,
|
|
int *type,
|
|
virTypedParameterPtr *params,
|
|
int *nparams)
|
|
{
|
|
virTypedParameterPtr par = NULL;
|
|
int maxpar = 0;
|
|
int npar = 0;
|
|
|
|
if (virTypedParamsAddULLong(&par, &npar, &maxpar,
|
|
VIR_DOMAIN_JOB_TIME_ELAPSED,
|
|
info->timeElapsed) < 0 ||
|
|
virTypedParamsAddULLong(&par, &npar, &maxpar,
|
|
VIR_DOMAIN_JOB_DATA_TOTAL,
|
|
info->dataTotal) < 0 ||
|
|
virTypedParamsAddULLong(&par, &npar, &maxpar,
|
|
VIR_DOMAIN_JOB_DATA_PROCESSED,
|
|
info->dataProcessed) < 0 ||
|
|
virTypedParamsAddULLong(&par, &npar, &maxpar,
|
|
VIR_DOMAIN_JOB_DATA_REMAINING,
|
|
info->dataRemaining) < 0)
|
|
goto error;
|
|
|
|
|
|
*type = info->type;
|
|
*params = par;
|
|
*nparams = npar;
|
|
return 0;
|
|
|
|
error:
|
|
virTypedParamsFree(par, npar);
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetJobStats(virDomainPtr domain,
|
|
int *type,
|
|
virTypedParameterPtr *params,
|
|
int *nparams,
|
|
unsigned int flags)
|
|
{
|
|
virDomainJobInfo info;
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainGetJobStatsEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainGetJobInfoImpl(dom, &info) < 0)
|
|
goto cleanup;
|
|
|
|
if (info.type == VIR_DOMAIN_JOB_NONE) {
|
|
*type = VIR_DOMAIN_JOB_NONE;
|
|
*params = NULL;
|
|
*nparams = 0;
|
|
ret = 0;
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = vzDomainJobInfoToParams(&info, type, params, nparams);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#define VZ_ADD_STAT_PARAM_UUL(group, field, counter) \
|
|
do { \
|
|
if (stat.field != -1) { \
|
|
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, \
|
|
group ".%zu." counter, i); \
|
|
if (virTypedParamsAddULLong(&record->params, \
|
|
&record->nparams, \
|
|
maxparams, \
|
|
param_name, \
|
|
stat.field) < 0) \
|
|
return -1; \
|
|
} \
|
|
} while (0)
|
|
|
|
static int
|
|
vzDomainGetBlockStats(virDomainObjPtr dom,
|
|
virDomainStatsRecordPtr record,
|
|
int *maxparams)
|
|
{
|
|
vzDomObjPtr privdom = dom->privateData;
|
|
size_t i;
|
|
char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
|
|
|
|
if (virTypedParamsAddUInt(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
"block.count",
|
|
dom->def->ndisks) < 0)
|
|
return -1;
|
|
|
|
for (i = 0; i < dom->def->ndisks; i++) {
|
|
virDomainBlockStatsStruct stat;
|
|
virDomainDiskDefPtr disk = dom->def->disks[i];
|
|
|
|
if (prlsdkGetBlockStats(privdom->stats,
|
|
disk,
|
|
&stat,
|
|
IS_CT(dom->def)) < 0)
|
|
return -1;
|
|
|
|
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
|
|
"block.%zu.name", i);
|
|
if (virTypedParamsAddString(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
param_name,
|
|
disk->dst) < 0)
|
|
return -1;
|
|
|
|
if (virStorageSourceIsLocalStorage(disk->src) && disk->src->path) {
|
|
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
|
|
"block.%zu.path", i);
|
|
if (virTypedParamsAddString(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
param_name,
|
|
disk->src->path) < 0)
|
|
return -1;
|
|
}
|
|
|
|
VZ_ADD_STAT_PARAM_UUL("block", rd_req, "rd.reqs");
|
|
VZ_ADD_STAT_PARAM_UUL("block", rd_bytes, "rd.bytes");
|
|
VZ_ADD_STAT_PARAM_UUL("block", wr_req, "wr.reqs");
|
|
VZ_ADD_STAT_PARAM_UUL("block", wr_bytes, "wr.bytes");
|
|
|
|
if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
|
|
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH,
|
|
"block.%zu.capacity", i);
|
|
if (virTypedParamsAddULLong(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
param_name,
|
|
disk->src->capacity) < 0)
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetNetStats(virDomainObjPtr dom,
|
|
virDomainStatsRecordPtr record,
|
|
int *maxparams)
|
|
{
|
|
vzDomObjPtr privdom = dom->privateData;
|
|
size_t i;
|
|
char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
|
|
|
|
if (virTypedParamsAddUInt(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
"net.count",
|
|
dom->def->nnets) < 0)
|
|
return -1;
|
|
|
|
for (i = 0; i < dom->def->nnets; i++) {
|
|
virDomainInterfaceStatsStruct stat;
|
|
virDomainNetDefPtr net = dom->def->nets[i];
|
|
|
|
if (prlsdkGetNetStats(privdom->stats, privdom->sdkdom, net->ifname,
|
|
&stat) < 0)
|
|
return -1;
|
|
|
|
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "net.%zu.name", i);
|
|
if (virTypedParamsAddString(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
param_name,
|
|
net->ifname) < 0)
|
|
return -1;
|
|
|
|
VZ_ADD_STAT_PARAM_UUL("net", rx_bytes, "rx.bytes");
|
|
VZ_ADD_STAT_PARAM_UUL("net", rx_packets, "rx.pkts");
|
|
VZ_ADD_STAT_PARAM_UUL("net", tx_bytes, "tx.bytes");
|
|
VZ_ADD_STAT_PARAM_UUL("net", tx_packets, "tx.pkts");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetVCPUStats(virDomainObjPtr dom,
|
|
virDomainStatsRecordPtr record,
|
|
int *maxparams)
|
|
{
|
|
vzDomObjPtr privdom = dom->privateData;
|
|
size_t i;
|
|
char param_name[VIR_TYPED_PARAM_FIELD_LENGTH];
|
|
|
|
if (virTypedParamsAddUInt(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
"vcpu.current",
|
|
virDomainDefGetVcpus(dom->def)) < 0)
|
|
return -1;
|
|
|
|
if (virTypedParamsAddUInt(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
"vcpu.maximum",
|
|
virDomainDefGetVcpusMax(dom->def)) < 0)
|
|
return -1;
|
|
|
|
for (i = 0; i < virDomainDefGetVcpusMax(dom->def); i++) {
|
|
int state = dom->def->vcpus[i]->online ? VIR_VCPU_RUNNING :
|
|
VIR_VCPU_OFFLINE;
|
|
unsigned long long time;
|
|
|
|
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "vcpu.%zu.state", i);
|
|
if (virTypedParamsAddInt(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
param_name,
|
|
state) < 0)
|
|
return -1;
|
|
|
|
if (prlsdkGetVcpuStats(privdom->stats, i, &time) < 0)
|
|
return -1;
|
|
|
|
g_snprintf(param_name, VIR_TYPED_PARAM_FIELD_LENGTH, "vcpu.%zu.time", i);
|
|
if (virTypedParamsAddULLong(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
param_name,
|
|
time) < 0)
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetBalloonStats(virDomainObjPtr dom,
|
|
virDomainStatsRecordPtr record,
|
|
int *maxparams)
|
|
{
|
|
vzDomObjPtr privdom = dom->privateData;
|
|
virDomainMemoryStatStruct stats[VIR_DOMAIN_MEMORY_STAT_NR];
|
|
size_t i;
|
|
int n;
|
|
|
|
if (virTypedParamsAddULLong(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
"balloon.maximum",
|
|
virDomainDefGetMemoryTotal(dom->def)) < 0)
|
|
return -1;
|
|
|
|
if (virTypedParamsAddULLong(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
"balloon.current",
|
|
virDomainDefGetMemoryTotal(dom->def)) < 0)
|
|
return -1;
|
|
|
|
n = prlsdkGetMemoryStats(privdom->stats, stats, VIR_DOMAIN_MEMORY_STAT_NR);
|
|
if (n < 0)
|
|
return -1;
|
|
|
|
#define STORE_MEM_RECORD(TAG, NAME) \
|
|
if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ ##TAG) \
|
|
if (virTypedParamsAddULLong(&record->params, \
|
|
&record->nparams, \
|
|
maxparams, \
|
|
"balloon." NAME, \
|
|
stats[i].val) < 0) \
|
|
return -1;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
STORE_MEM_RECORD(SWAP_IN, "swap_in")
|
|
STORE_MEM_RECORD(SWAP_OUT, "swap_out")
|
|
STORE_MEM_RECORD(MAJOR_FAULT, "major_fault")
|
|
STORE_MEM_RECORD(MINOR_FAULT, "minor_fault")
|
|
STORE_MEM_RECORD(AVAILABLE, "available")
|
|
STORE_MEM_RECORD(UNUSED, "unused")
|
|
}
|
|
|
|
#undef STORE_MEM_RECORD
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainGetStateStats(virDomainObjPtr dom,
|
|
virDomainStatsRecordPtr record,
|
|
int *maxparams)
|
|
{
|
|
if (virTypedParamsAddInt(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
"state.state",
|
|
dom->state.state) < 0)
|
|
return -1;
|
|
|
|
if (virTypedParamsAddInt(&record->params,
|
|
&record->nparams,
|
|
maxparams,
|
|
"state.reason",
|
|
dom->state.reason) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static virDomainStatsRecordPtr
|
|
vzDomainGetAllStats(virConnectPtr conn,
|
|
virDomainObjPtr dom)
|
|
{
|
|
virDomainStatsRecordPtr stat;
|
|
int maxparams = 0;
|
|
|
|
if (VIR_ALLOC(stat) < 0)
|
|
return NULL;
|
|
|
|
if (vzDomainGetStateStats(dom, stat, &maxparams) < 0)
|
|
goto error;
|
|
|
|
if (vzDomainGetBlockStats(dom, stat, &maxparams) < 0)
|
|
goto error;
|
|
|
|
if (vzDomainGetNetStats(dom, stat, &maxparams) < 0)
|
|
goto error;
|
|
|
|
if (vzDomainGetVCPUStats(dom, stat, &maxparams) < 0)
|
|
goto error;
|
|
|
|
if (vzDomainGetBalloonStats(dom, stat, &maxparams) < 0)
|
|
goto error;
|
|
|
|
if (!(stat->dom = virGetDomain(conn, dom->def->name, dom->def->uuid, dom->def->id)))
|
|
goto error;
|
|
|
|
return stat;
|
|
|
|
error:
|
|
virTypedParamsFree(stat->params, stat->nparams);
|
|
virObjectUnref(stat->dom);
|
|
VIR_FREE(stat);
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
vzConnectGetAllDomainStats(virConnectPtr conn,
|
|
virDomainPtr *domains,
|
|
unsigned int ndomains,
|
|
unsigned int stats,
|
|
virDomainStatsRecordPtr **retStats,
|
|
unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
vzDriverPtr driver = privconn->driver;
|
|
unsigned int lflags = flags & (VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
|
|
VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
|
|
VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE);
|
|
unsigned int supported = VIR_DOMAIN_STATS_STATE |
|
|
VIR_DOMAIN_STATS_VCPU |
|
|
VIR_DOMAIN_STATS_INTERFACE |
|
|
VIR_DOMAIN_STATS_BALLOON |
|
|
VIR_DOMAIN_STATS_BLOCK;
|
|
virDomainObjPtr *doms = NULL;
|
|
size_t ndoms;
|
|
virDomainStatsRecordPtr *tmpstats = NULL;
|
|
int nstats = 0;
|
|
int ret = -1;
|
|
size_t i;
|
|
|
|
virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE |
|
|
VIR_CONNECT_LIST_DOMAINS_FILTERS_PERSISTENT |
|
|
VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE |
|
|
VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS, -1);
|
|
|
|
if (virConnectGetAllDomainStatsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
if (!stats) {
|
|
stats = supported;
|
|
} else if ((flags & VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS) &&
|
|
(stats & ~supported)) {
|
|
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
|
|
_("Stats types bits 0x%x are not supported by this daemon"),
|
|
stats & ~supported);
|
|
return -1;
|
|
}
|
|
|
|
if (ndomains) {
|
|
if (virDomainObjListConvert(driver->domains, conn, domains, ndomains, &doms,
|
|
&ndoms, virConnectGetAllDomainStatsCheckACL,
|
|
lflags, true) < 0)
|
|
return -1;
|
|
} else {
|
|
if (virDomainObjListCollect(driver->domains, conn, &doms, &ndoms,
|
|
virConnectGetAllDomainStatsCheckACL,
|
|
lflags) < 0)
|
|
return -1;
|
|
}
|
|
|
|
if (VIR_ALLOC_N(tmpstats, ndoms + 1) < 0)
|
|
goto cleanup;
|
|
|
|
for (i = 0; i < ndoms; i++) {
|
|
virDomainStatsRecordPtr tmp;
|
|
virDomainObjPtr dom = doms[i];
|
|
|
|
virObjectLock(dom);
|
|
tmp = vzDomainGetAllStats(conn, dom);
|
|
virObjectUnlock(dom);
|
|
|
|
if (!tmp)
|
|
goto cleanup;
|
|
|
|
tmpstats[nstats++] = tmp;
|
|
}
|
|
|
|
*retStats = tmpstats;
|
|
tmpstats = NULL;
|
|
ret = nstats;
|
|
|
|
cleanup:
|
|
virDomainStatsRecordListFree(tmpstats);
|
|
virObjectListFreeCount(doms, ndoms);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#undef VZ_ADD_STAT_PARAM_UUL
|
|
|
|
static int
|
|
vzDomainAbortJob(virDomainPtr domain)
|
|
{
|
|
virDomainObjPtr dom;
|
|
int ret = -1;
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainAbortJobEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkCancelJob(dom);
|
|
|
|
cleanup:
|
|
virDomainObjEndAPI(&dom);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzDomainReset(virDomainPtr domain, unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(0, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
return -1;
|
|
|
|
if (virDomainResetEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkReset(dom);
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
|
|
VIR_DOMAIN_AFFECT_CONFIG, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
goto cleanup;
|
|
|
|
if (vzCheckConfigUpdateFlags(dom, &flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (virDomainSetVcpusFlagsEnsureACL(domain->conn, dom->def, flags) < 0)
|
|
goto cleanup;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
ret = prlsdkSetCpuCount(dom, nvcpus);
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static int vzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
|
|
{
|
|
return vzDomainSetVcpusFlags(dom, nvcpus,
|
|
VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);
|
|
}
|
|
static int
|
|
vzDomainBlockResize(virDomainPtr domain,
|
|
const char *path,
|
|
unsigned long long size,
|
|
unsigned int flags)
|
|
{
|
|
virDomainObjPtr dom = NULL;
|
|
virDomainDiskDefPtr disk = NULL;
|
|
int ret = -1;
|
|
bool job = false;
|
|
|
|
virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
|
|
|
|
if (!(dom = vzDomObjFromDomain(domain)))
|
|
goto cleanup;
|
|
|
|
if (virDomainBlockResizeEnsureACL(domain->conn, dom->def) < 0)
|
|
goto cleanup;
|
|
|
|
if (path[0] == '\0') {
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
"%s", _("empty path"));
|
|
goto cleanup;
|
|
}
|
|
|
|
/* sdk wants Mb */
|
|
if (flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES)
|
|
size /= 1024;
|
|
size /= 1024;
|
|
|
|
if (vzDomainObjBeginJob(dom) < 0)
|
|
goto cleanup;
|
|
job = true;
|
|
|
|
if (vzEnsureDomainExists(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (virDomainObjCheckActive(dom) < 0)
|
|
goto cleanup;
|
|
|
|
if (!(disk = virDomainDiskByName(dom->def, path, false))) {
|
|
virReportError(VIR_ERR_INVALID_ARG,
|
|
_("invalid path: %s"), path);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = prlsdkResizeImage(dom, disk, size);
|
|
|
|
cleanup:
|
|
if (job)
|
|
vzDomainObjEndJob(dom);
|
|
virDomainObjEndAPI(&dom);
|
|
return ret;
|
|
}
|
|
|
|
static virHypervisorDriver vzHypervisorDriver = {
|
|
.name = "vz",
|
|
.connectOpen = vzConnectOpen, /* 0.10.0 */
|
|
.connectClose = vzConnectClose, /* 0.10.0 */
|
|
.connectGetVersion = vzConnectGetVersion, /* 0.10.0 */
|
|
.connectGetHostname = vzConnectGetHostname, /* 0.10.0 */
|
|
.connectGetSysinfo = vzConnectGetSysinfo, /* 1.3.4 */
|
|
.connectGetMaxVcpus = vzConnectGetMaxVcpus, /* 1.2.21 */
|
|
.nodeGetInfo = vzNodeGetInfo, /* 0.10.0 */
|
|
.nodeGetCPUStats = vzNodeGetCPUStats, /* 1.2.21 */
|
|
.nodeGetMemoryStats = vzNodeGetMemoryStats, /* 1.2.21 */
|
|
.nodeGetCellsFreeMemory = vzNodeGetCellsFreeMemory, /* 1.2.21 */
|
|
.nodeGetFreeMemory = vzNodeGetFreeMemory, /* 1.2.21 */
|
|
.connectGetCapabilities = vzConnectGetCapabilities, /* 0.10.0 */
|
|
.connectBaselineCPU = vzConnectBaselineCPU, /* 1.2.6 */
|
|
.connectListDomains = vzConnectListDomains, /* 0.10.0 */
|
|
.connectNumOfDomains = vzConnectNumOfDomains, /* 0.10.0 */
|
|
.connectListDefinedDomains = vzConnectListDefinedDomains, /* 0.10.0 */
|
|
.connectNumOfDefinedDomains = vzConnectNumOfDefinedDomains, /* 0.10.0 */
|
|
.connectListAllDomains = vzConnectListAllDomains, /* 0.10.0 */
|
|
.domainLookupByID = vzDomainLookupByID, /* 0.10.0 */
|
|
.domainLookupByUUID = vzDomainLookupByUUID, /* 0.10.0 */
|
|
.domainLookupByName = vzDomainLookupByName, /* 0.10.0 */
|
|
.domainGetOSType = vzDomainGetOSType, /* 0.10.0 */
|
|
.domainGetInfo = vzDomainGetInfo, /* 0.10.0 */
|
|
.domainGetState = vzDomainGetState, /* 0.10.0 */
|
|
.domainGetXMLDesc = vzDomainGetXMLDesc, /* 0.10.0 */
|
|
.domainIsPersistent = vzDomainIsPersistent, /* 0.10.0 */
|
|
.domainGetAutostart = vzDomainGetAutostart, /* 0.10.0 */
|
|
.domainGetVcpus = vzDomainGetVcpus, /* 1.2.6 */
|
|
.domainSuspend = vzDomainSuspend, /* 0.10.0 */
|
|
.domainResume = vzDomainResume, /* 0.10.0 */
|
|
.domainDestroy = vzDomainDestroy, /* 0.10.0 */
|
|
.domainDestroyFlags = vzDomainDestroyFlags, /* 2.2.0 */
|
|
.domainShutdown = vzDomainShutdown, /* 0.10.0 */
|
|
.domainShutdownFlags = vzDomainShutdownFlags, /* 2.2.0 */
|
|
.domainCreate = vzDomainCreate, /* 0.10.0 */
|
|
.domainCreateWithFlags = vzDomainCreateWithFlags, /* 1.2.10 */
|
|
.domainReboot = vzDomainReboot, /* 1.3.0 */
|
|
.domainDefineXML = vzDomainDefineXML, /* 0.10.0 */
|
|
.domainDefineXMLFlags = vzDomainDefineXMLFlags, /* 1.2.12 */
|
|
.domainUndefine = vzDomainUndefine, /* 1.2.10 */
|
|
.domainUndefineFlags = vzDomainUndefineFlags, /* 1.2.10 */
|
|
.domainAttachDevice = vzDomainAttachDevice, /* 1.2.15 */
|
|
.domainAttachDeviceFlags = vzDomainAttachDeviceFlags, /* 1.2.15 */
|
|
.domainDetachDevice = vzDomainDetachDevice, /* 1.2.15 */
|
|
.domainDetachDeviceFlags = vzDomainDetachDeviceFlags, /* 1.2.15 */
|
|
.domainIsActive = vzDomainIsActive, /* 1.2.10 */
|
|
.domainIsUpdated = vzDomainIsUpdated, /* 1.2.21 */
|
|
.domainSetVcpus = vzDomainSetVcpus, /* 3.3.0 */
|
|
.domainSetVcpusFlags = vzDomainSetVcpusFlags, /* 3.3.0 */
|
|
.domainGetVcpusFlags = vzDomainGetVcpusFlags, /* 1.2.21 */
|
|
.domainGetMaxVcpus = vzDomainGetMaxVcpus, /* 1.2.21 */
|
|
.domainSetUserPassword = vzDomainSetUserPassword, /* 2.0.0 */
|
|
.connectDomainEventRegisterAny = vzConnectDomainEventRegisterAny, /* 1.2.10 */
|
|
.connectDomainEventDeregisterAny = vzConnectDomainEventDeregisterAny, /* 1.2.10 */
|
|
.nodeGetCPUMap = vzNodeGetCPUMap, /* 1.2.8 */
|
|
.connectIsEncrypted = vzConnectIsEncrypted, /* 1.2.5 */
|
|
.connectIsSecure = vzConnectIsSecure, /* 1.2.5 */
|
|
.connectIsAlive = vzConnectIsAlive, /* 1.2.5 */
|
|
.domainHasManagedSaveImage = vzDomainHasManagedSaveImage, /* 1.2.13 */
|
|
.domainManagedSave = vzDomainManagedSave, /* 1.2.14 */
|
|
.domainManagedSaveRemove = vzDomainManagedSaveRemove, /* 1.2.14 */
|
|
.domainGetMaxMemory = vzDomainGetMaxMemory, /* 1.2.15 */
|
|
.domainBlockStats = vzDomainBlockStats, /* 1.2.17 */
|
|
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
|
|
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */
|
|
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
|
|
.connectRegisterCloseCallback = vzConnectRegisterCloseCallback, /* 1.3.2 */
|
|
.connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */
|
|
.domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */
|
|
.domainSetMemory = vzDomainSetMemory, /* 1.3.4 */
|
|
.domainSnapshotNum = vzDomainSnapshotNum, /* 1.3.5 */
|
|
.domainSnapshotListNames = vzDomainSnapshotListNames, /* 1.3.5 */
|
|
.domainListAllSnapshots = vzDomainListAllSnapshots, /* 1.3.5 */
|
|
.domainSnapshotGetXMLDesc = vzDomainSnapshotGetXMLDesc, /* 1.3.5 */
|
|
.domainSnapshotNumChildren = vzDomainSnapshotNumChildren, /* 1.3.5 */
|
|
.domainSnapshotListChildrenNames = vzDomainSnapshotListChildrenNames, /* 1.3.5 */
|
|
.domainSnapshotListAllChildren = vzDomainSnapshotListAllChildren, /* 1.3.5 */
|
|
.domainSnapshotLookupByName = vzDomainSnapshotLookupByName, /* 1.3.5 */
|
|
.domainHasCurrentSnapshot = vzDomainHasCurrentSnapshot, /* 1.3.5 */
|
|
.domainSnapshotGetParent = vzDomainSnapshotGetParent, /* 1.3.5 */
|
|
.domainSnapshotCurrent = vzDomainSnapshotCurrent, /* 1.3.5 */
|
|
.domainSnapshotIsCurrent = vzDomainSnapshotIsCurrent, /* 1.3.5 */
|
|
.domainSnapshotHasMetadata = vzDomainSnapshotHasMetadata, /* 1.3.5 */
|
|
.domainSnapshotCreateXML = vzDomainSnapshotCreateXML, /* 1.3.5 */
|
|
.domainSnapshotDelete = vzDomainSnapshotDelete, /* 1.3.5 */
|
|
.domainRevertToSnapshot = vzDomainRevertToSnapshot, /* 1.3.5 */
|
|
.connectSupportsFeature = vzConnectSupportsFeature, /* 1.3.5 */
|
|
.domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */
|
|
.domainMigratePrepare3Params = vzDomainMigratePrepare3Params, /* 1.3.5 */
|
|
.domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */
|
|
.domainMigrateFinish3Params = vzDomainMigrateFinish3Params, /* 1.3.5 */
|
|
.domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */
|
|
.domainUpdateDeviceFlags = vzDomainUpdateDeviceFlags, /* 2.0.0 */
|
|
.domainGetJobInfo = vzDomainGetJobInfo, /* 2.2.0 */
|
|
.domainGetJobStats = vzDomainGetJobStats, /* 2.2.0 */
|
|
.connectGetAllDomainStats = vzConnectGetAllDomainStats, /* 3.1.0 */
|
|
.domainAbortJob = vzDomainAbortJob, /* 3.1.0 */
|
|
.domainReset = vzDomainReset, /* 3.1.0 */
|
|
.domainBlockResize = vzDomainBlockResize, /* 3.3.0 */
|
|
};
|
|
|
|
static virConnectDriver vzConnectDriver = {
|
|
.localOnly = true,
|
|
.uriSchemes = (const char *[]){ "vz", NULL },
|
|
.hypervisorDriver = &vzHypervisorDriver,
|
|
};
|
|
|
|
static int
|
|
vzStateCleanup(void)
|
|
{
|
|
if (vz_driver_privileged) {
|
|
virObjectUnref(vz_driver);
|
|
vz_driver = NULL;
|
|
if (vz_driver_lock_fd != -1)
|
|
virPidFileRelease(VZ_STATEDIR, "driver", vz_driver_lock_fd);
|
|
virMutexDestroy(&vz_driver_lock);
|
|
prlsdkDeinit();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzStateInitialize(bool privileged,
|
|
virStateInhibitCallback callback G_GNUC_UNUSED,
|
|
void *opaque G_GNUC_UNUSED)
|
|
{
|
|
if (!privileged)
|
|
return VIR_DRV_STATE_INIT_SKIPPED;
|
|
|
|
vz_driver_privileged = privileged;
|
|
|
|
if (virFileMakePathWithMode(VZ_STATEDIR, S_IRWXU) < 0) {
|
|
virReportSystemError(errno, _("cannot create state directory '%s'"),
|
|
VZ_STATEDIR);
|
|
return VIR_DRV_STATE_INIT_ERROR;
|
|
}
|
|
|
|
if ((vz_driver_lock_fd =
|
|
virPidFileAcquire(VZ_STATEDIR, "driver", false, getpid())) < 0)
|
|
return VIR_DRV_STATE_INIT_ERROR;
|
|
|
|
if (prlsdkInit() < 0) {
|
|
VIR_DEBUG("%s", _("Can't initialize Parallels SDK"));
|
|
return VIR_DRV_STATE_INIT_ERROR;
|
|
}
|
|
|
|
if (virMutexInit(&vz_driver_lock) < 0)
|
|
goto error;
|
|
|
|
/* Failing to create driver here is not fatal and only means
|
|
* that next driver client will try once more when connecting */
|
|
vz_driver = vzDriverObjNew();
|
|
return VIR_DRV_STATE_INIT_COMPLETE;
|
|
|
|
error:
|
|
vzStateCleanup();
|
|
return VIR_DRV_STATE_INIT_ERROR;
|
|
}
|
|
|
|
static virStateDriver vzStateDriver = {
|
|
.name = "vz",
|
|
.stateInitialize = vzStateInitialize,
|
|
.stateCleanup = vzStateCleanup,
|
|
};
|
|
|
|
/* Parallels domain type backward compatibility*/
|
|
static virHypervisorDriver parallelsHypervisorDriver;
|
|
static virConnectDriver parallelsConnectDriver = {
|
|
.localOnly = true,
|
|
.uriSchemes = (const char *[]){ "parallels", NULL },
|
|
.hypervisorDriver = ¶llelsHypervisorDriver,
|
|
};
|
|
|
|
/**
|
|
* vzRegister:
|
|
*
|
|
* Registers the vz driver
|
|
*/
|
|
int
|
|
vzRegister(void)
|
|
{
|
|
char *prlctl_path;
|
|
|
|
prlctl_path = virFindFileInPath(PRLCTL);
|
|
if (!prlctl_path) {
|
|
VIR_DEBUG("%s", _("Can't find prlctl command in the PATH env"));
|
|
return 0;
|
|
}
|
|
|
|
VIR_FREE(prlctl_path);
|
|
|
|
/* Backward compatibility with Parallels domain type */
|
|
parallelsHypervisorDriver = vzHypervisorDriver;
|
|
parallelsHypervisorDriver.name = "Parallels";
|
|
if (virRegisterConnectDriver(¶llelsConnectDriver, true) < 0)
|
|
return -1;
|
|
|
|
if (virRegisterConnectDriver(&vzConnectDriver, true) < 0)
|
|
return -1;
|
|
|
|
if (virRegisterStateDriver(&vzStateDriver) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|