diff --git a/ChangeLog b/ChangeLog index deff7ea54f..b06392fe11 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Mon Jul 28 16:04:58 CEST 2008 Daniel Veillard + + * src/domain_conf.[ch] src/openvz_conf.[ch] src/openvz_driver.c: + patch from Evgeniy Sokolov doing the OpenVZ xml refactoring, + still needs to be ported to the new XML parsing code but + implements the new format. + Mon Jul 28 14:50:55 CEST 2008 Daniel Veillard * src/qemu_driver.c: patch from Guido Günther to make sure create diff --git a/src/domain_conf.c b/src/domain_conf.c index 8ddfb6e7bf..d62909340b 100644 --- a/src/domain_conf.c +++ b/src/domain_conf.c @@ -640,7 +640,7 @@ static void virDomainNetRandomMAC(virDomainNetDefPtr def) { * @param node XML nodeset to parse for net definition * @return 0 on success, -1 on failure */ -static virDomainNetDefPtr +virDomainNetDefPtr virDomainNetDefParseXML(virConnectPtr conn, xmlNodePtr node) { virDomainNetDefPtr def; diff --git a/src/domain_conf.h b/src/domain_conf.h index b438bc8d70..e2c513d3e0 100644 --- a/src/domain_conf.h +++ b/src/domain_conf.h @@ -474,6 +474,9 @@ int virDomainLoadAllConfigs(virConnectPtr conn, int virDomainDeleteConfig(virConnectPtr conn, virDomainObjPtr dom); +virDomainNetDefPtr virDomainNetDefParseXML(virConnectPtr conn, + xmlNodePtr node); + VIR_ENUM_DECL(virDomainVirt) VIR_ENUM_DECL(virDomainBoot) VIR_ENUM_DECL(virDomainFeature) diff --git a/src/openvz_conf.c b/src/openvz_conf.c index 743b6d4929..6b4dda0196 100644 --- a/src/openvz_conf.c +++ b/src/openvz_conf.c @@ -56,6 +56,8 @@ #include "buf.h" #include "memory.h" #include "util.h" +#include "xml.h" +#include "domain_conf.h" static char *openvzLocateConfDir(void); static struct openvz_vm_def *openvzParseXML(virConnectPtr conn, xmlDocPtr xml); @@ -136,6 +138,34 @@ strtoI(const char *str) return val; } +/* function checks MAC address is empty + return 0 - empty + 1 - not +*/ +int openvzCheckEmptyMac(const unsigned char *mac) +{ + int i; + for (i = 0; i < VIR_DOMAIN_NET_MAC_SIZE; i++) + if (mac[i] != 0x00) + return 1; + + return 0; +} + +/* convert mac address to string + return pointer to string or NULL +*/ +char *openvzMacToString(const unsigned char *mac) +{ + char str[20]; + if (snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]) >= 18) + return NULL; + + return strdup(str); +} + void openvzRemoveInactiveVM(struct openvz_driver *driver, struct openvz_vm *vm) { @@ -148,30 +178,7 @@ 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; - VIR_FREE(prev); - } - while (ip) { - struct ovz_ip *prev = ip; - - ip = ip->next; - VIR_FREE(prev); - } - while (ns) { - struct ovz_ns *prev = ns; - - ns = ns->next; - VIR_FREE(prev); - } - - VIR_FREE(def); + virDomainNetDefFree(def->net); } } @@ -285,6 +292,91 @@ struct openvz_vm_def return def; } +/* Parse filesystem section +Sample: + + + + + +*/ +static int openvzParseDomainFS(virConnectPtr conn, + struct openvz_fs_def *fs, + xmlXPathContextPtr ctxt) +{ + xmlNodePtr cur, obj; + char *type = NULL; + int n; + xmlNodePtr *nodes = NULL; + + + if ((n = virXPathNodeSet("/domain/devices/filesystem", ctxt, &nodes)) < 0) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("missing filesystem tag")); + goto error; + } + + if (n > 1) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("There should be only one filesystem tag")); + goto error; + } + + obj = nodes[0]; + + /*check template type*/ + type = virXMLPropString(obj, "type"); + if (type == NULL) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("missing type attribute")); + goto error; + } + + if (STRNEQ(type, "template")) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("Unknown type attribute %s"), type); + goto error; + } + VIR_FREE(type); + + cur = obj->children; + while(cur != NULL) + { + if (cur->type == XML_ELEMENT_NODE) { + if (xmlStrEqual(cur->name, BAD_CAST "source")) { + char * name = virXMLPropString(cur, "name"); + + if (name != NULL) { + strncpy(fs->tmpl, name,sizeof(fs->tmpl)); + fs->tmpl[sizeof(fs->tmpl) - 1] = '\0'; + } + VIR_FREE(name); + } else if (xmlStrEqual(cur->name, BAD_CAST "quota")) { + char * qtype = virXMLPropString(cur, "type"); + char * max = virXMLPropString(cur, "max"); + + if (qtype != NULL && STREQ(qtype, "size") && max != NULL) + fs->disksize = strtoI(max); + else if (qtype != NULL && STREQ(qtype, "inodes") && max != NULL) + fs->diskinodes = strtoI(max); + VIR_FREE(qtype); + VIR_FREE(max); + } + } + cur = cur->next; + } + VIR_FREE(nodes); + + return 0; + + error: + VIR_FREE(nodes); + VIR_FREE(type); + + return -1; +} + + /* * Parses a libvirt XML definition of a guest, and populates the * the openvz_vm struct with matching data about the guests config @@ -293,12 +385,12 @@ static struct openvz_vm_def *openvzParseXML(virConnectPtr conn, xmlDocPtr xml) { xmlNodePtr root = NULL; - xmlChar *prop = NULL; + char *prop = NULL; xmlXPathContextPtr ctxt = NULL; xmlXPathObjectPtr obj = NULL; - struct openvz_vm_def *def; - struct ovz_ip *ovzIp; - struct ovz_ns *ovzNs; + struct openvz_vm_def *def = NULL; + xmlNodePtr *nodes = NULL; + int i, n; if (VIR_ALLOC(def) < 0) { openvzError(conn, VIR_ERR_NO_MEMORY, _("xmlXPathContext")); @@ -306,7 +398,6 @@ static struct openvz_vm_def } /* Prepare parser / xpath context */ - root = xmlDocGetRootElement(xml); if ((root == NULL) || (!xmlStrEqual(root->name, BAD_CAST "domain"))) { openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("incorrect root element")); @@ -318,14 +409,15 @@ static struct openvz_vm_def openvzError(conn, VIR_ERR_NO_MEMORY, _("xmlXPathContext")); goto bail_out; } + ctxt->node = root; /* Find out what type of OPENVZ virtualization to use */ - if (!(prop = xmlGetProp(root, BAD_CAST "type"))) { + if (!(prop = virXMLPropString(root, "type"))) { openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("missing domain type attribute")); goto bail_out; } - if (STRNEQ((char *)prop, "openvz")){ + if (STRNEQ(prop, "openvz")){ openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("invalid domain type attribute")); goto bail_out; } @@ -347,142 +439,55 @@ static struct openvz_vm_def } strncpy(def->name, (const char *) obj->stringval, OPENVZ_NAME_MAX); xmlXPathFreeObject(obj); + obj = NULL; /* 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)) { + prop = virXPathString("string(./uuid[1])", ctxt); + if (!prop) { int err; - if ((err = virUUIDGenerate(def->uuid))) { - openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Failed to generate UUID")); + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("Failed to generate UUID: %s"), + strerror(err)); goto bail_out; } - } else if (virUUIDParse((const char *)obj->stringval, def->uuid) < 0) { - openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("malformed uuid element")); - goto bail_out; + } else { + if (virUUIDParse(prop, def->uuid) < 0) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("malformed uuid element")); + goto bail_out; + } + VIR_FREE(prop); } - xmlXPathFreeObject(obj); + + /* extract virtual CPUs */ + if (virXPathULong("string(./vcpu[1])", ctxt, &def->vcpus) < 0) + def->vcpus = 0; //use default CPUs count /* Extract filesystem info */ - 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)) { - openvzError(conn, VIR_ERR_OS_TYPE, NULL); - goto bail_out; - } - strncpy(def->fs.tmpl, (const char *) obj->stringval, OPENVZ_TMPL_MAX); - xmlXPathFreeObject(obj); - - /* TODO Add quota processing here */ - - /* TODO analysis of the network devices */ - - - /* 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)) { + if (openvzParseDomainFS(conn, &(def->fs), ctxt)) { openvzError(conn, VIR_ERR_INTERNAL_ERROR, - _("ipaddress length too long")); + _("malformed filesystem tag")); goto bail_out; } - if (VIR_ALLOC(ovzIp) < 0) { - 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)) { + /* analysis of the network devices */ + if ((n = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes)) < 0) { openvzError(conn, VIR_ERR_INTERNAL_ERROR, - _("netmask length too long")); + "%s", _("cannot extract network devices")); 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); + for (i = n - 1 ; i >= 0 ; i--) { + virDomainNetDefPtr net = virDomainNetDefParseXML(conn, + nodes[i]); + if (!net) + goto bail_out; - if (strlen((const char *) obj->stringval) >= (OPENVZ_HOSTNAME_MAX - 1)) { - openvzError(conn, VIR_ERR_INTERNAL_ERROR, - _("hostname length too long")); - goto bail_out; + net->next = def->net; + def->net = net; } - 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)) { - openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("gateway length too long")); - 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)) { - openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("nameserver length too long")); - goto bail_out; - } - if (VIR_ALLOC(ovzNs) < 0) { - 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)) { - openvzError(conn, VIR_ERR_INTERNAL_ERROR, NULL); - goto bail_out; - } - if (strlen((const char *) obj->stringval) >= (OPENVZ_PROFILE_MAX - 1)) { - openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("profile length too long")); - goto bail_out; - } - strncpy(def->profile, (const char *) obj->stringval, OPENVZ_PROFILE_MAX - 1); - xmlXPathFreeObject(obj); + VIR_FREE(nodes); xmlXPathFreeContext(ctxt); return def; diff --git a/src/openvz_conf.h b/src/openvz_conf.h index 6f83612743..5f0d3a461c 100644 --- a/src/openvz_conf.h +++ b/src/openvz_conf.h @@ -29,6 +29,7 @@ #define OPENVZ_CONF_H #include "openvz_driver.h" +#include "domain_conf.h" enum { OPENVZ_WARN, OPENVZ_ERR }; @@ -61,33 +62,16 @@ struct vps_props { 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; + long int disksize, diskinodes; }; struct openvz_vm_def { char name[OPENVZ_NAME_MAX]; unsigned char uuid[VIR_UUID_BUFLEN]; char profile[OPENVZ_PROFILE_MAX]; + unsigned long vcpus; struct openvz_fs_def fs; - struct openvz_net_def net; + virDomainNetDefPtr net; }; struct ovz_quota { @@ -133,4 +117,7 @@ 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(const char *str); +int openvzCheckEmptyMac(const unsigned char *mac); +char *openvzMacToString(const unsigned char *mac); + #endif /* OPENVZ_CONF_H */ diff --git a/src/openvz_driver.c b/src/openvz_driver.c index a0b6c8d82a..981fd8a2a9 100644 --- a/src/openvz_driver.c +++ b/src/openvz_driver.c @@ -155,14 +155,6 @@ static int openvzDomainDefineCmd(virConnectPtr conn, ADD_ARG_LIT("--config"); ADD_ARG_LIT(vmdef->profile); } - if ((vmdef->net.ips->ip && *(vmdef->net.ips->ip))) { - ADD_ARG_LIT("--ipadd"); - ADD_ARG_LIT(vmdef->net.ips->ip); - } - if ((vmdef->net.hostname && *(vmdef->net.hostname))) { - ADD_ARG_LIT("--hostname"); - ADD_ARG_LIT(vmdef->net.hostname); - } ADD_ARG(NULL); return 0; @@ -336,6 +328,98 @@ static int openvzDomainReboot(virDomainPtr dom, return 0; } +static int +openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid, + virDomainNetDefPtr net) +{ + int rc = 0, narg; + char *prog[OPENVZ_MAX_ARG]; + char *mac = NULL; + +#define ADD_ARG_LIT(thisarg) \ + do { \ + if (narg >= OPENVZ_MAX_ARG) \ + goto no_memory; \ + if ((prog[narg++] = strdup(thisarg)) == NULL) \ + goto no_memory; \ + } while (0) + + + if (net == NULL) + return 0; + if (vpsid == NULL) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("Container ID is not specified")); + return -1; + } + + for (narg = 0; narg < OPENVZ_MAX_ARG; narg++) + prog[narg] = NULL; + + narg = 0; + + if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE || + net->type == VIR_DOMAIN_NET_TYPE_ETHERNET) { + ADD_ARG_LIT(VZCTL); + ADD_ARG_LIT("--quiet"); + ADD_ARG_LIT("set"); + ADD_ARG_LIT(vpsid); + } + + if (openvzCheckEmptyMac(net->mac) > 0) + mac = openvzMacToString(net->mac); + + if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE && + net->data.bridge.brname != NULL) { + char opt[1024]; + //--netif_add ifname[,mac,host_ifname,host_mac] + ADD_ARG_LIT("--netif_add") ; + strncpy(opt, net->data.bridge.brname, 256); + if (mac != NULL) { + strcat(opt, ","); + strcat(opt, mac); + } + ADD_ARG_LIT(opt) ; + }else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET && + net->data.ethernet.ipaddr != NULL) { + //--ipadd ip + ADD_ARG_LIT("--ipadd") ; + ADD_ARG_LIT(net->data.ethernet.ipaddr) ; + } + + //TODO: processing NAT and physical device + + if (prog[0] != NULL){ + ADD_ARG_LIT("--save"); + if (virRun(conn, (char **)prog, NULL) < 0) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("Could not exec %s"), VZCTL); + rc = -1; + goto exit; + } + } + + if (net->next != NULL) + if (openvzDomainSetNetwork(conn, vpsid, net->next) < 0) { + rc = -1; + goto exit; + } + + exit: + cmdExecFree(prog); + VIR_FREE(mac); + return rc; + + no_memory: + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("Could not put argument to %s"), VZCTL); + cmdExecFree(prog); + VIR_FREE(mac); + return -1; + +#undef ADD_ARG_LIT +} + static virDomainPtr openvzDomainDefineXML(virConnectPtr conn, const char *xml) { @@ -366,6 +450,9 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml) goto exit; } + //TODO: set number virtual CPUs + //TODO: set quota + if (virRun(conn, (char **)prog, NULL) < 0) { openvzError(conn, VIR_ERR_INTERNAL_ERROR, _("Could not exec %s"), VZCTL); @@ -375,7 +462,14 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml) dom = virGetDomain(conn, vm->vmdef->name, vm->vmdef->uuid); if (dom) dom->id = vm->vpsid; - exit: + + if (openvzDomainSetNetwork(conn, vmdef->name, vmdef->net) < 0) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("Could not configure network")); + goto exit; + } + + exit: cmdExecFree(prog); return dom; } @@ -420,6 +514,12 @@ openvzDomainCreateLinux(virConnectPtr conn, const char *xml, goto exit; } + if (openvzDomainSetNetwork(conn, vmdef->name, vmdef->net) < 0) { + openvzError(conn, VIR_ERR_INTERNAL_ERROR, + _("Could not configure network")); + goto exit; + } + progstart[3] = vmdef->name; if (virRun(conn, (char **)progstart, NULL) < 0) {