Code

facter plugin: Added a plugin collecting local facter values.
authorSebastian Harl <sh@tokkee.org>
Thu, 4 Dec 2014 19:55:00 +0000 (20:55 +0100)
committerSebastian Harl <sh@tokkee.org>
Thu, 4 Dec 2014 19:55:00 +0000 (20:55 +0100)
The plugin uses libfacter from the cfacter project. libfacter is a C++
library, so the plugin is implemented in C++ as well using a small shim to
talk to SysDB.

configure.ac
src/Makefile.am
src/plugins/backend/facter.cc [new file with mode: 0644]

index 10c18c9add8aa80b8e2ff60fb132958722242d50..088a4b59fc994ad313dbd9540b1fc70901808b6d 100644 (file)
@@ -132,6 +132,16 @@ if test "x$enable_standards" = "xyes"; then
        done
 fi
 
+dnl We need C++11 for facter.
+AC_MSG_CHECKING([whether $CXX accepts -std=c++11])
+if test_cxx_flags -std=c++11; then
+       CXXFLAGS="$CXXFLAGS -std=c++11"
+       AC_MSG_RESULT([yes])
+else
+       # Oh well, the header check will determine if it works anyway.
+       AC_MSG_RESULT([no])
+fi
+
 dnl Hardening (see e.g. http://wiki.debian.org/Hardening for a motivation).
 AC_DEFINE([_FORTIFY_SOURCE], 2,
                [Define to enable protection against static sized buffer overflows.])
@@ -454,6 +464,37 @@ AC_SUBST([READLINE_LIBS])
 AC_SUBST([READLINE_CFLAGS])
 AM_CONDITIONAL([BUILD_CLIENT], test "x$readline_support" != "no")
 
+AC_LANG_PUSH(C++)
+AC_ARG_WITH([libfacter],
+               [AS_HELP_STRING([--with-libfacter], [libfacter support (default: auto)])],
+               [with_libfacter="$withval"],
+               [with_libfacter="yes"])
+if test "x$with_libfacter" = "xyes" || test "x$with_libfacter" = "xauto"; then
+       AC_CHECK_HEADERS([facter/facts/collection.hpp],
+                       [have_libfacter="yes"],
+                       [have_libfacter="no (facter/facts/collection.hpp not found)"])
+else if test "x$with_libfacter" = "xno"; then
+       have_libfacter="$with_libfacter (disabled on command-line)"
+else
+       AC_MSG_ERROR([Invalid value for option --with-libfacter=$with_libfacter (expected "yes", "no", or "auto")])
+fi; fi
+if test "x$have_libfacter" = "xyes"; then
+       AC_MSG_CHECKING([for facter::facts::collection in -lfacter])
+       AC_LINK_IFELSE(
+                       [AC_LANG_PROGRAM(
+                               [[[ #include <facter/facts/collection.hpp> ]]],
+                               [[[
+                                       facter::facts::collection facts;
+                                       facts.add_default_facts();
+                               ]]]
+                       )],
+                       [TEST_LIBS=$TEST_LIBS -lfacter],
+                       [have_libfacter="yes"],
+                       [have_libfacter="no (libfacter not found)"])
+       AC_MSG_RESULT([$have_libfacter])
+fi
+AC_LANG_POP(C++)
+
 AC_ARG_WITH([librrd],
                [AS_HELP_STRING([--with-librrd], [librrd support (default: auto)])],
                [with_librrd="$withval"],
@@ -500,6 +541,10 @@ fi
 AM_CONDITIONAL([INTEGRATION_TESTING], test "x$integration_tests" = "xyes")
 
 dnl Plugin checks.
+facter_default=$have_libfacter
+if test "x$facter_default" != "xyes"; then
+       facter_default="no (requires libfacter)"
+fi
 puppet_storeconfigs_default=$with_libdbi
 if test "x$puppet_storeconfigs_default" != "xyes"; then
        puppet_storeconfigs_default="no (requires libdbi)"
@@ -515,6 +560,8 @@ Backends:])
 AC_SDB_PLUGIN_INIT
 AC_SDB_PLUGIN([collectd-unixsock], [yes],
                [backend accessing the system statistics collection daemon])
+AC_SDB_PLUGIN([facter], [$facter_default],
+               [backend retrieving local facter facts])
 AC_SDB_PLUGIN([mk-livestatus], [yes],
                [backend accessing Nagios/Icinga/Shinken using MK Livestatus])
 AC_SDB_PLUGIN([puppet-storeconfigs], [$puppet_storeconfigs_default],
@@ -573,6 +620,7 @@ AC_MSG_RESULT([    librrd: . . . . . . . . . . $have_librrd])
 AC_MSG_RESULT()
 AC_MSG_RESULT([  Backends:])
 AC_MSG_RESULT([    collectd::unixsock: . . . . $enable_collectd_unixsock])
+AC_MSG_RESULT([    facter  . . . . . . . . . . $enable_facter])
 AC_MSG_RESULT([    mk-livestatus:  . . . . . . $enable_mk_livestatus])
 AC_MSG_RESULT([    puppet::storeconfigs: . . . $enable_puppet_storeconfigs])
 AC_MSG_RESULT()
index 1583217d9d79c8ca0c61827be20daf6449922da6..3472b6f527ed55068670db2cd99069e2f40ef0c7 100644 (file)
@@ -171,6 +171,14 @@ sysdbd_LDADD += -dlopen plugins/backend/collectd/unixsock.la
 sysdbd_DEPENDENCIES += plugins/backend/collectd/unixsock.la
 endif
 
+if BUILD_PLUGIN_FACTER
+pkgbackendlib_LTLIBRARIES += plugins/backend/facter.la
+plugins_backend_facter_la_SOURCES = plugins/backend/facter.cc
+plugins_backend_facter_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version -lfacter
+sysdbd_LDADD += -dlopen plugins/backend/facter.la
+sysdbd_DEPENDENCIES += plugins/backend/facter.la
+endif
+
 if BUILD_PLUGIN_MKLIVESTATUS
 pkgbackendlib_LTLIBRARIES += plugins/backend/mk-livestatus.la
 plugins_backend_mk_livestatus_la_SOURCES = plugins/backend/mk-livestatus.c
diff --git a/src/plugins/backend/facter.cc b/src/plugins/backend/facter.cc
new file mode 100644 (file)
index 0000000..98f7f57
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * SysDB - src/plugins/backend/facter.cc
+ * Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if HAVE_CONFIG_H
+#      include "config.h"
+#endif
+
+#include "sysdb.h"
+#include "core/plugin.h"
+#include "core/store.h"
+#include "utils/error.h"
+
+#include <facter/facts/collection.hpp>
+#include <iostream>
+#include <sstream>
+
+static const char *hostname;
+static sdb_time_t now;
+
+static bool
+fact_iter(std::string const &k, facter::facts::value const *v)
+{
+       /* Don't ignore hidden values for now; they also provide the old,
+        * non-structured facts. */
+
+       std::stringstream ss;
+       v->write(ss, false);
+       std::string s = ss.str();
+       char *str = const_cast<char *>(s.c_str());
+
+       /* Ignore non-structured facts for now. */
+       if (str[0] == '{')
+               return true;
+
+       sdb_data_t value = { SDB_TYPE_STRING, { .string = str } };
+       sdb_store_attribute(hostname, k.c_str(), &value, now);
+       return true;
+} /* fact_iter */
+
+/* SysDB interface */
+extern "C" {
+
+       SDB_PLUGIN_MAGIC;
+
+       static int
+       facter_collect(sdb_object_t __attribute__((unused)) *user_data)
+       {
+               facter::facts::collection facts;
+
+               /* XXX: this may execute other programs; can we be sure that works
+                * reasonably well in a multi-threaded program? */
+               facts.add_default_facts();
+               facts.add_external_facts();
+
+               now = sdb_gettime();
+               facter::facts::value const *v = facts["fqdn"];
+               std::stringstream ss;
+               v->write(ss, false);
+               std::string s = ss.str();
+               hostname = s.c_str();
+
+               sdb_store_host(hostname, now);
+               facts.each(fact_iter);
+               sdb_log(SDB_LOG_DEBUG, "facter backend: Processed %zu facts "
+                               "for host '%s'", facts.size(), hostname);
+               return 0;
+       } /* main */
+
+       int
+       sdb_module_init(sdb_plugin_info_t *info)
+       {
+               sdb_plugin_set_info(info, SDB_PLUGIN_INFO_DESC,
+                               "backend retrieving local facter facts");
+               sdb_plugin_set_info(info, SDB_PLUGIN_INFO_COPYRIGHT,
+                               "Copyright (C) 2014 Sebastian 'tokkee' Harl <sh@tokkee.org>");
+               sdb_plugin_set_info(info, SDB_PLUGIN_INFO_LICENSE, "BSD");
+               sdb_plugin_set_info(info, SDB_PLUGIN_INFO_VERSION, SDB_VERSION);
+               sdb_plugin_set_info(info, SDB_PLUGIN_INFO_PLUGIN_VERSION, SDB_VERSION);
+
+               sdb_plugin_register_collector("main", facter_collect,
+                               /* interval */ NULL, /* user_data */ NULL);
+               return 0;
+       } /* sdb_module_init */
+
+} /* extern C */
+
+/* vim: set tw=78 sw=4 ts=4 noexpandtab : */
+