Local modifications to ClusterLabs/Anvil by Alteeve
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4224 lines
191 KiB

#!/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);
}