Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- use strict;
- use warnings;
- use POSIX qw( setuid setgid );
- my %packages = (
- 'Fedora' => {
- 'Config::Simple' => "perl-Config-Simple",
- },
- );
- loadModules();
- # Define flag-variables
- my ( $user, $group );
- my ( $socket_path, $spool, $pid, $check_dir, $check_config, $cron_file, $log_file, $log_level );
- my ( $username, $password, $api_host, $api_key );
- my ( $download_checks, $auto_upgrade, $download_config, $redownload_config );
- my ( $new_checks, $bulk, $bulk_sleep, $bulk_pid, $daemon, $client, $help );
- my ( $proxy_daemon, $proxy_client, $proxy_address, $proxy_port, $proxy_pid );
- # Define internal variables
- my ( $listener, $configuration, $config, $socket, $uid, $child_pid, $status, $check, $checks, $distro );
- my $version = "0.1";
- my $continue = 1;
- $0 = "revmon";
- # Load all flags
- GetOptions (
- "u|user=s" => \$user,
- "g|group=s" => \$group,
- "S|socket=s" => \$socket_path,
- "s|spool=s" => \$spool,
- "p|pid=s" => \$pid,
- "e|check-dir=s" => \$check_dir,
- "l|cron-file=s" => \$cron_file,
- "J|check-config=s" => \$check_config,
- "L|log-file=s" => \$log_file,
- "V|log-level=s" => \$log_level,
- "U|username=s" => \$username,
- "P|password=s" => \$password,
- "A|api-host=s" => \$api_host,
- "K|api-key=s" => \$api_key,
- "D|download-checks" => \$download_checks,
- "a|auto-upgrade" => \$auto_upgrade,
- "C|download-config" => \$download_config,
- "E|redownload-config" => \$redownload_config,
- "i|new-checks" => \$new_checks,
- "b|bulk" => \$bulk,
- "B|bulk-sleep" => \$bulk_sleep,
- "d|daemon" => \$daemon,
- "c|client" => \$client,
- "check=s" => \$check,
- "proxy-daemon" => \$proxy_daemon,
- "proxy-client" => \$proxy_client,
- "proxy-address" => \$proxy_address,
- "proxy-port" => \$proxy_port,
- "help|h" => \$help,
- );
- if ($help) {
- help();
- }
- # Default configuration values
- my %default_config = (
- user => 'nobody',
- group => 'nogroup',
- socket_path => '/var/run/run/revmon.sock',
- spool => '/var/spool/revmon',
- pid => '/var/run/revmon.pid',
- check_dir => '/usr/share/revmon',
- cron_file => '/etc/cron.d/revmon',
- check_config => '/etc/revmon_checks.conf',
- log_file => '/var/log/revmon.log',
- log_level => '0',
- download_checks => 'true',
- auto_upgrade => 'true',
- download_config => 'true',
- bulk => 'false',
- bulk_sleep => '300',
- proxy_client => 'false',
- proxy_daemon => 'false',
- proxy_address => '127.0.0.1',
- proxy_port => '6872',
- );
- ############################################
- # Here is were the program actually starts #
- ############################################
- loadConfig();
- getDistro();
- # Define kill-actions
- $SIG{TERM} = \&cleanup;
- $SIG{INT} = \&cleanup;
- $SIG{QUIT} = \&cleanup;
- if ( $new_checks ) {
- parseCron();
- exit 0;
- }
- getConfigs();
- # Daemonize stuff
- if ( $daemon ) {
- pidCheck();
- # Local pids to get magic info for system users
- my ($p_name, $p_pass, $p_uid, $p_gid, $p_quota, $p_comment, $p_gcos, $p_dir, $p_shell, $p_expire) = getpwnam ( $user );
- $daemon = Proc::Daemon->new('pid_file' => $pid );
- $daemon->Init();
- # Fix ownership of pid-file
- chown $p_uid, $p_gid, $pid;
- # No need for socket in bulk-mode
- unlink( $socket_path );
- # Initilize UNIX-socket
- if ($proxy_daemon ne "true" && $bulk ne "true") {
- $listener = IO::Socket::UNIX->new(
- Type => SOCK_STREAM(),
- Local => $socket_path,
- Listen => SOMAXCONN(),
- )
- or die( "Can't create server socket: $!\n" );
- # Fix permissions
- chown $p_uid, $p_gid, $socket_path;
- dropPrivileges();
- # Listen for input
- while( $socket = $listener->accept() ) {
- chomp( my $line = <$socket> );
- sendResults($line);
- }
- }
- # Initilize proxy
- if ( $proxy_daemon eq "true") {
- $proxy_daemon = Proc::Daemon->new();
- $proxy_pid = $proxy_daemon->Init();
- unless ($proxy_pid) {
- dropPrivileges();
- $listener = IO::Socket::INET->new(Listen => 5,
- LocalAddr => $proxy_address,
- LocalPort => $proxy_port, #
- Proto => 'tcp');
- while ( $socket = $listener->accept() ) {
- chomp (my $line = <$socket> );
- spoolWrite($line);
- }
- }
- }
- # Initilize bulk-mode
- if ($bulk eq "true") {
- $bulk = Proc::Daemon->new();
- $bulk_pid = $bulk->Init();
- unless ( $bulk_pid ) {
- unless ( -e $spool ) {
- mkdir( $spool );
- chown $p_uid, $p_gid, $spool;
- }
- dropPrivileges();
- # Sleep according to bulk_sleep and call processBulk
- while ( $continue ) {
- sleep $bulk_sleep;
- processBulk();
- }
- }
- }
- while ( $continue ) {
- # Come up with somethng fun for the master process
- }
- }
- if ( $client ) {
- dropPrivileges();
- my $line = runCheck($check);
- chomp($line);
- $line = time . "," . $api_key . "," . $check . "," . $line;
- chomp($line);
- # Take input from check and sent to UNIX-socket or sent to proxy
- if ( $line ) {
- unless( $bulk eq "true" || $proxy_client eq "true") {
- print "regular mode\n";
- $socket = IO::Socket::UNIX->new(
- Type => SOCK_STREAM(),
- Peer => $socket_path,
- )
- or die( "Can't connect to server: $!\n" );
- print $socket $line;
- } elsif ($proxy_client eq "true") {
- $socket = IO::Socket::INET->new(
- PeerAddr => $proxy_address,
- PeerPort => $proxy_port,
- Proto => 'tcp',
- );
- print $socket $line;
- } else {
- spoolWrite($line);
- }
- exit( 0 );
- }
- }
- sub queryAuth {
- print "Username: ";
- $username = <STDIN>;
- chomp($username);
- print "Password: ";
- system "stty -echo -icanon";
- while (sysread STDIN, $a, 1) {
- if (ord($a) < 32) { last; }
- $password .= $a;
- syswrite STDOUT, "*", 1; # print asterisk
- }
- system "stty echo icanon";
- print "\n";
- print "Key: ";
- $api_key = <STDIN>;
- chomp($api_key);
- unless( $username || $password || $api_key ) {
- print "You didn't fill in all fields";
- exit(1);
- }
- setGlobalConf($username, $password, $api_key);
- }
- sub setGlobalConf {
- $username = $_[0];
- $password = $_[1];
- $api_key = $_[2];
- open ( CFGFILE, ">>$configuration" );
- print CFGFILE "username=${username}\n";
- print CFGFILE "password=${password}\n";
- print CFGFILE "key=${api_key}\n";
- if ( $api_host ) { print CFGFILE "api_host=" . $api_host . "\n"; }
- else { print CFGFILE "api_host=" . $default_config{'api_host'} . "\n"; }
- if ( $socket_path ) { print CFGFILE "socket_path=" . $socket_path . "\n"; }
- else { print CFGFILE "socket=" . $default_config{'socket'} . "\n"; }
- if ( $spool ) { print CFGFILE "spool=" . $spool . "\n"; }
- else { print CFGFILE "spool=" . $default_config{'spool'} . "\n"; }
- if ( $pid ) { print CFGFILE "pid=" . $pid . "\n"; }
- else { print CFGFILE "pid=" . $default_config{'pid'} . "\n"; }
- if ( $check_dir ) { print CFGFILE "check_dir=" . $check_dir . "\n"; }
- else { print CFGFILE "check_dir=" . $default_config{'check_dir'} . "\n"; }
- if ( $cron_file ) { print CFGFILE "cron_file=" . $cron_file . "\n"; }
- else { print CFGFILE "cron_file=" . $default_config{'cron_file'} . "\n"; }
- if ( $check_config ) { print CFGFILE "check_config=" . $check_config . "\n"; }
- else { print CFGFILE "check_config=" . $default_config{'check_config'} . "\n"; }
- if ( $log_file ) { print CFGFILE "log_file=" . $log_file . "\n"; }
- else { print CFGFILE "log_file=" . $default_config{'log_file'} . "\n"; }
- if ( $log_level ) { print CFGFILE "log_level=" . $log_level . "\n"; }
- else { print CFGFILE "log_level=" . $default_config{'log_level'} . "\n"; }
- if ( $download_checks ) { print CFGFILE "download_checks=false\n"; }
- else { print CFGFILE "download_checks=" . $default_config{'download_checks'} . "\n"; }
- if ( $auto_upgrade ) { print CFGFILE "auto_upgrade=false\n"; }
- else { print CFGFILE "auto_upgrade=" . $default_config{'auto_upgrade'} . "\n"; }
- if ( $download_config ) { print CFGFILE "download_config=false\n"; }
- else { print CFGFILE "download_config=" . $default_config{'download_config'} . "\n"; }
- if ( $bulk ) {
- print CFGFILE "bulk=true\n";
- if ( $bulk_sleep ) {
- print CFGFILE "bulk_sleep=" . $bulk_sleep . "\n";
- } else {
- print CFGFILE "bulk_sleep=" . $default_config{'bulk_sleep'} . "\n";
- }
- }
- if ( $proxy_client) {
- if ( $proxy_client ) { print CFGFILE "proxy_client=true\n"; }
- else { print CFGFILE "proxy_client=" . $default_config{'proxy_client'} . "\n"; }
- }
- if ( $proxy_daemon ) {
- if ( $proxy_daemon ) { print CFGFILE "proxy_daemon=true\n"; }
- else { print CFGFILE "proxy_daemon=" . $default_config{'proxy_daemon'} . "\n"; }
- if ( $proxy_address ) {
- print CFGFILE "proxy_address=" . $proxy_address . "\n";
- } else {
- print CFGFILE "proxy_address=" . $default_config{'proxy_address'} . "\n";
- }
- if ( $proxy_port ) {
- print CFGFILE "proxy_port=" . $proxy_port . "\n";
- } else {
- print CFGFILE "proxy_port=" . $default_config{'proxy_port'} . "\n";
- }
- }
- if ( $user ) { print CFGFILE "user=" . $user . "\n"; }
- else { print CFGFILE "user=" . $default_config{'user'} . "\n"; }
- if ( $group ) { print CFGFILE "group=" . $group . "\n"; }
- else { print CFGFILE "group=" . $default_config{'group'} . "\n"; }
- close ( CFGFILE );
- print "\nConfig saved, please re-run $0\n";
- exit(0);
- }
- sub help {
- print <<EOF;
- Revmon $version - 2013
- Usage: $0 [OPTION]
- Agent for revmon service
- -u, --user <username> Runtime username
- -g, --group <password> Runtime password
- -S, --socket </var/run/revmon.sock> Socket file path
- -s, --spool </var/spool/revmon> Socket directory path
- -p, --pid </var/run/revmon.pid> PID file path
- -c, --check-dir </usr/share/revmon> Check directory
- -l, --cron-file </etc/cron.d/revmon> CRON file
- -L, --log-file </var/log/revmon.log> Log file
- -U, --username <username> API username
- -P, --password <password> API password
- -A, --api-host <http://api.revmon.org> API host
- -K, --api-key <key> API key
- -d, --download-checks Disable automatic check downloads
- -a, --auto-upgrade Disable agent auto upgrade
- -C, --download-config Disable automatic config download
- -E, --redownload-config Download new configuration
- -i, --new-checks Check check directory for new checks
- -b, --bulk Run in bulk mode
- -B, --bulk-sleep Sleep interval for bulk-processing
- -d, --daemon Daemonize process
- -c, --client Run as client
- --proxy-daemon Run proxy daemon
- --proxy-client Run proxy client
- --proxy-address Address to listen on
- --proxy-port Port to listen on
- -h, --help Show this helpsection
- EOF
- exit;
- }
- sub getConfigs {
- if ( ! -e $cron_file || $redownload_config ) {
- $status = getstore( $api_host . "/" . $config->param('username').".cfg", $cron_file );
- die "Unable to download cron-file $status" unless is_success($status);
- }
- if ( ! -e $check_config || $redownload_config ) {
- $status = getstore( $api_host . "/check_configs/" . $config->param('username').".cfg", $check_config );
- die "Unable to download check-config $status" unless is_success($status);
- }
- }
- # Parse cron
- sub parseCron {
- my @checks;
- open (CRON, "<" . $cron_file);
- while (my $line = <CRON>) {
- my @line = split(/#/, $line);
- my $cron_check = $line[1];
- push ( @checks, $cron_check );
- }
- checkChecks(@checks);
- close (CRON);
- }
- # Function to handle verification of checks, downloads of new and repoting of unknowns
- sub checkChecks {
- map scalar $_, @_;
- # Create check_dir if not present
- unless ( -e $check_dir ) {
- mkdir $check_dir;
- }
- # Loop all checks available and download if not present on the system
- if ( @_ ) {
- foreach ( @_ ) {
- unless ( -e $check_dir . "/" . $_ ) {
- $status = getstore( $api_host . "/checks/" . $_, $check_dir . "/" . $_);
- die "Unable to download check-file $status" unless is_success($status);
- }
- }
- }
- # Check check_dir for unknown checks and initialize them
- opendir( CHECKDIR, $check_dir );
- while ( my $file = readdir( CHECKDIR ) ) {
- next if ($file =~ m/^\./);
- if ( ! grep (/$file/, @_ ) ) {
- open (TEST, ">>/tmp/test");
- print TEST "Found new check $file\n";
- print TEST initializeCheck($file);
- close (TEST);
- }
- }
- closedir(CHECKDIR);
- }
- # Execute check
- sub runCheck {
- $checks = new Config::Simple($check_config);
- $check = $_[0];
- my $checkresult = readpipe($check_dir . "/" . $checks->param($check));
- return $checkresult;
- }
- # Function to initialize checks
- sub initializeCheck {
- $check = $_[0];
- $check = readpipe($check_dir . "/" . $check . " -i");
- return $check;
- }
- # Load all configuration options
- sub loadConfig {
- # Path to configuration
- $configuration = "/etc/revmon.conf";
- # Check that config is present
- unless ( -e $configuration ) {
- queryAuth();
- }
- # Call configuration-file
- $config = new Config::Simple($configuration);
- # If value is defined by a flag, override configuration, if missing in config override by default_config
- unless ( $user ) { unless ( $user = $config->param( 'user' ) ) { $user = $default_config{'user'}; } }
- unless ( $group ) { unless ( $group = $config->param( 'group' ) ) { $group = $default_config{'group'}; } }
- unless ( $socket_path ) { unless ( $socket_path = $config->param( 'socket_path' ) ) { $socket_path = $default_config{'socket_path'}; } }
- unless ( $spool ) { unless ( $spool = $config->param( 'spool' ) ) { $spool = $default_config{'spool'}; } }
- unless ( $pid ) { unless ( $pid = $config->param( 'pid' ) ) { $pid = $default_config{'pid'}; } }
- unless ( $check_dir ) { unless ( $check_dir = $config->param( 'check_dir' ) ) { $check_dir = $default_config{'check_dir'}; } }
- unless ( $cron_file ) { unless ( $cron_file = $config->param( 'cron_file' ) ) { $cron_file = $default_config{'cron_file'}; } }
- unless ( $check_config ) { unless ( $check_config = $config->param( 'check_config' ) ) { $check_config = $default_config{'check_config'}; } }
- unless ( $log_file ) { unless ( $log_file = $config->param( 'log_file' ) ) { $log_file = $default_config{'log_file'}; } }
- unless ( $log_level ) { unless ( $log_level = $config->param( 'log_level' ) ) { $log_level = $default_config{'log_level'}; } }
- unless ( $username ) { $username = $config->param( 'username' ); }
- unless ( $password ) { $password = $config->param( 'password' ); }
- unless ( $api_host ) { unless ( $api_host = $config->param( 'api_host' ) ) { $api_host = $default_config{'api_host'}; } }
- unless ( $api_key ) { $api_key = $config->param( 'api_key' ); }
- unless ( $download_checks ) { unless ( $download_checks = $config->param( 'download_checks' ) ) { $download_checks = $default_config{'download_checks'}; } }
- unless ( $auto_upgrade ) { unless ( $auto_upgrade = $config->param( 'auto_upgrade' ) ) { $auto_upgrade = $default_config{'auto_upgrade'}; } }
- unless ( $download_config ) { unless ( $download_config = $config->param( 'download_config' ) ) { $download_config = $default_config{'download_config'}; } }
- unless ( $new_checks ) { unless ( $new_checks = $config->param( 'new_checks' ) ) { $new_checks = $default_config{'new_checks'}; } }
- unless ( $proxy_client ) { unless ( $proxy_client = $config->param( 'proxy_client' ) ) { $proxy_client = $default_config{'proxy_client'} }; }
- unless ( $proxy_daemon ) { unless ( $proxy_daemon = $config->param( 'proxy_daemon' ) ) { $proxy_daemon = $default_config{'proxy_daemon'} }; }
- # No need to define bulk_sleep unless bulk is defined
- unless ( $bulk ) {
- $bulk = $config->param( 'bulk' );
- unless ( $bulk_sleep ) { unless ( $bulk_sleep = $config->param( 'bulk_sleep' ) ) { $bulk_sleep = $default_config{'bulk_sleep'} }; }
- }
- # No need to define proxy-variables unless daemon or client is active
- unless ( $proxy_daemon || $proxy_client ) {
- unless ( $proxy_address ) { unless ( $proxy_address = $config->param( 'proxy_address' ) ) { $proxy_address = $default_config{'proxy_address'} }; }
- unless ( $proxy_port ) { unless ( $proxy_port = $config->param( 'proxy_port' ) ) { $proxy_port = $default_config{'proxy_port'} }; }
- }
- # Proxy must run as bulk
- if ( $proxy_daemon eq "true" ) {
- unless ( $bulk ) {
- print "When running proxy-daemon you must run checks in bulk, please update your config";
- exit 1;
- }
- }
- }
- # Function to drop privileges to unprivileged user
- sub dropPrivileges {
- $uid = getpwnam($user);
- $< = $> = $uid;
- if( $< != $uid ){
- die "Couldn't become uid \"$uid\"\n";
- }
- POSIX::setuid( $uid ) || die "Couldn't POSIX::setuid to \"$uid\" [$!]+n";
- }
- # Process availabl results in spool
- sub processBulk {
- my @lines;
- opendir( SPOOL, $spool );
- while ( my $file = readdir( SPOOL ) ) {
- next if ($file =~ m/^\./);
- open ( SPOOLFILE, "<", $spool . "/" . $file );
- push( @lines, <SPOOLFILE> );
- close( SPOOLFILE );
- unlink( $spool . "/" . $file );
- }
- closedir(SPOOL);
- if ( scalar( grep {defined $_} @lines ) > 0 ) {
- sendResults(@lines);
- }
- }
- # Sedn results to API-server
- sub sendResults {
- map scalar $_, @_;
- open (TEST, ">>/tmp/test");
- if ( @_ ) {
- foreach ( @_ ) {
- print TEST $_ . "\n";
- }
- } else {
- print TEST $_[0] . "\n";
- }
- close (TEST);
- }
- # Function to verify that the API is available
- sub checkAPI {
- }
- # Clean up pids and child processes
- sub cleanup {
- my @files = ($pid, $socket_path); unlink ( @files );
- $continue = 0;
- kill 'KILL', $bulk_pid;
- kill 'KILL', $proxy_pid;
- }
- # Load modules necessary to run the agent
- sub loadModules {
- my @install_packages;
- if ( ! eval { require Getopt::Long;1; } ) { push (@install_packages, "Getopt::Long"); }
- else { Getopt::Long->import(); Getopt::Long::Configure(qw{no_auto_abbrev no_ignore_case_always}); }
- if ( ! eval { require Proc::Daemon;1; } ) { push (@install_packages, "Proc::Daemon"); }
- else { Proc::Daemon->import(); }
- if ( ! eval { require Config::Simple;1; } ) { push (@install_packages, "Config::Simple"); }
- else { Config::Simple->import(); }
- if ( ! eval { require LWP::UserAgent;1; } ) { push (@install_packages, "LWP::UserAgent"); }
- else { LWP::UserAgent->import(); }
- if ( ! eval { require IO::Socket::UNIX;1; } ) { push (@install_packages, "IO::Socket::UNIX"); *SOCK_STREAM = sub() { die }; *SOMAXCONN = sub() { die } }
- else { IO::Socket::UNIX->import( qw( SOCK_STREAM SOMAXCONN ) ); }
- if ( ! eval { require IO::Socket::INET;1; } ) { push (@install_packages, "IO::Socket::INET"); }
- else { IO::Socket::INET->import(); }
- if ( ! eval { require LWP::Simple;1; } ) { push (@install_packages, "LWP::Simple"); *getstore = sub() { die }; *is_success = sub() { die } }
- else { LWP::Simple->import( qw( getstore is_success ) ); }
- if ( scalar( grep {defined $_} @install_packages ) > 0 ) {
- installModules(@install_packages);
- }
- }
- # Write check-results to spool
- sub spoolWrite {
- open( SPOOLFILE, ">", "$spool/" . time );
- print SPOOLFILE $_[0];
- close( SPOOLFILE );
- }
- sub pidCheck {
- if ( -e $pid ) {
- open (PIDFILE, "<$pid");
- my $pid_id = <PIDFILE>;
- close (PIDFILE);
- if (kill 0, $pid_id) {
- print "Daemon is already running\n";
- exit(1);
- } else {
- print "Daemon isn't running but the pidfile-still exists\n";
- unlink ($pid);
- exit(1);
- }
- }
- }
- sub logger {
- open (LOGFILE, "<$log_file");
- print LOGFILE $_[0];
- close (LOGFILE);
- }
- sub getDistro {
- open my $file, '<', "/etc/issue";
- my @distro = split(' ', <$file>);
- close $file;
- return $distro[0];
- }
- sub installModules {
- map scalar $_, @_;
- my @install_packages = @_;
- $distro = getDistro();
- my @install_string;
- if ( $distro eq "Fedora" || $distro eq "CentOS" ) {
- push( @install_string, "yum install" );
- } elsif ( $distro eq "Debian" || $distro eq "Ubuntu" ) {
- push( @install_string, "apt-get install" );
- }
- foreach (@install_packages) {
- push( @install_string, $packages{$distro}{$_} );
- }
- print "You've missing dependencies, do you wish to install them? [y/n]: ";
- my $answer = <STDIN>;
- chomp($answer);
- if ($answer eq "y" ) {
- system(join(' ', @install_string));
- } else {
- print "You're missing " . join(',', @install_packages) . ' please run "' . join(' ', @install_string) . '" to install them'."\n";
- }
- exit(1);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement