jeffa has asked for the wisdom of the Perl Monks concerning the following question:
I am working on a system monitoring agent. A server program
will run in the background on the machine to be monitored
and will listen to requests from clients on a specified port.
Once it receives a request, it will return the output of the
requested command (df, top, etc) to the client.
In my search I decided to use the Msg.pm and RPC.pm modules
written by Sriram Srinivasan in his Advanced Perl
Programming book (chpt 13).
My question is: has anybody in the monastary used these
modules and does anybody know of any issues associated with
them?
So far so good - they _seem_ to be working for me like a
charm. But I have a suspicious feeling that there might be
something else out there that might offer a better solution.
Plus, if anybody has any tips, I would appreciate them as
well.
Thanks,
Jeff
Re: RPC
by lhoward (Vicar) on Nov 08, 2000 at 00:46 UTC
|
I feel bad giving you a non-perl answer, but
why not just use
an SNMP agent (like the free UCDavis SNMP agent)? It is
already designed to do what you want
(take in network requests and
return status info; it has an
extension to run programs and return the results).
SNMP is a well-documented, RFC'd protocol designed to do this kind of
stuff. There are already perl modules that implement SNMP (so you can
easily do your client bit in perl). Using what is already built will probably save you a lot
of time and effort.
| [reply] |
|
Good answer, but the boss man wants to use TCP/IP - SNMP is
right out. Most of the time and effort I spend on this is
helping me understand networking in general - so I don't
mind - at least not yet! ;)
| [reply] |
RE (tilly) 1: RPC
by tilly (Archbishop) on Nov 08, 2000 at 06:34 UTC
|
Well a natural RPC protocol to use is called http. Really.
I would suggest a simple CGI script for this task. That
is a well-known protocol. Perl is able to be the client,
or you can view what you want from any machine using a
regular old browser... | [reply] |
|
Yeah, I gotta one up this. jeffa and I chatted about this
on the phone (welcome to Louisville, Jeff =) and I pointed
out that he was lucky merlyn was infiltrating the Java
types. Normally we leave it to him to shout HTTP eq instant_solution
in these cases.
To add to what tilly is saying here when you are simply
invoking a process on a remote box with real simple arguements
or none at all why throw IPC and the like at the problem? And
as he said, the benefit of HTTP is that you can use all kinds
of handy toys with it. And most, if you want a slightly
more strict data-markup, throw XML::Simple into the mix.
--
$you = new YOU;
honk() if $you->love(perl)
| [reply] |
|
Thanks for the input tilly and extremely - I totally
agree, and at some point I will probably drop this
RPC solution and use HTTP. I think the boss-man wanted to
give me a project to help me understand how networking and
sockets work in general, while at the same time helping me
to understand how our servers are set up (and get on the
good side of the sysadmins).
| [reply] |
Re: RPC
by reyjrar (Hermit) on Nov 08, 2000 at 03:47 UTC
|
oh yeah, and be careful.. make sure your script has an array of commands its allowed to run, that way no one can cat /etc/passwd through your script or something like that. if you're going to need to cehck files on the system.. it might pay to setup an array of those files, that way no one can access anything you don't want them to see via your script.
ie:
my @CMDS = ("ps", "top", "df", "vmstat", "blah");
my @FILES = ( "/etc/running.cfg", "/home/me/lastchecked.txt", "/var/l
+og/httpd/error_log");
my ($cmd, @ARGS) = split(/\s/, $input);
my $ok;
for(@CMDS) {
if($cmd eq $_) { $ok=1; }
}
if(!$ok) { die "tried to do something that wasn't cool: $input\n"; }
# then check for files in args
my $ok=0;
my $arg;
foreach $arg (@ARGS)
if(-e $arg) {
# we have a file
$file=true;
for(@FILES) {
if($arg eq $_) {
$ok=1;
}
}
}
}
if($file && !$ok) { die "tried to access a bad thing: $input\n"; }
# We're pretty much safe to continue
untested, but you get the idea.. make sure that only what you anticipate being input is actually input, that way you can pretty much secure the script.. also run it as a user with as little privileges as possible..
-brad | [reply] [d/l] |
|
Done and done!
I went overboard on this issue. The server has a config file
that it reads the actual *nix commands from, along with a
pneumonic name (i.e. inodes='df -i') and stores the key-value
pairs in a hash. When a client connects to the server, the
server sends the pneumonics, so the client never sees the
actual command.
# from server
sub get_commands() {
open CONF, 'query.conf' or die "No config file found: $!\n";
while (<CONF>) {
next if /^#/;
chomp;
my ($command, $query) = split(/\t/, $_);
$commands{$command} = $query;
}
close CONF;
}
sub send_commands {
my $rhost = shift;
my @commands = sort keys %commands;
&log_msg("Request for command list from $rhost");
return join(":", @commands);
}
# and from the client
sub get_commands {
my $answer;
my $i = 'a';
eval { $answer = $conn->rpc('send_commands', $host) };
die "Server $rhost not responding\n" if $@;
map { $commands{$i++} = $_ } split(":", $answer);
}
sub print_menu {
print '#' x 30, "\n";
map { print "# $_) $commands{$_}\n" } sort keys %commands;
print "# q) quit\n";
print '#' x 30, "\n";
print "Enter choice: ";
}
# the main processing loop for the client
$SIG{ALRM} = sub { die "TIMEOUT" };
&print_menu;
while (my $arg = <>) {
last if $arg =~ /q/;
chomp $arg;
my $answer;
eval {
alarm(10);
$answer = $conn->rpc('run', $commands{$arg}, $host) };
alarm(0);
};
warn "$queries{$arg} timed out - $host could be down\n" if $@ =~ /
+TIMEOUT/;
print $answer;
&print_menu;
}
Of course the major limitation at this point is only 'a' thru
'p' commands will be available. | [reply] [d/l] |
RE: RPC
by geektron (Curate) on Nov 08, 2000 at 02:22 UTC
|
i'd actually opt for IPC::Open2 or IPC::Open3.
errors in the process running remotely are captured w/ Open3.
i'd also suggest SNMP, but if that's not an option. . .
| [reply] |
|
|