libvirt/src/openvz/openvz_driver.c

2266 lines
63 KiB
C
Raw Normal View History

/*
* openvz_driver.c: core driver methods for managing OpenVZ VEs
*
util: make it easier to grab only regular command exit Auditing all callers of virCommandRun and virCommandWait that passed a non-NULL pointer for exit status turned up some interesting observations. Many callers were merely passing a pointer to avoid the overall command dying, but without caring what the exit status was - but these callers would be better off treating a child death by signal as an abnormal exit. Other callers were actually acting on the status, but not all of them remembered to filter by WIFEXITED and convert with WEXITSTATUS; depending on the platform, this can result in a status being reported as 256 times too big. And among those that correctly parse the output, it gets rather verbose. Finally, there were the callers that explicitly checked that the status was 0, and gave their own message, but with fewer details than what virCommand gives for free. So the best idea is to move the complexity out of callers and into virCommand - by default, we return the actual exit status already cleaned through WEXITSTATUS and treat signals as a failed command; but the few callers that care can ask for raw status and act on it themselves. * src/util/vircommand.h (virCommandRawStatus): New prototype. * src/libvirt_private.syms (util/command.h): Export it. * docs/internals/command.html.in: Document it. * src/util/vircommand.c (virCommandRawStatus): New function. (virCommandWait): Adjust semantics. * tests/commandtest.c (test1): Test it. * daemon/remote.c (remoteDispatchAuthPolkit): Adjust callers. * src/access/viraccessdriverpolkit.c (virAccessDriverPolkitCheck): Likewise. * src/fdstream.c (virFDStreamCloseInt): Likewise. * src/lxc/lxc_process.c (virLXCProcessStart): Likewise. * src/qemu/qemu_command.c (qemuCreateInBridgePortWithHelper): Likewise. * src/xen/xen_driver.c (xenUnifiedXendProbe): Simplify. * tests/reconnect.c (mymain): Likewise. * tests/statstest.c (mymain): Likewise. * src/bhyve/bhyve_process.c (virBhyveProcessStart) (virBhyveProcessStop): Don't overwrite virCommand error. * src/libvirt.c (virConnectAuthGainPolkit): Likewise. * src/openvz/openvz_driver.c (openvzDomainGetBarrierLimit) (openvzDomainSetBarrierLimit): Likewise. * src/util/virebtables.c (virEbTablesOnceInit): Likewise. * src/util/viriptables.c (virIpTablesOnceInit): Likewise. * src/util/virnetdevveth.c (virNetDevVethCreate): Fix debug message. * src/qemu/qemu_capabilities.c (virQEMUCapsInitQMP): Add comment. * src/storage/storage_backend_iscsi.c (virStorageBackendISCSINodeUpdate): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-20 00:32:19 +00:00
* Copyright (C) 2010-2014 Red Hat, Inc.
* Copyright (C) 2006, 2007 Binary Karma
* Copyright (C) 2006 Shuveb Hussain
* Copyright (C) 2007 Anoop Joe Cyriac
*
* 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/>.
*
* Authors:
* Shuveb Hussain <shuveb@binarykarma.com>
* Anoop Joe Cyriac <anoop@binarykarma.com>
*
*/
#include <config.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <paths.h>
#include <pwd.h>
#include <sys/wait.h>
#include "virerror.h"
#include "datatypes.h"
#include "openvz_driver.h"
#include "openvz_util.h"
#include "virbuffer.h"
#include "openvz_conf.h"
2007-07-25 23:16:30 +00:00
#include "nodeinfo.h"
2012-12-12 18:06:53 +00:00
#include "viralloc.h"
#include "virfile.h"
#include "virtypedparam.h"
2012-12-12 17:59:27 +00:00
#include "virlog.h"
#include "vircommand.h"
#include "viruri.h"
#include "virstatslinux.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_OPENVZ
VIR_LOG_INIT("openvz.openvz_driver");
#define OPENVZ_MAX_ARG 28
#define CMDBUF_LEN 1488
#define CMDOP_LEN 288
#define OPENVZ_NB_MEM_PARAM 3
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid);
static int openvzConnectGetMaxVcpus(virConnectPtr conn, const char *type);
static int openvzDomainGetMaxVcpus(virDomainPtr dom);
static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
unsigned int nvcpus);
static int openvzDomainSetMemoryInternal(virDomainObjPtr vm,
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
unsigned long long memory);
static int openvzGetVEStatus(virDomainObjPtr vm, int *status, int *reason);
static void openvzDriverLock(struct openvz_driver *driver)
{
2009-01-15 19:56:05 +00:00
virMutexLock(&driver->lock);
}
static void openvzDriverUnlock(struct openvz_driver *driver)
{
2009-01-15 19:56:05 +00:00
virMutexUnlock(&driver->lock);
}
struct openvz_driver ovz_driver;
static int
openvzDomainDefPostParse(virDomainDefPtr def,
virCapsPtr caps ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
/* fill the init path */
if (STREQ(def->os.type, "exe") && !def->os.init)
return VIR_STRDUP(def->os.init, "/sbin/init") < 0 ? -1 : 0;
return 0;
}
static int
openvzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev,
maint: avoid 'const fooPtr' in domain_conf 'const fooPtr' is the same as 'foo * const' (the pointer won't change, but it's contents can). But in general, if an interface is trying to be const-correct, it should be using 'const foo *' (the pointer is to data that can't be changed). Fix up offenders in src/conf/domain_conf, and their fallout. Several things to note: virObjectLock() requires a non-const argument; if this were C++, we could treat the locking field as 'mutable' and allow locking an otherwise 'const' object, but that is a more invasive change, so I instead dropped attempts to be const-correct on domain lookup. virXMLPropString and friends require a non-const xmlNodePtr - this is because libxml2 is not a const-correct library. We could make the src/util/virxml wrappers cast away const, but I figured it was easier to not try to mark xmlNodePtr as const. Finally, virDomainDeviceDefCopy was a rather hard conversion - it calls virDomainDeviceDefPostParse, which in turn in the xen driver was actually modifying the domain outside of the current device being visited. We should not be adding a device on the first per-device callback, but waiting until after all per-device callbacks are complete. * src/conf/domain_conf.h (virDomainObjListFindByID) (virDomainObjListFindByUUID, virDomainObjListFindByName) (virDomainObjAssignDef, virDomainObjListAdd): Drop attempt at const. (virDomainDeviceDefCopy): Use intended type. (virDomainDeviceDefParse, virDomainDeviceDefPostParseCallback) (virDomainVideoDefaultType, virDomainVideoDefaultRAM) (virDomainChrGetDomainPtrs): Make const-correct. * src/conf/domain_conf.c (virDomainObjListFindByID) (virDomainObjListFindByUUID, virDomainObjListFindByName) (virDomainDeviceDefCopy, virDomainObjListAdd) (virDomainObjAssignDef, virDomainHostdevSubsysUsbDefParseXML) (virDomainHostdevSubsysPciOrigStatesDefParseXML) (virDomainHostdevSubsysPciDefParseXML) (virDomainHostdevSubsysScsiDefParseXML) (virDomainControllerModelTypeFromString) (virDomainTPMDefParseXML, virDomainTimerDefParseXML) (virDomainSoundCodecDefParseXML, virDomainSoundDefParseXML) (virDomainWatchdogDefParseXML, virDomainRNGDefParseXML) (virDomainMemballoonDefParseXML, virDomainNVRAMDefParseXML) (virSysinfoParseXML, virDomainVideoAccelDefParseXML) (virDomainVideoDefParseXML, virDomainHostdevDefParseXML) (virDomainRedirdevDefParseXML) (virDomainRedirFilterUsbDevDefParseXML) (virDomainRedirFilterDefParseXML, virDomainIdMapEntrySort) (virDomainIdmapDefParseXML, virDomainVcpuPinDefParseXML) (virDiskNameToBusDeviceIndex, virDomainDeviceDefCopy) (virDomainVideoDefaultType, virDomainHostdevAssignAddress) (virDomainDeviceDefPostParseInternal, virDomainDeviceDefPostParse) (virDomainChrGetDomainPtrs, virDomainControllerSCSINextUnit) (virDomainSCSIDriveAddressIsUsed) (virDomainDriveAddressIsUsedByDisk) (virDomainDriveAddressIsUsedByHostdev): Fix fallout. * src/openvz/openvz_driver.c (openvzDomainDeviceDefPostParse): Likewise. * src/libxl/libxl_domain.c (libxlDomainDeviceDefPostParse): Likewise. * src/qemu/qemu_domain.c (qemuDomainDeviceDefPostParse) (qemuDomainDefaultNetModel): Likewise. * src/lxc/lxc_domain.c (virLXCDomainDeviceDefPostParse): Likewise. * src/uml/uml_driver.c (umlDomainDeviceDefPostParse): Likewise. * src/xen/xen_driver.c (xenDomainDeviceDefPostParse): Split... (xenDomainDefPostParse): ...since per-device callback is not the time to be adding a device. Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-08 15:08:25 +00:00
const virDomainDef *def ATTRIBUTE_UNUSED,
virCapsPtr caps ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE)
dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_OPENVZ;
return 0;
}
virDomainDefParserConfig openvzDomainDefParserConfig = {
.domainPostParseCallback = openvzDomainDefPostParse,
.devicesPostParseCallback = openvzDomainDeviceDefPostParse,
};
/* generate arguments to create OpenVZ container
return -1 - error
0 - OK
Caller has to free the cmd
*/
static virCommandPtr
openvzDomainDefineCmd(virDomainDefPtr vmdef)
{
virCommandPtr cmd = virCommandNewArgList(VZCTL,
"--quiet",
"create",
NULL);
if (vmdef == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Container is not defined"));
virCommandFree(cmd);
return NULL;
}
virCommandAddArgList(cmd, vmdef->name, "--name", vmdef->name, NULL);
2008-09-05 15:00:14 +00:00
if (vmdef->nfss == 1 &&
vmdef->fss[0]->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
virCommandAddArgList(cmd, "--ostemplate", vmdef->fss[0]->src, NULL);
}
return cmd;
}
static int openvzSetInitialConfig(virDomainDefPtr vmdef)
{
int ret = -1;
int vpsid;
char * confdir = NULL;
virCommandPtr cmd = NULL;
if (vmdef->nfss > 1) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("only one filesystem supported"));
goto cleanup;
}
if (vmdef->nfss == 1 &&
vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_TEMPLATE &&
vmdef->fss[0]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
{
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("filesystem is not of type 'template' or 'mount'"));
goto cleanup;
}
if (vmdef->nfss == 1 &&
vmdef->fss[0]->type == VIR_DOMAIN_FS_TYPE_MOUNT)
{
if (virStrToLong_i(vmdef->name, NULL, 10, &vpsid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not convert domain name to VEID"));
goto cleanup;
}
if (openvzCopyDefaultConfig(vpsid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not copy default config"));
goto cleanup;
}
if (openvzWriteVPSConfigParam(vpsid, "VE_PRIVATE", vmdef->fss[0]->src) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set the source dir for the filesystem"));
goto cleanup;
}
} else {
cmd = openvzDomainDefineCmd(vmdef);
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(confdir);
virCommandFree(cmd);
return ret;
}
static int
openvzSetDiskQuota(virDomainDefPtr vmdef,
virDomainFSDefPtr fss,
bool persist)
{
int ret = -1;
unsigned long long sl, hl;
virCommandPtr cmd = virCommandNewArgList(VZCTL,
"--quiet",
"set",
vmdef->name,
NULL);
if (persist)
virCommandAddArg(cmd, "--save");
if (fss->type == VIR_DOMAIN_FS_TYPE_TEMPLATE) {
if (fss->space_hard_limit) {
hl = VIR_DIV_UP(fss->space_hard_limit, 1024);
virCommandAddArg(cmd, "--diskspace");
if (fss->space_soft_limit) {
sl = VIR_DIV_UP(fss->space_soft_limit, 1024);
virCommandAddArgFormat(cmd, "%lld:%lld", sl, hl);
} else {
virCommandAddArgFormat(cmd, "%lld", hl);
}
} else if (fss->space_soft_limit) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("Can't set soft limit without hard limit"));
goto cleanup;
}
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
}
ret = 0;
cleanup:
virCommandFree(cmd);
return ret;
}
2012-07-10 11:58:44 +00:00
static char *
openvzDomainGetHostname(virDomainPtr dom, unsigned int flags)
{
char *hostname = NULL;
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
virCheckFlags(0, NULL);
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
2012-07-10 11:58:44 +00:00
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
hostname = openvzVEGetStringParam(dom, "hostname");
if (hostname == NULL)
goto error;
/* vzlist prints an unset hostname as '-' */
if (STREQ(hostname, "-")) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("Hostname of '%s' is unset"), vm->def->name);
goto error;
}
cleanup:
2012-07-10 11:58:44 +00:00
if (vm)
virObjectUnlock(vm);
2012-07-10 11:58:44 +00:00
return hostname;
error:
2012-07-10 11:58:44 +00:00
VIR_FREE(hostname);
goto cleanup;
}
static virDomainPtr openvzDomainLookupByID(virConnectPtr conn,
int id)
{
struct openvz_driver *driver = conn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
openvzDriverLock(driver);
vm = virDomainObjListFindByID(driver->domains, id);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom)
dom->id = vm->def->id;
cleanup:
if (vm)
virObjectUnlock(vm);
return dom;
}
static int openvzConnectGetVersion(virConnectPtr conn, unsigned long *version)
{
struct openvz_driver *driver = conn->privateData;
openvzDriverLock(driver);
*version = driver->version;
openvzDriverUnlock(driver);
return 0;
}
static char *openvzConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
{
return virGetHostname();
}
static char *openvzDomainGetOSType(virDomainPtr dom)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
char *ret = NULL;
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
ignore_value(VIR_STRDUP(ret, vm->def->os.type));
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn,
const unsigned char *uuid)
{
struct openvz_driver *driver = conn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom)
dom->id = vm->def->id;
cleanup:
if (vm)
virObjectUnlock(vm);
return dom;
}
static virDomainPtr openvzDomainLookupByName(virConnectPtr conn,
const char *name)
{
struct openvz_driver *driver = conn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
openvzDriverLock(driver);
vm = virDomainObjListFindByName(driver->domains, name);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom)
dom->id = vm->def->id;
2008-09-05 15:00:14 +00:00
cleanup:
if (vm)
virObjectUnlock(vm);
return dom;
}
static int openvzDomainGetInfo(virDomainPtr dom,
virDomainInfoPtr info)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int state;
int ret = -1;
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
if (openvzGetVEStatus(vm, &state, NULL) == -1)
goto cleanup;
info->state = state;
2008-09-05 15:00:14 +00:00
if (info->state != VIR_DOMAIN_RUNNING) {
info->cpuTime = 0;
} else {
if (openvzGetProcessInfo(&(info->cpuTime), dom->id) < 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("cannot read cputime for domain %d"), dom->id);
goto cleanup;
}
}
info->maxMem = vm->def->mem.max_balloon;
info->memory = vm->def->mem.cur_balloon;
info->nrVirtCpu = vm->def->vcpus;
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static int
openvzDomainGetState(virDomainPtr dom,
int *state,
int *reason,
unsigned int flags)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
int ret = -1;
virCheckFlags(0, -1);
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
ret = openvzGetVEStatus(vm, state, reason);
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static int openvzDomainIsActive(virDomainPtr dom)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr obj;
int ret = -1;
openvzDriverLock(driver);
obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!obj) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
ret = virDomainObjIsActive(obj);
cleanup:
if (obj)
virObjectUnlock(obj);
return ret;
}
static int openvzDomainIsPersistent(virDomainPtr dom)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr obj;
int ret = -1;
openvzDriverLock(driver);
obj = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!obj) {
virReportError(VIR_ERR_NO_DOMAIN, NULL);
goto cleanup;
}
ret = obj->persistent;
cleanup:
if (obj)
virObjectUnlock(obj);
return ret;
}
static int openvzDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
{
return 0;
}
drivers: prefer unsigned int for flags Now that the public APIs always use unsigned flags, the internal driver callbacks might as well do likewise. * src/driver.h (vrDrvOpen, virDrvDomainCoreDump) (virDrvDomainGetXMLDesc, virDrvNetworkGetXMLDesc) (virDrvNWFilterGetXMLDesc): Update type. * src/remote/remote_protocol.x (remote_open_args) (remote_domain_core_dump_args, remote_domain_get_xml_desc_args) (remote_network_get_xml_desc_args) (remote_nwfilter_get_xml_desc_args): Likewise. * src/test/test_driver.c: Update clients. * src/remote/remote_driver.c: Likewise. * src/xen/xen_hypervisor.c: Likewise. * src/xen/xen_hypervisor.h: Likewise. * src/xen/xen_driver.c: Likewise. * src/xen/xend_internal.c: Likewise. * src/xen/xend_internal.h: Likewise. * src/xen/xm_internal.c: Likewise. * src/xen/xm_internal.h: Likewise. * src/xen/xs_internal.c: Likewise. * src/xen/xs_internal.h: Likewise. * src/xen/xen_inotify.c: Likewise. * src/xen/xen_inotify.h: Likewise. * src/phyp/phyp_driver.c: Likewise. * src/openvz/openvz_driver.c: Likewise. * src/vmware/vmware_driver.c: Likewise. * src/vbox/vbox_driver.c: Likewise. * src/vbox/vbox_tmpl.c: Likewise. * src/xenapi/xenapi_driver.c: Likewise. * src/esx/esx_driver.c: Likewise. * src/esx/esx_interface_driver.c: Likewise. * src/esx/esx_network_driver.c: Likewise. * src/esx/esx_storage_driver.c: Likewise. * src/esx/esx_device_monitor.c: Likewise. * src/esx/esx_secret_driver.c: Likewise. * src/esx/esx_nwfilter_driver.c: Likewise. * src/interface/netcf_driver.c: Likewise. * src/nwfilter/nwfilter_driver.c: Likewise. * src/libxl/libxl_driver.c: Likewise. * src/qemu/qemu_driver.c: Likewise. * src/lxc/lxc_driver.c: Likewise. * src/uml/uml_driver.c: Likewise. * src/network/bridge_driver.c: Likewise. * src/secret/secret_driver.c: Likewise. * src/storage/storage_driver.c: Likewise. * src/node_device/node_device_hal.c: Likewise. * src/node_device/node_device_udev.c: Likewise. * src/remote_protocol-structs: Likewise.
2011-07-06 20:40:19 +00:00
static char *openvzDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
char *ret = NULL;
2008-09-05 15:00:14 +00:00
/* Flags checked by virDomainDefFormat */
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
2008-09-05 15:00:14 +00:00
ret = virDomainDefFormat(vm->def, flags);
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
/*
* Convenient helper to target a command line argv
* and fill in an empty slot with the supplied
* key value. This lets us declare the argv on the
* stack and just splice in the domain name after
*/
#define PROGRAM_SENTINEL ((char *)0x1)
static void openvzSetProgramSentinal(const char **prog, const char *key)
{
const char **tmp = prog;
while (tmp && *tmp) {
if (*tmp == PROGRAM_SENTINEL) {
*tmp = key;
break;
}
tmp++;
}
}
static int openvzDomainSuspend(virDomainPtr dom)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
const char *prog[] = {VZCTL, "--quiet", "chkpnt", PROGRAM_SENTINEL, "--suspend", NULL};
int ret = -1;
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("Domain is not running"));
goto cleanup;
}
if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
openvzSetProgramSentinal(prog, vm->def->name);
if (virRun(prog, NULL) < 0) {
goto cleanup;
}
virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
}
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static int openvzDomainResume(virDomainPtr dom)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
const char *prog[] = {VZCTL, "--quiet", "chkpnt", PROGRAM_SENTINEL, "--resume", NULL};
int ret = -1;
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("Domain is not running"));
goto cleanup;
}
if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
openvzSetProgramSentinal(prog, vm->def->name);
if (virRun(prog, NULL) < 0) {
goto cleanup;
}
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNPAUSED);
}
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static int
openvzDomainShutdownFlags(virDomainPtr dom,
unsigned int flags)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
const char *prog[] = {VZCTL, "--quiet", "stop", PROGRAM_SENTINEL, NULL};
int ret = -1;
int status;
virCheckFlags(0, -1);
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
2008-09-05 15:00:14 +00:00
if (openvzGetVEStatus(vm, &status, NULL) == -1)
goto cleanup;
openvzSetProgramSentinal(prog, vm->def->name);
if (status != VIR_DOMAIN_RUNNING) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("domain is not in running state"));
goto cleanup;
}
2008-09-05 15:00:14 +00:00
if (virRun(prog, NULL) < 0)
goto cleanup;
2008-09-05 15:00:14 +00:00
vm->def->id = -1;
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
2010-07-30 17:50:12 +00:00
dom->id = -1;
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static int
openvzDomainShutdown(virDomainPtr dom)
{
return openvzDomainShutdownFlags(dom, 0);
}
static int
openvzDomainDestroy(virDomainPtr dom)
{
return openvzDomainShutdownFlags(dom, 0);
}
static int
openvzDomainDestroyFlags(virDomainPtr dom, unsigned int flags)
{
return openvzDomainShutdownFlags(dom, flags);
}
static int openvzDomainReboot(virDomainPtr dom,
unsigned int flags)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
const char *prog[] = {VZCTL, "--quiet", "restart", PROGRAM_SENTINEL, NULL};
int ret = -1;
int status;
virCheckFlags(0, -1);
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
if (openvzGetVEStatus(vm, &status, NULL) == -1)
goto cleanup;
openvzSetProgramSentinal(prog, vm->def->name);
if (status != VIR_DOMAIN_RUNNING) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("domain is not in running state"));
goto cleanup;
}
if (virRun(prog, NULL) < 0)
goto cleanup;
ret = 0;
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static char *
openvzGenerateVethName(int veid, char *dev_name_ve)
{
int ifNo = 0;
char *ret;
if (sscanf(dev_name_ve, "%*[^0-9]%d", &ifNo) != 1)
return NULL;
ignore_value(virAsprintf(&ret, "veth%d.%d.", veid, ifNo));
return ret;
}
static char *
openvzGenerateContainerVethName(int veid)
{
char *temp = NULL;
char *name = NULL;
/* try to get line "^NETIF=..." from config */
if (openvzReadVPSConfigParam(veid, "NETIF", &temp) <= 0) {
ignore_value(VIR_STRDUP(name, "eth0"));
} else {
char *saveptr = NULL;
char *s;
int max = 0;
/* get maximum interface number (actually, it is the last one) */
for (s = strtok_r(temp, ";", &saveptr); s; s = strtok_r(NULL, ";", &saveptr)) {
int x;
if (sscanf(s, "ifname=eth%d", &x) != 1) return NULL;
if (x > max) max = x;
}
/* set new name */
ignore_value(virAsprintf(&name, "eth%d", max + 1));
}
VIR_FREE(temp);
return name;
}
static int
openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
virDomainNetDefPtr net,
virBufferPtr configBuf)
{
int rc = -1;
char macaddr[VIR_MAC_STRING_BUFLEN];
virMacAddr host_mac;
char host_macaddr[VIR_MAC_STRING_BUFLEN];
struct openvz_driver *driver = conn->privateData;
virCommandPtr cmd = NULL;
char *guest_ifname = NULL;
if (net == NULL)
return 0;
if (vpsid == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Container ID is not specified"));
return -1;
}
if (net->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
net->type != VIR_DOMAIN_NET_TYPE_ETHERNET)
return 0;
cmd = virCommandNewArgList(VZCTL, "--quiet", "set", vpsid, NULL);
virMacAddrFormat(&net->mac, macaddr);
virDomainNetGenerateMAC(driver->xmlopt, &host_mac);
virMacAddrFormat(&host_mac, host_macaddr);
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
(net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
net->data.ethernet.ipaddr == NULL)) {
virBuffer buf = VIR_BUFFER_INITIALIZER;
int veid = openvzGetVEID(vpsid);
/* if net is ethernet and the user has specified guest interface name,
* let's use it; otherwise generate a new one */
if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
net->data.ethernet.dev != NULL) {
if (VIR_STRDUP(guest_ifname, net->data.ethernet.dev) == -1)
goto cleanup;
} else {
guest_ifname = openvzGenerateContainerVethName(veid);
if (guest_ifname == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not generate eth name for container"));
goto cleanup;
}
}
/* if user doesn't specified host interface name,
* than we need to generate it */
if (net->ifname == NULL) {
net->ifname = openvzGenerateVethName(veid, guest_ifname);
if (net->ifname == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not generate veth name"));
goto cleanup;
}
}
virBufferAdd(&buf, guest_ifname, -1); /* Guest dev */
virBufferAsprintf(&buf, ",%s", macaddr); /* Guest dev mac */
virBufferAsprintf(&buf, ",%s", net->ifname); /* Host dev */
virBufferAsprintf(&buf, ",%s", host_macaddr); /* Host dev mac */
if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
if (driver->version >= VZCTL_BRIDGE_MIN_VERSION) {
virBufferAsprintf(&buf, ",%s", net->data.bridge.brname); /* Host bridge */
} else {
virBufferAsprintf(configBuf, "ifname=%s", guest_ifname);
virBufferAsprintf(configBuf, ",mac=%s", macaddr); /* Guest dev mac */
virBufferAsprintf(configBuf, ",host_ifname=%s", net->ifname); /* Host dev */
virBufferAsprintf(configBuf, ",host_mac=%s", host_macaddr); /* Host dev mac */
virBufferAsprintf(configBuf, ",bridge=%s", net->data.bridge.brname); /* Host bridge */
}
}
/* --netif_add ifname[,mac,host_ifname,host_mac] */
virCommandAddArg(cmd, "--netif_add");
virCommandAddArgBuffer(cmd, &buf);
} else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
net->data.ethernet.ipaddr != NULL) {
/* --ipadd ip */
virCommandAddArgList(cmd, "--ipadd", net->data.ethernet.ipaddr, NULL);
}
/* TODO: processing NAT and physical device */
virCommandAddArg(cmd, "--save");
rc = virCommandRun(cmd, NULL);
cleanup:
virCommandFree(cmd);
VIR_FREE(guest_ifname);
return rc;
}
static int
openvzDomainSetNetworkConfig(virConnectPtr conn,
virDomainDefPtr def)
{
size_t i;
virBuffer buf = VIR_BUFFER_INITIALIZER;
char *param;
int first = 1;
struct openvz_driver *driver = conn->privateData;
for (i = 0; i < def->nnets; i++) {
if (driver->version < VZCTL_BRIDGE_MIN_VERSION &&
def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
if (first)
first = 0;
else
virBufferAddLit(&buf, ";");
}
if (openvzDomainSetNetwork(conn, def->name, def->nets[i], &buf) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not configure network"));
goto exit;
}
}
if (driver->version < VZCTL_BRIDGE_MIN_VERSION && def->nnets) {
param = virBufferContentAndReset(&buf);
if (param) {
if (openvzWriteVPSConfigParam(strtoI(def->name), "NETIF", param) < 0) {
VIR_FREE(param);
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot replace NETIF config"));
return -1;
}
VIR_FREE(param);
}
}
return 0;
exit:
virBufferFreeAndReset(&buf);
return -1;
}
static virDomainPtr
openvzDomainDefineXML(virConnectPtr conn, const char *xml)
{
struct openvz_driver *driver = conn->privateData;
virDomainDefPtr vmdef = NULL;
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
openvzDriverLock(driver);
if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
1 << VIR_DOMAIN_VIRT_OPENVZ,
VIR_DOMAIN_XML_INACTIVE)) == NULL)
goto cleanup;
vm = virDomainObjListFindByName(driver->domains, vmdef->name);
if (vm) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("Already an OPENVZ VM active with the id '%s'"),
vmdef->name);
goto cleanup;
}
if (!(vm = virDomainObjListAdd(driver->domains, vmdef,
driver->xmlopt,
0, NULL)))
goto cleanup;
vmdef = NULL;
vm->persistent = 1;
if (openvzSetInitialConfig(vm->def) < 0) {
VIR_ERROR(_("Error creating initial configuration"));
goto cleanup;
}
if (vm->def->nfss == 1) {
if (openvzSetDiskQuota(vm->def, vm->def->fss[0], true) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set disk quota"));
goto cleanup;
}
}
if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set UUID"));
goto cleanup;
}
if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
goto cleanup;
2010-09-29 16:20:07 +00:00
if (vm->def->vcpus != vm->def->maxvcpus) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("current vcpu count must equal maximum"));
2010-09-29 16:20:07 +00:00
goto cleanup;
}
if (vm->def->maxvcpus > 0) {
if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set number of vCPUs"));
goto cleanup;
}
}
if (vm->def->mem.cur_balloon > 0) {
if (openvzDomainSetMemoryInternal(vm, vm->def->mem.cur_balloon) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set memory size"));
goto cleanup;
}
}
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom)
dom->id = -1;
cleanup:
virDomainDefFree(vmdef);
if (vm)
virObjectUnlock(vm);
openvzDriverUnlock(driver);
return dom;
}
static virDomainPtr
openvzDomainCreateXML(virConnectPtr conn, const char *xml,
unsigned int flags)
{
struct openvz_driver *driver = conn->privateData;
virDomainDefPtr vmdef = NULL;
virDomainObjPtr vm = NULL;
virDomainPtr dom = NULL;
const char *progstart[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINEL, NULL};
virCheckFlags(0, NULL);
openvzDriverLock(driver);
if ((vmdef = virDomainDefParseString(xml, driver->caps, driver->xmlopt,
1 << VIR_DOMAIN_VIRT_OPENVZ,
VIR_DOMAIN_XML_INACTIVE)) == NULL)
goto cleanup;
vm = virDomainObjListFindByName(driver->domains, vmdef->name);
if (vm) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("Already an OPENVZ VM defined with the id '%s'"),
vmdef->name);
goto cleanup;
}
if (!(vm = virDomainObjListAdd(driver->domains,
vmdef,
driver->xmlopt,
VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
NULL)))
goto cleanup;
vmdef = NULL;
/* All OpenVZ domains seem to be persistent - this is a bit of a violation
* of this libvirt API which is intended for transient domain creation */
vm->persistent = 1;
if (openvzSetInitialConfig(vm->def) < 0) {
VIR_ERROR(_("Error creating initial configuration"));
goto cleanup;
}
if (vm->def->nfss == 1) {
if (openvzSetDiskQuota(vm->def, vm->def->fss[0], true) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set disk quota"));
goto cleanup;
}
}
if (openvzSetDefinedUUID(strtoI(vm->def->name), vm->def->uuid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set UUID"));
goto cleanup;
}
if (openvzDomainSetNetworkConfig(conn, vm->def) < 0)
goto cleanup;
openvzSetProgramSentinal(progstart, vm->def->name);
if (virRun(progstart, NULL) < 0) {
goto cleanup;
}
vm->pid = strtoI(vm->def->name);
vm->def->id = vm->pid;
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
2008-09-05 15:00:14 +00:00
2010-09-29 16:20:07 +00:00
if (vm->def->maxvcpus > 0) {
if (openvzDomainSetVcpusInternal(vm, vm->def->maxvcpus) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set number of vCPUs"));
goto cleanup;
}
}
dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
if (dom)
dom->id = vm->def->id;
cleanup:
virDomainDefFree(vmdef);
if (vm)
virObjectUnlock(vm);
openvzDriverUnlock(driver);
return dom;
}
static int
openvzDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
const char *prog[] = {VZCTL, "--quiet", "start", PROGRAM_SENTINEL, NULL };
int ret = -1;
int status;
virCheckFlags(0, -1);
openvzDriverLock(driver);
vm = virDomainObjListFindByName(driver->domains, dom->name);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching id"));
goto cleanup;
}
if (openvzGetVEStatus(vm, &status, NULL) == -1)
goto cleanup;
if (status != VIR_DOMAIN_SHUTOFF) {
virReportError(VIR_ERR_OPERATION_DENIED, "%s",
_("domain is not in shutoff state"));
goto cleanup;
}
openvzSetProgramSentinal(prog, vm->def->name);
if (virRun(prog, NULL) < 0) {
goto cleanup;
}
vm->pid = strtoI(vm->def->name);
vm->def->id = vm->pid;
dom->id = vm->pid;
virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static int
openvzDomainCreate(virDomainPtr dom)
{
return openvzDomainCreateWithFlags(dom, 0);
}
static int
openvzDomainUndefineFlags(virDomainPtr dom,
unsigned int flags)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
const char *prog[] = { VZCTL, "--quiet", "destroy", PROGRAM_SENTINEL, NULL };
int ret = -1;
int status;
virCheckFlags(0, -1);
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
if (openvzGetVEStatus(vm, &status, NULL) == -1)
goto cleanup;
openvzSetProgramSentinal(prog, vm->def->name);
if (virRun(prog, NULL) < 0) {
goto cleanup;
}
if (virDomainObjIsActive(vm)) {
vm->persistent = 0;
} else {
virDomainObjListRemove(driver->domains, vm);
vm = NULL;
}
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
openvzDriverUnlock(driver);
return ret;
}
static int
openvzDomainUndefine(virDomainPtr dom)
{
return openvzDomainUndefineFlags(dom, 0);
}
static int
openvzDomainSetAutostart(virDomainPtr dom, int autostart)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
"--onboot", autostart ? "yes" : "no",
"--save", NULL };
int ret = -1;
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
openvzSetProgramSentinal(prog, vm->def->name);
if (virRun(prog, NULL) < 0) {
goto cleanup;
}
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static int
openvzDomainGetAutostart(virDomainPtr dom, int *autostart)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
char *value = NULL;
int ret = -1;
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
if (openvzReadVPSConfigParam(strtoI(vm->def->name), "ONBOOT", &value) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not read container config"));
goto cleanup;
}
*autostart = 0;
if (STREQ(value, "yes"))
*autostart = 1;
ret = 0;
cleanup:
VIR_FREE(value);
if (vm)
virObjectUnlock(vm);
return ret;
}
static int openvzConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED,
const char *type)
{
if (type == NULL || STRCASEEQ(type, "openvz"))
return 1028; /* OpenVZ has no limitation */
virReportError(VIR_ERR_INVALID_ARG,
_("unknown type '%s'"), type);
return -1;
}
vcpu: make old API trivially wrap to new API Note - this wrapping is completely mechanical; the old API will function identically, since the new API validates that the exact same flags are provided by the old API. On a per-driver basis, it may make sense to have the old API pass a different set of flags, but that should be done in the per-driver patch that implements the full range of flag support in the new API. * src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): Move guts... (esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new functions. (esxDriver): Trivially support the new API. * src/openvz/openvz_driver.c (openvzDomainSetVcpus) (openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) (openvzDomainGetVcpusFlags, openvzDriver): Likewise. * src/phyp/phyp_driver.c (phypDomainSetCPU) (phypDomainSetVcpusFlags, phypGetLparCPUMAX) (phypDomainGetVcpusFlags, phypDriver): Likewise. * src/qemu/qemu_driver.c (qemudDomainSetVcpus) (qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) (qemudDomainGetVcpusFlags, qemuDriver): Likewise. * src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) (testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) (vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) (virDomainGetVcpusFlags, virDriver): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) (xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) (xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) (xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) (xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. (xenapiError): New helper macro.
2010-09-27 22:37:53 +00:00
static int
openvzDomainGetVcpusFlags(virDomainPtr dom ATTRIBUTE_UNUSED,
unsigned int flags)
{
if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
virReportError(VIR_ERR_INVALID_ARG,
_("unsupported flags (0x%x)"), flags);
vcpu: make old API trivially wrap to new API Note - this wrapping is completely mechanical; the old API will function identically, since the new API validates that the exact same flags are provided by the old API. On a per-driver basis, it may make sense to have the old API pass a different set of flags, but that should be done in the per-driver patch that implements the full range of flag support in the new API. * src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): Move guts... (esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new functions. (esxDriver): Trivially support the new API. * src/openvz/openvz_driver.c (openvzDomainSetVcpus) (openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) (openvzDomainGetVcpusFlags, openvzDriver): Likewise. * src/phyp/phyp_driver.c (phypDomainSetCPU) (phypDomainSetVcpusFlags, phypGetLparCPUMAX) (phypDomainGetVcpusFlags, phypDriver): Likewise. * src/qemu/qemu_driver.c (qemudDomainSetVcpus) (qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) (qemudDomainGetVcpusFlags, qemuDriver): Likewise. * src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) (testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) (vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) (virDomainGetVcpusFlags, virDriver): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) (xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) (xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) (xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) (xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. (xenapiError): New helper macro.
2010-09-27 22:37:53 +00:00
return -1;
}
return openvzConnectGetMaxVcpus(NULL, "openvz");
}
vcpu: make old API trivially wrap to new API Note - this wrapping is completely mechanical; the old API will function identically, since the new API validates that the exact same flags are provided by the old API. On a per-driver basis, it may make sense to have the old API pass a different set of flags, but that should be done in the per-driver patch that implements the full range of flag support in the new API. * src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): Move guts... (esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new functions. (esxDriver): Trivially support the new API. * src/openvz/openvz_driver.c (openvzDomainSetVcpus) (openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) (openvzDomainGetVcpusFlags, openvzDriver): Likewise. * src/phyp/phyp_driver.c (phypDomainSetCPU) (phypDomainSetVcpusFlags, phypGetLparCPUMAX) (phypDomainGetVcpusFlags, phypDriver): Likewise. * src/qemu/qemu_driver.c (qemudDomainSetVcpus) (qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) (qemudDomainGetVcpusFlags, qemuDriver): Likewise. * src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) (testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) (vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) (virDomainGetVcpusFlags, virDriver): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) (xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) (xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) (xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) (xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. (xenapiError): New helper macro.
2010-09-27 22:37:53 +00:00
static int openvzDomainGetMaxVcpus(virDomainPtr dom)
{
return openvzDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
vcpu: make old API trivially wrap to new API Note - this wrapping is completely mechanical; the old API will function identically, since the new API validates that the exact same flags are provided by the old API. On a per-driver basis, it may make sense to have the old API pass a different set of flags, but that should be done in the per-driver patch that implements the full range of flag support in the new API. * src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): Move guts... (esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new functions. (esxDriver): Trivially support the new API. * src/openvz/openvz_driver.c (openvzDomainSetVcpus) (openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) (openvzDomainGetVcpusFlags, openvzDriver): Likewise. * src/phyp/phyp_driver.c (phypDomainSetCPU) (phypDomainSetVcpusFlags, phypGetLparCPUMAX) (phypDomainGetVcpusFlags, phypDriver): Likewise. * src/qemu/qemu_driver.c (qemudDomainSetVcpus) (qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) (qemudDomainGetVcpusFlags, qemuDriver): Likewise. * src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) (testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) (vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) (virDomainGetVcpusFlags, virDriver): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) (xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) (xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) (xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) (xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. (xenapiError): New helper macro.
2010-09-27 22:37:53 +00:00
VIR_DOMAIN_VCPU_MAXIMUM));
}
static int openvzDomainSetVcpusInternal(virDomainObjPtr vm,
unsigned int nvcpus)
{
char str_vcpus[32];
const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
"--cpus", str_vcpus, "--save", NULL };
unsigned int pcpus;
pcpus = openvzGetNodeCPUs();
if (pcpus > 0 && pcpus < nvcpus)
nvcpus = pcpus;
snprintf(str_vcpus, 31, "%d", nvcpus);
str_vcpus[31] = '\0';
openvzSetProgramSentinal(prog, vm->def->name);
if (virRun(prog, NULL) < 0) {
return -1;
}
2010-09-29 16:20:07 +00:00
vm->def->maxvcpus = vm->def->vcpus = nvcpus;
return 0;
}
vcpu: make old API trivially wrap to new API Note - this wrapping is completely mechanical; the old API will function identically, since the new API validates that the exact same flags are provided by the old API. On a per-driver basis, it may make sense to have the old API pass a different set of flags, but that should be done in the per-driver patch that implements the full range of flag support in the new API. * src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): Move guts... (esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new functions. (esxDriver): Trivially support the new API. * src/openvz/openvz_driver.c (openvzDomainSetVcpus) (openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) (openvzDomainGetVcpusFlags, openvzDriver): Likewise. * src/phyp/phyp_driver.c (phypDomainSetCPU) (phypDomainSetVcpusFlags, phypGetLparCPUMAX) (phypDomainGetVcpusFlags, phypDriver): Likewise. * src/qemu/qemu_driver.c (qemudDomainSetVcpus) (qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) (qemudDomainGetVcpusFlags, qemuDriver): Likewise. * src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) (testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) (vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) (virDomainGetVcpusFlags, virDriver): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) (xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) (xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) (xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) (xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. (xenapiError): New helper macro.
2010-09-27 22:37:53 +00:00
static int openvzDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
unsigned int flags)
{
virDomainObjPtr vm;
struct openvz_driver *driver = dom->conn->privateData;
int ret = -1;
if (flags != VIR_DOMAIN_AFFECT_LIVE) {
virReportError(VIR_ERR_INVALID_ARG,
_("unsupported flags (0x%x)"), flags);
vcpu: make old API trivially wrap to new API Note - this wrapping is completely mechanical; the old API will function identically, since the new API validates that the exact same flags are provided by the old API. On a per-driver basis, it may make sense to have the old API pass a different set of flags, but that should be done in the per-driver patch that implements the full range of flag support in the new API. * src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): Move guts... (esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new functions. (esxDriver): Trivially support the new API. * src/openvz/openvz_driver.c (openvzDomainSetVcpus) (openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) (openvzDomainGetVcpusFlags, openvzDriver): Likewise. * src/phyp/phyp_driver.c (phypDomainSetCPU) (phypDomainSetVcpusFlags, phypGetLparCPUMAX) (phypDomainGetVcpusFlags, phypDriver): Likewise. * src/qemu/qemu_driver.c (qemudDomainSetVcpus) (qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) (qemudDomainGetVcpusFlags, qemuDriver): Likewise. * src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) (testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) (vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) (virDomainGetVcpusFlags, virDriver): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) (xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) (xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) (xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) (xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. (xenapiError): New helper macro.
2010-09-27 22:37:53 +00:00
return -1;
}
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
if (nvcpus <= 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Number of vCPUs should be >= 1"));
goto cleanup;
}
if (openvzDomainSetVcpusInternal(vm, nvcpus) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not set number of vCPUs"));
goto cleanup;
}
ret = 0;
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
vcpu: make old API trivially wrap to new API Note - this wrapping is completely mechanical; the old API will function identically, since the new API validates that the exact same flags are provided by the old API. On a per-driver basis, it may make sense to have the old API pass a different set of flags, but that should be done in the per-driver patch that implements the full range of flag support in the new API. * src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): Move guts... (esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new functions. (esxDriver): Trivially support the new API. * src/openvz/openvz_driver.c (openvzDomainSetVcpus) (openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) (openvzDomainGetVcpusFlags, openvzDriver): Likewise. * src/phyp/phyp_driver.c (phypDomainSetCPU) (phypDomainSetVcpusFlags, phypGetLparCPUMAX) (phypDomainGetVcpusFlags, phypDriver): Likewise. * src/qemu/qemu_driver.c (qemudDomainSetVcpus) (qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) (qemudDomainGetVcpusFlags, qemuDriver): Likewise. * src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) (testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) (vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) (virDomainGetVcpusFlags, virDriver): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) (xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) (xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) (xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) (xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. (xenapiError): New helper macro.
2010-09-27 22:37:53 +00:00
static int
openvzDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
return openvzDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
vcpu: make old API trivially wrap to new API Note - this wrapping is completely mechanical; the old API will function identically, since the new API validates that the exact same flags are provided by the old API. On a per-driver basis, it may make sense to have the old API pass a different set of flags, but that should be done in the per-driver patch that implements the full range of flag support in the new API. * src/esx/esx_driver.c (esxDomainSetVcpus, escDomainGetMaxVpcus): Move guts... (esxDomainSetVcpusFlags, esxDomainGetVcpusFlags): ...to new functions. (esxDriver): Trivially support the new API. * src/openvz/openvz_driver.c (openvzDomainSetVcpus) (openvzDomainSetVcpusFlags, openvzDomainGetMaxVcpus) (openvzDomainGetVcpusFlags, openvzDriver): Likewise. * src/phyp/phyp_driver.c (phypDomainSetCPU) (phypDomainSetVcpusFlags, phypGetLparCPUMAX) (phypDomainGetVcpusFlags, phypDriver): Likewise. * src/qemu/qemu_driver.c (qemudDomainSetVcpus) (qemudDomainSetVcpusFlags, qemudDomainGetMaxVcpus) (qemudDomainGetVcpusFlags, qemuDriver): Likewise. * src/test/test_driver.c (testSetVcpus, testDomainSetVcpusFlags) (testDomainGetMaxVcpus, testDomainGetVcpusFlags, testDriver): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainSetVcpus) (vboxDomainSetVcpusFlags, virDomainGetMaxVcpus) (virDomainGetVcpusFlags, virDriver): Likewise. * src/xen/xen_driver.c (xenUnifiedDomainSetVcpus) (xenUnifiedDomainSetVcpusFlags, xenUnifiedDomainGetMaxVcpus) (xenUnifiedDomainGetVcpusFlags, xenUnifiedDriver): Likewise. * src/xenapi/xenapi_driver.c (xenapiDomainSetVcpus) (xenapiDomainSetVcpusFlags, xenapiDomainGetMaxVcpus) (xenapiDomainGetVcpusFlags, xenapiDriver): Likewise. (xenapiError): New helper macro.
2010-09-27 22:37:53 +00:00
}
static virDrvOpenStatus openvzConnectOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
unsigned int flags)
{
struct openvz_driver *driver;
virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
if (conn->uri == NULL) {
if (!virFileExists("/proc/vz"))
return VIR_DRV_OPEN_DECLINED;
if (access("/proc/vz", W_OK) < 0)
return VIR_DRV_OPEN_DECLINED;
if (!(conn->uri = virURIParse("openvz:///system")))
return VIR_DRV_OPEN_ERROR;
} else {
/* If scheme isn't 'openvz', then its for another driver */
if (conn->uri->scheme == NULL ||
STRNEQ(conn->uri->scheme, "openvz"))
return VIR_DRV_OPEN_DECLINED;
/* If server name is given, its for remote driver */
if (conn->uri->server != NULL)
return VIR_DRV_OPEN_DECLINED;
/* If path isn't /system, then they typoed, so tell them correct path */
if (conn->uri->path == NULL ||
STRNEQ(conn->uri->path, "/system")) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected OpenVZ URI path '%s', try openvz:///system"),
conn->uri->path);
return VIR_DRV_OPEN_ERROR;
}
if (!virFileExists("/proc/vz")) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("OpenVZ control file /proc/vz does not exist"));
return VIR_DRV_OPEN_ERROR;
}
if (access("/proc/vz", W_OK) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("OpenVZ control file /proc/vz is not accessible"));
return VIR_DRV_OPEN_ERROR;
}
}
/* We now know the URI is definitely for this driver, so beyond
* here, don't return DECLINED, always use ERROR */
if (VIR_ALLOC(driver) < 0)
return VIR_DRV_OPEN_ERROR;
if (!(driver->domains = virDomainObjListNew()))
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
goto cleanup;
if (!(driver->caps = openvzCapsInit()))
goto cleanup;
if (!(driver->xmlopt = virDomainXMLOptionNew(&openvzDomainDefParserConfig,
NULL, NULL)))
goto cleanup;
if (openvzLoadDomains(driver) < 0)
goto cleanup;
if (openvzExtractVersion(driver) < 0)
goto cleanup;
conn->privateData = driver;
return VIR_DRV_OPEN_SUCCESS;
cleanup:
openvzFreeDriver(driver);
return VIR_DRV_OPEN_ERROR;
};
static int openvzConnectClose(virConnectPtr conn)
{
struct openvz_driver *driver = conn->privateData;
openvzFreeDriver(driver);
conn->privateData = NULL;
return 0;
}
static const char *openvzConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
return "OpenVZ";
}
static int openvzConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* Encryption is not relevant / applicable to way we talk to openvz */
return 0;
}
static int openvzConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
/* We run CLI tools directly so this is secure */
return 1;
}
static int
openvzConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
return 1;
}
static char *openvzConnectGetCapabilities(virConnectPtr conn) {
struct openvz_driver *driver = conn->privateData;
char *ret;
openvzDriverLock(driver);
ret = virCapabilitiesFormatXML(driver->caps);
openvzDriverUnlock(driver);
return ret;
}
static int openvzConnectListDomains(virConnectPtr conn ATTRIBUTE_UNUSED,
int *ids, int nids)
{
int got = 0;
int veid;
int outfd = -1;
int rc = -1;
int ret;
char buf[32];
char *endptr;
virCommandPtr cmd = virCommandNewArgList(VZLIST, "-ovpsid", "-H", NULL);
virCommandSetOutputFD(cmd, &outfd);
if (virCommandRunAsync(cmd, NULL) < 0)
goto cleanup;
while (got < nids) {
ret = openvz_readline(outfd, buf, 32);
if (!ret)
break;
if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not parse VPS ID %s"), buf);
continue;
}
ids[got] = veid;
got ++;
}
if (virCommandWait(cmd, NULL) < 0)
goto cleanup;
if (VIR_CLOSE(outfd) < 0) {
virReportSystemError(errno, "%s", _("failed to close file"));
goto cleanup;
}
rc = got;
cleanup:
VIR_FORCE_CLOSE(outfd);
virCommandFree(cmd);
return rc;
}
static int openvzConnectNumOfDomains(virConnectPtr conn)
{
struct openvz_driver *driver = conn->privateData;
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
int n;
openvzDriverLock(driver);
n = virDomainObjListNumOfDomains(driver->domains, true, NULL, NULL);
openvzDriverUnlock(driver);
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
return n;
}
static int openvzConnectListDefinedDomains(virConnectPtr conn ATTRIBUTE_UNUSED,
char **const names, int nnames) {
int got = 0;
int veid, outfd = -1, ret;
int rc = -1;
char vpsname[32];
char buf[32];
char *endptr;
virCommandPtr cmd = virCommandNewArgList(VZLIST,
"-ovpsid", "-H", "-S", NULL);
/* the -S options lists only stopped domains */
virCommandSetOutputFD(cmd, &outfd);
if (virCommandRunAsync(cmd, NULL) < 0)
goto out;
while (got < nnames) {
ret = openvz_readline(outfd, buf, 32);
if (!ret)
break;
if (virStrToLong_i(buf, &endptr, 10, &veid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Could not parse VPS ID %s"), buf);
continue;
}
snprintf(vpsname, sizeof(vpsname), "%d", veid);
if (VIR_STRDUP(names[got], vpsname) < 0)
goto out;
got ++;
}
if (virCommandWait(cmd, NULL) < 0)
goto out;
if (VIR_CLOSE(outfd) < 0) {
virReportSystemError(errno, "%s", _("failed to close file"));
goto out;
}
rc = got;
out:
VIR_FORCE_CLOSE(outfd);
virCommandFree(cmd);
if (rc < 0) {
for (; got >= 0; got--)
VIR_FREE(names[got]);
}
return rc;
}
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid)
{
FILE *fp;
char *line = NULL;
size_t line_size = 0;
unsigned long long usertime, systime, nicetime;
int readvps = vpsid + 1; /* ensure readvps is initially different */
ssize_t ret;
int err = 0;
/* read statistic from /proc/vz/vestat.
sample:
Version: 2.2
VEID user nice system uptime idle other..
33 78 0 1330 59454597 142650441835148 other..
55 178 0 5340 59424597 542650441835148 other..
*/
if ((fp = fopen("/proc/vz/vestat", "r")) == NULL)
return -1;
/*search line with VEID=vpsid*/
while (1) {
ret = getline(&line, &line_size, fp);
if (ret < 0) {
err = !feof(fp);
break;
}
if (sscanf(line, "%d %llu %llu %llu",
&readvps, &usertime, &nicetime, &systime) == 4
&& readvps == vpsid) { /*found vpsid*/
/* convert jiffies to nanoseconds */
*cpuTime = (1000ull * 1000ull * 1000ull
* (usertime + nicetime + systime)
/ (unsigned long long)sysconf(_SC_CLK_TCK));
break;
}
}
VIR_FREE(line);
VIR_FORCE_FCLOSE(fp);
if (err)
return -1;
if (readvps != vpsid) /*not found*/
return -1;
return 0;
}
static int openvzConnectNumOfDefinedDomains(virConnectPtr conn)
{
struct openvz_driver *driver = conn->privateData;
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
int n;
openvzDriverLock(driver);
n = virDomainObjListNumOfDomains(driver->domains, false, NULL, NULL);
openvzDriverUnlock(driver);
Convert virDomainObjListPtr to use a hash of domain objects The current virDomainObjListPtr object stores domain objects in an array. This means that to find a particular objects requires O(n) time, and more critically acquiring O(n) mutex locks. The new impl replaces the array with a virHashTable, keyed off UUID. Finding a object based on UUID is now O(1) time, and only requires a single mutex lock. Finding by name/id is unchanged in complexity. In changing this, all code which iterates over the array had to be updated to use a hash table iterator function callback. Several of the functions which were identically duplicating across all drivers were pulled into domain_conf.c * src/conf/domain_conf.h, src/conf/domain_conf.c: Change virDomainObjListPtr to use virHashTable. Add a initializer method virDomainObjListInit, and rename virDomainObjListFree to virDomainObjListDeinit, since its not actually freeing the container, only its contents. Also add some convenient methods virDomainObjListGetInactiveNames, virDomainObjListGetActiveIDs and virDomainObjListNumOfDomains which can be used to implement the correspondingly named public API entry points in drivers * src/libvirt_private.syms: Export new methods from domain_conf.h * src/lxc/lxc_driver.c, src/opennebula/one_driver.c, src/openvz/openvz_conf.c, src/openvz/openvz_driver.c, src/qemu/qemu_driver.c, src/test/test_driver.c, src/uml/uml_driver.c, src/vbox/vbox_tmpl.c: Update all code to deal with hash tables instead of arrays for domains
2009-10-09 11:33:51 +00:00
return n;
}
static int
openvzDomainSetMemoryInternal(virDomainObjPtr vm,
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
unsigned long long mem)
{
char str_mem[16];
const char *prog[] = { VZCTL, "--quiet", "set", PROGRAM_SENTINEL,
"--kmemsize", str_mem, "--save", NULL
};
/* memory has to be changed its format from kbyte to byte */
xml: use better types for memory values Using 'unsigned long' for memory values is risky on 32-bit platforms, as a PAE guest can have more than 4GiB memory. Our API is (unfortunately) locked at 'unsigned long' and a scale of 1024, but the rest of our system should consistently use 64-bit values, especially since the previous patch centralized overflow checking. * src/conf/domain_conf.h (_virDomainDef): Always use 64-bit values for memory. Change hugepage_backed to a bool. * src/conf/domain_conf.c (virDomainDefParseXML) (virDomainDefCheckABIStability, virDomainDefFormatInternal): Fix clients. * src/vmx/vmx.c (virVMXFormatConfig): Likewise. * src/xenxs/xen_sxpr.c (xenParseSxpr, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetULongLong): New function. (xenXMConfigGetULong, xenXMConfigSetInt): Avoid truncation. (xenParseXM, xenFormatXM): Fix clients. * src/phyp/phyp_driver.c (phypBuildLpar): Likewise. * src/openvz/openvz_driver.c (openvzDomainSetMemoryInternal): Likewise. * src/vbox/vbox_tmpl.c (vboxDomainDefineXML): Likewise. * src/qemu/qemu_command.c (qemuBuildCommandLine): Likewise. * src/qemu/qemu_process.c (qemuProcessStart): Likewise. * src/qemu/qemu_monitor.h (qemuMonitorGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.h (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_text.c (qemuMonitorTextGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.h (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_monitor_json.c (qemuMonitorJSONGetBalloonInfo): Likewise. * src/qemu/qemu_driver.c (qemudDomainGetInfo) (qemuDomainGetXMLDesc): Likewise. * src/uml/uml_conf.c (umlBuildCommandLine): Likewise.
2012-03-02 20:27:39 +00:00
snprintf(str_mem, sizeof(str_mem), "%llu", mem * 1024);
openvzSetProgramSentinal(prog, vm->def->name);
if (virRun(prog, NULL) < 0) {
goto cleanup;
}
return 0;
cleanup:
return -1;
}
static int
openvzDomainGetBarrierLimit(virDomainPtr domain,
const char *param,
unsigned long long *barrier,
unsigned long long *limit)
{
util: make it easier to grab only regular command exit Auditing all callers of virCommandRun and virCommandWait that passed a non-NULL pointer for exit status turned up some interesting observations. Many callers were merely passing a pointer to avoid the overall command dying, but without caring what the exit status was - but these callers would be better off treating a child death by signal as an abnormal exit. Other callers were actually acting on the status, but not all of them remembered to filter by WIFEXITED and convert with WEXITSTATUS; depending on the platform, this can result in a status being reported as 256 times too big. And among those that correctly parse the output, it gets rather verbose. Finally, there were the callers that explicitly checked that the status was 0, and gave their own message, but with fewer details than what virCommand gives for free. So the best idea is to move the complexity out of callers and into virCommand - by default, we return the actual exit status already cleaned through WEXITSTATUS and treat signals as a failed command; but the few callers that care can ask for raw status and act on it themselves. * src/util/vircommand.h (virCommandRawStatus): New prototype. * src/libvirt_private.syms (util/command.h): Export it. * docs/internals/command.html.in: Document it. * src/util/vircommand.c (virCommandRawStatus): New function. (virCommandWait): Adjust semantics. * tests/commandtest.c (test1): Test it. * daemon/remote.c (remoteDispatchAuthPolkit): Adjust callers. * src/access/viraccessdriverpolkit.c (virAccessDriverPolkitCheck): Likewise. * src/fdstream.c (virFDStreamCloseInt): Likewise. * src/lxc/lxc_process.c (virLXCProcessStart): Likewise. * src/qemu/qemu_command.c (qemuCreateInBridgePortWithHelper): Likewise. * src/xen/xen_driver.c (xenUnifiedXendProbe): Simplify. * tests/reconnect.c (mymain): Likewise. * tests/statstest.c (mymain): Likewise. * src/bhyve/bhyve_process.c (virBhyveProcessStart) (virBhyveProcessStop): Don't overwrite virCommand error. * src/libvirt.c (virConnectAuthGainPolkit): Likewise. * src/openvz/openvz_driver.c (openvzDomainGetBarrierLimit) (openvzDomainSetBarrierLimit): Likewise. * src/util/virebtables.c (virEbTablesOnceInit): Likewise. * src/util/viriptables.c (virIpTablesOnceInit): Likewise. * src/util/virnetdevveth.c (virNetDevVethCreate): Fix debug message. * src/qemu/qemu_capabilities.c (virQEMUCapsInitQMP): Add comment. * src/storage/storage_backend_iscsi.c (virStorageBackendISCSINodeUpdate): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-20 00:32:19 +00:00
int ret = -1;
char *endp, *output = NULL;
const char *tmp;
virCommandPtr cmd = virCommandNewArgList(VZLIST, "--no-header", NULL);
virCommandSetOutputBuffer(cmd, &output);
virCommandAddArgFormat(cmd, "-o%s.b,%s.l", param, param);
virCommandAddArg(cmd, domain->name);
util: make it easier to grab only regular command exit Auditing all callers of virCommandRun and virCommandWait that passed a non-NULL pointer for exit status turned up some interesting observations. Many callers were merely passing a pointer to avoid the overall command dying, but without caring what the exit status was - but these callers would be better off treating a child death by signal as an abnormal exit. Other callers were actually acting on the status, but not all of them remembered to filter by WIFEXITED and convert with WEXITSTATUS; depending on the platform, this can result in a status being reported as 256 times too big. And among those that correctly parse the output, it gets rather verbose. Finally, there were the callers that explicitly checked that the status was 0, and gave their own message, but with fewer details than what virCommand gives for free. So the best idea is to move the complexity out of callers and into virCommand - by default, we return the actual exit status already cleaned through WEXITSTATUS and treat signals as a failed command; but the few callers that care can ask for raw status and act on it themselves. * src/util/vircommand.h (virCommandRawStatus): New prototype. * src/libvirt_private.syms (util/command.h): Export it. * docs/internals/command.html.in: Document it. * src/util/vircommand.c (virCommandRawStatus): New function. (virCommandWait): Adjust semantics. * tests/commandtest.c (test1): Test it. * daemon/remote.c (remoteDispatchAuthPolkit): Adjust callers. * src/access/viraccessdriverpolkit.c (virAccessDriverPolkitCheck): Likewise. * src/fdstream.c (virFDStreamCloseInt): Likewise. * src/lxc/lxc_process.c (virLXCProcessStart): Likewise. * src/qemu/qemu_command.c (qemuCreateInBridgePortWithHelper): Likewise. * src/xen/xen_driver.c (xenUnifiedXendProbe): Simplify. * tests/reconnect.c (mymain): Likewise. * tests/statstest.c (mymain): Likewise. * src/bhyve/bhyve_process.c (virBhyveProcessStart) (virBhyveProcessStop): Don't overwrite virCommand error. * src/libvirt.c (virConnectAuthGainPolkit): Likewise. * src/openvz/openvz_driver.c (openvzDomainGetBarrierLimit) (openvzDomainSetBarrierLimit): Likewise. * src/util/virebtables.c (virEbTablesOnceInit): Likewise. * src/util/viriptables.c (virIpTablesOnceInit): Likewise. * src/util/virnetdevveth.c (virNetDevVethCreate): Fix debug message. * src/qemu/qemu_capabilities.c (virQEMUCapsInitQMP): Add comment. * src/storage/storage_backend_iscsi.c (virStorageBackendISCSINodeUpdate): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-20 00:32:19 +00:00
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
tmp = output;
virSkipSpaces(&tmp);
if (virStrToLong_ull(tmp, &endp, 10, barrier) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Can't parse limit from "VZLIST" output '%s'"), output);
goto cleanup;
}
tmp = endp;
virSkipSpaces(&tmp);
if (virStrToLong_ull(tmp, &endp, 10, limit) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Can't parse barrier from "VZLIST" output '%s'"), output);
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(output);
virCommandFree(cmd);
return ret;
}
static int
openvzDomainSetBarrierLimit(virDomainPtr domain,
const char *param,
unsigned long long barrier,
unsigned long long limit)
{
util: make it easier to grab only regular command exit Auditing all callers of virCommandRun and virCommandWait that passed a non-NULL pointer for exit status turned up some interesting observations. Many callers were merely passing a pointer to avoid the overall command dying, but without caring what the exit status was - but these callers would be better off treating a child death by signal as an abnormal exit. Other callers were actually acting on the status, but not all of them remembered to filter by WIFEXITED and convert with WEXITSTATUS; depending on the platform, this can result in a status being reported as 256 times too big. And among those that correctly parse the output, it gets rather verbose. Finally, there were the callers that explicitly checked that the status was 0, and gave their own message, but with fewer details than what virCommand gives for free. So the best idea is to move the complexity out of callers and into virCommand - by default, we return the actual exit status already cleaned through WEXITSTATUS and treat signals as a failed command; but the few callers that care can ask for raw status and act on it themselves. * src/util/vircommand.h (virCommandRawStatus): New prototype. * src/libvirt_private.syms (util/command.h): Export it. * docs/internals/command.html.in: Document it. * src/util/vircommand.c (virCommandRawStatus): New function. (virCommandWait): Adjust semantics. * tests/commandtest.c (test1): Test it. * daemon/remote.c (remoteDispatchAuthPolkit): Adjust callers. * src/access/viraccessdriverpolkit.c (virAccessDriverPolkitCheck): Likewise. * src/fdstream.c (virFDStreamCloseInt): Likewise. * src/lxc/lxc_process.c (virLXCProcessStart): Likewise. * src/qemu/qemu_command.c (qemuCreateInBridgePortWithHelper): Likewise. * src/xen/xen_driver.c (xenUnifiedXendProbe): Simplify. * tests/reconnect.c (mymain): Likewise. * tests/statstest.c (mymain): Likewise. * src/bhyve/bhyve_process.c (virBhyveProcessStart) (virBhyveProcessStop): Don't overwrite virCommand error. * src/libvirt.c (virConnectAuthGainPolkit): Likewise. * src/openvz/openvz_driver.c (openvzDomainGetBarrierLimit) (openvzDomainSetBarrierLimit): Likewise. * src/util/virebtables.c (virEbTablesOnceInit): Likewise. * src/util/viriptables.c (virIpTablesOnceInit): Likewise. * src/util/virnetdevveth.c (virNetDevVethCreate): Fix debug message. * src/qemu/qemu_capabilities.c (virQEMUCapsInitQMP): Add comment. * src/storage/storage_backend_iscsi.c (virStorageBackendISCSINodeUpdate): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-20 00:32:19 +00:00
int ret = -1;
virCommandPtr cmd = virCommandNewArgList(VZCTL, "--quiet", "set", NULL);
/* LONG_MAX indicates unlimited so reject larger values */
if (barrier > LONG_MAX || limit > LONG_MAX) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("Failed to set %s for %s: value too large"), param,
domain->name);
goto cleanup;
}
virCommandAddArg(cmd, domain->name);
virCommandAddArgFormat(cmd, "--%s", param);
virCommandAddArgFormat(cmd, "%llu:%llu", barrier, limit);
virCommandAddArg(cmd, "--save");
util: make it easier to grab only regular command exit Auditing all callers of virCommandRun and virCommandWait that passed a non-NULL pointer for exit status turned up some interesting observations. Many callers were merely passing a pointer to avoid the overall command dying, but without caring what the exit status was - but these callers would be better off treating a child death by signal as an abnormal exit. Other callers were actually acting on the status, but not all of them remembered to filter by WIFEXITED and convert with WEXITSTATUS; depending on the platform, this can result in a status being reported as 256 times too big. And among those that correctly parse the output, it gets rather verbose. Finally, there were the callers that explicitly checked that the status was 0, and gave their own message, but with fewer details than what virCommand gives for free. So the best idea is to move the complexity out of callers and into virCommand - by default, we return the actual exit status already cleaned through WEXITSTATUS and treat signals as a failed command; but the few callers that care can ask for raw status and act on it themselves. * src/util/vircommand.h (virCommandRawStatus): New prototype. * src/libvirt_private.syms (util/command.h): Export it. * docs/internals/command.html.in: Document it. * src/util/vircommand.c (virCommandRawStatus): New function. (virCommandWait): Adjust semantics. * tests/commandtest.c (test1): Test it. * daemon/remote.c (remoteDispatchAuthPolkit): Adjust callers. * src/access/viraccessdriverpolkit.c (virAccessDriverPolkitCheck): Likewise. * src/fdstream.c (virFDStreamCloseInt): Likewise. * src/lxc/lxc_process.c (virLXCProcessStart): Likewise. * src/qemu/qemu_command.c (qemuCreateInBridgePortWithHelper): Likewise. * src/xen/xen_driver.c (xenUnifiedXendProbe): Simplify. * tests/reconnect.c (mymain): Likewise. * tests/statstest.c (mymain): Likewise. * src/bhyve/bhyve_process.c (virBhyveProcessStart) (virBhyveProcessStop): Don't overwrite virCommand error. * src/libvirt.c (virConnectAuthGainPolkit): Likewise. * src/openvz/openvz_driver.c (openvzDomainGetBarrierLimit) (openvzDomainSetBarrierLimit): Likewise. * src/util/virebtables.c (virEbTablesOnceInit): Likewise. * src/util/viriptables.c (virIpTablesOnceInit): Likewise. * src/util/virnetdevveth.c (virNetDevVethCreate): Fix debug message. * src/qemu/qemu_capabilities.c (virQEMUCapsInitQMP): Add comment. * src/storage/storage_backend_iscsi.c (virStorageBackendISCSINodeUpdate): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-20 00:32:19 +00:00
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
ret = 0;
cleanup:
virCommandFree(cmd);
return ret;
}
static int
openvzDomainGetMemoryParameters(virDomainPtr domain,
virTypedParameterPtr params,
int *nparams,
unsigned int flags)
{
size_t i;
int result = -1;
const char *name;
long kb_per_pages;
unsigned long long barrier, limit, val;
virCheckFlags(0, -1);
kb_per_pages = openvzKBPerPages();
if (kb_per_pages < 0)
goto cleanup;
if (*nparams == 0) {
*nparams = OPENVZ_NB_MEM_PARAM;
return 0;
}
for (i = 0; i <= *nparams; i++) {
virMemoryParameterPtr param = &params[i];
switch (i) {
case 0:
name = "privvmpages";
if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
goto cleanup;
val = (limit == LONG_MAX) ? 0ull : limit * kb_per_pages;
if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
VIR_TYPED_PARAM_ULLONG, val) < 0)
goto cleanup;
break;
case 1:
name = "privvmpages";
if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
goto cleanup;
val = (barrier == LONG_MAX) ? 0ull : barrier * kb_per_pages;
if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
VIR_TYPED_PARAM_ULLONG, val) < 0)
goto cleanup;
break;
case 2:
name = "vmguarpages";
if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
goto cleanup;
val = (barrier == LONG_MAX) ? 0ull : barrier * kb_per_pages;
if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
VIR_TYPED_PARAM_ULLONG, val) < 0)
goto cleanup;
break;
}
}
if (*nparams > OPENVZ_NB_MEM_PARAM)
*nparams = OPENVZ_NB_MEM_PARAM;
result = 0;
cleanup:
return result;
}
static int
openvzDomainSetMemoryParameters(virDomainPtr domain,
virTypedParameterPtr params,
int nparams,
unsigned int flags)
{
size_t i;
int result = -1;
long kb_per_pages;
kb_per_pages = openvzKBPerPages();
if (kb_per_pages < 0)
goto cleanup;
virCheckFlags(0, -1);
if (virTypedParamsValidate(params, nparams,
VIR_DOMAIN_MEMORY_HARD_LIMIT,
VIR_TYPED_PARAM_ULLONG,
VIR_DOMAIN_MEMORY_SOFT_LIMIT,
VIR_TYPED_PARAM_ULLONG,
VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
VIR_TYPED_PARAM_ULLONG,
NULL) < 0)
return -1;
for (i = 0; i < nparams; i++) {
virTypedParameterPtr param = &params[i];
unsigned long long barrier, limit;
if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
if (openvzDomainGetBarrierLimit(domain, "privvmpages",
&barrier, &limit) < 0)
goto cleanup;
limit = params[i].value.ul / kb_per_pages;
if (openvzDomainSetBarrierLimit(domain, "privvmpages",
barrier, limit) < 0)
goto cleanup;
} else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
if (openvzDomainGetBarrierLimit(domain, "privvmpages",
&barrier, &limit) < 0)
goto cleanup;
barrier = params[i].value.ul / kb_per_pages;
if (openvzDomainSetBarrierLimit(domain, "privvmpages",
barrier, limit) < 0)
goto cleanup;
} else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
barrier = params[i].value.ul / kb_per_pages;
if (openvzDomainSetBarrierLimit(domain, "vmguarpages",
barrier, LONG_MAX) < 0)
goto cleanup;
}
}
result = 0;
cleanup:
return result;
}
static int
openvzGetVEStatus(virDomainObjPtr vm, int *status, int *reason)
{
virCommandPtr cmd;
char *outbuf;
char *line;
int state;
int ret = -1;
cmd = virCommandNewArgList(VZLIST, vm->def->name, "-ostatus", "-H", NULL);
virCommandSetOutputBuffer(cmd, &outbuf);
if (virCommandRun(cmd, NULL) < 0)
goto cleanup;
if ((line = strchr(outbuf, '\n')) == NULL) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Failed to parse vzlist output"));
goto cleanup;
}
*line++ = '\0';
state = virDomainObjGetState(vm, reason);
if (STREQ(outbuf, "running")) {
/* There is no way to detect whether a domain is paused or not
* with vzlist */
if (state == VIR_DOMAIN_PAUSED)
*status = state;
else
*status = VIR_DOMAIN_RUNNING;
} else {
*status = VIR_DOMAIN_SHUTOFF;
}
ret = 0;
cleanup:
virCommandFree(cmd);
VIR_FREE(outbuf);
return ret;
}
static int
openvzDomainInterfaceStats(virDomainPtr dom,
const char *path,
struct _virDomainInterfaceStats *stats)
{
struct openvz_driver *driver = dom->conn->privateData;
virDomainObjPtr vm;
size_t i;
int ret = -1;
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
openvzDriverUnlock(driver);
if (!vm) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(dom->uuid, uuidstr);
virReportError(VIR_ERR_NO_DOMAIN,
_("no domain with matching uuid '%s'"), uuidstr);
goto cleanup;
}
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_OPERATION_INVALID,
"%s", _("domain is not running"));
goto cleanup;
}
/* Check the path is one of the domain's network interfaces. */
for (i = 0; i < vm->def->nnets; i++) {
if (vm->def->nets[i]->ifname &&
STREQ(vm->def->nets[i]->ifname, path)) {
ret = 0;
break;
}
}
if (ret == 0)
ret = linuxDomainInterfaceStats(path, stats);
else
virReportError(VIR_ERR_INVALID_ARG,
_("invalid path, '%s' is not a known interface"), path);
cleanup:
if (vm)
virObjectUnlock(vm);
return ret;
}
static int
openvzUpdateDevice(virDomainDefPtr vmdef,
virDomainDeviceDefPtr dev,
bool persist)
{
virDomainFSDefPtr fs, cur;
int pos;
if (dev->type == VIR_DOMAIN_DEVICE_FS) {
fs = dev->data.fs;
pos = virDomainFSIndexByName(vmdef, fs->dst);
if (pos < 0) {
virReportError(VIR_ERR_INVALID_ARG,
_("target %s doesn't exist."), fs->dst);
return -1;
}
cur = vmdef->fss[pos];
/* We only allow updating the quota */
if (!STREQ(cur->src, fs->src)
|| cur->type != fs->type
|| cur->accessmode != fs->accessmode
|| cur->wrpolicy != fs->wrpolicy
|| cur->readonly != fs->readonly) {
maint: don't permit format strings without % Any time we have a string with no % passed through gettext, a translator can inject a % to cause a stack overread. When there is nothing to format, it's easier to ask for a string that cannot be used as a formatter, by using a trivial "%s" format instead. In the past, we have used --disable-nls to catch some of the offenders, but that doesn't get run very often, and many more uses have crept in. Syntax check to the rescue! The syntax check can catch uses such as virReportError(code, _("split " "string")); by using a sed script to fold context lines into one pattern space before checking for a string without %. This patch is just mechanical insertion of %s; there are probably several messages touched by this patch where we would be better off giving the user more information than a fixed string. * cfg.mk (sc_prohibit_diagnostic_without_format): New rule. * src/datatypes.c (virUnrefConnect, virGetDomain) (virUnrefDomain, virGetNetwork, virUnrefNetwork, virGetInterface) (virUnrefInterface, virGetStoragePool, virUnrefStoragePool) (virGetStorageVol, virUnrefStorageVol, virGetNodeDevice) (virGetSecret, virUnrefSecret, virGetNWFilter, virUnrefNWFilter) (virGetDomainSnapshot, virUnrefDomainSnapshot): Add %s wrapper. * src/lxc/lxc_driver.c (lxcDomainSetBlkioParameters) (lxcDomainGetBlkioParameters): Likewise. * src/conf/domain_conf.c (virSecurityDeviceLabelDefParseXML) (virDomainDiskDefParseXML, virDomainGraphicsDefParseXML): Likewise. * src/conf/network_conf.c (virNetworkDNSHostsDefParseXML) (virNetworkDefParseXML): Likewise. * src/conf/nwfilter_conf.c (virNWFilterIsValidChainName): Likewise. * src/conf/nwfilter_params.c (virNWFilterVarValueCreateSimple) (virNWFilterVarAccessParse): Likewise. * src/libvirt.c (virDomainSave, virDomainSaveFlags) (virDomainRestore, virDomainRestoreFlags) (virDomainSaveImageGetXMLDesc, virDomainSaveImageDefineXML) (virDomainCoreDump, virDomainGetXMLDesc) (virDomainMigrateVersion1, virDomainMigrateVersion2) (virDomainMigrateVersion3, virDomainMigrate, virDomainMigrate2) (virStreamSendAll, virStreamRecvAll) (virDomainSnapshotGetXMLDesc): Likewise. * src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel) (virNWFilterDHCPSnoopReq): Likewise. * src/openvz/openvz_driver.c (openvzUpdateDevice): Likewise. * src/openvz/openvz_util.c (openvzKBPerPages): Likewise. * src/qemu/qemu_cgroup.c (qemuSetupCgroup): Likewise. * src/qemu/qemu_command.c (qemuBuildHubDevStr, qemuBuildChrChardevStr) (qemuBuildCommandLine): Likewise. * src/qemu/qemu_driver.c (qemuDomainGetPercpuStats): Likewise. * src/qemu/qemu_hotplug.c (qemuDomainAttachNetDevice): Likewise. * src/rpc/virnetsaslcontext.c (virNetSASLSessionGetIdentity): Likewise. * src/rpc/virnetsocket.c (virNetSocketNewConnectUNIX) (virNetSocketSendFD, virNetSocketRecvFD): Likewise. * src/storage/storage_backend_disk.c (virStorageBackendDiskBuildPool): Likewise. * src/storage/storage_backend_fs.c (virStorageBackendFileSystemProbe) (virStorageBackendFileSystemBuild): Likewise. * src/storage/storage_backend_rbd.c (virStorageBackendRBDOpenRADOSConn): Likewise. * src/storage/storage_driver.c (storageVolumeResize): Likewise. * src/test/test_driver.c (testInterfaceChangeBegin) (testInterfaceChangeCommit, testInterfaceChangeRollback): Likewise. * src/vbox/vbox_tmpl.c (vboxListAllDomains): Likewise. * src/xenxs/xen_sxpr.c (xenFormatSxprDisk, xenFormatSxpr): Likewise. * src/xenxs/xen_xm.c (xenXMConfigGetUUID, xenFormatXMDisk) (xenFormatXM): Likewise.
2012-07-23 20:33:08 +00:00
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
_("Can only modify disk quota"));
return -1;
}
if (openvzSetDiskQuota(vmdef, fs, persist) < 0) {
return -1;
}
cur->space_hard_limit = fs->space_hard_limit;
cur->space_soft_limit = fs->space_soft_limit;
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Can't modify device type '%s'"),
virDomainDeviceTypeToString(dev->type));
return -1;
}
return 0;
}
static int
openvzDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
unsigned int flags)
{
int ret = -1;
int veid;
struct openvz_driver *driver = dom->conn->privateData;
virDomainDeviceDefPtr dev = NULL;
virDomainObjPtr vm = NULL;
virDomainDefPtr vmdef = NULL;
bool persist = false;
virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);
openvzDriverLock(driver);
vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
if (!vm) {
virReportError(VIR_ERR_NO_DOMAIN, "%s",
_("no domain with matching uuid"));
goto cleanup;
}
vmdef = vm->def;
if (virStrToLong_i(vmdef->name, NULL, 10, &veid) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not convert domain name to VEID"));
goto cleanup;
}
if (virDomainLiveConfigHelperMethod(driver->caps,
driver->xmlopt,
vm,
&flags,
&vmdef) < 0)
goto cleanup;
dev = virDomainDeviceDefParse(xml, vmdef, driver->caps, driver->xmlopt,
VIR_DOMAIN_XML_INACTIVE);
if (!dev)
goto cleanup;
if (flags & VIR_DOMAIN_AFFECT_CONFIG)
persist = true;
if (openvzUpdateDevice(vmdef, dev, persist) < 0)
goto cleanup;
ret = 0;
cleanup:
openvzDriverUnlock(driver);
virDomainDeviceDefFree(dev);
if (vm)
virObjectUnlock(vm);
return ret;
}
static int
openvzConnectListAllDomains(virConnectPtr conn,
virDomainPtr **domains,
unsigned int flags)
{
struct openvz_driver *driver = conn->privateData;
int ret = -1;
virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
openvzDriverLock(driver);
ret = virDomainObjListExport(driver->domains, conn, domains,
NULL, flags);
openvzDriverUnlock(driver);
return ret;
}
static int
openvzNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
virNodeInfoPtr nodeinfo)
{
return nodeGetInfo(nodeinfo);
}
static int
openvzNodeGetCPUStats(virConnectPtr conn ATTRIBUTE_UNUSED,
int cpuNum,
virNodeCPUStatsPtr params,
int *nparams,
unsigned int flags)
{
return nodeGetCPUStats(cpuNum, params, nparams, flags);
}
static int
openvzNodeGetMemoryStats(virConnectPtr conn ATTRIBUTE_UNUSED,
int cellNum,
virNodeMemoryStatsPtr params,
int *nparams,
unsigned int flags)
{
return nodeGetMemoryStats(cellNum, params, nparams, flags);
}
static int
openvzNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
unsigned long long *freeMems,
int startCell,
int maxCells)
{
return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}
static unsigned long long
openvzNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
{
unsigned long long freeMem;
if (nodeGetMemory(NULL, &freeMem) < 0)
return 0;
return freeMem;
}
static int
openvzNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
unsigned char **cpumap,
unsigned int *online,
unsigned int flags)
{
return nodeGetCPUMap(cpumap, online, flags);
}
static virDriver openvzDriver = {
.no = VIR_DRV_OPENVZ,
.name = "OPENVZ",
.connectOpen = openvzConnectOpen, /* 0.3.1 */
.connectClose = openvzConnectClose, /* 0.3.1 */
.connectGetType = openvzConnectGetType, /* 0.3.1 */
.connectGetVersion = openvzConnectGetVersion, /* 0.5.0 */
.connectGetHostname = openvzConnectGetHostname, /* 0.9.12 */
.connectGetMaxVcpus = openvzConnectGetMaxVcpus, /* 0.4.6 */
.nodeGetInfo = openvzNodeGetInfo, /* 0.3.2 */
.nodeGetCPUStats = openvzNodeGetCPUStats, /* 0.9.12 */
.nodeGetMemoryStats = openvzNodeGetMemoryStats, /* 0.9.12 */
.nodeGetCellsFreeMemory = openvzNodeGetCellsFreeMemory, /* 0.9.12 */
.nodeGetFreeMemory = openvzNodeGetFreeMemory, /* 0.9.12 */
.nodeGetCPUMap = openvzNodeGetCPUMap, /* 1.0.0 */
.connectGetCapabilities = openvzConnectGetCapabilities, /* 0.4.6 */
.connectListDomains = openvzConnectListDomains, /* 0.3.1 */
.connectNumOfDomains = openvzConnectNumOfDomains, /* 0.3.1 */
.connectListAllDomains = openvzConnectListAllDomains, /* 0.9.13 */
.domainCreateXML = openvzDomainCreateXML, /* 0.3.3 */
.domainLookupByID = openvzDomainLookupByID, /* 0.3.1 */
.domainLookupByUUID = openvzDomainLookupByUUID, /* 0.3.1 */
.domainLookupByName = openvzDomainLookupByName, /* 0.3.1 */
.domainSuspend = openvzDomainSuspend, /* 0.8.3 */
.domainResume = openvzDomainResume, /* 0.8.3 */
.domainShutdown = openvzDomainShutdown, /* 0.3.1 */
.domainShutdownFlags = openvzDomainShutdownFlags, /* 0.9.10 */
.domainReboot = openvzDomainReboot, /* 0.3.1 */
.domainDestroy = openvzDomainDestroy, /* 0.3.1 */
.domainDestroyFlags = openvzDomainDestroyFlags, /* 0.9.4 */
.domainGetOSType = openvzDomainGetOSType, /* 0.3.1 */
.domainGetMemoryParameters = openvzDomainGetMemoryParameters, /* 0.9.12 */
.domainSetMemoryParameters = openvzDomainSetMemoryParameters, /* 0.9.12 */
.domainGetInfo = openvzDomainGetInfo, /* 0.3.1 */
.domainGetState = openvzDomainGetState, /* 0.9.2 */
.domainSetVcpus = openvzDomainSetVcpus, /* 0.4.6 */
.domainSetVcpusFlags = openvzDomainSetVcpusFlags, /* 0.8.5 */
.domainGetVcpusFlags = openvzDomainGetVcpusFlags, /* 0.8.5 */
.domainGetMaxVcpus = openvzDomainGetMaxVcpus, /* 0.4.6 */
.domainGetXMLDesc = openvzDomainGetXMLDesc, /* 0.4.6 */
.connectListDefinedDomains = openvzConnectListDefinedDomains, /* 0.3.1 */
.connectNumOfDefinedDomains = openvzConnectNumOfDefinedDomains, /* 0.3.1 */
.domainCreate = openvzDomainCreate, /* 0.3.1 */
.domainCreateWithFlags = openvzDomainCreateWithFlags, /* 0.8.2 */
.domainDefineXML = openvzDomainDefineXML, /* 0.3.3 */
.domainUndefine = openvzDomainUndefine, /* 0.3.3 */
.domainUndefineFlags = openvzDomainUndefineFlags, /* 0.9.4 */
.domainGetAutostart = openvzDomainGetAutostart, /* 0.4.6 */
.domainSetAutostart = openvzDomainSetAutostart, /* 0.4.6 */
.domainInterfaceStats = openvzDomainInterfaceStats, /* 0.9.12 */
.connectIsEncrypted = openvzConnectIsEncrypted, /* 0.7.3 */
.connectIsSecure = openvzConnectIsSecure, /* 0.7.3 */
.domainIsActive = openvzDomainIsActive, /* 0.7.3 */
.domainIsPersistent = openvzDomainIsPersistent, /* 0.7.3 */
.domainIsUpdated = openvzDomainIsUpdated, /* 0.8.6 */
.connectIsAlive = openvzConnectIsAlive, /* 0.9.8 */
.domainUpdateDeviceFlags = openvzDomainUpdateDeviceFlags, /* 0.9.13 */
.domainGetHostname = openvzDomainGetHostname, /* 0.10.0 */
};
int openvzRegister(void)
{
if (virRegisterDriver(&openvzDriver) < 0)
return -1;
return 0;
}