Quoting Stéphane Graber (stgra...@ubuntu.com): > Add initial support for showing and querying nested containers. > > This is done through a new --nesting argument to lxc-ls and uses > lxc-attach to go look for sub-containers. > > Known limitations include the dependency on setns support for the PID > and NETWORK namespaces and the assumption that LXCPATH for the sub-containers > matches that of the host. > > Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
looks nice, thanks :) Acked-by: Serge E. Hallyn <serge.hal...@ubuntu.com> > --- > doc/lxc-ls.sgml.in | 12 +++++++ > src/lxc/lxc-ls | 75 > ++++++++++++++++++++++++++++++++++----- > src/python-lxc/lxc/__init__.py.in | 15 ++------ > 3 files changed, 81 insertions(+), 21 deletions(-) > > diff --git a/doc/lxc-ls.sgml.in b/doc/lxc-ls.sgml.in > index 83618e5..877404d 100644 > --- a/doc/lxc-ls.sgml.in > +++ b/doc/lxc-ls.sgml.in > @@ -56,6 +56,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA > 02111-1307 USA > <arg choice="opt">--stopped</arg> > <arg choice="opt">--fancy</arg> > <arg choice="opt">--fancy-format</arg> > + <arg choice="opt">--nesting</arg> > <arg choice="opt">filter</arg> > </cmdsynopsis> > </refsynopsisdiv> > @@ -152,6 +153,17 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA > 02111-1307 USA > > <varlistentry> > <term> > + <option><optional>--nesting</optional></option> > + </term> > + <listitem> > + <para> > + Show nested containers. > + </para> > + </listitem> > + </varlistentry> > + > + <varlistentry> > + <term> > <option><optional>filter</optional></option> > </term> > <listitem> > diff --git a/src/lxc/lxc-ls b/src/lxc/lxc-ls > index 92a4e53..6468890 100644 > --- a/src/lxc/lxc-ls > +++ b/src/lxc/lxc-ls > @@ -31,9 +31,11 @@ warnings.filterwarnings("ignore", "The python-lxc API > isn't yet stable") > > import argparse > import gettext > +import json > import lxc > import os > import re > +import subprocess > import sys > > _ = gettext.gettext > @@ -85,6 +87,23 @@ def getTerminalSize(): > > return int(cr[1]), int(cr[0]) > > + > +def getSubContainers(container, lxcpath): > + attach = ['lxc-attach', '-R', '-s', 'NETWORK|PID', '-n', container, > + '--', sys.argv[0], "--nesting"] > + > + with open(os.devnull, "w") as fd: > + newenv = dict(os.environ) > + newenv['NESTED'] = "/proc/1/root/%s" % lxcpath > + sp = subprocess.Popen(attach, stderr=fd, stdout=subprocess.PIPE, > + env=newenv, universal_newlines=True) > + sp.wait() > + out = sp.stdout.read() > + if out: > + return json.loads(out) > + return None > + > + > # Begin parsing the command line > parser = argparse.ArgumentParser(description=_("LXC: List containers"), > > formatter_class=argparse.RawTextHelpFormatter) > @@ -93,7 +112,8 @@ parser.add_argument("-1", dest="one", action="store_true", > help=_("list one container per line (default when > piped)")) > > parser.add_argument("-P", "--lxcpath", dest="lxcpath", metavar="PATH", > - help=_("Use specified container path"), default=None) > + help=_("Use specified container path"), > + default=lxc.default_config_path) > > parser.add_argument("--active", action="store_true", > help=_("list only active containers " > @@ -114,6 +134,9 @@ parser.add_argument("--fancy", action="store_true", > parser.add_argument("--fancy-format", type=str, > default="name,state,ipv4,ipv6", > help=_("comma separated list of fields to show")) > > +parser.add_argument("--nesting", dest="nesting", action="store_true", > + help=_("show nested containers")) > + > parser.add_argument("filter", metavar='FILTER', type=str, nargs="?", > help=_("regexp to be applied on the container list")) > > @@ -129,6 +152,9 @@ if args.active: > if not sys.stdout.isatty(): > args.one = True > > +# Set the lookup path for the containers > +lxcpath = os.environ.get('NESTED', args.lxcpath) > + > # Turn args.fancy_format into a list > args.fancy_format = args.fancy_format.strip().split(",") > > @@ -141,7 +167,7 @@ if not os.geteuid() == 0 and (args.fancy or args.state): > > # List of containers, stored as dictionaries > containers = [] > -for container_name in lxc.list_containers(config_path=args.lxcpath): > +for container_name in lxc.list_containers(config_path=lxcpath): > entry = {} > entry['name'] = container_name > > @@ -150,7 +176,7 @@ for container_name in > lxc.list_containers(config_path=args.lxcpath): > continue > > # Return before grabbing the object (non-root) > - if not args.state and not args.fancy: > + if not args.state and not args.fancy and not args.nesting: > containers.append(entry) > continue > > @@ -161,28 +187,47 @@ for container_name in > lxc.list_containers(config_path=args.lxcpath): > continue > > # Nothing more is needed if we're not printing some fancy output > - if not args.fancy: > + if not args.fancy and not args.nesting: > containers.append(entry) > continue > > # Some extra field we may want > - if 'state' in args.fancy_format: > + if 'state' in args.fancy_format or args.nesting: > entry['state'] = container.state > - if 'pid' in args.fancy_format: > + > + if 'pid' in args.fancy_format or args.nesting: > entry['pid'] = "-" > if container.init_pid != -1: > entry['pid'] = str(container.init_pid) > > # Get the IPs > for protocol in ('ipv4', 'ipv6'): > - if protocol in args.fancy_format: > + if protocol in args.fancy_format or args.nesting: > entry[protocol] = "-" > ips = container.get_ips(protocol=protocol, timeout=1) > if ips: > entry[protocol] = ", ".join(ips) > > + # Append the container > containers.append(entry) > > + # Nested containers > + if args.nesting: > + sub = getSubContainers(container_name, args.lxcpath) > + if sub: > + for entry in sub: > + if 'nesting_parent' not in entry: > + entry['nesting_parent'] = [] > + entry['nesting_parent'].insert(0, container_name) > + entry['nesting_real_name'] = entry.get('nesting_real_name', > + entry['name']) > + entry['name'] = "%s -> %s" % (container_name, entry['name']) > + containers += sub > + > +# Deal with json output: > +if 'NESTED' in os.environ: > + print(json.dumps(containers)) > + sys.exit(0) > > # Print the list > ## Standard list with one entry per line > @@ -226,7 +271,12 @@ if args.fancy: > > for container in containers: > for field in args.fancy_format: > - if len(container[field]) > field_maxlength[field]: > + if field == 'name' and 'nesting_real_name' in container: > + fieldlen = len(" " * ((len(container['nesting_parent']) - 1) > + * 4) + " \_ " + > container['nesting_real_name']) > + if fieldlen > field_maxlength[field]: > + field_maxlength[field] = fieldlen > + elif len(container[field]) > field_maxlength[field]: > field_maxlength[field] = len(container[field]) > > # Generate the line format string based on the maximum length and > @@ -250,5 +300,12 @@ if args.fancy: > # Print the entries > for container in sorted(containers, > key=lambda container: container['name']): > - fields = [container[field] for field in args.fancy_format] > + fields = [] > + for field in args.fancy_format: > + if field == 'name' and 'nesting_real_name' in container: > + prefix = " " * ((len(container['nesting_parent']) - 1) * 4) > + fields.append(prefix + " \_ " + > container['nesting_real_name']) > + else: > + fields.append(container[field]) > + > print(line_format.format(fields=fields)) > diff --git a/src/python-lxc/lxc/__init__.py.in > b/src/python-lxc/lxc/__init__.py.in > index e262c23..f1848f2 100644 > --- a/src/python-lxc/lxc/__init__.py.in > +++ b/src/python-lxc/lxc/__init__.py.in > @@ -337,18 +337,9 @@ class Container(_lxc.Container): > Returns the list of IP addresses for the container. > """ > > - if not self.defined or not self.running: > + if not self.running: > return False > > - try: > - os.makedirs("/run/netns") > - except: > - pass > - > - path = tempfile.mktemp(dir="/run/netns") > - > - os.symlink("/proc/%s/ns/net" % self.init_pid, path) > - > ips = [] > > count = 0 > @@ -356,7 +347,8 @@ class Container(_lxc.Container): > if count != 0: > time.sleep(1) > > - base_cmd = ["ip", "netns", "exec", path.split("/")[-1], "ip"] > + base_cmd = ["lxc-attach", "-s", "NETWORK", "-n", self.name, "--", > + "ip"] > > # Get IPv6 > if protocol in ("ipv6", None): > @@ -397,7 +389,6 @@ class Container(_lxc.Container): > > count += 1 > > - os.remove(path) > return ips > > def get_keys(self, key=None): > -- > 1.8.1.2 > > > ------------------------------------------------------------------------------ > Everyone hates slow websites. So do we. > Make your web apps faster with AppDynamics > Download AppDynamics Lite for free today: > http://p.sf.net/sfu/appdyn_d2d_feb > _______________________________________________ > Lxc-devel mailing list > Lxc-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/lxc-devel ------------------------------------------------------------------------------ Everyone hates slow websites. So do we. Make your web apps faster with AppDynamics Download AppDynamics Lite for free today: http://p.sf.net/sfu/appdyn_d2d_feb _______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel