[Libvir] [RFC] 2 of 4 Linux Container support - lxc_conf files

Daniel Veillard veillard at redhat.com
Thu Mar 20 16:00:32 UTC 2008


On Wed, Mar 19, 2008 at 11:14:31PM -0700, Dave Leskovec wrote:
> This patch adds the lxc_conf source files.
[...]
> +#define LXC_MAX_XML_LENGTH 4096

  maybe up that a bit, or even better try to avoid a fixed size buffer
but that can be done separately

> +#define LXC_MAX_ERROR_LEN 1024
> +#define LXC_DOMAIN_TYPE "linuxcontainer"

  In general try to provide comments for types, even if it looks easy to
figure out :-)

> +typedef struct __lxc_mount lxc_mount_t;
> +struct __lxc_mount {
> +    char source[PATH_MAX]; /* user's directory */
> +    char target[PATH_MAX];
> +
> +    lxc_mount_t *next;
> +};
> +
> +typedef struct __lxc_vm_def lxc_vm_def_t;
> +struct __lxc_vm_def {
> +    unsigned char uuid[VIR_UUID_BUFLEN];
> +    char* name;
> +    int id;
> +
> +    /* init command string */
> +    char init[PATH_MAX];
> +
> +    int maxMemory;

  In kbytes I assume, maybe an unsigned long would be in order there...

> +    /* mounts - list of mount structs */
> +    int nmounts;
> +    lxc_mount_t *mounts;
> +
> +    /* tty device */
> +    char tty[LXC_MAX_TTY_NAME];
> +};
[...]

> Index: b/src/lxc_conf.c
[...]
> +static inline int lxcIsEmptyXPathStringObj(xmlXPathObjectPtr xpathObj)
> +{
> +    if ((xpathObj == NULL) ||
> +        (xpathObj->type != XPATH_STRING) ||
> +        (xpathObj->stringval == NULL) ||
> +        (xpathObj->stringval[0] == 0)) {
> +        return 1;
> +    } else {
> +        return 0;
> +    }
> +}

  best made a convenience function exported from xml.h . I'm not sure 
inlining functions is really a net gain in a libvirt context, it's not
like anything is time critical, but this can add up on the size of the
library quicker than one would expect.

> +static int lxcParseMountXML(virConnectPtr conn, xmlNodePtr nodePtr,
> +                            lxc_mount_t *lxcMount)
> +{
> +    xmlChar *fsType = NULL;
> +    xmlNodePtr curNode;
> +    xmlChar *mountSource = NULL;
> +    xmlChar *mountTarget = NULL;
> +    int strLen;
> +    int rc = -1;
> +
> +    if (NULL == (fsType = xmlGetProp(nodePtr, BAD_CAST "type"))) {

  stylistic, separate the affectation and the test, more readable IMHO.
And it makes more obvious the fact that the returned value need to be freed.

> +        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                 _("missing filesystem type"));
> +        goto error;
> +    }
[...]
> +static int lxcParseDomainName(virConnectPtr conn, char **name,
> +                              xmlXPathContextPtr contextPtr)
> +{
> +    int rc = -1;
> +    xmlXPathObjectPtr xpathObj = NULL;
> +
> +    xpathObj = xmlXPathEval(BAD_CAST "string(/domain/name[1])", contextPtr);
> +    if (lxcIsEmptyXPathStringObj(xpathObj)) {
> +        lxcError(conn, NULL, VIR_ERR_NO_NAME, NULL);
> +        goto parse_complete;
> +    }

  Hum, why not use virXPathString() it hides the libxml2 XPath details,

> +    *name = strdup((const char *)xpathObj->stringval);
> +    if (NULL == *name) {
> +        lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL);
> +        goto parse_complete;
> +    }
> +
> +
> +    rc = 0;
> +
> +parse_complete:
> +    xmlXPathFreeObject(xpathObj);
> +    return rc;
> +}

  and simplifies the cleanup/exit, no strdup, no xmlXPathFreeObject,
I guess each time you use the combo xmlXPathEval/lxcIsEmptyXPathStringObj
a virXPathString call would be clearer and more in line with other libvirt
code

> +static int lxcParseDomainMounts(virConnectPtr conn,
> +                                lxc_mount_t **mounts,
> +                                xmlXPathContextPtr contextPtr)
> +{
> +    int rc = -1;
> +    xmlXPathObjectPtr xpathObj = NULL;
> +    int i;
> +    lxc_mount_t *mountObj;
> +    lxc_mount_t *prevObj = NULL;
> +    int nmounts = 0;
> +
> +    xpathObj = xmlXPathEval(BAD_CAST "/domain/devices/filesystem",

  Hum, I'm sure using virXPathNodeSet() would make this code clearer

> +    if ((xpathObj != NULL) &&
> +        (xpathObj->type == XPATH_NODESET) &&
> +        (xpathObj->nodesetval != NULL) &&
> +        (xpathObj->nodesetval->nodeNr >= 0)) {
> +        for (i = 0; i < xpathObj->nodesetval->nodeNr; ++i) {
> +            mountObj = calloc(1, sizeof(lxc_mount_t));
> +            if (NULL == mountObj) {
> +                lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "mount");
> +                goto parse_complete;
> +            }
> +
> +            rc = lxcParseMountXML(conn, xpathObj->nodesetval->nodeTab[i],
> +                                  mountObj);
> +            if (0 > rc) {
> +                free(mountObj);
> +                goto parse_complete;
> +            }
> +
> +            /* set the linked list pointers */
> +            nmounts++;
> +            mountObj->next = NULL;
> +            if (0 == i) {
> +                *mounts = mountObj;
> +            } else {
> +                prevObj->next = mountObj;
> +            }
> +            prevObj = mountObj;
> +        }
> +    }
> +
> +    rc = nmounts;
> +
> +parse_complete:
> +    xmlXPathFreeObject(xpathObj);
> +
> +    return rc;
> +}
[...]
> +static int lxcParseDomainMemory(virConnectPtr conn, int* memory, xmlXPathContextPtr contextPtr)
> +{
> +    int rc = -1;
> +    xmlXPathObjectPtr xpathObj = NULL;
> +    char *endChar = NULL;
> +
> +    xpathObj = xmlXPathEval(BAD_CAST "string(/domain/memory[1])", contextPtr);
> +    if (lxcIsEmptyXPathStringObj(xpathObj)) {
> +        /* not an error, default to an invalid value so it's not used */
> +        *memory = -1;
> +    } else {
> +        *memory = strtoll((const char*)xpathObj->stringval,
> +                                          &endChar, 10);
> +        if ((endChar == (const char*)xpathObj->stringval) ||
> +           (*endChar != '\0')) {
> +            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                     _("invalid memory value"));
> +            goto parse_complete;
> +        }
> +    }
>

 use virXPathLong() and keep as a long in the structure,

> +    rc = 0;
[...]
> +static lxc_vm_def_t * lxcParseXML(virConnectPtr conn, xmlDocPtr docPtr)
> +{
> +    xmlNodePtr rootNodePtr = NULL;
> +    xmlXPathContextPtr contextPtr = NULL;
> +    xmlChar *xmlProp = NULL;
> +    lxc_vm_def_t *containerDef;
> +
> +    if (!(containerDef = calloc(1, sizeof(*containerDef)))) {
> +        lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "containerDef");
> +        return NULL;
> +    }
> +
> +    /* Prepare parser / xpath context */
> +    rootNodePtr = xmlDocGetRootElement(docPtr);
> +    if ((rootNodePtr == NULL) ||
> +       (!xmlStrEqual(rootNodePtr->name, BAD_CAST "domain"))) {
> +        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                 _("invalid root element"));
> +        goto error;
> +    }
> +
> +    contextPtr = xmlXPathNewContext(docPtr);
> +    if (contextPtr == NULL) {
> +        lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "context");
> +        goto error;
> +    }
> +
> +    /* Verify the domain type is linuxcontainer */
> +    if (!(xmlProp = xmlGetProp(rootNodePtr, BAD_CAST "type"))) {
> +        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                 _("missing domain type"));
> +        goto error;
> +    }
> +
> +    if (!(xmlStrEqual(xmlProp, BAD_CAST LXC_DOMAIN_TYPE))) {
> +        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                 _("invalid domain type"));
> +        goto error;
> +    }
> +    free(xmlProp);
> +    xmlProp = NULL;

  Hum, maybe this check could be unified as a simple 
     type = virXPathString("/domain/@type", contextPtr);
and check the returned string against LXC_DOMAIN_TYPE, smaller, simpler
and would insure that the root element is named domain (without namespace)

> +    if ((xmlProp = xmlGetProp(rootNodePtr, BAD_CAST "id"))) {
> +        if (0 > virStrToLong_i((char*)xmlProp, NULL, 10, &(containerDef->id))) {
> +            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                     "invalid domain id");
> +            goto error;
> +        }
> +    } else {
> +        containerDef->id = -1;
> +    }
> +    free(xmlProp);
> +    xmlProp = NULL;

   Same with virXPathString("/domain/@id, ...)

> +    if (lxcParseDomainName(conn, &(containerDef->name), contextPtr) < 0) {
[...]
> +int lxcLoadDriverConfig(virConnectPtr conn)
> +{
> +    lxc_driver_t *driverPtr = (lxc_driver_t*)conn->privateData;
> +
> +    /* Set the container configuration directory */
> +    driverPtr->configDir = strdup(SYSCONF_DIR "/libvirt/lxc");
> +    if (NULL == driverPtr->configDir) {
> +        lxcError(conn, NULL, VIR_ERR_NO_MEMORY, "configDir");
> +        return -1;
> +    }
> +
> +    return 0;
> +}

  Hum, is there something missing in that function ?

[...]
[...]
> +int lxcLoadContainerInfo(virConnectPtr conn)
> +{
> +    int rc = -1;
> +    lxc_driver_t *driverPtr = (lxc_driver_t*)conn->privateData;
> +    DIR *dir;
> +    struct dirent *dirEntry;
> +
> +    if (!(dir = opendir(driverPtr->configDir))) {
> +        if (ENOENT == errno) {
> +            /* no config dir => no containers */
> +            rc = 0;
> +        } else {
> +            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                     _("failed to open config directory: %s"), strerror(errno));
> +        }
> +
> +        goto load_complete;
> +    }
> +
> +    while ((dirEntry = readdir(dir))) {
> +        if (dirEntry->d_name[0] == '.') {
> +            continue;
> +        }
> +
> +        if (!virFileHasSuffix(dirEntry->d_name, ".xml")) {
> +            continue;
> +        }

  so container definition files are detected by a .xml suffix, maybe
using something like .lxc would be more specific, not a big deal, but
once it's set it's a bit annoying to change

[...]
> +int lxcDeleteConfig(virConnectPtr conn,
> +                    lxc_driver_t *driver ATTRIBUTE_UNUSED,
> +                    const char *configFile,
> +                    const char *name)
> +{
> +    if (!configFile[0]) {
> +        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                 _("no config file for %s"), name);
> +        return -1;
> +    }

  Hum ... can we make a little bit of checking here for the file
to be an absolute path and having the right prefix ? 

> +    if (unlink(configFile) < 0) {
> +        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
> +                 _("cannot remove config for %s"), name);
> +        return -1;
> +    }
> +
> +    return 0;
> +}

  Still look fine, I could make the XPath access cleanups in a second
step.

Daniel

-- 
Red Hat Virtualization group http://redhat.com/virtualization/
Daniel Veillard      | virtualization library  http://libvirt.org/
veillard at redhat.com  | libxml GNOME XML XSLT toolkit  http://xmlsoft.org/
http://veillard.com/ | Rpmfind RPM search engine  http://rpmfind.net/




More information about the libvir-list mailing list