From b36902c37af5d902adf5483eff2f79503db1ef09 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Mon, 3 Sep 2007 15:37:07 +0000 Subject: [PATCH] * src/openvz_conf.c src/openvz_conf.h src/openvz_driver.c src/openvz_driver.h: Applied patch from Shuveb Hussain and Anoop Cyriac to extent OpenVZ driver capabilities, especially Create(). Daniel --- ChangeLog | 6 + src/openvz_conf.c | 392 ++++++++++++++++++++++++++++++++++++-------- src/openvz_conf.h | 38 ++++- src/openvz_driver.c | 343 ++++++++++++++++++++++++++++++++++---- src/openvz_driver.h | 16 +- 5 files changed, 680 insertions(+), 115 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6a72989b8b..1eca5e683f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Mon Sep 3 17:35:15 CEST 2007 Daniel Veillard + + * src/openvz_conf.c src/openvz_conf.h src/openvz_driver.c + src/openvz_driver.h: Applied patch from Shuveb Hussain and Anoop + Cyriac to extent OpenVZ driver capabilities, especially Create(). + Thu Aug 30 15:11:44 CEST 2007 Daniel Veillard * src/buf.c: applied patch from Masayuki Sunou fixing a loop diff --git a/src/openvz_conf.c b/src/openvz_conf.c index 964221aacf..141139a0e6 100644 --- a/src/openvz_conf.c +++ b/src/openvz_conf.c @@ -3,6 +3,7 @@ * * 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 @@ -18,7 +19,10 @@ * 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 + * Authors: + * Shuveb Hussain + * Anoop Joe Cyriac + * */ #ifdef WITH_OPENVZ @@ -31,6 +35,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -39,11 +47,21 @@ #include -#include "openvz_conf.h" #include "openvz_driver.h" +#include "openvz_conf.h" #include "uuid.h" #include "buf.h" +#include + +static char *openvzLocateConfDir(void); +static void error (virConnectPtr conn, virErrorNumber code, const char *info); +static struct openvz_vm_def *openvzParseXML(virConnectPtr conn, xmlDocPtr xml); +static int openvzGetVPSUUID(int vpsid, char *uuidstr); +static int openvzSetUUID(int vpsid); +static struct openvz_vm *openvzLoadConfig(struct openvz_driver *driver, + const char *path, + const char *xmlStr); /* For errors internal to this library. */ static void @@ -98,30 +116,172 @@ struct openvz_vm 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; +int +strtoI(char *str) +{ + int base = 10; + char *endptr; + int val; - while (quota) { - struct ovz_quota *prev = quota; - quota = quota->next; - free(prev); + val = (int) strtol(str, &endptr, base); + + /* Check for various possible errors */ + if ((endptr == str) /* "No digits were found" */ + ||((*endptr != '\0') + && (*endptr != ' ')) /*"Name contain characters other than integers" */ ) + return 0; + return val; +} + +void +openvzRemoveInactiveVM(struct openvz_driver *driver, struct openvz_vm *vm) +{ + driver->num_inactive--; + openvzFreeVM(driver, vm, 1); +} + +/* Free all memory associated with a openvz_vm_def structure */ +void +openvzFreeVMDef(struct openvz_vm_def *def) +{ + if (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); + def = NULL; } - while (ip) { - struct ovz_ip *prev = ip; - ip = ip->next; - free(prev); +} + +/* Free all memory associated with a openvz_vm structure + * @checkCallee == 0 then openvzFreeDriver() is callee else some other function + */ +void +openvzFreeVM(struct openvz_driver *driver, struct openvz_vm *vm, + int checkCallee) +{ + struct openvz_vm *vms; + + if (!vm && !driver) + return; + vms = driver->vms; + if (checkCallee) { + if (vms == vm) + driver->vms = vm->next; + else { + while (vms) { + struct openvz_vm *prev = vms; + + vms = vms->next; + if (vms == vm) { + prev->next = vms->next; + break; + } + } + } } - while (ns) { - struct ovz_ns *prev = ns; - ns = ns->next; - free(prev); + if (vms) { + openvzFreeVMDef(vm->vmdef); + free(vm); + vm = NULL; + } +} + +/* Free all memory associated with a openvz_driver structure */ +void +openvzFreeDriver(struct openvz_driver *driver) +{ + struct openvz_vm *next; + + if (!driver) + return; + if (driver->vms) + for(next = driver->vms->next; driver->vms; driver->vms = next) + openvzFreeVM(driver, driver->vms, 0); + free(driver); + driver = NULL; +} + +struct openvz_vm * +openvzAssignVMDef(virConnectPtr conn, + struct openvz_driver *driver, struct openvz_vm_def *def) +{ + struct openvz_vm *vm = NULL; + + if (!driver || !def) + return NULL; + + if ((vm = openvzFindVMByName(driver, def->name))) { + if (!openvzIsActiveVM(vm)) { + openvzFreeVMDef(vm->vmdef); + vm->vmdef = def; + } + else + { + openvzLog(OPENVZ_ERR, "Error already an active OPENVZ VM having id '%s'", + def->name); + openvzFreeVMDef(def); + return NULL; /* can't redefine an active domain */ + } + + return vm; } - free(def); + if (!(vm = calloc(1, sizeof(struct openvz_vm)))) { + openvzFreeVMDef(def); + error(conn, VIR_ERR_NO_MEMORY, "vm"); + return NULL; + } + + vm->vpsid = -1; /* -1 needed for to represent inactiveness of domain before 'start' */ + vm->status = VIR_DOMAIN_SHUTOFF; + vm->vmdef = def; + vm->next = driver->vms; + + driver->vms = vm; + driver->num_inactive++; + + return vm; +} + +struct openvz_vm_def +*openvzParseVMDef(virConnectPtr conn, + const char *xmlStr, const char *displayName) +{ + xmlDocPtr xml; + struct openvz_vm_def *def = NULL; + + xml = xmlReadDoc(BAD_CAST xmlStr, displayName ? displayName : "domain.xml", NULL, + XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (!xml) { + error(conn, VIR_ERR_XML_ERROR, NULL); + return NULL; + } + + def = openvzParseXML(conn, xml); + xmlFreeDoc(xml); + + return def; } /* @@ -136,6 +296,8 @@ static struct openvz_vm_def xmlXPathContextPtr ctxt = NULL; xmlXPathObjectPtr obj = NULL; struct openvz_vm_def *def; + struct ovz_ip *ovzIp; + struct ovz_ns *ovzNs; if (!(def = calloc(1, sizeof(struct openvz_vm_def)))) { error(conn, VIR_ERR_NO_MEMORY, "xmlXPathContext"); @@ -143,6 +305,7 @@ static struct openvz_vm_def } /* 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"); @@ -155,8 +318,7 @@ static struct openvz_vm_def goto bail_out; } - - /* Find out what type of QEMU virtualization to use */ + /* Find out what type of OPENVZ virtualization to use */ if (!(prop = xmlGetProp(root, BAD_CAST "type"))) { error(conn, VIR_ERR_INTERNAL_ERROR, "missing domain type attribute"); goto bail_out; @@ -171,16 +333,19 @@ static struct openvz_vm_def /* Extract domain name */ obj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", ctxt); - if ((obj == NULL) || (obj->type != XPATH_NUMBER) || + if ((obj == NULL) || (obj->type != XPATH_STRING) || (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"); + + /* rejecting VPS ID <= OPENVZ_RSRV_VM_LIMIT for they are reserved */ + if (strtoI(BAD_CAST obj->stringval) <= OPENVZ_RSRV_VM_LIMIT) { + error(conn, VIR_ERR_INTERNAL_ERROR, + "VPS ID Error (must be an integer greater than 100"); goto bail_out; } - strcpy(def->name, (const char *)obj->stringval); + strncpy(def->name, (const char *) obj->stringval, OPENVZ_NAME_MAX); xmlXPathFreeObject(obj); /* Extract domain uuid */ @@ -188,9 +353,9 @@ static struct openvz_vm_def 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"); + error(conn, VIR_ERR_INTERNAL_ERROR, "Failed to generate UUID"); goto bail_out; } } else if (virUUIDParse((const char *)obj->stringval, def->uuid) < 0) { @@ -200,21 +365,133 @@ static struct openvz_vm_def 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)) { + obj = xmlXPathEval(BAD_CAST "string(/domain/container/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); + strncpy(def->fs.tmpl, (const char *) obj->stringval, OPENVZ_TMPL_MAX); xmlXPathFreeObject(obj); /* TODO Add quota processing here */ /* TODO analysis of the network devices */ - xmlXPathFreeContext(ctxt); + /* Extract network */ + /* Extract ipaddress */ + obj = xmlXPathEval(BAD_CAST"string(/domain/container/network/ipaddress[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) + || (obj->stringval[0] == 0)) { + openvzLog(OPENVZ_WARN, "No IP address in the given xml config file '%s'", + xml->name); + } + if (xmlStrlen(obj->stringval) >= (OPENVZ_IP_MAX)) { + char errorMessage[OPENVZ_MAX_ERROR_LEN]; + + snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s", "ipaddress length too long"); + error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage); + goto bail_out; + } + if (!(ovzIp = calloc(1, sizeof(struct ovz_ip)))) { + openvzLog(OPENVZ_ERR, "Failed to Create Memory for 'ovz_ip' structure"); + goto bail_out; + } + strncpy(ovzIp->ip, (const char *) obj->stringval, OPENVZ_IP_MAX); + def->net.ips = ovzIp; + xmlXPathFreeObject(obj); + + /* Extract netmask */ + obj = xmlXPathEval(BAD_CAST "string(/domain/container/network/netmask[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) + || (obj->stringval == NULL) || (obj->stringval[0] == 0)) + openvzLog(OPENVZ_WARN, "No Netmask address in the given xml config file '%s'", + xml->name); + + if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) { + char errorMessage[OPENVZ_MAX_ERROR_LEN]; + + snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s", "netmask length too long"); + error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage); + goto bail_out; + } + strncpy(def->net.ips->netmask, (const char *) obj->stringval, OPENVZ_IP_MAX); + xmlXPathFreeObject(obj); + + /* Extract hostname */ + obj = xmlXPathEval(BAD_CAST "string(/domain/container/network/hostname[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) + || (obj->stringval[0] == 0)) + openvzLog(OPENVZ_WARN, "No hostname in the given xml config file '%s'", xml->name); + + if (strlen((const char *) obj->stringval) >= (OPENVZ_HOSTNAME_MAX - 1)) { + char errorMessage[OPENVZ_MAX_ERROR_LEN]; + + snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s", "hostname length too long"); + error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage); + goto bail_out; + } + strncpy(def->net.hostname, (const char *) obj->stringval, OPENVZ_HOSTNAME_MAX - 1); + xmlXPathFreeObject(obj); + + /* Extract gateway */ + obj = xmlXPathEval(BAD_CAST"string(/domain/container/network/gateway[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) + || (obj->stringval[0] == 0)) + openvzLog(OPENVZ_WARN, "No Gateway address in the given xml config file '%s'", + xml->name); + + if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) { + char errorMessage[OPENVZ_MAX_ERROR_LEN]; + + snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s", "gateway length too long"); + error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage); + goto bail_out; + } + strncpy(def->net.def_gw, (const char *) obj->stringval, OPENVZ_IP_MAX); + xmlXPathFreeObject(obj); + + /* Extract nameserver */ + obj = xmlXPathEval(BAD_CAST "string(/domain/container/network/nameserver[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) + || (obj->stringval[0] == 0)) + openvzLog(OPENVZ_WARN, "No Nameserver address inthe given xml config file '%s'", + xml->name); + + if (strlen((const char *) obj->stringval) >= (OPENVZ_IP_MAX)) { + char errorMessage[OPENVZ_MAX_ERROR_LEN]; + + snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s", "nameserver length too long"); + error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage); + goto bail_out; + } + if (!(ovzNs = calloc(1, sizeof(struct ovz_ns)))) { + openvzLog(OPENVZ_ERR, "Failed to Create Memory for 'ovz_ns' structure"); + goto bail_out; + } + strncpy(ovzNs->ip, (const char *) obj->stringval, OPENVZ_IP_MAX); + def->net.ns = ovzNs; + xmlXPathFreeObject(obj); + + /* Extract profile */ + obj = xmlXPathEval(BAD_CAST "string(/domain/container/profile[1])", ctxt); + if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) + || (obj->stringval[0] == 0)) { + error(conn, VIR_ERR_INTERNAL_ERROR, NULL); + goto bail_out; + } + if (strlen((const char *) obj->stringval) >= (OPENVZ_PROFILE_MAX - 1)) { + char errorMessage[OPENVZ_MAX_ERROR_LEN]; + + snprintf(errorMessage, OPENVZ_MAX_ERROR_LEN - 1, "%s", "profile length too long"); + error(conn, VIR_ERR_INTERNAL_ERROR, errorMessage); + goto bail_out; + } + strncpy(def->profile, (const char *) obj->stringval, OPENVZ_PROFILE_MAX - 1); + xmlXPathFreeObject(obj); + + xmlXPathFreeContext(ctxt); return def; bail_out: @@ -225,30 +502,10 @@ static struct openvz_vm_def 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; @@ -271,9 +528,9 @@ openvzGetVPSInfo(virConnectPtr conn) { } pnext = &vm; while(!feof(fp)) { - *pnext = malloc(sizeof(struct openvz_vm)); + *pnext = calloc(1, sizeof(struct openvz_vm)); if(!*pnext) { - error(conn, VIR_ERR_INTERNAL_ERROR, "malloc failed"); + error(conn, VIR_ERR_INTERNAL_ERROR, "calloc failed"); return NULL; } @@ -293,9 +550,9 @@ openvzGetVPSInfo(virConnectPtr conn) { thought this doesn't make sense for OpenVZ */ } - vmdef = malloc(sizeof(struct openvz_vm_def)); + vmdef = calloc(1, sizeof(struct openvz_vm_def)); if(!vmdef) { - error(conn, VIR_ERR_INTERNAL_ERROR, "malloc failed"); + error(conn, VIR_ERR_INTERNAL_ERROR, "calloc failed"); return NULL; } @@ -356,11 +613,11 @@ openvz_readline(int fd, char *ptr, int maxlen) } static int -openvzGetVPSUUID(int vpsid, char *uuidbuf) +openvzGetVPSUUID(int vpsid, char *uuidstr) { char conf_file[PATH_MAX]; char line[1024]; - char uuid[1024]; + char uuidbuf[1024]; char iden[1024]; char *conf_dir; int fd, ret; @@ -379,13 +636,13 @@ openvzGetVPSUUID(int vpsid, char *uuidbuf) return -1; if(ret == 0) { /* EoF, UUID was not found */ - uuidbuf[0] = (char)NULL; + uuidstr[0] = 0; break; } - sscanf(line, "%s %s\n", iden, uuid); + sscanf(line, "%s %s\n", iden, uuidbuf); if(!strcmp(iden, "#UUID:")) { - strncpy(uuidbuf, uuid, VIR_UUID_STRING_BUFLEN); + strncpy(uuidstr, uuidbuf, VIR_UUID_STRING_BUFLEN); break; } } @@ -413,17 +670,17 @@ openvzSetUUID(int vpsid) if(fd == -1) return -1; - ret = openvzGetVPSUUID(vpsid, uuid); + ret = openvzGetVPSUUID(vpsid, uuidstr); if(ret == -1) return -1; - if(uuid[0] == (int)NULL) { + if(uuidstr[0] == 0) { virUUIDGenerate(uuid); virUUIDFormat(uuid, uuidstr); lseek(fd, 0, SEEK_END); write(fd, "\n#UUID: ", 8); - write(fd, uuid, strlen(uuid)); + write(fd, uuidstr, strlen(uuidstr)); write(fd, "\n", 1); close(fd); } @@ -467,4 +724,3 @@ int openvzAssignUUIDs(void) } #endif - diff --git a/src/openvz_conf.h b/src/openvz_conf.h index e869ddab74..e1ccc72451 100644 --- a/src/openvz_conf.h +++ b/src/openvz_conf.h @@ -3,6 +3,7 @@ * * 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 @@ -18,7 +19,10 @@ * 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 + * Authors: + * Shuveb Hussain + * Anoop Joe Cyriac + * */ #ifndef OPENVZ_CONF_H @@ -26,12 +30,19 @@ #include "openvz_driver.h" +enum { OPENVZ_WARN, OPENVZ_ERR }; + #define OPENVZ_NAME_MAX 8 #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 +#define OPENVZ_MAX_ERROR_LEN 1024 +#define OPENVZ_MAX_XML_LEN 4096 +#define OPENVZ_MAX_QUOTA 8 +#define OPENVZ_MAX_XPathEval_LEN 256 +#define OPENVZ_RSRV_VM_LIMIT 100 enum openvz_quota{ VM_LEVEL = 0, @@ -93,21 +104,30 @@ struct openvz_vm { struct openvz_vm *next; }; -static char *openvzLocateConfDir(void); +static inline int +openvzIsActiveVM(struct openvz_vm *vm) +{ + return vm->vpsid != -1; +} + int openvz_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 *openvzFindVMByName(const struct openvz_driver *driver, const char *name); struct openvz_vm_def *openvzParseVMDef(virConnectPtr conn, const char *xmlStr, const char *displayName); + +struct openvz_vm *openvzAssignVMDef(virConnectPtr conn, struct openvz_driver *driver, + struct openvz_vm_def *def); + struct openvz_vm *openvzGetVPSInfo(virConnectPtr conn); void openvzGenerateUUID(unsigned char *uuid); -static int openvzGetVPSUUID(int vpsid, char *uuidbuf); -static int openvzSetUUID(int vpsid); int openvzAssignUUIDs(void); +void openvzRemoveInactiveVM(struct openvz_driver *driver, struct openvz_vm *vm); +void openvzFreeDriver(struct openvz_driver *driver); +void openvzFreeVM(struct openvz_driver *driver, struct openvz_vm *vm, int checkCallee); +void openvzFreeVMDef(struct openvz_vm_def *def); +int strtoI(char *str); #endif /* OPENVZ_CONF_H */ diff --git a/src/openvz_driver.c b/src/openvz_driver.c index b994fabc87..aad775c12d 100644 --- a/src/openvz_driver.c +++ b/src/openvz_driver.c @@ -3,6 +3,7 @@ * * 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 @@ -18,7 +19,10 @@ * 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 + * Authors: + * Shuveb Hussain + * Anoop Joe Cyriac + * */ #ifdef WITH_OPENVZ @@ -50,15 +54,16 @@ #include +#include "openvz_driver.h" #include "event.h" #include "buf.h" #include "util.h" -#include "openvz_driver.h" #include "openvz_conf.h" #include "nodeinfo.h" - -#define openvzLog(level, msg...) fprintf(stderr, msg) +#define OPENVZ_MAX_ARG 28 +#define CMDBUF_LEN 1488 +#define CMDOP_LEN 288 static virDomainPtr openvzDomainLookupByID(virConnectPtr conn, int id); static char *openvzGetOSType(virDomainPtr dom); @@ -71,6 +76,7 @@ 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); @@ -82,10 +88,49 @@ 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); +static virDrvOpenStatus openvzOpenNetwork(virConnectPtr conn, + const char *name ATTRIBUTE_UNUSED, int flags ATTRIBUTE_UNUSED); + +static virDomainPtr openvzDomainDefineXML(virConnectPtr conn, const char *xml); +static virDomainPtr openvzDomainCreateLinux(virConnectPtr conn, const char *xml, + unsigned int flags ATTRIBUTE_UNUSED); + +static int openvzDomainUndefine(virDomainPtr dom); +static int convCmdbufExec(char cmdbuf[], char *cmdExec[]); +static void cmdExecFree(char *cmdExec[]); + struct openvz_driver ovz_driver; +static int convCmdbufExec(char cmdbuf[], char *cmdExec[]) +{ + int i=0, limit = OPENVZ_MAX_ARG - 1; + char cmdWord[CMDOP_LEN]; + while(*cmdbuf) + { + if(i >= limit) + { + cmdExec[i] = NULL; + return -1; + } + sscanf(cmdbuf, "%s", cmdWord); + cmdbuf += strlen(cmdWord); + while(*cmdbuf == ' ') cmdbuf++; + cmdExec[i++] = strdup(cmdWord); + } + cmdExec[i] = NULL; + return i; +} + +static void cmdExecFree(char *cmdExec[]) +{ + int i=-1; + while(cmdExec[++i]) + { + free(cmdExec[i]); + cmdExec[i] = NULL; + } +} + /* For errors internal to this library. */ static void error (virConnectPtr conn, virErrorNumber code, const char *info) @@ -122,7 +167,7 @@ static virDomainPtr openvzDomainLookupByID(virConnectPtr conn, static char *openvzGetOSType(virDomainPtr dom) { /* OpenVZ runs on Linux and runs only Linux */ - return strdup("Linux"); + return strdup("linux"); } @@ -133,7 +178,7 @@ static virDomainPtr openvzDomainLookupByUUID(virConnectPtr conn, virDomainPtr dom; if (!vm) { - error(conn, VIR_ERR_INTERNAL_ERROR, "no domain with matching uuid"); + error(conn, VIR_ERR_INVALID_DOMAIN, "no domain with matching uuid"); return NULL; } @@ -172,6 +217,7 @@ 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; @@ -188,8 +234,10 @@ static int openvzDomainGetInfo(virDomainPtr dom, } static int openvzDomainShutdown(virDomainPtr dom) { - char cmdbuf[1024]; + char cmdbuf[CMDBUF_LEN]; int ret; + char *cmdExec[OPENVZ_MAX_ARG]; + int pid, outfd, errfd; struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData; struct openvz_vm *vm = openvzFindVMByID(driver, dom->id); @@ -202,24 +250,36 @@ static int openvzDomainShutdown(virDomainPtr dom) { 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"); + snprintf(cmdbuf, CMDBUF_LEN - 1, VZCTL " stop %d ", dom->id); + + if((ret = convCmdbufExec(cmdbuf, cmdExec)) == -1) + { + openvzLog(OPENVZ_ERR, "Error in parsing Options to OPENVZ"); + goto bail_out; + } + + ret = virExec(dom->conn, (char **)cmdExec, &pid, -1, &outfd, &errfd); + if(ret == -1) { + error(dom->conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); return -1; } + vm->vpsid = -1; vm->status = VIR_DOMAIN_SHUTOFF; ovz_driver.num_inactive ++; ovz_driver.num_active --; +bail_out: + cmdExecFree(cmdExec); + return ret; } static int openvzDomainReboot(virDomainPtr dom, unsigned int flags) { - char cmdbuf[1024]; + char cmdbuf[CMDBUF_LEN]; int ret; + char *cmdExec[OPENVZ_MAX_ARG]; + int pid, outfd, errfd; struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData; struct openvz_vm *vm = openvzFindVMByID(driver, dom->id); @@ -232,22 +292,187 @@ static int openvzDomainReboot(virDomainPtr dom, unsigned int flags) { 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"); + snprintf(cmdbuf, CMDBUF_LEN - 1, VZCTL " restart %d ", dom->id); + + if((ret = convCmdbufExec(cmdbuf, cmdExec)) == -1) + { + openvzLog(OPENVZ_ERR, "Error in parsing Options to OPENVZ"); + goto bail_out1; + } + ret = virExec(dom->conn, (char **)cmdExec, &pid, -1, &outfd, &errfd); + if(ret == -1) { + error(dom->conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); return -1; } + +bail_out1: + cmdExecFree(cmdExec); return ret; } -static int openvzDomainCreate(virDomainPtr dom) { - char cmdbuf[1024]; +static virDomainPtr +openvzDomainDefineXML(virConnectPtr conn, const char *xml) +{ + struct openvz_driver *driver = (struct openvz_driver *) conn->privateData; + struct openvz_vm_def *vmdef = NULL; + struct openvz_vm *vm = NULL; + virDomainPtr dom; + char cmdbuf[CMDBUF_LEN], cmdOption[CMDOP_LEN], *cmdExec[OPENVZ_MAX_ARG]; + int ret, pid, outfd, errfd; + + if (!(vmdef = openvzParseVMDef(conn, xml, NULL))) + goto bail_out2; + + vm = openvzFindVMByID(driver, strtoI(vmdef->name)); + if (vm) { + openvzLog(OPENVZ_ERR, "Already an OPENVZ VM active with the id '%s'", + vmdef->name); + goto bail_out2; + } + if (!(vm = openvzAssignVMDef(conn, driver, vmdef))) { + openvzFreeVMDef(vmdef); + openvzLog(OPENVZ_ERR, "Error creating OPENVZ VM"); + } + + snprintf(cmdbuf, CMDBUF_LEN - 1, VZCTL " create %s", vmdef->name); + if ((vmdef->fs.tmpl && *(vmdef->fs.tmpl))) { + snprintf(cmdOption, CMDOP_LEN - 1, " --ostemplate %s", vmdef->fs.tmpl); + strcat(cmdbuf, cmdOption); + } + if ((vmdef->profile && *(vmdef->profile))) { + snprintf(cmdOption, CMDOP_LEN - 1, " --config %s", vmdef->profile); + strcat(cmdbuf, cmdOption); + } + if ((vmdef->net.ips->ip && *(vmdef->net.ips->ip))) { + snprintf(cmdOption, CMDOP_LEN - 1, " --ipadd %s", vmdef->net.ips->ip); + strcat(cmdbuf, cmdOption); + } + if ((vmdef->net.hostname && *(vmdef->net.hostname))) { + snprintf(cmdOption, CMDOP_LEN - 1, " --hostname %s", vmdef->net.hostname); + strcat(cmdbuf, cmdOption); + } + + if((ret = convCmdbufExec(cmdbuf, cmdExec)) == -1) + { + openvzLog(OPENVZ_ERR, "Error in parsing Options to OPENVZ"); + goto bail_out2; + } + ret = virExec(conn, (char **)cmdExec, &pid, -1, &outfd, &errfd); + if(ret == -1) { + error(conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); + goto bail_out2; + } + + waitpid(pid, NULL, 0); + cmdExecFree(cmdExec); + + dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid); + if (dom) + dom->id = vm->vpsid; + return dom; +bail_out2: + cmdExecFree(cmdExec); + return NULL; +} + +static virDomainPtr +openvzDomainCreateLinux(virConnectPtr conn, const char *xml, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct openvz_vm_def *vmdef = NULL; + struct openvz_vm *vm = NULL; + virDomainPtr dom; + struct openvz_driver *driver = (struct openvz_driver *) conn->privateData; + char cmdbuf[CMDBUF_LEN], cmdOption[CMDOP_LEN], *cmdExec[OPENVZ_MAX_ARG]; + int ret, pid, outfd, errfd; + + if (!(vmdef = openvzParseVMDef(conn, xml, NULL))) + return NULL; + + vm = openvzFindVMByID(driver, strtoI(vmdef->name)); + if (vm) { + openvzFreeVMDef(vmdef); + openvzLog(OPENVZ_ERR, "Already an OPENVZ VM defined with the id '%d'", + strtoI(vmdef->name)); + return NULL; + } + if (!(vm = openvzAssignVMDef(conn, driver, vmdef))) { + openvzLog(OPENVZ_ERR, "Error creating OPENVZ VM"); + return NULL; + } + + snprintf(cmdbuf, CMDBUF_LEN - 1, VZCTL " create %s", vmdef->name); + if ((vmdef->fs.tmpl && *(vmdef->fs.tmpl))) { + snprintf(cmdOption, CMDOP_LEN - 1, " --ostemplate %s", vmdef->fs.tmpl); + strcat(cmdbuf, cmdOption); + } + if ((vmdef->profile && *(vmdef->profile))) { + snprintf(cmdOption, CMDOP_LEN - 1, " --config %s", vmdef->profile); + strcat(cmdbuf, cmdOption); + } + if ((vmdef->net.ips->ip && *(vmdef->net.ips->ip))) { + snprintf(cmdOption, CMDOP_LEN - 1, " --ipadd %s", vmdef->net.ips->ip); + strcat(cmdbuf, cmdOption); + } + if ((vmdef->net.hostname && *(vmdef->net.hostname))) { + snprintf(cmdOption, CMDOP_LEN - 1, " --hostname %s", vmdef->net.hostname); + strcat(cmdbuf, cmdOption); + } + + if((ret = convCmdbufExec(cmdbuf, cmdExec)) == -1) + { + openvzLog(OPENVZ_ERR, "Error in parsing Options to OPENVZ"); + goto bail_out3; + } + ret = virExec(conn, (char **)cmdExec, &pid, -1, &outfd, &errfd); + if(ret == -1) { + error(conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); + return NULL; + } + + waitpid(pid, NULL, 0); + cmdExecFree(cmdExec); + + snprintf(cmdbuf, CMDBUF_LEN - 1, VZCTL " start %s ", vmdef->name); + + if((ret = convCmdbufExec(cmdbuf, cmdExec)) == -1) + { + openvzLog(OPENVZ_ERR, "Error in parsing Options to OPENVZ"); + goto bail_out3; + } + ret = virExec(conn, (char **)cmdExec, &pid, -1, &outfd, &errfd); + if(ret == -1) { + error(conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); + return NULL; + } + + sscanf(vmdef->name, "%d", &vm->vpsid); + vm->status = VIR_DOMAIN_RUNNING; + ovz_driver.num_inactive--; + ovz_driver.num_active++; + + waitpid(pid, NULL, 0); + cmdExecFree(cmdExec); + + dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid); + if (dom) + dom->id = vm->vpsid; + return dom; +bail_out3: + cmdExecFree(cmdExec); + return NULL; +} + +static int +openvzDomainCreate(virDomainPtr dom) +{ + char cmdbuf[CMDBUF_LEN]; int ret; + char *cmdExec[OPENVZ_MAX_ARG] ; + int pid, outfd, errfd; struct openvz_driver *driver = (struct openvz_driver *)dom->conn->privateData; - struct openvz_vm *vm = openvzFindVMByID(driver, dom->id); + struct openvz_vm *vm = openvzFindVMByName(driver, dom->name); struct openvz_vm_def *vmdef; if (!vm) { @@ -261,20 +486,69 @@ static int openvzDomainCreate(virDomainPtr dom) { } 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"); + snprintf(cmdbuf, CMDBUF_LEN - 1, VZCTL " start %s ", vmdef->name); + + if((ret = convCmdbufExec(cmdbuf, cmdExec)) == -1) + { + openvzLog(OPENVZ_ERR, "Error in parsing Options to OPENVZ"); + goto bail_out4; + } + ret = virExec(dom->conn, (char **)cmdExec, &pid, -1, &outfd, &errfd); + if(ret == -1) { + error(dom->conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); return -1; } + sscanf(vmdef->name, "%d", &vm->vpsid); vm->status = VIR_DOMAIN_RUNNING; ovz_driver.num_inactive --; ovz_driver.num_active ++; + + waitpid(pid, NULL, 0); +bail_out4: + cmdExecFree(cmdExec); return ret; } +static int +openvzDomainUndefine(virDomainPtr dom) +{ + char cmdbuf[CMDBUF_LEN], *cmdExec[OPENVZ_MAX_ARG]; + int ret, pid, outfd, errfd; + virConnectPtr conn= dom->conn; + struct openvz_driver *driver = (struct openvz_driver *) conn->privateData; + struct openvz_vm *vm = openvzFindVMByUUID(driver, dom->uuid); + + if (!vm) { + error(conn, VIR_ERR_INVALID_DOMAIN, "no domain with matching uuid"); + return -1; + } + + if (openvzIsActiveVM(vm)) { + error(conn, VIR_ERR_INTERNAL_ERROR, "cannot delete active domain"); + return -1; + } + snprintf(cmdbuf, CMDBUF_LEN - 1, VZCTL " destroy %s ", vm->vmdef->name); + + if((ret = convCmdbufExec(cmdbuf, cmdExec)) == -1) + { + openvzLog(OPENVZ_ERR, "Error in parsing Options to OPENVZ"); + goto bail_out5; + } + ret = virExec(conn, (char **)cmdExec, &pid, -1, &outfd, &errfd); + if(ret == -1) { + error(conn, VIR_ERR_INTERNAL_ERROR, "Could not exec " VZLIST); + return -1; + } + + waitpid(pid, NULL, 0); + openvzRemoveInactiveVM(driver, vm); +bail_out5: + cmdExecFree(cmdExec); + return ret; +} + static virDrvOpenStatus openvzOpen(virConnectPtr conn, const char *name, int flags ATTRIBUTE_UNUSED) { @@ -306,7 +580,6 @@ 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); @@ -328,13 +601,11 @@ static const char *openvzGetType(virConnectPtr conn ATTRIBUTE_UNUSED) { return strdup("OpenVZ"); } - static int openvzGetNodeInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo) { return virNodeInfoPopulate(conn, nodeinfo); } - static int openvzListDomains(virConnectPtr conn, int *ids, int nids) { int got = 0; int veid, pid, outfd, errfd; @@ -370,7 +641,7 @@ static int openvzListDefinedDomains(virConnectPtr conn, int veid, pid, outfd, errfd, ret; char vpsname[OPENVZ_NAME_MAX]; char buf[32]; - const char *cmd[] = {VZLIST, "-ovpsid", "-H", NULL}; + const char *cmd[] = {VZLIST, "-ovpsid", "-H", "-S", NULL}; /* the -S options lists only stopped domains */ ret = virExec(conn, (char **)cmd, &pid, -1, &outfd, &errfd); @@ -391,7 +662,6 @@ static int openvzListDefinedDomains(virConnectPtr conn, return got; } - static int openvzNumDefinedDomains(virConnectPtr conn) { return ovz_driver.num_inactive; } @@ -427,13 +697,13 @@ static virDrvOpenStatus openvzOpenNetwork(virConnectPtr conn, return VIR_DRV_OPEN_SUCCESS; } - static virDriver openvzDriver = { VIR_DRV_OPENVZ, "OPENVZ", LIBVIR_VERSION_NUMBER, openvzOpen, /* open */ openvzClose, /* close */ + NULL, /* supports_feature */ openvzGetType, /* type */ NULL, /* version */ NULL, /* hostname */ @@ -443,7 +713,7 @@ static virDriver openvzDriver = { NULL, /* getCapabilities */ openvzListDomains, /* listDomains */ openvzNumDomains, /* numOfDomains */ - NULL, /* domainCreateLinux */ + openvzDomainCreateLinux, /* domainCreateLinux */ openvzDomainLookupByID, /* domainLookupByID */ openvzDomainLookupByUUID, /* domainLookupByUUID */ openvzDomainLookupByName, /* domainLookupByName */ @@ -468,8 +738,8 @@ static virDriver openvzDriver = { openvzListDefinedDomains, /* listDomains */ openvzNumDefinedDomains, /* numOfDomains */ openvzDomainCreate, /* domainCreate */ - NULL, /* domainDefineXML */ - NULL, /* domainUndefine */ + openvzDomainDefineXML, /* domainDefineXML */ + openvzDomainUndefine, /* domainUndefine */ NULL, /* domainAttachDevice */ NULL, /* domainDetachDevice */ NULL, /* domainGetAutostart */ @@ -480,6 +750,7 @@ static virDriver openvzDriver = { }; static virNetworkDriver openvzNetworkDriver = { + NULL, /* name */ openvzOpenNetwork, /* open */ openvzCloseNetwork, /* close */ NULL, /* numOfNetworks */ diff --git a/src/openvz_driver.h b/src/openvz_driver.h index 84735e986b..c73a00a965 100644 --- a/src/openvz_driver.h +++ b/src/openvz_driver.h @@ -1,8 +1,9 @@ /* * openvz_driver.h: core driver methods for managing OpenVZ VPSs * - * Copyright (C) 2006, 2007 Binary Karma. + * 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 @@ -18,7 +19,10 @@ * 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 + * Authors: + * Shuveb Hussain + * Anoop Joe Cyriac + * */ @@ -39,6 +43,14 @@ struct openvz_driver { int openvzRegister(void); +#define openvzLog(level, msg...) { if(level == OPENVZ_WARN) \ + fprintf(stderr, "\nWARNING: ");\ + else \ + fprintf(stderr, "\nERROR: ");\ + fprintf(stderr, "\n\t");\ + fprintf(stderr, msg);\ + fprintf(stderr, "\n"); } + #endif