#! /usr/bin/perl ############################## check_modules ## ############################################################################# # # Name : check_modules # Version : 1.0 # Date : Feb 16, 2012 # Author : Anton Hofland # Company : 2024Sight (www.2024sight.com) # Licence : GPL - http://www.fsf.org/licenses/gpl.txt # # This plugin was developed to monitor that required kernel modules have been loaded. In cases where a custom module is # required i.e. sensors that are installed in a system, and where this module is not part of the standard # distribution, this plug-in will monitor that it is missing after kernel upgrades and what not. It also warns of # unexpected modules. It has the concept of mandatory modules and optional modules. It has been noted that under some # circumstances, especially when there are updates, the kernel is asked to load additional modules. This will cause a # warning. By registering these modules as an optional module, the warning will be suppressed. But when the module is # not loaded, no critical error will be raised. # ############################################################################################################################# use strict; use Getopt::Long; use User::Utmp qw(:constants); my $Version = '1.0'; my $Module_Log_File = "/var/lib/nagios/logs/check_modules"; # Location of the log file my $O_Help = undef; # Print the help message my $O_Version = undef; # Print version my $O_Mandatory = undef; # Creating a log file with all mandatory modules my $O_Optional = undef; # Creating a log file with all optional modules my $O_Remove = undef; # Remove the the log file file my $O_Module_Name = undef; # Updating an individual module status my %Errors = ( 'OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3, 'DEPENDENT' => 4 ); ############################################################################################################################# sub print_version { print "check_modules version : $Version\n"; } ############################################################################################################################# sub print_usage { print "Usage: check_modules --help\n"; print " check_modules --version\n"; print " check_modules --remove\n"; print " check_modules --mandatory [module name ...]\n"; print " check_modules --optional [module name ...]\n"; } ############################################################################################################################# sub print_help { print "\n"; print "Nagios Plugin to check that all necessary kernel modules have been loaded\n"; print "\n"; print_usage(); print "\n"; print " --help print help message\n"; print " --version print version\n"; print " --remove Remove the log file to start from fresh\n"; print " --mandatory register a module as a mandatory module. If no module name\n"; print " has been provided, register all modules as mandatory modules\n"; print " --optional register a module as an optional module. If no module name\n"; print " has been provided, register all modules as optional modules\n"; print "\n\n"; print "This plugin creates a logfile which has to be writeable by the nagios system.\n"; print "The full path is: $Module_Log_File\n"; print "\n\n"; print "The Nagios check_modules plugin has been developed by 2024Sight (www.2024sight.com)\n"; print "\n"; } ############################################################################################################################# sub check_options { Getopt::Long::Configure("bundling"); GetOptions( 'h' => \$O_Help, 'help' => \$O_Help, 'v' => \$O_Version, 'version' => \$O_Version, 'm' => \$O_Mandatory, 'mandatory' => \$O_Mandatory, 'o' => \$O_Optional, 'optional' => \$O_Optional, 'r' => \$O_Remove, 'remove' => \$O_Remove ); if ( defined( $O_Help )) { print_help(); exit $Errors{ "UNKNOWN" }; } if ( defined( $O_Version )) { print_version(); exit $Errors{ "UNKNOWN" }; } if (( defined( $O_Mandatory )) || ( defined( $O_Optional ))) { while ( scalar( @ARGV ) > 0 ) { if ( defined( $O_Module_Name )) { $O_Module_Name = $O_Module_Name . " " . $ARGV[ 0 ]; } else { $O_Module_Name = $ARGV[ 0 ]; } shift( @ARGV ); } } else { if ( scalar( @ARGV ) > 0 ) { print_help(); exit $Errors{ "UNKNOWN" }; } } if (( defined( $O_Mandatory )) && ( defined( $O_Optional ))) { print_help(); exit $Errors{ "UNKNOWN" }; } } ################################# Main Program ############################################################################## my $Initialise = undef; # Flag to indicate whether we are creating the log my $Initialise_Flag = "M"; # A module is by default Mandatory my $Update = undef; # Flag to indicate whether we are updating the log my $Line = undef; my $Module_Name = undef; my $Missing_Mandatory_Modules = undef; # String containing a comma seperated list of missing, mandatory modules my $Missing_Optional_Modules = undef; # String containing a comma seperated list of missing, optional modules my $New_Modules = undef; # String containing a comma seperated list of new mandatory modules my $Result_String = undef; # String in which the output is collected my $Return_Code = undef; # Reurn code to be sent back to Nagios my %Modules_Loaded_Before; my %Modules_Loaded; ################################# Main Program ############################################################################## check_options(); if ( defined( $O_Remove )) { unlink( "$Module_Log_File" ); print "Removed $Module_Log_File\n"; exit $Errors{ "UNKNOWN" }; } if (( ! defined( $O_Mandatory )) && ( defined( $O_Optional ))) { $Initialise_Flag = "O"; } # # Read the file containing the log of modules loaded before. If the file does not exist we are # clearly initialising. Set the flag accordingly. # if ( open( MODULES, "$Module_Log_File" )) { if (( defined( $O_Mandatory )) || ( defined( $O_Optional ))) { $Initialise = 0; $Update = 1; } else { $Initialise = 0; $Update = 0; } while ( $Line = ) { chomp( $Line ); if ( $Line =~ /^(\w+)$/ ) { $Module_Name = $1; $Modules_Loaded_Before{ $Module_Name } = $Initialise_Flag; } elsif ( $Line =~ /^(\w+);(\w+)$/ ) { $Module_Name = $1; $Modules_Loaded_Before{ $Module_Name } = $2 } } close( MODULES ); } else { $Initialise = 1; $Update = 0; } # # Read which modules are currently loaded in the kernel # if ( ! open( MODULES, "/proc/modules" )) { print "Could not open /proc/modules\n"; exit $Errors{ "UNKNOWN" }; } while ( $Line = ) { my $Module_Name = undef; if ( $Line =~ /^(\w+)/ ) { $Module_Name = $1; $Modules_Loaded{ $Module_Name } = $Initialise_Flag; } } close MODULES; # # Then check if we are creating or updating the log file. If we are then just dump the list of # modules in a sorted format in a log file with the mandtory or optional flag so that we can # compare against this the next time round. If the file does not exist, we assume it has to be # created and all modules found are mandatory. # if ( $Initialise ) { if ( defined( $O_Module_Name )) { print_help(); exit $Errors{ "UNKNOWN" }; } if ( ! open( MODULES, ">$Module_Log_File" )) { print "Could not create $Module_Log_File\n"; exit $Errors{ "UNKNOWN" }; } for $Module_Name ( sort keys %Modules_Loaded ) { print MODULES "$Module_Name;$Initialise_Flag\n"; } close MODULES; print "Created $Module_Log_File\n"; exit $Errors{ "UNKNOWN" }; } # # We are not initialising. If we are updating, then save the file again and exit. If we # are not updating, then compare whether the modules loaded before are the ones loaded now. # Keep track of missing modules and also of new modules which appeared. # if ( $Update ) { if ( defined( $O_Module_Name )) { for $Module_Name ( split( ' ', $O_Module_Name )) { if ( ! defined( $Modules_Loaded_Before{ $Module_Name } )) { print "Adding $Module_Name; "; } else { print "Updating $Module_Name; "; } $Modules_Loaded_Before{ $Module_Name } = $Initialise_Flag; } } else { for $Module_Name ( keys %Modules_Loaded_Before ) { $Modules_Loaded_Before{ $Module_Name } = $Initialise_Flag; } } if ( ! open( MODULES, ">$Module_Log_File" )) { print "Could not create $Module_Log_File\n"; exit $Errors{ "UNKNOWN" }; } for $Module_Name ( sort keys %Modules_Loaded_Before ) { print MODULES "$Module_Name;$Modules_Loaded_Before{ $Module_Name }\n"; } close MODULES; print "Updated $Module_Log_File\n"; exit $Errors{ "UNKNOWN" }; } ############################################################################################################################# # # We got here. That means we are checking instead of updating our configuration. At this point Modules_Load contains the # list of kernel loaded modules. Modules_Load_Before contains a list of previously loaded modules and an indication whether # a module is mandatory or optional. We will raise a critical error of missing mandatory modules. We will notify missing # optional modules. We will also warn of new modules. # ############################################################################################################################# for $Module_Name ( keys %Modules_Loaded_Before ) { if ( defined( $Modules_Loaded{ $Module_Name } )) { delete( $Modules_Loaded{ $Module_Name } ); delete( $Modules_Loaded_Before{ $Module_Name } ); } } for $Module_Name ( sort keys %Modules_Loaded_Before ) { if ( $Modules_Loaded_Before{ $Module_Name } =~ "M" ) { if ( defined( $Missing_Mandatory_Modules )) { $Missing_Mandatory_Modules .= " " . $Module_Name; } else { $Missing_Mandatory_Modules = $Module_Name; } } else { if ( defined( $Missing_Optional_Modules )) { $Missing_Optional_Modules .= " " . $Module_Name; } else { $Missing_Optional_Modules = $Module_Name; } } } for $Module_Name ( sort keys %Modules_Loaded ) { if ( defined( $New_Modules )) { $New_Modules .= " " . $Module_Name; } else { $New_Modules = $Module_Name; } } if ( defined( $Missing_Optional_Modules )) { $Result_String = "Missing Optional Modules: " . $Missing_Optional_Modules; $Return_Code = "OK"; } if ( defined( $New_Modules )) { if ( defined( $Result_String )) { $Result_String = "New Modules: " . $New_Modules . "; " . $Result_String; } else { $Result_String = "New Modules: " . $New_Modules; } $Return_Code = "WARNING"; } if ( defined( $Missing_Mandatory_Modules )) { if ( defined( $Result_String )) { $Result_String = "Missing Mandatory Modules: " . $Missing_Mandatory_Modules . "; " . $Result_String; } else { $Result_String = "Missing Mandatory Modules: " . $Missing_Mandatory_Modules; } $Return_Code = "CRITICAL"; } if ( ! defined( $Result_String )) { $Result_String = "All Modules loaded"; $Return_Code = "OK"; } print "$Result_String\n"; exit $Errors{ $Return_Code };