]> xenbits.xensource.com Git - libvirt.git/commitdiff
* configure.in src/Makefile.am src/driver.h src/libvirt.c:
authorDaniel Veillard <veillard@redhat.com>
Tue, 17 Jul 2007 13:27:26 +0000 (13:27 +0000)
committerDaniel Veillard <veillard@redhat.com>
Tue, 17 Jul 2007 13:27:26 +0000 (13:27 +0000)
  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
configure.in
src/Makefile.am
src/driver.h
src/libvirt.c
src/openvz_conf.c [new file with mode: 0644]
src/openvz_conf.h [new file with mode: 0644]
src/openvz_driver.c [new file with mode: 0644]
src/openvz_driver.h [new file with mode: 0644]

index 13c42ea0ef451e6d3dada38f275410b7b66ab882..fa164717b17ed7699a3dbcfff2f2ea87894b9d7a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Tue Jul 17 15:24:27 CEST 2007 Daniel Veillard <veillard@redhat.com>
+
+       * 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 <berrange@redhat.com>
 
        * docs/libvir.html, docs/remote.html: Re-write notes on IPV6
index dc5e38052c6759927852820ae2c5fe80773e6c51..7ceebe1fe438e17cafea40eef699bd51aba835e9 100644 (file)
@@ -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
index 8bb87ce900137d7061761f84f333696508fbae51..c4bf4a2ac8dabe2bd31ed8d220a303791d6ee5f9 100644 (file)
@@ -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         \
index fe4f9e2439e70a18cb15878f2a71c269ce3a1aec..9b2b196403c7bc870a1773f0dd46f90d58b78424 100644 (file)
@@ -21,6 +21,7 @@ typedef enum {
     VIR_DRV_TEST = 2,
     VIR_DRV_QEMU = 3,
     VIR_DRV_REMOTE = 4,
+    VIR_DRV_OPENVZ = 5,
 } virDrvNo;
 
 
index 1ef11dc809eecab7a1751a8643de5e98d2c7e41e..cc750e0643f22026bdb58339e336be076ef8182b 100644 (file)
@@ -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 (file)
index 0000000..ad4bb73
--- /dev/null
@@ -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 <shuveb@binarykarma.com>
+ */
+
+#ifdef WITH_OPENVZ
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <strings.h>
+#include <time.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/uri.h>
+
+#include <libvirt/virterror.h>
+
+#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 (file)
index 0000000..ffc7738
--- /dev/null
@@ -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 <shuveb@binarykarma.com>
+ */
+
+#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 (file)
index 0000000..18afd86
--- /dev/null
@@ -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 <shuveb@binarykarma.com>
+ */
+
+#ifdef WITH_OPENVZ
+
+#include <config.h>
+
+#define _GNU_SOURCE /* for asprintf */
+
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <dirent.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <strings.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <paths.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <sys/wait.h>
+
+#include <libvirt/virterror.h>
+
+#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 (file)
index 0000000..84735e9
--- /dev/null
@@ -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 <shuveb@binarykarma.com>
+ */
+
+
+#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:
+ */