1 #!/usr/bin/perl
2 #
3 # collectd - contrib/cussh.pl
4 # Copyright (C) 2007-2008 Sebastian Harl
5 #
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the
8 # Free Software Foundation; only version 2 of the License is applicable.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 #
19 # Author:
20 # Sebastian Harl <sh at tokkee.org>
21 #
23 =head1 NAME
25 cussh - collectd UNIX socket shell
27 =head1 SYNOPSIS
29 B<cussh> [I<E<lt>pathE<gt>>]
31 =head1 DESCRIPTION
33 B<collectd>'s unixsock plugin allows external programs to access the values it
34 has collected or received and to submit own values. This is a little
35 interactive frontend for this plugin.
37 =head1 OPTIONS
39 =over 4
41 =item I<E<lt>pathE<gt>>
43 The path to the UNIX socket provided by collectd's unixsock plugin. (Default:
44 F</var/run/collectd-unixsock>)
46 =back
48 =cut
50 use strict;
51 use warnings;
53 use Collectd::Unixsock();
55 { # main
56 my $path = $ARGV[0] || "/var/run/collectd-unixsock";
57 my $sock = Collectd::Unixsock->new($path);
59 my $cmds = {
60 HELP => \&cmd_help,
61 PUTVAL => \&putval,
62 GETVAL => \&getval,
63 FLUSH => \&flush,
64 LISTVAL => \&listval,
65 PUTNOTIF => \&putnotif,
66 };
68 if (! $sock) {
69 print STDERR "Unable to connect to $path!\n";
70 exit 1;
71 }
73 print "cussh version 0.2, Copyright (C) 2007-2008 Sebastian Harl\n"
74 . "cussh comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
75 . "and you are welcome to redistribute it under certain conditions.\n"
76 . "See the GNU General Public License 2 for more details.\n\n";
78 while (1) {
79 print "cussh> ";
80 my $line = <STDIN>;
82 last if (! $line);
84 chomp $line;
86 last if ($line =~ m/^quit$/i);
88 my ($cmd) = $line =~ m/^(\w+)\s*/;
89 $line = $';
91 next if (! $cmd);
92 $cmd = uc $cmd;
94 my $f = undef;
95 if (defined $cmds->{$cmd}) {
96 $f = $cmds->{$cmd};
97 }
98 else {
99 print STDERR "ERROR: Unknown command $cmd!\n";
100 next;
101 }
103 if (! $f->($sock, $line)) {
104 print STDERR "ERROR: Command failed!\n";
105 next;
106 }
107 }
109 $sock->destroy();
110 exit 0;
111 }
113 sub getid {
114 my $string = shift || return;
116 print $$string . $/;
117 my ($h, $p, $pi, $t, $ti) =
118 $$string =~ m#^([^/]+)/([^/-]+)(?:-([^/]+))?/([^/-]+)(?:-([^/]+))?\s*#;
119 $$string = $';
121 return if ((! $h) || (! $p) || (! $t));
123 my %id = ();
125 ($id{'host'}, $id{'plugin'}, $id{'type'}) = ($h, $p, $t);
127 $id{'plugin_instance'} = $pi if defined ($pi);
128 $id{'type_instance'} = $ti if defined ($ti);
129 return \%id;
130 }
132 sub putid {
133 my $ident = shift || return;
135 my $string;
137 $string = $ident->{'host'} . "/" . $ident->{'plugin'};
139 if (defined $ident->{'plugin_instance'}) {
140 $string .= "-" . $ident->{'plugin_instance'};
141 }
143 $string .= "/" . $ident->{'type'};
145 if (defined $ident->{'type_instance'}) {
146 $string .= "-" . $ident->{'type_instance'};
147 }
148 return $string;
149 }
151 =head1 COMMANDS
153 =over 4
155 =item B<HELP>
157 =cut
159 sub cmd_help {
160 print <<HELP;
161 Available commands:
162 HELP
163 PUTVAL
164 GETVAL
165 FLUSH
166 LISTVAL
167 PUTNOTIF
169 See the embedded Perldoc documentation for details. To do that, run:
170 perldoc $0
171 HELP
172 return 1;
173 } # cmd_help
175 =item B<GETVAL> I<Identifier>
177 =cut
179 sub putval {
180 my $sock = shift || return;
181 my $line = shift || return;
183 my $id = getid(\$line);
185 if (! $id) {
186 print STDERR $sock->{'error'} . $/;
187 return;
188 }
190 my ($time, @values) = split m/:/, $line;
191 return $sock->putval(%$id, time => $time, values => \@values);
192 }
194 =item B<PUTVAL> I<Identifier> I<Valuelist>
196 =cut
198 sub getval {
199 my $sock = shift || return;
200 my $line = shift || return;
202 my $id = getid(\$line);
204 if (! $id) {
205 print STDERR $sock->{'error'} . $/;
206 return;
207 }
209 my $vals = $sock->getval(%$id);
211 if (! $vals) {
212 print STDERR $sock->{'error'} . $/;
213 return;
214 }
216 foreach my $key (keys %$vals) {
217 print "\t$key: $vals->{$key}\n";
218 }
219 return 1;
220 }
222 =item B<FLUSH> [B<timeout>=I<$timeout>] [B<plugin>=I<$plugin>[ ...]]
224 =cut
226 sub flush {
227 my $sock = shift || return;
228 my $line = shift;
230 my $res;
232 if (! $line) {
233 $res = $sock->flush();
234 }
235 else {
236 my %args = ();
238 foreach my $i (split m/ /, $line) {
239 my ($option, $value) = $i =~ m/^([^=]+)=(.+)$/;
240 next if (! ($option && $value));
242 if ($option eq "plugin") {
243 push @{$args{"plugins"}}, $value;
244 }
245 elsif ($option eq "timeout") {
246 $args{"timeout"} = $value;
247 }
248 elsif ($option eq "identifier") {
249 my $id = getid (\$value);
250 if (!$id)
251 {
252 print STDERR "Not a valid identifier: \"$value\"\n";
253 next;
254 }
255 push @{$args{"identifier"}}, $id;
256 }
257 else {
258 print STDERR "Invalid option \"$option\".\n";
259 return;
260 }
261 }
263 $res = $sock->flush(%args);
264 }
266 if (! $res) {
267 print STDERR $sock->{'error'} . $/;
268 return;
269 }
270 return 1;
271 }
273 =item B<LISTVAL>
275 =cut
277 sub listval {
278 my $sock = shift || return;
280 my @res;
282 @res = $sock->listval();
284 if (! @res) {
285 print STDERR $sock->{'error'} . $/;
286 return;
287 }
289 foreach my $ident (@res) {
290 print $ident->{'time'} . " " . putid($ident) . $/;
291 }
292 return 1;
293 }
295 =item B<PUTNOTIF> [[B<severity>=I<$severity>] [B<message>=I<$message>] [ ...]]
297 =cut
299 sub putnotif {
300 my $sock = shift || return;
301 my $line = shift || return;
303 my (%values) = ();
304 foreach my $i (split m/ /, $line) {
305 my($key,$val) = split m/=/, $i, 2;
306 if ($key && $val) {
307 $values{$key} = $val;
308 }
309 else {
310 $values{'message'} .= ' '.$key;
311 }
312 }
313 $values{'time'} ||= time();
314 my(@tmp) = %values;
315 return $sock->putnotif(%values);
316 }
318 =back
320 These commands follow the exact same syntax as described in
321 L<collectd-unixsock(5)>.
323 =head1 SEE ALSO
325 L<collectd(1)>, L<collectd-unisock(5)>
327 =head1 AUTHOR
329 Written by Sebastian Harl E<lt>sh@tokkee.orgE<gt>.
331 B<collectd> has been written by Florian Forster and others.
333 =head1 COPYRIGHT
335 Copyright (C) 2007 Sebastian Harl.
337 This program is free software; you can redistribute it and/or modify it under
338 the terms of the GNU General Public License as published by the Free Software
339 Foundation; only version 2 of the License is applicable.
341 =cut
343 # vim: set sw=4 ts=4 tw=78 noexpandtab :