#!/usr/bin/perl # # This scans the network, bridges, bonds and interfaces. # # Examples; # # Exit codes; # 0 = Normal exit. # 1 = Startup failure (not running as root, no DB, bad file read, etc) # # TODO: # - # use strict; use warnings; use Anvil::Tools; use Data::Dumper; # Disable buffering $| = 1; # Prevent a discrepency between UID/GID and EUID/EGID from throwing an error. $< = $>; $( = $); my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; if (($running_directory =~ /^\./) && ($ENV{PWD})) { $running_directory =~ s/^\./$ENV{PWD}/; } my $anvil = Anvil::Tools->new(); # Make sure we're running as 'root' # $< == real UID, $> == effective UID if (($< != 0) && ($> != 0)) { # Not root print $anvil->Words->string({key => "error_0005"})."\n"; $anvil->nice_exit({exit_code => 1}); } # These are the threasholds for when to alert when swap is running out. $anvil->data->{switches}{force} = 0; #$anvil->Storage->read_config(); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0115", variables => { program => $THIS_FILE }}); # Read switches $anvil->Get->switches; # Handle start-up tasks my $problem = $anvil->ScanCore->agent_startup({agent => $THIS_FILE}); if ($problem) { $anvil->nice_exit({exit_code => 1}); } if ($anvil->data->{switches}{purge}) { # This can be called when doing bulk-database purges. my $schema_file = $anvil->data->{path}{directories}{scan_agents}."/".$THIS_FILE."/".$THIS_FILE.".sql"; $anvil->Database->purge_data({ debug => 2, tables => $anvil->Database->get_tables_from_schema({schema_file => $schema_file}), }); $anvil->nice_exit({exit_code => 0}); } # Read the data. collect_data($anvil); # Load stored data. read_last_scan($anvil); # Look for changes. find_changes($anvil); # Finally, process health weights. process_health($anvil); # This clears the TX and RX variable data for interfaces older than 'scancore::database::age_out'. clear_old_variables($anvil); # This removes network interfaces that have been marked as DELETED for a while now. clear_old_interfaces($anvil); # Shut down. $anvil->ScanCore->agent_shutdown({agent => $THIS_FILE}); ############################################################################################################# # Functions # ############################################################################################################# # This removes network interfaces that have been marked as DELETED for a while now. sub clear_old_interfaces { my ($anvil) = @_; # Read in all interfaces and for each, delete historical records over the age-out time. my $age = $anvil->data->{scancore}{database}{age_out}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }}); if ($age =~ /\D/) { # Age is not valid, set it to defaults. $age = 24; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }}); } my $query = "SELECT now() - '".$age."h'::interval;"; my $old_timestamp = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query, old_timestamp => $old_timestamp, }}); # It is possible that a record exists on one DB, but not the other. Unsure how this happens, but this # cleans it up. foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid})." (".$uuid.")", }}); my $query = " SELECT ip_address_uuid, ip_address_address FROM ip_addresses WHERE ip_address_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." AND ip_address_note = 'DELETED' AND modified_date < '".$old_timestamp."' ORDER BY ip_address_address ASC ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $ip_address_uuid = $row->[0]; my $ip_address_address = $row->[1]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:ip_address_uuid' => $ip_address_uuid, 's2:ip_address_address' => $ip_address_address, }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0005", variables => { age => $age, ip => $ip_address_address, }}); my $queries = []; push @{$queries}, "DELETE FROM history.ip_addresses WHERE ip_address_uuid = '".$ip_address_uuid."';"; push @{$queries}, "DELETE FROM ip_addresses WHERE ip_address_uuid = '".$ip_address_uuid."';"; foreach my $query (@{$queries}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } # Write to both DBs. $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); } # Remove interfaces $query = " SELECT network_interface_uuid, network_interface_mac_address, network_interface_name FROM network_interfaces WHERE network_interface_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." AND network_interface_operational = 'DELETED' AND modified_date < '".$old_timestamp."' ORDER BY network_interface_name ASC ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $network_interface_uuid = $row->[0]; my $network_interface_mac_address = $row->[1]; my $network_interface_name = $row->[2]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:network_interface_uuid' => $network_interface_uuid, 's2:network_interface_mac_address' => $network_interface_mac_address, 's3:network_interface_name' => $network_interface_name, }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0002", variables => { age => $age, mac => $network_interface_mac_address, name => $network_interface_name, }}); my $queries = []; push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_uuid = '".$network_interface_uuid."';"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_uuid = '".$network_interface_uuid."';"; foreach my $query (@{$queries}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } # Write to both DBs. $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); } # Delete old bonds $query = " SELECT bond_uuid, bond_name FROM bonds WHERE bond_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." AND bond_mode = 'DELETED' AND modified_date < '".$old_timestamp."' ORDER BY bond_name ASC ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $bond_uuid = $row->[0]; my $bond_name = $row->[1]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:bond_uuid' => $bond_uuid, 's2:bond_name' => $bond_name, }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0003", variables => { age => $age, name => $bond_name, }}); my $queries = []; push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = '".$bond_uuid."';"; push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = '".$bond_uuid."';"; foreach my $query (@{$queries}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } # Write to both DBs. $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); } # Delete old bridges $query = " SELECT bridge_uuid, bridge_name FROM bridges WHERE bridge_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." AND bridge_id = 'DELETED' AND modified_date < '".$old_timestamp."' ORDER BY bridge_name ASC ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $bridge_uuid = $row->[0]; my $bridge_name = $row->[1]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:bridge_uuid' => $bridge_uuid, 's2:bridge_name' => $bridge_name, }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0004", variables => { age => $age, name => $bridge_name, }}); my $queries = []; push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = '".$bridge_uuid."';"; push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = '".$bridge_uuid."';"; foreach my $query (@{$queries}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } # Write to both DBs. $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); } } return(0); } # This clears the TX and RX variable data for interfaces older than 'scancore::database::age_out'. sub clear_old_variables { my ($anvil) = @_; # Only Strikers run this. my $host_type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); if ($host_type ne "striker") { return(0); } # Read in all interfaces and for each, delete historical records over the age-out time. my $age = $anvil->data->{scancore}{database}{age_out}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { age => $age }}); if ($age =~ /\D/) { # Age is not valid, set it to defaults. $age = 24; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { age => $age }}); } # Get the timestamp to delete thermal and power records older than $age hours. my $query = "SELECT now() - '".$age."h'::interval;"; my $old_timestamp = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query, old_timestamp => $old_timestamp, }}); # Read in all interface RX and TX variables. foreach my $uuid (keys %{$anvil->data->{cache}{database_handle}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uuid => $uuid, db_host => $anvil->Get->host_name_from_uuid({host_uuid => $uuid}), }}); my $queries = []; $query = " SELECT variable_uuid, variable_name FROM variables WHERE variable_name LIKE '%::tx_bytes' OR variable_name LIKE '%::rx_bytes' ;"; my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $variable_uuid = $row->[0]; my $variable_name = $row->[1]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 's1:variable_name' => $variable_name, 's2:variable_uuid' => $variable_uuid, }}); # Find out of there are any records to remove at all. my $query = "SELECT history_id FROM history.variables WHERE variable_uuid = ".$anvil->Database->quote($variable_uuid)." AND modified_date <= '".$old_timestamp."';"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { results => $results, count => $count, }}); if ($count) { # Find how many records will be left. If it's 0, we'll use an OFFSET 1. my $query = "SELECT history_id FROM history.variables WHERE variable_uuid = ".$anvil->Database->quote($variable_uuid)." AND modified_date > '".$old_timestamp."';"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { results => $results, count => $count, }}); if ($count) { # At least one record will be left, we can do a simple delete. my $query = "DELETE FROM history.variables WHERE variable_uuid = ".$anvil->Database->quote($variable_uuid)." AND modified_date <= '".$old_timestamp."';"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); push @{$queries}, $query; } else { # This would delete everything, reserve at least one record. foreach my $row (@{$results}) { my $history_id = $row->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { history_id => $history_id }}); my $query = "DELETE FROM history.variables WHERE variable_uuid = ".$anvil->Database->quote($variable_uuid)." AND history_id = '".$history_id."';"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); push @{$queries}, $query; } } } } my $commits = @{$queries}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { commits => $commits }}); if ($commits) { # Commit the DELETEs. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_log_0001", variables => { age => $age, records => $commits, host => $anvil->Get->host_name_from_uuid({host_uuid => $uuid}), }}); $anvil->Database->write({debug => 3, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__}); undef $queries; } } return(0); } # This reads in all of the network data sub collect_data { my ($anvil) = @_; $anvil->Network->get_ips({debug => 2}); # Read the data from the ifcfg files, if available. We'll use this to check for bond interfaces that # didn't start. $anvil->Network->check_network(); my $uptime = $anvil->Get->uptime(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uptime => $uptime }}); if ($uptime < 600) { $anvil->Network->read_nmcli({debug => 2}) } # The 'local_host' is needed to pull data recorded by Network->get_ips(); my $local_host = $anvil->Get->short_host_name(); my $directory = "/sys/class/net"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_host => $local_host, directory => $directory, }}); # Make sure there are no virsh bridges, removing any found. my $host_type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); if (($host_type eq "node") or ($host_type eq "dr")) { my $default_network = "/etc/libvirt/qemu/networks/default.xml"; if (-e $default_network) { my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy default"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine default"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); # Register an alert my $variables = { bridge => "default", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0001", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0001", variables => $variables, set_by => $THIS_FILE, }); } =cut my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-list --all --name"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); # This often hangs. my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); if (not $return_code) { # Virsh is up. foreach my $line (split/\n/, $output) { $line =~ s/^\s+//; $line =~ s/\s+$//; next if not $line; next if $line =~ /^error/; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "striker_0287", variables => { bridge => $line }}); my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy ".$line; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine ".$line; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); # Register an alert my $variables = { bridge => $line, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0001", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0001", variables => $variables, set_by => $THIS_FILE, }); } } =cut } # Walk through the sysfs files. local(*DIRECTORY); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }}); opendir(DIRECTORY, $directory); while(my $file = readdir(DIRECTORY)) { next if $file eq "."; next if $file eq ".."; next if $file eq "lo"; my $full_path = $directory."/".$file; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); if (-d $full_path) { # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. my $interface = $file; my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link my $media = "unknown"; my $type = "interface"; my $driver = ""; my $tx_bytes = 0; # How many bytes transmitted my $rx_bytes = 0; # How many bytes received # Clean up some newlines. $link_state =~ s/\n$//; $mtu =~ s/\n$//; $duplex =~ s/\n$//; $operational =~ s/\n$//; $speed =~ s/\n$//; $modalias =~ s/\n$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface, link_state => $link_state, mtu => $mtu, duplex => $duplex, operational => $operational, speed => $speed, modalias => $modalias, }}); ### NOTE: This only parses virtio so far. # Pick out our driver. if ($modalias =~ /^virtio:/) { $driver = "virtio"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver => $driver }}); } # The MAC address can faked by a number of ways, so we make an explicit call to 'ethtool' to get the permanent mac address. my $mac_address = ""; my $shell_call = $anvil->data->{path}{exe}{ethtool}." -P ".$interface; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); if ($output =~ /(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/) { $mac_address = lc($1); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); } else { # Get it by reading the address file. if (-e $full_path."/bonding_slave/perm_hwaddr") { $mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); } elsif (-e $full_path."/address") { $mac_address = $anvil->Storage->read_file({file => $full_path."/address"}); $mac_address =~ s/\n//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); } } # These are variables that will be needed if this is a bond interface. my $ip_address = ""; my $subnet_mask = ""; my $bond_mode = ""; my $primary_interface = ""; my $primary_reselect = ""; my $active_interface = ""; my $mii_polling_interval = ""; my $up_delay = ""; my $down_delay = ""; my $bond_master = ""; # These are variables that will be needed if this is a bridge interface my $bridge_id = ""; my $bridge_stp_enabled = ""; # Explicitly check for the existing of the hash so that we don't auto-vivivate the interface. if (exists $anvil->data->{network}{$local_host}{interface}{$interface}) { $ip_address = defined $anvil->data->{network}{$local_host}{interface}{$interface}{ip} ? $anvil->data->{network}{$local_host}{interface}{$interface}{ip} : ""; $subnet_mask = defined $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} ? $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} : ""; $type = defined $anvil->data->{network}{$local_host}{interface}{$interface}{type} ? $anvil->data->{network}{$local_host}{interface}{$interface}{type} : "interface"; $tx_bytes = defined $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes} ? $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes} : 0; $rx_bytes = defined $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes} ? $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes} : 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address => $ip_address, subnet_mask => $subnet_mask, type => $type, rx_bytes => $rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", tx_bytes => $tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", }}); } # If this interface is already a bond slave, the real mac address will be in a # sub-directory. my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr"; if (-e $mac_bond_file) { # It's a slave. $mac_address = $anvil->Storage->read_file({file => $mac_bond_file}); $mac_address =~ s/\n$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); } # If this is a virtual interface, set some fake values that don't actually exist on # the system for the sake of a cleaner display. if (($mac_address =~ /^52:54:00/) or ($driver eq "virtio")) { ### Set some fake values. # Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary. if ((not $speed) or ($speed eq "-1")) { $speed = 10000; } if ((not $duplex) or ($duplex eq "unknown")) { $duplex = "full"; } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed, duplex => $duplex, }}); } # If the state is 'down', set the speed to '0'. if (not $link_state) { $speed = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); } # Is this a bond interface? if (-e "/proc/net/bonding/".$interface) { # Yup, we'll neet to dig into the bond proc files to get the proper slaved # interface MAC addresses. $type = "bond"; # Read the bond mode. $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); $primary_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"}); $primary_reselect = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"}); $active_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"}); $mii_polling_interval = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"}); $up_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"}); $down_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"}); $bond_mode =~ s/\s.*//; $bond_mode =~ s/\n$//; $primary_interface =~ s/\n$//; $primary_reselect =~ s/\s.*//; $primary_reselect =~ s/\n$//; $active_interface =~ s/\n$//; $mii_polling_interval =~ s/\n$//; $up_delay =~ s/\n$//; $down_delay =~ s/\n$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { active_interface => $active_interface, bond_mode => $bond_mode, mii_polling_interval => $mii_polling_interval, primary_reselect => $primary_reselect, primary_interface => $primary_interface, type => $type, }}); } elsif ((-e $full_path."/master") && ($interface !~ /^vnet/)) { # We're in a bond. my $target = readlink($full_path."/master"); $bond_master = ($target =~ /^.*\/(.*)$/)[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target => $target, bond_master => $bond_master, }}); } elsif (-d $full_path."/bridge") { # It's a bridge $type = "bridge"; $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); $bridge_id =~ s/\n$//; $bridge_stp_enabled =~ s/\n$//; $speed = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_id => $bridge_id, bridge_stp_enabled => $bridge_stp_enabled, type => $type, }}); if ($bridge_stp_enabled eq "0") { $bridge_stp_enabled = "disabled"; } elsif ($bridge_stp_enabled eq "1") { $bridge_stp_enabled = "enabled_kernel"; } elsif ($bridge_stp_enabled eq "2") { $bridge_stp_enabled = "enabled_userland"; } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_stp_enabled => $bridge_stp_enabled }}); } # If this is a 'vnet' device, set 'operational' to up if ($interface =~ /^vnet/) { $operational = "up"; $media = "virtual"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { operational => $operational, media => $media, }}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { active_interface => $active_interface, bond_master => $bond_master, bond_mode => $bond_mode, bridge_id => $bridge_id, bridge_stp_enabled => $bridge_stp_enabled, down_delay => $down_delay, duplex => $duplex, interface => $interface, mac_address => $mac_address, mii_polling_interval => $mii_polling_interval, mtu => $mtu, operational => $operational, primary_reselect => $primary_reselect, primary_interface => $primary_interface, speed => $speed, subnet_mask => $subnet_mask, type => $type, up_delay => $up_delay, }}); # If the MAC address starts with '52:54:00', we've got a virtio NIC. if ((not defined $speed) or ($speed eq "")) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0001", variables => { file => $full_path."/speed" }}); next; } if ($speed =~ /\D/) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0002", variables => { file => $full_path."/speed", speed => $speed, }}); next; } if ($speed > 100000) { # NOTE: This is probably 0 now... Though someday >100 Gbps will be reasonable # and we'll need to change this. $speed = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); } # Find the media, if possible. (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"}); foreach my $line (split/\n/, $ethtool) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); if ($line =~ /Supported ports: \[ (.*?) \]/i) { $media = lc($1); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); # This can be 'tp mii', which breaks json. if ($media =~ /\t/) { $media =~ s/\t/,/g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); } last; } } # Store new information we found. $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface} = $active_interface; $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode} = $bond_mode; $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master} = $bond_master; $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id} = $bridge_id; $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled} = $bridge_stp_enabled; $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay} = $down_delay; $anvil->data->{network}{$local_host}{interface}{$interface}{duplex} = $duplex; $anvil->data->{network}{$local_host}{interface}{$interface}{ip} = $ip_address; $anvil->data->{network}{$local_host}{interface}{$interface}{link_state} = $link_state; $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address} = $mac_address; $anvil->data->{network}{$local_host}{interface}{$interface}{media} = $media; $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval} = $mii_polling_interval; $anvil->data->{network}{$local_host}{interface}{$interface}{mtu} = $mtu; $anvil->data->{network}{$local_host}{interface}{$interface}{operational} = $operational; $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect} = $primary_reselect; $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface} = $primary_interface; $anvil->data->{network}{$local_host}{interface}{$interface}{speed} = $speed; $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} = $subnet_mask; $anvil->data->{network}{$local_host}{interface}{$interface}{type} = $type; $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay} = $up_delay; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network::${local_host}::interface::${interface}::active_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}, "network::${local_host}::interface::${interface}::bond_mode" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}, "network::${local_host}::interface::${interface}::bond_master" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}, "network::${local_host}::interface::${interface}::bridge_id" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}, "network::${local_host}::interface::${interface}::bridge_stp_enabled" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}, "network::${local_host}::interface::${interface}::down_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}, "network::${local_host}::interface::${interface}::duplex" => $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}, "network::${local_host}::interface::${interface}::ip" => $anvil->data->{network}{$local_host}{interface}{$interface}{ip}, "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, "network::${local_host}::interface::${interface}::mac_address" => $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}, "network::${local_host}::interface::${interface}::media" => $anvil->data->{network}{$local_host}{interface}{$interface}{media}, "network::${local_host}::interface::${interface}::mii_polling_interval" => $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}, "network::${local_host}::interface::${interface}::mtu" => $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}, "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, "network::${local_host}::interface::${interface}::primary_reselect" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}, "network::${local_host}::interface::${interface}::primary_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}, "network::${local_host}::interface::${interface}::speed" => $anvil->data->{network}{$local_host}{interface}{$interface}{speed}, "network::${local_host}::interface::${interface}::subnet_mask" => $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}, "network::${local_host}::interface::${interface}::type" => $anvil->data->{network}{$local_host}{interface}{$interface}{type}, "network::${local_host}::interface::${interface}::up_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}, }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, }}); # If this is a link and there's no database connections, cache the data. if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) { $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational."\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cache::new_file" => $anvil->data->{cache}{new_file}, }}); } } } closedir(DIRECTORY); # Find what interfaces are connected to which bridges $anvil->Network->bridge_info({debug => 2}); foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) { my $ip_address = $anvil->data->{network}{$local_host}{interface}{$interface}{ip}; my $type = $anvil->data->{network}{$local_host}{interface}{$interface}{type}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface, ip_address => $ip_address, type => $type, }}); $anvil->data->{interface}{name_to_type}{$interface} = $type; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface::name_to_type::${interface}" => $anvil->data->{interface}{name_to_type}{$interface}, }}); if ($type eq "bridge") { # Store the bridge $anvil->data->{new}{bridge}{$interface}{id} = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}; $anvil->data->{new}{bridge}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; $anvil->data->{new}{bridge}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; $anvil->data->{new}{bridge}{$interface}{stp_enabled} = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}; $anvil->data->{new}{bridge}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{bridge}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "new::bridge::${interface}::id" => $anvil->data->{new}{bridge}{$interface}{id}, "new::bridge::${interface}::mac_address" => $anvil->data->{new}{bridge}{$interface}{mac_address}, "new::bridge::${interface}::mtu" => $anvil->data->{new}{bridge}{$interface}{mtu}, "new::bridge::${interface}::stp_enabled" => $anvil->data->{new}{bridge}{$interface}{stp_enabled}, "new::bridge::${interface}::tx_bytes" => $anvil->data->{new}{bridge}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bridge}{$interface}{tx_bytes}}).")", "new::bridge::${interface}::rx_bytes" => $anvil->data->{new}{bridge}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bridge}{$interface}{rx_bytes}}).")", }}); } elsif ($type eq "bond") { # Store the bond $anvil->data->{new}{bond}{$interface}{mode} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}; $anvil->data->{new}{bond}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; $anvil->data->{new}{bond}{$interface}{master} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; $anvil->data->{new}{bond}{$interface}{link_state} = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; $anvil->data->{new}{bond}{$interface}{operational} = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; $anvil->data->{new}{bond}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; $anvil->data->{new}{bond}{$interface}{primary_interface} = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}; $anvil->data->{new}{bond}{$interface}{primary_reselect} = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}; $anvil->data->{new}{bond}{$interface}{active_interface} = $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}; $anvil->data->{new}{bond}{$interface}{mii_polling_interval} = $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}; $anvil->data->{new}{bond}{$interface}{up_delay} = $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}; $anvil->data->{new}{bond}{$interface}{down_delay} = $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}; $anvil->data->{new}{bond}{$interface}{bridge_uuid} = ""; # We'll dig his out later as the bridge might not be in the database yet. $anvil->data->{new}{bond}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{bond}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "new::bond::${interface}::mode" => $anvil->data->{new}{bond}{$interface}{mode}, "new::bond::${interface}::mtu" => $anvil->data->{new}{bond}{$interface}{mtu}, "new::bond::${interface}::master" => $anvil->data->{new}{bond}{$interface}{master}, "new::bond::${interface}::link_state" => $anvil->data->{new}{bond}{$interface}{link_state}, "new::bond::${interface}::operational" => $anvil->data->{new}{bond}{$interface}{operational}, "new::bond::${interface}::mac_address" => $anvil->data->{new}{bond}{$interface}{mac_address}, "new::bond::${interface}::primary_interface" => $anvil->data->{new}{bond}{$interface}{primary_interface}, "new::bond::${interface}::primary_reselect" => $anvil->data->{new}{bond}{$interface}{primary_reselect}, "new::bond::${interface}::active_interface" => $anvil->data->{new}{bond}{$interface}{active_interface}, "new::bond::${interface}::mii_polling_interval" => $anvil->data->{new}{bond}{$interface}{mii_polling_interval}, "new::bond::${interface}::up_delay" => $anvil->data->{new}{bond}{$interface}{up_delay}, "new::bond::${interface}::down_delay" => $anvil->data->{new}{bond}{$interface}{down_delay}, "new::bond::${interface}::bridge_uuid" => $anvil->data->{new}{bond}{$interface}{bridge_uuid}, "new::bond::${interface}::tx_bytes" => $anvil->data->{new}{bond}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bond}{$interface}{tx_bytes}}).")", "new::bond::${interface}::rx_bytes" => $anvil->data->{new}{bond}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bond}{$interface}{rx_bytes}}).")", }}); } elsif ($type eq "interface") { # Store the interface $anvil->data->{new}{interface}{$interface}{bond_uuid} = ""; $anvil->data->{new}{interface}{$interface}{bond_name} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; $anvil->data->{new}{interface}{$interface}{bridge_uuid} = ""; $anvil->data->{new}{interface}{$interface}{bridge_name} = ""; $anvil->data->{new}{interface}{$interface}{duplex} = $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}; $anvil->data->{new}{interface}{$interface}{link_state} = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; $anvil->data->{new}{interface}{$interface}{operational} = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; $anvil->data->{new}{interface}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; $anvil->data->{new}{interface}{$interface}{medium} = $anvil->data->{network}{$local_host}{interface}{$interface}{media}; $anvil->data->{new}{interface}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; $anvil->data->{new}{interface}{$interface}{speed} = $anvil->data->{network}{$local_host}{interface}{$interface}{speed}; $anvil->data->{new}{interface}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{interface}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "new::interface::${interface}::bond_uuid" => $anvil->data->{new}{interface}{$interface}{bond_uuid}, "new::interface::${interface}::bond_name" => $anvil->data->{new}{interface}{$interface}{bond_name}, "new::interface::${interface}::bridge_uuid" => $anvil->data->{new}{interface}{$interface}{bridge_uuid}, "new::interface::${interface}::bridge_name" => $anvil->data->{new}{interface}{$interface}{bridge_name}, "new::interface::${interface}::duplex" => $anvil->data->{new}{interface}{$interface}{duplex}, "new::interface::${interface}::link_state" => $anvil->data->{new}{interface}{$interface}{link_state}, "new::interface::${interface}::operational" => $anvil->data->{new}{interface}{$interface}{operational}, "new::interface::${interface}::mac_address" => $anvil->data->{new}{interface}{$interface}{mac_address}, "new::interface::${interface}::medium" => $anvil->data->{new}{interface}{$interface}{medium}, "new::interface::${interface}::mtu" => $anvil->data->{new}{interface}{$interface}{mtu}, "new::interface::${interface}::speed" => $anvil->data->{new}{interface}{$interface}{speed}, "new::interface::${interface}::tx_bytes" => $anvil->data->{new}{interface}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{tx_bytes}}).")", "new::interface::${interface}::rx_bytes" => $anvil->data->{new}{interface}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{rx_bytes}}).")", }}); # On some occassions, an interface that is in a bond won't start. If the host uptime # is less than ten minutes, and a bond's member interface is down, up it. if ($uptime < 600) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "nmcli::${local_host}::device_to_uuid::${interface}" => $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$interface}, }}); my $uuid = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$interface}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); if ($uuid) { my $state = $anvil->data->{nmcli}{$local_host}{uuid}{$uuid}{'state'}; my $filename = $anvil->data->{nmcli}{$local_host}{uuid}{$uuid}{filename}; my $name = ($filename =~ /ifcfg-(.*?)$/)[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { filename => $filename, name => $name, 'state' => $state, }}); # This could be 'active' or 'activated' if ($state !~ /activ/) { # Try brinding the interface up. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0147", variables => { interface => $interface, uptime => $uptime, 'state' => $state, }}); my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); } } } } # Record the IP address info. if ($ip_address) { $anvil->data->{new}{ip_address}{$ip_address}{on_interface} = $interface; $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask} = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}; $anvil->data->{new}{ip_address}{$ip_address}{gateway} = $anvil->data->{network}{$local_host}{interface}{$interface}{gateway}; $anvil->data->{new}{ip_address}{$ip_address}{default_gateway} = $anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway}; $anvil->data->{new}{ip_address}{$ip_address}{dns} = $anvil->data->{network}{$local_host}{interface}{$interface}{dns}; $anvil->data->{new}{ip_address}{$ip_address}{on_uuid} = ""; $anvil->data->{new}{ip_address}{$ip_address}{note} = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "new::ip_address::${ip_address}::on_interface" => $anvil->data->{new}{ip_address}{$ip_address}{on_interface}, "new::ip_address::${ip_address}::subnet_mask" => $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask}, "new::ip_address::${ip_address}::gateway" => $anvil->data->{new}{ip_address}{$ip_address}{gateway}, "new::ip_address::${ip_address}::default_gateway" => $anvil->data->{new}{ip_address}{$ip_address}{default_gateway}, "new::ip_address::${ip_address}::dns" => $anvil->data->{new}{ip_address}{$ip_address}{dns}, "new::ip_address::${ip_address}::on_uuid" => $anvil->data->{new}{ip_address}{$ip_address}{on_uuid}, "new::ip_address::${ip_address}::note" => $anvil->data->{new}{ip_address}{$ip_address}{note}, }}); } } return(0); } # This reads in the states from the last can sub read_last_scan { my ($anvil) = @_; ### NOTE: There is a bug somewhere where interfaces are periodically being added twice per host. This ### checks for / cleans those up. Remove this when the core issue is resolved. clear_duplicates($anvil); # Read in the old bridge data. load_bridge_data($anvil); load_bond_data($anvil); load_interface_data($anvil); load_ip_address_data($anvil); return(0); } # There is a bug somewhere where interfaces, bridges and ip addresses are periodically being added twice per # host. This checks for / cleans those up. Remove this when the core issue is resolved. sub clear_duplicates { my ($anvil) = @_; # Look for duplicate bridges. my $query = " SELECT bridge_uuid, bridge_name, bridge_id, bridge_mac_address FROM bridges WHERE bridge_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ORDER BY bridge_name ASC, bridge_id DESC ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $bridge_uuid = $row->[0]; my $bridge_name = $row->[1]; my $bridge_id = $row->[2]; my $bridge_mac_address = $row->[3]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid, bridge_name => $bridge_name, bridge_id => $bridge_id, bridge_mac_address => $bridge_mac_address, }}); if (not exists $anvil->data->{duplicate_bridges}{seen}{$bridge_name}) { $anvil->data->{duplicate_bridges}{seen}{$bridge_name} = []; } push @{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}, $bridge_uuid; $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_name} = $bridge_name; $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address} = $bridge_mac_address; $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id} = $bridge_id; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_name" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}, "duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_id" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}, "duplicate_bridges::bridge_uuid::${bridge_uuid}::bridge_mac_address" => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}, }}); $anvil->data->{deleted_bridges}{$bridge_uuid} = 0; } foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_bridges}{seen}}) { my $count = @{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:bridge_name' => $bridge_name, 's2:count' => $count, }}); if ($count > 1) { # Duplicate! Is one of them marked as DELETED? foreach my $bridge_uuid (@{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}) { # Is this one deleted? my $bridge_mac_address = $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}; my $bridge_id = $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid, bridge_mac_address => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}, bridge_id => $anvil->data->{duplicate_bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}, }}); if ($bridge_id eq "DELETED") { # Take this one out. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { name => $bridge_name, uuid => $bridge_uuid, }}); # If there's a bond connected to this bridge, get it's bond_uuid so # we can remove any interfaces linked to it. my $bond_uuid = ""; my $query = "SELECT bond_uuid FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); if ($count) { $bond_uuid = $results->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); } my $queries = []; push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; if ($bond_uuid) { push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; } push @{$queries}, "DELETE FROM history.bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; push @{$queries}, "DELETE FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; # Write it out. $anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__}); $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); $anvil->data->{deleted_bridges}{$bridge_uuid} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "deleted_bridges::${bridge_uuid}" => $anvil->data->{deleted_bridges}{$bridge_uuid}, }}); } last if $count == 1; } # If count is still > 1, we need to arbitrarily delete an interface. if ($count > 1) { foreach my $bridge_uuid (@{$anvil->data->{duplicate_bridges}{seen}{$bridge_name}}) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { name => $bridge_name, uuid => $bridge_uuid, }}); # If there's a bond connected to this bridge, get it's bond_uuid so # we can remove any interfaces linked to it. my $bond_uuid = ""; my $query = "SELECT bond_uuid FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); if ($count) { $bond_uuid = $results->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); } my $queries = []; push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; if ($bond_uuid) { push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; } push @{$queries}, "DELETE FROM history.bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; push @{$queries}, "DELETE FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; push @{$queries}, "DELETE FROM history.bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; push @{$queries}, "DELETE FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; # Write it out. $anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__}); $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); $anvil->data->{deleted_bridges}{$bridge_uuid} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "deleted_bridges::${bridge_uuid}" => $anvil->data->{deleted_bridges}{$bridge_uuid}, }}); } last if $count == 1; } } } delete $anvil->data->{duplicate_bridges}; # Load the bridges again. $anvil->Database->get_bridges({include_deleted => 1}); # Look for duplicate bonds. $query = " SELECT bond_uuid, bond_name, bond_operational, bond_mac_address, bond_bridge_uuid FROM bonds WHERE bond_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ORDER BY bond_name ASC, bond_operational DESC ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $bond_uuid = $row->[0]; my $bond_name = $row->[1]; my $bond_operational = $row->[2]; my $bond_mac_address = $row->[3]; my $bond_bridge_uuid = defined $row->[4] ? $row->[4] : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid, bond_name => $bond_name, bond_operational => $bond_operational, bond_mac_address => $bond_mac_address, bond_bridge_uuid => $bond_bridge_uuid, }}); if (not exists $anvil->data->{duplicate_bonds}{seen}{$bond_name}) { $anvil->data->{duplicate_bonds}{seen}{$bond_name} = []; } push @{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}, $bond_uuid; $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_name} = $bond_name; $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address} = $bond_mac_address; $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational} = $bond_operational; $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid} = $bond_bridge_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "duplicate_bonds::bond_uuid::${bond_uuid}::bond_name" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_name}, "duplicate_bonds::bond_uuid::${bond_uuid}::bond_operational" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational}, "duplicate_bonds::bond_uuid::${bond_uuid}::bond_mac_address" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address}, "duplicate_bonds::bond_uuid::${bond_uuid}::bond_bridge_uuid" => $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid}, }}); $anvil->data->{deleted_bonds}{$bond_uuid} = 0; } foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_bonds}{seen}}) { my $count = @{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:bond_name' => $bond_name, 's2:count' => $count, }}); if ($count > 1) { # Duplicate! Is one of them marked as DELETED? foreach my $bond_uuid (@{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}) { # Is this one deleted? my $bond_mac_address = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_mac_address}; my $bond_operational = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_operational}; my $bond_bridge_uuid = $anvil->data->{duplicate_bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid, bond_mac_address => $bond_mac_address, bond_operational => $bond_operational, bond_bridge_uuid => $bond_bridge_uuid, }}); if ((($bond_bridge_uuid) && ($anvil->data->{deleted_bridges}{$bond_bridge_uuid})) or ($bond_operational eq "DELETED")) { # Take this one out. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { name => $bond_name, uuid => $bond_uuid, }}); my $queries = []; push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; # Write it out. $anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__}); $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); $anvil->data->{deleted_bonds}{$bond_uuid} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "deleted_bonds::${bond_uuid}" => $anvil->data->{deleted_bonds}{$bond_uuid}, }}); } } # If count is still > 1, we need to arbitrarily delete an interface. if ($count > 1) { foreach my $bond_uuid (@{$anvil->data->{duplicate_bonds}{seen}{$bond_name}}) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0685", variables => { name => $bond_name, uuid => $bond_uuid, }}); my $queries = []; push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; push @{$queries}, "DELETE FROM history.bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; push @{$queries}, "DELETE FROM bonds WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; # Write it out. $anvil->Database->write({debug => 2, query => $queries, source => $THIS_FILE, line => __LINE__}); $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); $anvil->data->{deleted_bonds}{$bond_uuid} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "deleted_bonds::${bond_uuid}" => $anvil->data->{deleted_bonds}{$bond_uuid}, }}); } last if $count == 1; } } } delete $anvil->data->{duplicate_bonds}; # Look for duplicate network interfaces $query = " SELECT network_interface_uuid, network_interface_name, network_interface_mac_address, network_interface_operational, network_interface_bond_uuid, network_interface_bridge_uuid FROM network_interfaces WHERE network_interface_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ORDER BY network_interface_name ASC ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $network_interface_uuid = $row->[0]; my $network_interface_name = $row->[1]; my $network_interface_mac_address = $row->[2]; my $network_interface_operational = $row->[3]; my $network_interface_bond_uuid = defined $row->[4] ? $row->[4] : ""; my $network_interface_bridge_uuid = defined $row->[5] ? $row->[5] : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid, network_interface_name => $network_interface_name, network_interface_mac_address => $network_interface_mac_address, network_interface_operational => $network_interface_operational, network_interface_bond_uuid => $network_interface_bond_uuid, network_interface_bridge_uuid => $network_interface_bridge_uuid, }}); if (not exists $anvil->data->{duplicate_nics}{seen}{$network_interface_name}) { $anvil->data->{duplicate_nics}{seen}{$network_interface_name} = []; } push @{$anvil->data->{duplicate_nics}{seen}{$network_interface_name}}, $network_interface_uuid; $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_name; $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address} = $network_interface_mac_address; $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $network_interface_operational; $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid} = $network_interface_bond_uuid; $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = $network_interface_bridge_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_name" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}, "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}, "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_operational" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}, "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_bond_uuid" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}, "duplicate_nics::network_interface_uuid::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}, }}); } foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{duplicate_nics}{seen}}) { my $count = @{$anvil->data->{duplicate_nics}{seen}{$network_interface_name}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:network_interface_name' => $network_interface_name, 's2:count' => $count, }}); if ($count > 1) { # Duplicate! Is one of them marked as DELETED? foreach my $network_interface_uuid (@{$anvil->data->{duplicate_nics}{seen}{$network_interface_name}}) { # Is this one deleted? my $network_interface_mac_address = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}; my $network_interface_operational = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}; my $network_interface_bond_uuid = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}; my $network_interface_bridge_uuid = $anvil->data->{duplicate_nics}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid, network_interface_mac_address => $network_interface_mac_address, network_interface_operational => $network_interface_operational, network_interface_bond_uuid => $network_interface_bond_uuid, network_interface_bridge_uuid => $network_interface_bridge_uuid, }}); if ((($network_interface_bond_uuid) && ($anvil->data->{deleted_bonds}{$network_interface_bond_uuid})) or (($network_interface_bridge_uuid) && ($anvil->data->{deleted_bridges}{$network_interface_bridge_uuid})) or ($network_interface_operational eq "DELETED")) { # Take this one out. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0647", variables => { name => $network_interface_name, uuid => $network_interface_uuid, }}); my $queries = []; push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";"; foreach my $query (@{$queries}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); } } # If count is still > 1, we need to arbitrarily delete an interface. if ($count > 1) { foreach my $network_interface_uuid (@{$anvil->data->{duplicate_nics}{seen}{$network_interface_name}}) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0647", variables => { name => $network_interface_name, uuid => $network_interface_uuid, }}); my $queries = []; push @{$queries}, "DELETE FROM history.network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";"; push @{$queries}, "DELETE FROM network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";"; foreach my $query (@{$queries}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); } last if $count == 1; } } } delete $anvil->data->{duplicate_nics}; $query = " SELECT ip_address_uuid, ip_address_address, ip_address_note FROM ip_addresses WHERE ip_address_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ORDER BY ip_address_address ASC ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $ip_address_uuid = $row->[0]; my $ip_address_address = $row->[1]; my $ip_address_note = $row->[2]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid, ip_address_address => $ip_address_address, ip_address_note => $ip_address_note, }}); if (not exists $anvil->data->{duplicate_ips}{seen}{$ip_address_address}) { $anvil->data->{duplicate_ips}{seen}{$ip_address_address} = []; } push @{$anvil->data->{duplicate_ips}{seen}{$ip_address_address}}, $ip_address_uuid; $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_address} = $ip_address_address; $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_note} = $ip_address_note; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "duplicate_ips::ip_address_uuid::${ip_address_uuid}::ip_address_address" => $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_address}, "duplicate_ips::ip_address_uuid::${ip_address_uuid}::ip_address_note" => $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}, }}); } foreach my $ip_address_address (sort {$a cmp $b} keys %{$anvil->data->{duplicate_ips}{seen}}) { my $count = @{$anvil->data->{duplicate_ips}{seen}{$ip_address_address}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:ip_address_address' => $ip_address_address, 's2:count' => $count, }}); if ($count > 1) { # Duplicate! Is one of them marked as DELETED? foreach my $ip_address_uuid (@{$anvil->data->{duplicate_ips}{seen}{$ip_address_address}}) { # Is this one deleted? my $ip_address_note = $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid, ip_address_note => $anvil->data->{duplicate_ips}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}, }}); if ($ip_address_note eq "DELETED") { # Take this one out. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0664", variables => { ip => $ip_address_address, uuid => $ip_address_uuid, }}); my $queries = []; push @{$queries}, "DELETE FROM history.ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";"; push @{$queries}, "DELETE FROM ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";"; foreach my $query (@{$queries}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); } last if $count == 1; } # If count is still > 1, we need to arbitrarily delete an interface. if ($count > 1) { foreach my $ip_address_uuid (@{$anvil->data->{duplicate_ips}{seen}{$ip_address_address}}) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0664", variables => { ip => $ip_address_address, uuid => $ip_address_uuid, }}); my $queries = []; push @{$queries}, "DELETE FROM history.ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";"; push @{$queries}, "DELETE FROM ip_addresses WHERE ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid).";"; foreach my $query (@{$queries}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); } $anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); $count--; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); } last if $count == 1; } } } return(0); } sub load_ip_address_data { my ($anvil) = @_; # Now record the IPs. my $query = " SELECT ip_address_uuid, ip_address_on_type, ip_address_on_uuid, ip_address_address, ip_address_subnet_mask, ip_address_gateway, ip_address_default_gateway, ip_address_dns, ip_address_note FROM ip_addresses WHERE ip_address_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $ip_address_uuid = $row->[0]; my $ip_address_on_type = $row->[1]; my $ip_address_address = $row->[3]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid, ip_address_on_type => $ip_address_on_type, ip_address_address => $ip_address_address, }}); $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_type} = $ip_address_on_type; $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_uuid} = $row->[2]; $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_address} = $ip_address_address; $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_subnet_mask} = $row->[4]; $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_gateway} = $row->[5]; $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_default_gateway} = $row->[6]; $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_dns} = $row->[7]; $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_note} = $row->[8]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_on_type" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_type}, "old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_on_uuid" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_uuid}, "old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_address" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_address}, "old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_subnet_mask" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_subnet_mask}, "old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_gateway" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_gateway}, "old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_default_gateway" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_default_gateway}, "old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_dns" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_dns}, "old::ip_addresses::ip_address_uuid::${ip_address_uuid}::ip_address_note" => $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}, }}); $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address_address} = $ip_address_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "old::ip_addresses::ip_to_uuid::${ip_address_address}" => $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address_address}, }}); } return(0); } sub load_interface_data { my ($anvil) = @_; # Process interfaces my $query = " SELECT network_interface_uuid, network_interface_mac_address, network_interface_name, network_interface_speed, network_interface_mtu, network_interface_link_state, network_interface_operational, network_interface_duplex, network_interface_medium, network_interface_bond_uuid, network_interface_bridge_uuid FROM network_interfaces WHERE network_interface_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $network_interface_uuid = $row->[0]; my $network_interface_mac_address = $row->[1]; my $network_interface_name = $row->[2]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid, network_interface_mac_address => $network_interface_mac_address, network_interface_name => $network_interface_name, }}); # Read in the RX/TX values, set to '0' if not found. my ($rx_bytes, $rx_variable_uuid, $modified_date) = $anvil->Database->read_variable({ variable_name => "network_interface::".$network_interface_name."::rx_bytes", variable_source_uuid => $network_interface_uuid, variable_source_table => "network_interfaces", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_bytes => $rx_bytes, rx_variable_uuid => $rx_variable_uuid, }}); (my $tx_bytes, my $tx_variable_uuid, $modified_date) = $anvil->Database->read_variable({ variable_name => "network_interface::".$network_interface_name."::tx_bytes", variable_source_uuid => $network_interface_uuid, variable_source_table => "network_interfaces", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_bytes => $tx_bytes, tx_variable_uuid => $tx_variable_uuid, }}); $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address} = $network_interface_mac_address; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_name; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed} = $row->[3]; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu} = $row->[4]; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state} = $row->[5]; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $row->[6]; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex} = $row->[7]; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium} = $row->[8]; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid} = defined $row->[9] ? $row->[9] : ''; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = defined $row->[10] ? $row->[10] : ''; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes} = $rx_bytes =~ /^\d+$/ ? $rx_bytes : 0; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid} = $rx_variable_uuid; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes} = $tx_bytes =~ /^\d+$/ ? $tx_bytes : 0; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid} = $tx_variable_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_name" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_speed" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_mtu" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_link_state" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_operational" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_duplex" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_medium" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_bond_uuid" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::rx_bytes" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}}).")", "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::rx_variable_uuid" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::tx_bytes" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}}).")", "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::tx_variable_uuid" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid}, }}); $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid} = $network_interface_name; $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address} = $network_interface_uuid; $anvil->data->{interface}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::name_to_uuid::${network_interface_name}" => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}, "network_interfaces::uuid_to_name::${network_interface_name}" => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}, "network_interfaces::mac_to_uuid::${network_interface_mac_address}" => $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address}, "interface::name_to_uuid::${network_interface_name}" => $anvil->data->{interface}{name_to_uuid}{$network_interface_name}, }}); } return(0); } sub load_bond_data { my ($anvil) = @_; # 'bond_mode' will be 'DELETED' if the bond was removed. my $query = " SELECT bond_uuid, bond_name, bond_mode, bond_mtu, bond_primary_interface, bond_primary_reselect, bond_active_interface, bond_mii_polling_interval, bond_up_delay, bond_down_delay, bond_mac_address, bond_operational, bond_bridge_uuid FROM bonds WHERE bond_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $bond_uuid = $row->[0]; my $bond_name = $row->[1]; my $bond_bridge_uuid = defined $row->[12] ? $row->[12] : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid, bond_name => $bond_name, bond_bridge_uuid => $bond_bridge_uuid, }}); # Read in the RX/TX values, set to '0' if not found. my ($rx_bytes, $rx_variable_uuid, $modified_date) = $anvil->Database->read_variable({ variable_name => "bond::".$bond_name."::rx_bytes", variable_source_uuid => $bond_uuid, variable_source_table => "bonds", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_bytes => $rx_bytes, rx_variable_uuid => $rx_variable_uuid, }}); (my $tx_bytes, my $tx_variable_uuid, $modified_date) = $anvil->Database->read_variable({ variable_name => "bond::".$bond_name."::tx_bytes", variable_source_uuid => $bond_uuid, variable_source_table => "bonds", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_bytes => $tx_bytes, tx_variable_uuid => $tx_variable_uuid, }}); $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_name} = $bond_name; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mode} = $row->[2]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mtu} = $row->[3]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_interface} = $row->[4]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_reselect} = $row->[5]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_active_interface} = $row->[6]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mii_polling_interval} = $row->[7]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_up_delay} = $row->[8]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_down_delay} = $row->[9]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mac_address} = $row->[10]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_operational} = $row->[11]; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid} = $bond_bridge_uuid; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes} = $rx_bytes =~ /\d/ ? $rx_bytes : 0; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_variable_uuid} = $rx_variable_uuid; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes} = $tx_bytes =~ /\d/ ? $tx_bytes : 0; $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_variable_uuid} = $tx_variable_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "old::bonds::bond_uuid::${bond_uuid}::bond_name" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_name}, "old::bonds::bond_uuid::${bond_uuid}::bond_mode" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mode}, "old::bonds::bond_uuid::${bond_uuid}::bond_mtu" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mtu}, "old::bonds::bond_uuid::${bond_uuid}::bond_primary_interface" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_interface}, "old::bonds::bond_uuid::${bond_uuid}::bond_primary_reselect" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_reselect}, "old::bonds::bond_uuid::${bond_uuid}::bond_active_interface" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_active_interface}, "old::bonds::bond_uuid::${bond_uuid}::bond_mii_polling_interval" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mii_polling_interval}, "old::bonds::bond_uuid::${bond_uuid}::bond_up_delay" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_up_delay}, "old::bonds::bond_uuid::${bond_uuid}::bond_down_delay" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_down_delay}, "old::bonds::bond_uuid::${bond_uuid}::bond_mac_address" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mac_address}, "old::bonds::bond_uuid::${bond_uuid}::bond_operational" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_operational}, "old::bonds::bond_uuid::${bond_uuid}::bond_bridge_uuid" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid}, "old::bonds::bond_uuid::${bond_uuid}::rx_bytes" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes}}).")", "old::bonds::bond_uuid::${bond_uuid}::rx_variable_uuid" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_variable_uuid}, "old::bonds::bond_uuid::${bond_uuid}::tx_bytes" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes}}).")", "old::bonds::bond_uuid::${bond_uuid}::tx_variable_uuid" => $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_variable_uuid}, }}); $anvil->data->{bonds}{name_to_uuid}{$bond_name} = $bond_uuid; $anvil->data->{bonds}{uuid_to_name}{$bond_uuid} = $bond_name; $anvil->data->{interface}{name_to_uuid}{$bond_name} = $bond_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bonds::name_to_uuid::${bond_name}" => $anvil->data->{bonds}{name_to_uuid}{$bond_name}, "bonds::uuid_to_name::${bond_uuid}" => $anvil->data->{bonds}{uuid_to_name}{$bond_uuid}, "interface::name_to_uuid::${bond_name}" => $anvil->data->{interface}{name_to_uuid}{$bond_name}, }}); } return(0); } sub load_bridge_data { my ($anvil) = @_; # The 'bridge_id' will be DELETED if the bridge was removed earlier. my $query = " SELECT bridge_uuid, bridge_name, bridge_id, bridge_mac_address, bridge_mtu, bridge_stp_enabled FROM bridges WHERE bridge_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $bridge_uuid = $row->[0]; my $bridge_name = $row->[1]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid, bridge_name => $bridge_name, }}); # Read in the RX/TX values, set to '0' if not found. my ($rx_bytes, $rx_variable_uuid, $modified_date) = $anvil->Database->read_variable({ variable_name => "bridge::".$bridge_name."::rx_bytes", variable_source_uuid => $bridge_uuid, variable_source_table => "bridges", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_bytes => $rx_bytes, rx_variable_uuid => $rx_variable_uuid, }}); (my $tx_bytes, my $tx_variable_uuid, $modified_date) = $anvil->Database->read_variable({ variable_name => "bridge::".$bridge_name."::tx_bytes", variable_source_uuid => $bridge_uuid, variable_source_table => "bridges", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_bytes => $tx_bytes, tx_variable_uuid => $tx_variable_uuid, }}); # Record the data in the hash, too. $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_name} = $bridge_name; $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id} = $row->[2]; $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address} = $row->[3]; $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mtu} = $row->[4]; $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_stp_enabled} = $row->[5]; $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes} = $rx_bytes =~ /\d/ ? $rx_bytes : 0; $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_variable_uuid} = $rx_variable_uuid; $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes} = $tx_bytes =~ /\d/ ? $tx_bytes : 0; $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_variable_uuid} = $tx_variable_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "old::bridges::bridge_uuid::${bridge_uuid}::bridge_name" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}, "old::bridges::bridge_uuid::${bridge_uuid}::bridge_id" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}, "old::bridges::bridge_uuid::${bridge_uuid}::bridge_mac_address" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}, "old::bridges::bridge_uuid::${bridge_uuid}::bridge_mtu" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mtu}, "old::bridges::bridge_uuid::${bridge_uuid}::bridge_stp_enabled" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_stp_enabled}, "old::bridges::bridge_uuid::${bridge_uuid}::rx_bytes" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes}}).")", "old::bridges::bridge_uuid::${bridge_uuid}::rx_variable_uuid" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_variable_uuid}, "old::bridges::bridge_uuid::${bridge_uuid}::tx_bytes" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes}}).")", "old::bridges::bridge_uuid::${bridge_uuid}::tx_variable_uuid" => $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_variable_uuid}, }}); $anvil->data->{bridges}{name_to_uuid}{$bridge_name} = $bridge_uuid; $anvil->data->{bridges}{uuid_to_name}{$bridge_uuid} = $bridge_name; $anvil->data->{interface}{name_to_uuid}{$bridge_name} = $bridge_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bridges::name_to_uuid::${bridge_name}" => $anvil->data->{bridges}{name_to_uuid}{$bridge_name}, "bridges::uuid_to_name::${bridge_uuid}" => $anvil->data->{bridges}{uuid_to_name}{$bridge_uuid}, "interface::name_to_uuid::${bridge_name}" => $anvil->data->{interface}{name_to_uuid}{$bridge_name}, }}); } return(0); } # This compares the last scan and the read state info and handles changes. sub find_changes { my ($anvil) = @_; check_bridges($anvil); check_bonds($anvil); check_interfaces($anvil); check_ip_addresses($anvil); return(0); } # Handle IP addresses sub check_ip_addresses { my ($anvil) = @_; foreach my $ip_address (sort {$a cmp $b} keys %{$anvil->data->{new}{ip_address}}) { my $on_interface = $anvil->data->{new}{ip_address}{$ip_address}{on_interface}; my $new_on_type = $anvil->data->{interface}{name_to_type}{$on_interface}; my $new_on_uuid = $anvil->data->{interface}{name_to_uuid}{$on_interface}; my $new_subnet_mask = $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask}; my $new_gateway = $anvil->data->{new}{ip_address}{$ip_address}{gateway}; my $new_default_gateway = $anvil->data->{new}{ip_address}{$ip_address}{default_gateway}; my $new_dns = $anvil->data->{new}{ip_address}{$ip_address}{dns}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address => $ip_address, on_interface => $on_interface, new_on_type => $new_on_type, new_on_uuid => $new_on_uuid, new_subnet_mask => $new_subnet_mask, new_gateway => $new_gateway, new_default_gateway => $new_default_gateway, new_dns => $new_dns, }}); if (exists $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address}) { # Existing, update? my $ip_address_uuid = $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address}; my $old_on_type = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_type}; my $old_on_uuid = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_on_uuid}; my $old_subnet_mask = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_subnet_mask}; my $old_gateway = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_gateway}; my $old_default_gateway = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_default_gateway}; my $old_dns = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_dns}; my $old_note = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_note}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address => $ip_address, old_on_type => $old_on_type, old_on_uuid => $old_on_uuid, old_subnet_mask => $old_subnet_mask, old_gateway => $old_gateway, old_default_gateway => $old_default_gateway, old_dns => $old_dns, old_note => $old_note, }}); # Delete this old entry so we know we've processed it. delete $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}; my $say_old_interface = "--"; if ($old_on_type eq "bridge") { $say_old_interface = $anvil->data->{bridges}{uuid_to_name}{$old_on_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_old_interface => $say_old_interface }}); } elsif ($old_on_type eq "bond") { $say_old_interface = $anvil->data->{bonds}{uuid_to_name}{$old_on_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_old_interface => $say_old_interface }}); } elsif ($old_on_type eq "interface") { $say_old_interface = $anvil->data->{network_interfaces}{uuid_to_name}{$old_on_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_old_interface => $say_old_interface }}); } # Now look for changes. my $changes = 0; # These will always change together. if (($new_on_type ne $old_on_type) or ($new_on_uuid ne $old_on_uuid)) { # This was likely changed by an admin, so it's a notice level alert. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { ip_address => $ip_address, old => $say_old_interface, new => $on_interface, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0050", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0050", variables => $variables, set_by => $THIS_FILE, }); } if ($new_subnet_mask ne $old_subnet_mask) { # This was likely changed by an admin, so it's a notice level alert. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { ip_address => $ip_address, interface => $on_interface, old => $ip_address."/".$old_subnet_mask, new => $ip_address."/".$new_subnet_mask, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0051", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0051", variables => $variables, set_by => $THIS_FILE, }); } if ($new_gateway ne $old_gateway) { # This was likely changed by an admin, so it's a notice level alert. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { ip_address => $ip_address, interface => $on_interface, old => $old_gateway eq "" ? "--" : $old_gateway, new => $new_gateway eq "" ? "--" : $new_gateway, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0052", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0052", variables => $variables, set_by => $THIS_FILE, }); } if ($new_default_gateway ne $old_default_gateway) { # This was likely changed by an admin, so it's a notice level alert. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { ip_address => $ip_address, interface => $on_interface, old => $old_default_gateway ? "#!string!unit_0001!#" : "#!string!unit_0002!#", new => $new_default_gateway ? "#!string!unit_0001!#" : "#!string!unit_0002!#", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0053", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0053", variables => $variables, set_by => $THIS_FILE, }); } if ($new_dns ne $old_dns) { # This was likely changed by an admin, so it's a notice level alert. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { ip_address => $ip_address, interface => $on_interface, old => $old_dns eq "" ? "--" : $old_dns, new => $new_dns eq "" ? "--" : $new_dns, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0054", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0054", variables => $variables, set_by => $THIS_FILE, }); } # We only care about 'old_note' if it's set to 'DELETED'. if ($old_note eq "DELETED") { # This was likely changed by an admin, so it's a notice level alert. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { ip_address => $ip_address, interface => $on_interface, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0055", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0055", variables => $variables, set_by => $THIS_FILE, }); } if ($changes) { # If the note was 'DELETED', change it to ''. Otherwise, use the old note. $old_note = "" if $old_note eq "DELETED"; my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ debug => 2, ip_address_uuid => $ip_address_uuid, ip_address_on_type => $new_on_type, ip_address_on_uuid => $new_on_uuid, ip_address_address => $ip_address, ip_address_subnet_mask => $new_subnet_mask, ip_address_gateway => $new_gateway, ip_address_default_gateway => $new_default_gateway, ip_address_dns => $new_dns, ip_address_note => $old_note, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid }}); } } else { # New, store. my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ debug => 2, ip_address_on_type => $new_on_type, ip_address_on_uuid => $new_on_uuid, ip_address_address => $ip_address, ip_address_subnet_mask => $new_subnet_mask, ip_address_gateway => $new_gateway, ip_address_default_gateway => $new_default_gateway, ip_address_dns => $new_dns, ip_address_note => "", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid }}); # Register a notice level alert. my $variables = { ip_address => $ip_address, interface => $on_interface, subnet_mask => $new_subnet_mask, gateway => $new_gateway eq "" ? "--" : $new_gateway, default_gateway => $new_default_gateway ? "#!string!unit_0001!#" : "#!string!unit_0002!#", dns => $new_dns eq "" ? "--" : $new_dns, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0056", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0056", variables => $variables, set_by => $THIS_FILE, }); } } # Look for left over / deleted bonds. foreach my $ip_address_uuid (keys %{$anvil->data->{old}{ip_addresses}{ip_address_uuid}}) { # Skip if already deleted. next if $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_note} eq "DELETED"; my $ip_address_address = $anvil->data->{old}{ip_addresses}{ip_address_uuid}{$ip_address_uuid}{ip_address_address}; my $variables = { ip => $ip_address_address }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0060", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0060", variables => $variables, set_by => $THIS_FILE, }); my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ debug => 2, ip_address_uuid => $ip_address_uuid, 'delete' => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address_uuid => $ip_address_uuid }}); } return(0); } # Look for changes in network interfaces. sub check_interfaces { my ($anvil) = @_; foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{new}{interface}}) { my $new_bond_uuid = $anvil->data->{new}{interface}{$network_interface_name}{bond_uuid}; my $new_bond_name = $anvil->data->{new}{interface}{$network_interface_name}{bond_name}; my $new_bridge_uuid = $anvil->data->{new}{interface}{$network_interface_name}{bridge_uuid}; my $new_bridge_name = $anvil->data->{new}{interface}{$network_interface_name}{bridge_name}; my $new_duplex = $anvil->data->{new}{interface}{$network_interface_name}{duplex}; my $new_link_state = $anvil->data->{new}{interface}{$network_interface_name}{link_state}; my $new_operational = $anvil->data->{new}{interface}{$network_interface_name}{operational}; my $new_mac_address = $anvil->data->{new}{interface}{$network_interface_name}{mac_address}; my $new_medium = $anvil->data->{new}{interface}{$network_interface_name}{medium}; my $new_mtu = $anvil->data->{new}{interface}{$network_interface_name}{mtu}; my $new_speed = $anvil->data->{new}{interface}{$network_interface_name}{speed}; my $new_tx_bytes = $anvil->data->{new}{interface}{$network_interface_name}{tx_bytes}; my $new_rx_bytes = $anvil->data->{new}{interface}{$network_interface_name}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_name => $network_interface_name, new_bond_uuid => $new_bond_uuid, new_bond_name => $new_bond_name, new_bridge_uuid => $new_bridge_uuid, new_bridge_name => $new_bridge_name, new_duplex => $new_duplex, new_link_state => $new_link_state, new_operational => $new_operational, new_mac_address => $new_mac_address, new_medium => $new_medium, new_mtu => $new_mtu, new_speed => $new_speed, new_tx_bytes => $new_tx_bytes, new_rx_bytes => $new_rx_bytes, }}); # Find the bridge, if any, and the bond UUID, if there's a bond name. if ($new_bond_name) { $new_bond_uuid = $anvil->data->{bonds}{name_to_uuid}{$new_bond_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_bond_uuid => $new_bond_uuid }}); } if (exists $anvil->data->{interface_to_bridge}{$network_interface_name}) { # This interface is on a bridge $new_bridge_name = $anvil->data->{interface_to_bridge}{$network_interface_name}; $new_bridge_uuid = $anvil->data->{bridges}{name_to_uuid}{$new_bridge_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_bridge_name => $new_bridge_name, new_bridge_uuid => $new_bridge_uuid, }}); } # New or existing? if (exists $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}) { # Existing. Changes? my $network_interface_uuid = $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}; my $old_bond_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}; my $old_bond_name = ""; my $old_bridge_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}; my $old_bridge_name = ""; my $old_duplex = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex}; my $old_link_state = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}; my $old_operational = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}; my $old_mac_address = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}; my $old_medium = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium}; my $old_mtu = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}; my $old_speed = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}; my $old_rx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}; my $rx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid}; my $old_tx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}; my $tx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_bond_uuid => $old_bond_uuid, old_bridge_uuid => $old_bridge_uuid, old_duplex => $old_duplex, old_link_state => $old_link_state, old_operational => $old_operational, old_mac_address => $old_mac_address, old_medium => $old_medium, old_mtu => $old_mtu, old_speed => $old_speed, old_tx_bytes => $old_tx_bytes, tx_variable_uuid => $tx_variable_uuid, old_rx_bytes => $old_rx_bytes, rx_variable_uuid => $rx_variable_uuid, }}); # Delete this so we know it's processed. delete $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}; # Get the old bridge or bond name, if required. if ($old_bridge_uuid) { # Get the bridge name $old_bridge_name = $anvil->data->{bridges}{uuid_to_name}{$old_bridge_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_bridge_name => $old_bridge_name }}); } if ($old_bond_uuid) { $old_bond_name = $anvil->data->{bonds}{uuid_to_name}{$old_bond_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_bond_name => $old_bond_name }}); } # Look for changes. my $changes = 0; if ($new_bond_uuid ne $old_bond_uuid) { # We're making this a warning level alert as it should not be changing. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $key = "scan_network_alert_0032"; if (not $new_bond_uuid) { # Left the bond $key = "scan_network_alert_0031"; } elsif (not $old_bond_uuid) { # Joined the bond $key = "scan_network_alert_0030"; } my $variables = { name => $network_interface_name, old => $old_bond_name." (".$old_bond_uuid.")", new => $new_bond_name." (".$new_bond_uuid.")", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_bridge_uuid ne $old_bridge_uuid) { # If this is a vnet* device, it's a notice level alert. Otherwise it's a # warning level alert. The vnetX devices come and go with VMs. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $log_level = 1; my $alert_level = "warning"; my $key = "scan_network_alert_0035"; if ($network_interface_name =~ /^vnet/) { # Left the bridge $log_level = 1; $alert_level = "warning"; } if ($new_bridge_uuid) { # Left the bridge $key = "scan_network_alert_0034"; } elsif (not $old_bridge_uuid) { # Joined the bridge $key = "scan_network_alert_0033"; } my $variables = { name => $network_interface_name, old => $old_bridge_name." (".$old_bridge_uuid.")", new => $new_bridge_name." (".$new_bridge_uuid.")", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_duplex ne $old_duplex) { # This is always a warning $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $clear = 0; my $key = "scan_network_alert_0036"; my $alert_level = "notice"; if ($new_duplex eq "full") { # Duplex is back to being OK $clear = 1; $key = "scan_network_alert_0037"; } # Is this one of our interface? if (not $anvil->Network->is_our_interface({interface => $network_interface_name})) { # Not an interface we care about. $alert_level = "notice"; } my $variables = { name => $network_interface_name, old => $old_duplex, new => $new_duplex, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, clear_alert => $clear, message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_link_state ne $old_link_state) { # This is always a warning, if it's a NIC we care about. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $clear = 0; my $key = "scan_network_alert_0038"; my $alert_level = "warning"; if ($new_link_state) { # Link is up $clear = 1; $key = "scan_network_alert_0039"; } # Is this one of our interface? if (not $anvil->Network->is_our_interface({interface => $network_interface_name})) { # Not an interface we care about. $alert_level = "notice"; } my $variables = { name => $network_interface_name, old => $old_link_state, new => $new_link_state, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, clear_alert => $clear, message => $key, variables => $variables, set_by => $THIS_FILE, }); } # Operation can be DELETED if ($new_operational ne $old_operational) { # This is always a warning $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); # Is it up or down? my $clear = 0; my $key = "scan_network_alert_0040"; my $alert_level = "notice"; if ($old_operational eq "DELETED") { # Link is back. Is it up? if ($new_operational eq "up") { # It's up $clear = 1; $key = "scan_network_alert_0042"; } else { # It's back, but down $key = "scan_network_alert_0043"; } } elsif ($new_operational eq "up") { # It's up $clear = 1; $key = "scan_network_alert_0041"; } # Is this one of our interface? if (not $anvil->Network->is_our_interface({interface => $network_interface_name})) { # Not an interface we care about. $alert_level = "notice"; } my $variables = { name => $network_interface_name, old => $old_operational, new => $new_operational, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, clear_alert => $clear, message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_mac_address ne $old_mac_address) { # This is a notice level alert as it's almost certainly a NIC change # performed by an admin. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $network_interface_name, old => $old_mac_address, new => $new_mac_address, }; my $key = "scan_network_alert_0044"; if ($network_interface_name =~ /^vnet/) { # This is a server booting or migrating $key = "scan_network_alert_0061"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_medium ne $old_medium) { # This is a notice level alert as it's almost certainly a NIC change # performed by an admin. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $network_interface_name, old => $old_medium, new => $new_medium, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0045", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0045", variables => $variables, set_by => $THIS_FILE, }); } if ($new_mtu ne $old_mtu) { # We're making this a warning level alert if the MTU drops. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $network_interface_name, old => $old_mtu, new => $new_mtu, }; my $log_level = 2; my $alert_level = "notice"; my $key = "scan_network_alert_0046"; if ($new_mtu < $old_mtu) { # Make it an alert $log_level = 1; $alert_level = "warning"; $key = "scan_network_alert_0047"; } # Is this one of our interface? if (not $anvil->Network->is_our_interface({interface => $network_interface_name})) { # Not an interface we care about. $alert_level = "notice"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_speed ne $old_speed) { # We're making this a warning level as speed shouldn't change $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $network_interface_name, old => $old_speed, new => $new_speed, }; my $key = "scan_network_alert_0048"; if ($new_speed > $old_speed) { # Speed dropped, likely a faulty network cable $key = "scan_network_alert_0049"; } # Is this one of our interface? my $alert_level = "notice"; if (not $anvil->Network->is_our_interface({interface => $network_interface_name})) { # Not an interface we care about. $alert_level = "notice"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($changes) { my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, network_interface_name => $network_interface_name, network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, network_interface_mac_address => $new_mac_address, network_interface_medium => $new_medium, network_interface_mtu => $new_mtu, network_interface_speed => $new_speed, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); } # Track usage of interfaces we care about if ($anvil->Network->is_our_interface({interface => $network_interface_name})) { # Rx and Tx almost always change, so they're only info-level alerts. if ($new_tx_bytes ne $old_tx_bytes) { if ($tx_variable_uuid) { my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_uuid => $tx_variable_uuid, update_value_only => 1, variable_value => $new_tx_bytes, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } else { # No value seen before, create my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "network_interface::".$network_interface_name."::tx_bytes", variable_value => $new_tx_bytes, variable_default => 0, variable_description => "striker_0291", variable_section => "stats", variable_source_uuid => $network_interface_uuid, variable_source_table => "network_interfaces", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } my $variables = { name => $network_interface_name, old => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", new => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", }; # Reset or normal increase? my $key = "scan_network_alert_0007"; my $alert_level = "info"; my $log_level = 2; if ($old_tx_bytes > $new_tx_bytes) { # Reset $key = "scan_network_alert_0008"; $alert_level = "notice"; $log_level = 2; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_rx_bytes ne $old_rx_bytes) { if ($rx_variable_uuid) { my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_uuid => $rx_variable_uuid, update_value_only => 1, variable_value => $new_rx_bytes, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } else { # No value seen before, create my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "network_interface::".$network_interface_name."::rx_bytes", variable_value => $new_rx_bytes, variable_default => 0, variable_description => "striker_0290", variable_section => "stats", variable_source_uuid => $network_interface_uuid, variable_source_table => "network_interfaces", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } my $variables = { name => $network_interface_name, old => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", new => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", }; # Reset or normal increase? my $key = "scan_network_alert_0009"; my $alert_level = "info"; my $log_level = 2; if ($old_rx_bytes > $new_rx_bytes) { # Reset $key = "scan_network_alert_0010"; $alert_level = "notice"; $log_level = 2; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } } } else { # Record the interface my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, network_interface_name => $network_interface_name, network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, network_interface_mac_address => $new_mac_address, network_interface_medium => $new_medium, network_interface_mtu => $new_mtu, network_interface_speed => $new_speed, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); # Store the interface so IPs can find our UUID. $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid} = $network_interface_name; $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address} = $network_interface_uuid; $anvil->data->{interface}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::name_to_uuid::${network_interface_name}" => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}, "network_interfaces::uuid_to_name::${network_interface_uuid}" => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}, "network_interfaces::mac_to_uuid::${new_mac_address}" => $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address}, "interface::name_to_uuid::${network_interface_name}" => $anvil->data->{interface}{name_to_uuid}{$network_interface_name}, }}); # Store the rx_bytes and tx_bytes my $rx_variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "network_interface::".$network_interface_name."::rx_bytes", variable_value => $new_rx_bytes, variable_default => 0, variable_description => "striker_0290", variable_section => "stats", variable_source_uuid => $new_bond_uuid, variable_source_table => "bonds", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_variable_uuid => $rx_variable_uuid }}); my $tx_variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "network_interface::".$network_interface_name."::tx_bytes", variable_value => $new_tx_bytes, variable_default => 0, variable_description => "striker_0291", variable_section => "stats", variable_source_uuid => $new_bond_uuid, variable_source_table => "bonds", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_variable_uuid => $tx_variable_uuid }}); # Report. my $say_duplex = "#!string!unit_0004!#"; if ($new_duplex =~ /full/i) { $say_duplex = "#!string!unit_0015!#"; } elsif ($new_duplex =~ /half/i) { $say_duplex = "#!string!unit_0016!#"; } my $variables = { interface_name => $network_interface_name, bond_name => $new_bond_name ? $new_bond_name : "--", bridge_name => $new_bridge_name ? $new_bridge_name : "--", duplex => $say_duplex, link_state => $new_link_state ? "#!string!unit_0013!#" : "#!string!unit_0014!#", # up / down operational => $new_operational, mac_address => $new_mac_address, medium => $new_medium, mtu => $new_mtu, speed => $new_speed, say_tx => $anvil->Convert->add_commas({number => $new_tx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", say_rx => $anvil->Convert->add_commas({number => $new_rx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0029", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0029", variables => $variables, set_by => $THIS_FILE, }); } } # Look for left over / deleted bonds. foreach my $network_interface_uuid (keys %{$anvil->data->{old}{network_interfaces}{network_interface_uuid}}) { # Skip if already deleted. next if $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} eq "DELETED"; my $network_interface_name = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}; my $tx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}; my $rx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}; my $variables = { name => $network_interface_name, tx => $anvil->Convert->add_commas({number => $tx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", rx => $anvil->Convert->add_commas({number => $rx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", }; # If this a vnet device, it's only a notice message as this is expected when a VM migrates or # shuts down. my $alert_level = $network_interface_name =~ /^vnet/ ? "notice" : "warning"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0059", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0059", variables => $variables, set_by => $THIS_FILE, }); my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, network_interface_uuid => $network_interface_uuid, 'delete' => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); } return(0); } # Look for changes in the bonds. sub check_bonds { my ($anvil) = @_; foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{new}{bond}}) { # Store the bond my $new_mode = $anvil->data->{new}{bond}{$bond_name}{mode}; my $new_mtu = $anvil->data->{new}{bond}{$bond_name}{mtu}; my $new_operational = $anvil->data->{new}{bond}{$bond_name}{operational}; my $new_mac_address = $anvil->data->{new}{bond}{$bond_name}{mac_address}; my $new_primary_interface = $anvil->data->{new}{bond}{$bond_name}{primary_interface}; my $new_primary_reselect = $anvil->data->{new}{bond}{$bond_name}{primary_reselect}; my $new_active_interface = $anvil->data->{new}{bond}{$bond_name}{active_interface}; my $new_mii_polling_interval = $anvil->data->{new}{bond}{$bond_name}{mii_polling_interval}; my $new_up_delay = $anvil->data->{new}{bond}{$bond_name}{up_delay}; my $new_down_delay = $anvil->data->{new}{bond}{$bond_name}{down_delay}; my $new_tx_bytes = $anvil->data->{new}{bond}{$bond_name}{tx_bytes}; my $new_rx_bytes = $anvil->data->{new}{bond}{$bond_name}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_name => $bond_name, new_mode => $new_mode, new_mtu => $new_mtu, new_operational => $new_operational, new_mac_address => $new_mac_address, new_primary_interface => $new_primary_interface, new_primary_reselect => $new_primary_reselect, new_active_interface => $new_active_interface, new_mii_polling_interval => $new_mii_polling_interval, new_up_delay => $new_up_delay, new_down_delay => $new_down_delay, new_tx_bytes => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", new_rx_bytes => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", }}); # If we don't have a bridge_uuid, find it by the name. my $new_bridge_uuid = ""; my $new_bridge_name = ""; if (exists $anvil->data->{interface_to_bridge}{$bond_name}) { # This bond is on a bridge $new_bridge_name = $anvil->data->{interface_to_bridge}{$bond_name}; $new_bridge_uuid = $anvil->data->{bridges}{name_to_uuid}{$new_bridge_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_bridge_name => $new_bridge_name, new_bridge_uuid => $new_bridge_uuid, }}); } # New or existing? if (exists $anvil->data->{bonds}{name_to_uuid}{$bond_name}) { # Existing, look for changes. my $bond_uuid = $anvil->data->{bonds}{name_to_uuid}{$bond_name}; my $old_mode = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mode}; my $old_mtu = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mtu}; my $old_primary_interface = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_interface}; my $old_primary_reselect = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_primary_reselect}; my $old_active_interface = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_active_interface}; my $old_mii_polling_interval = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mii_polling_interval}; my $old_up_delay = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_up_delay}; my $old_down_delay = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_down_delay}; my $old_mac_address = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_mac_address}; my $old_operational = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_operational}; my $old_bridge_uuid = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_bridge_uuid}; my $old_rx_bytes = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes}; my $rx_variable_uuid = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_variable_uuid}; my $old_tx_bytes = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes}; my $tx_variable_uuid = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_variable_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid, old_mode => $old_mode, old_mtu => $old_mtu, old_primary_interface => $old_primary_interface, old_primary_reselect => $old_primary_reselect, old_active_interface => $old_active_interface, old_mii_polling_interval => $old_mii_polling_interval, old_up_delay => $old_up_delay, old_down_delay => $old_down_delay, old_mac_address => $old_mac_address, old_operational => $old_operational, old_bridge_uuid => $old_bridge_uuid, old_rx_bytes => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", rx_variable_uuid => $rx_variable_uuid, old_tx_bytes => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", tx_variable_uuid => $tx_variable_uuid, }}); # Delete the old record so we know it's been processed. delete $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}; my $old_bridge_name = ""; if ($old_bridge_uuid) { $old_bridge_name = $anvil->data->{bridges}{uuid_to_name}{$old_bridge_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_bridge_name => $old_bridge_name }}); } my $changes = 0; if ($new_mode ne $old_mode) { # We're making this a warning level alert as it should not be changing. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $say_old_name = "scan_network_bond_".$old_mode."_name"; my $say_old_number = "scan_network_bond_".$old_mode."_number"; my $say_old_description = "scan_network_bond_".$old_mode."_description"; my $say_new_name = "scan_network_bond_".$new_mode."_name"; my $say_new_number = "scan_network_bond_".$new_mode."_number"; my $say_new_description = "scan_network_bond_".$new_mode."_description"; my $variables = { name => $bond_name, old => $say_old_name, old_number => $say_old_number, old_description => $say_old_description, new => $say_new_name, new_number => $say_new_number, new_description => $say_new_description, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0012", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0012", variables => $variables, set_by => $THIS_FILE, }); } if ($new_mtu ne $old_mtu) { # We're making this a warning level alert if the MTU drops. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_mtu, new => $new_mtu, }; my $log_level = 2; my $alert_level = "notice"; my $key = "scan_network_alert_0013"; if ($new_mtu < $old_mtu) { # Make it an alert $log_level = 1; $alert_level = "warning"; $key = "scan_network_alert_0014"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_bridge_name ne $old_bridge_name) { # We're making this a warning level alert as it should not be changing. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_bridge_name ? $old_bridge_name : "--", new => $new_bridge_name ? $new_bridge_name : "--", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0015", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0015", variables => $variables, set_by => $THIS_FILE, }); } if ($new_operational ne $old_operational) { # We're making this a warning level alert as it should not be changing. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_operational eq "up" ? "#!string!unit_0013!#" : "#!string!unit_0014!#", new => $new_operational eq "up" ? "#!string!unit_0013!#" : "#!string!unit_0014!#", }; # Gone up, down or returned? my $key = "scan_network_alert_0016"; if ($old_operational eq "DELETED") { # Bond is back from being deleted. Is it up or down? if ($new_operational eq "up") { # Back and up $key = "scan_network_alert_0027"; } else { # Back but down $key = "scan_network_alert_0028"; } } elsif ($new_operational eq "up") { $key = "scan_network_alert_0017"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_mac_address ne $old_mac_address) { # We're making this a notice as it can change with the active interface # changing. There will be a warning if a given interface dropped. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_mac_address, new => $new_mac_address, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0018", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0018", variables => $variables, set_by => $THIS_FILE, }); } if ($new_primary_interface ne $old_primary_interface) { # We're making this a notice as it will only change if an admin did it. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_primary_interface, new => $new_primary_interface, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0019", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0019", variables => $variables, set_by => $THIS_FILE, }); } if ($new_primary_reselect ne $old_primary_reselect) { # We're making this a notice as it will only change if an admin did it. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_primary_reselect, new => $new_primary_reselect, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0020", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0020", variables => $variables, set_by => $THIS_FILE, }); } if ($new_active_interface ne $old_active_interface) { # We're making this a warning as this generally happens when a link drops or returns. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_active_interface, new => $new_active_interface, }; # Did the primary interface return? my $key = "scan_network_alert_0021"; if ($new_active_interface eq $new_primary_interface) { # Primary link is back $key = "scan_network_alert_0022"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_mii_polling_interval ne $old_mii_polling_interval) { # We're making this a notice as this will only ever change by an admin. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_mii_polling_interval, new => $new_mii_polling_interval, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0023", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0023", variables => $variables, set_by => $THIS_FILE, }); } if ($new_up_delay ne $old_up_delay) { # We're making this a notice as this will only ever change by an admin. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_up_delay, new => $new_up_delay, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0024", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0024", variables => $variables, set_by => $THIS_FILE, }); } if ($new_down_delay ne $old_down_delay) { # We're making this a notice as this will only ever change by an admin. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bond_name, old => $old_down_delay, new => $new_down_delay, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0024", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0024", variables => $variables, set_by => $THIS_FILE, }); } # Save the changes, if any. if ($changes) { my $bond_uuid = $anvil->Database->insert_or_update_bonds({ debug => 2, bond_name => $bond_name, bond_mode => $new_mode, bond_mtu => $new_mtu, bond_operational => $new_operational, bond_mac_address => $new_mac_address, bond_primary_interface => $new_primary_interface, bond_primary_reselect => $new_primary_reselect, bond_active_interface => $new_active_interface, bond_mii_polling_interval => $new_mii_polling_interval, bond_up_delay => $new_up_delay, bond_down_delay => $new_down_delay, bond_bridge_uuid => $new_bridge_uuid, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); } # Rx and Tx almost always change, so they're only info-level alerts. if ($new_tx_bytes ne $old_tx_bytes) { if ($tx_variable_uuid) { my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_uuid => $tx_variable_uuid, update_value_only => 1, variable_value => $new_tx_bytes, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } else { # No value seen before, create my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "bond::".$bond_name."::tx_bytes", variable_value => $new_tx_bytes, variable_default => 0, variable_description => "striker_0291", variable_section => "stats", variable_source_uuid => $bond_uuid, variable_source_table => "bonds", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } my $variables = { name => $bond_name, old => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", new => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", }; # Reset or normal increase? my $key = "scan_network_alert_0007"; my $alert_level = "info"; my $log_level = 2; if ($old_tx_bytes > $new_tx_bytes) { # Reset $key = "scan_network_alert_0008"; $alert_level = "notice"; $log_level = 2; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_rx_bytes ne $old_rx_bytes) { if ($rx_variable_uuid) { my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_uuid => $rx_variable_uuid, update_value_only => 1, variable_value => $new_rx_bytes, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } else { # No value seen before, create my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "bond::".$bond_name."::rx_bytes", variable_value => $new_rx_bytes, variable_default => 0, variable_description => "striker_0290", variable_section => "stats", variable_source_uuid => $bond_uuid, variable_source_table => "bonds", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } my $variables = { name => $bond_name, old => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", new => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", }; # Reset or normal increase? Reset Normal increase my $key = "scan_network_alert_0009"; my $alert_level = "info"; my $log_level = 2; if ($old_rx_bytes > $new_rx_bytes) { # Reset $key = "scan_network_alert_0010"; $alert_level = "notice"; $log_level = 2; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } } else { # New bond. Is it on a bridge? my $bridge_name = ""; my $bridge_uuid = ""; if (exists $anvil->data->{interface_to_bridge}{$bond_name}) { $bridge_name = $anvil->data->{interface_to_bridge}{$bond_name}; $bridge_uuid = $anvil->data->{bridges}{name_to_uuid}{$bridge_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_name => $bridge_name, bridge_uuid => $bridge_uuid, }}); } # Record the bond my $bond_uuid = $anvil->Database->insert_or_update_bonds({ debug => 2, bond_name => $bond_name, bond_mode => $new_mode, bond_mtu => $new_mtu, bond_operational => $new_operational, bond_mac_address => $new_mac_address, bond_primary_interface => $new_primary_interface, bond_primary_reselect => $new_primary_reselect, bond_active_interface => $new_active_interface, bond_mii_polling_interval => $new_mii_polling_interval, bond_up_delay => $new_up_delay, bond_down_delay => $new_down_delay, bond_bridge_uuid => $bridge_uuid, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); # Store the bond so our links can find our UUID. $anvil->data->{bonds}{name_to_uuid}{$bond_name} = $bond_uuid; $anvil->data->{bonds}{uuid_to_name}{$bond_uuid} = $bond_name; $anvil->data->{interface}{name_to_uuid}{$bond_name} = $bond_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bonds::name_to_uuid::${bond_name}" => $anvil->data->{bonds}{name_to_uuid}{$bond_name}, "bonds::uuid_to_name::${bond_uuid}" => $anvil->data->{bonds}{uuid_to_name}{$bond_uuid}, "interface::name_to_uuid::${bond_name}" => $anvil->data->{interface}{name_to_uuid}{$bond_name}, }}); # Store the rx_bytes and tx_bytes my $rx_variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "bond::".$bond_name."::rx_bytes", variable_value => $new_rx_bytes, variable_default => 0, variable_description => "striker_0290", variable_section => "stats", variable_source_uuid => $bond_uuid, variable_source_table => "bonds", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_variable_uuid => $rx_variable_uuid }}); my $tx_variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "bond::".$bond_name."::tx_bytes", variable_value => $new_tx_bytes, variable_default => 0, variable_description => "striker_0291", variable_section => "stats", variable_source_uuid => $bond_uuid, variable_source_table => "bonds", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_variable_uuid => $tx_variable_uuid }}); # Report. my $variables = { bond_name => $bond_name, mode => "scan_network_bond_".$new_mode."_name", number => "scan_network_bond_".$new_mode."_number", description => "scan_network_bond_".$new_mode."_description", mtu => $new_mtu, bridge => $bridge_name ? $bridge_name : "--", operational => $new_operational eq "up" ? "#!string!unit_0013!#" : "#!string!unit_0014!#", mac_address => $new_mac_address, primary_interface => $new_primary_interface, primary_reselect => $new_primary_reselect, active_interface => $new_active_interface, mii_polling_interval => $new_mii_polling_interval, up_delay => $new_up_delay, down_delay => $new_down_delay, say_tx => $anvil->Convert->add_commas({number => $new_tx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", say_rx => $anvil->Convert->add_commas({number => $new_rx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0011", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0011", variables => $variables, set_by => $THIS_FILE, }); } } # Look for left over / deleted bonds. foreach my $bond_uuid (keys %{$anvil->data->{old}{bonds}{bond_uuid}}) { # Skip if already deleted. next if $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_operational} eq "DELETED"; my $bond_name = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{bond_name}; my $tx_bytes = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{tx_bytes}; my $rx_bytes = $anvil->data->{old}{bonds}{bond_uuid}{$bond_uuid}{rx_bytes}; my $variables = { name => $bond_name, tx => $anvil->Convert->add_commas({number => $tx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", rx => $anvil->Convert->add_commas({number => $rx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0058", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0058", variables => $variables, set_by => $THIS_FILE, }); my $bond_uuid = $anvil->Database->insert_or_update_bonds({ debug => 2, bond_uuid => $bond_uuid, 'delete' => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); } return(0); } # Look for changes in the bridges. sub check_bridges { my ($anvil) = @_; # Loop through the new stuff found and look for changes. Bridges first. foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{new}{bridge}}) { # The RX/TX always change. my $new_bridge_id = $anvil->data->{new}{bridge}{$bridge_name}{id}; my $new_mac_address = $anvil->data->{new}{bridge}{$bridge_name}{mac_address}; my $new_mtu = $anvil->data->{new}{bridge}{$bridge_name}{mtu}; my $new_stp_enabled = $anvil->data->{new}{bridge}{$bridge_name}{stp_enabled}; my $new_tx_bytes = $anvil->data->{new}{bridge}{$bridge_name}{tx_bytes}; my $new_rx_bytes = $anvil->data->{new}{bridge}{$bridge_name}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_name => $bridge_name, new_bridge_id => $new_bridge_id, new_mac_address => $new_mac_address, new_mtu => $new_mtu, new_stp_enabled => $new_stp_enabled, new_tx_bytes => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", new_rx_bytes => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", }}); # New or existing? if (exists $anvil->data->{bridges}{name_to_uuid}{$bridge_name}) { # Existing, look for changes. my $bridge_uuid = $anvil->data->{bridges}{name_to_uuid}{$bridge_name}; my $old_bridge_id = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}; my $old_mac_address = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mac_address}; my $old_mtu = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_mtu}; my $old_stp_enabled = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_stp_enabled}; my $old_tx_bytes = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes}; my $tx_variable_uuid = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_variable_uuid}; my $old_rx_bytes = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes}; my $rx_variable_uuid = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_variable_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid, old_bridges_id => $old_bridge_id, old_mac_address => $old_mac_address, old_mtu => $old_mtu, old_stp_enabled => $old_stp_enabled, old_tx_bytes => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", tx_variable_uuid => $tx_variable_uuid, old_rx_bytes => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", rx_variable_uuid => $rx_variable_uuid, }}); # Delete the old record so we know it's been processed. delete $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}; my $changes = 0; if ($new_bridge_id ne $old_bridge_id) { # We're making this a notice level alert as it has no impact on the system, # unless it's returned from being deleted. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bridge_name, old => $old_bridge_id, new => $new_bridge_id, }; # Did the bridge return? my $key = "scan_network_alert_0003"; my $log_level = 2; my $alert_level = "notice"; if ($old_bridge_id eq "DELETED") { # Bridge is back. $key = "scan_network_alert_0026"; $log_level = 1; $alert_level = "warning"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } elsif ($new_mac_address ne $old_mac_address) { # This is odd, but not harmful $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bridge_name, old => $old_mac_address, new => $new_mac_address, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0004", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0004", variables => $variables, set_by => $THIS_FILE, }); } elsif ($new_mtu ne $old_mtu) { # This is a waning, need to ensure the client understands what's going on here. $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bridge_name, old => $old_mtu, new => $new_mtu, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0005", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0005", variables => $variables, set_by => $THIS_FILE, }); } elsif ($new_stp_enabled ne $old_stp_enabled) { # This is a notice $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); my $variables = { name => $bridge_name, old => $old_stp_enabled, new => $new_stp_enabled, }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_network_alert_0006", variables => $variables}); $anvil->Alert->register({ alert_level => "notice", message => "scan_network_alert_0006", variables => $variables, set_by => $THIS_FILE, }); } if ($changes) { # Update my $bridge_uuid = $anvil->Database->insert_or_update_bridges({ debug => 2, bridge_name => $bridge_name, bridge_id => $new_bridge_id, bridge_mac_address => $new_mac_address, bridge_mtu => $new_mtu, bridge_stp_enabled => $new_stp_enabled, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); } # Rx and Tx almost always change, so they're only info-level alerts. if ($new_tx_bytes ne $old_tx_bytes) { if ($tx_variable_uuid) { my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_uuid => $tx_variable_uuid, update_value_only => 1, variable_value => $new_tx_bytes, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } else { # No value seen before, create my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "bridge::".$bridge_name."::tx_bytes", variable_value => $new_tx_bytes, variable_default => 0, variable_description => "striker_0291", variable_section => "stats", variable_source_uuid => $bridge_uuid, variable_source_table => "bridges", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } my $variables = { name => $bridge_name, old => $old_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_tx_bytes}).")", new => $new_tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", }; # Reset or normal increase? my $key = "scan_network_alert_0007"; my $alert_level = "info"; my $log_level = 2; if ($old_tx_bytes > $new_tx_bytes) { # Reset $key = "scan_network_alert_0008"; $alert_level = "notice"; $log_level = 2; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } if ($new_rx_bytes ne $old_rx_bytes) { if ($rx_variable_uuid) { my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_uuid => $rx_variable_uuid, update_value_only => 1, variable_value => $new_rx_bytes, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } else { # No value seen before, create my $variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "bridge::".$bridge_name."::rx_bytes", variable_value => $new_rx_bytes, variable_default => 0, variable_description => "striker_0290", variable_section => "stats", variable_source_uuid => $bridge_uuid, variable_source_table => "bridges", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); } my $variables = { name => $bridge_name, old => $old_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_rx_bytes}).")", new => $new_rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", }; # Reset or normal increase? Reset Normal increase my $key = "scan_network_alert_0009"; my $alert_level = "info"; my $log_level = 2; if ($old_rx_bytes > $new_rx_bytes) { # Reset $key = "scan_network_alert_0010"; $alert_level = "notice"; $log_level = 2; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, key => $key, variables => $variables}); $anvil->Alert->register({ alert_level => $alert_level, message => $key, variables => $variables, set_by => $THIS_FILE, }); } } else { # New, INSERT it and record the new UUID for the interfaces connected on this bridge # to find. my $bridge_uuid = $anvil->Database->insert_or_update_bridges({ debug => 2, bridge_name => $bridge_name, bridge_id => $new_bridge_id, bridge_mac_address => $new_mac_address, bridge_mtu => $new_mtu, bridge_stp_enabled => $new_stp_enabled, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); $anvil->data->{bridges}{name_to_uuid}{$bridge_name} = $bridge_uuid; $anvil->data->{bridges}{uuid_to_name}{$bridge_uuid} = $bridge_name; $anvil->data->{interface}{name_to_uuid}{$bridge_name} = $bridge_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "old::bridges::name_to_uuid::${bridge_name}" => $anvil->data->{bridges}{name_to_uuid}{$bridge_name}, "old::bridges::uuid_to_name::${bridge_uuid}" => $anvil->data->{bridges}{uuid_to_name}{$bridge_uuid}, "interface::name_to_uuid::${bridge_name}" => $anvil->data->{interface}{name_to_uuid}{$bridge_name}, }}); # Store the rx_bytes and tx_bytes my $rx_variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "bridge::".$bridge_name."::rx_bytes", variable_value => $new_rx_bytes, variable_default => 0, variable_description => "striker_0290", variable_section => "stats", variable_source_uuid => $bridge_uuid, variable_source_table => "bridges", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rx_variable_uuid => $rx_variable_uuid }}); my $tx_variable_uuid = $anvil->Database->insert_or_update_variables({ debug => 2, variable_name => "bridge::".$bridge_name."::tx_bytes", variable_value => $new_tx_bytes, variable_default => 0, variable_description => "striker_0291", variable_section => "stats", variable_source_uuid => $bridge_uuid, variable_source_table => "bridges", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { tx_variable_uuid => $tx_variable_uuid }}); # Report. my $variables = { bridge_name => $bridge_name, bridge_id => $new_bridge_id, mac_address => $new_mac_address, mtu => $new_mtu, stp_enabled => $new_stp_enabled, say_tx => $anvil->Convert->add_commas({number => $new_tx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_tx_bytes}).")", say_rx => $anvil->Convert->add_commas({number => $new_rx_bytes})." #!string!suffix_0057!# (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_rx_bytes}).")", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0002", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0002", variables => $variables, set_by => $THIS_FILE, }); } } # Look for left over / deleted bridges. foreach my $bridge_uuid (keys %{$anvil->data->{old}{bridges}{bridge_uuid}}) { # Skip if already deleted. if (not $bridge_uuid) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_warning_0001"}); $anvil->nice_exit({exit_code => 1}); } my $bridge_name = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_name}; my $bridge_id = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{bridge_id}; my $tx_bytes = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{tx_bytes}; my $rx_bytes = $anvil->data->{old}{bridges}{bridge_uuid}{$bridge_uuid}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid, bridge_name => $bridge_name, tx_bytes => $tx_bytes, rx_bytes => $rx_bytes, }}); next if $bridge_id eq "DELETED"; my $variables = { name => $bridge_name, tx => $anvil->Convert->add_commas({number => $tx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", rx => $anvil->Convert->add_commas({number => $rx_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", }; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0057", variables => $variables}); $anvil->Alert->register({ alert_level => "warning", message => "scan_network_alert_0057", variables => $variables, set_by => $THIS_FILE, }); my $bridge_uuid = $anvil->Database->insert_or_update_bridges({ debug => 2, bridge_uuid => $bridge_uuid, 'delete' => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); } return(0); } # This handles health record changes. sub process_health { my ($anvil) = @_; # Get the existing health scores, if any. my $query = " SELECT health_uuid, health_source_name, health_source_weight FROM health WHERE health_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." AND health_source_name LIKE '".$THIS_FILE."%' ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { # We've got an entry in the 'scan_hardware' table, so now we'll look for data in the node and # services tables. my $health_source_name = $row->[1]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_source_name => $health_source_name }}); $anvil->data->{old}{health}{$health_source_name}{health_uuid} = $row->[0]; $anvil->data->{old}{health}{$health_source_name}{health_source_weight} = $row->[2]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "old::health::${health_source_name}::health_uuid" => $anvil->data->{old}{health}{$health_source_name}{health_uuid}, "old::health::${health_source_name}::health_source_weight" => $anvil->data->{old}{health}{$health_source_name}{health_source_weight}, }}); } # Now look for interfaces that are down. For now, that's all we look for to set / clear health. foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{new}{interface}}) { my $new_duplex = $anvil->data->{new}{interface}{$network_interface_name}{duplex}; my $new_link_state = $anvil->data->{new}{interface}{$network_interface_name}{link_state}; my $new_operational = $anvil->data->{new}{interface}{$network_interface_name}{operational}; my $source_name = $THIS_FILE."::".$network_interface_name."::problem"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_name => $network_interface_name, new_duplex => $new_duplex, new_link_state => $new_link_state, new_operational => $new_operational, source_name => $source_name, }}); # Don't set / clear interfaces that appear down but aren't named ifn/bcn/sn as they're probably # unconfigured/unusued interfaces. my $problem = 0; my $check = 0; my $monitored = $anvil->Network->is_our_interface({interface => $network_interface_name}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { monitored => $monitored }}); if ($monitored) { # One we monitor $check = 1; } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { check => $check }}); if (($check) && ((not $new_link_state) or ($new_operational eq "down") or ($new_duplex ne "full"))) { $problem = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); if (exists $anvil->data->{old}{health}{$source_name}) { # Already registered. delete $anvil->data->{old}{health}{$source_name}; } else { # Has the interface been down for at least a minute? my $age = $anvil->Alert->check_condition_age({ debug => 2, name => $source_name, host_uuid => $anvil->Get->host_uuid, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }}); if ($age > 60) { # New, save. my ($health_uuid) = $anvil->Database->insert_or_update_health({ debug => 2, health_agent_name => $THIS_FILE, health_source_name => $source_name, health_source_weight => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_uuid => $health_uuid }}); } } } else { # Clear any old conditions. my $age = $anvil->Alert->check_condition_age({ debug => 2, clear => 1, name => $source_name, host_uuid => $anvil->Get->host_uuid, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { age => $age }}); } } # Any remaining health scores can be deleted. foreach my $health_source_name (sort {$a cmp $b} keys %{$anvil->data->{old}{health}}) { my $health_uuid = $anvil->data->{old}{health}{$health_source_name}{health_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { health_source_name => $health_source_name, health_uuid => $health_uuid, }}); $anvil->Database->insert_or_update_health({ debug => 2, health_uuid => $health_uuid, 'delete' => 1, }); } return(0); }