[lxc-devel] [PATCH] define list container api

Stéphane Graber stgraber at ubuntu.com
Thu Oct 10 03:00:45 UTC 2013


On Wed, Oct 09, 2013 at 07:17:43AM -0500, Serge Hallyn wrote:
> 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.
> 
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>

Overall looks good, thanks!

I just have one question/comment below that may impact memory/cpu usage
and performance quite a bit on machines with a lot of containers.

> ---
>  src/lxc/lxccontainer.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++
>  src/lxc/lxccontainer.h |  19 ++++++
>  src/tests/Makefile.am  |   6 +-
>  src/tests/list.c       |  57 ++++++++++++++++++
>  4 files changed, 235 insertions(+), 2 deletions(-)
>  create mode 100644 src/tests/list.c
> 
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 13ed4d2..5a0edce 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -2744,3 +2744,158 @@ int lxc_get_wait_states(const char **states)
>  			states[i] = lxc_state2str(i);
>  	return MAX_STATE;
>  }
> +
> +
> +bool add_to_clist(struct lxc_container ***list, struct lxc_container *c, int pos)
> +{
> +	struct lxc_container **newlist = realloc(*list, pos * sizeof(struct lxc_container *));
> +	if (!newlist) {
> +		free(*list);
> +		*list = NULL;
> +		ERROR("Out of memory");
> +		return false;
> +	}
> +
> +	*list = newlist;
> +	newlist[pos-1] = c;
> +	return true;
> +}
> +
> +int list_defined_containers(const char *lxcpath, struct lxc_container ***cret)
> +{
> +	DIR *dir;
> +	int nfound = 0;
> +	struct dirent dirent, *direntp;
> +
> +	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;
> +
> +	while (!readdir_r(dir, &dirent, &direntp)) {
> +		if (!direntp)
> +			break;
> +		if (!strcmp(direntp->d_name, "."))
> +			continue;
> +		if (!strcmp(direntp->d_name, ".."))
> +			continue;

Is it actually faster or more reliable to load the whole container
instead of just looking for direntp->d_name/config?

> +
> +		struct lxc_container *c = lxc_container_new(direntp->d_name, lxcpath);
> +		if (!c)
> +			continue;
> +		if (!lxcapi_is_defined(c)) {
> +			lxc_container_put(c);
> +			continue;
> +		}
> +
> +		nfound++;
> +
> +		if (cret) {
> +			if (!add_to_clist(cret, c, nfound))
> +				goto free_bad;
> +		} else {
> +			lxc_container_put(c);
> +		}
> +	}
> +
> +	process_lock();
> +	closedir(dir);
> +	process_unlock();
> +	return nfound;
> +
> +free_bad:
> +	if (cret && *cret) {
> +		while (--nfound >= 0)
> +			lxc_container_put((*cret)[nfound]);
> +		free(*cret);
> +	}
> +	process_lock();
> +	closedir(dir);
> +	process_unlock();
> +	return -1;
> +}
> +
> +int list_active_containers(const char *lxcpath, struct lxc_container ***cret)
> +{
> +	int 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;
> +	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';
> +		c = lxc_container_new(p, lxcpath);
> +		if (!c)
> +			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.
> +		 */
> +
> +		nfound++;
> +
> +		if (cret) {
> +			if (!add_to_clist(cret, c, nfound))
> +				goto free_bad;
> +		} else {
> +			lxc_container_put(c);
> +		}
> +
> +	}
> +
> +	process_lock();
> +	fclose(f);
> +	process_unlock();
> +	return nfound;
> +
> +free_bad:
> +	if (cret && *cret) {
> +		while (--nfound >= 0)
> +			lxc_container_put((*cret)[nfound]);
> +		free(*cret);
> +	}
> +	process_lock();
> +	fclose(f);
> +	process_unlock();
> +	return -1;
> +}
> diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
> index 20ab8e8..691e7d9 100644
> --- a/src/lxc/lxccontainer.h
> +++ b/src/lxc/lxccontainer.h
> @@ -248,6 +248,25 @@ 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.
> + * @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, 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
> + * @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, struct lxc_container ***cret);
> +
>  #if 0
>  char ** lxc_get_valid_keys();
>  char ** lxc_get_valid_values(char *key);
> diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
> index 1814c4b..5fce195 100644
> --- a/src/tests/Makefile.am
> +++ b/src/tests/Makefile.am
> @@ -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
>  
> @@ -61,4 +62,5 @@ EXTRA_DIST = \
>  	lxc-test-usernic \
>  	snapshot.c \
>  	concurrent.c \
> -	may_control.c
> +	may_control.c \
> +	list.c
> diff --git a/src/tests/list.c b/src/tests/list.c
> new file mode 100644
> index 0000000..01018eb
> --- /dev/null
> +++ b/src/tests/list.c
> @@ -0,0 +1,57 @@
> +/* list.c
> + *
> + * Copyright © 2013 Canonical, Inc
> + * Author: Serge Hallyn <serge.hallyn at 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;
> +	int n, n2;
> +
> +	if (argc > 1)
> +		lxcpath = argv[1];
> +
> +	n = list_defined_containers(lxcpath, NULL);
> +	printf("Found %d defined containers\n", n);
> +	n2 = list_defined_containers(lxcpath, &clist);
> +	if (n2 != n)
> +		printf("Warning: first call returned %d, second %d\n", n, n2);
> +	for (n=0; n<n2; n++) {
> +		struct lxc_container *c = clist[n];
> +		printf("Found defined container %s\n", c->name);
> +		lxc_container_put(c);
> +	}
> +	free(clist);
> +
> +	n = list_active_containers(lxcpath, NULL);
> +	printf("Found %d active containers\n", n);
> +	n2 = list_active_containers(lxcpath, &clist);
> +	if (n2 != n)
> +		printf("Warning: first call returned %d, second %d\n", n, n2);
> +	for (n=0; n<n2; n++) {
> +		printf("Found active container %s\n", clist[n]->name);
> +		lxc_container_put(clist[n]);
> +	}
> +	free(clist);
> +
> +	exit(0);
> +}
> -- 
> 1.8.1.2
> 
> 
> ------------------------------------------------------------------------------
> October Webinars: Code for Performance
> Free Intel webinars can help you accelerate application performance.
> Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from 
> the latest Intel processors and coprocessors. See abstracts and register >
> http://pubads.g.doubleclick.net/gampad/clk?id=60134071&iu=/4140/ostg.clktrk
> _______________________________________________
> Lxc-devel mailing list
> Lxc-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20131009/cddf39ee/attachment.pgp>


More information about the lxc-devel mailing list