changeset 7:8339ab15527d

Add running/stopped containers global statistics and refactor some things
author Louis Opter <louis@dotcloud.com>
date Sat, 01 Jan 2011 17:46:40 +0100
parents e2b88f50e136
children fe254ba0818d
files CMakeLists.txt _lxcstats.h container.c globals.c lxcstats.h open.c tests/CMakeLists.txt tests/container_count.c tests/open.c tests/span_containers.c utils.c
diffstat 11 files changed, 150 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Sat Jan 01 16:18:17 2011 +0100
+++ b/CMakeLists.txt	Sat Jan 01 17:46:40 2011 +0100
@@ -40,6 +40,7 @@
     compat/strlcat.c
     close.c
     container.c
+    globals.c
     open.c
     utils.c
     ${PROBES_SRC}
--- a/_lxcstats.h	Sat Jan 01 16:18:17 2011 +0100
+++ b/_lxcstats.h	Sat Jan 01 17:46:40 2011 +0100
@@ -6,6 +6,8 @@
 
 # define NSEC_PER_SEC   1000000000L
 
+# define LXC_DIR        "/var/lib/lxc/"
+
 # define ARRAY_SIZE(a)  (sizeof((a)) / sizeof((a)[0]))
 
 struct      dirent;
@@ -14,14 +16,17 @@
  * Store all informations needed to get statistics from a cgroup
  * hierarchy.
  */
-struct      _lxcst_controller {
-    char    *cgroup_dir; /**< Mount point of the cgroup hierarchy. */
+struct          _lxcst_controller {
+    char        *cgroup_dir;    /**< Mount point of the cgroup hierarchy.   */
+    const char  *lxc_dir;       /**< LXC configuration directory (LXC_DIR). */
 };
 
+extern struct lxcst_globals _lxcst_globals;
+
 /**
  * Allocate a new lxcst structure for the given container.
  */
-struct lxcst    *_lxcst_container_new(struct _lxcst_controller *, const char *);
+struct lxcst    *_lxcst_container_new(const struct _lxcst_controller *, const char *);
 
 /**
  * Free a lxcst structure.
@@ -29,19 +34,26 @@
 void            _lxcst_container_delete(struct lxcst *);
 
 /**
+ * Get the total number of LXC containers on this machine.
+ */
+int             _lxcst_container_count(const struct _lxcst_controller *ct);
+
+/**
  * Get statistics on a container.
  */
 int             _lxcst_container_read_infos(struct lxcst *);
 
+/**
+ * Reset the global statistics structure.
+ */
+void            _lxcst_globals_reset(void);
+
 char            *_lxcst_join_path(char *, size_t , const char *, const char *);
 
 /**
- * Used to select only directories with scandir. We can't directly use it with
- * scandir because we need the cgroup_dir.
- *
- * @return true if the given directory entry is a directory.
+ * @return true if the given path is a directory.
  */
-int             _lxcst_isdir(const struct _lxcst_controller *, const struct dirent *);
+int             _lxcst_isdir(const char *);
 
 /**
  * Allocate a buffer and read an entire file in it.
--- a/container.c	Sat Jan 01 16:18:17 2011 +0100
+++ b/container.c	Sat Jan 01 17:46:40 2011 +0100
@@ -18,7 +18,7 @@
 }
 
 struct lxcst *
-_lxcst_container_new(struct _lxcst_controller *ct, const char *name)
+_lxcst_container_new(const struct _lxcst_controller *ct, const char *name)
 {
     char            buf[256];
     struct lxcst    *c;
@@ -56,6 +56,32 @@
     }
 }
 
+/*
+ * Should be equivalent to the number of directories found under /var/lib/lxc/
+ */
+int
+_lxcst_container_count(const struct _lxcst_controller *ct)
+{
+    int             n;
+    struct dirent   **c_vec;
+    int             count;
+    char            buf[PATH_MAX];
+
+    n = scandir(ct->lxc_dir, &c_vec, &_lxcst_unselect_current_and_parent, NULL);
+    if (n != -1) {
+        count = n;
+        while (n--) {
+            if (!_lxcst_isdir(_lxcst_join_path(buf, sizeof(buf), ct->lxc_dir, c_vec[n]->d_name)))
+                --count;
+            free(c_vec[n]);
+        }
+        free(c_vec);
+        return (count);
+    }
+
+    return (-1);
+}
+
 int
 _lxcst_container_read_infos(struct lxcst *c)
 {
@@ -76,16 +102,20 @@
     int             n;
     struct dirent   **c_vec;
     struct lxcst    *c;
+    char            buf[PATH_MAX];
 
     assert(hdl);
     assert(hdl->cgroup_dir);
     assert(cb);
 
+    _lxcst_globals_reset();
+
     n = scandir(hdl->cgroup_dir, &c_vec, &_lxcst_unselect_current_and_parent, NULL);
     if (n > 0) {
         while (n--) {
-            if (_lxcst_isdir(hdl, c_vec[n])) {
+            if (_lxcst_isdir(_lxcst_join_path(buf, sizeof(buf), hdl->cgroup_dir, c_vec[n]->d_name))) {
                 c = _lxcst_container_new(hdl, c_vec[n]->d_name);
+                _lxcst_globals.running_containers++;
                 if (c && _lxcst_container_read_infos(c) == 0
                     && cb(ctx, c)) {
                     errno = EINTR;
@@ -99,6 +129,14 @@
         return (-1);
     }
 
+    n = _lxcst_container_count(hdl);
+    if (n == -1) {
+        warn("can't get the total number of containers");
+        return (-1);
+    }
+
+    _lxcst_globals.stopped_containers = n - _lxcst_globals.running_containers;
+
     return (0);
 
 abort_by_cb:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/globals.c	Sat Jan 01 17:46:40 2011 +0100
@@ -0,0 +1,22 @@
+#include <sys/types.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include "lxcstats.h"
+#include "_lxcstats.h"
+
+struct lxcst_globals _lxcst_globals = { 0, 0 };
+
+void
+_lxcst_globals_reset(void)
+{
+    memset(&_lxcst_globals, 0, sizeof(_lxcst_globals));
+}
+
+void
+lxcst_globals_statistics(struct lxcst_globals *sb)
+{
+    assert(sb);
+    memcpy(sb, &_lxcst_globals, sizeof(*sb));
+}
--- a/lxcstats.h	Sat Jan 01 16:18:17 2011 +0100
+++ b/lxcstats.h	Sat Jan 01 17:46:40 2011 +0100
@@ -27,8 +27,8 @@
  * Note: see how lxc-info gets these infos.
  */
 struct          lxcst_globals {
-    uint32_t    running_containers;
-    uint32_t    stopped_containers;
+    uint16_t    running_containers;
+    uint16_t    stopped_containers;
 };
 
 /**
@@ -51,7 +51,10 @@
 int             lxcst_close(lxcst_handle *hdl);
 
 /**
- * @brief Collect statistic on all containers.
+ * @brief Collect statistics on all containers.
+ *
+ * Walk the cgroup pseudo filesystem and get statistics for all found
+ * containers. Also refresh the global statistics struture.
  *
  * @param [in] hdl The pointer returned by lxcst_handle.
  * @param [in] cb A function pointer to a callback which takes a pointer to an
@@ -61,7 +64,20 @@
  * lxcst_span_containers stops and return with -1 with errno set to EINTR.
  *
  * @return 0 on success, -1 on error with errno set.
+ *
+ * @see lxcst_globals_statistics
+ * @see struct lxcst
  */
 int             lxcst_span_containers(lxcst_handle *hdl, int (*cb)(void *, const struct lxcst *), void *ctx);
 
+/**
+ * @brief Get a copy of the global LXC statistics object.
+ *
+ * @param [out] sb A pointer to a struct lxcst_globals.
+ *
+ * @see struct lxcst_globals
+ * @see lxcst_span_containers
+ */
+void            lxcst_globals_statistics(struct lxcst_globals *sb);
+
 #endif
--- a/open.c	Sat Jan 01 16:18:17 2011 +0100
+++ b/open.c	Sat Jan 01 17:46:40 2011 +0100
@@ -48,6 +48,8 @@
     if (!c->cgroup_dir)
         goto free_controller;
 
+    c->lxc_dir = LXC_DIR;
+
     return (c);
 
 free_controller:
--- a/tests/CMakeLists.txt	Sat Jan 01 16:18:17 2011 +0100
+++ b/tests/CMakeLists.txt	Sat Jan 01 17:46:40 2011 +0100
@@ -11,6 +11,7 @@
 
 SET(TESTS
     close
+    container_count
     open
     read_file
     read_big_file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/container_count.c	Sat Jan 01 17:46:40 2011 +0100
@@ -0,0 +1,30 @@
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lxcstats.h"
+#include "_lxcstats.h"
+
+int
+main(int argc, char *argv[])
+{
+    lxcst_handle    *hdl;
+    int             count;
+
+    hdl = lxcst_open();
+    if (!hdl)
+        err(EXIT_FAILURE, "lxcst_open failed");
+
+    count = _lxcst_container_count(hdl);
+    if (count == -1)
+        err(EXIT_FAILURE, "_lxcst_container_count failed");
+
+    printf("%s: %d containers.\n", *argv, count);
+
+    lxcst_close(hdl);
+
+    return (EXIT_SUCCESS);
+    (void)argc;
+}
--- a/tests/open.c	Sat Jan 01 16:18:17 2011 +0100
+++ b/tests/open.c	Sat Jan 01 17:46:40 2011 +0100
@@ -12,8 +12,9 @@
 
     hdl = lxcst_open();
 
-    if (hdl) {
-        printf("%s: mnt_dir=%s.\n", *argv, hdl->cgroup_dir);
+    if (hdl && hdl->cgroup_dir && hdl->lxc_dir) {
+        printf("%s: cgroup_dir=%s.\n", *argv, hdl->cgroup_dir);
+        printf("%s: lxc_dir=%s.\n", *argv, hdl->lxc_dir);
         return (EXIT_SUCCESS);
     }
 
--- a/tests/span_containers.c	Sat Jan 01 16:18:17 2011 +0100
+++ b/tests/span_containers.c	Sat Jan 01 17:46:40 2011 +0100
@@ -23,7 +23,8 @@
 int
 main(int argc, char *argv[])
 {
-    lxcst_handle   *hdl;
+    lxcst_handle            *hdl;
+    struct lxcst_globals    globals;
 
     hdl = lxcst_open();
     if (!hdl)
@@ -35,6 +36,13 @@
 
     printf("%s: spanned %d containers.\n", *argv, n);
 
+    lxcst_globals_statistics(&globals);
+
+    if (globals.running_containers != n)
+        errx(EXIT_FAILURE, "running_containers != spanned containers");
+
+    printf("%s: %d running containers, %d stopped containers.\n", *argv, globals.running_containers, globals.stopped_containers);
+
     return (EXIT_SUCCESS);
     (void)argc;
 }
--- a/utils.c	Sat Jan 01 16:18:17 2011 +0100
+++ b/utils.c	Sat Jan 01 17:46:40 2011 +0100
@@ -29,15 +29,12 @@
 }
 
 int
-_lxcst_isdir(const struct _lxcst_controller *hdl, const struct dirent *d)
+_lxcst_isdir(const char *path)
 {
     struct stat sb;
-    char        buf[PATH_MAX];
 
-    _lxcst_join_path(buf, sizeof(buf), hdl->cgroup_dir, d->d_name);
-
-    if (stat(buf, &sb) == -1) {
-        warn("can't stat file: %s", buf);
+    if (stat(path, &sb) == -1) {
+        warn("can't stat path: %s", path);
         return (0);
     }