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 };
67 if (! $sock) {
68 print STDERR "Unable to connect to $path!\n";
69 exit 1;
70 }
72 print "cussh version 0.2, Copyright (C) 2007-2008 Sebastian Harl\n"
73 . "cussh comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
74 . "and you are welcome to redistribute it under certain conditions.\n"
75 . "See the GNU General Public License 2 for more details.\n\n";
77 while (1) {
78 print "cussh> ";
79 my $line = <STDIN>;
81 last if (! $line);
83 chomp $line;
85 last if ($line =~ m/^quit$/i);
87 my ($cmd) = $line =~ m/^(\w+)\s*/;
88 $line = $';
90 next if (! $cmd);
91 $cmd = uc $cmd;
93 my $f = undef;
94 if (defined $cmds->{$cmd}) {
95 $f = $cmds->{$cmd};
96 }
97 else {
98 print STDERR "ERROR: Unknown command $cmd!\n";
99 next;
100 }
102 if (! $f->($sock, $line)) {
103 print STDERR "ERROR: Command failed!\n";
104 next;
105 }
106 }
108 $sock->destroy();
109 exit 0;
110 }
112 sub getid {
113 my $string = shift || return;
115 print $$string . $/;
116 my ($h, $p, $pi, $t, $ti) =
117 $$string =~ m#^([^/]+)/([^/-]+)(?:-([^/]+))?/([^/-]+)(?:-([^/]+))?\s*#;
118 $$string = $';
120 return if ((! $h) || (! $p) || (! $t));
122 my %id = ();
124 ($id{'host'}, $id{'plugin'}, $id{'type'}) = ($h, $p, $t);
126 $id{'plugin_instance'} = $pi if defined ($pi);
127 $id{'type_instance'} = $ti if defined ($ti);
128 return \%id;
129 }
131 sub putid {
132 my $ident = shift || return;
134 my $string;
136 $string = $ident->{'host'} . "/" . $ident->{'plugin'};
138 if (defined $ident->{'plugin_instance'}) {
139 $string .= "-" . $ident->{'plugin_instance'};
140 }
142 $string .= "/" . $ident->{'type'};
144 if (defined $ident->{'type_instance'}) {
145 $string .= "-" . $ident->{'type_instance'};
146 }
147 return $string;
148 }
150 =head1 COMMANDS
152 =over 4
154 =item B<HELP>
156 =cut
158 sub cmd_help {
159 print <<HELP;
160 Available commands:
161 HELP
162 PUTVAL
163 GETVAL
164 FLUSH
165 LISTVAL
167 See the embedded Perldoc documentation for details. To do that, run:
168 perldoc $0
169 HELP
170 return 1;
171 } # cmd_help
173 =item B<GETVAL> I<Identifier>
175 =cut
177 sub putval {
178 my $sock = shift || return;
179 my $line = shift || return;
181 my $id = getid(\$line);
183 if (! $id) {
184 print STDERR $sock->{'error'} . $/;
185 return;
186 }
188 my ($time, @values) = split m/:/, $line;
189 return $sock->putval(%$id, time => $time, values => \@values);
190 }
192 =item B<PUTVAL> I<Identifier> I<Valuelist>
194 =cut
196 sub getval {
197 my $sock = shift || return;
198 my $line = shift || return;
200 my $id = getid(\$line);
202 if (! $id) {
203 print STDERR $sock->{'error'} . $/;
204 return;
205 }
207 my $vals = $sock->getval(%$id);
209 if (! $vals) {
210 print STDERR $sock->{'error'} . $/;
211 return;
212 }
214 foreach my $key (keys %$vals) {
215 print "\t$key: $vals->{$key}\n";
216 }
217 return 1;
218 }
220 =item B<FLUSH> [B<timeout>=I<$timeout>] [B<plugin>=I<$plugin>[ ...]]
222 =cut
224 sub flush {
225 my $sock = shift || return;
226 my $line = shift;
228 my $res;
230 if (! $line) {
231 $res = $sock->flush();
232 }
233 else {
234 my %args = ();
236 foreach my $i (split m/ /, $line) {
237 my ($option, $value) = $i =~ m/^([^=]+)=(.+)$/;
238 next if (! ($option && $value));
240 if ($option eq "plugin") {
241 push @{$args{"plugins"}}, $value;
242 }
243 elsif ($option eq "timeout") {
244 $args{"timeout"} = $value;
245 }
246 elsif ($option eq "identifier") {
247 my $id = getid (\$value);
248 if (!$id)
249 {
250 print STDERR "Not a valid identifier: \"$value\"\n";
251 next;
252 }
253 push @{$args{"identifier"}}, $id;
254 }
255 else {
256 print STDERR "Invalid option \"$option\".\n";
257 return;
258 }
259 }
261 $res = $sock->flush(%args);
262 }
264 if (! $res) {
265 print STDERR $sock->{'error'} . $/;
266 return;
267 }
268 return 1;
269 }
271 =item B<LISTVAL>
273 =cut
275 sub listval {
276 my $sock = shift || return;
278 my @res;
280 @res = $sock->listval();
282 if (! @res) {
283 print STDERR $sock->{'error'} . $/;
284 return;
285 }
287 foreach my $ident (@res) {
288 print $ident->{'time'} . " " . putid($ident) . $/;
289 }
290 return 1;
291 }
293 =back
295 These commands follow the exact same syntax as described in
296 L<collectd-unixsock(5)>.
298 =head1 SEE ALSO
300 L<collectd(1)>, L<collectd-unisock(5)>
302 =head1 AUTHOR
304 Written by Sebastian Harl E<lt>sh@tokkee.orgE<gt>.
306 B<collectd> has been written by Florian Forster and others.
308 =head1 COPYRIGHT
310 Copyright (C) 2007 Sebastian Harl.
312 This program is free software; you can redistribute it and/or modify it under
313 the terms of the GNU General Public License as published by the Free Software
314 Foundation; only version 2 of the License is applicable.
316 =cut
318 # vim: set sw=4 ts=4 tw=78 noexpandtab :