This rewrite is mostly compatible with the shell version. --active and -1 still work and behave as they used to.
This adds --running, --stopped and --frozen as state filters. A new "fancy" view is also implemented (can be used with --fancy) and will show containers in a column-based interface with the following fields: - name - state - ipv4 - ipv6 - pid of init Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- .gitignore | 1 - configure.ac | 1 - doc/lxc-ls.sgml.in | 150 ++++++++++++++++++++++----------- src/lxc/Makefile.am | 2 +- src/lxc/lxc-ls | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc-ls.in | 94 --------------------- 6 files changed, 340 insertions(+), 144 deletions(-) create mode 100644 src/lxc/lxc-ls delete mode 100644 src/lxc/lxc-ls.in diff --git a/.gitignore b/.gitignore index d5b07e3..398e4fc 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,6 @@ src/lxc/lxc-freeze src/lxc/lxc-info src/lxc/lxc-init src/lxc/lxc-kill -src/lxc/lxc-ls src/lxc/lxc-monitor src/lxc/lxc-netstat src/lxc/lxc-ps diff --git a/configure.ac b/configure.ac index b6fa365..5f0cc0b 100644 --- a/configure.ac +++ b/configure.ac @@ -257,7 +257,6 @@ AC_CONFIG_FILES([ src/Makefile src/lxc/Makefile src/lxc/lxc-ps - src/lxc/lxc-ls src/lxc/lxc-netstat src/lxc/lxc-checkconfig src/lxc/lxc-setcap diff --git a/doc/lxc-ls.sgml.in b/doc/lxc-ls.sgml.in index f5f6573..138908d 100644 --- a/doc/lxc-ls.sgml.in +++ b/doc/lxc-ls.sgml.in @@ -49,8 +49,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA <refsynopsisdiv> <cmdsynopsis> <command>lxc-ls</command> + <arg choice="opt">-1</arg> <arg choice="opt">--active</arg> - <arg choice="opt">ls option</arg> + <arg choice="opt">--frozen</arg> + <arg choice="opt">--running</arg> + <arg choice="opt">--stopped</arg> + <arg choice="opt">--fancy</arg> + <arg choice="opt">--fancy-format</arg> + <arg choice="opt">filter</arg> </cmdsynopsis> </refsynopsisdiv> @@ -65,77 +71,127 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA <refsect1> <title>Options</title> <variablelist> + <varlistentry> + <term> + <option><optional>-1</optional></option> + </term> + <listitem> + <para> + Show one entry per line. (default when /dev/stdout isn't a tty) + </para> + </listitem> + </varlistentry> <varlistentry> - <term> - <option><optional>--active</optional></option> - </term> - <listitem> - <para> - List active containers. - </para> - </listitem> + <term> + <option><optional>--active</optional></option> + </term> + <listitem> + <para> + List only active containers (same as --frozen --running). + </para> + </listitem> </varlistentry> <varlistentry> - <term> - <option><optional>ls options</optional></option> - </term> - <listitem> - <para> - The option passed to <command>lxc-ls</command> are the - same as the <command>ls</command> command. - </para> - </listitem> + <term> + <option><optional>--frozen</optional></option> + </term> + <listitem> + <para> + List only frozen containers. + </para> + </listitem> </varlistentry> - </variablelist> + <varlistentry> + <term> + <option><optional>--running</optional></option> + </term> + <listitem> + <para> + List only running containers. + </para> + </listitem> + </varlistentry> - </refsect1> + <varlistentry> + <term> + <option><optional>--stopped</optional></option> + </term> + <listitem> + <para> + List only stopped containers. + </para> + </listitem> + </varlistentry> - <refsect1> - <title>Examples</title> - <variablelist> <varlistentry> - <term>lxc-ls -l</term> - <listitem> - <para> - list all the container and their permissions. - </para> - </listitem> + <term> + <option><optional>--fancy</optional></option> + </term> + <listitem> + <para> + Use a fancy, column-based output. + </para> + </listitem> </varlistentry> <varlistentry> - <term>lxc-ls --active -1</term> - <listitem> - <para> - list active containers and display the list in one column. - </para> - </listitem> + <term> + <option><optional>--fancy-format</optional></option> + </term> + <listitem> + <para> + Comma separate list of column to show in the fancy output. + Valid values are: name, state, ipv4, ipv6 and pid + Default is: name,state,ipv4,ipv6 + </para> + </listitem> </varlistentry> + <varlistentry> + <term> + <option><optional>filter</optional></option> + </term> + <listitem> + <para> + The filter passed to <command>lxc-ls</command> will be + applied to the container name. The format is a regular expression. + </para> + </listitem> + </varlistentry> </variablelist> </refsect1> <refsect1> - <title>See Also</title> - - <simpara> - <citerefentry> - <refentrytitle>ls</refentrytitle> - <manvolnum>1</manvolnum> - </citerefentry>, - </simpara> + <title>Examples</title> + <variablelist> + <varlistentry> + <term>lxc-ls --fancy</term> + <listitem> + <para> + list all the containers, listing one per line along with its + name, state, ipv4 and ipv6 addresses. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>lxc-ls --active -1</term> + <listitem> + <para> + list active containers and display the list in one column. + </para> + </listitem> + </varlistentry> + </variablelist> </refsect1> - &seealso; - <refsect1> <title>Author</title> - <para>Daniel Lezcano <email>daniel.lezc...@free.fr</email></para> + <para>Stéphane Graber <email>stgra...@ubuntu.com</email></para> </refsect1> - </refentry> <!-- Keep this comment at the end of the file diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 7d86ad6..9219ba6 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -87,7 +87,6 @@ liblxc_so_LDADD = -lutil $(CAP_LIBS) $(APPARMOR_LIBS) $(SECCOMP_LIBS) -lrt bin_SCRIPTS = \ lxc-ps \ lxc-netstat \ - lxc-ls \ lxc-checkconfig \ lxc-setcap \ lxc-setuid \ @@ -98,6 +97,7 @@ bin_SCRIPTS = \ lxc-destroy if ENABLE_PYTHON + bin_SCRIPTS += lxc-ls bin_SCRIPTS += lxc-start-ephemeral endif diff --git a/src/lxc/lxc-ls b/src/lxc/lxc-ls new file mode 100644 index 0000000..8a1d1ed --- /dev/null +++ b/src/lxc/lxc-ls @@ -0,0 +1,236 @@ +#!/usr/bin/python3 +# +# lxc-ls: List containers +# +# This python implementation is based on the work done in the original +# shell implementation done by Serge Hallyn in Ubuntu (and other contributors) +# +# (C) Copyright Canonical Ltd. 2012 +# +# Authors: +# Stéphane Graber <stgra...@ubuntu.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# NOTE: To remove once the API is stabilized +import warnings +warnings.filterwarnings("ignore", "The python-lxc API isn't yet stable") + +import argparse +import gettext +import lxc +import re +import sys + +_ = gettext.gettext +gettext.textdomain("lxc-ls") + + +# Functions used later on +def batch(iterable, cols=1): + import math + + length = len(iterable) + lines = math.ceil(length / cols) + + for line in range(lines): + fields = [] + for col in range(cols): + index = line + (col * lines) + if index < length: + fields.append(iterable[index]) + yield fields + + +def getTerminalSize(): + import os + env = os.environ + + def ioctl_GWINSZ(fd): + try: + import fcntl + import termios + import struct + cr = struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, + '1234')) + return cr + except: + return + + cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) + if not cr: + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + cr = ioctl_GWINSZ(fd) + os.close(fd) + except: + pass + + if not cr: + cr = (env.get('LINES', 25), env.get('COLUMNS', 80)) + + return int(cr[1]), int(cr[0]) + +# Begin parsing the command line +parser = argparse.ArgumentParser(description=_("LXC: List containers"), + formatter_class=argparse.RawTextHelpFormatter) + +parser.add_argument("-1", dest="one", action="store_true", + help=_("list one container per line (default when piped)")) + +parser.add_argument("--active", action="store_true", + help=_("list only active containers " + "(same as --running --frozen)")) + +parser.add_argument("--frozen", dest="state", action="append_const", + const="FROZEN", help=_("list only frozen containers")) + +parser.add_argument("--running", dest="state", action="append_const", + const="RUNNING", help=_("list only running containers")) + +parser.add_argument("--stopped", dest="state", action="append_const", + const="STOPPED", help=_("list only stopped containers")) + +parser.add_argument("--fancy", action="store_true", + help=_("use fancy output")) + +parser.add_argument("--fancy-format", type=str, default="name,state,ipv4,ipv6", + help=_("comma separated list of fields to show")) + +parser.add_argument("filter", metavar='FILTER', type=str, nargs="?", + help=_("regexp to be applied on the container list")) + +args = parser.parse_args() + +# --active is the same as --running --frozen +if args.active: + if not args.state: + args.state = [] + args.state += ["RUNNING", "FROZEN"] + +# If the output is piped, default to --one +if not sys.stdout.isatty(): + args.one = True + +# Turn args.fancy_format into a list +args.fancy_format = args.fancy_format.strip().split(",") + +# List of containers, stored as dictionaries +containers = [] +for container in lxc.list_containers(as_object=True): + # Filter by status + if args.state and container.state not in args.state: + continue + + # Apply filter + if args.filter and not re.match(args.filter, container.name): + continue + + entry = {} + entry['name'] = container.name + + # Nothing more is needed if we're not printing some fancy output + if not args.fancy: + containers.append(entry) + continue + + # Some extra field we may want + if 'state' in args.fancy_format: + entry['state'] = container.state + if 'pid' in args.fancy_format: + 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: + entry[protocol] = "-" + ips = container.get_ips(protocol=protocol, timeout=1) + if ips: + entry[protocol] = ", ".join(ips) + + containers.append(entry) + + +# Print the list +## Standard list with one entry per line +if not args.fancy and args.one: + for container in sorted(containers, + key=lambda container: container['name']): + print(container['name']) + sys.exit(0) + +## Standard list with multiple entries per line +if not args.fancy and not args.one: + # Get the longest name and extra simple list + field_maxlength = 0 + container_names = [] + for container in containers: + if len(container['name']) > field_maxlength: + field_maxlength = len(container['name']) + container_names.append(container['name']) + + # Figure out how many we can put per line + width = getTerminalSize()[0] + + entries = int(width / (field_maxlength + 2)) + if entries == 0: + entries = 1 + + for line in batch(sorted(container_names), entries): + line_format = "" + for index in range(len(line)): + line_format += "{line[%s]:%s}" % (index, field_maxlength + 2) + + print(line_format.format(line=line)) + +## Fancy listing +if args.fancy: + field_maxlength = {} + + # Get the maximum length per field + for field in args.fancy_format: + field_maxlength[field] = len(field) + + for container in containers: + for field in args.fancy_format: + if len(container[field]) > field_maxlength[field]: + field_maxlength[field] = len(container[field]) + + # Generate the line format string based on the maximum length and + # a 2 character padding + line_format = "" + index = 0 + for field in args.fancy_format: + line_format += "{fields[%s]:%s}" % (index, field_maxlength[field] + 2) + index += 1 + + # Get the line length minus the padding of the last field + line_length = -2 + for field in field_maxlength: + line_length += field_maxlength[field] + 2 + + # Print header + print(line_format.format(fields=[header.upper() + for header in args.fancy_format])) + print("-" * line_length) + + # Print the entries + for container in sorted(containers, + key=lambda container: container['name']): + fields = [container[field] for field in args.fancy_format] + print(line_format.format(fields=fields)) diff --git a/src/lxc/lxc-ls.in b/src/lxc/lxc-ls.in deleted file mode 100644 index f26572d..0000000 --- a/src/lxc/lxc-ls.in +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/bash - -# -# lxc: linux Container library - -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. - -# This library 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 -# Lesser General Public License for more details. - -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -lxc_path=@LXCPATH@ - -usage() -{ - echo "usage: $(basename $0) [--active] [--] [LS_OPTIONS...]" >&2 -} - -help() { - usage - echo >&2 - echo "List containers existing on the system." >&2 - echo >&2 - echo " --active list active containers" >&2 - echo " LS_OPTIONS ls command options (see \`ls --help')" >&2 -} - -get_parent_cgroup() -{ - local hierarchies hierarchy fields subsystems init_cgroup mountpoint - - parent_cgroup="" - - # Obtain a list of hierarchies that contain one or more subsystems - hierarchies=$(tail -n +2 /proc/cgroups | cut -f 2) - - # Iterate through the list until a suitable hierarchy is found - for hierarchy in $hierarchies; do - # Obtain information about the init process in the hierarchy - fields=$(grep -E "^$hierarchy:" /proc/1/cgroup | head -n 1) - if [ -z "$fields" ]; then continue; fi - fields=${fields#*:} - - # Get a comma-separated list of the hierarchy's subsystems - subsystems=${fields%:*} - - # Get the cgroup of the init process in the hierarchy - init_cgroup=${fields#*:} - - # Get the filesystem mountpoint of the hierarchy - mountpoint=$(grep -E "^[^ ]+ [^ ]+ cgroup ([^ ]+,)?$subsystems(,[^ ]+)? " /proc/self/mounts | cut -d ' ' -f 2) - if [ -z "$mountpoint" ]; then continue; fi - - # Return the absolute path to the containers' parent cgroup - # (do not append '/lxc' if the hierarchy contains the 'ns' subsystem) - if [[ ",$subsystems," == *,ns,* ]]; then - parent_cgroup="${mountpoint}${init_cgroup%/}" - else - parent_cgroup="${mountpoint}${init_cgroup%/}/lxc" - fi - break - done -} - -directory=$(readlink -f "$lxc_path") - -for i in "$@"; do - case $i in - --help) - help; exit;; - --active) - get_parent_cgroup; directory="$parent_cgroup"; shift;; - --) - shift; break;; - *) - break;; - esac -done - -containers="" -if [ ! -z "$directory" ]; then - containers=$(find $directory -mindepth 1 -maxdepth 1 -type d -printf "%f\n" 2>/dev/null) -fi - -cd "$directory" -ls -d $@ -- $containers -- 1.8.0
signature.asc
Description: OpenPGP digital signature
------------------------------------------------------------------------------ Monitor your physical, virtual and cloud infrastructure from a single web console. Get in-depth insight into apps, servers, databases, vmware, SAP, cloud infrastructure, etc. Download 30-day Free Trial. Pricing starts from $795 for 25 servers or applications! http://p.sf.net/sfu/zoho_dev2dev_nov
_______________________________________________ Lxc-devel mailing list Lxc-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lxc-devel