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 PUTVAL => \&putval,
61 GETVAL => \&getval,
62 FLUSH => \&flush,
63 LISTVAL => \&listval,
64 };
66 if (! $sock) {
67 print STDERR "Unable to connect to $path!\n";
68 exit 1;
69 }
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";
76 while (1) {
77 print "cussh> ";
78 my $line = <STDIN>;
80 last if (! $line);
82 chomp $line;
84 last if ($line =~ m/^quit$/i);
86 my ($cmd) = $line =~ m/^(\w+)\s*/;
87 $line = $';
89 next if (! $cmd);
90 $cmd = uc $cmd;
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 }
101 if (! $f->($sock, $line)) {
102 print STDERR "ERROR: Command failed!\n";
103 next;
104 }
105 }
107 $sock->destroy();
108 exit 0;
109 }
111 sub getid {
112 my $string = shift || return;
114 print $$string . $/;
115 my ($h, $p, $pi, $t, $ti) =
116 $$string =~ m/^(\w+)\/(\w+)(?:-(\w+))?\/(\w+)(?:-(\w+))?\s*/;
117 $$string = $';
119 return if ((! $h) || (! $p) || (! $t));
121 my %id = ();
123 ($id{'host'}, $id{'plugin'}, $id{'type'}) = ($h, $p, $t);
125 $id{'plugin_instance'} = $pi if ($pi);
126 $id{'type_instance'} = $ti if ($ti);
127 return \%id;
128 }
130 sub putid {
131 my $ident = shift || return;
133 my $string;
135 $string = $ident->{'host'} . "/" . $ident->{'plugin'};
137 if (defined $ident->{'plugin_instance'}) {
138 $string .= "-" . $ident->{'plugin_instance'};
139 }
141 $string .= "/" . $ident->{'type'};
143 if (defined $ident->{'type_instance'}) {
144 $string .= "-" . $ident->{'type_instance'};
145 }
146 return $string;
147 }
149 =head1 COMMANDS
151 =over 4
153 =item B<GETVAL> I<Identifier>
155 =cut
157 sub putval {
158 my $sock = shift || return;
159 my $line = shift || return;
161 my $id = getid(\$line);
163 if (! $id) {
164 print STDERR $sock->{'error'} . $/;
165 return;
166 }
168 my ($time, @values) = split m/:/, $line;
169 return $sock->putval(%$id, time => $time, values => \@values);
170 }
172 =item B<PUTVAL> I<Identifier> I<Valuelist>
174 =cut
176 sub getval {
177 my $sock = shift || return;
178 my $line = shift || return;
180 my $id = getid(\$line);
182 if (! $id) {
183 print STDERR $sock->{'error'} . $/;
184 return;
185 }
187 my $vals = $sock->getval(%$id);
189 if (! $vals) {
190 print STDERR $sock->{'error'} . $/;
191 return;
192 }
194 foreach my $key (keys %$vals) {
195 print "\t$key: $vals->{$key}\n";
196 }
197 return 1;
198 }
200 =item B<FLUSH> [B<timeout>=I<$timeout>] [B<plugin>=I<$plugin>[ ...]]
202 =cut
204 sub flush {
205 my $sock = shift || return;
206 my $line = shift;
208 my $res;
210 if (! $line) {
211 $res = $sock->flush();
212 }
213 else {
214 my %args = ();
216 foreach my $i (split m/ /, $line) {
217 my ($option, $value) = $i =~ m/^([^=]+)=(.+)$/;
218 next if (! ($option && $value));
220 if ($option eq "plugin") {
221 push @{$args{"plugins"}}, $value;
222 }
223 elsif ($option eq "timeout") {
224 $args{"timeout"} = $value;
225 }
226 else {
227 print STDERR "Invalid option \"$option\".\n";
228 return;
229 }
230 }
232 $res = $sock->flush(%args);
233 }
235 if (! $res) {
236 print STDERR $sock->{'error'} . $/;
237 return;
238 }
239 return 1;
240 }
242 =item B<LISTVAL>
244 =cut
246 sub listval {
247 my $sock = shift || return;
249 my @res;
251 @res = $sock->listval();
253 if (! @res) {
254 print STDERR $sock->{'error'} . $/;
255 return;
256 }
258 foreach my $ident (@res) {
259 print $ident->{'time'} . " " . putid($ident) . $/;
260 }
261 return 1;
262 }
264 =back
266 These commands follow the exact same syntax as described in
267 L<collectd-unixsock(5)>.
269 =head1 SEE ALSO
271 L<collectd(1)>, L<collectd-unisock(5)>
273 =head1 AUTHOR
275 Written by Sebastian Harl E<lt>sh@tokkee.orgE<gt>.
277 B<collectd> has been written by Florian Forster and others.
279 =head1 COPYRIGHT
281 Copyright (C) 2007 Sebastian Harl.
283 This program is free software; you can redistribute it and/or modify it under
284 the terms of the GNU General Public License as published by the Free Software
285 Foundation; only version 2 of the License is applicable.
287 =cut
289 # vim: set sw=4 ts=4 tw=78 noexpandtab :