Merge branch 'collectd-4.4'
[collectd.git] / contrib / cussh.pl
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 #
22
23 =head1 NAME
24
25 cussh - collectd UNIX socket shell
26
27 =head1 SYNOPSIS
28
29 B<cussh> [I<E<lt>pathE<gt>>]
30
31 =head1 DESCRIPTION
32
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.
36
37 =head1 OPTIONS
38
39 =over 4
40
41 =item I<E<lt>pathE<gt>>
42
43 The path to the UNIX socket provided by collectd's unixsock plugin. (Default:
44 F</var/run/collectd-unixsock>)
45
46 =back
47
48 =cut
49
50 use strict;
51 use warnings;
52
53 use Collectd::Unixsock();
54
55 { # main
56         my $path = $ARGV[0] || "/var/run/collectd-unixsock";
57         my $sock = Collectd::Unixsock->new($path);
58
59         my $cmds = {
60                 PUTVAL  => \&putval,
61                 GETVAL  => \&getval,
62                 FLUSH   => \&flush,
63                 LISTVAL => \&listval,
64         };
65
66         if (! $sock) {
67                 print STDERR "Unable to connect to $path!\n";
68                 exit 1;
69         }
70
71         print "cussh version 0.2, Copyright (C) 2007-2008 Sebastian Harl\n"
72                 . "cussh comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
73                 . "and you are welcome to redistribute it under certain conditions.\n"
74                 . "See the GNU General Public License 2 for more details.\n\n";
75
76         while (1) {
77                 print "cussh> ";
78                 my $line = <STDIN>;
79
80                 last if (! $line);
81
82                 chomp $line;
83
84                 last if ($line =~ m/^quit$/i);
85
86                 my ($cmd) = $line =~ m/^(\w+)\s*/;
87                 $line = $';
88
89                 next if (! $cmd);
90                 $cmd = uc $cmd;
91
92                 my $f = undef;
93                 if (defined $cmds->{$cmd}) {
94                         $f = $cmds->{$cmd};
95                 }
96                 else {
97                         print STDERR "ERROR: Unknown command $cmd!\n";
98                         next;
99                 }
100
101                 if (! $f->($sock, $line)) {
102                         print STDERR "ERROR: Command failed!\n";
103                         next;
104                 }
105         }
106
107         $sock->destroy();
108         exit 0;
109 }
110
111 sub getid {
112         my $string = shift || return;
113
114         print $$string . $/;
115         my ($h, $p, $pi, $t, $ti) =
116                 $$string =~ m#^([^/]+)/([^/-]+)(?:-([^/]+))?/([^/-]+)(?:-([^/]+))?\s*#;
117         $$string = $';
118
119         return if ((! $h) || (! $p) || (! $t));
120
121         my %id = ();
122
123         ($id{'host'}, $id{'plugin'}, $id{'type'}) = ($h, $p, $t);
124
125         $id{'plugin_instance'} = $pi if defined ($pi);
126         $id{'type_instance'} = $ti if defined ($ti);
127         return \%id;
128 }
129
130 sub putid {
131         my $ident = shift || return;
132
133         my $string;
134
135         $string = $ident->{'host'} . "/" . $ident->{'plugin'};
136
137         if (defined $ident->{'plugin_instance'}) {
138                 $string .= "-" . $ident->{'plugin_instance'};
139         }
140
141         $string .= "/" . $ident->{'type'};
142
143         if (defined $ident->{'type_instance'}) {
144                 $string .= "-" . $ident->{'type_instance'};
145         }
146         return $string;
147 }
148
149 =head1 COMMANDS
150
151 =over 4
152
153 =item B<GETVAL> I<Identifier>
154
155 =cut
156
157 sub putval {
158         my $sock = shift || return;
159         my $line = shift || return;
160
161         my $id = getid(\$line);
162
163         if (! $id) {
164                 print STDERR $sock->{'error'} . $/;
165                 return;
166         }
167
168         my ($time, @values) = split m/:/, $line;
169         return $sock->putval(%$id, time => $time, values => \@values);
170 }
171
172 =item B<PUTVAL> I<Identifier> I<Valuelist>
173
174 =cut
175
176 sub getval {
177         my $sock = shift || return;
178         my $line = shift || return;
179
180         my $id = getid(\$line);
181
182         if (! $id) {
183                 print STDERR $sock->{'error'} . $/;
184                 return;
185         }
186
187         my $vals = $sock->getval(%$id);
188
189         if (! $vals) {
190                 print STDERR $sock->{'error'} . $/;
191                 return;
192         }
193
194         foreach my $key (keys %$vals) {
195                 print "\t$key: $vals->{$key}\n";
196         }
197         return 1;
198 }
199
200 =item B<FLUSH> [B<timeout>=I<$timeout>] [B<plugin>=I<$plugin>[ ...]]
201
202 =cut
203
204 sub flush {
205         my $sock = shift || return;
206         my $line = shift;
207
208         my $res;
209
210         if (! $line) {
211                 $res = $sock->flush();
212         }
213         else {
214                 my %args = ();
215
216                 foreach my $i (split m/ /, $line) {
217                         my ($option, $value) = $i =~ m/^([^=]+)=(.+)$/;
218                         next if (! ($option && $value));
219
220                         if ($option eq "plugin") {
221                                 push @{$args{"plugins"}}, $value;
222                         }
223                         elsif ($option eq "timeout") {
224                                 $args{"timeout"} = $value;
225                         }
226                         elsif ($option eq "identifier") {
227                                 my $id = getid (\$value);
228                                 if (!$id)
229                                 {
230                                         print STDERR "Not a valid identifier: \"$value\"\n";
231                                         next;
232                                 }
233                                 push @{$args{"identifier"}}, $id;
234                         }
235                         else {
236                                 print STDERR "Invalid option \"$option\".\n";
237                                 return;
238                         }
239                 }
240
241                 $res = $sock->flush(%args);
242         }
243
244         if (! $res) {
245                 print STDERR $sock->{'error'} . $/;
246                 return;
247         }
248         return 1;
249 }
250
251 =item B<LISTVAL>
252
253 =cut
254
255 sub listval {
256         my $sock = shift || return;
257
258         my @res;
259
260         @res = $sock->listval();
261
262         if (! @res) {
263                 print STDERR $sock->{'error'} . $/;
264                 return;
265         }
266
267         foreach my $ident (@res) {
268                 print $ident->{'time'} . " " . putid($ident) . $/;
269         }
270         return 1;
271 }
272
273 =back
274
275 These commands follow the exact same syntax as described in
276 L<collectd-unixsock(5)>.
277
278 =head1 SEE ALSO
279
280 L<collectd(1)>, L<collectd-unisock(5)>
281
282 =head1 AUTHOR
283
284 Written by Sebastian Harl E<lt>sh@tokkee.orgE<gt>.
285
286 B<collectd> has been written by Florian Forster and others.
287
288 =head1 COPYRIGHT
289
290 Copyright (C) 2007 Sebastian Harl.
291
292 This program is free software; you can redistribute it and/or modify it under
293 the terms of the GNU General Public License as published by the Free Software
294 Foundation; only version 2 of the License is applicable.
295
296 =cut
297
298 # vim: set sw=4 ts=4 tw=78 noexpandtab :