#!/usr/bin/perl # # This software was created by Alteeve's Niche! Inc. and has been released # under the terms of the GNU GPL version 2. # # ScanCore Scan Agent for monitoring status of equipment available through standard tools, like proc file # data for CPUs and memory. # # https://alteeve.com # # Exit Codes: # 0 - Success # Use my modules. use strict; use warnings; use AN::Tools; use Data::Dumper; use Socket; no warnings 'recursion'; #use utf8; #binmode STDOUT, 'encoding(utf8)'; # Disable buffering. $| = 1; # Figure out who and where I am. my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; if (($running_directory =~ /^\./) && ($ENV{PWD})) { $running_directory =~ s/^\./$ENV{PWD}/; } my $scancore_directory = ($running_directory =~ /^(.*?)\/agents\/$THIS_FILE$/)[0]; ### TODO: Rework this whole agent... # Get the handle to the AN::Tools and preset some variables I will use. my $an = AN::Tools->new({data => { path => { core_strings => "$scancore_directory/ScanCore.xml", sql => "$running_directory/$THIS_FILE.sql", striker_config => "/etc/striker/striker.conf", striker_strings => "/sbin/striker/Data/strings.xml", strings => "$running_directory/$THIS_FILE.xml", }, sys => { alert_sort => 0, # When a lock is requested, this is set to the time the lock was set. # DB->do_db_write() and DB->do_db_read() will check this and if its age is >50% of # scancore::locking::reap_age, it will renew the lock. local_lock_active => 0, scanning_myself => 0, sql => [], }, scancore => { archive => { directory => "/var/ScanCore/archives/", division => 25000, trigger => 20000, count => 10000, dump_file_header => " SET statement_timeout = 0; SET lock_timeout = 0; SET client_encoding = 'UTF8'; SET standard_conforming_strings = on; SET check_function_bodies = false; SET client_min_messages = warning; SET row_security = off; SET search_path = history, pg_catalog; ", }, }, 'scan-hardware' => { disable => 0, language => "en_CA", log_file => "/var/log/ScanCore.log", log_level => 1, log_language => "en_CA", log_db_transactions => 0, swap => { high => 75, # Swap use over this percentage triggers alert low => 25, # Swap use below this percentage clears alert }, }, }, }); # Read the config file $an->Storage->read_conf({file => $an->data->{path}{striker_config}}); # Set some defaults $an->default_language ($an->data->{'scan-hardware'}{language}); $an->default_log_language($an->data->{'scan-hardware'}{log_language}); $an->default_log_file ($an->data->{'scan-hardware'}{log_file}); # Set the log level. $an->Log->level($an->data->{'scan-hardware'}{log_level}); $an->Log->db_transactions(1) if $an->data->{'scan-hardware'}{log_db_transactions}; # Read in the language strings. $an->Storage->read_words({file => $an->data->{path}{strings}}); $an->Storage->read_words({file => $an->data->{path}{core_strings}}); $an->Storage->read_words({file => $an->data->{path}{striker_strings}}); # Get the switches before printing anything in case the user is asking for help. $an->Get->switches(); $an->Log->adjust_log_level({key => $THIS_FILE}); # Help? if (($an->data->{switches}{h}) or ($an->data->{switches}{'?'}) or ($an->data->{switches}{help})) { # Help! print_usage($an); $an->nice_exit({exit_code => 0}); } # Exit if we're disabled. if ($an->data->{'scan-hardware'}{disable}) { $an->nice_exit({exit_code => 1}); } print $an->String->get({key => "scan_hardware_message_0001"})."\n"; # I'll need to loop through the DBs and ensure our schema is loaded for each one. my $connections = $an->DB->connect_to_databases({file => $THIS_FILE}); $an->Log->entry({log_level => 3, message_key => "notice_message_0013", message_variables => { connections => $connections }, file => $THIS_FILE, line => __LINE__}); # Make sure this host's UUID is in the 'hosts' table. If the user is running this directly without first # running ScanCore, it won't be. if (not $an->DB->verify_host_uuid()) { # ScanCore hasn't run, this host isn't in the 'hosts' table. $an->Alert->error({title_key => "an_0003", message_key => "scancore_error_0020", message_variables => { uuid => $an->data->{sys}{host_uuid} }, code => 255, file => $THIS_FILE, line => __LINE__}); } # If we were called with '--prep-db', we'll prep the database schema regardless. if ($an->data->{switches}{'prep-db'}) { if ($connections) { prep_databases($an); } else { # Failed $an->Log->entry({log_level => 1, message_key => "scancore_warning_0031", file => $THIS_FILE, line => __LINE__}); print $an->String->get({key => "scancore_warning_0031"})."\n"; } } # Read the data. collect_data($an); # Do the loading of the schemas and copying data from more up to date DBs if the DB was loaded. prep_databases($an); # Archive, if needed. archive_if_needed($an); # Look to see if any databases need to be updated. update_db($an); # Read in the last scan data, if any. read_last_scan($an); # Look for changes. find_changes($an); # Finally, process health weights. process_health($an); # Update the database $an->DB->update_time({file => $THIS_FILE}); # Clean up and go away. $an->nice_exit({exit_code => 0}); ############################################################################################################# # Functions # ############################################################################################################# # Here we see if our peer has more or less RAM. If we have less, we'll mark our health as degraded. sub process_health { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "process_health" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); # Only do this on nodes. my $i_am_a = $an->Get->what_am_i(); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "i_am_a", value1 => $i_am_a, }, file => $THIS_FILE, line => __LINE__}); return(0) if $i_am_a ne "node"; my $peer_hostname = $an->Cman->peer_hostname(); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "peer_hostname", value1 => $peer_hostname, }, file => $THIS_FILE, line => __LINE__}); # Find the host_uuid for the peer's hostname. my $query = "SELECT host_uuid FROM hosts WHERE host_name = ".$an->data->{sys}{use_db_fh}->quote($peer_hostname).";"; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); my $peer_host_uuid = $an->DB->do_db_query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $peer_host_uuid = "" if not defined $peer_host_uuid; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "peer_host_uuid", value1 => $peer_host_uuid, }, file => $THIS_FILE, line => __LINE__}); # How much RAM is on the other node? $query = "SELECT hardware_ram_total FROM hardware WHERE hardware_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($peer_host_uuid).";"; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); my $peer_ram_total = $an->DB->do_db_query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $peer_ram_total = "" if not defined $peer_ram_total; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "peer_ram_total", value1 => $an->Readable->comma($peer_ram_total)." (".$an->Readable->bytes_to_hr({'bytes' => $peer_ram_total}).")", }, file => $THIS_FILE, line => __LINE__}); # Do we know the peer's RAM? if ($peer_ram_total) { # We don't want to freak out unless the difference is at least 1GiB my $hardware_ram_total = $an->data->{summary}{ram}{size}; my $difference = $peer_ram_total - $hardware_ram_total; $an->Log->entry({log_level => 2, message_key => "an_variables_0002", message_variables => { name1 => "hardware_ram_total", value1 => $an->Readable->comma($hardware_ram_total)." (".$an->Readable->bytes_to_hr({'bytes' => $hardware_ram_total}).")", name2 => "difference", value2 => $an->Readable->comma($difference)." (".$an->Readable->bytes_to_hr({'bytes' => $difference}).")", }, file => $THIS_FILE, line => __LINE__}); # greater than 1 GiB or less than 128 MiB if (($peer_ram_total > $hardware_ram_total) && ($difference > 1073741824)) { # Mark us as having a fairly major health issue. print $THIS_FILE." ".__LINE__."; difference\n"; my $set = $an->Alert->check_alert_sent({ type => "warning", # This is not the alert level, 'warning' == trouble, 'clear' == ok now. alert_sent_by => $THIS_FILE, alert_record_locator => "na", alert_name => "less_ram_than_peer", modified_date => $an->data->{sys}{db_timestamp}, }); $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "set", value1 => $set, }, file => $THIS_FILE, line => __LINE__}); if ($set) { # Warn the user. $an->Alert->register_alert({ alert_level => "warning", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0004", alert_message_key => "scan_hardware_note_0009", alert_message_variables => { difference => $an->Readable->bytes_to_hr({'bytes' => $difference})." (".$an->Readable->comma($difference)." #!string!suffix_0009!#)", local_ram => $an->Readable->bytes_to_hr({'bytes' => $hardware_ram_total})." (".$an->Readable->comma($hardware_ram_total)." #!string!suffix_0009!#)", peer_ram => $an->Readable->bytes_to_hr({'bytes' => $peer_ram_total})." (".$an->Readable->comma($peer_ram_total)." #!string!suffix_0009!#)", }, }); my $query = " INSERT INTO health ( health_uuid, health_host_uuid, health_agent_name, health_source_name, health_source_weight, modified_date ) VALUES ( ".$an->data->{sys}{use_db_fh}->quote($an->Get->uuid).", ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid}).", ".$an->data->{sys}{use_db_fh}->quote($THIS_FILE).", 'less_ram_than_peer', '5', ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{db_timestamp})." );"; $an->Log->entry({log_level => 1, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); $an->DB->do_db_write({query => $query, source => $THIS_FILE, line => __LINE__}); } } elsif (($peer_ram_total == $hardware_ram_total) or ($difference < 134217728)) { # If there was a difference before, clear it. my $clear = 0; my $set = $an->Alert->check_alert_sent({ type => "clear", # This is not the alert level, 'warning' == trouble, 'clear' == ok now. alert_sent_by => $THIS_FILE, alert_record_locator => "na", alert_name => "less_ram_than_peer", modified_date => $an->data->{sys}{db_timestamp}, }); $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "set", value1 => $set, }, file => $THIS_FILE, line => __LINE__}); if (not $set) { # There's a bug where the $query = "SELECT health_uuid FROM health WHERE health_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." AND health_source_name = 'less_ram_than_peer';"; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); my $health_uuid = $an->DB->do_db_query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $health_uuid = "" if not defined $health_uuid; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "health_uuid", value1 => $health_uuid, }, file => $THIS_FILE, line => __LINE__}); if ($health_uuid) { # Clear it. $clear = 1; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "clear", value1 => $clear, }, file => $THIS_FILE, line => __LINE__}); } } if ($set) { # Clear the warning $an->Alert->register_alert({ alert_level => "clear", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0004", alert_message_key => "scan_hardware_note_0010", alert_message_variables => { difference => $an->Readable->bytes_to_hr({'bytes' => $difference})." (".$an->Readable->comma($difference)." #!string!suffix_0009!#)", local_ram => $an->Readable->bytes_to_hr({'bytes' => $hardware_ram_total})." (".$an->Readable->comma($hardware_ram_total)." #!string!suffix_0009!#)", peer_ram => $an->Readable->bytes_to_hr({'bytes' => $peer_ram_total})." (".$an->Readable->comma($peer_ram_total)." #!string!suffix_0009!#)", }, }); $clear = 1;; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "clear", value1 => $clear, }, file => $THIS_FILE, line => __LINE__}); } $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "clear", value1 => $clear, }, file => $THIS_FILE, line => __LINE__}); if ($clear) { # Get the health_uuid my $query = "SELECT health_uuid FROM health WHERE health_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." AND health_source_name = 'less_ram_than_peer';"; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); my $health_uuid = $an->DB->do_db_query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $health_uuid = "" if not defined $health_uuid; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "health_uuid", value1 => $health_uuid, }, file => $THIS_FILE, line => __LINE__}); # Mark it as deleted for the history schema. if ($health_uuid) { my $query = " UPDATE health SET health_source_name = 'DELETED', health_source_weight = '0', modified_date = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{db_timestamp})." WHERE health_uuid = ".$an->data->{sys}{use_db_fh}->quote($health_uuid)." ;"; $an->Log->entry({log_level => 1, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); $an->DB->do_db_write({query => $query, source => $THIS_FILE, line => __LINE__}); # Now actually delete it. $query = " DELETE FROM health WHERE health_uuid = ".$an->data->{sys}{use_db_fh}->quote($health_uuid)." ;"; $an->Log->entry({log_level => 1, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); $an->DB->do_db_write({query => $query, source => $THIS_FILE, line => __LINE__}); } } } } return(0); } # This reads in the last scan data from one of the databases and compares it against the just-read data. If # anything changed, register an alert. sub find_changes { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "find_changes" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); # Walk through what I know. First the main info, then the RAM modules below. my $new_hardware_cpu_model = $an->data->{summary}{cpu}{model}; my $new_hardware_cpu_cores = $an->data->{summary}{cpu}{cores}; my $new_hardware_cpu_threads = $an->data->{summary}{cpu}{threads}; my $new_hardware_cpu_bugs = $an->data->{summary}{cpu}{bugs}; my $new_hardware_cpu_flags = $an->data->{summary}{cpu}{flags}; my $new_hardware_led_id = $an->data->{summary}{led}{id_led}; my $new_hardware_led_css = $an->data->{summary}{led}{css_led}; my $new_hardware_led_error = $an->data->{summary}{led}{error_led}; my $new_hardware_ram_total = $an->data->{summary}{ram}{size}; # This is from counting the actual module capacity my $new_hardware_memory_total = $an->data->{summary}{ram}{proc}{memory_total}; # This is from /proc/meminfo and subtracts RAM used by shared video, etc. my $new_hardware_memory_free = $an->data->{summary}{ram}{proc}{memory_free}; my $new_hardware_swap_total = $an->data->{summary}{ram}{proc}{swap_total}; my $new_hardware_swap_free = $an->data->{summary}{ram}{proc}{swap_free}; $an->Log->entry({log_level => 2, message_key => "an_variables_0013", message_variables => { name1 => "new_hardware_cpu_model", value1 => $new_hardware_cpu_model, name2 => "new_hardware_cpu_cores", value2 => $new_hardware_cpu_cores, name3 => "new_hardware_cpu_threads", value3 => $new_hardware_cpu_threads, name4 => "new_hardware_cpu_bugs", value4 => $new_hardware_cpu_bugs, name5 => "new_hardware_cpu_flags", value5 => $new_hardware_cpu_flags, name6 => "new_hardware_led_id", value6 => $new_hardware_led_id, name7 => "new_hardware_led_css", value7 => $new_hardware_led_css, name8 => "new_hardware_ram_total", value8 => $new_hardware_ram_total, name9 => "new_hardware_led_error", value9 => $new_hardware_led_error, name10 => "new_hardware_memory_total", value10 => $an->Readable->comma($new_hardware_memory_total)." (".$an->Readable->bytes_to_hr({'bytes' => $new_hardware_memory_total}).")", name11 => "new_hardware_memory_free", value11 => $an->Readable->comma($new_hardware_memory_free)." (".$an->Readable->bytes_to_hr({'bytes' => $new_hardware_memory_free}).")", name12 => "new_hardware_swap_total", value12 => $an->Readable->comma($new_hardware_swap_total)." (".$an->Readable->bytes_to_hr({'bytes' => $new_hardware_swap_total}).")", name13 => "new_hardware_swap_free", value13 => $an->Readable->comma($new_hardware_swap_free)." (".$an->Readable->bytes_to_hr({'bytes' => $new_hardware_swap_free}).")", }, file => $THIS_FILE, line => __LINE__}); # The LED status needs to be translated. my $say_new_hardware_led_id = "#!string!state_0001!#"; if ($new_hardware_led_id eq "on") { $say_new_hardware_led_id = "#!string!state_0039!#"; } elsif ($new_hardware_led_id eq "on") { $say_new_hardware_led_id = "#!string!state_0040!#"; } my $say_new_hardware_led_css = "#!string!state_0001!#"; if ($new_hardware_led_css eq "on") { $say_new_hardware_led_css = "#!string!state_0039!#"; } elsif ($new_hardware_led_css eq "on") { $say_new_hardware_led_css = "#!string!state_0040!#"; } my $say_new_hardware_led_error = "#!string!state_0001!#"; if ($new_hardware_led_error eq "on") { $say_new_hardware_led_error = "#!string!state_0039!#"; } elsif ($new_hardware_led_error eq "on") { $say_new_hardware_led_error = "#!string!state_0040!#"; } $an->Log->entry({log_level => 2, message_key => "an_variables_0003", message_variables => { name1 => "say_new_hardware_led_id", value1 => $say_new_hardware_led_id, name2 => "say_new_hardware_led_css", value2 => $say_new_hardware_led_css, name3 => "say_new_hardware_led_error", value3 => $say_new_hardware_led_error, }, file => $THIS_FILE, line => __LINE__}); # INSERT or UPDATE? if ((exists $an->data->{sql}{hardware_uuid}) && ($an->data->{sql}{hardware_uuid})) { # Look for changed. my $hardware_uuid = $an->data->{sql}{hardware_uuid}; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "hardware_uuid", value1 => $hardware_uuid }, file => $THIS_FILE, line => __LINE__}); my $old_hardware_cpu_model = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_model}; my $old_hardware_cpu_cores = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_cores}; my $old_hardware_cpu_threads = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_threads}; my $old_hardware_cpu_bugs = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_bugs}; my $old_hardware_cpu_flags = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_flags}; my $old_hardware_ram_total = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_ram_total}; my $old_hardware_memory_total = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_memory_total}; my $old_hardware_memory_free = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_memory_free}; my $old_hardware_swap_total = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_swap_total}; my $old_hardware_swap_free = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_swap_free}; my $old_hardware_led_id = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_led_id}; my $old_hardware_led_css = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_led_css}; my $old_hardware_led_error = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_led_error}; my $old_hardware_modified_date = $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_modified_date}; $an->Log->entry({log_level => 3, message_key => "an_variables_0013", message_variables => { name1 => "old_hardware_cpu_model", value1 => $old_hardware_cpu_model, name2 => "old_hardware_cpu_cores", value2 => $old_hardware_cpu_cores, name3 => "old_hardware_cpu_threads", value3 => $old_hardware_cpu_threads, name4 => "old_hardware_cpu_bugs", value4 => $old_hardware_cpu_bugs, name5 => "old_hardware_cpu_flags", value5 => $old_hardware_cpu_flags, name6 => "old_hardware_ram_total", value6 => $old_hardware_ram_total, name7 => "old_hardware_memory_total", value7 => $old_hardware_memory_total, name8 => "old_hardware_memory_free", value8 => $old_hardware_memory_free, name9 => "old_hardware_swap_total", value9 => $old_hardware_swap_total, name10 => "old_hardware_swap_free", value10 => $old_hardware_swap_free, name11 => "old_hardware_led_id", value11 => $old_hardware_led_id, name12 => "old_hardware_led_css", value12 => $old_hardware_led_css, name13 => "old_hardware_led_error", value13 => $old_hardware_led_error, name14 => "old_hardware_modified_date", value14 => $old_hardware_modified_date, }, file => $THIS_FILE, line => __LINE__}); my $update = 0; if (($new_hardware_cpu_model ne $old_hardware_cpu_model) or ($new_hardware_cpu_cores ne $old_hardware_cpu_cores) or ($new_hardware_cpu_threads ne $old_hardware_cpu_threads) or ($new_hardware_cpu_bugs ne $old_hardware_cpu_bugs) or ($new_hardware_cpu_flags ne $old_hardware_cpu_flags) or ($new_hardware_ram_total ne $old_hardware_ram_total) or ($new_hardware_memory_total ne $old_hardware_memory_total) or ($new_hardware_swap_total ne $old_hardware_swap_total) or ($new_hardware_led_id ne $old_hardware_led_id) or ($new_hardware_led_css ne $old_hardware_led_css) or ($new_hardware_led_error ne $old_hardware_led_error)) { # Something important changed, report. $update = 1; # The LED status needs to be translated. my $say_old_hardware_led_id = "#!string!state_0001!#"; if ($old_hardware_led_id eq "on") { $say_old_hardware_led_id = "#!string!state_0039!#"; } elsif ($old_hardware_led_id eq "on") { $say_old_hardware_led_id = "#!string!state_0040!#"; } my $say_old_hardware_led_css = "#!string!state_0001!#"; if ($old_hardware_led_css eq "on") { $say_old_hardware_led_css = "#!string!state_0039!#"; } elsif ($old_hardware_led_css eq "on") { $say_old_hardware_led_css = "#!string!state_0040!#"; } my $say_old_hardware_led_error = "#!string!state_0001!#"; if ($old_hardware_led_error eq "on") { $say_old_hardware_led_error = "#!string!state_0039!#"; } elsif ($old_hardware_led_error eq "on") { $say_old_hardware_led_error = "#!string!state_0040!#"; } $an->Log->entry({log_level => 2, message_key => "an_variables_0003", message_variables => { name1 => "say_old_hardware_led_id", value1 => $say_old_hardware_led_id, name2 => "say_old_hardware_led_css", value2 => $say_old_hardware_led_css, name3 => "say_old_hardware_led_error", value3 => $say_old_hardware_led_error, }, file => $THIS_FILE, line => __LINE__}); $an->Alert->register_alert({ alert_level => "warning", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0004", alert_message_key => "scan_hardware_note_0004", alert_message_variables => { new_cpu_model => $new_hardware_cpu_model, new_total_cores => $new_hardware_cpu_cores, new_total_threads => $new_hardware_cpu_threads, new_cpu_bugs => $new_hardware_cpu_bugs, new_cpu_flags => $new_hardware_cpu_flags, new_id_led => $say_new_hardware_led_id, new_css_led => $say_new_hardware_led_css, new_error_led => $say_new_hardware_led_error, new_ram_total_size => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_ram_total})." (".$an->Readable->comma($new_hardware_ram_total)." #!string!suffix_0009!#)", new_ram_memory_total => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_memory_total})." (".$an->Readable->comma($new_hardware_memory_total)." #!string!suffix_0009!#)", new_ram_swap_total => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_swap_total})." (".$an->Readable->comma($new_hardware_swap_total)." #!string!suffix_0009!#)", old_cpu_model => $old_hardware_cpu_model, old_total_cores => $old_hardware_cpu_cores, old_total_threads => $old_hardware_cpu_threads, old_cpu_bugs => $old_hardware_cpu_bugs, old_cpu_flags => $old_hardware_cpu_flags, old_id_led => $say_old_hardware_led_id, old_css_led => $say_old_hardware_led_css, old_error_led => $say_old_hardware_led_error, old_ram_total_size => $an->Readable->bytes_to_hr({'bytes' => $old_hardware_ram_total})." (".$an->Readable->comma($old_hardware_ram_total)." #!string!suffix_0009!#)", old_ram_memory_total => $an->Readable->bytes_to_hr({'bytes' => $old_hardware_memory_total})." (".$an->Readable->comma($old_hardware_memory_total)." #!string!suffix_0009!#)", old_ram_swap_total => $an->Readable->bytes_to_hr({'bytes' => $old_hardware_swap_total})." (".$an->Readable->comma($old_hardware_swap_total)." #!string!suffix_0009!#)", }, }); } elsif (($new_hardware_memory_free ne $old_hardware_memory_free) or ($new_hardware_swap_free ne $old_hardware_swap_free)) { # The RAM is always changing, so we only record when it crosses certain thresholds. # First, have we recorded the RAM change in a while? my $last_update = time - $old_hardware_modified_date; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "last_update", value1 => $last_update, }, file => $THIS_FILE, line => __LINE__}); if ($last_update > 900) { # Time to record the amount of free memory. Don't generate an alert. $update = 1; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "update", value1 => $update, }, file => $THIS_FILE, line => __LINE__}); } # If we have swap, have we gone over 25% (alert) used or below 10% (clear)? if ($new_hardware_swap_total) { # We have swap, how much is used, as a percentage? my $new_swap_bytes_used = $new_hardware_swap_total - $new_hardware_swap_free; my $old_swap_bytes_used = $old_hardware_swap_total - $old_hardware_swap_free; my $new_swap_percent_used = $an->Math->round({number => (($new_swap_bytes_used / $new_hardware_swap_total) * 100)}); my $old_swap_percent_used = $an->Math->round({number => (($old_swap_bytes_used / $old_hardware_swap_total) * 100)}); my $swap_percent_high = $an->data->{'scan-hardware'}{swap}{high} =~ /^\d+/ ? $an->data->{'scan-hardware'}{swap}{high} : 75; my $swap_percent_low = $an->data->{'scan-hardware'}{swap}{low} =~ /^\d+/ ? $an->data->{'scan-hardware'}{swap}{low} : 25; $an->Log->entry({log_level => 2, message_key => "an_variables_0006", message_variables => { name1 => "new_swap_bytes_used", value1 => $new_swap_bytes_used, name2 => "new_swap_percent_used", value2 => $new_swap_percent_used, name3 => "old_swap_bytes_used", value3 => $old_swap_bytes_used, name4 => "old_swap_percent_used", value4 => $old_swap_percent_used, name5 => "swap_percent_high", value5 => $swap_percent_high, name6 => "swap_percent_low", value6 => $swap_percent_low, }, file => $THIS_FILE, line => __LINE__}); if (($new_swap_percent_used > $swap_percent_high) && ($new_swap_percent_used <= $swap_percent_high)) { # Gone high, alert. $update = 1; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "update", value1 => $update, }, file => $THIS_FILE, line => __LINE__}); # Send an alert telling the user that we've found a new controller. $an->Alert->register_alert({ alert_level => "notice", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0003", alert_message_key => "scan_hardware_note_0002", alert_message_variables => { swap_high => $swap_percent_high, swap_low => $swap_percent_low, swap_used_percent => $new_swap_percent_used, swap_total => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_swap_total})." (".$an->Readable->comma($new_hardware_swap_total)." #!string!suffix_0009!#)", }, }); } elsif (($new_swap_percent_used < $swap_percent_low) && ($old_swap_percent_used >= $swap_percent_low)) { # Dropped low, clear. $update = 1; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "update", value1 => $update, }, file => $THIS_FILE, line => __LINE__}); # Send an alert telling the user that we've found a new controller. $an->Alert->register_alert({ alert_level => "notice", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0003", alert_message_key => "scan_hardware_note_0003", alert_message_variables => { swap_high => $swap_percent_high, swap_low => $swap_percent_low, swap_used_percent => $new_swap_percent_used, swap_total => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_swap_total})." (".$an->Readable->comma($new_hardware_swap_total)." #!string!suffix_0009!#)", }, }); } } } # Update? $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "update", value1 => $update, }, file => $THIS_FILE, line => __LINE__}); if ($update) { # Yup! my $query = " UPDATE public.hardware SET hardware_cpu_model = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_model).", hardware_cpu_cores = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_cores).", hardware_cpu_threads = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_threads).", hardware_cpu_bugs = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_bugs).", hardware_cpu_flags = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_flags).", hardware_ram_total = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_total).", hardware_memory_total = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_memory_total).", hardware_memory_free = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_memory_free).", hardware_swap_total = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_swap_total).", hardware_swap_free = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_swap_free).", hardware_led_id = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_led_id).", hardware_led_css = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_led_css).", hardware_led_error = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_led_error).", modified_date = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{db_timestamp})." WHERE hardware_uuid = ".$an->data->{sys}{use_db_fh}->quote($hardware_uuid)." ;"; # Now record the query in the array $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); $an->DB->do_db_write({query => $query, source => $THIS_FILE, line => __LINE__}); } } else { # Send an alert telling the user that we've recorded this data. $an->Alert->register_alert({ alert_level => "notice", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0003", alert_message_key => "scan_hardware_note_0001", alert_message_variables => { cpu_model => $new_hardware_cpu_model, total_cores => $new_hardware_cpu_cores, total_threads => $new_hardware_cpu_threads, cpu_bugs => $new_hardware_cpu_bugs, cpu_flags => $new_hardware_cpu_flags, id_led => $say_new_hardware_led_id, css_led => $say_new_hardware_led_css, error_led => $say_new_hardware_led_error, ram_total_size => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_ram_total})." (".$an->Readable->comma($new_hardware_ram_total)." #!string!suffix_0009!#)", ram_memory_total => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_memory_total})." (".$an->Readable->comma($new_hardware_memory_total)." #!string!suffix_0009!#)", ram_memory_free => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_memory_free})." (".$an->Readable->comma($new_hardware_memory_free)." #!string!suffix_0009!#)", ram_swap_total => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_swap_total})." (".$an->Readable->comma($new_hardware_swap_total)." #!string!suffix_0009!#)", ram_swap_free => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_swap_free})." (".$an->Readable->comma($new_hardware_swap_free)." #!string!suffix_0009!#)", }, }); # INSERT my $hardware_uuid = $an->Get->uuid(); my $query = " INSERT INTO hardware ( hardware_uuid, hardware_host_uuid, hardware_cpu_model, hardware_cpu_cores, hardware_cpu_threads, hardware_cpu_bugs, hardware_cpu_flags, hardware_ram_total, hardware_memory_total, hardware_memory_free, hardware_swap_total, hardware_swap_free, hardware_led_id, hardware_led_css, hardware_led_error, modified_date ) VALUES ( ".$an->data->{sys}{use_db_fh}->quote($hardware_uuid).", ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid}).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_model).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_cores).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_threads).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_bugs).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_cpu_flags).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_total).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_memory_total).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_memory_free).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_swap_total).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_swap_free).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_led_id).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_led_css).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_led_css).", ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{db_timestamp})." );"; # Now record the query in the array $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); $an->DB->do_db_write({query => $query, source => $THIS_FILE, line => __LINE__}); } # Now the RAM modules. foreach my $hardware_ram_module_locator (sort {$a cmp $b} keys %{$an->data->{ram}{dmi}{locator}}) { my $new_hardware_ram_module_size = $an->data->{ram}{dmi}{locator}{$hardware_ram_module_locator}{size}; my $new_hardware_ram_module_manufacturer = $an->data->{ram}{dmi}{locator}{$hardware_ram_module_locator}{manufacturer}; my $new_hardware_ram_module_model = $an->data->{ram}{dmi}{locator}{$hardware_ram_module_locator}{part_number}; my $new_hardware_ram_module_serial_number = $an->data->{ram}{dmi}{locator}{$hardware_ram_module_locator}{serial_number}; $an->Log->entry({log_level => 3, message_key => "an_variables_0005", message_variables => { name1 => "hardware_ram_module_locator", value1 => $hardware_ram_module_locator, name2 => "new_hardware_ram_module_size", value2 => $an->Readable->comma($new_hardware_ram_module_size)." (".$an->Readable->bytes_to_hr({'bytes' => $new_hardware_ram_module_size}).")", name3 => "new_hardware_ram_module_manufacturer", value3 => $new_hardware_ram_module_manufacturer, name4 => "new_hardware_ram_module_model", value4 => $new_hardware_ram_module_model, name5 => "new_hardware_ram_module_serial_number", value5 => $new_hardware_ram_module_serial_number, }, file => $THIS_FILE, line => __LINE__}); if ((exists $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator}) && ($an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator})) { # We've seen this module before, look for changes. my $hardware_ram_module_uuid = $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator}; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "sql::hardware_ram_module_uuid::${hardware_ram_module_locator}", value1 => $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator}, }, file => $THIS_FILE, line => __LINE__}); my $old_hardware_ram_module_size = $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_size}; my $old_hardware_ram_module_manufacturer = $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_manufacturer}; my $old_hardware_ram_module_model = $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_model}; my $old_hardware_ram_module_serial_number = $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_serial_number}; $an->Log->entry({log_level => 3, message_key => "an_variables_0004", message_variables => { name1 => "old_hardware_ram_module_size", value1 => $an->Readable->comma($old_hardware_ram_module_size)." (".$an->Readable->bytes_to_hr({'bytes' => $old_hardware_ram_module_size}).")", name2 => "old_hardware_ram_module_manufacturer", value2 => $old_hardware_ram_module_manufacturer, name3 => "old_hardware_ram_module_model", value3 => $old_hardware_ram_module_model, name4 => "old_hardware_ram_module_serial_number", value4 => $old_hardware_ram_module_serial_number, }, file => $THIS_FILE, line => __LINE__}); # Delete the entry so we know we've processed this existing module. delete $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator}; delete $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}; # Looks for changes. if (($new_hardware_ram_module_size ne $old_hardware_ram_module_size) or ($new_hardware_ram_module_manufacturer ne $old_hardware_ram_module_manufacturer) or ($old_hardware_ram_module_model ne $old_hardware_ram_module_model) or ($new_hardware_ram_module_serial_number ne $old_hardware_ram_module_serial_number)) { # This shouldn't change, but maybe the RAM was replaced or upgraded? It could # be that a vanished module has returned? if (($old_hardware_ram_module_manufacturer eq "VANISHED") && ($new_hardware_ram_module_manufacturer ne "VANISHED")) { # A vanished module has returned. $an->Alert->register_alert({ alert_level => "warning", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0006", alert_message_key => "scan_hardware_note_0008", alert_message_variables => { locator => $hardware_ram_module_locator, old_size => $an->Readable->bytes_to_hr({'bytes' => $old_hardware_ram_module_size})." (".$an->Readable->comma($old_hardware_ram_module_size)." #!string!suffix_0009!#)", old_manufacturer => $old_hardware_ram_module_manufacturer, old_model => $old_hardware_ram_module_model, old_serial_number => $old_hardware_ram_module_serial_number, }, }); } else { # Something else changed. $an->Alert->register_alert({ alert_level => "warning", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0004", alert_message_key => "scan_hardware_note_0006", alert_message_variables => { locator => $hardware_ram_module_locator, new_size => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_ram_module_size})." (".$an->Readable->comma($new_hardware_ram_module_size)." #!string!suffix_0009!#)", new_manufacturer => $new_hardware_ram_module_manufacturer, new_model => $new_hardware_ram_module_model, new_serial_number => $new_hardware_ram_module_serial_number, old_size => $an->Readable->bytes_to_hr({'bytes' => $old_hardware_ram_module_size})." (".$an->Readable->comma($old_hardware_ram_module_size)." #!string!suffix_0009!#)", old_manufacturer => $old_hardware_ram_module_manufacturer, old_model => $old_hardware_ram_module_model, old_serial_number => $old_hardware_ram_module_serial_number, }, }); } my $query = " UPDATE hardware_ram_modules SET hardware_ram_module_locator = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_locator).", hardware_ram_module_size = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_module_size).", hardware_ram_module_manufacturer = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_module_manufacturer).", hardware_ram_module_model = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_module_model).", hardware_ram_module_serial_number = ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_module_serial_number).", modified_date = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{db_timestamp})." WHERE hardware_ram_module_uuid = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_uuid)." ;"; # Now record the query in the array $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); $an->DB->do_db_write({query => $query, source => $THIS_FILE, line => __LINE__}); } } else { # Send an alert telling the user that we've found a new module. $an->Alert->register_alert({ alert_level => "notice", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0003", alert_message_key => "scan_hardware_note_0005", alert_message_variables => { locator => $hardware_ram_module_locator, size => $an->Readable->bytes_to_hr({'bytes' => $new_hardware_ram_module_size})." (".$an->Readable->comma($new_hardware_ram_module_size)." #!string!suffix_0009!#)", manufacturer => $new_hardware_ram_module_manufacturer, model => $new_hardware_ram_module_model, serial_number => $new_hardware_ram_module_serial_number, }, }); # INSERT my $hardware_ram_module_uuid = $an->Get->uuid(); my $query = " INSERT INTO hardware_ram_modules ( hardware_ram_module_host_uuid, hardware_ram_module_uuid, hardware_ram_module_locator, hardware_ram_module_size, hardware_ram_module_manufacturer, hardware_ram_module_model, hardware_ram_module_serial_number, modified_date ) VALUES ( ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid}).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_uuid).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_locator).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_module_size).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_module_manufacturer).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_module_model).", ".$an->data->{sys}{use_db_fh}->quote($new_hardware_ram_module_serial_number).", ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{db_timestamp})." );"; # Now record the query in the array $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); $an->DB->do_db_write({query => $query, source => $THIS_FILE, line => __LINE__}); } } # Now look for left over modules we found in the database but not on the local system. foreach my $hardware_ram_module_locator (keys %{$an->data->{sql}{hardware_ram_module_uuid}}) { # Module vanished! my $hardware_ram_module_uuid = $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator}; $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "sql::hardware_ram_module_uuid::${hardware_ram_module_locator}", value1 => $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator}, }, file => $THIS_FILE, line => __LINE__}); my $old_hardware_ram_module_size = $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_size}; my $old_hardware_ram_module_manufacturer = $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_manufacturer}; my $old_hardware_ram_module_model = $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_model}; my $old_hardware_ram_module_serial_number = $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_serial_number}; # Delete the entry so we know we've processed this existing module. delete $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator}; delete $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}; $an->Alert->register_alert({ alert_level => "warning", alert_agent_name => $THIS_FILE, alert_sort => $an->data->{sys}{alert_sort}++, alert_title_key => "an_alert_title_0004", alert_message_key => "scan_hardware_note_0007", alert_message_variables => { locator => $hardware_ram_module_locator, old_size => $an->Readable->bytes_to_hr({'bytes' => $old_hardware_ram_module_size})." (".$an->Readable->comma($old_hardware_ram_module_size)." #!string!suffix_0009!#)", old_manufacturer => $old_hardware_ram_module_manufacturer, old_model => $old_hardware_ram_module_model, old_serial_number => $old_hardware_ram_module_serial_number, }, }); my $query = " UPDATE hardware_ram_modules SET hardware_ram_module_manufacturer = 'VANISHED', modified_date = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{db_timestamp})." WHERE hardware_ram_module_uuid = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_uuid)." ;"; # Now record the query in the array $an->Log->entry({log_level => 2, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); $an->DB->do_db_write({query => $query, source => $THIS_FILE, line => __LINE__}); } return(0); } # This reads in the last scan's data. sub read_last_scan { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "read_last_scan" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); # This calls up the entry for this host. There will only be one. my $query = " SELECT hardware_uuid, hardware_cpu_model, hardware_cpu_cores, hardware_cpu_threads, hardware_cpu_bugs, hardware_cpu_flags, hardware_ram_total, hardware_memory_total, hardware_memory_free, hardware_swap_total, hardware_swap_free, hardware_led_id, hardware_led_css, hardware_led_error, floor(extract(epoch from modified_date)) FROM hardware WHERE hardware_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." ;"; # TODO: This query should only ever return one row, but this fact should be explicitely checked for. my $results = $an->DB->do_db_query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "query", value1 => $query, name2 => "count", value2 => $count, }, file => $THIS_FILE, line => __LINE__}); foreach my $row (@{$results}) { # We've got an entry in the 'hardware' table, so now we'll look for data in the node and # services tables. my $hardware_uuid = $row->[0]; my $hardware_cpu_model = $row->[1]; my $hardware_cpu_cores = $row->[2]; my $hardware_cpu_threads = $row->[3]; my $hardware_cpu_bugs = $row->[4]; my $hardware_cpu_flags = $row->[5]; my $hardware_ram_total = $row->[6]; my $hardware_memory_total = $row->[7]; my $hardware_memory_free = $row->[8]; my $hardware_swap_total = $row->[9]; my $hardware_swap_free = $row->[10]; my $hardware_led_id = $row->[11]; my $hardware_led_css = $row->[12]; my $hardware_led_error = $row->[13]; my $hardware_modified_date = $row->[14]; $an->Log->entry({log_level => 3, message_key => "an_variables_0015", message_variables => { name1 => "hardware_uuid", value1 => $hardware_uuid, name2 => "hardware_cpu_model", value2 => $hardware_cpu_model, name3 => "hardware_cpu_cores", value3 => $hardware_cpu_cores, name4 => "hardware_cpu_threads", value4 => $hardware_cpu_threads, name5 => "hardware_cpu_bugs", value5 => $hardware_cpu_bugs, name6 => "hardware_cpu_flags", value6 => $hardware_cpu_flags, name7 => "hardware_ram_total", value7 => $hardware_ram_total, name8 => "hardware_memory_total", value8 => $hardware_memory_total, name9 => "hardware_memory_free", value9 => $hardware_memory_free, name10 => "hardware_swap_total", value10 => $hardware_swap_total, name11 => "hardware_swap_free", value11 => $hardware_swap_free, name12 => "hardware_led_id", value12 => $hardware_led_id, name13 => "hardware_led_css", value13 => $hardware_led_css, name14 => "hardware_led_error", value14 => $hardware_led_error, name15 => "hardware_modified_date", value15 => $hardware_modified_date, }, file => $THIS_FILE, line => __LINE__}); # Record the hardware_uuid in an easy to find place for later when looking for changes. $an->data->{sql}{hardware_uuid} = $hardware_uuid; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "sql::hardware_uuid", value1 => $an->data->{sql}{hardware_uuid}, }, file => $THIS_FILE, line => __LINE__}); # Store the old data now. $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid} = { hardware_cpu_model => $hardware_cpu_model, hardware_cpu_cores => $hardware_cpu_cores, hardware_cpu_threads => $hardware_cpu_threads, hardware_cpu_bugs => $hardware_cpu_bugs, hardware_cpu_flags => $hardware_cpu_flags, hardware_ram_total => $hardware_ram_total, hardware_memory_total => $hardware_memory_total, hardware_memory_free => $hardware_memory_free, hardware_swap_total => $hardware_swap_total, hardware_swap_free => $hardware_swap_free, hardware_led_id => $hardware_led_id, hardware_led_css => $hardware_led_css, hardware_led_error => $hardware_led_error, hardware_modified_date => $hardware_modified_date, }; $an->Log->entry({log_level => 3, message_key => "an_variables_0013", message_variables => { name1 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_cpu_model", value1 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_model}, name2 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_cpu_cores", value2 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_cores}, name3 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_cpu_threads", value3 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_threads}, name4 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_cpu_bugs", value4 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_bugs}, name5 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_cpu_flags", value5 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_cpu_flags}, name6 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_ram_total", value6 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_ram_total}, name7 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_memory_total", value7 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_memory_total}, name8 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_memory_free", value8 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_memory_free}, name9 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_swap_total", value9 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_swap_total}, name10 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_swap_free", value10 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_swap_free}, name11 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_led_id", value11 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_led_id}, name12 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_led_css", value12 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_led_css}, name13 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_led_error", value13 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_led_error}, name14 => "sql::hardware::hardware_uuid::${hardware_uuid}::hardware_modified_date", value14 => $an->data->{sql}{hardware}{hardware_uuid}{$hardware_uuid}{hardware_modified_date}, }, file => $THIS_FILE, line => __LINE__}); } undef $count; undef $results; # Read in the RAM module data. $query = " SELECT hardware_ram_module_uuid, hardware_ram_module_locator, hardware_ram_module_size, hardware_ram_module_manufacturer, hardware_ram_module_model, hardware_ram_module_serial_number FROM hardware_ram_modules WHERE hardware_ram_module_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." ;"; # TODO: This query should only ever return one row, but this fact should be explicitely checked for. $results = $an->DB->do_db_query({query => $query, source => $THIS_FILE, line => __LINE__}); $count = @{$results}; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "query", value1 => $query, name2 => "count", value2 => $count, }, file => $THIS_FILE, line => __LINE__}); foreach my $row (@{$results}) { # We've got an entry in the 'hardware_ram_modules' table, so now we'll look for data in the node and # services tables. my $hardware_ram_module_uuid = $row->[0]; my $hardware_ram_module_locator = $row->[1]; my $hardware_ram_module_size = $row->[2]; my $hardware_ram_module_manufacturer = $row->[3]; my $hardware_ram_module_model = $row->[4]; my $hardware_ram_module_serial_number = $row->[5]; $an->Log->entry({log_level => 3, message_key => "an_variables_0006", message_variables => { name1 => "hardware_ram_module_uuid", value1 => $hardware_ram_module_uuid, name2 => "hardware_ram_module_locator", value2 => $hardware_ram_module_locator, name3 => "hardware_ram_module_size", value3 => $hardware_ram_module_size, name4 => "hardware_ram_module_manufacturer", value4 => $hardware_ram_module_manufacturer, name5 => "hardware_ram_module_model", value5 => $hardware_ram_module_model, name6 => "hardware_ram_module_serial_number", value6 => $hardware_ram_module_serial_number, }, file => $THIS_FILE, line => __LINE__}); # Record the hardware_ram_module_uuid in an easy to find place for later when looking for changes. $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator} = $hardware_ram_module_uuid; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "sql::hardware_ram_module_uuid::${hardware_ram_module_locator}", value1 => $an->data->{sql}{hardware_ram_module_uuid}{$hardware_ram_module_locator}, }, file => $THIS_FILE, line => __LINE__}); # Store the old data now. $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid} = { hardware_ram_module_locator => $hardware_ram_module_locator, hardware_ram_module_size => $hardware_ram_module_size, hardware_ram_module_manufacturer => $hardware_ram_module_manufacturer, hardware_ram_module_model => $hardware_ram_module_model, hardware_ram_module_serial_number => $hardware_ram_module_serial_number, }; $an->Log->entry({log_level => 3, message_key => "an_variables_0005", message_variables => { name1 => "sql::hardware_ram_module::hardware_ram_module_uuid::${hardware_ram_module_uuid}::hardware_ram_module_locator", value1 => $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_locator}, name2 => "sql::hardware_ram_module::hardware_ram_module_uuid::${hardware_ram_module_uuid}::hardware_ram_module_size", value2 => $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_size}, name3 => "sql::hardware_ram_module::hardware_ram_module_uuid::${hardware_ram_module_uuid}::hardware_ram_module_manufacturer", value3 => $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_manufacturer}, name4 => "sql::hardware_ram_module::hardware_ram_module_uuid::${hardware_ram_module_uuid}::hardware_ram_module_model", value4 => $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_model}, name5 => "sql::hardware_ram_module::hardware_ram_module_uuid::${hardware_ram_module_uuid}::hardware_ram_module_serial_number", value5 => $an->data->{sql}{hardware_ram_module}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_serial_number}, }, file => $THIS_FILE, line => __LINE__}); } return(0); } # This reads in all the data we can find on the local system sub collect_data { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "collect_data" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); # Collect CPU info. collect_cpu_data($an); # Collect RAM data. collect_ram_data($an); # If this is a machine with IPMI, see if we can gather more info. collect_led_states($an); return(0); } # If this is a machine with IPMI, see if we can gather more info. sub collect_led_states { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "collect_data" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); # I need to know what kind of machine I am. my $manufacturer = ""; my $id_led = "unknown"; my $css_led = "unknown"; my $error_led = "unknown"; my $shell_call = $an->data->{path}{dmidecode}." --string system-manufacturer"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "shell_call", value1 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "$shell_call 2>&1 |") or $an->Alert->error({title_key => "an_0003", message_key => "error_title_0014", message_variables => { shell_call => $shell_call, error => $! }, code => 2, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; $manufacturer = lc($_); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "manufacturer", value1 => $manufacturer, }, file => $THIS_FILE, line => __LINE__}); } close $file_handle; if ($manufacturer eq "fujitsu") { my $shell_call = $an->data->{path}{'ipmi-oem'}." Fujitsu get-system-status"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "shell_call", value1 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "$shell_call 2>&1 |") or $an->Alert->error({title_key => "an_0003", message_key => "error_title_0014", message_variables => { shell_call => $shell_call, error => $! }, code => 2, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; my $line = $_; $line =~ s/^\s+//; $line =~ s/\s+$//; $line =~ s/\s+:\s+/: /; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "line", value1 => $line, }, file => $THIS_FILE, line => __LINE__}); if ($line =~ /Identify LED: (.*)$/) { $id_led = lc($1); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "id_led", value1 => $id_led, }, file => $THIS_FILE, line => __LINE__}); } if ($line =~ /CSS LED: (.*)$/) { $css_led = lc($1); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "css_led", value1 => $css_led, }, file => $THIS_FILE, line => __LINE__}); } if ($line =~ /Global Error LED: (.*)$/) { $error_led = lc($1); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "error_led", value1 => $error_led, }, file => $THIS_FILE, line => __LINE__}); } } close $file_handle; } elsif ($manufacturer eq "fujitsu") { my $shell_call = $an->data->{path}{'ipmi-oem'}." Fujitsu get-system-status"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "shell_call", value1 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "$shell_call 2>&1 |") or $an->Alert->error({title_key => "an_0003", message_key => "error_title_0014", message_variables => { shell_call => $shell_call, error => $! }, code => 2, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; my $line = $_; $line =~ s/^\s+//; $line =~ s/\s+$//; $line =~ s/\s+:\s+/: /; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "line", value1 => $line, }, file => $THIS_FILE, line => __LINE__}); } close $file_handle; } # Record. $an->data->{summary}{led}{id_led} = $id_led; $an->data->{summary}{led}{css_led} = $css_led; $an->data->{summary}{led}{error_led} = $error_led; $an->Log->entry({log_level => 3, message_key => "an_variables_0003", message_variables => { name1 => "summary::led::id_led", value1 => $an->data->{summary}{led}{id_led}, name2 => "summary::led::css_led", value2 => $an->data->{summary}{led}{css_led}, name3 => "summary::led::error_led", value3 => $an->data->{summary}{led}{error_led}, }, file => $THIS_FILE, line => __LINE__}); return(0); } # This reads in data about the RAM sub collect_ram_data { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "collect_ram_data" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); my $total_size = 0; my $size = ""; my $locator = ""; my $manufacturer = ""; my $part_number = ""; my $serial_number = ""; my $shell_call = $an->data->{path}{dmidecode}." --type memory"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "shell_call", value1 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "$shell_call 2>&1 |") or $an->Alert->error({title_key => "an_0003", message_key => "error_title_0014", message_variables => { shell_call => $shell_call, error => $! }, code => 2, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; my $line = $_; $line =~ s/^\s+//; $line =~ s/\s+$//; $line =~ s/\s+:\s+/: /; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "line", value1 => $line, }, file => $THIS_FILE, line => __LINE__}); if ($line =~ /^Locator: (.*?)$/) { $locator = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "locator", value1 => $locator, }, file => $THIS_FILE, line => __LINE__}); } if ($line =~ /^Size: (.*?)$/) { $size = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "size", value1 => $size, }, file => $THIS_FILE, line => __LINE__}); # If the "size" is "no module installed", we're done here. if ($size !~ /^\d/) { $locator = ""; $size = ""; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "locator", value1 => $locator, name2 => "size", value2 => $size, }, file => $THIS_FILE, line => __LINE__}); next; } # THis reports in 'MB' but it's really 'MiB'. $size = $an->Readable->hr_to_bytes({ base2 => 1, size => $size, }); $total_size += $size; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "size", value1 => $size, name2 => "total_size", value2 => $total_size, }, file => $THIS_FILE, line => __LINE__}); } if ($line =~ /^Manufacturer: (.*)$/) { $manufacturer = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "manufacturer", value1 => $manufacturer, }, file => $THIS_FILE, line => __LINE__}); } if ($line =~ /^Part Number: (.*)$/) { $part_number = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "part_number", value1 => $part_number, }, file => $THIS_FILE, line => __LINE__}); } if ($line =~ /^Serial Number: (.*)$/) { $serial_number = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "serial_number", value1 => $serial_number, }, file => $THIS_FILE, line => __LINE__}); } next if not $locator; if (not $line) { if ($size) { $an->data->{ram}{dmi}{locator}{$locator}{size} = $size; $an->data->{ram}{dmi}{locator}{$locator}{manufacturer} = $manufacturer; $an->data->{ram}{dmi}{locator}{$locator}{part_number} = $part_number; $an->data->{ram}{dmi}{locator}{$locator}{serial_number} = $serial_number; $an->Log->entry({log_level => 3, message_key => "an_variables_0004", message_variables => { name1 => "ram::dmi::locator::${locator}::size", value1 => $an->Readable->comma($an->data->{ram}{dmi}{locator}{$locator}{size})." (".$an->Readable->bytes_to_hr({'bytes' => $an->data->{ram}{dmi}{locator}{$locator}{size}}).")", name2 => "ram::dmi::locator::${locator}::manufacturer", value2 => $an->data->{ram}{dmi}{locator}{$locator}{manufacturer}, name3 => "ram::dmi::locator::${locator}::part_number", value3 => $an->data->{ram}{dmi}{locator}{$locator}{part_number}, name4 => "ram::dmi::locator::${locator}::serial_number", value4 => $an->data->{ram}{dmi}{locator}{$locator}{serial_number}, }, file => $THIS_FILE, line => __LINE__}); } $size = ""; $locator = ""; $manufacturer = ""; $part_number = ""; $serial_number = ""; $an->Log->entry({log_level => 3, message_key => "an_variables_0005", message_variables => { name1 => "size", value1 => $size, name2 => "locator", value2 => $locator, name3 => "manufacturer", value3 => $manufacturer, name4 => "part_number", value4 => $part_number, name5 => "serial_number", value5 => $serial_number, }, file => $THIS_FILE, line => __LINE__}); } } close $file_handle; if (-r '/proc/meminfo') { my $shell_call = "/proc/meminfo"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "shell_call", value1 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "<$shell_call") or $an->Alert->error({title_key => "tools_title_0003", message_key => "error_message_0066", message_variables => { shell_call => $shell_call, error => $! }, code => 3, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; my $line = $_; $line =~ s/^\s+//; $line =~ s/\s+$//; $line =~ s/\s+:\s+/: /; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "line", value1 => $line, }, file => $THIS_FILE, line => __LINE__}); if ($line =~ /^(.*?):\s+(\d+.*?)$/) { my $variable = $1; my $size = $2; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "variable", value1 => $variable, name2 => "size", value2 => $size, }, file => $THIS_FILE, line => __LINE__}); # We care about a few variables only. my $say_variable = ""; if ($variable eq "MemTotal") { $say_variable = "memory_total"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "say_variable", value1 => $say_variable, }, file => $THIS_FILE, line => __LINE__}); } if ($variable eq "MemFree") { $say_variable = "memory_free"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "say_variable", value1 => $say_variable, }, file => $THIS_FILE, line => __LINE__}); } if ($variable eq "SwapTotal") { $say_variable = "swap_total"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "say_variable", value1 => $say_variable, }, file => $THIS_FILE, line => __LINE__}); } if ($variable eq "SwapFree") { $say_variable = "swap_free"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "say_variable", value1 => $say_variable, }, file => $THIS_FILE, line => __LINE__}); } next if not $say_variable; # This reports sizes as 'kB', but it's really base2. $size = $an->Readable->hr_to_bytes({ base2 => 1, size => $size, }); $an->data->{summary}{ram}{proc}{$say_variable} = $size; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "summary::ram::proc::${say_variable}", value1 => $an->Readable->comma($an->data->{summary}{ram}{proc}{$say_variable})." (".$an->Readable->bytes_to_hr({'bytes' => $an->data->{summary}{ram}{proc}{$say_variable}}).")", }, file => $THIS_FILE, line => __LINE__}); } } close $file_handle; } $an->data->{summary}{ram}{size} = $total_size; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "summary::ram::size", value1 => $an->Readable->comma($an->data->{summary}{ram}{size})." (".$an->Readable->bytes_to_hr({'bytes' => $an->data->{summary}{ram}{size}}).")", }, file => $THIS_FILE, line => __LINE__}); return(0); } # This reads in data about the CPU sub collect_cpu_data { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "collect_cpu_data" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); my $total_cores = 0; my $total_threads = 0; my $cores = 0; my $threads = 0; my $in_cpu = ""; my $shell_call = $an->data->{path}{dmidecode}." --type processor"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "shell_call", value1 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "$shell_call 2>&1 |") or $an->Alert->error({title_key => "an_0003", message_key => "error_title_0014", message_variables => { shell_call => $shell_call, error => $! }, code => 2, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; my $line = $_; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "line", value1 => $line, }, file => $THIS_FILE, line => __LINE__}); if ($line =~ /Socket Designation: (.*+)$/) { $in_cpu = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "in_cpu", value1 => $in_cpu, }, file => $THIS_FILE, line => __LINE__}); } elsif (not $line) { # TODO: Process here? $in_cpu = ""; $cores = 0; $threads = 0; $an->Log->entry({log_level => 3, message_key => "an_variables_0003", message_variables => { name1 => "in_cpu", value1 => $in_cpu, name2 => "cores", value2 => $cores, name3 => "threads", value3 => $threads, }, file => $THIS_FILE, line => __LINE__}); } next if $in_cpu eq ""; if ($line =~ /Core Count: (\d+)$/) { $cores = $1; $total_cores += $cores; $an->Log->entry({log_level => 3, message_key => "an_variables_0003", message_variables => { name1 => "cores", value1 => $cores, name2 => "total_cores", value2 => $total_cores, }, file => $THIS_FILE, line => __LINE__}); } if ($line =~ /Thread Count: (\d+)$/) { $threads = $1; $total_threads += $threads; $an->Log->entry({log_level => 3, message_key => "an_variables_0003", message_variables => { name1 => "threads", value1 => $threads, name2 => "total_threads", value2 => $total_threads, }, file => $THIS_FILE, line => __LINE__}); } } close $file_handle; # Read in /proc/cpuinfo. my $model = ""; my $flags = ""; my $bugs = ""; if (-r '/proc/cpuinfo') { my $shell_call = "/proc/cpuinfo"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "shell_call", value1 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "<$shell_call") or $an->Alert->error({title_key => "tools_title_0003", message_key => "error_message_0066", message_variables => { shell_call => $shell_call, error => $! }, code => 3, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; my $line = $_; $line =~ s/^\s+//; $line =~ s/\s+$//; $line =~ s/\s+:\s+/: /; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "line", value1 => $line, }, file => $THIS_FILE, line => __LINE__}); if ($line =~ /^flags: (.*?)$/) { my $these_flags = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "these_flags", value1 => $these_flags, }, file => $THIS_FILE, line => __LINE__}); if (not $flags) { $flags = $these_flags; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "flags", value1 => $flags, }, file => $THIS_FILE, line => __LINE__}); } elsif ($flags ne $these_flags) { ### TODO: Handle this # This should never happen. $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "these_flags", value1 => $these_flags, name2 => "flags", value2 => $flags, }, file => $THIS_FILE, line => __LINE__}); } } if ($line =~ /^bugs: (.*?)$/) { my $these_bugs = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "these_bugs", value1 => $these_bugs, }, file => $THIS_FILE, line => __LINE__}); if (not $bugs) { $bugs = $these_bugs; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "bugs", value1 => $bugs, }, file => $THIS_FILE, line => __LINE__}); } elsif ($bugs ne $these_bugs) { ### TODO: Handle this # This should never happen. $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "these_bugs", value1 => $these_bugs, name2 => "bugs", value2 => $bugs, }, file => $THIS_FILE, line => __LINE__}); } } if ($line =~ /^model name: (.*?)$/) { my $this_model = $1; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "this_model", value1 => $this_model, }, file => $THIS_FILE, line => __LINE__}); if (not $model) { $model = $this_model; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "model", value1 => $model, }, file => $THIS_FILE, line => __LINE__}); } elsif ($model ne $this_model) { ### TODO: Handle this # This should never happen. $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "this_model", value1 => $this_model, name2 => "model", value2 => $model, }, file => $THIS_FILE, line => __LINE__}); } } } close $file_handle; } # Record what we found. $an->data->{summary}{cpu}{model} = $model; $an->data->{summary}{cpu}{cores} = $total_cores; $an->data->{summary}{cpu}{threads} = $total_threads; $an->data->{summary}{cpu}{bugs} = $bugs; $an->data->{summary}{cpu}{flags} = $flags; $an->Log->entry({log_level => 3, message_key => "an_variables_0005", message_variables => { name1 => "summary::cpu::model", value1 => $an->data->{summary}{cpu}{model}, name2 => "summary::cpu::cores", value2 => $an->data->{summary}{cpu}{cores}, name3 => "summary::cpu::threads", value3 => $an->data->{summary}{cpu}{threads}, name4 => "summary::cpu::bugs", value4 => $an->data->{summary}{cpu}{bugs}, name5 => "summary::cpu::flags", value5 => $an->data->{summary}{cpu}{flags}, }, file => $THIS_FILE, line => __LINE__}); return(0); } # This will archive stuff in the 'history' schema, if needed. sub archive_if_needed { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "archive_if_needed" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); # If the 'trigger' is '0', archiving is disabled. if (not $an->data->{scancore}{archive}{trigger}) { return(1); } ### NOTE: If a ScanCore db server was offline when an archive ran, when it returns, it's records will ### sync back, triggering a sooner-than-expected subsequent archive. This shouldn't happen ### often, and the complexity of tracking archive dates is such that we'll not try to account ### for these cases. ### TODO: What we can do later is, when we write the restore stuff, build in a dedupe function. ### Process: # 1. Count the records in history for each table, restricting the results to those from this host # (save for special tables like 'server') and if the number of records is greater than # 'scancore::archive::trigger', start an archive. # 2. Set/update the 'archive_date' state. # 3. Lock the database. # 4. Select 'modified_date' from history.foo, offset by # ('scancore::archive::trigger' - 'scancore::archive::count'). # 5. Make sure the 'scancore::archive::directory' exists, creating it if needed. # 6. Select all records older that the 'modified_date', write them to a file and then DELETE those # records from the database. # Update the archive path, if set by a user. Also verify that there are sane archive values. $an->Log->entry({log_level => 3, message_key => "an_variables_0004", message_variables => { name1 => "path::scancore_archive", value1 => $an->data->{path}{scancore_archive}, name2 => "scancore::archive::directory", value2 => $an->data->{scancore}{archive}{directory}, name3 => "scancore::archive::trigger", value3 => $an->data->{scancore}{archive}{trigger}, name4 => "scancore::archive::count", value4 => $an->data->{scancore}{archive}{count}, }, file => $THIS_FILE, line => __LINE__}); if ($an->data->{scancore}{archive}{directory} =~ /\/.*/) { $an->data->{path}{scancore_archive} = $an->data->{scancore}{archive}{directory}; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "path::scancore_archive", value1 => $an->data->{path}{scancore_archive}, }, file => $THIS_FILE, line => __LINE__}); } if ((not $an->data->{scancore}{archive}{trigger}) or ($an->data->{scancore}{archive}{trigger} =~ /\D/)) { $an->data->{scancore}{archive}{trigger} = 100000; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "scancore::archive::trigger", value1 => $an->data->{scancore}{archive}{trigger}, }, file => $THIS_FILE, line => __LINE__}); } if ((not $an->data->{scancore}{archive}{count}) or ($an->data->{scancore}{archive}{count} =~ /\D/)) { $an->data->{scancore}{archive}{count} = 50000; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "scancore::archive::count", value1 => $an->data->{scancore}{archive}{count}, }, file => $THIS_FILE, line => __LINE__}); } if (not -e $an->data->{path}{scancore_archive}) { my $shell_call = $an->data->{path}{'mkdir'}." -p '".$an->data->{path}{scancore_archive}."'"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "shell_call", value1 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "$shell_call 2>&1 |") or $an->Alert->error({title_key => "an_0003", message_key => "error_title_0014", message_variables => { shell_call => $shell_call, error => $! }, code => 2, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; my $line = $_; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "line", value1 => $line, }, file => $THIS_FILE, line => __LINE__}); } close $file_handle; # Did it work? if (not -e $an->data->{path}{scancore_archive}) { # Nope. :( $an->Alert->warning({message_key => "scancore_warning_0030", message_variables => { directory => $an->data->{path}{scancore_archive} }, quiet => 1, file => $THIS_FILE, line => __LINE__}); return(1); } } $an->data->{archive}{table} = { hardware => { archive_date => "", host_column => "hardware_host_uuid", offset => 0, }, hardware_ram_modules => { archive_date => "", host_column => "hardware_ram_module_host_uuid", offset => 0, }, }; my $archive_needed = 0; foreach my $table (sort {$a cmp $b} keys %{$an->data->{archive}{table}}) { $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "table", value1 => $table, }, file => $THIS_FILE, line => __LINE__}); my $query = " SELECT COUNT(*) FROM history.$table WHERE ".$an->data->{archive}{table}{$table}{host_column}." = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." ;"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "query", value1 => $query, }, file => $THIS_FILE, line => __LINE__}); my $records = $an->DB->do_db_query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $records = 0 if not defined $records; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "records", value1 => $records, }, file => $THIS_FILE, line => __LINE__}); if ($records > $an->data->{scancore}{archive}{trigger}) { $archive_needed = 1; my $records_to_save = ($an->data->{scancore}{archive}{trigger} - $an->data->{scancore}{archive}{count}); my $offset = $records - $records_to_save; $an->data->{archive}{table}{$table}{offset} = $offset; $an->Log->entry({log_level => 3, message_key => "an_variables_0003", message_variables => { name1 => "archive_needed", value1 => $archive_needed, name2 => "records_to_save", value2 => $records_to_save, name3 => "archive::table::${table}::offset", value3 => $an->data->{archive}{table}{$table}{offset}, }, file => $THIS_FILE, line => __LINE__}); } } # If I have something to archive, do so now. if ($archive_needed) { # This will store the files to compress after we release the locks. my $compress = []; # Request a lock. $an->DB->locking({request => 1}); # Now loop through the table(s) that need to be archived. foreach my $table (sort {$a cmp $b} keys %{$an->data->{archive}{table}}) { next if not $an->data->{archive}{table}{$table}{offset}; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "table", value1 => $table, }, file => $THIS_FILE, line => __LINE__}); # Now to do the archive. if ($table eq "hardware") { $an->DB->archive_table({ table => $table, offset => $an->data->{archive}{table}{$table}{offset}, conditionals => { $an->data->{archive}{table}{$table}{host_column} => $an->data->{sys}{host_uuid} }, columns => ["hardware_uuid", "hardware_host_uuid", "hardware_cpu_model", "hardware_cpu_cores", "hardware_cpu_threads", "hardware_cpu_bugs", "hardware_cpu_flags", "hardware_ram_total", "hardware_memory_total", "hardware_memory_free", "hardware_swap_total", "hardware_swap_free", "hardware_led_id", "hardware_led_css", "hardware_led_error"], }); } elsif ($table eq "hardware_ram_modules") { $an->DB->archive_table({ table => $table, offset => $an->data->{archive}{table}{$table}{offset}, conditionals => { $an->data->{archive}{table}{$table}{host_column} => $an->data->{sys}{host_uuid} }, columns => ["hardware_ram_module_uuid", "hardware_ram_module_hardware_uuid", "hardware_ram_module_locator", "hardware_ram_module_size", "hardware_ram_module_manufacturer", "hardware_ram_module_model", "hardware_ram_module_serial_number"], }); } } ### TODO: Make this less of a hackish mc-hackington... # VACUUM FULL, if the database is on this machine. I need to do this from the command line # because the user we connect as isn't allowed to do it. We'll also only vacuum our DB. my $db_name = ""; foreach my $id (sort {$a cmp $b} keys %{$an->data->{scancore}{db}}) { $an->Log->entry({log_level => 3, message_key => "an_variables_0004", message_variables => { name1 => "id", value1 => $id, name2 => "scancore::db::${id}::host", value2 => $an->data->{scancore}{db}{$id}{host}, name3 => "hostname", value3 => $an->hostname, name4 => "short_hostname", value4 => $an->short_hostname, }, file => $THIS_FILE, line => __LINE__}); if (($an->data->{scancore}{db}{$id}{host} eq $an->hostname) or ($an->data->{scancore}{db}{$id}{host} eq $an->short_hostname)) { $db_name = $an->data->{scancore}{db}{$id}{name}; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "db_name", value1 => $db_name, name2 => "scancore::db::${id}::name", value2 => $an->data->{scancore}{db}{$id}{name}, }, file => $THIS_FILE, line => __LINE__}); last; } } if ($db_name) { my $start = time; my $shell_call = $an->data->{path}{su}." - postgres -c \"".$an->data->{path}{psql}." $db_name -c 'VACUUM FULL;'\""; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "start", value1 => $start, name2 => "shell_call", value2 => $shell_call, }, file => $THIS_FILE, line => __LINE__}); open (my $file_handle, "$shell_call 2>&1 |") or $an->Alert->error({title_key => "an_0003", message_key => "error_title_0014", message_variables => { shell_call => $shell_call, error => $! }, code => 2, file => $THIS_FILE, line => __LINE__}); while(<$file_handle>) { chomp; my $line = $_; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "line", value1 => $line, }, file => $THIS_FILE, line => __LINE__}); } close $file_handle; my $finished = time - $start; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "finished", value1 => $finished, }, file => $THIS_FILE, line => __LINE__}); } # Release the lock $an->DB->locking({release => 1}); } return(0); } # This checks to see if this agent's databases tables exist and, if not, load the schema. If the schema gets # loaded, we'll check other databases for older information and load it. sub prep_databases { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "prep_databases" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); $an->Log->entry({log_level => 3, message_key => "scancore_log_0016", message_variables => { agent => $THIS_FILE }, file => $THIS_FILE, line => __LINE__}); foreach my $id (sort {$a cmp $b} keys %{$an->data->{scancore}{db}}) { my $query = "SELECT COUNT(*) FROM pg_catalog.pg_tables WHERE tablename='hardware' AND schemaname='public';"; # The actual query -----------------. .------- Row 0 # Query this DB --. | | .-- Columns 0 my $count = $an->DB->do_db_query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "count", value1 => $count }, file => $THIS_FILE, line => __LINE__}); if ($count < 1) { # Need to load the database schema. $an->Log->entry({log_level => 1, message_key => "scancore_log_0017", file => $THIS_FILE, line => __LINE__}); $an->DB->load_schema({id => $id, file => $an->data->{path}{sql}}); # Send an alert telling the user that we've initialized this database. $an->Alert->register_alert({ alert_level => "notice", alert_agent_name => $THIS_FILE, alert_title_key => "an_alert_title_0003", alert_message_key => "notice_message_0002", alert_message_variables => { name => $an->data->{scancore}{db}{$id}{name}, host => $an->data->{scancore}{db}{$id}{host}, agent => $THIS_FILE, }, }); } else { # Table exists, schema load is not needed. $an->Log->entry({log_level => 3, message_key => "scancore_log_0018", file => $THIS_FILE, line => __LINE__}); } } return(0); } # This looks at each DB's 'updated' table entry to see if any tables are behind. If any are, it will update # the tables based on the time the last entry was made for a given host. sub update_db { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "update_db" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "scancore::db_resync_needed", value1 => $an->data->{scancore}{db_resync_needed}, }, file => $THIS_FILE, line => __LINE__}); if ($an->data->{scancore}{db_resync_needed}) { # Request a lock. $an->DB->locking({request => 1}); # Make a note in the databases that we're starting an update and ask it to wait 10 seconds # before returning to give other instances time to finish their scans. (our scans end quickly # enough). #$an->DB->set_update_db_flag({set => time, 'wait' => 10}); # Update hardware and ram modules update_db_hardware($an); update_db_hardware_ram_modules($an); # Release the lock $an->DB->locking({release => 1}); # Clear the update flag. #$an->DB->set_update_db_flag({set => 0}); } return(0); } # Update the 'hardware_ram_modules' table. sub update_db_hardware_ram_modules { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "update_db_hardware_ram_modules" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); # Now read in all the 'apc_pdu' table records that came from us. foreach my $id (sort {$a cmp $b} keys %{$an->data->{dbh}}) { # These will store the INSERTs for this DB, if needed. $an->data->{db_resync}{$id}{sql} = []; $an->data->{db_resync}{$id}{public}{sql} = []; $an->data->{db_resync}{$id}{history}{sql} = []; # Read in the history schema my $query = " SELECT hardware_ram_module_uuid, hardware_ram_module_locator, hardware_ram_module_size, hardware_ram_module_manufacturer, hardware_ram_module_model, hardware_ram_module_serial_number, modified_date FROM history.hardware_ram_modules WHERE hardware_ram_module_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." ;"; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "id", value1 => $id, name2 => "query", value2 => $query }, file => $THIS_FILE, line => __LINE__}); # Do the query against the source DB and loop through the results. my $results = $an->DB->do_db_query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__}); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "results", value1 => $results }, file => $THIS_FILE, line => __LINE__}); foreach my $row (@{$results}) { my $hardware_ram_module_uuid = $row->[0]; my $hardware_ram_module_locator = $row->[1]; my $hardware_ram_module_size = $row->[2]; my $hardware_ram_module_manufacturer = $row->[3]; my $hardware_ram_module_model = $row->[4]; my $hardware_ram_module_serial_number = $row->[5]; my $modified_date = $row->[6]; $an->Log->entry({log_level => 3, message_key => "an_variables_0007", message_variables => { name1 => "hardware_ram_module_uuid", value1 => $hardware_ram_module_uuid, name2 => "hardware_ram_module_locator", value2 => $hardware_ram_module_locator, name3 => "hardware_ram_module_size", value3 => $hardware_ram_module_size, name4 => "hardware_ram_module_manufacturer", value4 => $hardware_ram_module_manufacturer, name5 => "hardware_ram_module_model", value5 => $hardware_ram_module_model, name6 => "hardware_ram_module_serial_number", value6 => $hardware_ram_module_serial_number, name7 => "modified_date", value7 => $modified_date, }, file => $THIS_FILE, line => __LINE__}); # Record this in the unified and local hashes. $an->data->{db_data}{unified}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid} = { hardware_ram_module_locator => $hardware_ram_module_locator, hardware_ram_module_size => $hardware_ram_module_size, hardware_ram_module_manufacturer => $hardware_ram_module_manufacturer, hardware_ram_module_model => $hardware_ram_module_model, hardware_ram_module_serial_number => $hardware_ram_module_serial_number, }; $an->data->{db_data}{$id}{hardware_ram_modules}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{'exists'} = 1; $an->data->{db_data}{$id}{hardware_ram_modules}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{seen} = 0; $an->data->{db_data}{$id}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid} = { hardware_ram_module_locator => $hardware_ram_module_locator, hardware_ram_module_size => $hardware_ram_module_size, hardware_ram_module_manufacturer => $hardware_ram_module_manufacturer, hardware_ram_module_model => $hardware_ram_module_model, hardware_ram_module_serial_number => $hardware_ram_module_serial_number, }; } } ### NOTE: Sort '$b cmp $a' on the modified date. # Now, loop through each record from the unified table and see if it needs to be added to any DBs. foreach my $modified_date (sort {$b cmp $a} keys %{$an->data->{db_data}{unified}{hardware_ram_modules}{modified_date}}) { $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "modified_date", value1 => $modified_date, }, file => $THIS_FILE, line => __LINE__}); foreach my $hardware_ram_module_uuid (sort {$a cmp $b} keys %{$an->data->{db_data}{unified}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}}) { my $hardware_ram_module_locator = $an->data->{db_data}{unified}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_locator}; my $hardware_ram_module_size = $an->data->{db_data}{unified}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_size}; my $hardware_ram_module_manufacturer = $an->data->{db_data}{unified}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_manufacturer}; my $hardware_ram_module_model = $an->data->{db_data}{unified}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_model}; my $hardware_ram_module_serial_number = $an->data->{db_data}{unified}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{hardware_ram_module_serial_number}; $an->Log->entry({log_level => 3, message_key => "an_variables_0006", message_variables => { name1 => "hardware_ram_module_uuid", value1 => $hardware_ram_module_uuid, name2 => "hardware_ram_module_locator", value2 => $hardware_ram_module_locator, name3 => "hardware_ram_module_size", value3 => $hardware_ram_module_size, name4 => "hardware_ram_module_manufacturer", value4 => $hardware_ram_module_manufacturer, name5 => "hardware_ram_module_model", value5 => $hardware_ram_module_model, name6 => "hardware_ram_module_serial_number", value6 => $hardware_ram_module_serial_number, }, file => $THIS_FILE, line => __LINE__}); foreach my $id (sort {$a cmp $b} keys %{$an->data->{dbh}}) { # For each 'hardware_ram_module_uuid' we see; # - Check if we've *seen* it before # |- If not; See if it *exists* in the public schema yet. # | |- If so, check to see if the entry in the public schema is up to date. # | | \- If not, _UPDATE_ public schema. # | \- If not, do an _INSERT_ into public schema. # \- If we have, see if it exists at the current timestamp. # \- If not, _INSERT_ it into history schema. # $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "db_data::${id}::hardware_ram_modules::hardware_ram_module_uuid::${hardware_ram_module_uuid}::seen", value1 => $an->data->{db_data}{$id}{hardware_ram_modules}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{seen}, }, file => $THIS_FILE, line => __LINE__}); if (not $an->data->{db_data}{$id}{hardware_ram_modules}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{seen}) { # Mark this record as now having been seen. $an->data->{db_data}{$id}{hardware_ram_modules}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{seen} = 1; # Never seen it. Check if it exists. $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "db_data::${id}::hardware_ram_modules::hardware_ram_module_uuid::${hardware_ram_module_uuid}::exists", value1 => $an->data->{db_data}{$id}{hardware_ram_modules}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{'exists'}, }, file => $THIS_FILE, line => __LINE__}); if ($an->data->{db_data}{$id}{hardware_ram_modules}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}{'exists'}) { # It exists, but does it exist at this time stamp? $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "db_data::${id}::hardware_ram_modules::modified_date::${modified_date}::hardware_ram_module_uuid::${hardware_ram_module_uuid}", value1 => $an->data->{db_data}{$id}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}, }, file => $THIS_FILE, line => __LINE__}); if (not $an->data->{db_data}{$id}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}) { # No, so UPDATE it. my $query = " UPDATE public.hardware_ram_modules SET hardware_ram_module_locator = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_locator).", hardware_ram_module_size = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_size).", hardware_ram_module_manufacturer = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_manufacturer).", hardware_ram_module_model = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_model).", hardware_ram_module_serial_number = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_serial_number).", modified_date = ".$an->data->{sys}{use_db_fh}->quote($modified_date)." WHERE hardware_ram_module_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." AND hardware_ram_module_uuid = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_uuid)." ;"; # Now record the query in the array $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "id", value1 => $id, name2 => "query", value2 => $query }, file => $THIS_FILE, line => __LINE__}); push @{$an->data->{db_resync}{$id}{public}{sql}}, $query; } } else { # It doesn't exist, so INSERT it. my $query = " INSERT INTO public.hardware_ram_modules ( hardware_ram_module_host_uuid, hardware_ram_module_uuid, hardware_ram_module_locator, hardware_ram_module_size, hardware_ram_module_manufacturer, hardware_ram_module_model, hardware_ram_module_serial_number, modified_date ) VALUES ( ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid}).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_uuid).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_locator).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_size).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_manufacturer).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_model).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_serial_number).", ".$an->data->{sys}{use_db_fh}->quote($modified_date)." );"; # Now record the query in the array $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "id", value1 => $id, name2 => "query", value2 => $query }, file => $THIS_FILE, line => __LINE__}); ### NOTE: On some occasions, for as-yet unknown reasons, a ### record can end up in the public schema while ### nothing exists in the history schema (which is what ### we read during a resync). To deal with this, we'll ### do an explicit check before confirming the INSERT). my $count_query = "SELECT COUNT(*) FROM public.hardware_ram_modules WHERE hardware_ram_module_uuid = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_uuid).";"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "count_query", value1 => $count_query, }, file => $THIS_FILE, line => __LINE__}); my $count = $an->DB->do_db_query({id => $id, query => $count_query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "count", value1 => $count, }, file => $THIS_FILE, line => __LINE__}); if ($count) { # Already in, redirect to the history schema. $an->Log->entry({log_level => 1, message_key => "scancore_warning_0003", message_variables => { table => "hardware_ram_modules", id => $id, query => $query, }, file => $THIS_FILE, line => __LINE__}); $query =~ s/ public.hardware_ram_modules/ history.hardware_ram_modules/gs; push @{$an->data->{db_resync}{$id}{history}{sql}}, $query; } else { # No problem, record the query in the array push @{$an->data->{db_resync}{$id}{public}{sql}}, $query; } } } else { # We've seen this 'hardware_ram_module_uuid' before, so it is just a question of # whether the entry for the current timestamp exists in the history # schema. if (not $an->data->{db_data}{$id}{hardware_ram_modules}{modified_date}{$modified_date}{hardware_ram_module_uuid}{$hardware_ram_module_uuid}) { # It doesn't, INSERT it. my $query = " INSERT INTO history.hardware_ram_modules ( hardware_ram_module_host_uuid, hardware_ram_module_uuid, hardware_ram_module_locator, hardware_ram_module_size, hardware_ram_module_manufacturer, hardware_ram_module_model, hardware_ram_module_serial_number, modified_date ) VALUES ( ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid}).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_uuid).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_locator).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_size).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_manufacturer).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_model).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_module_serial_number).", ".$an->data->{sys}{use_db_fh}->quote($modified_date)." );"; # Now record the query in the array $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "id", value1 => $id, name2 => "query", value2 => $query }, file => $THIS_FILE, line => __LINE__}); push @{$an->data->{db_resync}{$id}{history}{sql}}, $query; } # Exist in history at timestamp? } # Seen hardware_ram_module_uuid? } # foreach my $id } # foreach my $hardware_ram_module_uuid ... } # foreach $modified_date ... # Free up memory by deleting the DB data from the main hash. delete $an->data->{db_data}; # Do the INSERTs now and then release the memory. foreach my $id (sort {$a cmp $b} keys %{$an->data->{dbh}}) { # Merge the queries with public schema queries being first. @{$an->data->{db_resync}{$id}{sql}} = (@{$an->data->{db_resync}{$id}{public}{sql}}, @{$an->data->{db_resync}{$id}{history}{sql}}); if (@{$an->data->{db_resync}{$id}{sql}} > 0) { $an->DB->do_db_write({id => $id, query => $an->data->{db_resync}{$id}{sql}, source => $THIS_FILE, line => __LINE__}); delete $an->data->{db_resync}{$id}{sql}; } } return(0); } # Update the 'hardware' table. sub update_db_hardware { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "update_db_hardware" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); # Now read in all the 'hardware' table records that came from us. foreach my $id (sort {$a cmp $b} keys %{$an->data->{dbh}}) { # These will store the INSERTs for this DB, if needed. $an->data->{db_resync}{$id}{sql} = []; $an->data->{db_resync}{$id}{public}{sql} = []; $an->data->{db_resync}{$id}{history}{sql} = []; # Read in the history schema my $query = " SELECT hardware_uuid, hardware_cpu_model, hardware_cpu_cores, hardware_cpu_threads, hardware_cpu_bugs, hardware_cpu_flags, hardware_ram_total, hardware_memory_total, hardware_memory_free, hardware_swap_total, hardware_swap_free, hardware_led_id, hardware_led_css, hardware_led_error, modified_date FROM history.hardware WHERE hardware_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." ;"; $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "id", value1 => $id, name2 => "query", value2 => $query }, file => $THIS_FILE, line => __LINE__}); # Do the query against the source DB and loop through the results. my $results = $an->DB->do_db_query({id => $id, query => $query, source => $THIS_FILE, line => __LINE__}); $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "results", value1 => $results }, file => $THIS_FILE, line => __LINE__}); foreach my $row (@{$results}) { my $hardware_uuid = $row->[0]; my $hardware_cpu_model = $row->[1]; my $hardware_cpu_cores = $row->[2]; my $hardware_cpu_threads = $row->[3]; my $hardware_cpu_bugs = $row->[4]; my $hardware_cpu_flags = $row->[5]; my $hardware_ram_total = $row->[6]; my $hardware_memory_total = $row->[7]; my $hardware_memory_free = $row->[8]; my $hardware_swap_total = $row->[9]; my $hardware_swap_free = $row->[10]; my $hardware_led_id = $row->[11]; my $hardware_led_css = $row->[12]; my $hardware_led_error = $row->[13]; my $modified_date = $row->[14]; $an->Log->entry({log_level => 3, message_key => "an_variables_0015", message_variables => { name1 => "hardware_uuid", value1 => $hardware_uuid, name2 => "hardware_cpu_model", value2 => $hardware_cpu_model, name3 => "hardware_cpu_cores", value3 => $hardware_cpu_cores, name4 => "hardware_cpu_threads", value4 => $hardware_cpu_threads, name5 => "hardware_cpu_bugs", value5 => $hardware_cpu_bugs, name6 => "hardware_cpu_flags", value6 => $hardware_cpu_flags, name7 => "hardware_ram_total", value7 => $hardware_ram_total, name8 => "hardware_memory_total", value8 => $hardware_memory_total, name9 => "hardware_memory_free", value9 => $hardware_memory_free, name10 => "hardware_swap_total", value10 => $hardware_swap_total, name11 => "hardware_swap_free", value11 => $hardware_swap_free, name12 => "hardware_led_id", value12 => $hardware_led_id, name13 => "hardware_led_css", value13 => $hardware_led_css, name14 => "hardware_led_error", value14 => $hardware_led_error, name15 => "modified_date", value15 => $modified_date }, file => $THIS_FILE, line => __LINE__}); # Record this in the unified and local hashes. $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid} = { hardware_cpu_model => $hardware_cpu_model, hardware_cpu_cores => $hardware_cpu_cores, hardware_cpu_threads => $hardware_cpu_threads, hardware_cpu_bugs => $hardware_cpu_bugs, hardware_cpu_flags => $hardware_cpu_flags, hardware_ram_total => $hardware_ram_total, hardware_memory_total => $hardware_memory_total, hardware_memory_free => $hardware_memory_free, hardware_swap_total => $hardware_swap_total, hardware_swap_free => $hardware_swap_free, hardware_led_id => $hardware_led_id, hardware_led_css => $hardware_led_css, hardware_led_error => $hardware_led_error, }; $an->data->{db_data}{$id}{hardware}{hardware_uuid}{$hardware_uuid}{'exists'} = 1; $an->data->{db_data}{$id}{hardware}{hardware_uuid}{$hardware_uuid}{seen} = 0; $an->data->{db_data}{$id}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid} = { hardware_cpu_model => $hardware_cpu_model, hardware_cpu_cores => $hardware_cpu_cores, hardware_cpu_threads => $hardware_cpu_threads, hardware_cpu_bugs => $hardware_cpu_bugs, hardware_cpu_flags => $hardware_cpu_flags, hardware_ram_total => $hardware_ram_total, hardware_memory_total => $hardware_memory_total, hardware_memory_free => $hardware_memory_free, hardware_swap_total => $hardware_swap_total, hardware_swap_free => $hardware_swap_free, hardware_led_id => $hardware_led_id, hardware_led_css => $hardware_led_css, hardware_led_error => $hardware_led_error, }; } } ### NOTE: Sort '$b cmp $a' on the modified date. # Now, loop through each record from the unified table and see if it needs to be added to any DBs. foreach my $modified_date (sort {$b cmp $a} keys %{$an->data->{db_data}{unified}{hardware}{modified_date}}) { $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "modified_date", value1 => $modified_date, }, file => $THIS_FILE, line => __LINE__}); foreach my $hardware_uuid (sort {$a cmp $b} keys %{$an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}}) { my $hardware_cpu_model = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_cpu_model}; my $hardware_cpu_cores = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_cpu_cores}; my $hardware_cpu_threads = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_cpu_threads}; my $hardware_cpu_bugs = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_cpu_bugs}; my $hardware_cpu_flags = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_cpu_flags}; my $hardware_ram_total = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_ram_total}; my $hardware_memory_total = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_memory_total}; my $hardware_memory_free = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_memory_free}; my $hardware_swap_total = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_swap_total}; my $hardware_swap_free = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_swap_free}; my $hardware_led_id = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_led_id}; my $hardware_led_css = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_led_css}; my $hardware_led_error = $an->data->{db_data}{unified}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}{hardware_led_error}; $an->Log->entry({log_level => 3, message_key => "an_variables_0014", message_variables => { name1 => "hardware_uuid", value1 => $hardware_uuid, name2 => "hardware_cpu_model", value2 => $hardware_cpu_model, name3 => "hardware_cpu_cores", value3 => $hardware_cpu_cores, name4 => "hardware_cpu_threads", value4 => $hardware_cpu_threads, name5 => "hardware_cpu_bugs", value5 => $hardware_cpu_bugs, name6 => "hardware_cpu_flags", value6 => $hardware_cpu_flags, name7 => "hardware_ram_total", value7 => $hardware_ram_total, name8 => "hardware_memory_total", value8 => $hardware_memory_total, name9 => "hardware_memory_free", value9 => $hardware_memory_free, name10 => "hardware_swap_total", value10 => $hardware_swap_total, name11 => "hardware_swap_free", value11 => $hardware_swap_free, name12 => "hardware_led_id", value12 => $hardware_led_id, name13 => "hardware_led_css", value13 => $hardware_led_css, name14 => "hardware_led_error", value14 => $hardware_led_error, }, file => $THIS_FILE, line => __LINE__}); foreach my $id (sort {$a cmp $b} keys %{$an->data->{dbh}}) { # For each 'hardware_uuid' we see; # - Check if we've *seen* it before # |- If not; See if it *exists* in the public schema yet. # | |- If so, check to see if the entry in the public schema is up to date. # | | \- If not, _UPDATE_ public schema. # | \- If not, do an _INSERT_ into public schema. # \- If we have, see if it exists at the current timestamp. # \- If not, _INSERT_ it into history schema. # $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "db_data::${id}::hardware::hardware_uuid::${hardware_uuid}::seen", value1 => $an->data->{db_data}{$id}{hardware}{hardware_uuid}{$hardware_uuid}{seen}, }, file => $THIS_FILE, line => __LINE__}); if (not $an->data->{db_data}{$id}{hardware}{hardware_uuid}{$hardware_uuid}{seen}) { # Mark this record as now having been seen. $an->data->{db_data}{$id}{hardware}{hardware_uuid}{$hardware_uuid}{seen} = 1; # Never seen it. Check if it exists. $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "db_data::${id}::hardware::hardware_uuid::${hardware_uuid}::exists", value1 => $an->data->{db_data}{$id}{hardware}{hardware_uuid}{$hardware_uuid}{'exists'}, }, file => $THIS_FILE, line => __LINE__}); if ($an->data->{db_data}{$id}{hardware}{hardware_uuid}{$hardware_uuid}{'exists'}) { # It exists, but does it exist at this time stamp? $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "db_data::${id}::hardware::modified_date::${modified_date}::hardware_uuid::${hardware_uuid}", value1 => $an->data->{db_data}{$id}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}, }, file => $THIS_FILE, line => __LINE__}); if (not $an->data->{db_data}{$id}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}) { # No, so UPDATE it. my $query = " UPDATE public.hardware SET hardware_cpu_model = ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_model).", hardware_cpu_cores = ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_cores).", hardware_cpu_threads = ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_threads).", hardware_cpu_bugs = ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_bugs).", hardware_cpu_flags = ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_flags).", hardware_ram_total = ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_total).", hardware_memory_total = ".$an->data->{sys}{use_db_fh}->quote($hardware_memory_total).", hardware_memory_free = ".$an->data->{sys}{use_db_fh}->quote($hardware_memory_free).", hardware_swap_total = ".$an->data->{sys}{use_db_fh}->quote($hardware_swap_total).", hardware_swap_free = ".$an->data->{sys}{use_db_fh}->quote($hardware_swap_free).", hardware_led_id = ".$an->data->{sys}{use_db_fh}->quote($hardware_led_id).", hardware_led_css = ".$an->data->{sys}{use_db_fh}->quote($hardware_led_css).", hardware_led_error = ".$an->data->{sys}{use_db_fh}->quote($hardware_led_error).", modified_date = ".$an->data->{sys}{use_db_fh}->quote($modified_date)." WHERE hardware_host_uuid = ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid})." AND hardware_uuid = ".$an->data->{sys}{use_db_fh}->quote($hardware_uuid)." ;"; # Now record the query in the array $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "id", value1 => $id, name2 => "query", value2 => $query }, file => $THIS_FILE, line => __LINE__}); push @{$an->data->{db_resync}{$id}{public}{sql}}, $query; } } else { # It doesn't exist, so INSERT it. my $query = " INSERT INTO public.hardware ( hardware_host_uuid, hardware_uuid, hardware_cpu_model, hardware_cpu_cores, hardware_cpu_threads, hardware_cpu_bugs, hardware_cpu_flags, hardware_ram_total, hardware_memory_total, hardware_memory_free, hardware_swap_total, hardware_swap_free, hardware_led_id, hardware_led_css, hardware_led_error, modified_date ) VALUES ( ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid}).", ".$an->data->{sys}{use_db_fh}->quote($hardware_uuid).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_model).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_cores).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_threads).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_bugs).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_flags).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_total).", ".$an->data->{sys}{use_db_fh}->quote($hardware_memory_total).", ".$an->data->{sys}{use_db_fh}->quote($hardware_memory_free).", ".$an->data->{sys}{use_db_fh}->quote($hardware_swap_total).", ".$an->data->{sys}{use_db_fh}->quote($hardware_swap_free).", ".$an->data->{sys}{use_db_fh}->quote($hardware_led_id).", ".$an->data->{sys}{use_db_fh}->quote($hardware_led_css).", ".$an->data->{sys}{use_db_fh}->quote($hardware_led_error).", ".$an->data->{sys}{use_db_fh}->quote($modified_date)." );"; # Now record the query in the array $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "id", value1 => $id, name2 => "query", value2 => $query }, file => $THIS_FILE, line => __LINE__}); ### NOTE: On some occasions, for as-yet unknown reasons, a ### record can end up in the public schema while ### nothing exists in the history schema (which is what ### we read during a resync). To deal with this, we'll ### do an explicit check before confirming the INSERT). my $count_query = "SELECT COUNT(*) FROM public.hardware WHERE hardware_uuid = ".$an->data->{sys}{use_db_fh}->quote($hardware_uuid).";"; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "count_query", value1 => $count_query, }, file => $THIS_FILE, line => __LINE__}); my $count = $an->DB->do_db_query({id => $id, query => $count_query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $an->Log->entry({log_level => 3, message_key => "an_variables_0001", message_variables => { name1 => "count", value1 => $count, }, file => $THIS_FILE, line => __LINE__}); if ($count) { # Already in, redirect to the history schema. $an->Log->entry({log_level => 1, message_key => "scancore_warning_0003", message_variables => { table => "hardware", id => $id, query => $query, }, file => $THIS_FILE, line => __LINE__}); $query =~ s/ public.hardware/ history.hardware/gs; push @{$an->data->{db_resync}{$id}{history}{sql}}, $query; } else { # No problem, record the query in the array push @{$an->data->{db_resync}{$id}{public}{sql}}, $query; } } } else { # We've seen this 'hardware_uuid' before, so it is just a question of # whether the entry for the current timestamp exists in the history # schema. if (not $an->data->{db_data}{$id}{hardware}{modified_date}{$modified_date}{hardware_uuid}{$hardware_uuid}) { # It doesn't, INSERT it. my $query = " INSERT INTO history.hardware ( hardware_host_uuid, hardware_uuid, hardware_cpu_model, hardware_cpu_cores, hardware_cpu_threads, hardware_cpu_bugs, hardware_cpu_flags, hardware_ram_total, hardware_memory_total, hardware_memory_free, hardware_swap_total, hardware_swap_free, hardware_led_id, hardware_led_css, hardware_led_error, modified_date ) VALUES ( ".$an->data->{sys}{use_db_fh}->quote($an->data->{sys}{host_uuid}).", ".$an->data->{sys}{use_db_fh}->quote($hardware_uuid).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_model).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_cores).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_threads).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_bugs).", ".$an->data->{sys}{use_db_fh}->quote($hardware_cpu_flags).", ".$an->data->{sys}{use_db_fh}->quote($hardware_ram_total).", ".$an->data->{sys}{use_db_fh}->quote($hardware_memory_total).", ".$an->data->{sys}{use_db_fh}->quote($hardware_memory_free).", ".$an->data->{sys}{use_db_fh}->quote($hardware_swap_total).", ".$an->data->{sys}{use_db_fh}->quote($hardware_swap_free).", ".$an->data->{sys}{use_db_fh}->quote($hardware_led_id).", ".$an->data->{sys}{use_db_fh}->quote($hardware_led_css).", ".$an->data->{sys}{use_db_fh}->quote($hardware_led_error).", ".$an->data->{sys}{use_db_fh}->quote($modified_date)." );"; # Now record the query in the array $an->Log->entry({log_level => 3, message_key => "an_variables_0002", message_variables => { name1 => "id", value1 => $id, name2 => "query", value2 => $query }, file => $THIS_FILE, line => __LINE__}); push @{$an->data->{db_resync}{$id}{history}{sql}}, $query; } # Exist in history at timestamp? } # Seen hardware_uuid? } # foreach my $id } # foreach my $hardware_uuid ... } # foreach $modified_date ... # Free up memory by deleting the DB data from the main hash. delete $an->data->{db_data}; # Do the INSERTs now and then release the memory. foreach my $id (sort {$a cmp $b} keys %{$an->data->{dbh}}) { # Merge the queries with public schema queries being first. @{$an->data->{db_resync}{$id}{sql}} = (@{$an->data->{db_resync}{$id}{public}{sql}}, @{$an->data->{db_resync}{$id}{history}{sql}}); if (@{$an->data->{db_resync}{$id}{sql}} > 0) { $an->DB->do_db_write({id => $id, query => $an->data->{db_resync}{$id}{sql}, source => $THIS_FILE, line => __LINE__}); delete $an->data->{db_resync}{$id}{sql}; } } return(0); } # Print the usage information. sub print_usage { my ($an) = @_; $an->Log->entry({log_level => 3, title_key => "tools_log_0001", title_variables => { function => "print_usage" }, message_key => "tools_log_0002", file => $THIS_FILE, line => __LINE__}); print $an->String->get({key => "scan_hardware_message_0002"})."\n"; return(0); }