Quoting Dwight Engen (dwight.en...@oracle.com): > - allow lxc-info to show more than one container, using regex for the name > > Signed-off-by: Dwight Engen <dwight.en...@oracle.com>
Acked-by: Serge E. Hallyn <serge.hal...@ubuntu.com> > --- > doc/lxc-info.sgml.in | 65 ++++++++++++- > src/lxc/lxc_info.c | 257 > +++++++++++++++++++++++++++++++++++++++++++++++---- > 2 files changed, 300 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..ba43f37 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, NULL); > + 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; > +} > -- > 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 ------------------------------------------------------------------------------ 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