OpenVZ xml refactoring

* 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.
Daniel
This commit is contained in:
Daniel Veillard 2008-07-28 14:06:54 +00:00
parent 387e06421f
commit 996933bbcd
6 changed files with 280 additions and 178 deletions

View File

@ -1,3 +1,10 @@
Mon Jul 28 16:04:58 CEST 2008 Daniel Veillard <veillard@redhat.com>
* 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 <veillard@redhat.com>
* src/qemu_driver.c: patch from Guido Günther to make sure create

View File

@ -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;

View File

@ -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)

View File

@ -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:
<filesystem type="template">
<source name="fedora-core-5-i386"/>
<quota type="size" max="10000"/>
<quota type="inodes" max="100"/>
</filesystem>
*/
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;

View File

@ -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 */

View File

@ -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) {