From b55718444f589e7497e804ac9e3611d9477362a2 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Tue, 17 Jul 2007 13:27:26 +0000 Subject: [PATCH] * configure.in src/Makefile.am src/driver.h src/libvirt.c: applied patch from Shuveb Hussain to plug the developping OpenVZ support. Disabled by default. * src/openvz_conf.[ch] src/openvz_driver.[ch]: added new OpenVZ driver files. Avoid a redefinition of readline(). Daniel --- ChangeLog | 8 + configure.in | 8 + src/Makefile.am | 4 +- src/driver.h | 1 + src/libvirt.c | 5 +- src/openvz_conf.c | 491 +++++++++++++++++++++++++++++++++++++++++++ src/openvz_conf.h | 114 ++++++++++ src/openvz_driver.c | 501 ++++++++++++++++++++++++++++++++++++++++++++ src/openvz_driver.h | 52 +++++ 9 files changed, 1182 insertions(+), 2 deletions(-) create mode 100644 src/openvz_conf.c create mode 100644 src/openvz_conf.h create mode 100644 src/openvz_driver.c create mode 100644 src/openvz_driver.h diff --git a/ChangeLog b/ChangeLog index 13c42ea0ef..fa164717b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Tue Jul 17 15:24:27 CEST 2007 Daniel Veillard + + * configure.in src/Makefile.am src/driver.h src/libvirt.c: + applied patch from Shuveb Hussain to plug the developping + OpenVZ support. Disabled by default. + * src/openvz_conf.[ch] src/openvz_driver.[ch]: added new + OpenVZ driver files. Avoid a redefinition of readline(). + Mon Jul 16 17:36:24 EST 2007 Daniel P. Berrange * docs/libvir.html, docs/remote.html: Re-write notes on IPV6 diff --git a/configure.in b/configure.in index dc5e38052c..7ceebe1fe4 100644 --- a/configure.in +++ b/configure.in @@ -75,6 +75,8 @@ AC_ARG_WITH(xen, [ --with-xen add XEN support (on)]) AC_ARG_WITH(qemu, [ --with-qemu add QEMU/KVM support (on)]) +AC_ARG_WITH(openvz, +[ --with-openvz add OpenVZ support (off)]) AC_ARG_WITH(test, [ --with-test add test driver support (on)]) AC_ARG_WITH(remote, @@ -173,6 +175,12 @@ AC_ARG_WITH(depends, LIBVIRT_FEATURES= WITH_XEN=0 +if test "$with_openvz" = "yes" ; then + echo "Enabling OpenVZ support" + LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_OPENVZ" +else + echo "Disabling OpenVZ support" +fi if test "$with_qemu" = "no" ; then echo "Disabling QEMU/KVM support" else diff --git a/src/Makefile.am b/src/Makefile.am index 8bb87ce900..c4bf4a2ac8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,7 +47,9 @@ CLIENT_SOURCES = \ iptables.c iptables.h \ uuid.c uuid.h \ qemu_driver.c qemu_driver.h \ - qemu_conf.c qemu_conf.h + qemu_conf.c qemu_conf.h \ + openvz_conf.c openvz_conf.h \ + openvz_driver.c openvz_driver.h SERVER_SOURCES = \ ../qemud/protocol.h ../qemud/protocol.c \ diff --git a/src/driver.h b/src/driver.h index fe4f9e2439..9b2b196403 100644 --- a/src/driver.h +++ b/src/driver.h @@ -21,6 +21,7 @@ typedef enum { VIR_DRV_TEST = 2, VIR_DRV_QEMU = 3, VIR_DRV_REMOTE = 4, + VIR_DRV_OPENVZ = 5, } virDrvNo; diff --git a/src/libvirt.c b/src/libvirt.c index 1ef11dc809..cc750e0643 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -85,12 +85,15 @@ virInitialize(void) #ifdef WITH_TEST if (testRegister() == -1) return -1; #endif -#ifdef WITH_QEMU +#ifdef WITH_QEMU if (qemudRegister() == -1) return -1; #endif #ifdef WITH_XEN if (xenUnifiedRegister () == -1) return -1; #endif +#ifdef WITH_OPENVZ + if (openvzRegister() == -1) return -1; +#endif #ifdef WITH_REMOTE if (remoteRegister () == -1) return -1; #endif diff --git a/src/openvz_conf.c b/src/openvz_conf.c new file mode 100644 index 0000000000..ad4bb73bdc --- /dev/null +++ b/src/openvz_conf.c @@ -0,0 +1,491 @@ +/* + * openvz_conf.c: config functions for managing OpenVZ VEs + * + * Copyright (C) 2006, 2007 Binary Karma + * Copyright (C) 2006 Shuveb Hussain + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Shuveb Hussain + */ + +#ifdef WITH_OPENVZ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "openvz_conf.h" +#include "openvz_driver.h" +#include "uuid.h" +#include "buf.h" + + +/* For errors internal to this library. */ +static void +error (virConnectPtr conn, virErrorNumber code, const char *info) +{ + const char *errmsg; + + errmsg = __virErrorMsg (code, info); + __virRaiseError (conn, NULL, NULL, VIR_FROM_REMOTE, + code, VIR_ERR_ERROR, errmsg, info, NULL, 0, 0, + errmsg, info); +} + +struct openvz_vm *openvzFindVMByID(const struct openvz_driver *driver, int id) { + struct openvz_vm *vm = driver->vms; + + while (vm) { + if (vm->vpsid == id) + return vm; + vm = vm->next; + } + + return NULL; +} + +struct openvz_vm *openvzFindVMByUUID(const struct openvz_driver *driver, + const unsigned char *uuid) { + struct openvz_vm *vm = driver->vms; + + while (vm) { + if (!memcmp(vm->vmdef->uuid, uuid, OPENVZ_UUID_MAX)) + return vm; + vm = vm->next; + } + + return NULL; +} + +struct openvz_vm *openvzFindVMByName(const struct openvz_driver *driver, + const char *name) { + struct openvz_vm *vm = driver->vms; + + while (vm) { + if (!strcmp(vm->vmdef->name, name)) + return vm; + vm = vm->next; + } + + return NULL; +} + +/* Free all memory associated with a struct openvz_vm object */ +void openvzFreeVMDef(struct openvz_vm_def *def) { + struct ovz_quota *quota = def->fs.quota; + struct ovz_ip *ip = def->net.ips; + struct ovz_ns *ns = def->net.ns; + + while (quota) { + struct ovz_quota *prev = quota; + quota = quota->next; + free(prev); + } + while (ip) { + struct ovz_ip *prev = ip; + ip = ip->next; + free(prev); + } + while (ns) { + struct ovz_ns *prev = ns; + ns = ns->next; + free(prev); + } + + free(def); +} + +/* + * Parses a libvirt XML definition of a guest, and populates the + * the openvz_vm struct with matching data about the guests config + */ +static struct openvz_vm_def *openvzParseXML(virConnectPtr conn, + xmlDocPtr xml) { + xmlNodePtr root = NULL; + xmlChar *prop = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + struct openvz_vm_def *def; + + if (!(def = calloc(1, sizeof(struct openvz_vm_def)))) { + error(conn, VIR_ERR_NO_MEMORY, "xmlXPathContext"); + return NULL; + } + + /* Prepare parser / xpath context */ + root = xmlDocGetRootElement(xml); + if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) { + error(conn, VIR_ERR_INTERNAL_ERROR, "incorrect root element"); + goto bail_out; + } + + ctxt = xmlXPathNewContext(xml); + if (ctxt == NULL) { + error(conn, VIR_ERR_NO_MEMORY, "xmlXPathContext"); + goto bail_out; + } + + + /* Find out what type of QEMU virtualization to use */ + if (!(prop = xmlGetProp(root, BAD_CAST "type"))) { + error(conn, VIR_ERR_INTERNAL_ERROR, "missing domain type attribute"); + goto bail_out; + } + + if (strcmp((char *)prop, "openvz")){ + error(conn, VIR_ERR_INTERNAL_ERROR, "invalid domain type attribute"); + goto bail_out; + } + free(prop); + prop = NULL; + + /* Extract domain name */ + obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_NUMBER) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + error(conn, VIR_ERR_INTERNAL_ERROR,"invalid domain name"); + goto bail_out; + } + if (0/* check if VPS ID is < 101 */) { + error(conn, VIR_ERR_INTERNAL_ERROR, "VPS ID is less than 101"); + goto bail_out; + } + strcpy(def->name, (const char *)obj->stringval); + xmlXPathFreeObject(obj); + + /* Extract domain uuid */ + obj = xmlXPathEval(BAD_CAST "string(/domain/uuid[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + int err; + if ((err = virUUIDGenerate(def->uuid))) { + error(conn, VIR_ERR_INTERNAL_ERROR, + "Failed to generate UUID"); + goto bail_out; + } + } else if (virUUIDParse((const char *)obj->stringval, def->uuid) < 0) { + error(conn, VIR_ERR_INTERNAL_ERROR, "malformed uuid element"); + goto bail_out; + } + xmlXPathFreeObject(obj); + + /* Extract filesystem info */ + obj = xmlXPathEval(BAD_CAST "string(/domain/filesystem/template[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || + (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + error(conn, VIR_ERR_OS_TYPE, NULL); + goto bail_out; + } + strcpy(def->fs.tmpl, (const char *)obj->stringval); + xmlXPathFreeObject(obj); + + /* TODO Add quota processing here */ + + /* TODO analysis of the network devices */ + + xmlXPathFreeContext(ctxt); + + return def; + + bail_out: + if (prop) + free(prop); + if (obj) + xmlXPathFreeObject(obj); + if (ctxt) + xmlXPathFreeContext(ctxt); + openvzFreeVMDef(def); + return NULL; +} + +struct openvz_vm_def * +openvzParseVMDef(virConnectPtr conn, + const char *xmlStr, + const char *displayName) { + xmlDocPtr xml; + struct openvz_vm_def *def = NULL; + + if (!(xml = xmlReadDoc(BAD_CAST xmlStr, displayName ? displayName : "domain.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | + XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) { + error(conn, VIR_ERR_XML_ERROR, NULL); + return NULL; + } + + def = openvzParseXML(conn, xml); + + xmlFreeDoc(xml); + + return def; +} + +struct openvz_vm * +openvzGetVPSInfo(virConnectPtr conn) { + FILE *fp; + int veid, ret; + char status[16]; + char uuidstr[(VIR_UUID_BUFLEN * 2) + 1]; + struct openvz_vm *vm; + struct openvz_vm **pnext; + struct openvz_driver *driver; + struct openvz_vm_def *vmdef; + + vm = NULL; + driver = conn->privateData; + driver->num_active = 0; + driver->num_inactive = 0; + + if((fp = popen(VZLIST " -a -ovpsid,status -H 2>/dev/null", "r")) == NULL) { + error(conn, VIR_ERR_INTERNAL_ERROR, "popen failed"); + return NULL; + } + pnext = &vm; + while(!feof(fp)) { + *pnext = malloc(sizeof(struct openvz_vm)); + if(!*pnext) { + error(conn, VIR_ERR_INTERNAL_ERROR, "malloc failed"); + return NULL; + } + + if(!vm) + vm = *pnext; + + fscanf(fp, "%d %s\n", &veid, status); + if(strcmp(status, "stopped")) { + (*pnext)->status = VIR_DOMAIN_RUNNING; + driver->num_active ++; + (*pnext)->vpsid = veid; + } + else { + (*pnext)->status = VIR_DOMAIN_SHUTOFF; + driver->num_inactive ++; + (*pnext)->vpsid = -1; /* inactive domains don't have their ID set in libvirt, + thought this doesn't make sense for OpenVZ */ + } + + vmdef = malloc(sizeof(struct openvz_vm_def)); + if(!vmdef) { + error(conn, VIR_ERR_INTERNAL_ERROR, "malloc failed"); + return NULL; + } + + snprintf(vmdef->name, OPENVZ_NAME_MAX, "%i", veid); + openvzGetVPSUUID(veid, uuidstr); + ret = sscanf(uuidstr, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + (unsigned int *)&vmdef->uuid[0], (unsigned int *)&vmdef->uuid[1], (unsigned int *)&vmdef->uuid[2], + (unsigned int *)&vmdef->uuid[3], (unsigned int *)&vmdef->uuid[4], (unsigned int *)&vmdef->uuid[5], + (unsigned int *)&vmdef->uuid[6], (unsigned int *)&vmdef->uuid[7], (unsigned int *)&vmdef->uuid[8], + (unsigned int *)&vmdef->uuid[9], (unsigned int *)&vmdef->uuid[10], (unsigned int *)&vmdef->uuid[11], + (unsigned int *)&vmdef->uuid[12], (unsigned int *)&vmdef->uuid[13], (unsigned int *)&vmdef->uuid[14], + (unsigned int *)&vmdef->uuid[15]); + + if(ret != 16) { + error(conn, VIR_ERR_INTERNAL_ERROR, "UUID in config file malformed"); + return NULL; + } + + (*pnext)->vmdef = vmdef; + pnext = &(*pnext)->next; + } + return vm; +} + +char *openvzLocateConfDir(void) +{ + const char *conf_dir_list[] = {"/etc/vz/conf", "/usr/local/etc/conf", NULL}; + int i=0; + + while(conf_dir_list[i]) { + if(!access(conf_dir_list[i], F_OK)) + return strdup(conf_dir_list[i]); + i ++; + } + + return NULL; +} + +/* Richard Steven's classic readline() function */ + +int openvz_readline(int fd, char *ptr, int maxlen) +{ + int n, rc; + char c; + + for(n = 1; n < maxlen; n ++) { + if( (rc = read(fd, &c, 1)) == 1) { + *ptr++ = c; + if(c == '\n') + break; + } + else if(rc == 0) { + if(n == 1) + return 0; /* EOF condition */ + else + break; + } + else + return -1; /* error */ + } + *ptr = 0; + return n; +} + +void openvzGenerateUUID(unsigned char *uuid) +{ + unsigned int i; + int fd; + + /* seed rand() with kernel entrophy */ + fd = open("/dev/urandom", O_RDONLY); + if(fd != -1) { + read(fd, &i, sizeof(int)); + srand(i); + close(fd); + } + else { + srand((int) time(NULL)); + } + + for (i = 0 ; i < VIR_UUID_BUFLEN ; i++) { + uuid[i] = (unsigned char)(1 + (int) (256.0 * (rand() / (RAND_MAX + 1.0)))); + } +} + +int openvzGetVPSUUID(int vpsid, char *uuidbuf) +{ + char conf_file[PATH_MAX]; + char line[1024]; + char uuid[1024]; + char iden[1024]; + char *conf_dir; + int fd, ret; + + conf_dir = openvzLocateConfDir(); + sprintf(conf_file, "%s/%d.conf", conf_dir, vpsid); + free(conf_dir); + + fd = open(conf_file, O_RDWR); + if(fd == -1) + return -1; + + while(1) { + ret = openvz_readline(fd, line, sizeof(line)); + if(ret == -1) + return -1; + + if(ret == 0) { /* EoF, UUID was not found */ + uuidbuf[0] = (char)NULL; + break; + } + + sscanf(line, "%s %s\n", iden, uuid); + if(!strcmp(iden, "#UUID:")) { + strncpy(uuidbuf, uuid, (VIR_UUID_BUFLEN * 2) +1); + break; + } + } + return 0; +} + +/* Do actual checking for UUID presence in conf file, + * assign if not present. + */ + +int openvzSetUUID(int vpsid) +{ + char conf_file[PATH_MAX]; + char uuid[(VIR_UUID_BUFLEN * 2) + 1]; + unsigned char new_uuid[VIR_UUID_BUFLEN]; + char *conf_dir; + int fd, ret, i; + + conf_dir = openvzLocateConfDir(); + sprintf(conf_file, "%s/%d.conf", conf_dir, vpsid); + free(conf_dir); + + fd = open(conf_file, O_RDWR); + if(fd == -1) + return -1; + + ret = openvzGetVPSUUID(vpsid, uuid); + if(ret == -1) + return -1; + + if(uuid[0] == (int)NULL) { + openvzGenerateUUID(new_uuid); + bzero(uuid, (VIR_UUID_BUFLEN * 2) + 1); + for(i = 0; i < VIR_UUID_BUFLEN; i ++) + sprintf(uuid + (i * 2), "%02x", (unsigned char)new_uuid[i]); + + lseek(fd, 0, SEEK_END); + write(fd, "\n#UUID: ", 8); + write(fd, uuid, strlen(uuid)); + write(fd, "\n", 1); + close(fd); + } + + return 0; +} + +/* + * Scan VPS config files and see if they have a UUID. + * If not, assign one. Just append one to the config + * file as comment so that the OpenVZ tools ignore it. + * + */ + +int openvzAssignUUIDs(void) +{ + DIR *dp; + struct dirent *dent; + char *conf_dir; + int vpsid, res; + char ext[8]; + + conf_dir = openvzLocateConfDir(); + + dp = opendir(conf_dir); + if(dp == NULL) { + free(conf_dir); + return 0; + } + + while((dent = readdir(dp))) { + res = sscanf(dent->d_name, "%d.%5s", &vpsid, ext); + if(!(res == 2 && !strcmp(ext, "conf"))) + continue; + if(vpsid > 0) /* '0.conf' belongs to the host, ignore it */ + openvzSetUUID(vpsid); + } + closedir(dp); + free(conf_dir); + return 0; +} + +#endif + diff --git a/src/openvz_conf.h b/src/openvz_conf.h new file mode 100644 index 0000000000..ffc773868c --- /dev/null +++ b/src/openvz_conf.h @@ -0,0 +1,114 @@ +/* + * openvz_config.h: config information for OpenVZ VPSs + * + * Copyright (C) 2006, 2007 Binary Karma. + * Copyright (C) 2006 Shuveb Hussain + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Shuveb Hussain + */ + +#ifndef OPENVZ_CONF_H +#define OPENVZ_CONF_H + +#include "openvz_driver.h" + +#define OPENVZ_NAME_MAX 8 +#define OPENVZ_UUID_MAX 16 +#define OPENVZ_TMPL_MAX 256 +#define OPENVZ_UNAME_MAX 32 +#define OPENVZ_IP_MAX 16 +#define OPENVZ_HOSTNAME_MAX 256 +#define OPENVZ_PROFILE_MAX 256 + +enum openvz_quota{ + VM_LEVEL = 0, + USER_LEVEL = 1, +}; + +/* TODO Add more properties here */ +struct vps_props { + int kmemsize; /* currently held */ + int kmemsize_m; /* max held */ + int kmemsize_b; /* barrier */ + int kmemsize_l; /* limit */ + int kmemsize_f; /* fail count */ + +}; + +struct openvz_fs_def { + char tmpl[OPENVZ_TMPL_MAX]; + struct ovz_quota *quota; +}; + +struct ovz_ip { + char ip[OPENVZ_IP_MAX]; + char netmask[OPENVZ_IP_MAX]; + struct ovz_ip *next; +}; + +struct ovz_ns { + char ip[OPENVZ_IP_MAX]; + struct ovz_ns *next; +}; + +struct openvz_net_def { + char hostname[OPENVZ_HOSTNAME_MAX]; + char def_gw[OPENVZ_IP_MAX]; + struct ovz_ip *ips; + struct ovz_ns *ns; +}; + +struct openvz_vm_def { + char name[OPENVZ_NAME_MAX]; + unsigned char uuid[OPENVZ_UUID_MAX]; + char profile[OPENVZ_PROFILE_MAX]; + struct openvz_fs_def fs; + struct openvz_net_def net; +}; + +struct ovz_quota { + enum openvz_quota type; + unsigned int size; + char uname[OPENVZ_UNAME_MAX]; + struct ovz_quota *next; +}; + +struct openvz_vm { + int vpsid; + int status; + struct openvz_vm_def *vmdef; + struct openvz_vm *next; +}; + +char *openvzLocateConfDir(void); +int readline(int fd, char *ptr, int maxlen); +static void error (virConnectPtr conn, virErrorNumber code, const char *info); +struct openvz_vm *openvzFindVMByID(const struct openvz_driver *driver, int id); +struct openvz_vm *openvzFindVMByUUID(const struct openvz_driver *driver, + const unsigned char *uuid); +struct openvz_vm *openvzFindVMByName(const struct openvz_driver *driver, + const char *name); +void openvzFreeVMDef(struct openvz_vm_def *def); +static struct openvz_vm_def *openvzParseXML(virConnectPtr conn, xmlDocPtr xml); +struct openvz_vm_def *openvzParseVMDef(virConnectPtr conn, const char *xmlStr, + const char *displayName); +struct openvz_vm *openvzGetVPSInfo(virConnectPtr conn); +void openvzGenerateUUID(unsigned char *uuid); +int openvzGetVPSUUID(int vpsid, char *uuidbuf); +int openvzSetUUID(int vpsid); +int openvzAssignUUIDs(void); +#endif /* OPENVZ_CONF_H */ diff --git a/src/openvz_driver.c b/src/openvz_driver.c new file mode 100644 index 0000000000..18afd86b39 --- /dev/null +++ b/src/openvz_driver.c @@ -0,0 +1,501 @@ +/* + * openvz_driver.c: core driver methods for managing OpenVZ VEs + * + * Copyright (C) 2006, 2007 Binary Karma + * Copyright (C) 2006 Shuveb Hussain + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Shuveb Hussain + */ + +#ifdef WITH_OPENVZ + +#include + +#define _GNU_SOURCE /* for asprintf */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "event.h" +#include "buf.h" +#include "openvz_driver.h" +#include "openvz_conf.h" + + +#define openvzLog(level, msg...) fprintf(stderr, msg) + +static virDomainPtr openvzDomainLookupByID(virConnectPtr conn, int id); +static char *openvzGetOSType(virDomainPtr dom); +static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid); +static virDomainPtr openvzDomainLookupByName(virConnectPtr conn, const char *name); +static int openvzDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info); +static int openvzDomainShutdown(virDomainPtr dom); +static int openvzDomainReboot(virDomainPtr dom, unsigned int flags); +static int openvzDomainCreate(virDomainPtr dom); +static virDrvOpenStatus openvzOpen(virConnectPtr conn, const char *name, + int flags ATTRIBUTE_UNUSED); +static int openvzClose(virConnectPtr conn); +static const char *openvzGetType(virConnectPtr conn ATTRIBUTE_UNUSED); +static int openvzListDomains(virConnectPtr conn, int *ids, int nids); +static int openvzNumDomains(virConnectPtr conn); +static int openvzListDefinedDomains(virConnectPtr conn, char **const names, int nnames); +static int openvzNumDefinedDomains(virConnectPtr conn); +static int openvzStartup(void); +static int openvzShutdown(void); +static int openvzReload(void); +static int openvzActive(void); +static int openvzCloseNetwork(virConnectPtr conn); +static virDrvOpenStatus openvzOpenNetwork(virConnectPtr conn, const char *name ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED); +struct openvz_driver ovz_driver; + +/* For errors internal to this library. */ +static void +error (virConnectPtr conn, virErrorNumber code, const char *info) +{ + const char *errmsg; + + errmsg = __virErrorMsg (code, info); + __virRaiseError (conn, NULL, NULL, VIR_FROM_REMOTE, + code, VIR_ERR_ERROR, errmsg, info, NULL, 0, 0, + errmsg, info); +} + +static virDomainPtr openvzDomainLookupByID(virConnectPtr conn, + int id) { + struct openvz_driver *driver = (struct openvz_driver *)conn->privateData; + struct openvz_vm *vm = openvzFindVMByID(driver, id); + virDomainPtr dom; + + if (!vm) { + error(conn, VIR_ERR_INTERNAL_ERROR, "no domain with matching id"); + return NULL; + } + + dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid); + if (!dom) { + error(conn, VIR_ERR_NO_MEMORY, "virDomainPtr"); + return NULL; + } + + dom->id = vm->vpsid; + return dom; +} + +static char *openvzGetOSType(virDomainPtr dom) +{ + /* OpenVZ runs on Linux and runs only Linux */ + return strdup("Linux"); +} + + +static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) { + struct openvz_driver *driver = (struct openvz_driver *)conn->privateData; + struct openvz_vm *vm = openvzFindVMByUUID(driver, uuid); + virDomainPtr dom; + + if (!vm) { + error(conn, VIR_ERR_INTERNAL_ERROR, "no domain with matching uuid"); + return NULL; + } + + dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid); + if (!dom) { + error(conn, VIR_ERR_NO_MEMORY, "virDomainPtr"); + return NULL; + } + + dom->id = vm->vpsid; + return dom; +} + +static virDomainPtr openvzDomainLookupByName(virConnectPtr conn, + const char *name) { + struct openvz_driver *driver = (struct openvz_driver *)conn->privateData; + struct openvz_vm *vm = openvzFindVMByName(driver, name); + virDomainPtr dom; + + if (!vm) { + error(conn, VIR_ERR_INTERNAL_ERROR, "no domain with matching name"); + return NULL; + } + + dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid); + if (!dom) { + error(conn, VIR_ERR_NO_MEMORY, "virDomainPtr"); + return NULL; + } + + dom->id = vm->vpsid; + return dom; +} + +static int openvzDomainGetInfo(virDomainPtr dom, + virDomainInfoPtr info) { + struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData; + struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid); + if (!vm) { + error(dom->conn, VIR_ERR_INVALID_DOMAIN, "no domain with matching uuid"); + return -1; + } + + info->state = vm->status; + + /* TODO These need to be calculated differently for OpenVZ */ + //info->cpuTime = + //info->maxMem = vm->def->maxmem; + //info->memory = vm->def->memory; + //info->nrVirtCpu = vm->def->vcpus; + return 0; +} + +static int openvzDomainShutdown(virDomainPtr dom) { + char cmdbuf[1024]; + int ret; + struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData; + struct openvz_vm *vm = openvzFindVMByID(driver, dom->id); + + if (!vm) { + error(dom->conn, VIR_ERR_INVALID_DOMAIN, "no domain with matching id"); + return -1; + } + + if (vm->status != VIR_DOMAIN_RUNNING) { + error(dom->conn, VIR_ERR_OPERATION_DENIED, "domain is not in running state"); + return -1; + } + + snprintf(cmdbuf, 1024, VZCTL " stop %d >/dev/null 2>&1", dom->id); + ret = system(cmdbuf); + if(WEXITSTATUS(ret)) { + error(dom->conn, VIR_ERR_OPERATION_FAILED, "could not shutdown domain"); + return -1; + } + vm->vpsid = -1; + vm->status = VIR_DOMAIN_SHUTOFF; + ovz_driver.num_inactive ++; + ovz_driver.num_active --; + + return ret; +} + +static int openvzDomainReboot(virDomainPtr dom, unsigned int flags) { + char cmdbuf[1024]; + int ret; + struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData; + struct openvz_vm *vm = openvzFindVMByID(driver, dom->id); + + if (!vm) { + error(dom->conn, VIR_ERR_INVALID_DOMAIN, "no domain with matching id"); + return -1; + } + + if (vm->status != VIR_DOMAIN_RUNNING) { + error(dom->conn, VIR_ERR_OPERATION_DENIED, "domain is not in running state"); + return -1; + } + + snprintf(cmdbuf, 1024, VZCTL " restart %d >/dev/null 2>&1", dom->id); + ret = system(cmdbuf); + if(WEXITSTATUS(ret)) { + error(dom->conn, VIR_ERR_OPERATION_FAILED, "could not reboot domain"); + return -1; + } + + return ret; +} + +static int openvzDomainCreate(virDomainPtr dom) { + char cmdbuf[1024]; + int ret; + struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData; + struct openvz_vm *vm = openvzFindVMByID(driver, dom->id); + struct openvz_vm_def *vmdef; + + if (!vm) { + error(dom->conn, VIR_ERR_INVALID_DOMAIN, "no domain with matching id"); + return -1; + } + + if (vm->status != VIR_DOMAIN_SHUTOFF) { + error(dom->conn, VIR_ERR_OPERATION_DENIED, "domain is not in shutoff state"); + return -1; + } + + vmdef = vm->vmdef; + snprintf(cmdbuf, 1024, VZCTL " start %s >/dev/null 2>&1", vmdef->name); + ret = system(cmdbuf); + if(WEXITSTATUS(ret)) { + error(dom->conn, VIR_ERR_OPERATION_FAILED, "could not start domain"); + return -1; + } + sscanf(vmdef->name, "%d", &vm->vpsid); + vm->status = VIR_DOMAIN_RUNNING; + ovz_driver.num_inactive --; + ovz_driver.num_active ++; + + return ret; +} + +static virDrvOpenStatus openvzOpen(virConnectPtr conn, + const char *name, + int flags ATTRIBUTE_UNUSED) { + struct openvz_vm *vms; + + /* Just check if the guy is root. Nothing really to open for OpenVZ */ + if (getuid()) { // OpenVZ tools can only be used by r00t + return VIR_DRV_OPEN_DECLINED; + } else { + if (strcmp(name, "openvz:///system")) + return VIR_DRV_OPEN_DECLINED; + } + + conn->privateData = &ovz_driver; + + virStateInitialize(); + vms = openvzGetVPSInfo(conn); + ovz_driver.vms = vms; + + return VIR_DRV_OPEN_SUCCESS; +} + +static int openvzClose(virConnectPtr conn) { + + struct openvz_driver *driver = (struct openvz_driver *)conn->privateData; + struct openvz_vm *vm = driver->vms; + + + while(vm) { + openvzFreeVMDef(vm->vmdef); + vm = vm->next; + } + vm = driver->vms; + while (vm) { + struct openvz_vm *prev = vm; + vm = vm->next; + free(prev); + } + + conn->privateData = NULL; + + return 0; +} + +static const char *openvzGetType(virConnectPtr conn ATTRIBUTE_UNUSED) { + return strdup("OpenVZ"); +} + + +static int openvzListDomains(virConnectPtr conn, int *ids, int nids) { + int got = 0; + int veid; + FILE *fp; + + if((fp = popen(VZLIST " -o vpsid -H 2> /dev/null", "r")) == NULL){ + error(conn, VIR_ERR_INTERNAL_ERROR, "Could not popen " VZLIST); + return (int)NULL; + } + + while(!(feof(fp)) && got < nids){ + fscanf(fp, "%d\n", &veid); + ids[got] = veid; + got ++; + } + + return got; +} + +static int openvzNumDomains(virConnectPtr conn) { + return ovz_driver.num_active; +} + +static int openvzListDefinedDomains(virConnectPtr conn, + char **const names, int nnames) { + int got = 0; + FILE *fp; + int veid; + char vpsname[OPENVZ_NAME_MAX]; + + /* the -S options lists only stopped domains */ + if((fp = popen(VZLIST " -S -o vpsid -H 2> /dev/null", "r")) == NULL){ + error(conn, VIR_ERR_INTERNAL_ERROR, "Could not popen " VZLIST); + return (int)NULL; + } + + while(!(feof(fp)) && got < nnames){ + fscanf(fp, "%d\n", &veid); + sprintf(vpsname, "%d", veid); + names[got] = strdup(vpsname); + got ++; + } + + return got; +} + + +static int openvzNumDefinedDomains(virConnectPtr conn) { + return ovz_driver.num_inactive; +} + +static int openvzStartup(void) { + openvzAssignUUIDs(); + + return 0; +} + +static int openvzShutdown(void) { + + return 0; +} + +static int openvzReload(void) { + + return 0; +} + +static int openvzActive(void) { + + return 1; +} + +static int openvzCloseNetwork(virConnectPtr conn) { + return 0; +} + +static virDrvOpenStatus openvzOpenNetwork(virConnectPtr conn, + const char *name ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) { + return VIR_DRV_OPEN_SUCCESS; +} + + +static virDriver openvzDriver = { + VIR_DRV_OPENVZ, + "OPENVZ", + LIBVIR_VERSION_NUMBER, + openvzOpen, /* open */ + openvzClose, /* close */ + openvzGetType, /* type */ + NULL, /* version */ + NULL, /* hostname */ + NULL, /* uri */ + NULL, /* getMaxVcpus */ + NULL, /* nodeGetInfo */ + NULL, /* getCapabilities */ + openvzListDomains, /* listDomains */ + openvzNumDomains, /* numOfDomains */ + NULL, /* domainCreateLinux */ + openvzDomainLookupByID, /* domainLookupByID */ + openvzDomainLookupByUUID, /* domainLookupByUUID */ + openvzDomainLookupByName, /* domainLookupByName */ + NULL, /* domainSuspend */ + NULL, /* domainResume */ + openvzDomainShutdown, /* domainShutdown */ + openvzDomainReboot, /* domainReboot */ + openvzDomainShutdown, /* domainDestroy */ + openvzGetOSType, /* domainGetOSType */ + NULL, /* domainGetMaxMemory */ + NULL, /* domainSetMaxMemory */ + NULL, /* domainSetMemory */ + openvzDomainGetInfo, /* domainGetInfo */ + NULL, /* domainSave */ + NULL, /* domainRestore */ + NULL, /* domainCoreDump */ + NULL, /* domainSetVcpus */ + NULL, /* domainPinVcpu */ + NULL, /* domainGetVcpus */ + NULL, /* domainGetMaxVcpus */ + NULL, /* domainDumpXML */ + openvzListDefinedDomains, /* listDomains */ + openvzNumDefinedDomains, /* numOfDomains */ + openvzDomainCreate, /* domainCreate */ + NULL, /* domainDefineXML */ + NULL, /* domainUndefine */ + NULL, /* domainAttachDevice */ + NULL, /* domainDetachDevice */ + NULL, /* domainGetAutostart */ + NULL, /* domainSetAutostart */ + NULL, /* domainGetSchedulerType */ + NULL, /* domainGetSchedulerParameters */ + NULL, /* domainSetSchedulerParameters */ +}; + +static virNetworkDriver openvzNetworkDriver = { + openvzOpenNetwork, /* open */ + openvzCloseNetwork, /* close */ + NULL, /* numOfNetworks */ + NULL, /* listNetworks */ + NULL, /* numOfDefinedNetworks */ + NULL, /* listDefinedNetworks */ + NULL, /* networkLookupByUUID */ + NULL, /* networkLookupByName */ + NULL, /* networkCreateXML */ + NULL, /* networkDefineXML */ + NULL, /* networkUndefine */ + NULL, /* networkCreate */ + NULL, /* networkDestroy */ + NULL, /* networkDumpXML */ + NULL, /* networkGetBridgeName */ + NULL, /* networkGetAutostart */ + NULL, /* networkSetAutostart */ +}; + +static virStateDriver openvzStateDriver = { + openvzStartup, + openvzShutdown, + openvzReload, + openvzActive, +}; + +int openvzRegister(void) { + virRegisterDriver(&openvzDriver); + virRegisterNetworkDriver(&openvzNetworkDriver); + virRegisterStateDriver(&openvzStateDriver); + return 0; +} + +#endif /* WITH_OPENVZ */ + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */ diff --git a/src/openvz_driver.h b/src/openvz_driver.h new file mode 100644 index 0000000000..84735e986b --- /dev/null +++ b/src/openvz_driver.h @@ -0,0 +1,52 @@ +/* + * openvz_driver.h: core driver methods for managing OpenVZ VPSs + * + * Copyright (C) 2006, 2007 Binary Karma. + * Copyright (C) 2006 Shuveb Hussain + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Shuveb Hussain + */ + + +#ifndef OPENVZ_DRIVER_H +#define OPENVZ_DRIVER_H + +#include "internal.h" + +/* OpenVZ commands - Replace with wrapper scripts later? */ +#define VZLIST "vzlist" +#define VZCTL "vzctl" + +struct openvz_driver { + struct openvz_vm *vms; + int num_active; + int num_inactive; +}; + +int openvzRegister(void); + +#endif + + +/* + * Local variables: + * indent-tabs-mode: nil + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * End: + */