From 883dd23579329203ad3466d4e4cb705332f08574 Mon Sep 17 00:00:00 2001 From: vgilc Date: Tue, 21 Jun 2011 11:06:47 +0000 Subject: [PATCH] 2011-06-21 Vanessa Gil * win32/pandora_windows_service.cc win32/modules/pandora_module.cc win32/modules/pandora_module.h win32/modules/pandora_module_factory.cc unix/pandora_agent: Allow the windows and unix agent to include preconditions on modules. git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@4474 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f --- pandora_agents/ChangeLog | 8 + pandora_agents/unix/pandora_agent | 82 +++++- .../win32/modules/pandora_module.cc | 251 +++++++++++++++++- pandora_agents/win32/modules/pandora_module.h | 16 ++ .../win32/modules/pandora_module_factory.cc | 25 +- .../win32/pandora_windows_service.cc | 5 + 6 files changed, 379 insertions(+), 8 deletions(-) diff --git a/pandora_agents/ChangeLog b/pandora_agents/ChangeLog index 04ffe74125..f88b5a7da1 100644 --- a/pandora_agents/ChangeLog +++ b/pandora_agents/ChangeLog @@ -1,3 +1,11 @@ +2011-06-21 Vanessa Gil + + * win32/pandora_windows_service.cc + win32/modules/pandora_module.cc + win32/modules/pandora_module.h + win32/modules/pandora_module_factory.cc + unix/pandora_agent: Allow the windows and unix agent to include preconditions on modules. + 2011-06-09 Vanessa Gil * unix/pandora_agent: Clean the code: parse configuration files. diff --git a/pandora_agents/unix/pandora_agent b/pandora_agents/unix/pandora_agent index 44b94e2f2d..a2c9608fcc 100755 --- a/pandora_agents/unix/pandora_agent +++ b/pandora_agents/unix/pandora_agent @@ -16,7 +16,7 @@ Version 3.2 =head1 USAGE -C<< pandora_agent F >> +<< pandora_agent F >> =cut @@ -314,7 +314,9 @@ sub parse_conf_modules($) { 'conditions' => [], 'cron' => '', 'cron_utimestamp' => 0, - 'cron_interval' => -1 + 'cron_interval' => -1, + 'precondition' => [], + 'precon'=> 0 }; } elsif ($line =~ /^\s*module_name\s+(.+)$/) { $module->{'name'} = $1; @@ -322,6 +324,19 @@ sub parse_conf_modules($) { $module->{'description'} = $1; } elsif ($line =~ /^\s*module_type\s+(\S+)\s*$/) { $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}); + # Interval + } elsif ($action =~ /^\s*[(]\s*(\d+\.\d*)\s*,\s*(\d+\.\d*)\s*[)]\s+(.*)$/) { + push (@{$module->{'precondition'}}, {'operator' => '()', 'value_1' => $1, 'value_2' => $2, 'command' => $3}); + # Regular expression + } elsif ($action =~ /^\s*=~\s+(\S*)\s+(.*)$/) { + push (@{$module->{'precondition'}}, {'operator' => '=~', 'value_1' => $1, 'command' => $2}); + } } elsif ($line =~ /^\s*module_exec\s+(.+)$/) { $module->{'func'} = \&module_exec; $module->{'params'} = $1; @@ -1002,13 +1017,45 @@ 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. ################################################################################ sub module_exec ($) { my $module = shift; my @data; + my $exe; + $exe = evaluate_module_preconditions ($module); + + return @data if ($exe == 0); + # Check module parameters return () unless ($module->{'params'} ne ''); @@ -1192,6 +1239,37 @@ sub module_freepercentmemory ($) { return sprintf (("%d", $avail * 100 / $total)); } +################################################################################ +# Evaluate and execute module preconditions. +################################################################################ +sub evaluate_module_preconditions ($) { + my ($module) = @_; + my $exe = 1; + + # Evaluate preconditions + if ($module->{'precon'}){ + + foreach my $precondition (@{$module->{'precondition'}}) { + + my $data = `$precondition->{'command'} 2> $DevNull`; + + 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'})) { + $exe = 1; + } else { + $exe = 0; + return $exe; + } + } + } + return $exe; +} + + ################################################################################ # Evaluate and execute module conditions. ################################################################################ diff --git a/pandora_agents/win32/modules/pandora_module.cc b/pandora_agents/win32/modules/pandora_module.cc index 0dcee764dc..ab2379f60b 100644 --- a/pandora_agents/win32/modules/pandora_module.cc +++ b/pandora_agents/win32/modules/pandora_module.cc @@ -25,6 +25,8 @@ #include #include +#define BUFSIZE 4096 + using namespace Pandora; using namespace Pandora_Modules; using namespace Pandora_Strutils; @@ -50,6 +52,7 @@ Pandora_Module::Pandora_Module (string name) { this->async = false; this->data_list = NULL; this->inventory_list = NULL; + this->precondition_list = NULL; this->condition_list = NULL; this->cron = NULL; } @@ -61,11 +64,29 @@ Pandora_Module::Pandora_Module (string name) { */ Pandora_Module::~Pandora_Module () { Condition *cond = NULL; + Precondition *precond = NULL; list::iterator iter; + list::iterator iter_pre; /* Clean data lists */ this->cleanDataList (); + /* Clean precondition list */ + if (this->precondition_list != NULL && this->precondition_list->size () > 0) { + iter_pre = this->precondition_list->begin (); + for (iter_pre = this->precondition_list->begin (); + iter_pre != this->precondition_list->end (); + iter++) { + /* Free regular expressions */ + precond = *iter_pre; + if (precond->string_value != "") { + regfree (&(precond->regexp)); + } + delete (*iter_pre); + } + delete (this->precondition_list); + } + /* Clean condition list */ if (this->condition_list != NULL && this->condition_list->size () > 0) { iter = this->condition_list->begin (); @@ -674,6 +695,63 @@ Pandora_Module::getSave () { return this->save; } +/** + * Adds a new precondition to the module. + * + * @param precondition string. + */ +void +Pandora_Module::addPrecondition (string precondition) { + Precondition *precond; + char operation[256], string_value[1024], command[1024]; + + /* Create the precondition list if it does not exist */ + if (this->precondition_list == NULL) { + this->precondition_list = new list (); + } + + /* Create the new precondition */ + precond = new Precondition; + if (precond == NULL) { + return; + } + + precond->value_1 = 0; + precond->value_2 = 0; + + /* Numeric comparison */ + if (sscanf (precondition.c_str (), "%255s %lf %1023[^\n]s", operation, &(precond->value_1), command) == 3) { + precond->operation = operation; + precond->command = command; + precond->command = "cmd.exe /c \"" + precond->command + "\""; + this->precondition_list->push_back (precond); + return; + + /* Regular expression */ + } else if (sscanf (precondition.c_str (), "=~ %1023s %1023[^\n]s", string_value, command) == 2) { + precond->operation = "=~"; + precond->string_value = string_value; + precond->command = command; + if (regcomp (&(precond->regexp), string_value, 0) != 0) { + pandoraDebug ("Invalid regular expression %s", string_value); + delete (precond); + return; + } + this->precondition_list->push_back (precond); + + /* Interval */ + } else if (sscanf (precondition.c_str (), "(%lf , %lf) %1023[^\n]s", &(precond->value_1), &(precond->value_2), command) == 3) { + precond->operation = "()"; + precond->command = command; + this->precondition_list->push_back (precond); + } else { + pandoraDebug ("Invalid module condition: %s", precondition.c_str ()); + delete (precond); + return; + } +return; +} + /** * Adds a new condition to the module. * @@ -701,7 +779,7 @@ Pandora_Module::addCondition (string condition) { if (sscanf (condition.c_str (), "%255s %lf %1023[^\n]s", operation, &(cond->value_1), command) == 3) { cond->operation = operation; cond->command = command; - this->condition_list->push_back (cond); + this->condition_list->push_back (cond); /* Regular expression */ } else if (sscanf (condition.c_str (), "=~ %1023s %1023[^\n]s", string_value, command) == 2) { cond->operation = "=~"; @@ -712,7 +790,7 @@ Pandora_Module::addCondition (string condition) { delete (cond); return; } - this->condition_list->push_back (cond); + this->condition_list->push_back (cond); /* Interval */ } else if (sscanf (condition.c_str (), "(%lf , %lf) %1023[^\n]s", &(cond->value_1), &(cond->value_2), command) == 3) { cond->operation = "()"; @@ -723,11 +801,174 @@ Pandora_Module::addCondition (string condition) { delete (cond); return; } - - /* Run commands through cmd.exe */ - cond->command = "cmd.exe /c \"" + cond->command + "\""; } +/** + * Evaluates and executes module preconditions. + */ +int +Pandora_Module::evaluatePreconditions () { + STARTUPINFO si; + PROCESS_INFORMATION pi; + DWORD retval, dwRet; + SECURITY_ATTRIBUTES attributes; + HANDLE out, new_stdout, out_read, job; + string working_dir; + Precondition *precond = NULL; + float float_output; + list::iterator iter; + unsigned char run; + int exe = 1; + string output; + + if (this->precondition_list != NULL && this->precondition_list->size () > 0) { + + iter = this->precondition_list->begin (); + for (iter = this->precondition_list->begin (); + iter != this->precondition_list->end (); + iter++) { + + precond = *iter; + run = 0; + + + /* Set the bInheritHandle flag so pipe handles are inherited. */ + attributes.nLength = sizeof (SECURITY_ATTRIBUTES); + attributes.bInheritHandle = TRUE; + attributes.lpSecurityDescriptor = NULL; + + /* Create a job to kill the child tree if it become zombie */ + /* CAUTION: In order to compile this, WINVER should be defined to 0x0500. + This may need no change, since it was redefined by the + program, but if needed, the macro is defined + in */ + job = CreateJobObject (&attributes, this->module_name.c_str ()); + if (job == NULL) { + pandoraLog ("CreateJobObject bad. Err: %d", GetLastError ()); + this->has_output = false; + return 0; + } + + /* Get the handle to the current STDOUT. */ + out = GetStdHandle (STD_OUTPUT_HANDLE); + + if (! CreatePipe (&out_read, &new_stdout, &attributes, 0)) { + pandoraLog ("CreatePipe failed. Err: %d", GetLastError ()); + this->has_output = false; + return 0; + } + + /* Ensure the read handle to the pipe for STDOUT is not inherited */ + SetHandleInformation (out_read, HANDLE_FLAG_INHERIT, 0); + + /* Set up members of the STARTUPINFO structure. */ + ZeroMemory (&si, sizeof (si)); + GetStartupInfo (&si); + + si.cb = sizeof (si); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + si.hStdError = new_stdout; + si.hStdOutput = new_stdout; + + /* Set up members of the PROCESS_INFORMATION structure. */ + ZeroMemory (&pi, sizeof (pi)); + pandoraDebug ("Executing: %s", precond->command.c_str ()); + + /* Set the working directory of the process. It's "utils" directory + to find the GNU W32 tools */ + working_dir = getPandoraInstallDir () + "util\\"; + + /* Create the child process. */ + if (! CreateProcess (NULL, (CHAR *) precond->command.c_str (), NULL, + NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, + working_dir.c_str (), &si, &pi)) { + pandoraLog ("Pandora_Module_Exec: %s CreateProcess failed. Err: %d", + this->module_name.c_str (), GetLastError ()); + this->has_output = false; + } else { + char buffer[BUFSIZE + 1]; + unsigned long read, avail; + + if (! AssignProcessToJobObject (job, pi.hProcess)) { + pandoraLog ("Could not assigned proccess to job (error %d)", + GetLastError ()); + } + ResumeThread (pi.hThread); + + /*string output;*/ + int tickbase = GetTickCount(); + while ( (dwRet = WaitForSingleObject (pi.hProcess, 500)) != WAIT_ABANDONED ) { + PeekNamedPipe (out_read, buffer, BUFSIZE, &read, &avail, NULL); + if (avail > 0) { + ReadFile (out_read, buffer, BUFSIZE, &read, NULL); + buffer[read] = '\0'; + output += (char *) buffer; + } + + float_output = atof(output.c_str()); + + if (dwRet == WAIT_OBJECT_0) { + break; + } else if(this->getTimeout() < GetTickCount() - tickbase) { + /* STILL_ACTIVE */ + TerminateProcess(pi.hThread, STILL_ACTIVE); + pandoraLog ("Pandora_Module_Exec: %s timed out (retcode: %d)", this->module_name.c_str (), STILL_ACTIVE); + break; + } + } + + GetExitCodeProcess (pi.hProcess, &retval); + + if (retval != 0) { + if (! TerminateJobObject (job, 0)) { + pandoraLog ("TerminateJobObject failed. (error %d)", + GetLastError ()); + } + if (retval != STILL_ACTIVE) { + pandoraLog ("Pandora_Module_Exec: %s did not executed well (retcode: %d)", + this->module_name.c_str (), retval); + } + this->has_output = false; + } + + if (!output.empty()) { + this->setOutput (output); + } else { + this->setOutput (""); + } + + /* Close job, process and thread handles. */ + CloseHandle (job); + CloseHandle (pi.hProcess); + CloseHandle (pi.hThread); + } + + CloseHandle (new_stdout); + CloseHandle (out_read); + + if ((precond->operation == ">" && float_output > precond->value_1) || + (precond->operation == "<" && float_output < precond->value_1) || + (precond->operation == "=" && float_output == precond->value_1) || + (precond->operation == "!=" && float_output != precond->value_1) || + (precond->operation == "=~" && regexec (&(precond->regexp), output.c_str(), 0, NULL, 0) == 0) || + (precond->operation == "()" && float_output > precond->value_1 && float_output < precond->value_2)){ + exe = 1; + } else { + exe = 0; + return exe; + } + + CloseHandle (pi.hProcess); + } +} + return exe; +} + + + + + /** * Evaluates and executes module conditions. */ diff --git a/pandora_agents/win32/modules/pandora_module.h b/pandora_agents/win32/modules/pandora_module.h index 536407a0d5..d8e617e655 100644 --- a/pandora_agents/win32/modules/pandora_module.h +++ b/pandora_agents/win32/modules/pandora_module.h @@ -89,6 +89,18 @@ namespace Pandora_Modules { MODULE_PLUGIN /**< Plugin */ } Module_Kind; + /** + * Defines the structure that holds module preconditions. + */ + typedef struct { + double value_1; + double value_2; + string string_value; + string operation; + string command; + regex_t regexp; + } Precondition; + /** * Defines the structure that holds module conditions. */ @@ -165,6 +177,7 @@ namespace Pandora_Modules { Module_Kind module_kind; string save; list *condition_list; + list *precondition_list; Cron *cron; protected: @@ -248,7 +261,10 @@ namespace Pandora_Modules { void setSave (string save); void exportDataOutput (); + void addPrecondition (); void addCondition (string condition); + void addPrecondition (string precondition); + int evaluatePreconditions (); void evaluateConditions (); int checkCron (); void setCron (string cron_string); diff --git a/pandora_agents/win32/modules/pandora_module_factory.cc b/pandora_agents/win32/modules/pandora_module_factory.cc index 4bf74c90d0..c20770b05a 100644 --- a/pandora_agents/win32/modules/pandora_module_factory.cc +++ b/pandora_agents/win32/modules/pandora_module_factory.cc @@ -85,6 +85,7 @@ using namespace Pandora_Strutils; #define TOKEN_CONDITION ("module_condition ") #define TOKEN_CRONTAB ("module_crontab ") #define TOKEN_CRONINTERVAL ("module_cron_interval ") +#define TOKEN_PRECONDITION ("module_precondition ") string parseLine (string line, string token) { @@ -127,14 +128,16 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { string module_retries, module_startdelay, module_retrydelay; string module_perfcounter, module_tcpcheck; string module_port, module_timeout, module_regexp; - string module_plugin, module_save, module_condition; + string module_plugin, module_save, module_condition, module_precondition; string module_crontab, module_cron_interval, module_post_process; Pandora_Module *module; bool numeric; Module_Type type; long agent_interval; list condition_list; + list precondition_list; list::iterator condition_iter; + list::iterator precondition_iter; module_name = ""; module_type = ""; @@ -172,6 +175,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module_crontab = ""; module_cron_interval = ""; module_post_process = ""; + module_precondition = ""; stringtok (tokens, definition, "\n"); @@ -188,6 +192,15 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { if (module_type == "") { module_type = parseLine (line, TOKEN_TYPE); } + if (module_precondition == "") { + module_precondition = parseLine (line, TOKEN_PRECONDITION); + + /* Queue the precondition and keep looking for more */ + if (module_precondition != "") { + precondition_list.push_back (module_precondition); + module_precondition = ""; + } + } if (module_interval == "") { module_interval = parseLine (line, TOKEN_INTERVAL); } @@ -424,6 +437,16 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module->setAsync (true); } +/* Module precondition */ + if (precondition_list.size () > 0) { + precondition_iter = precondition_list.begin (); + for (precondition_iter = precondition_list.begin (); + precondition_iter != precondition_list.end (); + precondition_iter++) { + module->addPrecondition (*precondition_iter); + } + } + /* Module condition */ if (condition_list.size () > 0) { condition_iter = condition_list.begin (); diff --git a/pandora_agents/win32/pandora_windows_service.cc b/pandora_agents/win32/pandora_windows_service.cc index 10c677423a..62933d1229 100644 --- a/pandora_agents/win32/pandora_windows_service.cc +++ b/pandora_agents/win32/pandora_windows_service.cc @@ -1159,6 +1159,7 @@ Pandora_Windows_Service::pandora_run () { string server_addr; int startup_delay = 0; static unsigned char delayed = 0; + int exe = 1; pandoraDebug ("Run begin"); @@ -1189,7 +1190,11 @@ Pandora_Windows_Service::pandora_run () { Pandora_Module *module; module = this->modules->getCurrentValue (); + + exe = module->evaluatePreconditions (); + if (exe == 0) return; + pandoraDebug ("Run %s", module->getName ().c_str ()); if (module->checkCron () == 1) {