diff --git a/pandora_server/ChangeLog b/pandora_server/ChangeLog index 14192991c9..5e699d32a6 100644 --- a/pandora_server/ChangeLog +++ b/pandora_server/ChangeLog @@ -1,3 +1,11 @@ +2011-05-04 Miguel de Dios + + * util/pandora_xml_stress.pl: changed the source code to generate local conf + for each agent. And in next executions you can change in remote conf in + Pandora Console Enteprise as real agent. + + * util/pandora_xml_stress.README: added confs for the generate local conf. + 2011-05-04 Sergio Martin * util/pandora_manage.pl: Added standby field to be propagated diff --git a/pandora_server/util/pandora_xml_stress.README b/pandora_server/util/pandora_xml_stress.README index 7871b24efa..e0c7c99fc7 100644 --- a/pandora_server/util/pandora_xml_stress.README +++ b/pandora_server/util/pandora_xml_stress.README @@ -51,6 +51,14 @@ time_from 2009-06-01 00:00:00 # Data file generation end date, by default now. time_to 2009-06-05 00:00:00 +# Get and send the conf of agent from Pandora +get_and_send_agent_conf 1 + +# Directory of fake confs. +directory_confs . +# Directory of fake temp. +directory_temp /tmp + # Delay after generating the first data file for each agent to avoid # race conditions when auto-creating the agent, by default 2. startup_delay 2 @@ -80,11 +88,14 @@ altitude_base 0 position_radius 10 # Address of the Tentacle server where XML files will be sent (optional). -# server_ip 192.168.50.1 +#server_ip 127.0.0.1 # Port of the Tentacle server, by default 41121. # server_port 41121 +# Tentacle options. +#tentacle_options + # Module definitions. Similar to pandora_agent.conf. module_begin diff --git a/pandora_server/util/pandora_xml_stress.pl b/pandora_server/util/pandora_xml_stress.pl index 48eddc3709..bc00c7884f 100755 --- a/pandora_server/util/pandora_xml_stress.pl +++ b/pandora_server/util/pandora_xml_stress.pl @@ -24,11 +24,13 @@ use threads::shared; use Time::Local; use Time::HiRes qw(gettimeofday); -use POSIX qw (strftime ceil); +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; @@ -82,8 +84,8 @@ sub load_config ($\%\@) { ################################################################################ # Generate XML files. ################################################################################ -sub generate_xml_files ($$$$$) { - my ($agents, $start, $step, $conf, $modules) = @_; +sub generate_xml_files ($$$$$$) { + my ($agents, $start, $step, $conf, $modules, $local_conf) = @_; # Read agent configuration my $interval = get_conf_token ($conf, 'agent_interval', '300'); @@ -119,6 +121,12 @@ sub generate_xml_files ($$$$$) { # 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; @@ -130,8 +138,8 @@ sub generate_xml_files ($$$$$) { my $sign = int rand(2); $ag_timezone_offset += ($sign*(-1)+(1-$sign)) * int rand($ag_timezone_offset_range); $xml_data .= "\n"; + foreach my $module (@{$modules}) { - # Skip unnamed modules my $module_name = get_conf_token ($module, 'module_name', ''); next if ($module_name eq ''); @@ -214,6 +222,7 @@ sub generate_xml_files ($$$$$) { $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_file = $temporal . '/' . $agent_name . '_' . $utimestamp . '.data'; open (FILE, ">", $xml_file) || die ("[error] Could not write to '$xml_file': $!.\n\n"); print FILE $xml_data; @@ -375,6 +384,389 @@ sub log_message ($$) { } } + + +################################################################################ +# 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;printf($file . "\n"); + 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 ('', )); + 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 = ; + 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 .= " +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 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 ('', )); + 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, "\ERROR:\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 () { + $line = $_; + + # A module definition + if ($line =~ m/module_begin/) { + my %module; + + # A comment + next if ($line =~ m/^#/); + + while (my $line = ) { + + # 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, "\ERROR:\tOpen to parse the $agent_name.conf.'\n"); + } + + return \@return; +} + + ################################################################################ # Main ################################################################################ @@ -402,14 +794,21 @@ while (my $agent_name = ) { } 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_threadss', '10'); +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); + threads->create (\&generate_xml_files, \@agents, $i, $step, \%conf, \@modules, \%local_conf); } # Log some information for the user