Merge branch 'ent-10937-nuevo-planificador-de-lanzamiento-de-modulos-module_absoluteinterval' into 'develop'

Add support for module_absoluteinterval.

See merge request artica/pandorafms!6236
This commit is contained in:
Rafael Ameijeiras 2023-08-04 11:28:05 +00:00
commit 397653f89e
12 changed files with 301 additions and 14 deletions

View File

@ -42,6 +42,7 @@ mkdir -p temp_package/usr/bin/
mkdir -p temp_package/usr/sbin/
mkdir -p temp_package/etc/pandora/plugins
mkdir -p temp_package/etc/pandora/collections
mkdir -p temp_package/etc/pandora/ref
mkdir -p temp_package/etc/pandora/trans
mkdir -p temp_package/etc/pandora/commands
mkdir -p temp_package/etc/init.d/

View File

@ -30,6 +30,7 @@ else
mkdir -p /usr/local/share/man/man1/
mkdir -p /usr/local/share/pandora_agent/collections/
mkdir -p /usr/local/share/pandora_agent/commands/
mkdir -p /usr/local/share/pandora_agent/ref/
mkdir -p /etc/pandora/
mkdir -p /var/spool/pandora/data_out/
mkdir -p /var/log/pandora/
@ -39,6 +40,7 @@ else
# Setting permissions to directories and files
chmod -R 700 /usr/local/share/pandora_agent/collections
chmod -R 700 /usr/local/share/pandora_agent/commands
chmod -R 700 /usr/local/share/pandora_agent/ref
chmod -R 755 /etc/pandora/
chmod -R 700 /var/spool/pandora/data_out
chmod -R 711 /var/log/pandora
@ -69,6 +71,7 @@ chown root:wheel /usr/local/bin/tentacle_client
ln -s /usr/local/share/pandora_agent/plugins /etc/pandora/plugins
ln -s /usr/local/share/pandora_agent/commands /etc/pandora/commands
ln -s /usr/local/share/pandora_agent/collections /etc/pandora/collections
ln -s /usr/local/share/pandora_agent/ref /etc/pandora/ref
# Copy manuals
@ -90,4 +93,4 @@ echo "/var/log/pandora/pandora_agent.log : 640 5 204
# Clean all install utilites
rm -Rf inst_utilities
exit 0
exit 0

View File

@ -1003,7 +1003,7 @@ use strict;
use warnings;
use Scalar::Util qw(looks_like_number);
use POSIX qw(strftime floor);
use POSIX qw(ceil floor strftime);
use Sys::Hostname;
use File::Basename;
use File::Copy;
@ -1121,6 +1121,7 @@ my %DefaultConf = (
'server_path_md5' => 'md5', #undocumented
'server_path_conf' => 'conf', #undocumented
'server_path_zip' => 'collections', #undocumented
'server_path_ref' => 'ref', #undocumented
'logfile' =>'/var/log/pandora/pandora_agent.log',
'logsize' => DEFAULT_MAX_LOG_SIZE,
'logrotate' => DEFAULT_LOG_ROTATE,
@ -1569,6 +1570,34 @@ sub parse_conf_modules($) {
$module->{'post_process'} = $1;
} elsif ($line =~ /^\s*module_interval\s+(\d+)\s*$/) {
$module->{'interval'} = $1;
} elsif ($line =~ /^\s*module_absoluteinterval\s+(.*)$/) {
my $absolute_interval = $1;
if ($absolute_interval eq 'once') {
$module->{'absoluteinterval'} = 0;
} elsif ($absolute_interval =~ /^(\d+)([smhd])?\s*$/) {
if (defined($2)) {
# Seconds.
if ($2 eq 's') {
$module->{'absoluteinterval'} = int($1);
}
# Minutes (convert to seconds).
elsif ($2 eq 'm') {
$module->{'absoluteinterval'} = int($1) * 60;
}
# Hours (convert to seconds).
elsif ($2 eq 'h') {
$module->{'absoluteinterval'} = int($1) * 3600;
}
# Days (convert to seconds).
elsif ($2 eq 'd') {
$module->{'absoluteinterval'} = int($1) * 86400;
}
} else {
$module->{'absoluteinterval'} = int($1) * $Conf{'interval'};
}
} else {
log_message ('setup', "Invalid value for module_absoluteinterval: $absolute_interval");
}
} elsif ($line =~ /^\s*module_timeout\s+(\d+)\s*$/) {
$module->{'timeout'} = $1;
} elsif ($line =~ /^\s*module_save\s+(\w+)$/) {
@ -1636,6 +1665,27 @@ sub parse_conf_modules($) {
next;
}
# Configure modules with an absolute interval.
if (defined($module->{'absoluteinterval'})) {
# Convert from seconds to actual agent intervals.
$module->{'interval'} = ceil($module->{'absoluteinterval'} / $Conf{'interval'});
# Make sure modules that run once are asynchronous.
if ($module->{'interval'} == 0) {
if ($module->{'type'} eq 'generic_data') {
$module->{'type'} = 'async_data';
} elsif ($module->{'type'} eq 'generic_proc') {
$module->{'type'} = 'async_proc';
} elsif ($module->{'type'} eq 'generic_data_string') {
$module->{'type'} = 'async_string';
}
}
# This file will be used for persistence.
$module->{'timestamp_file'} = $ConfDir . '/' . $Conf{'server_path_ref'} . '/' . md5($module->{'name'}) . '.ref';
}
# Set the intensive interval
if ($module->{'is_intensive'} == 1) {
$module->{'intensive_interval'} = $module->{'interval'};
@ -1643,9 +1693,9 @@ sub parse_conf_modules($) {
$module->{'intensive_interval'} = $module->{'interval'} * ($Conf{'interval'} / $Conf{'intensive_interval'});
}
# Make the module run the first time
$module->{'counter'} = $module->{'intensive_interval'};
# Initialize the module's execution counter.
init_counter($module);
# Replace macros
replace_macros ($module);
@ -2805,7 +2855,15 @@ sub exec_module {
}
}
if (++($module->{'counter'}) < $module->{'intensive_interval'}) {
# Modules that will run once.
if ($module->{'interval'} == 0) {
if ($module->{'counter'} == 0) {
$ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1);
return;
}
}
# Modules that will run periodically.
elsif (++($module->{'counter'}) < $module->{'intensive_interval'}) {
$ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1);
return;
}
@ -2862,6 +2920,9 @@ sub exec_module {
}
}
# Save the module's timestamp to disk.
save_module_timestamp($module);
$ThreadSem->up () if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1);
}
@ -3547,6 +3608,44 @@ sub check_module_cron {
return 0;
}
################################################################################
# Initialize a module's internal execution counter.
################################################################################
sub init_counter($) {
my ($module) = @_;
# Open the timestamp file if available.
my $fh;
if (!defined($module->{'timestamp_file'}) ||
!open($fh, '<', $module->{'timestamp_file'})) {
# If intensive_interval is 0, setting counter to any value != 0 will make the module run.
$module->{'counter'} = $module->{'intensive_interval'} == 0 ? 1 : $module->{'intensive_interval'};
return;
}
# Read the timestamp from disk.
my $timestamp = int(<$fh>);
close($fh);
# Update the module's execution counter.
# If intensive_interval is 0, setting counter to 0 will prevent the module from running again.
$module->{'counter'} = $module->{'intensive_interval'} == 0 ? 0 : floor((time() - $timestamp) / $Conf{'interval'});
}
################################################################################
# Save a module's execution timestamp to disk for persistence.
################################################################################
sub save_module_timestamp($) {
my ($module) = @_;
return if (!defined($module->{'timestamp_file'}));
# Update the time reference.
open(my $fh, '>', $module->{'timestamp_file'}) or return;
print $fh time();
close($fh);
}
################################################################################
# Write module data in XML format.
################################################################################

View File

@ -100,6 +100,11 @@ if [ ! -e /etc/pandora/collections ]; then
ln -s /usr/share/pandora_agent/collections /etc/pandora
fi
if [ ! -e /etc/pandora/ref ]; then
mkdir -p /usr/share/pandora_agent/ref
ln -s /usr/share/pandora_agent/ref /etc/pandora
fi
if [ ! -e /etc/pandora/commands ]; then
mkdir -p /usr/share/pandora_agent/commands
ln -s /usr/share/pandora_agent/commands /etc/pandora
@ -143,7 +148,7 @@ fi
# Remove symbolic links
pushd /etc/pandora
for f in pandora_agent.conf plugins collections
for f in pandora_agent.conf plugins collections ref
do
[ -L $f ] && rm -f $f
done

View File

@ -94,6 +94,10 @@ if [ ! -e /etc/pandora/collections ]; then
mkdir /etc/pandora/collections
fi
if [ ! -e /etc/pandora/ref ]; then
mkdir /etc/pandora/ref
fi
if [ ! -e /etc/pandora/commands ]; then
mkdir /etc/pandora/commands
fi

View File

@ -408,6 +408,11 @@ install () {
chmod -R 700 $PANDORA_BASE$PANDORA_HOME/commands
ln -s $PANDORA_BASE_REAL$PANDORA_HOME/commands $PANDORA_BASE$PANDORA_CFG
echo "Creating the ref directory in to $PANDORA_BASE$PANDORA_HOME/ref..."
mkdir -p $PANDORA_BASE$PANDORA_HOME/ref
chmod -R 700 $PANDORA_BASE$PANDORA_HOME/ref
ln -s $PANDORA_BASE_REAL$PANDORA_HOME/ref $PANDORA_BASE$PANDORA_CFG
if [ $WITHOUT_TENTACLE_SERVER -eq 0 ]
then
echo "Copying tentacle server to $PANDORA_BASE$TENTACLE_SERVER"

View File

@ -31,6 +31,10 @@ using namespace std;
* File operations.
*/
namespace Pandora_File {
/* Size of a buffer that will be passed to Pandora_File::md5. */
const int MD5_BUF_SIZE = 33;
/**
* File super-class exception.
*/

View File

@ -19,11 +19,14 @@
*/
#include "pandora_module.h"
#include "pandora_windows_service.h"
#include "../misc/pandora_file.h"
#include "../pandora_strutils.h"
#include "../pandora.h"
#include <iostream>
#include <sstream>
#include <cmath>
#define BUFSIZE 4096
@ -472,18 +475,27 @@ Pandora_Module::setNoOutput () {
*/
void
Pandora_Module::run () {
/* Check the interval */
if (this->executions % this->intensive_interval != 0) {
// Run once.
if (this->intensive_interval == 0) {
if (this->executions == 0) {
has_output = false;
throw Interval_Not_Fulfilled ();
}
}
// Run periodically.
else if (++this->executions < this->intensive_interval) {
pandoraDebug ("%s: Interval is not fulfilled", this->module_name.c_str ());
this->executions++;
has_output = false;
throw Interval_Not_Fulfilled ();
}
/* Increment the executions after check. This is done to execute the
first time */
this->executions++;
// Reset the execution counter.
this->executions = 0;
has_output = true;
// Update the execution timestamp.
this->updateTimestampFile();
}
/**
@ -1663,6 +1675,63 @@ Pandora_Module::getTimestamp () {
return this->timestamp;
}
/**
* Sets the module timestamp file.
*
* @param file_name The name of the timestamp file.
*/
void
Pandora_Module::setTimestampFile (string file_name) {
this->timestamp_file = file_name;
}
/**
* Gets the module timestamp file.
*
* @return The name of the timestamp file.
*/
string
Pandora_Module::getTimestampFile () {
return this->timestamp_file;
}
/**
* Update the timestamp file with the current time.
*
*/
void
Pandora_Module::updateTimestampFile () {
try {
Pandora_File::writeFile(this->timestamp_file, std::to_string(std::time(NULL)));
} catch (...) {
/* Ignore errors. */
}
}
/**
* Initialize the module's internal execution counter.
*
*/
void
Pandora_Module::initExecutions () {
string timestamp;
try {
if (this->timestamp_file != "" && Pandora_File::readFile(this->timestamp_file, timestamp) != FILE_NOT_FOUND) {
// If the interval is 0, setting executions to 0 will prevent the module from running.
this->executions = this->intensive_interval == 0 ?
0 :
floor((1000.0 * (std::time(NULL) - strtoint(timestamp))) / Pandora_Windows_Service::getInstance()->getInterval());
return;
}
} catch (...) {
// Ignore errors.
}
// If the interval is 0, setting executions to any value != 0 will make the module run.
this->executions = this->intensive_interval == 0 ? 1 : this->intensive_interval;
}
/**
* Sets the value of intensive_match.
*

View File

@ -171,6 +171,7 @@ namespace Pandora_Modules {
Cron *cron;
list<Condition *> *intensive_condition_list;
time_t timestamp;
string timestamp_file;
unsigned char intensive_match;
int intensive_interval;
string unit, custom_id, str_warning, str_critical;
@ -238,6 +239,7 @@ namespace Pandora_Modules {
bool getAsync ();
void setExecutions(long executions=0);
long getExecutions();
void initExecutions ();
virtual string getXml ();
@ -303,6 +305,9 @@ namespace Pandora_Modules {
int hasOutput ();
void setTimestamp (time_t timestamp);
time_t getTimestamp ();
void setTimestampFile (string file_name);
string getTimestampFile ();
void updateTimestampFile ();
void setIntensiveMatch (unsigned char intensive_match);
unsigned char getIntensiveMatch ();
bool isIntensive ();

View File

@ -41,7 +41,10 @@
#include "pandora_module_snmpget.h"
#include "../windows/pandora_wmi.h"
#include "../pandora_strutils.h"
#include "../misc/pandora_file.h"
#include "../pandora.h"
#include <list>
#include <cmath>
using namespace Pandora;
using namespace Pandora_Modules;
@ -50,6 +53,7 @@ using namespace Pandora_Strutils;
#define TOKEN_NAME ("module_name ")
#define TOKEN_TYPE ("module_type ")
#define TOKEN_INTERVAL ("module_interval ")
#define TOKEN_ABSOLUTEINTERVAL ("module_absoluteinterval ")
#define TOKEN_EXEC ("module_exec ")
#define TOKEN_PROC ("module_proc ")
#define TOKEN_SERVICE ("module_service ")
@ -156,7 +160,8 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
list<string>::iterator iter;
string module_name, module_type, module_exec;
string module_min, module_max, module_description;
string module_interval, module_proc, module_service;
string module_interval, module_absoluteinterval;
string module_proc, module_service;
string module_freedisk, module_cpuusage, module_inventory;
string module_freedisk_percent, module_freememory_percent;
string module_dsn, module_freememory;
@ -196,6 +201,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
module_max = "";
module_description = "";
module_interval = "";
module_absoluteinterval = "";
module_exec = "";
module_proc = "";
module_service = "";
@ -290,6 +296,9 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
if (module_interval == "") {
module_interval = parseLine (line, TOKEN_INTERVAL);
}
if (module_absoluteinterval == "") {
module_absoluteinterval = parseLine (line, TOKEN_ABSOLUTEINTERVAL);
}
if (module_exec == "") {
module_exec = parseLine (line, TOKEN_EXEC);
}
@ -603,6 +612,13 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
}
}
if (module_absoluteinterval != "") {
pos_macro = module_absoluteinterval.find(macro_name);
if (pos_macro != string::npos){
module_absoluteinterval.replace(pos_macro, macro_name.size(), macro_value);
}
}
if (module_exec != "") {
pos_macro = module_exec.find(macro_name);
if (pos_macro != string::npos){
@ -1323,6 +1339,61 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
}
}
/* Set the module absolute interval */
if (module_absoluteinterval != "") {
int interval;
try {
service = Pandora_Windows_Service::getInstance();
// Run once.
if (module_absoluteinterval == "once") {
interval = 0;
}
// Seconds.
else if (module_absoluteinterval.back() == 's') {
interval = strtoint (module_absoluteinterval.substr(0, module_absoluteinterval.size() - 1));
}
// Minutes.
else if (module_absoluteinterval.back() == 'm') {
interval = strtoint (module_absoluteinterval.substr(0, module_absoluteinterval.size() - 1)) * 60;
}
// Hours.
else if (module_absoluteinterval.back() == 'h') {
interval = strtoint (module_absoluteinterval.substr(0, module_absoluteinterval.size() - 1)) * 3600;
}
// Days.
else if (module_absoluteinterval.back() == 'd') {
interval = strtoint (module_absoluteinterval.substr(0, module_absoluteinterval.size() - 1)) * 86400;
}
// Number of agent intervals.
else {
interval = strtoint(module_absoluteinterval) * (service->getIntervalSec());
}
// Convert from seconds to agent executions.
interval = ceil(interval / double(service->getIntervalSec()));
// Set the module interval.
module->setInterval (interval);
module->setIntensiveInterval (interval);
// Compute the MD5 hash of the module's name.
char module_name_md5[Pandora_File::MD5_BUF_SIZE];
Pandora_File::md5(module_name.c_str(), module_name.size(), module_name_md5);
// Set the timestamp file.
module->setTimestampFile(Pandora::getPandoraInstallDir().append("/ref/").append(module_name_md5).append(".ref"));
} catch (Invalid_Conversion e) {
pandoraLog ("Invalid absolute interval value \"%s\" for module %s",
module_absoluteinterval.c_str (),
module_name.c_str ());
}
catch (...) {
// Should not happen. Ignore errors.
}
}
/* Module intensive condition */
if (intensive_condition_list.size () > 0) {
intensive_condition_iter = intensive_condition_list.begin ();
@ -1337,6 +1408,9 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
module->setIntensiveInterval (module->getInterval () * (service->getInterval () / service->getIntensiveInterval ()));
}
/* Initialize the module's execution counter. */
module->initExecutions ();
/* Module cron */
module->setCron (module_crontab);
@ -1374,6 +1448,18 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
numeric = false;
}
// Make sure modules that run once are asynchronous.
if (module->getInterval() == 0) {
type = module->getTypeInt();
if (type == TYPE_GENERIC_DATA) {
module->setType("async_data");
} else if (type == TYPE_GENERIC_PROC) {
module->setType("async_proc");
} else if (type == TYPE_GENERIC_DATA_STRING) {
module->setType("async_string");
}
}
if (numeric) {
if (module_max != "") {
try {

View File

@ -2197,6 +2197,11 @@ Pandora_Windows_Service::getInterval () {
return this->interval;
}
long
Pandora_Windows_Service::getIntervalSec () {
return this->interval_sec;
}
long
Pandora_Windows_Service::getIntensiveInterval () {
return this->intensive_interval;

View File

@ -122,6 +122,7 @@ namespace Pandora {
Pandora_Agent_Conf *getConf ();
string getEHKey (string ehorus_conf);
long getInterval ();
long getIntervalSec ();
long getIntensiveInterval ();
string generateAgentName ();
bool writeToBuffer (string temporal);