pcp
[Top] [All Lists]

[PATCH] Add a new PMDA exporting the GPSD location data

To: pcp@xxxxxxxxxxx
Subject: [PATCH] Add a new PMDA exporting the GPSD location data
From: "Josef 'Jeff' Sipek" <jeffpc@xxxxxxxxxxxxxx>
Date: Fri, 9 Jul 2010 02:11:17 -0400
User-agent: Mutt/1.5.20 (2009-06-14)
From: Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>

Signed-off-by: Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
---
 src/pmdas/GNUmakefile      |    2 +-
 src/pmdas/gpsd/GNUmakefile |   45 +++++++
 src/pmdas/gpsd/Install     |   27 ++++
 src/pmdas/gpsd/Remove      |   25 ++++
 src/pmdas/gpsd/pmdagpsd.pl |  310 ++++++++++++++++++++++++++++++++++++++++++++
 src/pmns/stdpmid.pcp       |    1 +
 6 files changed, 409 insertions(+), 1 deletions(-)
 create mode 100644 src/pmdas/gpsd/GNUmakefile
 create mode 100644 src/pmdas/gpsd/Install
 create mode 100644 src/pmdas/gpsd/Remove
 create mode 100644 src/pmdas/gpsd/pmdagpsd.pl

diff --git a/src/pmdas/GNUmakefile b/src/pmdas/GNUmakefile
index fdd1a68..b6cac7a 100644
--- a/src/pmdas/GNUmakefile
+++ b/src/pmdas/GNUmakefile
@@ -22,7 +22,7 @@ SUBDIRS = pmcd linux solaris aix darwin windows \
        lmsensors process roomtemp summary hotproc \
        dbping memcache systemtap mysql vmware kvm \
        bonding lustrecomm mmv netfilter zimbra \
-       named pdns samba dtsrun postfix
+       named pdns samba dtsrun postfix gpsd
 
 LDIRT = pmcd.conf
 
diff --git a/src/pmdas/gpsd/GNUmakefile b/src/pmdas/gpsd/GNUmakefile
new file mode 100644
index 0000000..3191bec
--- /dev/null
+++ b/src/pmdas/gpsd/GNUmakefile
@@ -0,0 +1,45 @@
+#!gmake
+#
+# Copyright (c) 2010 Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
+#
+# 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; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+
+TOPDIR = ../../..
+include $(TOPDIR)/src/include/builddefs
+
+IAM    = gpsd
+PMDADIR        = $(PCP_PMDAS_DIR)/$(IAM)
+LSRCFILES = Install Remove pmda$(IAM).pl
+LDIRT  = domain.h root pmns *.log $(MAN_PAGES)
+
+ifneq ($(POD2MAN),)
+MAN_SECTION = 1
+MAN_PAGES = pmda$(IAM).$(MAN_SECTION)
+MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION)
+endif
+
+default: $(MAN_PAGES)
+
+pmda$(IAM).1: pmda$(IAM).pl
+       $(POD_MAKERULE)
+
+include $(BUILDRULES)
+
+install: default
+       $(INSTALL) -m 755 -d $(PMDADIR)
+       $(INSTALL) -m 755 Install Remove $(PMDADIR)
+       $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl
+       @$(INSTALL_MAN)
+
+default_pcp : default
+
+install_pcp : install
diff --git a/src/pmdas/gpsd/Install b/src/pmdas/gpsd/Install
new file mode 100644
index 0000000..ab2da06
--- /dev/null
+++ b/src/pmdas/gpsd/Install
@@ -0,0 +1,27 @@
+#! /bin/sh
+#
+# Copyright (c) 2010 Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
+#
+# 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; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# Install the gpsd PMDA
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=gpsd
+perl_opt=true
+daemon_opt=false
+
+pmdaSetup
+pmdaInstall
+exit 0
diff --git a/src/pmdas/gpsd/Remove b/src/pmdas/gpsd/Remove
new file mode 100644
index 0000000..2b52da3
--- /dev/null
+++ b/src/pmdas/gpsd/Remove
@@ -0,0 +1,25 @@
+#! /bin/sh
+#
+# Copyright (c) 2010 Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
+#
+# 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; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+# Remove the gpsd PMDA
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=gpsd
+
+pmdaSetup
+pmdaRemove
+exit 0
diff --git a/src/pmdas/gpsd/pmdagpsd.pl b/src/pmdas/gpsd/pmdagpsd.pl
new file mode 100644
index 0000000..36d7668
--- /dev/null
+++ b/src/pmdas/gpsd/pmdagpsd.pl
@@ -0,0 +1,310 @@
+#
+# Copyright (c) 2010 Josef 'Jeff' Sipek <jeffpc@xxxxxxxxxxxxxx>
+#
+# 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; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+
+use strict;
+use warnings;
+use PCP::PMDA;
+use JSON;
+use Time::HiRes qw ( time );
+
+use vars qw( $pmda );
+use vars qw( %devdata %satdata );
+
+my $gpspipe = "gpspipe -w";
+
+my $json;
+
+my $gpsd_release = "?";
+my $gpsd_rev = "?";
+my $gpsd_proto_maj = -1;
+my $gpsd_proto_min = -1;
+
+# FIXME: the following will need changing to support multiple devices
+my $gpsd_device = undef;
+my %devdata = (
+       "time"  => -1,
+       "ept"   => -1,
+       "lat"   => -1,
+       "lon"   => -1,
+       "alt"   => -1,
+       "track" => -1,
+       "speed" => -1,
+       "climb" => -1,
+       "mode"  => -1,
+       "xdop"  => -1,
+       "ydop"  => -1,
+       "vdop"  => -1,
+       "tdop"  => -1,
+       "hdop"  => -1,
+       "gdop"  => -1,
+       "pdop"  => -1,
+       "num_satellites" => 0,
+);
+my $gpsd_sat_indom = 0;
+my @gpsd_sat_dom = ();
+
+sub gpsd_pipe_callback
+{
+       (undef, $_) = @_;
+
+       $pmda->log("pipe got: $_");
+
+       my $jtxt = $json->decode($_);
+
+       if ($jtxt->{"class"} eq "VERSION") {
+               $gpsd_release   = $jtxt->{"release"};
+               $gpsd_rev       = $jtxt->{"rev"};
+               $gpsd_proto_maj = $jtxt->{"proto_major"};
+               $gpsd_proto_min = $jtxt->{"proto_minor"};
+       } elsif ($jtxt->{"class"} eq "DEVICES") {
+               foreach my $dev (@{$jtxt->{"devices"}}) {
+                       if ($dev->{"class"} eq "DEVICE") {
+                               $pmda->log("gpsd_pipe_callback: oops!  multiple 
" .
+                                       "devices detected, only using the first 
" . 
+                                       "($gpsd_device)") if 
(defined($gpsd_device) and
+                                                             $dev->{"path"} ne 
$gpsd_device);
+
+                               $gpsd_device = $dev->{"path"};
+                       } else {
+                               $pmda->log("gpsd_pipe_callback: unknown class 
'" .
+                                       $dev->{"class"} . "'");
+                       }
+               }
+       } elsif ($jtxt->{"class"} eq "DEVICE") {
+               # nothing to do
+       } elsif ($jtxt->{"class"} eq "WATCH") {
+               # nothing to do
+       } elsif ($jtxt->{"class"} eq "TPV") {
+               return if ($jtxt->{"device"} ne $gpsd_device);
+
+               $devdata{"time"}  = $jtxt->{"time"};
+               $devdata{"ept"}   = $jtxt->{"ept"};
+               $devdata{"lat"}   = $jtxt->{"lat"};
+               $devdata{"lon"}   = $jtxt->{"lon"};
+               $devdata{"alt"}   = $jtxt->{"alt"};
+               $devdata{"track"} = $jtxt->{"track"};
+               $devdata{"speed"} = $jtxt->{"speed"};
+               $devdata{"climb"} = $jtxt->{"climb"};
+               $devdata{"mode"}  = $jtxt->{"mode"};
+       } elsif ($jtxt->{"class"} eq "SKY") {
+               return if ($jtxt->{"device"} ne $gpsd_device);
+
+               $devdata{"xdop"} = $jtxt->{"xdop"};
+               $devdata{"ydop"} = $jtxt->{"ydop"};
+               $devdata{"vdop"} = $jtxt->{"vdop"};
+               $devdata{"tdop"} = $jtxt->{"tdop"};
+               $devdata{"hdop"} = $jtxt->{"hdop"};
+               $devdata{"gdop"} = $jtxt->{"gdop"};
+               $devdata{"pdop"} = $jtxt->{"pdop"};
+
+               my %sats = {};
+               my @dom = ();
+               foreach my $sat (@{$jtxt->{"satellites"}}) {
+                       push(@dom, $sat->{"PRN"} => "$sat->{'PRN'}");
+
+                       $sats{"el"}{$sat->{"PRN"}} = $sat->{"el"};
+                       $sats{"az"}{$sat->{"PRN"}} = $sat->{"az"};
+                       $sats{"ss"}{$sat->{"PRN"}} = $sat->{"ss"};
+                       $sats{"used"}{$sat->{"PRN"}} = $sat->{"used"};
+                       #push(@{$sats{"used"}}, $sat->{"PRN"} => 
$sat->{"used"});
+               }
+               %satdata = %sats;
+                $pmda->replace_indom($gpsd_sat_indom, \@dom);
+
+               $devdata{"num_satellites"} = scalar(@dom) / 2;
+       } else {
+               $pmda->log("gpsd_pipe_callback: unknown class '" . 
$jtxt->{"class"} . "'");
+       }
+}
+
+sub gpsd_fetch_callback
+{
+       my ($cluster, $item, $inst) = @_;
+       my $metric_name = pmda_pmid_name($cluster, $item);
+
+        $pmda->log("gpsd_fetch_callback $metric_name $cluster:$item 
($inst)\n");
+       
+       if (!defined($metric_name))    { return (PM_ERR_PMID, 0); }
+
+       if ($cluster == 0) {
+               return (PM_ERR_INST, 0) if ($inst != PM_IN_NULL);
+
+               if ($metric_name eq "gpsd.release") {
+                       return ($gpsd_release, 1);
+               } elsif ($metric_name eq "gpsd.rev") {
+                       return ($gpsd_rev, 1);
+               } elsif ($metric_name eq "gpsd.proto.major") {
+                       return ($gpsd_proto_maj, 1);
+               } elsif ($metric_name eq "gpsd.proto.minor") {
+                       return ($gpsd_proto_min, 1);
+               }
+       }
+
+       $metric_name =~ s/^gpsd\.devices\.dev0\.//;
+
+       if ($metric_name =~ m/^satellites\./) {
+               # satellite info
+               $metric_name =~ s/^satellites\.//;
+       
+        $pmda->log("gpsd_fetch_callbac2 $metric_name $cluster:$item ($inst): 
${satdata{$metric_name}}\n");
+        $pmda->log("gpsd_fetch_callbac2 $metric_name $cluster:$item ($inst): 
${satdata{$metric_name}{$inst}}\n");
+               return (PM_ERR_INST, 0) if ($inst == PM_IN_NULL);
+               return (PM_ERR_PMID, 0) if 
(!defined($satdata{$metric_name}{$inst}));
+               return ($satdata{$metric_name}{$inst}, 1);
+       }
+               
+       return (PM_ERR_INST, 0) if ($inst != PM_IN_NULL);
+       return (PM_ERR_PMID, 0) if (!defined($devdata{$metric_name}));
+       return ($devdata{$metric_name}, 1);
+}
+
+$json = new JSON;
+
+$pmda = PCP::PMDA->new('gpsd', 105);
+
+$pmda->add_metric(pmda_pmid(0,0), PM_TYPE_STRING, PM_INDOM_NULL, 
PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.release", '', '');
+$pmda->add_metric(pmda_pmid(0,1), PM_TYPE_STRING, PM_INDOM_NULL, 
PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.rev", '', '');
+$pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.proto.major", '', '');
+$pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.proto.minor", '', '');
+
+$pmda->add_metric(pmda_pmid(1,0), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.time", '', '');
+$pmda->add_metric(pmda_pmid(1,1), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.ept", '', '');
+$pmda->add_metric(pmda_pmid(1,2), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.lat", '', '');
+$pmda->add_metric(pmda_pmid(1,3), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.lon", '', '');
+$pmda->add_metric(pmda_pmid(1,4), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.alt", '', '');
+$pmda->add_metric(pmda_pmid(1,5), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.track", '', '');
+$pmda->add_metric(pmda_pmid(1,6), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.speed", '', '');
+$pmda->add_metric(pmda_pmid(1,7), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.climb", '', '');
+$pmda->add_metric(pmda_pmid(1,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.mode", '', '');
+
+$pmda->add_metric(pmda_pmid(1,9), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.xdop", '', '');
+$pmda->add_metric(pmda_pmid(1,10), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.ydop", '', '');
+$pmda->add_metric(pmda_pmid(1,11), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.vdop", '', '');
+$pmda->add_metric(pmda_pmid(1,12), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.tdop", '', '');
+$pmda->add_metric(pmda_pmid(1,13), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.hdop", '', '');
+$pmda->add_metric(pmda_pmid(1,14), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.gdop", '', '');
+$pmda->add_metric(pmda_pmid(1,15), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.pdop", '', '');
+
+$pmda->add_metric(pmda_pmid(1,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.num_satellites", '', '');
+
+$pmda->add_metric(pmda_pmid(1,100), PM_TYPE_U32, $gpsd_sat_indom, 
PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.satellites.el", '', '');
+$pmda->add_metric(pmda_pmid(1,101), PM_TYPE_U32, $gpsd_sat_indom, 
PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.satellites.az", '', '');
+$pmda->add_metric(pmda_pmid(1,102), PM_TYPE_U32, $gpsd_sat_indom, 
PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.satellites.ss", '', '');
+$pmda->add_metric(pmda_pmid(1,103), PM_TYPE_U32, $gpsd_sat_indom, 
PM_SEM_INSTANT,
+                pmda_units(0,0,0,0,0,0),
+                "gpsd.devices.dev0.satellites.used", '', '');
+
+$pmda->add_indom($gpsd_sat_indom, \@gpsd_sat_dom, '', '');
+$pmda->add_pipe($gpspipe, \&gpsd_pipe_callback, 0);
+
+$pmda->set_fetch_callback(\&gpsd_fetch_callback);
+$pmda->run;
+
+=pod
+
+=head1 NAME
+
+pmdagpsd - gpsd performance metrics domain agent (PMDA)
+
+=head1 DESCRIPTION
+
+B<pmdagpsd> is a Performance Metrics Domain Agent (PMDA) which exports
+values from the gpsd daemon.
+
+=head1 INSTALLATION
+
+If you want access to the names and values for gpsd, do the following as
+root:
+
+        # cd $PCP_PMDAS_DIR/gpsd
+        # ./Install
+
+If you want to undo the installation, do the following as root:
+
+        # cd $PCP_PMDAS_DIR/gpsd
+        # ./Remove
+
+B<pmdagpsd> is launched by pmcd(1) and should never be executed
+directly.  The Install and Remove scripts notify pmcd(1) when
+the agent is installed or removed.
+
+=head1 FILES
+
+=over
+
+=item $PCP_PMDAS_DIR/gpsd/Install
+
+installation script for the B<pmdagpsd> agent
+
+=item $PCP_PMDAS_DIR/gpsd/Remove
+
+undo installation script for the B<pmdagpsd> agent
+
+=item $PCP_LOG_DIR/pmcd/gpsd.log
+
+default log file for error messages from B<pmdagpsd>
+
+=back
+
+=head1 SEE ALSO
+
+pmcd(1).
diff --git a/src/pmns/stdpmid.pcp b/src/pmns/stdpmid.pcp
index 414338b..b2e8eb3 100644
--- a/src/pmns/stdpmid.pcp
+++ b/src/pmns/stdpmid.pcp
@@ -80,6 +80,7 @@ PDNS          101
 DTSRUN         102
 POSTFIX                103
 IPMI           104
+GPSD           105
 ### NEXT FREE SLOT ###
 DBPING         244
 COUNTD         245
-- 
1.7.1

<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH] Add a new PMDA exporting the GPSD location data, Josef 'Jeff' Sipek <=