2011-06-21 Vanessa Gil <vanessa.gil@artica.es>

* 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
This commit is contained in:
vgilc 2011-06-21 11:06:47 +00:00
parent ae8dff9657
commit 883dd23579
6 changed files with 379 additions and 8 deletions

View File

@ -1,3 +1,11 @@
2011-06-21 Vanessa Gil <vanessa.gil@artica.es>
* 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 <vanessa.gil@artica.es>
* unix/pandora_agent: Clean the code: parse configuration files.

View File

@ -16,7 +16,7 @@ Version 3.2
=head1 USAGE
C<< pandora_agent F<pandora home> >>
<< pandora_agent F<pandora home> >>
=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.
################################################################################

View File

@ -25,6 +25,8 @@
#include <iostream>
#include <sstream>
#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<Condition *>::iterator iter;
list<Precondition *>::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<Precondition *> ();
}
/* 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<Precondition *>::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 <windef.h> */
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.
*/

View File

@ -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 *> *condition_list;
list<Precondition *> *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);

View File

@ -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<string> condition_list;
list<string> precondition_list;
list<string>::iterator condition_iter;
list<string>::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 ();

View File

@ -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) {