<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>
<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>
<simpara>
<citerefentry>
- <refentrytitle>ls</refentrytitle>
- <manvolnum>1</manvolnum>
+ <refentrytitle>ls</refentrytitle>
+ <manvolnum>1</manvolnum>
</citerefentry>,
</simpara>
- </refsect1>
+ <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>
- &seealso;
+ <varlistentry>
+ <term>lxc-ls --active -1</term>
+ <listitem>
+ <para>
+ list active containers and display the list in one column.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
<refsect1>
<title>Author</title>
- <para>Daniel Lezcano <email>daniel.lezcano@free.fr</email></para>
+ <para>Stéphane Graber <email>stgraber@ubuntu.com</email></para>
</refsect1>
-
</refentry>
<!-- Keep this comment at the end of the file
--- /dev/null
+#!/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 <stgraber@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))
+++ /dev/null
-#!/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