[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libvir] collectd libvirtstats plugin (version 1, for discussion only)



Attached is a plugin allowing collectd to use libvirt to collect CPU, disk and network statistics for domains. There are a few problems with it at the moment, described below.

Firstly just to say that this is a patch against the released collectd 4.2.0. I need to pull out the GIT repository and rebase the patch against that. Any other comments, most welcome!

Usage
-----

With this patch you should be able to collect stats by adding the following to your collectd.conf file:

LoadPlugin libvirtstats

<Plugin libvirtstats>
        Connection "xen:///"
</Plugin>

'collectd' only needs to be running on the host. It uses libvirt to collect stats for each guest, via mechanisms in the hypervisor or host operating system.

Requirements
------------

libvirt >= 0.3.3 and libxml2. The configure file should auto-detect the requirements and configure libvirtstats plugin only if they are available.

Problems
--------

I can't seem to get the ignorelist to do anything at all. It seems like it includes all the domains and devices, no matter what I specify in the configuration file and what the state of IgnoreSelected is set to.

In the types.db, I have set the max for virt_cpu_total to be 256,000,000,000. The max CPU usage for a single CPU is 1 billion nanoseconds per second, but virt_cpu_total is for all CPUs in the system, and there could be (in theory) an unlimited number of CPUs, so an unlimited max. Therefore I have assumed here that max CPUs = 256.

I'm using CSV output, which works, but it seems to report the aggregate counter values instead of the differences. Is that to be expected?

Rich.

--
Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/
Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod
Street, Windsor, Berkshire, SL4 1TE, United Kingdom.  Registered in
England and Wales under Company Registration No. 03798903
Only in collectd-4.2.0-libvirt: aclocal.m4
diff -ur collectd-4.2.0/AUTHORS collectd-4.2.0-libvirt/AUTHORS
--- collectd-4.2.0/AUTHORS	2007-10-27 10:04:58.000000000 +0100
+++ collectd-4.2.0-libvirt/AUTHORS	2007-10-31 10:47:36.000000000 +0000
@@ -60,6 +60,9 @@
 contributed by:
   Luboš Staněk <lubek at users.sourceforge.net>
 
+Libvirt integration by:
+  Richard Jones <rjones redhat com>
+
 collectd is available at:
   <http://collectd.org/>
 
Only in collectd-4.2.0-libvirt: autom4te.cache
Only in collectd-4.2.0-libvirt/bindings: Makefile
Only in collectd-4.2.0-libvirt/bindings: Makefile.in
Only in collectd-4.2.0-libvirt/bindings/perl: blib
Only in collectd-4.2.0-libvirt/bindings/perl/Collectd: Makefile
Only in collectd-4.2.0-libvirt/bindings/perl/Collectd: pm_to_blib
Only in collectd-4.2.0-libvirt/bindings/perl: Makefile
Only in collectd-4.2.0-libvirt/bindings/perl: pm_to_blib
Only in collectd-4.2.0-libvirt: config.log
Only in collectd-4.2.0-libvirt: config.status
Only in collectd-4.2.0-libvirt: configure
diff -ur collectd-4.2.0/configure.in collectd-4.2.0-libvirt/configure.in
--- collectd-4.2.0/configure.in	2007-10-27 10:15:13.000000000 +0100
+++ collectd-4.2.0-libvirt/configure.in	2007-11-01 16:34:36.000000000 +0000
@@ -1598,6 +1598,30 @@
 fi
 AM_CONDITIONAL(BUILD_WITH_LIBNETLINK, test "x$with_libnetlink" = "xyes")
 
+dnl Check for libvirt and libxml2 libraries.
+AC_CHECK_LIB(xml2,xmlXPathEval,
+	     [with_libxml2="yes"],
+	     [with_libxml2="no"])
+
+with_libvirt="no"
+if test "x$with_libxml2" = "xyes"; then
+    AC_CHECK_LIB(virt,virDomainBlockStats,
+		 [with_libvirt="yes"],
+		 [with_libvirt="no (symbol virDomainBlockStats not found)"])
+fi
+dnl Add the right compiler flags and libraries.
+if test "x$with_libvirt" = "xyes"; then
+    PKG_PROG_PKG_CONFIG
+    if test "x$PKG_CONFIG" != "x"; then
+   	BUILD_WITH_LIBVIRTSTATS_CFLAGS="`pkg-config --cflags libvirt` `pkg-config --cflags libxml-2.0`"
+   	BUILD_WITH_LIBVIRTSTATS_LIBS="`pkg-config --libs libvirt` `pkg-config --libs libxml-2.0`"
+	AC_SUBST(BUILD_WITH_LIBVIRTSTATS_CFLAGS)
+	AC_SUBST(BUILD_WITH_LIBVIRTSTATS_LIBS)
+    fi
+fi
+
+dnl End of check for libvirt and libxml2 libraries.
+
 # Check for enabled/disabled features
 #
 
@@ -1859,6 +1883,7 @@
 AC_PLUGIN([iptables],    [$with_libiptc],      [IPTables rule counters])
 AC_PLUGIN([ipvs],        [$plugin_ipvs],       [IPVS connection statistics])
 AC_PLUGIN([irq],         [$plugin_irq],        [IRQ statistics])
+AC_PLUGIN([libvirtstats],[$with_libvirt],      [Virtual machine statistics])
 AC_PLUGIN([load],        [$plugin_load],       [System load])
 AC_PLUGIN([logfile],     [yes],                [File logging plugin])
 AC_PLUGIN([mbmon],       [yes],                [Query mbmond])
@@ -1957,6 +1982,8 @@
     libsensors  . . . . $with_lm_sensors
     libstatgrab . . . . $with_libstatgrab
     libupsclient  . . . $with_libupsclient
+    libvirt . . . . . . $with_libvirt
+    libxml2 . . . . . . $with_libxml2
     libxmms . . . . . . $with_libxmms
 
   Features:
@@ -1985,6 +2012,7 @@
     iptables  . . . . . $enable_iptables
     ipvs  . . . . . . . $enable_ipvs
     irq . . . . . . . . $enable_irq
+    libvirtstats  . . . $enable_libvirtstats
     load  . . . . . . . $enable_load
     logfile . . . . . . $enable_logfile
     mbmon . . . . . . . $enable_mbmon
Only in collectd-4.2.0-libvirt/libltdl: aclocal.m4
Only in collectd-4.2.0-libvirt/libltdl: autom4te.cache
Only in collectd-4.2.0-libvirt/libltdl: config.h
Only in collectd-4.2.0-libvirt/libltdl: config.log
Only in collectd-4.2.0-libvirt/libltdl: config.status
Only in collectd-4.2.0-libvirt/libltdl: configure
Only in collectd-4.2.0-libvirt/libltdl: libltdlc.la
Only in collectd-4.2.0-libvirt/libltdl: .libs
Only in collectd-4.2.0-libvirt/libltdl: libtool
Only in collectd-4.2.0-libvirt/libltdl: ltdl.lo
Only in collectd-4.2.0-libvirt/libltdl: ltdl.o
Only in collectd-4.2.0-libvirt/libltdl: Makefile
Only in collectd-4.2.0-libvirt/libltdl: Makefile.in
Only in collectd-4.2.0-libvirt/libltdl: stamp-h1
Only in collectd-4.2.0-libvirt: libtool
Only in collectd-4.2.0-libvirt: Makefile
Only in collectd-4.2.0-libvirt: Makefile.in
diff -ur collectd-4.2.0/README collectd-4.2.0-libvirt/README
--- collectd-4.2.0/README	2007-10-27 10:09:25.000000000 +0100
+++ collectd-4.2.0-libvirt/README	2007-10-31 17:43:19.000000000 +0000
@@ -80,6 +80,9 @@
     - load
       System load average over the last 1, 5 and 15 minutes.
 
+    - libvirt
+      CPU, disk and network I/O statistics from virtual machines.
+
     - mbmon
       Motherboard sensors: temperature, fanspeed and voltage information,
       using mbmon(1).
@@ -324,6 +327,9 @@
     For compiling on Darwin in general and the `apple_sensors' plugin in
     particular.
 
+  * libvirt (optional)
+    Collect statistics from virtual machines.
+
 
 Configuring / Compiling / Installing
 ------------------------------------
Only in collectd-4.2.0-libvirt/src: apache.la
Only in collectd-4.2.0-libvirt/src: apache_la-apache.lo
Only in collectd-4.2.0-libvirt/src: apcups.la
Only in collectd-4.2.0-libvirt/src: apcups.lo
Only in collectd-4.2.0-libvirt/src: battery.la
Only in collectd-4.2.0-libvirt/src: battery.lo
Only in collectd-4.2.0-libvirt/src: collectd
Only in collectd-4.2.0-libvirt/src: collectd-collectd.o
Only in collectd-4.2.0-libvirt/src: collectd-common.o
Only in collectd-4.2.0-libvirt/src: collectd.conf
Only in collectd-4.2.0-libvirt/src: collectd-configfile.o
Only in collectd-4.2.0-libvirt/src: collectd-nagios
Only in collectd-4.2.0-libvirt/src: collectd-nagios.o
Only in collectd-4.2.0-libvirt/src: collectd-plugin.o
Only in collectd-4.2.0-libvirt/src: collectd-types_list.o
Only in collectd-4.2.0-libvirt/src: collectd-utils_avltree.o
Only in collectd-4.2.0-libvirt/src: collectd-utils_ignorelist.o
Only in collectd-4.2.0-libvirt/src: collectd-utils_llist.o
Only in collectd-4.2.0-libvirt/src: collectd-utils_mount.o
Only in collectd-4.2.0-libvirt/src: config.h
diff -ur collectd-4.2.0/src/config.h.in collectd-4.2.0-libvirt/src/config.h.in
--- collectd-4.2.0/src/config.h.in	2007-10-27 10:18:32.000000000 +0100
+++ collectd-4.2.0-libvirt/src/config.h.in	2007-11-05 13:38:20.000000000 +0000
@@ -418,6 +418,9 @@
 /* Define to 1 if the irq plugin is enabled. */
 #undef HAVE_PLUGIN_IRQ
 
+/* Define to 1 if the libvirtstats plugin is enabled. */
+#undef HAVE_PLUGIN_LIBVIRTSTATS
+
 /* Define to 1 if the load plugin is enabled. */
 #undef HAVE_PLUGIN_LOAD
 
Only in collectd-4.2.0-libvirt/src: cpufreq.la
Only in collectd-4.2.0-libvirt/src: cpufreq.lo
Only in collectd-4.2.0-libvirt/src: cpu.la
Only in collectd-4.2.0-libvirt/src: cpu.lo
Only in collectd-4.2.0-libvirt/src: csv.la
Only in collectd-4.2.0-libvirt/src: csv.lo
Only in collectd-4.2.0-libvirt/src: .deps
Only in collectd-4.2.0-libvirt/src: df.la
Only in collectd-4.2.0-libvirt/src: df.lo
Only in collectd-4.2.0-libvirt/src: disk.la
Only in collectd-4.2.0-libvirt/src: disk.lo
Only in collectd-4.2.0-libvirt/src: email.la
Only in collectd-4.2.0-libvirt/src: email.lo
Only in collectd-4.2.0-libvirt/src: entropy.la
Only in collectd-4.2.0-libvirt/src: entropy.lo
Only in collectd-4.2.0-libvirt/src: exec.la
Only in collectd-4.2.0-libvirt/src: exec.lo
Only in collectd-4.2.0-libvirt/src: hddtemp.la
Only in collectd-4.2.0-libvirt/src: hddtemp.lo
Only in collectd-4.2.0-libvirt/src: interface.la
Only in collectd-4.2.0-libvirt/src: interface.lo
Only in collectd-4.2.0-libvirt/src: irq.la
Only in collectd-4.2.0-libvirt/src: irq.lo
Only in collectd-4.2.0-libvirt/src/liboconfig: liboconfig.la
Only in collectd-4.2.0-libvirt/src/liboconfig: .libs
Only in collectd-4.2.0-libvirt/src/liboconfig: Makefile
Only in collectd-4.2.0-libvirt/src/liboconfig: Makefile.in
Only in collectd-4.2.0-libvirt/src/liboconfig: oconfig.lo
Only in collectd-4.2.0-libvirt/src/liboconfig: parser.lo
Only in collectd-4.2.0-libvirt/src/liboconfig: scanner.lo
Only in collectd-4.2.0-libvirt/src/liboping: liboping.la
Only in collectd-4.2.0-libvirt/src/liboping: liboping.lo
Only in collectd-4.2.0-libvirt/src/liboping: .libs
Only in collectd-4.2.0-libvirt/src/liboping: Makefile
Only in collectd-4.2.0-libvirt/src/liboping: Makefile.in
Only in collectd-4.2.0-libvirt/src: .libs
diff -ur collectd-4.2.0/src/libvirtstats.c collectd-4.2.0-libvirt/src/libvirtstats.c
--- collectd-4.2.0/src/libvirtstats.c	2007-11-05 13:30:45.000000000 +0000
+++ collectd-4.2.0-libvirt/src/libvirtstats.c	2007-11-05 13:46:00.000000000 +0000
@@ -0,0 +1,743 @@
+/**
+ * collectd - src/libvirtstats.c
+ * Copyright (C) 2006,2007  Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the license is applicable.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Richard W.M. Jones <rjones redhat com>
+ **/
+
+#include "collectd.h"
+#include "common.h"
+#include "plugin.h"
+#include "configfile.h"
+#include "utils_ignorelist.h"
+
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#define LIBVIRTSTATS_DEBUG 1
+
+static const char *config_keys[] = {
+    "Connection",
+
+    "RefreshInterval",
+
+    "Domain",
+    "BlockDevice",
+    "InterfaceDevice",
+    "IgnoreSelected",
+    NULL
+};
+#define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
+
+/* Connection. */
+static virConnectPtr conn = 0;
+
+/* Seconds between list refreshes, 0 disables completely. */
+static int interval = 60;
+
+/* List of domains, if specified. */
+static ignorelist_t *il_domains = NULL;
+/* List of block devices, if specified. */
+static ignorelist_t *il_block_devices = NULL;
+/* List of network interface devices, if specified. */
+static ignorelist_t *il_interface_devices = NULL;
+
+static int ignore_device_match (ignorelist_t *,
+                                const char *domname, const char *devpath);
+
+/* Actual list of domains found on last refresh. */
+static virDomainPtr *domains = NULL;
+static int nr_domains = 0;
+
+static void free_domains (void);
+static int add_domain (virDomainPtr dom);
+
+/* Actual list of block devices found on last refresh. */
+struct block_device {
+    virDomainPtr dom;           /* domain */
+    char *path;                 /* name of block device */
+};
+
+static struct block_device *block_devices = NULL;
+static int nr_block_devices = 0;
+
+static void free_block_devices (void);
+static int add_block_device (virDomainPtr dom, const char *path);
+
+/* Actual list of network interfaces found on last refresh. */
+struct interface_device {
+    virDomainPtr dom;           /* domain */
+    char *path;                 /* name of interface device */
+};
+
+static struct interface_device *interface_devices = NULL;
+static int nr_interface_devices = 0;
+
+static void free_interface_devices (void);
+static int add_interface_device (virDomainPtr dom, const char *path);
+
+/* Time that we last refreshed. */
+static time_t last_refresh = (time_t) 0;
+
+static int refresh_lists (void);
+
+/* Submit functions. */
+static void cpu_submit (unsigned long long cpu_time,
+                        time_t t,
+                        const char *domname, const char *type);
+static void vcpu_submit (unsigned long long cpu_time,
+                         time_t t,
+                         const char *domname, int vcpu_nr, const char *type);
+static void disk_submit (long long read, long long write,
+                         time_t t,
+                         const char *domname, const char *devname,
+                         const char *type);
+static void if_submit (long long rx, long long tx,
+                       time_t t,
+                       const char *domname, const char *devname,
+                       const char *type);
+
+/* ERROR(...) macro for virterrors. */
+#define VIRT_ERROR(conn,s) do {                 \
+        virErrorPtr err;                        \
+        err = (conn) ? virConnGetLastError ((conn)) : virGetLastError (); \
+        if (err) ERROR ("%s: %s", (s), err->message);                   \
+    } while(0)
+
+static int
+libvirtstats_init (void)
+{
+    if (virInitialize () == -1)
+        return -1;
+
+    il_domains = ignorelist_create (0);
+    il_block_devices = ignorelist_create (0);
+    il_interface_devices = ignorelist_create (0);
+
+	return 0;
+}
+
+static int
+libvirtstats_config (const char *key, const char *value)
+{
+    if (virInitialize () == -1)
+        return 1;
+
+    if (strcasecmp (key, "Connection") == 0) {
+        if (conn != 0) {
+            ERROR ("Connection may only be given once in config file");
+            return 1;
+        }
+        conn = virConnectOpenReadOnly (value);
+        if (!conn) {
+            VIRT_ERROR (NULL, "connection failed");
+            return 1;
+        }
+        return 0;
+    }
+
+    if (strcasecmp (key, "RefreshInterval") == 0) {
+        char *eptr = NULL;
+        interval = strtol (value, &eptr, 10);
+        if (eptr == NULL || *eptr != '\0') return 1;
+        return 0;
+    }
+
+    if (strcasecmp (key, "Domain") == 0) {
+        if (ignorelist_add (il_domains, value)) return 1;
+        return 0;
+    }
+    if (strcasecmp (key, "BlockDevice") == 0) {
+        if (ignorelist_add (il_block_devices, value)) return 1;
+        return 0;
+    }
+    if (strcasecmp (key, "InterfaceDevice") == 0) {
+        if (ignorelist_add (il_interface_devices, value)) return 1;
+        return 0;
+    }
+
+    if (strcasecmp (key, "IgnoreSelected") == 0) {
+        if (strcasecmp (value, "True") == 0 ||
+            strcasecmp (value, "Yes") == 0 ||
+            strcasecmp (value, "On") == 0)
+        {
+            ignorelist_set_invert (il_domains, 0);
+            ignorelist_set_invert (il_block_devices, 0);
+            ignorelist_set_invert (il_interface_devices, 0);
+        }
+        else
+        {
+            ignorelist_set_invert (il_domains, 1);
+            ignorelist_set_invert (il_block_devices, 1);
+            ignorelist_set_invert (il_interface_devices, 1);
+        }
+    }
+
+    /* Unrecognised option. */
+    return -1;
+}
+
+static int
+libvirtstats_read (void)
+{
+    time_t t;
+    int i;
+
+    if (conn == NULL) {
+        ERROR ("Not connected.  Use Connection in config file to supply connection URI.  For more information see http://libvirt.org/uri.html";);
+        return -1;
+    }
+
+    time (&t);
+
+    /* Need to refresh domain or device lists? */
+    if (last_refresh == (time_t) 0 ||
+        (interval > 0 && last_refresh + interval <= t)) {
+        if (refresh_lists () == -1) return -1;
+        last_refresh = t;
+    }
+
+#if LIBVIRTSTATS_DEBUG
+    for (i = 0; i < nr_domains; ++i)
+        fprintf (stderr, "domain %s\n", virDomainGetName (domains[i]));
+    for (i = 0; i < nr_block_devices; ++i)
+        fprintf  (stderr, "block device %d %s:%s\n",
+                  i, virDomainGetName (block_devices[i].dom),
+                  block_devices[i].path);
+    for (i = 0; i < nr_interface_devices; ++i)
+        fprintf (stderr, "interface device %d %s:%s\n",
+                 i, virDomainGetName (interface_devices[i].dom),
+                 interface_devices[i].path);
+#endif
+
+    /* Get CPU usage, VCPU usage for each domain. */
+    for (i = 0; i < nr_domains; ++i) {
+        const char *name;
+        virDomainInfo info;
+        virVcpuInfoPtr vinfo = NULL;
+        int j;
+
+        name = virDomainGetName (domains[i]);
+        if (name == NULL) continue;
+
+        if (virDomainGetInfo (domains[i], &info) == -1) continue;
+
+        cpu_submit (info.cpuTime, t, name, "virt_cpu_total");
+
+        vinfo = malloc (info.nrVirtCpu * sizeof vinfo[0]);
+        if (vinfo == NULL) {
+            ERROR ("malloc: %s", strerror (errno));
+            continue;
+        }
+
+        if (virDomainGetVcpus (domains[i], vinfo, info.nrVirtCpu,
+                               NULL, 0) == -1) {
+            free (vinfo);
+            continue;
+        }
+
+        for (j = 0; j < info.nrVirtCpu; ++j)
+            vcpu_submit (vinfo[j].cpuTime,
+                         t, name, vinfo[j].number, "virt_vcpu");
+
+        free (vinfo);
+    }
+
+    /* Get block device stats for each domain. */
+    for (i = 0; i < nr_block_devices; ++i) {
+        const char *name;
+        struct _virDomainBlockStats stats;
+
+        name = virDomainGetName (block_devices[i].dom);
+        if (name == NULL) continue;
+
+        if (virDomainBlockStats (block_devices[i].dom, block_devices[i].path,
+                                 &stats, sizeof stats) == -1)
+            continue;
+
+        disk_submit (stats.rd_req, stats.wr_req,
+                     t, name, block_devices[i].path,
+                     "disk_ops");
+        disk_submit (stats.rd_bytes, stats.wr_bytes,
+                     t, name, block_devices[i].path,
+                     "disk_octets");
+    }
+
+    /* Get interface stats for each domain. */
+    for (i = 0; i < nr_interface_devices; ++i) {
+        const char *name;
+        struct _virDomainInterfaceStats stats;
+
+        name = virDomainGetName (interface_devices[i].dom);
+        if (name == NULL) continue;
+
+        if (virDomainInterfaceStats (interface_devices[i].dom,
+                                     interface_devices[i].path,
+                                     &stats, sizeof stats) == -1)
+            continue;
+
+        if_submit (stats.rx_bytes, stats.tx_bytes,
+                   t, name, interface_devices[i].path,
+                   "if_octets");
+        if_submit (stats.rx_packets, stats.tx_packets,
+                   t, name, interface_devices[i].path,
+                   "if_packets");
+        if_submit (stats.rx_errs, stats.tx_errs,
+                   t, name, interface_devices[i].path,
+                   "if_errors");
+        if_submit (stats.rx_drop, stats.tx_drop,
+                   t, name, interface_devices[i].path,
+                   "if_dropped");
+    }
+
+    return 0;
+}
+
+static int
+refresh_lists (void)
+{
+    int n;
+
+#if LIBVIRTSTATS_DEBUG
+    fprintf (stderr, "libvirtstats: refresh_lists called\n");
+#endif
+
+    n = virConnectNumOfDomains (conn);
+    if (n == -1) {
+        VIRT_ERROR (conn, "reading number of domains");
+        return -1;
+    }
+
+    if (n > 0) {
+        int i;
+        int *domids;
+
+        /* Get list of domains. */
+        domids = malloc (sizeof (int) * n);
+        if (domids == 0) {
+            ERROR ("malloc failed: %s", strerror (errno));
+            return -1;
+        }
+
+        n = virConnectListDomains (conn, domids, n);
+        if (n == -1) {
+            VIRT_ERROR (conn, "reading list of domains");
+            free (domids);
+            return -1;
+        }
+
+        free_block_devices ();
+        free_interface_devices ();
+        free_domains ();
+
+        /* Fetch each domain and add it to the list, unless ignore. */
+        for (i = 0; i < n; ++i) {
+            virDomainPtr dom = NULL;
+            const char *name;
+            char *xml = NULL;
+            xmlDocPtr xml_doc = NULL;
+            xmlXPathContextPtr xpath_ctx = NULL;
+            xmlXPathObjectPtr xpath_obj = NULL;
+            int j;
+
+            dom = virDomainLookupByID (conn, domids[i]);
+            if (dom == NULL) {
+                VIRT_ERROR (conn, "virDomainLookupByID");
+                /* Could be that the domain went away -- ignore it anyway. */
+                continue;
+            }
+
+            name = virDomainGetName (dom);
+            if (name == NULL) {
+                VIRT_ERROR (conn, "virDomainGetName");
+                goto cont;
+            }
+
+            if (il_domains && ignorelist_match (il_domains, name) != 0)
+                goto cont;
+
+#if LIBVIRTSTATS_DEBUG
+            fprintf (stderr, "name = %s\n", name);
+#endif
+
+            if (add_domain (dom) == -1) {
+                ERROR ("malloc: %s", strerror (errno));
+                goto cont;
+            }
+
+            /* Get a list of devices for this domain. */
+            xml = virDomainGetXMLDesc (dom, 0);
+            if (!xml) {
+                VIRT_ERROR (conn, "virDomainGetXMLDesc");
+                goto cont;
+            }
+
+            /* Yuck, XML.  Parse out the devices. */
+            xml_doc = xmlReadDoc ((xmlChar *) xml, NULL, NULL, XML_PARSE_NONET);
+            if (xml_doc == NULL) {
+                VIRT_ERROR (conn, "xmlReadDoc");
+                goto cont;
+            }
+
+            xpath_ctx = xmlXPathNewContext (xml_doc);
+
+            /* Block devices. */
+            xpath_obj = xmlXPathEval
+                ((xmlChar *) "/domain/devices/disk/target[ dev]",
+                 xpath_ctx);
+            if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
+                xpath_obj->nodesetval == NULL)
+                goto cont;
+
+            for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
+                xmlNodePtr node;
+                char *path = NULL;
+
+                node = xpath_obj->nodesetval->nodeTab[j];
+#if LIBVIRTSTATS_DEBUG
+                fprintf (stderr, "node = %p\n", node);
+#endif
+                if (!node) continue;
+                path = (char *) xmlGetProp (node, (xmlChar *) "dev");
+#if LIBVIRTSTATS_DEBUG
+                xmlElemDump (stderr, xml_doc, node);
+                fprintf (stderr, "\npath = %s\n", path);
+#endif
+                if (!path) continue;
+
+                if (il_block_devices &&
+                    ignore_device_match (il_block_devices, name, path) != 0)
+                    goto cont2;
+
+                add_block_device (dom, path);
+            cont2:
+                if (path) xmlFree (path);
+            }
+            xmlXPathFreeObject (xpath_obj);
+
+            /* Network interfaces. */
+            xpath_obj = xmlXPathEval
+                ((xmlChar *) "/domain/devices/interface/target[ dev]",
+                 xpath_ctx);
+            if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
+                xpath_obj->nodesetval == NULL)
+                goto cont;
+
+            for (j = 0; j < xpath_obj->nodesetval->nodeNr; ++j) {
+                xmlNodePtr node;
+                char *path = NULL;
+
+                node = xpath_obj->nodesetval->nodeTab[j];
+#if LIBVIRTSTATS_DEBUG
+                fprintf (stderr, "node = %p\n", node);
+#endif
+                if (!node) continue;
+                path = (char *) xmlGetProp (node, (xmlChar *) "dev");
+#if LIBVIRTSTATS_DEBUG
+                xmlElemDump (stderr, xml_doc, node);
+                fprintf (stderr, "\npath = %s\n", path);
+#endif
+                if (!path) continue;
+
+                if (il_interface_devices &&
+                    ignore_device_match (il_interface_devices, name, path) != 0)
+                    goto cont3;
+
+                add_interface_device (dom, path);
+            cont3:
+                if (path) xmlFree (path);
+            }
+
+        cont:
+            if (xpath_obj) xmlXPathFreeObject (xpath_obj);
+            if (xpath_ctx) xmlXPathFreeContext (xpath_ctx);
+            if (xml_doc) xmlFreeDoc (xml_doc);
+            if (xml) free (xml);
+        }
+
+        free (domids);
+    }
+
+#if LIBVIRTSTATS_DEBUG
+    fprintf (stderr, "libvirtstats: refresh_lists finished OK\n");
+#endif
+
+    return 0;
+}
+
+static void
+free_domains ()
+{
+    int i;
+
+    if (domains) {
+        for (i = 0; i < nr_domains; ++i)
+            virDomainFree (domains[i]);
+        free (domains);
+    }
+    domains = NULL;
+    nr_domains = 0;
+}
+
+static int
+add_domain (virDomainPtr dom)
+{
+    virDomainPtr *new_ptr;
+    int new_size = sizeof (domains[0]) * (nr_domains+1);
+
+    if (domains)
+        new_ptr = realloc (domains, new_size);
+    else
+        new_ptr = malloc (new_size);
+
+    if (new_ptr == NULL) return -1;
+    domains = new_ptr;
+    domains[nr_domains] = dom;
+    return nr_domains++;
+}
+
+static void
+free_block_devices ()
+{
+    int i;
+
+    if (block_devices) {
+        for (i = 0; i < nr_block_devices; ++i)
+            free (block_devices[i].path);
+        free (block_devices);
+    }
+    block_devices = NULL;
+    nr_block_devices = 0;
+}
+
+static int
+add_block_device (virDomainPtr dom, const char *path)
+{
+    struct block_device *new_ptr;
+    int new_size = sizeof (block_devices[0]) * (nr_block_devices+1);
+    char *path_copy;
+
+    path_copy = strdup (path);
+    if (!path_copy) return -1;
+
+    if (block_devices)
+        new_ptr = realloc (block_devices, new_size);
+    else
+        new_ptr = malloc (new_size);
+
+    if (new_ptr == NULL) {
+        free (path_copy);
+        return -1;
+    }
+    block_devices = new_ptr;
+    block_devices[nr_block_devices].dom = dom;
+    block_devices[nr_block_devices].path = path_copy;
+    return nr_block_devices++;
+}
+
+static void
+free_interface_devices ()
+{
+    int i;
+
+    if (interface_devices) {
+        for (i = 0; i < nr_interface_devices; ++i)
+            free (interface_devices[i].path);
+        free (interface_devices);
+    }
+    interface_devices = NULL;
+    nr_interface_devices = 0;
+}
+
+static int
+add_interface_device (virDomainPtr dom, const char *path)
+{
+    struct interface_device *new_ptr;
+    int new_size = sizeof (interface_devices[0]) * (nr_interface_devices+1);
+    char *path_copy;
+
+    path_copy = strdup (path);
+    if (!path_copy) return -1;
+
+    if (interface_devices)
+        new_ptr = realloc (interface_devices, new_size);
+    else
+        new_ptr = malloc (new_size);
+
+    if (new_ptr == NULL) {
+        free (path_copy);
+        return -1;
+    }
+    interface_devices = new_ptr;
+    interface_devices[nr_interface_devices].dom = dom;
+    interface_devices[nr_interface_devices].path = path_copy;
+    return nr_interface_devices++;
+}
+
+static int
+ignore_device_match (ignorelist_t *il, const char *domname, const char *devpath)
+{
+    char *name;
+    int n, r;
+
+    n = sizeof (char) * (strlen (domname) + strlen (devpath) + 2);
+    name = malloc (n);
+    if (name == NULL) {
+        ERROR ("malloc: %s", strerror (errno));
+        return 0;
+    }
+    snprintf (name, n, "%s:%s", domname, devpath);
+    r = ignorelist_match (il, name);
+    free (name);
+    return r;
+}
+
+static void
+cpu_submit (unsigned long long cpu_time,
+            time_t t,
+            const char *domname, const char *type)
+{
+    value_t values[1];
+    value_list_t vl = VALUE_LIST_INIT;
+
+    values[0].counter = cpu_time;
+
+    vl.values = values;
+    vl.values_len = 1;
+    vl.time = t;
+    vl.interval = interval_g;
+    strncpy (vl.plugin, "libvirtstats", DATA_MAX_NAME_LEN);
+    strncpy (vl.host, domname, DATA_MAX_NAME_LEN);
+    /*strncpy (vl.type_instance, ?, DATA_MAX_NAME_LEN);*/
+
+    plugin_dispatch_values (type, &vl);
+}
+
+static void
+vcpu_submit (unsigned long long cpu_time,
+             time_t t,
+             const char *domname, int vcpu_nr, const char *type)
+{
+    value_t values[1];
+    value_list_t vl = VALUE_LIST_INIT;
+
+    values[0].counter = cpu_time;
+
+    vl.values = values;
+    vl.values_len = 1;
+    vl.time = t;
+    vl.interval = interval_g;
+    strncpy (vl.plugin, "libvirtstats", DATA_MAX_NAME_LEN);
+    strncpy (vl.host, domname, DATA_MAX_NAME_LEN);
+    snprintf (vl.type_instance, DATA_MAX_NAME_LEN, "%d", vcpu_nr);
+
+    plugin_dispatch_values (type, &vl);
+}
+
+static void
+disk_submit (long long read, long long write,
+             time_t t,
+             const char *domname, const char *devname,
+             const char *type)
+{
+    value_t values[2];
+    value_list_t vl = VALUE_LIST_INIT;
+
+    values[0].counter = read >= 0 ? (unsigned long long) read : 0;
+    values[1].counter = write >= 0 ? (unsigned long long) write : 0;
+
+    vl.values = values;
+    vl.values_len = 2;
+    vl.time = t;
+    vl.interval = interval_g;
+    strncpy (vl.plugin, "libvirtstats", DATA_MAX_NAME_LEN);
+    strncpy (vl.host, domname, DATA_MAX_NAME_LEN);
+    strncpy (vl.type_instance, devname, DATA_MAX_NAME_LEN);
+
+    plugin_dispatch_values (type, &vl);
+}
+
+static void
+if_submit (long long rx, long long tx,
+           time_t t,
+           const char *domname, const char *devname,
+           const char *type)
+{
+    value_t values[2];
+    value_list_t vl = VALUE_LIST_INIT;
+
+    values[0].counter = rx >= 0 ? (unsigned long long) rx : 0;
+    values[1].counter = tx >= 0 ? (unsigned long long) tx : 0;
+
+    vl.values = values;
+    vl.values_len = 2;
+    vl.time = t;
+    vl.interval = interval_g;
+    strncpy (vl.plugin, "libvirtstats", DATA_MAX_NAME_LEN);
+    strncpy (vl.host, domname, DATA_MAX_NAME_LEN);
+    strncpy (vl.type_instance, devname, DATA_MAX_NAME_LEN);
+
+    plugin_dispatch_values (type, &vl);
+}
+
+static int
+libvirtstats_shutdown (void)
+{
+    free_block_devices ();
+    free_interface_devices ();
+    free_domains ();
+
+    ignorelist_free (il_domains);
+    il_domains = NULL;
+    ignorelist_free (il_block_devices);
+    il_block_devices = NULL;
+    ignorelist_free (il_interface_devices);
+    il_interface_devices = NULL;
+
+    if (conn) virConnectClose (conn);
+    conn = NULL;
+
+    return 0;
+}
+
+void
+module_register (void)
+{
+	plugin_register_config ("libvirtstats",
+                            libvirtstats_config,
+                            config_keys, NR_CONFIG_KEYS);
+    plugin_register_init ("libvirtstats", libvirtstats_init);
+	plugin_register_read ("libvirtstats", libvirtstats_read);
+	plugin_register_shutdown ("libvirtstats", libvirtstats_shutdown);
+}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
Only in collectd-4.2.0-libvirt/src: libvirtstats.la
Only in collectd-4.2.0-libvirt/src: libvirtstats_la-libvirtstats.lo
Only in collectd-4.2.0-libvirt/src: libvirtstats.loT
Only in collectd-4.2.0-libvirt/src: load.la
Only in collectd-4.2.0-libvirt/src: load.lo
Only in collectd-4.2.0-libvirt/src: logfile.la
Only in collectd-4.2.0-libvirt/src: logfile.lo
Only in collectd-4.2.0-libvirt/src: Makefile
diff -ur collectd-4.2.0/src/Makefile.am collectd-4.2.0-libvirt/src/Makefile.am
--- collectd-4.2.0/src/Makefile.am	2007-10-27 10:04:59.000000000 +0100
+++ collectd-4.2.0-libvirt/src/Makefile.am	2007-11-05 13:09:01.000000000 +0000
@@ -276,6 +276,16 @@
 collectd_DEPENDENCIES += irq.la
 endif
 
+if BUILD_PLUGIN_LIBVIRTSTATS
+pkglib_LTLIBRARIES += libvirtstats.la
+libvirtstats_la_SOURCES = libvirtstats.c
+libvirtstats_la_CFLAGS = $(BUILD_WITH_LIBVIRTSTATS_CFLAGS) -Wall -Werror
+libvirtstats_la_LIBADD = $(BUILD_WITH_LIBVIRTSTATS_LIBS)
+libvirtstats_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" libvirtstats.la
+collectd_DEPENDENCIES += libvirtstats.la
+endif
+
 if BUILD_PLUGIN_LOAD
 pkglib_LTLIBRARIES += load.la
 load_la_SOURCES = load.c
Only in collectd-4.2.0-libvirt/src: Makefile.in
Only in collectd-4.2.0-libvirt/src: mbmon.la
Only in collectd-4.2.0-libvirt/src: mbmon.lo
Only in collectd-4.2.0-libvirt/src: memcached.la
Only in collectd-4.2.0-libvirt/src: memcached_la-memcached.lo
Only in collectd-4.2.0-libvirt/src: memory.la
Only in collectd-4.2.0-libvirt/src: memory.lo
Only in collectd-4.2.0-libvirt/src: multimeter.la
Only in collectd-4.2.0-libvirt/src: multimeter.lo
Only in collectd-4.2.0-libvirt/src: network.la
Only in collectd-4.2.0-libvirt/src: network.lo
Only in collectd-4.2.0-libvirt/src: nfs.la
Only in collectd-4.2.0-libvirt/src: nfs.lo
Only in collectd-4.2.0-libvirt/src: nginx.la
Only in collectd-4.2.0-libvirt/src: nginx.lo
Only in collectd-4.2.0-libvirt/src: ntpd.la
Only in collectd-4.2.0-libvirt/src: ntpd.lo
Only in collectd-4.2.0-libvirt/src: perl.la
Only in collectd-4.2.0-libvirt/src: perl_la-perl.lo
Only in collectd-4.2.0-libvirt/src: ping.la
Only in collectd-4.2.0-libvirt/src: ping.lo
Only in collectd-4.2.0-libvirt/src: processes.la
Only in collectd-4.2.0-libvirt/src: processes.lo
Only in collectd-4.2.0-libvirt/src: serial.la
Only in collectd-4.2.0-libvirt/src: serial.lo
Only in collectd-4.2.0-libvirt/src: stamp-h1
Only in collectd-4.2.0-libvirt/src: swap.la
Only in collectd-4.2.0-libvirt/src: swap.lo
Only in collectd-4.2.0-libvirt/src: syslog.la
Only in collectd-4.2.0-libvirt/src: syslog.lo
Only in collectd-4.2.0-libvirt/src: tcpconns.la
Only in collectd-4.2.0-libvirt/src: tcpconns.lo
diff -ur collectd-4.2.0/src/types.db collectd-4.2.0-libvirt/src/types.db
--- collectd-4.2.0/src/types.db	2007-10-27 10:04:59.000000000 +0100
+++ collectd-4.2.0-libvirt/src/types.db	2007-11-05 13:34:35.000000000 +0000
@@ -73,6 +73,8 @@
 serial_octets		rx:COUNTER:0:4294967295, tx:COUNTER:0:4294967295
 swap			value:GAUGE:0:1099511627776
 users			users:GAUGE:0:65535
+virt_cpu_total		ns:COUNTER:0:256000000000
+virt_vcpu		ns:COUNTER:0:1000000000
 vs_threads		value:GAUGE:0:65535
 vs_processes		value:GAUGE:0:65535
 vs_memory		value:GAUGE:0:9223372036854775807
Only in collectd-4.2.0-libvirt/src: unixsock.la
Only in collectd-4.2.0-libvirt/src: unixsock_la-unixsock.lo
Only in collectd-4.2.0-libvirt/src: unixsock_la-utils_cmd_putval.lo
Only in collectd-4.2.0-libvirt/src: users.la
Only in collectd-4.2.0-libvirt/src: users.lo
Only in collectd-4.2.0-libvirt/src: utils_cmd_putval.lo
Only in collectd-4.2.0-libvirt/src: vserver.la
Only in collectd-4.2.0-libvirt/src: vserver.lo
Only in collectd-4.2.0-libvirt/src: wireless.la
Only in collectd-4.2.0-libvirt/src: wireless.lo
Only in collectd-4.2.0-libvirt: ylwrap

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]