From: Richard Jones Date: Tue, 6 Nov 2007 14:09:59 +0000 (+0000) Subject: uuid plugin: Add a plugin which sets the hostname to an UUID. X-Git-Tag: collectd-4.3.0beta0~117 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=30f3e7b81e938d2fcf0512acb46e639a8cb37ae7;p=collectd.git uuid plugin: Add a plugin which sets the hostname to an UUID. Florian Forster wrote: > Just out of curiosity: Why don't hostnames work for you? For guests there's the question of what we put in the hostname field. The previous plugin (libvirtstats) puts the guest's name in this field, but there are some problems with this: physicalserver1 <--- (hostname of physical server) | \--- database <--- (name of guest) \--- web physicalserver2 | \--- database \--- web coldbackupserver | (no guests) Guest names aren't really unique. Different physical servers may have guests with overlapping names as in the example above. Also guest names aren't fixed. Xen in particular renames guests at will. For example if a guest is about to migrate then Xen renames the guest as 'migrating-foo' and if the guest is about to shutdown Xen renames it as 'Zombie-foo'. The administrator of the physical server can also rename guests. While you're migrating you'll have an intermediate situation like this: physicalserver1 | \--- migrating-database \--- migrating-web | | migration coldbackupserver | | V \--- database \--- web During live migrations the old instance ('migrating-foo') is still running. The UUID is unique across physical servers, and is copied by migration and preserved across shutdowns so if you care about which guest your stats "really" came from then only the UUID tells you this. Guests also have a hostname which is separate from the guest's name (the guest's name is stored in the hypervisor, the hostname is stored inside the guest's kernel). However it's not feasible to access the guest's hostname from the hypervisor since this would involve some sort of snooping into the guest kernel. The guest might be running Windows or FreeBSD etc. The only feasible way to get this is to run an instance of collectd inside each guest, but then the uuid plugin will also work in this scenario and can get the UUID since it is exposed inside the guest either through an emulated BIOS or in /sys/hypervisor/uuid. Rich. Signed-off-by: Florian Forster --- diff --git a/AUTHORS b/AUTHORS index ee7e3920..d821df7a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -60,6 +60,10 @@ Much time and effort to find a nasty bug in the ntpd-plugin has been contributed by: Luboš Staněk +uuid module by: + Dan Berrange + Richard W.M. Jones + collectd is available at: diff --git a/configure.in b/configure.in index 75bc00f4..31e0582c 100644 --- a/configure.in +++ b/configure.in @@ -17,6 +17,7 @@ AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET +AM_PROG_CC_C_O AM_CONDITIONAL(COMPILER_IS_GCC, test "x$GCC" = "xyes") dnl configure libtool @@ -669,6 +670,20 @@ AC_CHECK_LIB(resolv, res_search, [with_libresolv="no"]) AM_CONDITIONAL(BUILD_WITH_LIBRESOLV, test "x$with_libresolv" = "xyes") +dnl Check for HAL (hardware abstraction library) +with_libhal="yes" +AC_CHECK_LIB(hal,libhal_device_property_exists, + [AC_DEFINE(HAVE_LIBHAL, 1, [Define to 1 if you have 'hal' library])], + [with_libhal="no"]) +if test "x$with_libhal" = "xyes"; then + PKG_PROG_PKG_CONFIG + if test "x$PKG_CONFIG" != "x"; then + BUILD_WITH_LIBHAL_CFLAGS="`pkg-config --cflags hal`" + BUILD_WITH_LIBHAL_LIBS="`pkg-config --libs hal`" + AC_SUBST(BUILD_WITH_LIBHAL_CFLAGS) + AC_SUBST(BUILD_WITH_LIBHAL_LIBS) + fi +fi m4_divert_once([HELP_WITH], [ collectd additional packages:]) @@ -1885,6 +1900,7 @@ AC_PLUGIN([tape], [$plugin_tape], [Tape drive statistics]) AC_PLUGIN([tcpconns], [$plugin_tcpconns], [TCP connection statistics]) AC_PLUGIN([unixsock], [yes], [Unixsock communication plugin]) AC_PLUGIN([users], [$plugin_users], [User statistics]) +AC_PLUGIN([uuid], [yes], [UUID as hostname plugin]) AC_PLUGIN([vserver], [$plugin_vserver], [Linux VServer statistics]) AC_PLUGIN([wireless], [$plugin_wireless], [Wireless statistics]) AC_PLUGIN([xmms], [$with_libxmms], [XMMS statistics]) @@ -2011,6 +2027,7 @@ Configuration: tcpconns . . . . . $enable_tcpconns unixsock . . . . . $enable_unixsock users . . . . . . . $enable_users + uuid . . . . . . . $enable_uuid vserver . . . . . . $enable_vserver wireless . . . . . $enable_wireless xmms . . . . . . . $enable_xmms diff --git a/src/Makefile.am b/src/Makefile.am index 0107241f..8bf62175 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -578,6 +578,16 @@ collectd_LDADD += "-dlopen" users.la collectd_DEPENDENCIES += users.la endif +if BUILD_PLUGIN_UUID +pkglib_LTLIBRARIES += uuid.la +uuid_la_SOURCES = uuid.c +uuid_la_CFLAGS = $(BUILD_WITH_LIBHAL_CFLAGS) +uuid_la_LIBADD = $(BUILD_WITH_LIBHAL_LIBS) +uuid_la_LDFLAGS = -module -avoid-version +collectd_LDADD += "-dlopen" uuid.la +collectd_DEPENDENCIES += uuid.la +endif + if BUILD_PLUGIN_VSERVER pkglib_LTLIBRARIES += vserver.la vserver_la_SOURCES = vserver.c diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index da12f863..83267047 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -869,6 +869,35 @@ L. Defaults to B<0770>. =back +=head2 Plugin C + +This plugin, if loaded, causes the Hostname to be taken from the +machine's UUID. The UUID is a universally unique designation for the +machine, usually taken from the machine's BIOS. This is most useful +if the machine is running in a virtual environment such as Xen, in +which case the UUID is preserved across shutdowns and migration. + +The following methods are used to find the machine's UUID, in order: + +Check I (or I). + +Check for UUID from HAL (L) +if present. + +Check for UUID from C / SMBIOS. + +Check for UUID from Xen hypervisor. + +If no UUID can be found then the hostname is not modified. + +=over 4 + +=item B I + +Take the UUID from the given file (default I). + +=back + =head2 Plugin C This plugin doesn't have any options. B support is only available for diff --git a/src/uuid.c b/src/uuid.c new file mode 100644 index 00000000..d54301a2 --- /dev/null +++ b/src/uuid.c @@ -0,0 +1,289 @@ +/** + * collectd - src/uuid.c + * Copyright (C) 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: + * Dan Berrange + * Richard W.M. Jones + * + * Derived from UUID detection code by Dan Berrange + * http://hg.et.redhat.com/virt/daemons/spectre--devel?f=f6e3a1b06433;file=lib/uuid.c + **/ + +#include "collectd.h" +#include "common.h" +#include "configfile.h" +#include "plugin.h" + +#if HAVE_LIBHAL +#include +#endif + +#define UUID_RAW_LENGTH 16 +#define UUID_PRINTABLE_COMPACT_LENGTH (UUID_RAW_LENGTH * 2) +#define UUID_PRINTABLE_NORMAL_LENGTH (UUID_PRINTABLE_COMPACT_LENGTH + 4) + +#define HANDLE_PREFIX "Handle" +#define SYSINFO_PREFIX "System Information" +#define ALT_SYSINFO_PREFIX "\tSystem Information" +#define UUID_PREFIX "\tUUID:" +#define ALT_UUID_PREFIX "\t\tUUID:" + +static int +looks_like_a_uuid (const char *uuid) +{ + int len; + + if (!uuid) return 0; + + len = strlen (uuid); + + if (len < UUID_PRINTABLE_COMPACT_LENGTH) + return 0; + + while (*uuid) { + if (!isxdigit (*uuid) && *uuid != '-') return 0; + uuid++; + } + return 1; +} + +static char * +uuid_parse_dmidecode(FILE *file) +{ + char line[1024]; + int inSysInfo = 0; + + for (;;) { + if (!fgets(line, sizeof(line)/sizeof(char), file)) { + return NULL; + } + if (strncmp(line, HANDLE_PREFIX, + (sizeof(HANDLE_PREFIX)/sizeof(char))-1) == 0) { + /*printf("Got handle %s\n", line);*/ + inSysInfo = 0; + } else if (strncmp(line, SYSINFO_PREFIX, + (sizeof(SYSINFO_PREFIX)/sizeof(char))-1) == 0) { + /*printf("Got system info %s\n", line);*/ + inSysInfo = 1; + } else if (strncmp(line, ALT_SYSINFO_PREFIX, + (sizeof(ALT_SYSINFO_PREFIX)/sizeof(char))-1) == 0) { + /*printf("Got alt system info %s\n", line);*/ + inSysInfo = 1; + } + + if (inSysInfo) { + if (strncmp(line, UUID_PREFIX, + (sizeof(UUID_PREFIX)/sizeof(char))-1) == 0) { + char *uuid = line + (sizeof(UUID_PREFIX)/sizeof(char)); + /*printf("Got uuid [%s]\n", uuid);*/ + if (looks_like_a_uuid (uuid)) + return strdup (uuid); + } + if (strncmp(line, ALT_UUID_PREFIX, + (sizeof(ALT_UUID_PREFIX)/sizeof(char))-1) == 0) { + char *uuid = line + (sizeof(ALT_UUID_PREFIX)/sizeof(char)); + /*printf("Got alt uuid [%s]\n", uuid);*/ + if (looks_like_a_uuid (uuid)) + return strdup (uuid); + } + } + } + return NULL; +} + +static char * +uuid_get_from_dmidecode(void) +{ + FILE *dmidecode = popen("dmidecode 2>/dev/null", "r"); + char *uuid; + + if (!dmidecode) { + return NULL; + } + + uuid = uuid_parse_dmidecode(dmidecode); + + pclose(dmidecode); + return uuid; +} + +#if HAVE_LIBHAL + +#define UUID_PATH "/org/freedesktop/Hal/devices/computer" +#define UUID_PROPERTY "smbios.system.uuid" + +static char * +uuid_get_from_hal(void) +{ + LibHalContext *ctx; + + DBusError error; + DBusConnection *con; + + dbus_error_init(&error); + + if (!(con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) ) { + goto bailout_nobus; + } + + ctx = libhal_ctx_new(); + libhal_ctx_set_dbus_connection(ctx, con); + + if (!libhal_ctx_init(ctx, &error)) { + goto bailout; + } + + if (!libhal_device_property_exists(ctx, + UUID_PATH, + UUID_PROPERTY, + &error)) { + goto bailout; + } + + char *uuid = libhal_device_get_property_string(ctx, + UUID_PATH, + UUID_PROPERTY, + &error); + if (looks_like_a_uuid (uuid)) { + return uuid; + } + + bailout: + { + DBusError ctxerror; + dbus_error_init(&ctxerror); + if (!(libhal_ctx_shutdown(ctx, &ctxerror))) { + dbus_error_free(&ctxerror); + } + } + + libhal_ctx_free(ctx); + //dbus_connection_unref(con); + + bailout_nobus: + if (dbus_error_is_set(&error)) { + /*printf("Error %s\n", error.name);*/ + dbus_error_free(&error); + } + return NULL; +} +#endif + +static char * +uuid_get_from_file(const char *path) +{ + FILE *file; + char uuid[UUID_PRINTABLE_NORMAL_LENGTH+1]; + + if (!(file = fopen(path, "r"))) { + return NULL; + } + + if (!fgets(uuid, sizeof(uuid), file)) { + fclose(file); + return NULL; + } + fclose(file); + + return strdup (uuid); +} + +static char *uuidfile = NULL; + +static char * +uuid_get_local(void) +{ + char *uuid; + + /* Check /etc/uuid / UUIDFile before any other method. */ + if ((uuid = uuid_get_from_file(uuidfile ? uuidfile : "/etc/uuid")) != NULL){ + return uuid; + } + +#if HAVE_LIBHAL + if ((uuid = uuid_get_from_hal()) != NULL) { + return uuid; + } +#endif + + if ((uuid = uuid_get_from_dmidecode()) != NULL) { + return uuid; + } + + if ((uuid = uuid_get_from_file("/sys/hypervisor/uuid")) != NULL) { + return uuid; + } + + return NULL; +} + +static const char *config_keys[] = { + "UUIDFile", + NULL +}; +#define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1) + +static int +uuid_config (const char *key, const char *value) +{ + if (strcasecmp (key, "UUIDFile") == 0) { + if (uuidfile) { + ERROR ("UUIDFile given twice in configuration file"); + return 1; + } + uuidfile = strdup (value); + return 0; + } + return 0; +} + +static int +uuid_init (void) +{ + char *uuid = uuid_get_local (); + + if (uuid) { + strncpy (hostname_g, uuid, DATA_MAX_NAME_LEN); + hostname_g[DATA_MAX_NAME_LEN-1] = '\0'; + sfree (uuid); + return 0; + } + + WARNING ("uuid: could not read UUID using any known method"); + return 0; +} + +void module_register (void) +{ + plugin_register_config ("uuid", uuid_config, + config_keys, NR_CONFIG_KEYS); + plugin_register_init ("uuid", uuid_init); +} + +/* + * 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: + */