pandorafms/pandora_server/util/pandora_xml_stress.pl

992 lines
32 KiB
Perl
Raw Normal View History

#!/usr/bin/perl
################################################################################
# Pandora XML Stress tool.
################################################################################
# Copyright (c) 2009 Ramon Novoa, rnovoa@artica.es
# Copyright (c) 2012 Artica Soluciones Tecnologicas S.L.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; version 2
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
################################################################################
use strict;
use warnings;
use threads;
use threads::shared;
use Time::Local;
use Time::HiRes qw(gettimeofday);
use POSIX qw (strftime ceil floor);
use Data::Dumper;
use Math::Trig;
use File::Copy;
# Global variables used for statistics
my $Agents :shared = 0;
my $Modules :shared = 0;
my $XMLFiles :shared = 0;
my $LogLock :shared;
########################################################################
# Load the configuration file.
########################################################################
sub load_config ($\%\@) {
my ($conf_file, $conf, $modules) = @_;
open (FILE, "<", $conf_file) || die ("[error] Could not open configuration file '$conf_file': $!.\n\n");
while (my $line = <FILE>) {
# A module definition
if ($line =~ m/module_begin/) {
my %module;
# A comment
next if ($line =~ m/^#/);
while (my $line = <FILE>) {
# A comment
next if ($line =~ m/^#/);
last if ($line =~ m/module_end/);
# Unknown line
next if ($line !~ /^\s*(\w+)\s+(.+)$/);
$module{$1} = $2;
}
push (@{$modules}, \%module);
$Modules++;
next;
}
# Unknown line
next if ($line !~ /^\s*(\w+)\s+(.+)$/);
$conf->{$1} = $2;
}
close (FILE);
}
################################################################################
# Generate XML files.
################################################################################
sub generate_xml_files ($$$$$$) {
my ($agents, $start, $step, $conf, $modules, $local_conf) = @_;
# Read agent configuration
my $interval = get_conf_token ($conf, 'agent_interval', '300');
my $xml_version = get_conf_token ($conf, 'xml_version', '1.0');
my $encoding = get_conf_token ($conf, 'encoding', 'UTF-8');
my $os_name = get_conf_token ($conf, 'os_name', 'Linux');
my $os_version = get_conf_token ($conf, 'os_version', '2.6');
my $temporal = get_conf_token ($conf, 'temporal', '/tmp');
my $startup_delay = get_conf_token ($conf, 'startup_delay', '5');
my $ag_timezone_offset = get_conf_token ($conf, 'timezone_offset', '0');
my $ag_timezone_offset_range = get_conf_token ($conf, 'timezone_offset_range', '0');
my $latitude_base = get_conf_token ($conf, 'latitude_base', '40.42056');
my $longitude_base = get_conf_token ($conf, 'longitude_base', '-3.708187');
my $altitude_base = get_conf_token ($conf, 'altitude_base', '0');
my $position_radius = get_conf_token ($conf, 'position_radius', '10');
my $group = get_conf_token ($conf, 'group', 'Servers');
# Get time_from
my $time_now = strftime ("%Y-%m-%d %H:%M:%S", localtime ());
my $time_from = get_conf_token ($conf, 'time_from', $time_now);
die ("[error] Invalid time_from: $time_from\n\n")
unless ($time_from =~ /(\d+)\-(\d+)\-(\d+) +(\d+):(\d+):(\d+)/);
my $utimestamp_from = timelocal($6, $5, $4, $3, $2 - 1, $1 - 1900);
# Get time_to
my $time_to = get_conf_token ($conf, 'time_to', $time_now);
die ("[error] Invalid time_to: $time_to\n\n")
unless ($time_to =~ /(\d+)\-(\d+)\-(\d+) +(\d+):(\d+):(\d+)/);
my $utimestamp_to = timelocal($6, $5, $4, $3, $2 - 1, $1 - 1900);
my %modules_src_pointers = init_src_pointers($modules);
# Previous data for incremental modules
my %prev_rnd_data;
# Generate data files
my $utimestamp = $utimestamp_from;
while ($utimestamp <= $utimestamp_to) {
for (my $i = $start; $i < $start + $step; $i++) {
# Get the name of the agent
last unless defined ($agents->[$i]);
my $agent_name = $agents->[$i];
# Use the modules of local conf of agent.
if ($local_conf->{$agent_name}) {
$modules = $local_conf->{$agent_name};
}
# Agent random position
my $ag_latitude = $latitude_base + (rand ($position_radius) - $position_radius/2)/100;
my $ag_longitude = $longitude_base + (rand ($position_radius) - $position_radius/2)/100;
my $ag_altitude = $altitude_base + (rand ($position_radius) - $position_radius/2)/100;
# XML header
my @localtime = localtime ($utimestamp);
my $wday = $localtime[6];
my $timestamp = strftime ("%Y-%m-%d %H:%M:%S", @localtime);
my $xml_data = "<?xml version='$xml_version' encoding='$encoding'?>\n";
my $sign = int rand(2);
$ag_timezone_offset += ($sign*(-1)+(1-$sign)) * int rand($ag_timezone_offset_range);
$xml_data .= "<agent_data os_name='$os_name' os_version='$os_version' interval='$interval' group='$group' version='$os_version' timestamp='$timestamp' agent_name='$agent_name' timezone_offset='$ag_timezone_offset' longitude='$ag_longitude' latitude='$ag_latitude' altitude='$ag_altitude'>\n";
foreach my $module (@{$modules}) {
# Skip unnamed modules
my $module_name = get_conf_token ($module, 'module_name', '');
next if ($module_name eq '');
# Read module configuration
my $module_type = get_conf_token ($module, 'module_type', 'generic_data');
my $module_description = get_conf_token ($module, 'module_description', '');
my $module_unit = get_conf_token ($module, 'module_unit', '');
my $module_incremental = get_conf_token ($module, 'module_incremental', '0');
my $attenuation = get_conf_token ($module, 'module_attenuation', '0');
my @attenuation_wdays = get_conf_token_array ($module, 'module_attenuation_wdays', ' ');
#my $module_min = get_conf_token ($module, 'module_min', '0');
#my $module_max = get_conf_token ($module, 'module_max', '255');
#my $module_variation = get_conf_token ($module, 'module_variation', '100');
#my $module_data = get_conf_token ($module, 'module_data', '');
# Extract the data config for the generator.
my $generation_type = get_generation_parameter($module, 'type', 'RANDOM');
my $module_variation = get_generation_parameter($module, 'variation', '100');
my $module_min = get_generation_parameter($module, 'min', '0');
my $module_max = get_generation_parameter($module, 'max', '255');
my $module_data = get_generation_parameter($module, 'data', '');
my $module_prob = get_generation_parameter($module, 'prob', '50');
my $module_avg = get_generation_parameter($module, 'avg', '127');
my $module_time_wave_length = get_generation_parameter($module, 'time_wave_length', '0');
my $module_time_offset = get_generation_parameter($module, 'time_offset', '0');
my $module_src = get_generation_parameter($module, 'src', 'source.txt');
my $module_min_critical = get_conf_token ($module, 'module_min_critical', '');
my $module_max_critical = get_conf_token ($module, 'module_max_critical', '');
my $module_min_warning = get_conf_token ($module, 'module_min_warning', '');
my $module_max_warning = get_conf_token ($module, 'module_max_warning', '');
# Generate module data
$xml_data .= "\t<module>\n";
$xml_data .= "\t\t<name>$module_name</name>\n";
$xml_data .= "\t\t<description>$module_description</description>\n";
$xml_data .= "\t\t<type>$module_type</type>\n";
if ($module_min_critical ne '') {
$xml_data .= "\t\t<min_critical>$module_min_critical</min_critical>\n";
}
if ($module_max_critical ne '') {
$xml_data .= "\t\t<max_critical>$module_max_critical</max_critical>\n";
}
if ($module_min_warning ne '') {
$xml_data .= "\t\t<min_warning>$module_min_warning</min_warning>\n";
}
if ($module_max_warning ne '') {
$xml_data .= "\t\t<max_warning>$module_max_warning</max_warning>\n";
}
$xml_data .= "\t\t<unit><![CDATA[$module_unit]]></unit>\n";
# Generate data
my $rnd_data = $module->{'module_data'};
if ($generation_type eq 'RANDOM') {
$rnd_data = generate_random_data ($module_type, $module_data,
$module_min, $module_max, $module_variation);
}
elsif ($generation_type eq 'SCATTER') {
if (($module_type eq 'generic_data_string') ||
($module_type eq 'async_string')) {
printf "\n";
log_message ($conf, "\tERROR:\tTry to generate scatter data in string module '$module_name' in agent '$agent_name'\n");
$rnd_data = $module_data;
}
else {
$rnd_data = generate_scatter_data ($module_type, $module_data,
$module_min, $module_max, $module_prob, $module_avg);
}
}
elsif ($generation_type eq 'CURVE') {
if (($module_type eq 'generic_data_string') ||
($module_type eq 'async_string')) {
printf "\n";
log_message ($conf, "\tERROR:\tTry to generate curve data in string module '$module_name' in agent '$agent_name'\n");
$rnd_data = $module_data;
}
else {
$rnd_data = generate_curve_data ($utimestamp, $module_min, $module_max,
$module_time_wave_length, $module_time_offset);
}
}
elsif ($generation_type eq 'SOURCE') {
$rnd_data = generate_data_from_source($module_name, $module_src, \%modules_src_pointers);
}
# Data attenuation
if ($attenuation != 0 && ($#attenuation_wdays < 0 || grep{$_ eq $wday} @attenuation_wdays)) {
$rnd_data *= $attenuation;
}
# Incremental module
if ($module_incremental == 1) {
if (defined ($prev_rnd_data{$module_name})) {
$rnd_data += $prev_rnd_data{$module_name};
}
$prev_rnd_data{$module_name} = $rnd_data;
}
# Save previous data
$module->{'module_data'} = $rnd_data;
$xml_data .= "\t\t<data><![CDATA[$rnd_data]]></data>\n";
$xml_data .= "\t</module>\n";
}
$xml_data .= "</agent_data>\n";
# Fix the temporal path
my $last_char = chop ($temporal);
$temporal .= $last_char if ($last_char ne '/');
# Save the XML data file
# The temporal dir is normaly the /var/spool/pandora/data_in
my $xml_fullpath_file = $temporal . '/' . $agent_name . '_' . $utimestamp . '.data';
my $xml_file = $agent_name . '_' . $utimestamp . '.data';
open (FILE, ">", $xml_fullpath_file) || die ("[error] Could not write to '$xml_fullpath_file': $!.\n\n");
print FILE $xml_data;
close (FILE);
copy_xml_file ($conf, $xml_fullpath_file, $xml_file);
$XMLFiles++;
}
#Update src pointers for a new xml
update_src_pointers(\%modules_src_pointers);
# First run, let the server create the new agent before sending more data
if ($utimestamp == $utimestamp_from) {
threads->yield ();
sleep ($startup_delay);
}
$utimestamp += $interval;
}
}
################################################################################
# Generates random data according to the module type.
################################################################################
sub generate_random_data ($$$$$) {
my ($module_type, $current_data, $min, $max, $variation) = @_;
my $change_rnd = int rand (100);
return $current_data unless ($variation > $change_rnd) or $current_data eq '';
# String
if ($module_type =~ m/string/) {
my @chars = ("A" .. "Z","a" .. "z", 0..9);
return join ("", @chars[map {rand @chars} (1..(rand ($max - $min + 1) + $min))]);
}
# Proc
if ($module_type =~ m/proc/) {
return int (rand ($max - $min + 1) + $min);
}
# Generic data
return int (rand ($max - $min + 1) + $min);
}
################################################################################
# Generates curve data.
################################################################################
sub generate_curve_data ($$$$$$) {
my ($utimestamp, $module_min, $module_max, $module_time_wave_length,
$module_time_offset) = @_;
#f(x) = (max - min) * Sin( (t * pi) / (wave_length) + (pi * (offset / wave_length))) + min
######################################################
# GRAPHICAL EXPLAIN
#
# offset
# |
# (max - min) -> |----- . . . .
# |V V. . . .
# ---------------|---------------------------------
# | . . . ^ ^
# min -> | . . . | |
# -------
# |
# wave_length
#
######################################################
my $return = ($module_max - $module_min)/2 *
sin( ($utimestamp * pi) / $module_time_wave_length +
(pi * ($module_time_offset / $module_time_wave_length))) + ($module_min + $module_max) / 2;
return $return;
}
################################################################################
# Generates scatter data.
################################################################################
sub generate_scatter_data ($$$$$$) {
my ($module_type, $current_data, $min, $max, $prob, $avg) = @_;
# And check the probability now
my $other_rnd = int rand(100);
if ($prob >= $other_rnd) {
return int (rand ($max - $min + 1) + $min);
}
else {
return $avg;
}
}
################################################################################
# Generates data from a txt source
################################################################################
sub generate_data_from_source ($$$) {
my ($module_name, $module_src, $pointers) = @_;
my $data = 0;
my $pointer;
if (-e $module_src) {
#Get data and split to an array
open (FD , "<", $module_src);
my @data_array = <FD>;
close(FD);
$module_name =~ s/\ /\_/;
$pointer = $pointers->{$module_name};
$pointer = $pointer % ($#data_array + 1);
$data = $data_array[$pointer];
}
else {
#There was an error, set last to 0 and return data
return $data;
}
return $data;
}
################################################################################
# Initialize SRC pointer for src modules
################################################################################
sub init_src_pointers ($) {
my ($modules) = shift;
my %pointers;
foreach my $mod (@{$modules}) {
# Skip unnamed modules
my $module_name = get_conf_token ($mod, 'module_name', '');
next if ($module_name eq '');
my $type = get_generation_parameter($mod, 'type', 'RANDOM');
if ($type eq 'SOURCE') {
$module_name =~ s/\ /\_/;
$pointers{$module_name} = 0;
}
}
return %pointers;
}
################################################################################
# Updates SRC pointer for src modules
################################################################################
sub update_src_pointers ($) {
my ($pointers) = shift;
foreach my $p (keys %{$pointers}) {
#Add 1 to the pointer
$pointers->{$p}++;
}
}
################################################################################
# Returns the value of a configuration token.
################################################################################
sub copy_xml_file ($$) {
my ($conf, $fullpath_file, $file) = @_;
my $server_ip = get_conf_token ($conf, 'server_ip', '');
my $local_copy = get_conf_token($conf, 'local_copy', 0);
if ($local_copy) {
my $local_dir = get_conf_token($conf, 'local_dir', '/var/spool/pandora/data_in');
move("$fullpath_file", "$local_dir/$file");
}
else {
return if ($server_ip eq '');
my $server_port = get_conf_token ($conf, 'server_port', '41121');
my $tentacle_opts = get_conf_token ($conf, 'tentacle_opts', '');
# Send the file and delete it
`tentacle_client -a $server_ip -p $server_port $tentacle_opts "$fullpath_file" > /dev/null 2>&1`;
if ($? != 0) {
log_message ($conf, "\tERROR:\tTry to send XML file (" . $file . ") with tentacle\n");
}
}
unlink ($file);
}
################################################################################
# Returns the value of a configuration token.
################################################################################
sub get_conf_token ($$$) {
my ($hash_ref, $token, $def_value) = @_;
return $def_value unless ref ($hash_ref) and defined ($hash_ref->{$token});
return $hash_ref->{$token};
}
################################################################################
# Returns the value of a configuration token.
################################################################################
sub get_conf_token_array ($$$) {
my ($hash_ref, $token, $separator) = @_;
my @tokens = ();
return @tokens unless ref ($hash_ref) and defined ($hash_ref->{$token});
@tokens = split($separator, $hash_ref->{$token});
return @tokens;
}
################################################################################
# Returns the parameter of a generator configuration of module.
################################################################################
sub get_generation_parameter($$$) {
my ($hash_ref, $token, $def_value) = @_;
return $def_value unless ref ($hash_ref) and defined ($hash_ref->{'module_exec'});
my $configuration = $hash_ref->{'module_exec'};
my $value = $def_value;
$value = $1 if ($configuration =~ /$token=([^;]+)/);
return $value;
}
################################################################################
# Prints a message to the logfile.
################################################################################
sub log_message ($$) {
my ($conf, $message) = @_;
my $utimestamp = time ();
my $log_file = get_conf_token ($conf, 'log_file', '');
# Log to stdout
if ($log_file eq '') {
print "[$utimestamp] $message\n";
return;
}
# Log to file
{
lock $LogLock;
open (LOG_FILE, '>>', $log_file) || die ("[error] Could not open log file '$log_file': $!.\n\n");
print LOG_FILE "[$utimestamp] $message\n";
close (LOG_FILE);
}
}
########################################################################
# INI MD5 FUNCTIONS
########################################################################
# Used to calculate the MD5 checksum of a string
use constant MOD232 => 2**32;
########################################################################
# MD5 leftrotate function.
# See http://en.wikipedia.org/wiki/MD5#Pseudocode.
########################################################################
sub leftrotate ($$) {
my ($x, $c) = @_;
return (0xFFFFFFFF & ($x << $c)) | ($x >> (32 - $c));
}
###############################################################################
# Initialize some variables needed by the MD5 algorithm.
# See http://en.wikipedia.org/wiki/MD5#Pseudocode.
###############################################################################
my (@R, @K);
sub md5_init () {
# R specifies the per-round shift amounts
@R = (7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21);
# Use binary integer part of the sines of integers (radians) as constants
for (my $i = 0; $i < 64; $i++) {
$K[$i] = floor(abs(sin($i + 1)) * MOD232);
}
}
###############################################################################
# Return the MD5 checksum of the given string.
# Pseudocode from http://en.wikipedia.org/wiki/MD5#Pseudocode.
###############################################################################
sub md5 ($) {
my $str = shift;
# Note: All variables are unsigned 32 bits and wrap modulo 2^32 when calculating
# Initialize variables
my $h0 = 0x67452301;
my $h1 = 0xEFCDAB89;
my $h2 = 0x98BADCFE;
my $h3 = 0x10325476;
# Pre-processing
my $msg = unpack ("B*", pack ("A*", $str));
my $bit_len = length ($msg);
# Append "1" bit to message
$msg .= '1';
# Append "0" bits until message length in bits ≡ 448 (mod 512)
$msg .= '0' while ((length ($msg) % 512) != 448);
# Append bit /* bit, not byte */ length of unpadded message as 64-bit little-endian integer to message
$msg .= unpack ("B64", pack ("VV", $bit_len));
# Process the message in successive 512-bit chunks
for (my $i = 0; $i < length ($msg); $i += 512) {
my @w;
my $chunk = substr ($msg, $i, 512);
# Break chunk into sixteen 32-bit little-endian words w[i], 0 <= i <= 15
for (my $j = 0; $j < length ($chunk); $j += 32) {
push (@w, unpack ("V", pack ("B32", substr ($chunk, $j, 32))));
}
# Initialize hash value for this chunk
my $a = $h0;
my $b = $h1;
my $c = $h2;
my $d = $h3;
my $f;
my $g;
# Main loop
for (my $y = 0; $y < 64; $y++) {
if ($y <= 15) {
$f = $d ^ ($b & ($c ^ $d));
$g = $y;
}
elsif ($y <= 31) {
$f = $c ^ ($d & ($b ^ $c));
$g = (5 * $y + 1) % 16;
}
elsif ($y <= 47) {
$f = $b ^ $c ^ $d;
$g = (3 * $y + 5) % 16;
}
else {
$f = $c ^ ($b | (0xFFFFFFFF & (~ $d)));
$g = (7 * $y) % 16;
}
my $temp = $d;
$d = $c;
$c = $b;
$b = ($b + leftrotate (($a + $f + $K[$y] + $w[$g]) % MOD232, $R[$y])) % MOD232;
$a = $temp;
}
# Add this chunk's hash to result so far
$h0 = ($h0 + $a) % MOD232;
$h1 = ($h1 + $b) % MOD232;
$h2 = ($h2 + $c) % MOD232;
$h3 = ($h3 + $d) % MOD232;
}
# Digest := h0 append h1 append h2 append h3 #(expressed as little-endian)
return unpack ("H*", pack ("V", $h0)) . unpack ("H*", pack ("V", $h1)) . unpack ("H*", pack ("V", $h2)) . unpack ("H*", pack ("V", $h3));
}
################################################################################
# END MD5 FUNCTIONS
################################################################################
################################################################################
################################################################################
# Sends a file to the server.
################################################################################
sub send_file($$) {
my $file = shift;
my $conf = shift;
my $output;
my $server_ip = get_conf_token($conf, 'server_ip', '');
my $server_port = get_conf_token($conf, 'server_port', '41121');
my $tentacle_options = get_conf_token($conf, 'tentacle_options', '');
# Shell command separator
my $CmdSep = ';';
# $DevNull
my $DevNull = '/dev/null';
$output = `tentacle_client -v -a $server_ip -p $server_port $tentacle_options $file 2>&1 >$DevNull`;
# Get the errorlevel
my $rc = $? >> 8;
if ($rc != 0) {
log_message($conf, "\tERROR:\tError sending file '$file': $output");
}
return $rc;
}
################################################################################
# Receive a file from the server.
################################################################################
sub recv_file ($$) {
my $file = shift;
my $conf = shift;
my $output;
my $directory_temp = get_conf_token($conf, 'directory_temp', '/tmp');
my $server_ip = get_conf_token($conf, 'server_ip', '');
my $server_port = get_conf_token($conf, 'server_port', '41121');
my $tentacle_options = get_conf_token($conf, 'tentacle_options', '');
# Shell command separator
my $CmdSep = ';';
# $DevNull
my $DevNull = '/dev/null';
$output = `cd "$directory_temp"$CmdSep tentacle_client -v -g -a $server_ip -p $server_port $tentacle_options $file 2>&1 >$DevNull`;
# Get the errorlevel
my $rc;
$rc = $? >> 8;
if ($rc != 0) {
log_message ($conf, "\tERROR:\tGetting the remote $file.'\n");
log_message ($conf, "\tERROR:\t$output'\n");
}
return $rc;
}
################################################################################
################################################################################
# Get the send agent conf and generate modules.
################################################################################
sub get_and_send_agent_conf(\@\%\@\%) {
my ($agents, $conf, $modules, $local_conf) = @_;
my $get_and_send_agent_conf = get_conf_token($conf, 'get_and_send_agent_conf', '0');
my $directory_confs = get_conf_token($conf, 'directory_confs', '.');
my $directory_temp = get_conf_token($conf, 'directory_temp', '/tmp');
my $md5_agent_name = '';
if ($get_and_send_agent_conf == 1) {
foreach my $agent (@{$agents}) {
$md5_agent_name = md5($agent);
if (open (CONF_FILE, "$directory_confs/$agent.conf")) {
binmode(CONF_FILE);
my $conf_md5 = md5 (join ('', <CONF_FILE>));
close (CONF_FILE);
# Get the remote MD5 file
if (recv_file("$md5_agent_name.md5", $conf) != 0) {
#The remote agent don't recive, then it send the agent conf and md5.
open (MD5_FILE, ">$directory_temp/$md5_agent_name.md5")
|| log_message ($conf, "\tERROR:\tCould not open file '$directory_temp/$md5_agent_name.md5' for writing: $!.");
print MD5_FILE $conf_md5;
close (MD5_FILE);
copy ("$directory_confs/$agent.conf", "$directory_temp/$md5_agent_name.conf");
send_file("$directory_temp/$md5_agent_name.conf", $conf);
send_file("$directory_temp/$md5_agent_name.md5", $conf);
log_message ($conf, "\tINFO:\tUploading configuration for the first time.");
unlink ("$directory_temp/$md5_agent_name.conf");
unlink ("$directory_temp/$md5_agent_name.md5");
}
else {
#There is a remote agent.
open (MD5_FILE, "< $directory_temp/$md5_agent_name.md5")
|| log_message ($conf, "Could not open file '$directory_confs/$md5_agent_name.md5' for writing: $!.");
#Get the first version of md5 file.
my $remote_conf_md5 = <MD5_FILE>;
close (MD5_FILE);
if ($remote_conf_md5 ne $conf_md5) {
if (recv_file ("$md5_agent_name.conf", $conf) != 0) {
log_message ($conf, "\tERROR:\t Get the remote '$agent.conf'.");
}
else {
move("$directory_temp/$md5_agent_name.conf", "$directory_confs/$agent.conf");
}
}
}
}
else {
log_message ($conf, "\tWARNING:\tThere is not the $agent.conf .'\n");
my $interval = get_conf_token($conf, 'agent_interval', '300');
my $timezone_offset = get_conf_token($conf, 'timezone_offset', '0');
my $module_txt = '';
my $temp = "";
# Create the block of modules.
foreach my $module (@{$modules}) {
$temp = $temp . "
module_begin
module_name " . $module->{'module_name'} . "
module_type " . $module->{'module_type'} . "
module_exec " . $module->{'module_exec'} . "
module_min " . $module->{'module_min'} . "
module_max " . $module->{'module_max'} . "
module_end
";
}
my $default_conf =
"# General Parameters
# ==================
server_ip " . get_conf_token ($conf, 'server_ip', 'localhost') . "
server_path /var/spool/pandora/data_in
temporal /tmp
logfile /var/log/pandora/pandora_agent.log
# Interval in seconds, 300 by default
interval $interval
# Debug mode only generate XML, and stop after first execution,
# and does not copy XML to server.
debug 0
# By default, agent takes machine name
agent_name $agent
# Agent description
description This conf is generated with pandora_xml_stress.
# Timezone offset: Difference with the server timezone
#timezone_offset $timezone_offset
# Listening TCP port for remote server. By default is 41121 (for tentacle)
# if you want to use SSH use 22, and FTP uses 21.
server_port 41121
# Transfer mode: tentacle, ftp, ssh or local
transfer_mode tentacle
# If set to 1 allows the agent to be configured via the web console (Only Enterprise version)
remote_config 1" . $temp;
if (open (CONF_FILE, ">$directory_confs/$agent.conf")) {
print CONF_FILE $default_conf;
close (CONF_FILE);
open (CONF_FILE, "$directory_confs/$agent.conf");
binmode(CONF_FILE);
my $conf_md5 = md5 (join ('', <CONF_FILE>));
close (CONF_FILE);
#Send files.
open (MD5_FILE, "> $directory_temp/$md5_agent_name.md5")
|| log_message ($conf, "\tERROR:\tCould not open file '$directory_temp/$agent.conf' for writing: $!.");
print MD5_FILE $conf_md5;
close (MD5_FILE);
copy ("$directory_confs/$agent.conf", "$directory_temp/$md5_agent_name.conf");
send_file ("$directory_temp/$md5_agent_name.conf", $conf);
send_file ("$directory_temp/$md5_agent_name.md5", $conf);
log_message ($conf, "\tINFO:\tUploading configuration for the first time.");
unlink ("$directory_temp/$md5_agent_name.conf");
unlink ("$directory_temp/$md5_agent_name.md5");
}
else {
log_message ($conf, "\tERROR:\tThe $agent.conf is not create.'\n");
}
}
# Fill the local conf for generate data
my $conf = parse_local_conf($agent, $conf);
$local_conf->{$agent} = $conf;
}
}
}
################################################################################
# Parse local conf.
################################################################################
sub parse_local_conf($$) {
my ($agent_name, $conf) = @_;
my $directory_confs = get_conf_token($conf, 'directory_confs', '.');
my @return;
if (open (CONF_FILE, "$directory_confs/$agent_name.conf")) {
my $line = '';
while (<CONF_FILE>) {
$line = $_;
# A module definition
if ($line =~ m/module_begin/) {
my %module;
# A comment
next if ($line =~ m/^#/);
while (my $line = <CONF_FILE>) {
# A comment
next if ($line =~ m/^#/);
last if ($line =~ m/module_end/);
# Unknown line
next if ($line !~ /^\s*(\w+)\s+(.+)$/);
$module{$1} = $2;
}
push(@return, \%module);
}
}
close (CONF_FILE);
}
else {
log_message ($conf, "\tERROR:\tOpen to parse the $agent_name.conf.'\n");
}
return \@return;
}
################################################################################
# Main
################################################################################
my (%conf, @modules);
# Check command line parameters
if ($#ARGV != 0) {
print "Usage:\n\t$0 <configuration file>\n\n";
exit 1;
}
# Load configuration file
load_config ($ARGV[0], %conf, @modules);
die ("[error] No agent file specified in configuration file.\n\n") unless defined ($conf{'agent_file'});
open (FILE, "<", $conf{'agent_file'}) ||
die ("[error] Could not open agent configuration file '" . $conf{'agent_file'} . "': $!.\n\n");
# Read agent names
my @agents;
while (my $agent_name = <FILE>) {
chomp ($agent_name);
push (@agents, $agent_name);
$Agents++;
}
close (FILE);
# Init MD5
md5_init();
# Get the agent conf, instead use the conf in the pandora_xml_stress.conf
my %local_conf;
get_and_send_agent_conf(@agents, %conf, @modules, %local_conf);
# Get the maximum number of threads and the number of agents per thread
my $max_threads = 0 + get_conf_token (\%conf, 'max_threads', '10');
my $step = ceil ($Agents / $max_threads);
my $t0 = gettimeofday ();
for (my $i = 0; $i < $Agents; $i += $step) {
threads->create (\&generate_xml_files, \@agents, $i, $step, \%conf, \@modules, \%local_conf);
}
# Log some information for the user
my $time_now = strftime ("%Y-%m-%d %H:%M:%S", localtime ());
my $time_from = get_conf_token (\%conf, 'time_from', $time_now);
my $time_to = get_conf_token (\%conf, 'time_to', $time_now);
my $interval = get_conf_token (\%conf, 'agent_interval', '300');
log_message (\%conf, "Generating XML data files for $Agents agents from $time_from to $time_to interval $interval.");
# Wait for all threads to finish
foreach my $thr (threads->list()) {
$thr->join ();
}
my $t1 = gettimeofday ();
# Log statistics
log_message (\%conf, "\tTotal agents:\t$Agents\n\t\tTotal modules:\t" . ($Agents * $Modules) . "\t($Modules per agent)\n\t\tTotal XML:\t$XMLFiles\t(" . int ($XMLFiles / ($t1 - $t0)) . " per second)");