On Mon, Nov 04, 2013 at 05:35:19PM -0500, Dwight Engen wrote:
> - added list_all_containers() which returns both defined and
>   active containers.
> 
> - allow lxc-info to show more than one container, using regex for the name
> 

Wouldn't it be better to have list_all_containers be similar to
list_(active|running)_containers and allow the caller to choose whether
it wants to get a list of names or a list of lxc_container?

> Signed-off-by: Dwight Engen <dwight.en...@oracle.com>
> ---
>  doc/lxc-info.sgml.in   |  65 ++++++++++++-
>  src/lxc/lxc_info.c     | 257 
> +++++++++++++++++++++++++++++++++++++++++++++----
>  src/lxc/lxccontainer.c |  47 +++++++++
>  src/lxc/lxccontainer.h |   2 +
>  4 files changed, 349 insertions(+), 22 deletions(-)
> 
> diff --git a/doc/lxc-info.sgml.in b/doc/lxc-info.sgml.in
> index 819d5ca..791d780 100644
> --- a/doc/lxc-info.sgml.in
> +++ b/doc/lxc-info.sgml.in
> @@ -47,20 +47,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, 
> Boston, MA 02110-1301 USA
>    <refsynopsisdiv>
>      <cmdsynopsis>
>        <command>lxc-info</command>
> -      <arg choice="req">-n <replaceable>name</replaceable></arg>
> +      <arg choice="opt">-n <replaceable>name</replaceable></arg>
>        <arg choice="opt">-c <replaceable>KEY</replaceable></arg>
>        <arg choice="opt">-s</arg>
>        <arg choice="opt">-p</arg>
>        <arg choice="opt">-i</arg>
>        <arg choice="opt">-t <replaceable>state</replaceable></arg>
> +      <arg choice="opt">-S</arg>
> +      <arg choice="opt">-H</arg>
>      </cmdsynopsis>
>    </refsynopsisdiv>
>  
>    <refsect1>
>      <title>Description</title>
>      <para>
> -      <command>lxc-info</command> queries and shows information about a
> -      container.
> +      <command>lxc-info</command> queries and shows information about
> +      containers.
>      </para>
>    </refsect1>
>  
> @@ -70,11 +72,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, 
> Boston, MA 02110-1301 USA
>  
>        <varlistentry>
>          <term>
> -          <option>-n <replaceable>name</replaceable></option>
> +          <option><optional>-n 
> <replaceable>name</replaceable></optional></option>
>          </term>
>          <listitem>
>            <para>
> -            The container name.
> +            The container name. It is interpreted as a regular expression,
> +            so it is possible to get information on all containers, several
> +            of them or just one. See
> +            <citerefentry>
> +             <refentrytitle><command>regex</command></refentrytitle>
> +          <manvolnum>7</manvolnum>
> +            </citerefentry> for regular expression syntax. If not specified,
> +            <replaceable>name</replaceable> will default to '.*' which
> +            will give information on all containers in
> +            <command>lxcpath</command>.
>            </para>
>          </listitem>
>        </varlistentry>
> @@ -126,6 +137,41 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, 
> Boston, MA 02110-1301 USA
>  
>        <varlistentry>
>          <term>
> +          <option><optional>-S</optional></option>
> +        </term>
> +        <listitem>
> +          <para>
> +            Just print the container's statistics.
> +            Note that for performance reasons the kernel does not account
> +            kernel memory use unless a kernel memory limit is set. If a limit
> +            is not set, <command>lxc-info</command> will display kernel 
> memory
> +            use as 0. A limit can be set by specifying
> +            <programlisting>
> +            lxc.cgroup.memory.kmem.limit_in_bytes = 
> <replaceable>number</replaceable>
> +            </programlisting>
> +            in your container configuration file, see
> +            <citerefentry>
> +              <refentrytitle>lxc.conf</refentrytitle>
> +              <manvolnum>5</manvolnum>
> +            </citerefentry>.
> +          </para>
> +        </listitem>
> +      </varlistentry>
> +
> +      <varlistentry>
> +        <term>
> +          <option><optional>-H</optional></option>
> +        </term>
> +        <listitem>
> +          <para>
> +            Print the container's statistics in raw, non-humanized form. The
> +            default is to print statistics in humanized form.
> +          </para>
> +        </listitem>
> +      </varlistentry>
> +
> +      <varlistentry>
> +        <term>
>            <option><optional>-t 
> <replaceable>state</replaceable></optional></option>
>          </term>
>          <listitem>
> @@ -152,6 +198,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, 
> Boston, MA 02110-1301 USA
>        </varlistentry>
>  
>        <varlistentry>
> +        <term>lxc-info -n 'ubuntu.*'</term>
> +        <listitem>
> +          <para>
> +            Show information for all containers whose name starts with 
> ubuntu.
> +          </para>
> +        </listitem>
> +      </varlistentry>
> +
> +      <varlistentry>
>          <term>lxc-info -n foo -t RUNNING</term>
>          <listitem>
>            <para>
> diff --git a/src/lxc/lxc_info.c b/src/lxc/lxc_info.c
> index aeaf9a8..a05d610 100644
> --- a/src/lxc/lxc_info.c
> +++ b/src/lxc/lxc_info.c
> @@ -25,11 +25,14 @@
>  #include <stdbool.h>
>  #include <stdlib.h>
>  #include <unistd.h>
> +#include <regex.h>
> +#include <limits.h>
>  #include <libgen.h>
>  #include <sys/types.h>
>  
>  #include <lxc/lxc.h>
>  #include <lxc/log.h>
> +#include <lxc/utils.h>
>  #include <lxc/lxccontainer.h>
>  
>  #include "commands.h"
> @@ -38,6 +41,8 @@
>  static bool ips;
>  static bool state;
>  static bool pid;
> +static bool stats;
> +static bool humanize = true;
>  static char *test_state = NULL;
>  static char **key = NULL;
>  static int keys = 0;
> @@ -53,6 +58,8 @@ static int my_parser(struct lxc_arguments* args, int c, 
> char* arg)
>       case 'i': ips = true; break;
>       case 's': state = true; break;
>       case 'p': pid = true; break;
> +     case 'S': stats = true; break;
> +     case 'H': humanize = false; break;
>       case 't': test_state = arg; break;
>       }
>       return 0;
> @@ -63,6 +70,8 @@ static const struct option my_longopts[] = {
>       {"ips", no_argument, 0, 'i'},
>       {"state", no_argument, 0, 's'},
>       {"pid", no_argument, 0, 'p'},
> +     {"stats", no_argument, 0, 'S'},
> +     {"no-humanize", no_argument, 0, 'H'},
>       {"state-is", required_argument, 0, 't'},
>       LXC_COMMON_OPTIONS,
>  };
> @@ -79,33 +88,177 @@ Options :\n\
>    -c, --config=KEY      show configuration variable KEY from running 
> container\n\
>    -i, --ips             shows the IP addresses\n\
>    -p, --pid             shows the process id of the init container\n\
> +  -S, --stats           shows usage stats\n\
> +  -H, --no-humanize     shows stats as raw numbers, not humanized\n\
>    -s, --state           shows the state of the container\n\
>    -t, --state-is=STATE  test if current state is STATE\n\
>                          returns success if it matches, false otherwise\n",
> +     .name     = ".*",
>       .options  = my_longopts,
>       .parser   = my_parser,
>       .checker  = NULL,
>  };
>  
> -int main(int argc, char *argv[])
> +static void str_chomp(char *buf)
>  {
> -     struct lxc_container *c;
> +     char *ch;
>  
> -     int i;
> +     /* remove trailing whitespace from buf */
> +     for(ch = &buf[strlen(buf)-1];
> +         ch >= buf && (*ch == '\t' || *ch == '\n' || *ch == ' ');
> +         ch--)
> +             *ch = '\0';
> +}
>  
> -     if (lxc_arguments_parse(&my_args, argc, argv))
> -             return -1;
> +static void size_humanize(unsigned long long val, char *buf, size_t bufsz)
> +{
> +     if (val > 1 << 30) {
> +             snprintf(buf, bufsz, "%u.%2.2u GiB",
> +                         (int)(val >> 30),
> +                         (int)(val & ((1 << 30) - 1)) / 10737419);
> +     } else if (val > 1 << 20) {
> +             int x = val + 5243;  /* for rounding */
> +             snprintf(buf, bufsz, "%u.%2.2u MiB",
> +                         x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
> +     } else if (val > 1 << 10) {
> +             int x = val + 5;  /* for rounding */
> +             snprintf(buf, bufsz, "%u.%2.2u KiB",
> +                         x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
> +     } else {
> +             snprintf(buf, bufsz, "%u bytes", (int)val);
> +     }
> +}
>  
> -     if (!my_args.log_file)
> -             my_args.log_file = "none";
> +static unsigned long long str_size_humanize(char *iobuf, size_t iobufsz)
> +{
> +     unsigned long long val;
> +     char *end = NULL;
>  
> -     if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
> -                      my_args.progname, my_args.quiet, my_args.lxcpath[0]))
> -             return -1;
> +     val = strtoull(iobuf, &end, 0);
> +     if (humanize) {
> +             if (*end == '\0' || *end == '\n')
> +                     size_humanize(val, iobuf, iobufsz);
> +             else
> +                     *iobuf = '\0';
> +     }
> +     return val;
> +}
> +
> +static void print_net_stats(const char *name, const char *lxcpath)
> +{
> +     int rc,netnr;
> +     unsigned long long rx_bytes = 0, tx_bytes = 0;
> +     char *ifname, *type;
> +     char path[PATH_MAX];
> +     char buf[256];
> +
> +     for(netnr = 0; ;netnr++) {
> +             sprintf(buf, "lxc.network.%d.type", netnr);
> +             type = lxc_cmd_get_config_item(name, buf, lxcpath);
> +             if (!type)
> +                     break;
>  
> -     c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
> -     if (!c)
> +             if (!strcmp(type, "veth")) {
> +                     sprintf(buf, "lxc.network.%d.veth.pair", netnr);
> +             } else {
> +                     sprintf(buf, "lxc.network.%d.link", netnr);
> +             }
> +             free(type);
> +             ifname = lxc_cmd_get_config_item(name, buf, lxcpath);
> +             if (!ifname)
> +                     return;
> +             printf("%-15s %s\n", "Link:", ifname);
> +
> +             /* XXX: tx and rx are reversed from the host vs container
> +              * perspective, print them from the container perspective
> +              */
> +             snprintf(path, sizeof(path), 
> "/sys/class/net/%s/statistics/rx_bytes", ifname);
> +             rc = lxc_read_from_file(path, buf, sizeof(buf));
> +             if (rc > 0) {
> +                     str_chomp(buf);
> +                     rx_bytes = str_size_humanize(buf, sizeof(buf));
> +                     printf("%-15s %s\n", " TX bytes:", buf);
> +             }
> +
> +             snprintf(path, sizeof(path), 
> "/sys/class/net/%s/statistics/tx_bytes", ifname);
> +             rc = lxc_read_from_file(path, buf, sizeof(buf));
> +             if (rc > 0) {
> +                     str_chomp(buf);
> +                     tx_bytes = str_size_humanize(buf, sizeof(buf));
> +                     printf("%-15s %s\n", " RX bytes:", buf);
> +             }
> +
> +             sprintf(buf, "%llu", rx_bytes + tx_bytes);
> +             str_size_humanize(buf, sizeof(buf));
> +             printf("%-15s %s\n", " Total bytes:", buf);
> +             free(ifname);
> +     }
> +}
> +
> +static void print_stats(struct lxc_container *c)
> +{
> +     int i, ret;
> +     char buf[256];
> +
> +     ret = c->get_cgroup_item(c, "cpuacct.usage", buf, sizeof(buf));
> +     if (ret > 0 && ret < sizeof(buf)) {
> +             str_chomp(buf);
> +             if (humanize) {
> +                     float seconds = strtof(buf, NULL) / 1000000000.0;
> +                     printf("%-15s %.2f seconds\n", "CPU use:", seconds);
> +             } else {
> +                     printf("%-15s %s\n", "CPU use:", buf);
> +             }
> +     }
> +
> +     ret = c->get_cgroup_item(c, "blkio.throttle.io_service_bytes", buf, 
> sizeof(buf));
> +     if (ret > 0 && ret < sizeof(buf)) {
> +             char *ch;
> +
> +             /* put ch on last "Total" line */
> +             str_chomp(buf);
> +             for(ch = &buf[strlen(buf)-1]; ch > buf && *ch != '\n'; ch--)
> +                     ;
> +             if (*ch == '\n')
> +                     ch++;
> +
> +             if (strncmp(ch, "Total", 5) == 0) {
> +                     ch += 6;
> +                     memmove(buf, ch, strlen(ch)+1);
> +                     str_size_humanize(buf, sizeof(buf));
> +                     printf("%-15s %s\n", "BlkIO use:", buf);
> +             }
> +     }
> +
> +     static const struct {
> +             const char *name;
> +             const char *file;
> +     } lxstat[] = {
> +             { "Memory use:", "memory.usage_in_bytes" },
> +             { "KMem use:",   "memory.kmem.usage_in_bytes" },
> +             { NULL, NULL },
> +     };
> +
> +     for (i = 0; lxstat[i].name; i++) {
> +             ret = c->get_cgroup_item(c, lxstat[i].file, buf, sizeof(buf));
> +             if (ret > 0 && ret < sizeof(buf)) {
> +                     str_chomp(buf);
> +                     str_size_humanize(buf, sizeof(buf));
> +                     printf("%-15s %s\n", lxstat[i].name, buf);
> +             }
> +     }
> +}
> +
> +static int print_info(const char *name, const char *lxcpath)
> +{
> +     int i;
> +     struct lxc_container *c;
> +
> +     c = lxc_container_new(name, lxcpath);
> +     if (!c) {
> +             fprintf(stderr, "Insufficent privileges to control %s\n", 
> c->name);
>               return -1;
> +     }
>  
>       if (!c->may_control(c)) {
>               fprintf(stderr, "Insufficent privileges to control %s\n", 
> c->name);
> @@ -113,14 +266,16 @@ int main(int argc, char *argv[])
>               return -1;
>       }
>  
> -     if (!state && !pid && !ips && keys <= 0)
> -             state = pid = ips = true;
> +     if (!state && !pid && !ips && !stats && keys <= 0)
> +             state = pid = ips = stats = true;
> +
> +     printf("%-15s %s\n", "Name:", c->name);
>  
>       if (state || test_state) {
>               if (test_state)
>                       return strcmp(c->state(c), test_state) != 0;
>  
> -             printf("state: \t%s\n", c->state(c));
> +             printf("%-15s %s\n", "State:", c->state(c));
>       }
>  
>       if (pid) {
> @@ -128,7 +283,7 @@ int main(int argc, char *argv[])
>  
>               initpid = c->init_pid(c);
>               if (initpid >= 0)
> -                     printf("pid: \t%d\n", initpid);
> +                     printf("%-15s %d\n", "Pid:", initpid);
>       }
>  
>       if (ips) {
> @@ -138,12 +293,17 @@ int main(int argc, char *argv[])
>                       i = 0;
>                       while (addresses[i]) {
>                               address = addresses[i];
> -                             printf("ip: \t%s\n", address);
> +                             printf("%-15s %s\n", "IP:", address);
>                               i++;
>                       }
>               }
>       }
>  
> +     if (stats) {
> +             print_stats(c);
> +             print_net_stats(name, lxcpath);
> +     }
> +
>       for(i = 0; i < keys; i++) {
>               int len = c->get_config_item(c, key[i], NULL, 0);
>  
> @@ -164,3 +324,66 @@ int main(int argc, char *argv[])
>       lxc_container_put(c);
>       return 0;
>  }
> +
> +int main(int argc, char *argv[])
> +{
> +     int rc, i, len, ret = EXIT_FAILURE;
> +     char *regexp;
> +     regex_t preg;
> +     int ct_cnt;
> +     char **ct_name;
> +     bool printed;
> +
> +     if (lxc_arguments_parse(&my_args, argc, argv))
> +             goto err1;
> +
> +     if (!my_args.log_file)
> +             my_args.log_file = "none";
> +
> +     if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
> +                      my_args.progname, my_args.quiet, my_args.lxcpath[0]))
> +             goto err1;
> +
> +     len = strlen(my_args.name) + 3;
> +     regexp = malloc(len + 3);
> +     if (!regexp) {
> +             fprintf(stderr, "failed to allocate memory");
> +             goto err1;
> +     }
> +     rc = snprintf(regexp, len, "^%s$", my_args.name);
> +     if (rc < 0 || rc >= len) {
> +             fprintf(stderr, "Name too long");
> +             goto err2;
> +     }
> +
> +     if (regcomp(&preg, regexp, REG_NOSUB|REG_EXTENDED)) {
> +             fprintf(stderr, "failed to compile the regex '%s'", 
> my_args.name);
> +             goto err2;
> +     }
> +
> +     printed = false;
> +     ct_cnt = list_all_containers(my_args.lxcpath[0], &ct_name);
> +     if (ct_cnt < 0)
> +             goto err3;
> +
> +     for (i = 0; i < ct_cnt; i++) {
> +             if (regexec(&preg, ct_name[i], 0, NULL, 0) == 0)
> +             {
> +                     if (printed)
> +                             printf("\n");
> +                     print_info(ct_name[i], my_args.lxcpath[0]);
> +                     printed = true;
> +             }
> +             free(ct_name[i]);
> +     }
> +     if (ct_name)
> +             free(ct_name);
> +     ret = EXIT_SUCCESS;
> +
> +err3:
> +     regfree(&preg);
> +err2:
> +     free(regexp);
> +err1:
> +     return ret;
> +}
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 89b45ed..f16c032 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -3206,3 +3206,50 @@ free_bad:
>       process_unlock();
>       return -1;
>  }
> +
> +int list_all_containers(const char *lxcpath, char ***names)
> +{
> +     int all_cnt, active_cnt, i, ret;
> +     char **all_name;
> +     char **active_name;
> +
> +     all_cnt = list_defined_containers(lxcpath, &all_name, NULL);
> +     if (all_cnt < 0)
> +             return all_cnt;
> +
> +     active_cnt = list_active_containers(lxcpath, &active_name, NULL);
> +     if (active_cnt < 0) {
> +             ret = active_cnt;
> +             goto free_all;
> +     }
> +
> +     for (i = 0; i < active_cnt; i++) {
> +             if (!array_contains(&all_name, active_name[i], all_cnt)) {
> +                     if (!add_to_array(&all_name, active_name[i], all_cnt)) {
> +                             ret = -1;
> +                             goto free_active;
> +                     }
> +                     all_cnt++;
> +             }
> +             free(active_name[i]);
> +             active_name[i] = NULL;
> +     }
> +     free(active_name);
> +
> +     *names = all_name;
> +     return all_cnt;
> +
> +free_active:
> +     for (i = 0; i < active_cnt; i++) {
> +             if (active_name[i])
> +                     free(active_name[i]);
> +     }
> +     free(active_name);
> +
> +free_all:
> +     for (i = 0; i < all_cnt; i++) {
> +             free(all_name[i]);
> +     }
> +     free(all_name);
> +     return ret;
> +}
> diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
> index 762e1b0..d83202b 100644
> --- a/src/lxc/lxccontainer.h
> +++ b/src/lxc/lxccontainer.h
> @@ -277,6 +277,8 @@ int list_defined_containers(const char *lxcpath, char 
> ***names, struct lxc_conta
>   */
>  int list_active_containers(const char *lxcpath, char ***names, struct 
> lxc_container ***cret);
>  
> +int list_all_containers(const char *lxcpath, char ***names);
> +
>  #if 0
>  char ** lxc_get_valid_keys();
>  char ** lxc_get_valid_values(char *key);
> -- 
> 1.8.3.1
> 
> 
> ------------------------------------------------------------------------------
> November Webinars for C, C++, Fortran Developers
> Accelerate application performance with scalable programming models. Explore
> techniques for threading, error checking, porting, and tuning. Get the most 
> from the latest Intel processors and coprocessors. See abstracts and register
> http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
> _______________________________________________
> Lxc-devel mailing list
> Lxc-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com

Attachment: signature.asc
Description: Digital signature

------------------------------------------------------------------------------
November Webinars for C, C++, Fortran Developers
Accelerate application performance with scalable programming models. Explore
techniques for threading, error checking, porting, and tuning. Get the most 
from the latest Intel processors and coprocessors. See abstracts and register
http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
_______________________________________________
Lxc-devel mailing list
Lxc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lxc-devel

Reply via email to