mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-11-01 10:51:12 +00:00
4ce29411fc
When running in libvirtd, we are happy for any of the drivers to simply skip their initialization in virStateInitialize, as other drivers are still potentially useful. When running in per-driver daemons though, we want the daemon to abort startup if the driver cannot initialize itself, as the daemon will be useless without it. Reviewed-by: Andrea Bolognani <abologna@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
4199 lines
114 KiB
C
4199 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 LOCALSTATEDIR "/run/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 (virCapabilitiesInitNUMA(caps) < 0)
|
|
goto error;
|
|
|
|
if (virCapabilitiesInitCaches(caps) < 0)
|
|
goto error;
|
|
|
|
verify(ARRAY_CARDINALITY(archs) == ARRAY_CARDINALITY(emulators));
|
|
|
|
for (i = 0; i < ARRAY_CARDINALITY(ostypes); i++)
|
|
for (j = 0; j < ARRAY_CARDINALITY(archs); j++)
|
|
for (k = 0; k < ARRAY_CARDINALITY(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);
|
|
VIR_STEAL_PTR(driver, vz_driver);
|
|
VIR_STEAL_PTR(privconn_list, 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;
|
|
char *xml;
|
|
|
|
if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
|
|
return NULL;
|
|
|
|
xml = virCapabilitiesFormatXML(privconn->driver->caps);
|
|
return xml;
|
|
}
|
|
|
|
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,
|
|
virCapsPtr caps ATTRIBUTE_UNUSED,
|
|
unsigned int parseFlags ATTRIBUTE_UNUSED,
|
|
void *opaque ATTRIBUTE_UNUSED,
|
|
void *parseOpaque ATTRIBUTE_UNUSED)
|
|
{
|
|
if (vzDomainDefAddDefaultInputDevices(def) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainDefValidate(const virDomainDef *def,
|
|
virCapsPtr caps ATTRIBUTE_UNUSED,
|
|
void *opaque)
|
|
{
|
|
if (vzCheckUnsupportedControllers(def, opaque) < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
vzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
|
|
const virDomainDef *def,
|
|
virCapsPtr caps ATTRIBUTE_UNUSED,
|
|
unsigned int parseFlags ATTRIBUTE_UNUSED,
|
|
void *opaque ATTRIBUTE_UNUSED,
|
|
void *parseOpaque ATTRIBUTE_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 ATTRIBUTE_UNUSED)
|
|
{
|
|
if (dev->type == VIR_DOMAIN_DEVICE_DISK)
|
|
return vzCheckUnsupportedDisk(def, dev->data.disk, opaque);
|
|
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->vzCaps;
|
|
|
|
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 ATTRIBUTE_UNUSED,
|
|
virConfPtr conf ATTRIBUTE_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;
|
|
if (virBufferCheckError(&buf) < 0)
|
|
return NULL;
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
}
|
|
|
|
static int
|
|
vzConnectListDomains(virConnectPtr conn, int *ids, int maxids)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
int n;
|
|
|
|
if (virConnectListDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
n = virDomainObjListGetActiveIDs(privconn->driver->domains, ids, maxids,
|
|
virConnectListDomainsCheckACL, conn);
|
|
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
vzConnectNumOfDomains(virConnectPtr conn)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
int count;
|
|
|
|
if (virConnectNumOfDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
count = virDomainObjListNumOfDomains(privconn->driver->domains, true,
|
|
virConnectNumOfDomainsCheckACL, conn);
|
|
|
|
return count;
|
|
}
|
|
|
|
static int
|
|
vzConnectListDefinedDomains(virConnectPtr conn, char **const names, int maxnames)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
int n;
|
|
|
|
if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
memset(names, 0, sizeof(*names) * maxnames);
|
|
n = virDomainObjListGetInactiveNames(privconn->driver->domains, names,
|
|
maxnames,
|
|
virConnectListDefinedDomainsCheckACL,
|
|
conn);
|
|
|
|
return n;
|
|
}
|
|
|
|
static int
|
|
vzConnectNumOfDefinedDomains(virConnectPtr conn)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
int count;
|
|
|
|
if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
count = virDomainObjListNumOfDomains(privconn->driver->domains, false,
|
|
virConnectNumOfDefinedDomainsCheckACL,
|
|
conn);
|
|
return count;
|
|
}
|
|
|
|
static int
|
|
vzConnectListAllDomains(virConnectPtr conn,
|
|
virDomainPtr **domains,
|
|
unsigned int flags)
|
|
{
|
|
vzConnPtr privconn = conn->privateData;
|
|
int ret = -1;
|
|
|
|
virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
|
|
|
|
if (virConnectListAllDomainsEnsureACL(conn) < 0)
|
|
return -1;
|
|
|
|
ret = virDomainObjListExport(privconn->driver->domains, conn, domains,
|
|
virConnectListAllDomainsCheckACL, flags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
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;
|
|
|
|
ignore_value(VIR_STRDUP(ret, 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;
|
|
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, privconn->driver->caps, 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->caps, 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 ATTRIBUTE_UNUSED)
|
|
{
|
|
/* Encryption is not relevant / applicable to way we talk to PCS */
|
|
return 0;
|
|
}
|
|
|
|
static int vzConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
|
|
{
|
|
/* We run CLI tools directly so this is secure */
|
|
return 1;
|
|
}
|
|
|
|
static int vzConnectIsAlive(virConnectPtr conn ATTRIBUTE_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->caps,
|
|
driver->xmlopt, 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->caps,
|
|
driver->xmlopt,
|
|
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->caps,
|
|
driver->xmlopt,
|
|
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->caps,
|
|
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;
|
|
VIR_AUTOUNREF(virDomainSnapshotDefPtr) 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->caps,
|
|
driver->xmlopt, 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");
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
return -1;
|
|
|
|
*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->caps,
|
|
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;
|
|
}
|
|
|
|
if (virAsprintf(&uri, "vzmigr://%s", hostname) < 0)
|
|
goto cleanup;
|
|
|
|
cleanup:
|
|
VIR_FREE(hostname);
|
|
return uri;
|
|
}
|
|
|
|
static int
|
|
vzDomainMigratePrepare3Params(virConnectPtr conn,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
const char *cookiein ATTRIBUTE_UNUSED,
|
|
int cookieinlen ATTRIBUTE_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->caps, driver->xmlopt,
|
|
NULL,
|
|
VIR_DOMAIN_DEF_PARSE_INACTIVE)))
|
|
goto cleanup;
|
|
|
|
if (dname) {
|
|
VIR_FREE(def->name);
|
|
if (VIR_STRDUP(def->name, dname) < 0)
|
|
goto cleanup;
|
|
}
|
|
|
|
if (virDomainMigratePrepare3ParamsEnsureACL(conn, def) < 0)
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
virDomainDefFree(def);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
vzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_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;
|
|
|
|
VIR_STEAL_PTR(cookiein, 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) {
|
|
orig_err = virSaveLastError();
|
|
goto finish;
|
|
}
|
|
|
|
VIR_FREE(cookiein);
|
|
VIR_STEAL_PTR(cookiein, cookieout);
|
|
cookieinlen = cookieoutlen;
|
|
cookieoutlen = 0;
|
|
if (vzDomainMigratePerformStep(dom, driver, params, nparams, cookiein,
|
|
cookieinlen, flags) < 0) {
|
|
orig_err = virSaveLastError();
|
|
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:
|
|
if (orig_err) {
|
|
virSetError(orig_err);
|
|
virFreeError(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 ATTRIBUTE_UNUSED,
|
|
int *cookieoutlen ATTRIBUTE_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 ATTRIBUTE_UNUSED,
|
|
int cookieinlen ATTRIBUTE_UNUSED,
|
|
char **cookieout ATTRIBUTE_UNUSED,
|
|
int *cookieoutlen ATTRIBUTE_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 ATTRIBUTE_UNUSED,
|
|
virTypedParameterPtr params,
|
|
int nparams,
|
|
const char *cookiein ATTRIBUTE_UNUSED,
|
|
int cookieinlen ATTRIBUTE_UNUSED,
|
|
unsigned int flags,
|
|
int cancelled ATTRIBUTE_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) { \
|
|
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;
|
|
|
|
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) {
|
|
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) {
|
|
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;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
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 ATTRIBUTE_UNUSED,
|
|
void *opaque ATTRIBUTE_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;
|
|
}
|