From e726c32455628a0c657969f12e6116134045017e Mon Sep 17 00:00:00 2001 From: Ramon Novoa <rnovoa@artica.es> Date: Tue, 3 Jan 2012 17:18:45 +0000 Subject: [PATCH] 2012-01-03 Ramon Novoa <rnovoa@artica.es> * pandora_agent: Added support for intensive modules. git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@5317 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f --- pandora_agents/unix/ChangeLog | 4 + pandora_agents/unix/pandora_agent | 344 +++++++++++++++++------------- 2 files changed, 201 insertions(+), 147 deletions(-) diff --git a/pandora_agents/unix/ChangeLog b/pandora_agents/unix/ChangeLog index bb2997c8f9..e82c4fb65e 100644 --- a/pandora_agents/unix/ChangeLog +++ b/pandora_agents/unix/ChangeLog @@ -1,3 +1,7 @@ +2012-01-03 Ramon Novoa <rnovoa@artica.es> + + * pandora_agent: Added support for intensive modules. + 2011-12-19 Ramon Novoa <rnovoa@artica.es> * pandora_agent: Merged from 4.0 branch. Empty the broker PID array. diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 4b71af13f6..1bf89947f3 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -155,6 +155,8 @@ my %Conf = ( 'proxy_mode' => 0, 'proxy_max_connection' => 10, 'proxy_timeout' => 1, + 'intensive_interval' => 0, + 'timestamp' => 0, ); # Modules @@ -328,7 +330,10 @@ sub parse_conf_modules($) { 'cron_utimestamp' => 0, 'cron_interval' => -1, 'precondition' => [], - 'precon'=> 0 + 'is_intensive' => 0, + 'intensive_conditions' => [], + 'intensive_match' => 0, + 'timestamp' => 0, }; } elsif ($line =~ /^\s*module_name\s+(.+)$/) { $module->{'name'} = $1; @@ -338,7 +343,7 @@ sub parse_conf_modules($) { $module->{'type'} = $1; }elsif ($line =~ /^\s*module_precondition\s+(.*)$/) { my $action = $1; - $module->{'precon'} = 1; + # Numeric comparison if ($action =~ /^\s*([<>!=]+)\s+(\d+(?:\.\d*)?)\s+(.*)$/) { push (@{$module->{'precondition'}}, {'operator' => $1, 'value_1' => $2, 'command' => $3}); @@ -387,9 +392,6 @@ sub parse_conf_modules($) { $module->{'post_process'} = $1; } elsif ($line =~ /^\s*module_interval\s+(\d+)\s*$/) { $module->{'interval'} = $1; - - # Make the module run the first time - $module->{'counter'} = $1; } elsif ($line =~ /^\s*module_timeout\s+(\d+)\s*$/) { $module->{'timeout'} = $1; } elsif ($line =~ /^\s*module_save\s+(\w+)$/) { @@ -406,12 +408,38 @@ sub parse_conf_modules($) { } elsif ($action =~ /^\s*=~\s+(\S*)\s+(.*)$/) { push (@{$module->{'conditions'}}, {'operator' => '=~', 'value_1' => $1, 'command' => $2}); } + } elsif ($line =~ /^\s*module_intensive_condition\s+(.*)$/) { + my $action = $1; + + $module->{'is_intensive'} = 1; + + # Numeric comparison + if ($action =~ /^\s*([<>!=]+)\s+(\d+(?:\.\d*)?)\s*$/) { + push (@{$module->{'intensive_conditions'}}, {'operator' => $1, 'value_1' => $2}); + # Interval + } elsif ($action =~ /^\s*[(]\s*(\d+(?:\.\d*)?)\s*,\s*(\d+(?:\.\d*)?)\s*[)]\s*$/) { + push (@{$module->{'intensive_conditions'}}, {'operator' => '()', 'value_1' => $1, 'value_2' => $2}); + # Regular expression + } elsif ($action =~ /^\s*=~\s+(\S*)\s*$/) { + push (@{$module->{'intensive_conditions'}}, {'operator' => '=~', 'value_1' => $1}); + } } elsif ($line =~ /^\s*module_crontab\s+(((\*|(\d+(-\d+){0,1}))\s*){5}).*$/) { $module->{'cron'} = $1; } elsif ($line =~ /^\s*module_cron_interval\s+(\d+).*$/) { $module->{'cron_interval'} = $1; } elsif ($line =~ /^\s*module_end\s*$/) { next unless ($module->{'name'} ne '') and ($module->{'func'} != 0); + + # Set the intensive interval + if ($module->{'is_intensive'} == 1) { + $module->{'intensive_interval'} = $module->{'interval'}; + } else { + $module->{'intensive_interval'} = $module->{'interval'} * ($Conf{'interval'} / $Conf{'intensive_interval'}); + } + + # Make the module run the first time + $module->{'counter'} = $module->{'intensive_interval'}; + push (@Modules, $module); # Plugin } elsif ($line =~ /^\s*module_plugin\s+(.+)$/) { @@ -572,7 +600,11 @@ sub read_config (;$) { $Conf{'secondary_server_opts'} = '-x \'' . $Conf{'secondary_server_pwd'} . '\' ' . $Conf{'secondary_server_opts'} if ($Conf{'secondary_server_pwd'} ne ''); $Conf{'secondary_server_opts'} = '-c ' . $Conf{'secondary_server_opts'} if ($Conf{'secondary_server_ssl'} eq 'yes'); } - + + # Set the intensive interval + if ($Conf{'intensive_interval'} == 0) { + $Conf{'intensive_interval'} = $Conf{'interval'}; + } } ################################################################################# @@ -986,7 +1018,7 @@ sub exec_module ($) { } # Check module interval - if (++($module->{'counter'}) < $module->{'interval'}) { + if (++($module->{'counter'}) < $module->{'intensive_interval'}) { $ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); return; } @@ -996,6 +1028,11 @@ sub exec_module ($) { $ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); return; } + + # Check module preconditions + if (evaluate_module_preconditions ($module) == 0) { + return; + } # Reset module counter $module->{'counter'} = 0; @@ -1005,6 +1042,29 @@ sub exec_module ($) { # Run my @value = &{$module->{'func'}}($module); + if (defined ($value[0])) { + + # Evaluate intensive conditions + if ($module->{'is_intensive'} == 1) { + my $intensive_match = evaluate_module_intensive_conditions ($module, $value[0]); + if ($intensive_match == $module->{'intensive_match'} && $module->{'timestamp'} + $module->{'interval'} * $Conf{'interval'} > time ()) { + $ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); + return; + } + + # Update the time reference + $module->{'timestamp'} = time () if ($module->{'timestamp'} + $module->{'interval'} * $Conf{'interval'} <= time ()); + + # Update the intensive match status + $module->{'intensive_match'} = $intensive_match; + } + + # Evaluate module conditions + evaluate_module_conditions ($module, $value[0]); + + # Write the module XML + write_module_xml ($module, @value); + } # Save the module value if needed (only works for the first returned value) if ($module->{'save'} ne '') { @@ -1014,8 +1074,6 @@ sub exec_module ($) { $ENV{$module->{'save'}} = ''; } } - - write_module_xml ($module, @value); $ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); } @@ -1102,33 +1160,6 @@ sub load_parts () { $Parts{'__utimestamp__'} = $utimestamp; } -################################################################################ -# Execute the given command precondition. -################################################################################ -sub module_precondition_exec ($) { - my $module = shift; - my @data; - - # Check module parameters - return () unless ($module->{'params_precon'} ne ''); - - # Execute the command - if ($module->{'timeout'} == 0) { - @data = `$module->{'params_precon'} 2> $DevNull`; - } else { - my $cmd = quotemeta ($module->{'params_precon'}); - @data = `$Conf{'pandora_exec'} $module->{'timeout'} $cmd 2> $DevNull`; - } - - # Something went wrong or no data - return () unless ($? eq 0 && defined ($data[0])); - -# Evaluate module preconditions - evaluate_module_preconditions ($module, $data[0]); - - return @data; -} - ################################################################################ # Execute the given command. ################################################################################ @@ -1137,10 +1168,6 @@ sub module_exec ($) { my @data; my $exe; - $exe = evaluate_module_preconditions ($module); - - return @data if ($exe == 0); - # Check module parameters return () unless ($module->{'params'} ne ''); @@ -1155,9 +1182,6 @@ sub module_exec ($) { # Something went wrong or no data return () unless ($? eq 0 && defined ($data[0])); - # Evaluate module conditions - evaluate_module_conditions ($module, $data[0]); - return @data; } @@ -1334,29 +1358,33 @@ sub evaluate_module_preconditions ($) { my ($module) = @_; # Evaluate preconditions - if ($module->{'precon'}){ - - foreach my $precondition (@{$module->{'precondition'}}) { - - my $data = `$precondition->{'command'} 2> $DevNull`; - - { - # Do not display a warning if the output of the command is not numeric - no warnings; - if (($precondition->{'operator'} eq '>' && $data > $precondition->{'value_1'}) || - ($precondition->{'operator'} eq '<' && $data < $precondition->{'value_1'}) || - ($precondition->{'operator'} eq '=' && $data == $precondition->{'value_1'}) || - ($precondition->{'operator'} eq '!=' && $data != $precondition->{'value_1'}) || - ($precondition->{'operator'} eq '=~' && $data =~ /$precondition->{'value_1'}/) || - ($precondition->{'operator'} eq '()' && $data > $precondition->{'value_1'} && $data < $precondition->{'value_2'})) { - } else { - return 0; - } - }; + foreach my $precondition (@{$module->{'precondition'}}) { + my $data = `$precondition->{'command'} 2> $DevNull`; + return 0 if (evaluate_condition ($precondition, $data) == 0); + } + + return 1; +} + +################################################################################ +# Evaluate a module condition. Returns 1 if the condition matches, 0 otherwise. +################################################################################ +sub evaluate_condition ($$) { + my ($condition, $data) = @_; + + { + no warnings; + if (($condition->{'operator'} eq '>' && $data > $condition->{'value_1'}) || + ($condition->{'operator'} eq '<' && $data < $condition->{'value_1'}) || + ($condition->{'operator'} eq '=' && $data == $condition->{'value_1'}) || + ($condition->{'operator'} eq '!=' && $data != $condition->{'value_1'}) || + ($condition->{'operator'} eq '=~' && $data =~ /$condition->{'value_1'}/) || + ($condition->{'operator'} eq '()' && $data > $condition->{'value_1'} && $data < $condition->{'value_2'})) { + return 1; } } - return 1; + return 0; } @@ -1368,17 +1396,26 @@ sub evaluate_module_conditions ($$) { # Evaluate conditions foreach my $condition (@{$module->{'conditions'}}) { - if (($condition->{'operator'} eq '>' && $data > $condition->{'value_1'}) || - ($condition->{'operator'} eq '<' && $data < $condition->{'value_1'}) || - ($condition->{'operator'} eq '=' && $data == $condition->{'value_1'}) || - ($condition->{'operator'} eq '!=' && $data != $condition->{'value_1'}) || - ($condition->{'operator'} eq '=~' && $data =~ /$condition->{'value_1'}/) || - ($condition->{'operator'} eq '()' && $data > $condition->{'value_1'} && $data < $condition->{'value_2'})) { + if (evaluate_condition ($condition, $data) == 1) { `$condition->{'command'} 2> $DevNull`; } } } +################################################################################ +# Evaluate intensive conditions. +################################################################################ +sub evaluate_module_intensive_conditions ($$) { + my ($module, $data) = @_; + + # Evaluate conditions + foreach my $condition (@{$module->{'intensive_conditions'}}) { + return 0 if (evaluate_condition ($condition, $data) == 0); + } + + return 1; +} + ################################################################################ # Checks the module's cron string. Returns 1 if the module should be run, 0 if # not. @@ -1463,7 +1500,7 @@ sub write_module_xml ($@) { " <type>" . $module->{'type'} . "</type>\n"; # Interval - $Xml .= " <module_interval>" . $module->{'interval'} . "</module_interval>\n" if ($module->{'interval'} > 1); + $Xml .= " <module_interval>" . $module->{'interval'} . "</module_interval>\n"; # Min $Xml .= " <min>" . $module->{'min'} . "</min>\n" if (defined ($module->{'min'})); @@ -1736,51 +1773,8 @@ while (1) { } } - $Xml = "<?xml version='1.0' encoding='" . $Conf{'encoding'} . "'?>\n" . - "<agent_data description='" . $Conf{'description'} ."' group='" . $Conf{'group'} . - "' os_name='$OS' os_version='$OS_VERSION' interval='" . $Conf{'interval'} . - "' version='" . AGENT_VERSION . '(Build ' . AGENT_BUILD . ')' . ($Conf{'autotime'} eq '1' ? '' : "' timestamp='" . strftime ('%Y/%m/%d %H:%M:%S', localtime ())) . - "' agent_name='" . $Conf{'agent_name'} . "' timezone_offset='". $Conf{'timezone_offset'}; - - if (defined ($Conf{'address'})) { - $Xml .= "' address='" .$address; - } - - if (defined ($Conf{'parent_agent_name'})) { - $Xml .= "' parent_agent_name='" .$Conf{'parent_agent_name'}; - } - - # Check the gis mode (exec or manual). If exec script is defined, we execute it and get the coordenates - if (defined ($Conf{'gis_exec'}) && (-e $Conf{'gis_exec'})) { - my $coord_str = `$Conf{'gis_exec'}`; - chomp($coord_str); - my @coords = split(',',$coord_str); - # Check if lat and long are numeric - if (defined($coords[0]) && defined($coords[1]) && ($coords[0] =~ /^-?(\d+)\.(\d+)$|^-?(\d+)$/) && ($coords[1] =~ /^-?(\d+)\.(\d+)$|^-?(\d+)$/)) { - my $lat = $coords[0]; - my $long = $coords[1]; - - $Xml .= "' longitude='" .$long . "' latitude='" .$lat; - - if (defined ($coords[2])) { - my $alt = $coords[2]; - $Xml .= "' altitude='" .$alt; - } - if (defined ($Conf{'position_description'})) { - $Xml .= "' position_description='" .$Conf{'position_description'}; - } - } - } - elsif (defined ($Conf{'longitude'}) && defined ($Conf{'latitude'})) { - $Xml .= "' longitude='" .$Conf{'longitude'} . "' latitude='" .$Conf{'latitude'}; - if (defined ($Conf{'altitude'})) { - $Xml .= "' altitude='" .$Conf{'altitude'}; - } - if (defined ($Conf{'position_description'})) { - $Xml .= "' position_description='" .$Conf{'position_description'}; - } - } - $Xml .= "'>\n"; + # Clear the XML + $Xml = ""; # Execute modules foreach my $module (@Modules) { @@ -1801,51 +1795,103 @@ while (1) { } # Execute plugins - foreach my $plugin (@Plugins) { - - # Execute the plugin in a separate thread - if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1) { - $ThreadSem->down (); - my $thr = threads->create (\&exec_plugin, $plugin); - if (! defined ($thr)) { - $ThreadSem->up (); + if ($Conf{'timestamp'} + $Conf{'interval'} <= time ()) { + foreach my $plugin (@Plugins) { + + # Execute the plugin in a separate thread + if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1) { + $ThreadSem->down (); + my $thr = threads->create (\&exec_plugin, $plugin); + if (! defined ($thr)) { + $ThreadSem->up (); + } else { + $thr->detach(); + } + # Execute the plugin } else { - $thr->detach(); + exec_plugin ($plugin); } - # Execute the plugin - } else { - exec_plugin ($plugin); } } # Wait for all the threads $ThreadSem->down ($Conf{'agent_threads'}) if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); $ThreadSem->up ($Conf{'agent_threads'}) if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1); + + if ($Xml ne "" || $Conf{'timestamp'} + $Conf{'interval'} <= time ()) { + + # Update the time reference + $Conf{'timestamp'} = time () if ($Conf{'timestamp'} + $Conf{'interval'} <= time ()); + + # Compose the XML + my $xml_header = "<?xml version='1.0' encoding='" . $Conf{'encoding'} . "'?>\n" . + "<agent_data description='" . $Conf{'description'} ."' group='" . $Conf{'group'} . + "' os_name='$OS' os_version='$OS_VERSION' interval='" . $Conf{'interval'} . + "' version='" . AGENT_VERSION . '(Build ' . AGENT_BUILD . ')' . ($Conf{'autotime'} eq '1' ? '' : "' timestamp='" . strftime ('%Y/%m/%d %H:%M:%S', localtime ())) . + "' agent_name='" . $Conf{'agent_name'} . "' timezone_offset='". $Conf{'timezone_offset'}; - $Xml .= "</agent_data>"; + if (defined ($Conf{'address'})) { + $xml_header .= "' address='" .$address; + } + + if (defined ($Conf{'parent_agent_name'})) { + $xml_header .= "' parent_agent_name='" .$Conf{'parent_agent_name'}; + } + + # Check the gis mode (exec or manual). If exec script is defined, we execute it and get the coordenates + if (defined ($Conf{'gis_exec'}) && (-e $Conf{'gis_exec'})) { + my $coord_str = `$Conf{'gis_exec'}`; + chomp($coord_str); + my @coords = split(',',$coord_str); + # Check if lat and long are numeric + if (defined($coords[0]) && defined($coords[1]) && ($coords[0] =~ /^-?(\d+)\.(\d+)$|^-?(\d+)$/) && ($coords[1] =~ /^-?(\d+)\.(\d+)$|^-?(\d+)$/)) { + my $lat = $coords[0]; + my $long = $coords[1]; + + $xml_header .= "' longitude='" .$long . "' latitude='" .$lat; + + if (defined ($coords[2])) { + my $alt = $coords[2]; + $xml_header .= "' altitude='" .$alt; + } + if (defined ($Conf{'position_description'})) { + $xml_header .= "' position_description='" .$Conf{'position_description'}; + } + } + } + elsif (defined ($Conf{'longitude'}) && defined ($Conf{'latitude'})) { + $xml_header .= "' longitude='" .$Conf{'longitude'} . "' latitude='" .$Conf{'latitude'}; + if (defined ($Conf{'altitude'})) { + $xml_header .= "' altitude='" .$Conf{'altitude'}; + } + if (defined ($Conf{'position_description'})) { + $xml_header .= "' position_description='" .$Conf{'position_description'}; + } + } + $xml_header .= "'>\n"; + $Xml = $xml_header . $Xml . "</agent_data>"; - # Save XML data file - my $temp_file = $Conf{'temporal'} . '/' . $Conf{'agent_name'} . '.' . time () . '.data'; - open (TEMP_FILE, "> $temp_file") || error ("Could not write XML data file: $!"); - print TEMP_FILE $Xml; - close (TEMP_FILE); + # Save XML data file + my $temp_file = $Conf{'temporal'} . '/' . $Conf{'agent_name'} . '.' . time () . '.data'; + open (TEMP_FILE, "> $temp_file") || error ("Could not write XML data file: $!"); + print TEMP_FILE $Xml; + close (TEMP_FILE); - # Debug mode - if ($Conf{'debug'} eq '1') { - log_message ('debug', "Wrote XML data file '$temp_file'"); - log_message ('debug', "Wrote XML data file '$temp_file'", *STDOUT); - last; + # Debug mode + if ($Conf{'debug'} eq '1') { + log_message ('debug', "Wrote XML data file '$temp_file'"); + log_message ('debug', "Wrote XML data file '$temp_file'", *STDOUT); + last; + } + + # Send the XML data file + send_file ($temp_file, 1); + unlink ($temp_file); + } - - # Send the XML data file - send_file ($temp_file, 1); - unlink ($temp_file); - - # Cron mode - last if ($Conf{'cron_mode'} == 1); # Enable signal capture to break the Sleep interval on UDP signal - if ($Conf{'udp_server'} == 1){ + if ($Conf{'udp_server'} == 1) { $SIG{'INT'} = \&udp_server_signal; } @@ -1854,7 +1900,11 @@ while (1) { foreach my $broker_pid (@BrokerPid) { waitpid ($broker_pid, 0); } - sleep ($Conf{'interval'}); + + # Cron mode + last if ($Conf{'cron_mode'} == 1); + + sleep ($Conf{'intensive_interval'}); } # Finish if broker agent else {