Changeset 1043

Show
Ignore:
Timestamp:
07/24/06 11:43:05 (6 years ago)
Author:
ilmari
Message:

r8471@vesla: ilmari | 2006-07-23 21:26:12 +0100
Add Munin::Node::Runner and convert munin-run to use it.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • people/ilmari/modularisation-branch/ChangeLog

    r1014 r1043  
    11munin (repository) 
    22 
     3  * Node: Add Munin::Node::Runner and convert munin-run to use it. 
    34  * Plugins: Add module Munin::Plugin::SNMP and convert plugins to use it. 
    45  * Move Perl modules to {node,server}/lib/. 
  • people/ilmari/modularisation-branch/Makefile

    r1015 r1043  
    9090 
    9191        mkdir -p $(PERLLIB)/Munin/Plugin 
     92        mkdir -p $(PERLLIB)/Munin/Node 
    9293        $(INSTALL) -m 0644 build/node/lib/Munin/Plugin/SNMP.pm $(PERLLIB)/Munin/Plugin/ 
     94        $(INSTALL) -m 0644 build/node/lib/Munin/Node/Runner.pm $(PERLLIB)/Munin/Node/ 
    9395 
    9496        #TODO: 
     
    280282t/install:  
    281283        $(MAKE) clean install-node install-node-plugins CONFIG=t/Makefile.config INSTALL_PLUGINS=test 
     284        rmdir t/install/etc/plugin-conf.d 
     285        ln -s ../../plugin-conf.d t/install/etc/ 
    282286 
    283287.PHONY: install install-main install-node install-doc install-man build build-doc deb clean source_dist test 
  • people/ilmari/modularisation-branch/node/munin-run.in

    r1014 r1043  
    2121# 
    2222 
     23use lib qw(@@PERLLIB@@); 
    2324use strict; 
    24 use vars qw(@ISA); 
    2525use Getopt::Long; 
    26  
     26use Munin::Node::Runner qw(:all); 
    2727# "Clean" environment to disable taint-checking on the environment. We _know_ 
    2828# that the environment is insecure, but we want to let admins shoot themselves 
     
    3939        } 
    4040} 
    41  
    42 my %services; 
    43 my %nodes; 
    44 my $servicedir="@@CONFDIR@@/plugins"; 
    45 my $sconfdir="@@CONFDIR@@/plugin-conf.d"; 
    46 my $conffile="@@CONFDIR@@/munin-node.conf"; 
    47 my $sconffile=undef; 
    48 my $FQDN=""; 
    49 my $do_usage = 0; 
    50 my $DEBUG = 0; 
    51 my $do_version = 0; 
    52 my $VERSION="@@VERSION@@"; 
    53 my $defuser = getpwnam ("@@PLUGINUSER@@"); 
    54 my $defgroup= getgrnam ("@@GROUP@@"); 
    55 my $paranoia = 0; 
    56 my @ignores = (); 
    57  
    58 my %sconf  = (); 
     41delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; 
    5942 
    6043$do_usage=1  unless  
     
    124107} 
    125108 
    126  
    127  
    128109if ($do_version) 
    129110{ 
     
    143124} 
    144125 
    145 # Check permissions of configuration 
    146  
    147 if (!&check_perms ($servicedir) or !&check_perms ($conffile)) 
    148 
    149         die "Fatal error. Bailing out."; 
    150 
    151  
    152 if (! -f $conffile) { 
    153   print "ERROR: Cannot open $conffile\n"; 
    154   exit 1; 
    155 
    156  
    157 open FILE,$conffile or die "Cannot open $conffile\n"; 
    158 while (<FILE>) { 
    159   chomp; 
    160   s/#.*//;                # no comments 
    161   s/^\s+//;               # no leading white 
    162   s/\s+$//;               # no trailing white 
    163   next unless length;     # anything left? 
    164   /(^\w*)\s+(.*)/; 
    165   if (($1 eq "host_name" or $1 eq "hostname") and $2) 
    166   { 
    167       $FQDN=$2; 
    168   } 
    169   elsif (($1 eq "default_plugin_user" or $1 eq "default_client_user") and $2) 
    170   { 
    171       my $tmpid = $2; 
    172       my $defuser = &get_uid ($tmpid); 
    173       if (! defined ($defuser)) 
    174       { 
    175           die "Default user defined in \"$conffile\" does not exist ($tmpid)"; 
    176       } 
    177   } 
    178   elsif (($1 eq "default_plugin_group" or $1 eq "default_client_group") and $2) 
    179   { 
    180       my $tmpid = $2; 
    181       $defgroup = &get_gid ($tmpid); 
    182       if (! defined ($defgroup)) 
    183       { 
    184           die "Default group defined in \"$conffile\" does not exist ($tmpid)"; 
    185       } 
    186   } 
    187   elsif (($1 eq "paranoia") and defined $2) 
    188   { 
    189       if ("$2" eq "no" or "$2" eq "false" or "$2" eq "off" or "$2" eq "0") 
    190       { 
    191           $paranoia = 0; 
    192       }    
    193       else 
    194       { 
    195           $paranoia = 1; 
    196       }    
    197   }    
    198   elsif (($1 eq "ignore_file") and defined $2) 
    199   { 
    200           push @ignores, $2; 
    201   }    
    202 
    203  
    204 $FQDN ||= &get_fq_hostname; 
    205  
    206 $ENV{FQDN}=$FQDN; 
    207  
    208 &load_services; 
    209  
    210 exit; 
    211  
    212  
    213  
    214  
    215 ### over-ridden subs below 
    216  
    217 sub load_services { 
    218     if ($sconffile) 
    219     { 
    220         if (!&load_auth_file ("", $sconffile, \%sconf)) 
    221         { 
    222             warn "Something wicked happened while reading \"$sconffile\". Check the previous log lines for spesifics."; 
    223         } 
    224     } 
    225     else 
    226     { 
    227         if (opendir (DIR,$sconfdir)) 
    228         { 
    229 FILES: 
    230             for my $file (grep { -f "$sconfdir/$_" } readdir (DIR)) 
    231             { 
    232                 next if $file =~ m/^\./; # Hidden files 
    233                 next if $file !~ m/^([-\w.]+)$/; # Skip if any weird chars 
    234                 $file = $1; # Not tainted anymore. 
    235                 foreach my $regex (@ignores) 
    236                 { 
    237                         next FILES if $file =~ /$regex/; 
    238                 } 
    239                 if (!&load_auth_file ($sconfdir, $file, \%sconf)) 
    240                 { 
    241                     warn "Something wicked happened while reading \"$servicedir/$file\". Check the previous log lines for spesifics."; 
    242                 } 
    243             } 
    244             closedir (DIR); 
    245         } 
    246     } 
    247      
    248     opendir (DIR,$servicedir) || die "Cannot open plugindir: $servicedir $!"; 
    249 FILES: 
    250     for my $file (grep { -f "$servicedir/$_" } readdir(DIR)) { 
    251         next if $file =~ m/^\./; # Hidden files 
    252         next if $file =~ m/.conf$/; # Config files 
    253         next if $file !~ m/^([-\w.]+)$/; # Skip if any weird chars 
    254         $file = $1; # Not tainted anymore. 
    255         foreach my $regex (@ignores) 
    256         { 
    257                 next FILES if $file =~ /$regex/; 
    258         } 
    259         next if (! -x "$servicedir/$file"); # File not executeable 
    260         next unless ($file =~ /^$ARGV[0]$/); 
    261         print "# file: '$file'\n" if $DEBUG; 
    262         my $arg = undef; 
    263         if (defined $ARGV[1]) 
    264         { 
    265             if ($ARGV[1] =~ /^c/i) 
    266             { 
    267                 $arg = "config"; 
    268             } 
    269             elsif ($ARGV[1] =~ /^a/i) 
    270             { 
    271                 $arg = "autoconf"; 
    272             } 
    273             elsif ($ARGV[1] =~ /^snmp/i) 
    274             { 
    275                 $arg = "snmpconf"; 
    276             } 
    277             elsif ($ARGV[1] =~ /^s/i) 
    278             { 
    279                 $arg = "suggest"; 
    280             } 
    281         } 
    282         $services{$file}=1; 
    283         my @rows = run_service($file, $arg); 
    284         my $node = $FQDN; 
    285         for my $row (@rows) { 
    286           print "row: $row\n" if $DEBUG; 
    287           if ($row =~ m/^host_name (.+)$/) { 
    288             print "Found host_name, using it\n" if $DEBUG; 
    289             $node = $1; 
    290           } 
    291         } 
    292         $nodes{$node}{$file}=1; 
    293     } 
    294     closedir DIR; 
    295     print "ERROR: Could not execute plugin (plugin doesn't exist?).\n"; 
    296     exit 1; 
    297 
    298  
    299 sub run_service { 
    300   my ($service,$command) = @_; 
    301   $command ||=""; 
    302   my @lines = ();; 
    303   my $timed_out = 0; 
    304   if ($services{$service}) { 
    305     my $child = 0; 
    306     local $SIG{ALRM} = sub {  
    307       $timed_out = 1;  
    308     }; 
    309  
    310     # Setting environment 
    311     $sconf{$service}{user}    = &get_var (\%sconf, $service, 'user'); 
    312     $sconf{$service}{group}   = &get_var (\%sconf, $service, 'group'); 
    313     $sconf{$service}{command} = &get_var (\%sconf, $service, 'command'); 
    314     &get_var (\%sconf, $service, 'env', \%{$sconf{$service}{env}}); 
    315      
    316         if ($< == 0) # If root 
    317         { 
    318                 # Giving up gid egid uid euid 
    319                 my $u  = (defined $sconf{$service}{'user'}? 
    320                         $sconf{$service}{'user'}: 
    321                         $defuser); 
    322                 my $g  = $defgroup; 
    323                 my $gs = "$g $g" . 
    324                   (defined($sconf{$service}{'group'}) ?  
    325                    " $sconf{$service}{group}" : ""); 
    326  
    327                 print "# Want to run as euid/egid $u/$g\n" if $DEBUG; 
    328  
    329                 $( = $g    unless $g == 0; 
    330                 $) = $gs   unless $g == 0; 
    331                 $< = $u    unless $u == 0; 
    332                 $> = $u    unless $u == 0; 
    333  
    334                 if ($> != $u or $g != (split (' ', $)))[0]) 
    335                 { 
    336                 print "# Can't drop privileges. Bailing out. (wanted uid=",  
    337                 ($sconf{$service}{'user'} || $defuser), " gid=\"",  
    338                 $gs, "\"($g), got uid=$> gid=\"$)\"(", (split (' ', $)))[0], ").\n"; 
    339                 exit 1; 
    340                 } 
    341                 print "# Running as uid/gid/euid/egid $</$(/$>/$)\n" if $DEBUG; 
    342                 if (!&check_perms ("$servicedir/$service")) 
    343                 { 
    344                 print "# Error: unsafe permissions. Bailing out."; 
    345                 exit 1; 
    346                 } 
    347         } 
    348  
    349     # Setting environment... 
    350     if (exists $sconf{$service}{'env'} and 
    351             defined $sconf{$service}{'env'}) 
    352     { 
    353         foreach my $key (keys %{$sconf{$service}{'env'}}) 
    354         { 
    355             print "Setting environment $key=$sconf{$service}{env}{$key}\n" if $DEBUG; 
    356             $ENV{$key} = $sconf{$service}{env}{$key}; 
    357         } 
    358     } 
    359     if (exists $sconf{$service}{'command'} and 
    360         defined $sconf{$service}{'command'}) 
    361     { 
    362         my @run = (); 
    363         foreach my $t (@{$sconf{$service}{'command'}}) 
    364         { 
    365             if ($t =~ /^%c$/) 
    366             { 
    367                 push (@run, "$servicedir/$service", $command); 
    368             } 
    369             else 
    370             { 
    371                 push (@run, $t); 
    372             } 
    373         } 
    374         print STDERR "About to run \"", join (' ', @run), "\"\n" if $DEBUG; 
    375         print "About to run \"", join (' ', @run), "\"\n" if $DEBUG; 
    376         exec (@run) if @run; 
    377     } 
    378     else 
    379     { 
    380         print STDERR "DEBUG: About to exec \"$servicedir/$service\"." if $DEBUG; 
    381         if (!exec ("$servicedir/$service", $command)) 
    382         { 
    383             print "no (could not execute plugin)\n"; exit 1; 
    384         } 
    385     } 
    386   } else { 
    387     print "# Unknown service\n"; 
    388   } 
    389   chomp @lines; 
    390   return (@lines); 
    391 
    392  
    393 sub get_fq_hostname { 
    394     my $hostname; 
    395     eval { 
    396         require Net::Domain; 
    397         $hostname = Net::Domain::hostfqdn(); 
    398     }; 
    399     return $hostname if $hostname; 
    400  
    401     $hostname = `hostname`;  # Fall$ 
    402     chomp($hostname); 
    403     $hostname =~ s/\s//g; 
    404     return $hostname; 
    405 
    406  
    407  
    408 sub get_uid 
    409 
    410     my $user = shift; 
    411     return undef if (!defined $user); 
    412  
    413     if ($user !~ /\d/) 
    414     { 
    415         $user = getpwnam ($user); 
    416     } 
    417     return $user; 
    418 
    419  
    420 sub get_gid 
    421 
    422     my $group = shift; 
    423     return undef if (!defined $group); 
    424  
    425     if ($group !~ /\d/) 
    426     { 
    427         $group = getgrnam ($group); 
    428     } 
    429     return $group; 
    430 
    431  
    432 sub load_auth_file  
    433 
    434     my ($dir, $file, $sconf) = @_; 
    435     my $service = $file; 
    436  
    437     if (!defined $dir or !defined $file or !defined $sconf) 
    438     { 
    439         return undef; 
    440     } 
    441  
    442     return undef if (length $dir and !&check_perms ($dir)); 
    443     return undef if (!&check_perms ("$dir/$file")); 
    444  
    445     if (!open (IN, "$dir/$file")) 
    446     { 
    447         warn "Could not open file \"$dir/$file\" for reading ($!), skipping plugin\n"; 
    448         return undef; 
    449     } 
    450     while (<IN>) 
    451     { 
    452         chomp; 
    453         s/#.*$//; 
    454         next unless /\S/; 
    455         if (/^\s*\[([^\]]+)\]\s*$/) 
    456         { 
    457             $service = $1; 
    458         } 
    459         elsif (/^\s*user\s+(\S+)\s*$/) 
    460         { 
    461             my $tmpid = $1; 
    462             $sconf->{$service}{'user'} = &get_uid ($tmpid); 
    463             if (!defined $sconf->{$service}{'user'}) 
    464             { 
    465                 warn "User \"$tmpid\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
    466                 return undef; 
    467             } 
    468         } 
    469         elsif (/^\s*group\s+(.+)\s*$/) 
    470         { 
    471             my $tmpid = $1; 
    472             foreach my $group (split /\s*,\s*/, $tmpid) 
    473             { 
    474                 my $optional = 0; 
    475  
    476                 if ($group =~ /^\(([^)]+)\)$/) 
    477                 { 
    478                     $optional = 1; 
    479                     $group = $1; 
    480                 } 
    481  
    482                 my $g = &get_gid ($group); 
    483                 if (!defined $g and !$optional) 
    484                 { 
    485                     warn "Group \"$group\" in configuration file \"$dir/$file\" nonexistant. Skipping plugin."; 
    486                     return undef; 
    487                 } 
    488                 elsif (!defined $g and $optional) 
    489                 { 
    490                     print "DEBUG: Skipping \"$group\" (optional).\n" if $DEBUG; 
    491                     next; 
    492                 } 
    493                  
    494                 if (!defined $sconf->{$service}{'group'}) 
    495                 { 
    496                     $sconf->{$service}{'group'} = $g; 
    497                 } 
    498                 else 
    499                 { 
    500                     $sconf->{$service}{'group'} .= " $g"; 
    501                 } 
    502             } 
    503         } 
    504         elsif (/^\s*command\s+(.+)\s*$/) 
    505         { 
    506             @{$sconf->{$service}{'command'}} = split (/\s+/, $1); 
    507         } 
    508         elsif (/^\s*host_name\s+(.+)\s*$/) 
    509         { 
    510             $sconf->{$service}{'host_name'} = $1; 
    511         }  
    512         elsif (/^\s*timeout\s+(\d+)\s*$/) 
    513         { 
    514             $sconf->{$service}{'timeout'} = $1; 
    515             print STDERR "DEBUG: $service: setting timeout to $1\n" 
    516                 if $DEBUG; 
    517         } 
    518         elsif (/^\s*(allow)\s+(.+)\s*$/ or /^\s*(deny)\s+(.+)\s*$/) 
    519         { 
    520             push (@{$sconf->{$service}{'allow_deny'}}, [$1, $2]); 
    521                 print STDERR "DEBUG: Pushing allow_deny: $1, $2\n" if $DEBUG; 
    522         } 
    523         elsif (/^\s*env\s+([^=\s]+)\s*=\s*(.+)$/) 
    524         { 
    525             $sconf->{$service}{'env'}{$1} = $2; 
    526             print "Saving $service->env->$1 = $2...\n" if $DEBUG; 
    527                         warn "Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"env $1=$2\" should be rewritten to \"env.$1 $2\")."; 
    528         }  
    529         elsif (/^\s*env\.(\S+)\s+(.+)$/) 
    530         { 
    531             $sconf->{$service}{'env'}{$1} = $2; 
    532             print "Saving $service->env->$1 = $2...\n" if $DEBUG; 
    533         } 
    534         elsif (/^\s*(\w+)\s+(.+)$/) 
    535         { 
    536             $sconf->{$service}{'env'}{"lrrd_$1"} = $2; 
    537             print "Saving $service->env->lrrd_$1 = $2...\n" if $DEBUG;  
    538             warn "Warning: Deprecated format in \"$dir/$file\" under \"[$service]\" (\"$1 $2\" should be rewritten to \"env lrrd_$1=$2\")."; 
    539         }  
    540         elsif (/\S/) 
    541         { 
    542             warn "Warning: Unknown config option in \"$dir/$file\" under \"[$service]\": $_"; 
    543         } 
    544     } 
    545     close (IN); 
    546  
    547     return 1; 
    548 
    549  
    550 sub check_perms 
    551 
    552     my $target = shift; 
    553     my @stat; 
    554     return undef if (!defined $target); 
    555     return 1 if (!$paranoia); 
    556  
    557     if (! -e "$target") 
    558     { 
    559         warn "Failed to check permissions on nonexistant target: \"$target\""; 
    560         return undef; 
    561     } 
    562  
    563     @stat = stat ($target); 
    564     if (!$stat[4] == 0 or 
    565         ($stat[5] != 0 and $stat[2] & 00020) or 
    566         ($stat[2] & 00002)) 
    567     { 
    568         warn "Warning: \"$target\" has dangerous permissions (", sprintf ("%04o", $stat[2] & 07777), ")."; 
    569         return 0; 
    570     } 
    571  
    572     if (-f "$target") # Check dir as well 
    573     { 
    574         (my $dirname = $target) =~ s/[^\/]+$//; 
    575         return &check_perms ($dirname); 
    576     } 
    577  
    578     return 1; 
    579 
    580  
    581 sub get_var 
    582 
    583     my $sconf   = shift; 
    584     my $name    = shift; 
    585     my $var     = shift; 
    586     my $env     = shift; 
    587  
    588     if ($var eq 'env' and !defined $env) 
    589     { 
    590         %{$env} = (); 
    591     } 
    592      
    593     if ($var ne 'env' and exists $sconf->{$name}{$var}) 
    594     { 
    595         return $sconf->{$name}{$var}; 
    596     } 
    597     # Deciding environment 
    598     foreach my $wildservice (grep (/\*$/, reverse sort keys %{$sconf})) 
    599     { 
    600         (my $tmpservice = $wildservice) =~ s/\*$//; 
    601         next unless ($name =~ /^$tmpservice/); 
    602         print "Checking $wildservice...\n" if $DEBUG; 
    603  
    604         if ($var eq 'env') 
    605         { 
    606             if (exists $sconf->{$wildservice}{'env'}) 
    607             { 
    608                 foreach my $key (keys %{$sconf->{$wildservice}{'env'}}) 
    609                 { 
    610                     if (! exists $sconf->{$name}{'env'}{$key}) 
    611                     { 
    612                         $sconf->{$name}{'env'}{$key} = $sconf->{$wildservice}{'env'}{$key}; 
    613                         print "Saving $wildservice->$key\n" if $DEBUG; 
    614                     } 
    615                 } 
    616             } 
    617         } 
    618         else 
    619         { 
    620             if (! exists $sconf->{$name}{$var} and 
    621                     exists $sconf->{$wildservice}{$var}) 
    622             { 
    623                 return ($sconf->{$wildservice}{$var}); 
    624             } 
    625         } 
    626     } 
    627     return $env; 
    628 
    629  
    630  
    631  
    632 1; 
     126load_services(); 
     127print run_service(@ARGV); 
    633128 
    634129=head1 NAME