]> git.proxmox.com Git - mirror_lxc.git/commitdiff
define list container api (v2)
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Fri, 11 Oct 2013 15:44:39 +0000 (10:44 -0500)
committerSerge Hallyn <serge.hallyn@ubuntu.com>
Mon, 14 Oct 2013 17:42:39 +0000 (12:42 -0500)
Two new commands are defined: list_defined_containers() and
list_active_containers().  Both take an lxcpath (NULL means
use the default lxcpath) and return the number of containers
found.  If a lxc_container ** is passed in, then an array of
lxc_container's is returned, one for each container found.
The caller must then lxc_container_put() each container and
free the array, as shown in the new list testcase.
If a char ** is passed in, then an array of container names
is returned, after which the caller must free all the names
and the name array, as showsn in the testcase.

Changelog:
Check for the container config file before trying to
create an lxc_container *, to save some work. [ per
stgraber comments]
Add names ** argument to return only container names.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
.gitignore
src/lxc/lxccontainer.c
src/lxc/lxccontainer.h
src/tests/Makefile.am
src/tests/list.c [new file with mode: 0644]

index 536423a9c28b6d9fd572c537063d20b1eaaebea0..ab0105af695b29ccb7112554974ee333dd3db517 100644 (file)
@@ -94,6 +94,7 @@ src/tests/lxc-test-startone
 src/tests/lxc-usernic-test
 src/tests/lxc-test-may-control
 src/tests/lxc-test-reboot
+src/tests/lxc-test-list
 
 config/compile
 config/config.guess
index 13ed4d202e0d4580dbd08d6c35b28c857a2676e3..6f978791109d6e34da85737290accfcc2b3bd181 100644 (file)
@@ -69,6 +69,19 @@ static bool file_exists(char *f)
        return stat(f, &statbuf) == 0;
 }
 
+static bool config_file_exists(const char *lxcpath, const char *cname)
+{
+       /* $lxcpath + '/' + $cname + '/config' + \0 */
+       int ret, len = strlen(lxcpath) + strlen(cname) + 9;
+       char *fname = alloca(len);
+
+       ret = snprintf(fname, len,  "%s/%s/config", lxcpath, cname);
+       if (ret < 0 || ret >= len)
+               return false;
+
+       return file_exists(fname);
+}
+
 /*
  * A few functions to help detect when a container creation failed.
  * If a container creation was killed partway through, then trying
@@ -2744,3 +2757,225 @@ int lxc_get_wait_states(const char **states)
                        states[i] = lxc_state2str(i);
        return MAX_STATE;
 }
+
+
+static bool add_to_names(char ***names, char *cname, int pos)
+{
+       char **newnames = realloc(*names, (pos+1) * sizeof(char *));
+       if (!newnames) {
+               ERROR("Out of memory");
+               return false;
+       }
+       *names = newnames;
+       newnames[pos] = strdup(cname);
+       if (!newnames[pos])
+               return false;
+       return true;
+}
+
+static bool add_to_clist(struct lxc_container ***list, struct lxc_container *c, int pos)
+{
+       struct lxc_container **newlist = realloc(*list, (pos+1) * sizeof(struct lxc_container *));
+       if (!newlist) {
+               ERROR("Out of memory");
+               return false;
+       }
+
+       *list = newlist;
+       newlist[pos] = c;
+       return true;
+}
+
+/*
+ * These next two could probably be done smarter with reusing a common function
+ * with different iterators and tests...
+ */
+int list_defined_containers(const char *lxcpath, char ***names, struct lxc_container ***cret)
+{
+       DIR *dir;
+       int i, cfound = 0, nfound = 0;
+       struct dirent dirent, *direntp;
+       struct lxc_container *c;
+
+       if (!lxcpath)
+               lxcpath = default_lxc_path();
+
+       process_lock();
+       dir = opendir(lxcpath);
+       process_unlock();
+
+       if (!dir) {
+               SYSERROR("opendir on lxcpath");
+               return -1;
+       }
+
+       if (cret)
+               *cret = NULL;
+       if (names)
+               *names = NULL;
+
+       while (!readdir_r(dir, &dirent, &direntp)) {
+               if (!direntp)
+                       break;
+               if (!strcmp(direntp->d_name, "."))
+                       continue;
+               if (!strcmp(direntp->d_name, ".."))
+                       continue;
+
+               if (!config_file_exists(lxcpath, direntp->d_name))
+                       continue;
+
+               if (names) {
+                       if (!add_to_names(names, direntp->d_name, cfound))
+                               goto free_bad;
+               }
+               cfound++;
+
+               if (!cret) {
+                       nfound++;
+                       continue;
+               }
+
+               c = lxc_container_new(direntp->d_name, lxcpath);
+               if (!c) {
+                       INFO("Container %s:%s has a config but could not be loaded",
+                               lxcpath, direntp->d_name);
+                       if (names)
+                               free((*names)[cfound--]);
+                       continue;
+               }
+               if (!lxcapi_is_defined(c)) {
+                       INFO("Container %s:%s has a config but is not defined",
+                               lxcpath, direntp->d_name);
+                       if (names)
+                               free((*names)[cfound--]);
+                       lxc_container_put(c);
+                       continue;
+               }
+
+               if (!add_to_clist(cret, c, nfound)) {
+                       lxc_container_put(c);
+                       goto free_bad;
+               }
+               nfound++;
+       }
+
+       process_lock();
+       closedir(dir);
+       process_unlock();
+       return nfound;
+
+free_bad:
+       if (names && *names) {
+               for (i=0; i<cfound; i++)
+                       free((*names)[i]);
+               free(*names);
+       }
+       if (cret && *cret) {
+               for (i=0; i<nfound; i++)
+                       lxc_container_put((*cret)[i]);
+               free(*cret);
+       }
+       process_lock();
+       closedir(dir);
+       process_unlock();
+       return -1;
+}
+
+int list_active_containers(const char *lxcpath, char ***names, struct lxc_container ***cret)
+{
+       int i, cfound = 0, nfound = 0;
+       int lxcpath_len;
+       char *line = NULL;
+       size_t len = 0;
+       struct lxc_container *c;
+
+       if (!lxcpath)
+               lxcpath = default_lxc_path();
+       lxcpath_len = strlen(lxcpath);
+
+       if (cret)
+               *cret = NULL;
+       if (names)
+               *names = NULL;
+
+       process_lock();
+       FILE *f = fopen("/proc/net/unix", "r");
+       process_unlock();
+       if (!f)
+               return -1;
+
+       while (getline(&line, &len, f) != -1) {
+               char *p = rindex(line, ' '), *p2;
+               if (!p)
+                       continue;
+               p++;
+               if (*p != 0x40)
+                       continue;
+               p++;
+               if (strncmp(p, lxcpath, lxcpath_len) != 0)
+                       continue;
+               p += lxcpath_len;
+               while (*p == '/')
+                       p++;
+
+               // Now p is the start of lxc_name
+               p2 = index(p, '/');
+               if (!p2 || strncmp(p2, "/command", 8) != 0)
+                       continue;
+               *p2 = '\0';
+
+               if (names) {
+                       if (!add_to_names(names, p, nfound))
+                               goto free_bad;
+               }
+               cfound++;
+
+               if (!cret) {
+                       nfound++;
+                       continue;
+               }
+
+               c = lxc_container_new(p, lxcpath);
+               if (!c) {
+                       INFO("Container %s:%s is running but could not be loaded",
+                               lxcpath, p);
+                       if (names)
+                               free((*names)[cfound--]);
+                       continue;
+               }
+
+               /*
+                * If this is an anonymous container, then is_defined *can*
+                * return false.  So we don't do that check.  Count on the
+                * fact that the command socket exists.
+                */
+
+               if (!add_to_clist(cret, c, nfound)) {
+                       lxc_container_put(c);
+                       goto free_bad;
+               }
+               nfound++;
+       }
+
+       process_lock();
+       fclose(f);
+       process_unlock();
+       return nfound;
+
+free_bad:
+       if (names && *names) {
+               for (i=0; i<cfound; i++)
+                       free((*names)[i]);
+               free(*names);
+       }
+       if (cret && *cret) {
+               for (i=0; i<nfound; i++)
+                       lxc_container_put((*cret)[i]);
+               free(*cret);
+       }
+       process_lock();
+       fclose(f);
+       process_unlock();
+       return -1;
+}
index 20ab8e870e357389abaee8e9eebbcb66eba4cf91..5901066a5784ca5b1ccfca580f460b2cd967e887 100644 (file)
@@ -248,6 +248,27 @@ const char *lxc_get_default_lvm_vg(void);
 const char *lxc_get_default_zfs_root(void);
 const char *lxc_get_version(void);
 
+/*
+ * Get a list of defined containers in a lxcpath.
+ * @lxcpath: lxcpath under which to look.
+ * @names: if not null, then a list of container names will be returned here.
+ * @cret: if not null, then a list of lxc_containers will be returned here.
+ *
+ * Returns the number of containers found, or -1 on error.
+ */
+int list_defined_containers(const char *lxcpath, char ***names, struct lxc_container ***cret);
+
+/*
+ * Get a list of active containers in a lxcpath.  Note that some of these
+ * containers may not be "defined".
+ * @lxcpath: lxcpath under which to look
+ * @names: if not null, then a list of container names will be returned here.
+ * @cret: if not null, then a list of lxc_containers will be returned here.
+ *
+ * Returns the number of containers found, or -1 on error.
+ */
+int list_active_containers(const char *lxcpath, char ***names, struct lxc_container ***cret);
+
 #if 0
 char ** lxc_get_valid_keys();
 char ** lxc_get_valid_values(char *key);
index e18693ba54729dc9ecc421a82931efe384e7b8a5..509e41405f880fdb956e25c1100532983e93fef0 100644 (file)
@@ -21,6 +21,7 @@ lxc_test_snapshot_SOURCES = snapshot.c
 lxc_test_concurrent_SOURCES = concurrent.c
 lxc_test_may_control_SOURCES = may_control.c
 lxc_test_reboot_SOURCES = reboot.c
+lxc_test_list_SOURCES = list.c
 
 AM_CFLAGS=-I$(top_srcdir)/src \
        -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
@@ -34,7 +35,7 @@ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \
        lxc-test-shutdowntest lxc-test-get_item lxc-test-getkeys lxc-test-lxcpath \
        lxc-test-cgpath lxc-test-clonetest lxc-test-console lxc-usernic-test \
        lxc-test-snapshot lxc-test-concurrent lxc-test-may-control \
-       lxc-test-reboot
+       lxc-test-reboot lxc-test-list
 
 bin_SCRIPTS = lxc-test-usernic
 
@@ -62,4 +63,5 @@ EXTRA_DIST = \
        snapshot.c \
        concurrent.c \
        may_control.c \
-       lxc-test-ubuntu
+       lxc-test-ubuntu \
+       list.c
diff --git a/src/tests/list.c b/src/tests/list.c
new file mode 100644 (file)
index 0000000..a061542
--- /dev/null
@@ -0,0 +1,117 @@
+/* list.c
+ *
+ * Copyright © 2013 Canonical, Inc
+ * Author: Serge Hallyn <serge.hallyn@ubuntu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <lxc/lxccontainer.h>
+
+int main(int argc, char *argv[])
+{
+       char *lxcpath = NULL;
+       struct lxc_container **clist;
+       char **names;
+       int i, n, n2;
+
+       if (argc > 1)
+               lxcpath = argv[1];
+
+       printf("Counting defined containers only\n");
+       n = list_defined_containers(lxcpath, NULL, NULL);
+       printf("Found %d defined containers\n", n);
+       printf("Looking for defined containers only\n");
+       n2 = list_defined_containers(lxcpath, NULL, &clist);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               struct lxc_container *c = clist[i];
+               printf("Found defined container %s\n", c->name);
+               lxc_container_put(c);
+       }
+       if (n2 > 0)
+               free(clist);
+
+       printf("Looking for defined names only\n");
+       n2 = list_defined_containers(lxcpath, &names, NULL);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               printf("Found defined container %s\n", names[i]);
+               free(names[i]);
+       }
+       if (n2 > 0)
+               free(names);
+
+       printf("Looking for defined names and containers\n");
+       n2 = list_defined_containers(lxcpath, &names, &clist);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               struct lxc_container *c = clist[i];
+               printf("Found defined container %s, name was %s\n", c->name, names[i]);
+               free(names[i]);
+               lxc_container_put(c);
+       }
+       if (n2 > 0) {
+               free(names);
+               free(clist);
+       }
+
+
+       printf("Counting active containers only\n");
+       n = list_active_containers(lxcpath, NULL, NULL);
+       printf("Found %d active containers\n", n);
+       printf("Looking for active containers only\n");
+       n2 = list_active_containers(lxcpath, NULL, &clist);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               printf("Found active container %s\n", clist[i]->name);
+               lxc_container_put(clist[i]);
+       }
+       if (n2 > 0)
+               free(clist);
+
+       printf("Looking for active names only\n");
+       n2 = list_active_containers(lxcpath, &names, NULL);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               printf("Found active container %s\n", names[i]);
+               free(names[i]);
+       }
+       if (n2 > 0)
+               free(names);
+
+       printf("Looking for active names and containers\n");
+       n2 = list_active_containers(lxcpath, &names, &clist);
+       if (n2 != n)
+               printf("Warning: first call returned %d, second %d\n", n, n2);
+       for (i=0; i<n2; i++) {
+               struct lxc_container *c = clist[i];
+               printf("Found active container %s, name was %s\n", c->name, names[i]);
+               free(names[i]);
+               lxc_container_put(c);
+       }
+       if (n2 > 0) {
+               free(names);
+               free(clist);
+       }
+
+       exit(0);
+}