anvil/tools/anvil-update-states
Digimer 11b1900e1b Note: Continuing to resolve the build issues with network startup. Expect breakage.
* Upped the aging of jobs and alerts data from 2 to 24 hours. Also added a check to prevent deleting a job of any age that is incomplete.
* Major update to anvil-configure-host to not touch the network unless something has actually changed. Not yet tested on a fresh system, will verify nothing broke in the CI tests this commit will trigger. Also changed it so that, if after reconfiguring the network it times out trying to reconnect to a database, it calls a reboot instead of simply exiting. Further, a reboot is now not called on exit unless something changed to require it.
* Updated Network->check_bonds() to return '1' if anything was done to heal a bond.
* Updated anvil-update-states to be more careful about clearing virsh bridges. Specifically, it checks to see if virsh is running and that the returned bridges aren't actually error codes.

Signed-off-by: Digimer <digimer@alteeve.ca>
2021-06-14 01:58:25 -04:00

1079 lines
54 KiB
Perl
Executable File

#!/usr/bin/perl
#
# This updates things like the current network configuration, shared file data and writes it out to a json file.
#
use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;
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();
$anvil->Get->switches;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# If there's no DB (or cached data isn't recorded to the database yet), this will store those records.
$anvil->data->{cache}{new_file} = "# interface,timestamp,mac_address,speed,link_state,operational\n";
$anvil->Database->connect({debug => 3});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
# No database, but we need to keep going. If the user unplugged the only cable connecting us to the
# network, we'll lose all DBs, but we still need to record the order the NICs went up and down.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0016"});
}
process_interface_cache($anvil);
update_network($anvil);
# Write out the interface cache
$anvil->Storage->write_file({
debug => 3,
body => $anvil->data->{cache}{new_file},
file => $anvil->data->{path}{data}{network_cache},
overwrite => 1,
backup => 0,
});
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
# This reads in the interface cache file and looks for records that haven't been stored in the database yet.
sub process_interface_cache
{
my ($anvil) = @_;
# Does the file exist? If so, read it in.
if (-e $anvil->data->{path}{data}{network_cache})
{
my $body = $anvil->Storage->read_file({debug => 3, cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}});
foreach my $line (split/\n/, $body)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
next if $line =~ /^#/;
my ($interface, $timestamp, $mac_address, $speed, $link_state, $operational) = (split/,/, $line);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
interface => $interface,
timestamp => $timestamp,
speed => $speed,
mac_address => $mac_address,
link_state => $link_state,
operational => $operational,
}});
if ($anvil->data->{sys}{database}{connections})
{
my ($network_interface_uuid) = $anvil->Database->insert_or_update_network_interfaces({
debug => 3,
link_only => 1,
timestamp => $timestamp,
network_interface_name => $interface,
network_interface_link_state => $link_state,
network_interface_mac_address => $mac_address,
network_interface_operational => $operational,
network_interface_speed => $speed,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }});
if (not $network_interface_uuid)
{
# Failed to update, could be that we cached data for an interface not yet
# seen. If so, the coming scan will add it and this cache should flush out
# next time.
$anvil->data->{cache}{new_file} .= $line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }});
}
}
else
{
# No database, re-cache
$anvil->data->{cache}{new_file} .= $line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }});
}
}
}
return(0);
}
# This reports the current network interface states, tracked by the MAC address.
sub update_network
{
my ($anvil) = @_;
# Run 'ip addr' to see what IPs are in use.
$anvil->Network->get_ips();
# We'll read through '/sys/class/net' looking for network interfaces.
# * 'network::${local_host}::interface::<iface_name>::ip' - If an IP address is set
# * 'network::${local_host}::interface::<iface_name>::subnet_mask' - If an IP is set
my $local_host = $anvil->Get->short_host_name();
my $directory = "/sys/class/net";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { directory => $directory }});
# We'll need to know what interfaces to remove, if any. This will store the interfaces we've seen and
# any others will be removed.
$anvil->data->{seen} = {
interface => {},
bond => {},
bridge => {},
ip => {},
};
# 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 $shell_call = $anvil->data->{path}{exe}{virsh}." net-list --all --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,
}});
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}{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}{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,
}});
}
}
}
# Walk through the sysfs files.
local(*DIRECTORY);
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, 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 $mac_address = -e $full_path."/address" ? $anvil->Storage->read_file({file => $full_path."/address"}) : "";
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 $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";
# If the NIC is a bond member, the MAC address could be virtual.
if (-e $full_path."/bonding_slave/perm_hwaddr")
{
$mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"});
}
# Clean up some newlines.
$mac_address =~ s/\n$//;
$link_state =~ s/\n$//;
$mtu =~ s/\n$//;
$duplex =~ s/\n$//;
$operational =~ s/\n$//;
$speed =~ s/\n$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
interface => $interface,
speed => $speed,
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";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ip_address => $ip_address,
subnet_mask => $subnet_mask,
type => $type,
}});
}
# 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 => 3, 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/)
{
### Set some fake values.
# Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary.
$speed = 1000 if ((not $speed) or ($speed eq "-1"));
$duplex = "full" if not $duplex;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, 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 => 3, 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")
{
# No, but it's slaved to one.
my $target = readlink($full_path."/master");
$bond_master = ($target =~ /^.*\/(.*)$/)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, 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 => 3, list => { bridge_stp_enabled => $bridge_stp_enabled }});
}
$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 ""))
{
die $THIS_FILE." ".__LINE__."; No speed for: [".$full_path."/speed]\n";
}
if ($speed =~ /\D/)
{
die $THIS_FILE." ".__LINE__."; Speed: [$speed] isn't numeric for: [".$full_path."/speed]\n";
}
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 => 3, 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 => 3, list => { line => $line }});
if ($line =~ /Supported ports: \[ (.*?) \]/i)
{
$media = lc($1);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { media => $media }});
last;
}
}
# Record this interface
$anvil->data->{seen}{$type}{$interface} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "seen::${type}::${interface}" => $anvil->data->{seen}{$type}{$interface} }});
# Record the IP, if set.
if ($ip_address)
{
$anvil->data->{seen}{ip}{$ip_address} = $interface;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "seen::ip::${ip_address}" => $anvil->data->{seen}{ip}{$ip_address} }});
}
# 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 => 3, 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 => 3, 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 => 3, 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});
delete $anvil->data->{interface_to_bridge} if exists $anvil->data->{interface_to_bridge};
foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{bridge}{$local_host}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bridge_name => $bridge_name }});
foreach my $interface_name (sort {$a cmp $b} @{$anvil->data->{bridge}{$local_host}{$bridge_name}{interfaces}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { interface_name => $interface_name }});
$anvil->data->{interface_to_bridge}{$interface_name} = $bridge_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"interface_to_bridge::${interface_name}" => $anvil->data->{interface_to_bridge}{$interface_name},
}});
}
}
# We need to record bridges first so we know their UUIDs when looking at bonds and interfaces that
# might be connected to them. Then we need to look at bonds so that their UUIDs are available when
# recording interfaces.
foreach my $processing ("bridge", "bond", "interface")
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { processing => $processing }});
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}})
{
# Skip if this isn't the device type we're working on.
next if not defined $anvil->data->{network}{$local_host}{interface}{$interface}{type};
my $type = $anvil->data->{network}{$local_host}{interface}{$interface}{type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:interface' => $interface,
's2:type' => $type,
's3:processing' => $processing,
}});
next if $processing ne $anvil->data->{network}{$local_host}{interface}{$interface}{type};
my $active_interface = $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface};
my $bond_mode = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode};
my $bond_master = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master};
my $bridge_id = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id};
my $bridge_stp_enabled = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled};
my $down_delay = $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay};
my $duplex = $anvil->data->{network}{$local_host}{interface}{$interface}{duplex};
my $ip_address = $anvil->data->{network}{$local_host}{interface}{$interface}{ip};
my $link_state = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state};
my $mac_address = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address};
my $media = $anvil->data->{network}{$local_host}{interface}{$interface}{media};
my $mii_polling_interval = $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval};
my $mtu = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu};
my $operational = $anvil->data->{network}{$local_host}{interface}{$interface}{operational};
my $primary_reselect = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect};
my $primary_interface = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface};
my $speed = $anvil->data->{network}{$local_host}{interface}{$interface}{speed};
my $subnet_mask = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask};
my $up_delay = $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay};
my $default_gateway = $anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway};
my $gateway = $anvil->data->{network}{$local_host}{interface}{$interface}{gateway};
my $dns = $anvil->data->{network}{$local_host}{interface}{$interface}{dns};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
active_interface => $active_interface,
bond_mode => $bond_mode,
bond_master => $bond_master,
default_gateway => $default_gateway,
down_delay => $down_delay,
dns => $dns,
duplex => $duplex,
gateway => $gateway,
interface => $interface,
ip_address => $ip_address,
link_state => $link_state,
mac_address => $mac_address,
media => $media,
mii_polling_interval => $mii_polling_interval,
mtu => $mtu,
operational => $operational,
primary_reselect => $primary_reselect,
primary_interface => $primary_interface,
speed => $speed,
subnet_mask => $subnet_mask,
up_delay => $up_delay,
}});
if (($type eq $processing) && ($type eq "bridge"))
{
if ($anvil->data->{sys}{database}{connections})
{
my $bridge_uuid = $anvil->Database->insert_or_update_bridges({
debug => 3,
file => $THIS_FILE,
line => __LINE__,
bridge_name => $interface,
bridge_id => $bridge_id,
bridge_mac_address => $mac_address,
bridge_mtu => $mtu,
bridge_stp_enabled => $bridge_stp_enabled,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }});
$anvil->data->{bridge_by_name}{$interface} = $bridge_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bridge_by_name::${interface}" => $anvil->data->{bridge_by_name}{$interface} }});
if (($bridge_uuid) && ($ip_address))
{
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
ip_address_on_type => $type,
ip_address_on_uuid => $bridge_uuid,
ip_address_address => $ip_address,
ip_address_subnet_mask => $subnet_mask,
ip_address_gateway => $gateway,
ip_address_default_gateway => $default_gateway,
ip_address_dns => $dns,
ip_address_note => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address_uuid => $ip_address_uuid }});
}
}
}
if (($type eq $processing) && ($type eq "bond"))
{
# Is this bond connected to a bridge?
my $bond_bridge_uuid = "";
my $bond_on_bridge = exists $anvil->data->{interface_to_bridge}{$interface} ? $anvil->data->{interface_to_bridge}{$interface} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_on_bridge => $bond_on_bridge }});
if ($bond_on_bridge)
{
$bond_bridge_uuid = $anvil->data->{bridge_by_name}{$bond_on_bridge};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_bridge_uuid => $bond_bridge_uuid }});
}
if ($anvil->data->{sys}{database}{connections})
{
my $bond_uuid = $anvil->Database->insert_or_update_bonds({
debug => 3,
file => $THIS_FILE,
line => __LINE__,
bond_name => $interface,
bond_mode => $bond_mode,
bond_mtu => $mtu,
bond_link_state => $link_state,
bond_operational => $operational,
bond_mac_address => $mac_address,
bond_primary_interface => $primary_interface,
bond_primary_reselect => $primary_reselect,
bond_active_interface => $active_interface,
bond_mii_polling_interval => $mii_polling_interval,
bond_up_delay => $up_delay,
bond_down_delay => $down_delay,
bond_bridge_uuid => $bond_bridge_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_uuid => $bond_uuid }});
$anvil->data->{bond_by_name}{$interface} = $bond_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "bond_by_name::${interface}" => $anvil->data->{bond_by_name}{$interface} }});
if (($bond_uuid) && ($ip_address))
{
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
ip_address_on_type => $type,
ip_address_on_uuid => $bond_uuid,
ip_address_address => $ip_address,
ip_address_subnet_mask => $subnet_mask,
ip_address_gateway => $gateway,
ip_address_default_gateway => $default_gateway,
ip_address_dns => $dns,
ip_address_note => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address_uuid => $ip_address_uuid }});
}
}
}
if (($type eq $processing) && ($type eq "interface"))
{
# Is this interface connected to a bridge?
my $network_interface_bridge_uuid = "";
my $network_interface_on_bridge = exists $anvil->data->{interface_to_bridge}{$interface} ? $anvil->data->{interface_to_bridge}{$interface} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_on_bridge => $network_interface_on_bridge }});
if ($network_interface_on_bridge)
{
$network_interface_bridge_uuid = $anvil->data->{bridge_by_name}{$network_interface_on_bridge};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_bridge_uuid => $network_interface_bridge_uuid }});
}
my $say_bond_uuid = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_master => $bond_master }});
if (($bond_master) && ($anvil->data->{bond_by_name}{$bond_master}))
{
$say_bond_uuid = $anvil->data->{bond_by_name}{$bond_master};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"bond_by_name::${bond_master}" => $anvil->data->{bond_by_name}{$bond_master},
say_bond_uuid => $say_bond_uuid,
}});
}
if ($anvil->data->{sys}{database}{connections})
{
my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
network_interface_bond_uuid => $say_bond_uuid,
network_interface_bridge_uuid => $network_interface_bridge_uuid,
network_interface_name => $interface,
network_interface_duplex => $duplex,
network_interface_link_state => $link_state,
network_interface_operational => $operational,
network_interface_mac_address => $mac_address,
network_interface_medium => $media,
network_interface_mtu => $mtu,
network_interface_speed => $speed,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
$anvil->data->{interface_by_name}{$interface} = $network_interface_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface_by_name::${interface}" => $anvil->data->{interface_by_name}{$interface} }});
if (($network_interface_uuid) && ($ip_address))
{
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
ip_address_on_type => $type,
ip_address_on_uuid => $network_interface_uuid,
ip_address_address => $ip_address,
ip_address_subnet_mask => $subnet_mask,
ip_address_gateway => $gateway,
ip_address_default_gateway => $default_gateway,
ip_address_dns => $dns,
ip_address_note => "",
});
}
}
}
}
}
if (not $anvil->data->{sys}{database}{connections})
{
return(0);
}
# I need to read back in the interface and bridge data and splice it together before I write out the
# XML and JSON files.
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
FROM
bonds
WHERE
bond_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})."
AND
bond_mode != 'DELETED'
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $bond_uuid = $row->[0];
my $bond_name = $row->[1];
$anvil->data->{bonds}{$bond_uuid} = {
bond_name => $bond_name,
bond_mode => $row->[2],
bond_mtu => $row->[3],
bond_primary_interface => $row->[4],
bond_primary_reselect => $row->[5],
bond_active_interface => $row->[6],
bond_mii_polling_interval => $row->[7],
bond_up_delay => $row->[8],
bond_down_delay => $row->[9],
bond_mac_address => $row->[10],
bond_operational => $row->[11],
};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"bonds::${bond_uuid}::bond_name" => $anvil->data->{bonds}{$bond_uuid}{bond_name},
"bonds::${bond_uuid}::bond_mode" => $anvil->data->{bonds}{$bond_uuid}{bond_mode},
"bonds::${bond_uuid}::bond_mtu" => $anvil->data->{bonds}{$bond_uuid}{bond_mtu},
"bonds::${bond_uuid}::bond_primary_interface" => $anvil->data->{bonds}{$bond_uuid}{bond_primary_interface},
"bonds::${bond_uuid}::bond_primary_reselect" => $anvil->data->{bonds}{$bond_uuid}{bond_primary_reselect},
"bonds::${bond_uuid}::bond_active_interface" => $anvil->data->{bonds}{$bond_uuid}{bond_active_interface},
"bonds::${bond_uuid}::bond_mii_polling_interval" => $anvil->data->{bonds}{$bond_uuid}{bond_mii_polling_interval},
"bonds::${bond_uuid}::bond_up_delay" => $anvil->data->{bonds}{$bond_uuid}{bond_up_delay},
"bonds::${bond_uuid}::bond_down_delay" => $anvil->data->{bonds}{$bond_uuid}{bond_down_delay},
"bonds::${bond_uuid}::bond_mac_address" => $anvil->data->{bonds}{$bond_uuid}{bond_mac_address},
"bonds::${bond_uuid}::bond_operational" => $anvil->data->{bonds}{$bond_uuid}{bond_operational},
}});
# Make sure I've seen this interface in this scan and, if not, update this entry to remove it.
if ((not exists $anvil->data->{seen}{bond}{$bond_name}) or (not $anvil->data->{seen}{bond}{$bond_name}))
{
# Mark it as deleted.
my $query = "UPDATE bonds SET bond_mode = 'DELETED' WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
$anvil->Database->write({debug => 3, query => $query, source => $THIS_FILE, line => __LINE__});
# Remove it from the hash so we don't add it to the .json and .xml files.
delete $anvil->data->{bonds}{$bond_uuid};
}
}
$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->data->{sys}{host_uuid})."
AND
bridge_id != 'DELETED'
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, 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];
my $bridge_mtu = $row->[4];
my $bridge_stp_enabled = $row->[5];
$anvil->data->{bridges}{$bridge_uuid} = {
bridge_name => $bridge_name,
bridge_id => $bridge_id,
bridge_mac_address => $bridge_mac_address,
bridge_mtu => $bridge_mtu,
bridge_stp_enabled => $bridge_stp_enabled,
};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"bridges::${bridge_uuid}::bridge_name" => $anvil->data->{bridges}{$bridge_uuid}{bridge_name},
"bridges::${bridge_uuid}::bridge_id" => $anvil->data->{bridges}{$bridge_uuid}{bridge_id},
"bridges::${bridge_uuid}::bridge_mac_address" => $anvil->data->{bridges}{$bridge_uuid}{bridge_mac_address},
"bridges::${bridge_uuid}::bridge_mtu" => $anvil->data->{bridges}{$bridge_uuid}{bridge_mtu},
"bridges::${bridge_uuid}::bridge_stp_enabled" => $anvil->data->{bridges}{$bridge_uuid}{bridge_stp_enabled},
}});
# Make sure I've seen this interface in this scan and, if not, update this entry to remove it.
if ((not exists $anvil->data->{seen}{bridge}{$bridge_name}) or (not $anvil->data->{seen}{bridge}{$bridge_name}))
{
# Mark it as deleted.
my $query = "UPDATE bridges SET bridge_id = 'DELETED' WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";";
$anvil->Database->write({debug => 3, query => $query, source => $THIS_FILE, line => __LINE__});
# Remove it from the hash so we don't add it to the .json and .xml files.
delete $anvil->data->{bridges}{$bridge_uuid};
}
}
# Process interfaces
$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->data->{sys}{host_uuid})."
ORDER BY
modified_date DESC
;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, list => {
results => $results,
count => $count,
}});
# The order will track the order the interfaces were last modified, which is a way to determine when
# they came up.
my $network_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
$network_xml .= "<network>\n";
my $network_json = "{\"networks\":[\n";
my $order = 1;
foreach my $row (@{$results})
{
my $network_interface_uuid = $row->[0];
my $network_interface_name = $row->[2];
$anvil->data->{network_interfaces}{$network_interface_uuid} = {
network_interface_mac_address => $row->[1],
network_interface_name => $network_interface_name,
network_interface_speed => $row->[3],
network_interface_mtu => $row->[4],
network_interface_link_state => $row->[5],
network_interface_operational => $row->[6],
network_interface_duplex => $row->[7],
network_interface_medium => $row->[8],
network_interface_bond_uuid => defined $row->[9] ? $row->[9] : 'NULL',
network_interface_bridge_uuid => defined $row->[10] ? $row->[10] : 'NULL',
};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"network_interfaces::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address},
"network_interfaces::${network_interface_uuid}::network_interface_name" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name},
"network_interfaces::${network_interface_uuid}::network_interface_speed" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed},
"network_interfaces::${network_interface_uuid}::network_interface_mtu" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu},
"network_interfaces::${network_interface_uuid}::network_interface_link_state" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state},
"network_interfaces::${network_interface_uuid}::network_interface_operational" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational},
"network_interfaces::${network_interface_uuid}::network_interface_duplex" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex},
"network_interfaces::${network_interface_uuid}::network_interface_medium" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium},
"network_interfaces::${network_interface_uuid}::network_interface_bond_uuid" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bond_uuid},
"network_interfaces::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bridge_uuid},
order => $order,
}});
# Make sure I've seen this interface in this scan and, if not, update this entry to remove it.
if (not exists $anvil->data->{network}{$local_host}{interface}{$network_interface_name})
{
if ($anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational} ne "DELETED")
{
# Mark it as deleted.
my $query = "UPDATE network_interfaces SET network_interface_operational = 'DELETED' WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
}
# Remove it from the hash so we don't add it to the .json and .xml files.
delete $anvil->data->{interface}{$network_interface_uuid};
# Loop so we don't try to process any further.
next;
}
my $say_bond = "";
my $network_interface_bond_uuid = $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bond_uuid};
my $network_interface_bridge_uuid = $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bridge_uuid};
if (($network_interface_bond_uuid) && ($network_interface_bond_uuid ne 'NULL'))
{
$say_bond = $anvil->data->{bonds}{$network_interface_bond_uuid}{bond_name};
}
my $say_bridge = "";
if (($network_interface_bridge_uuid) && ($network_interface_bridge_uuid ne 'NULL'))
{
$say_bridge = $anvil->data->{bridges}{$network_interface_bridge_uuid}{bridge_name};
}
$network_json .= " { \"name\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name}."\", \"mac\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}."\", \"link\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state}."\", \"speed\":\"".$anvil->Convert->add_commas({number => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}})."\", \"mtu\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu}."\", \"duplex\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex}."\", \"state\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational}."\", \"media\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium}."\", \"bond\":\"".$say_bond."\", \"bridge\":\"".$say_bridge."\", \"order\":\"".$order."\" },\n";
$network_xml .= " <interface name=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name}."\" mac=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}."\" link=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state}."\" speed=\"".$anvil->Convert->add_commas({number => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}})."\" mtu=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu}."\" duplex=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex}."\" state=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational}."\" media=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium}."\" bond=\"".$say_bond."\" bridge=\"".$say_bridge."\" order=\"".$order."\" />\n";
$order++;
}
$network_json =~ s/,$//s;
$network_json .= "],\n";
$network_json .= "\"ips\":[\n";
# Now record the IPs.
$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 => 3, 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 => 3, 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_on_uuid = $row->[2];
my $ip_address_address = $row->[3];
my $ip_address_subnet_mask = $row->[4];
my $ip_address_gateway = $row->[5];
my $ip_address_default_gateway = $row->[6];
my $ip_address_dns = $row->[7];
my $ip_address_note = $row->[8];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ip_address_on_type => $ip_address_on_type,
ip_address_on_uuid => $ip_address_on_uuid,
ip_address_address => $ip_address_address,
ip_address_subnet_mask => $ip_address_subnet_mask,
ip_address_gateway => $ip_address_gateway,
ip_address_default_gateway => $ip_address_default_gateway,
ip_address_dns => $ip_address_dns,
ip_address_note => $ip_address_note,
}});
if ((not exists $anvil->data->{seen}{ip}{$ip_address_address}) or (not $anvil->data->{seen}{ip}{$ip_address_address}))
{
# This IP address no longer exists on this host, removing it.
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
'delete' => 1,
ip_address_uuid => $ip_address_uuid,
});
next;
}
my $say_on = "";
if ($ip_address_on_type eq "interface")
{
$say_on = $anvil->data->{network_interfaces}{$ip_address_on_uuid}{network_interface_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }});
}
elsif ($ip_address_on_type eq "bond")
{
$say_on = $anvil->data->{bonds}{$ip_address_on_uuid}{bond_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }});
}
elsif ($ip_address_on_type eq "bridge")
{
$say_on = $anvil->data->{bridges}{$ip_address_on_uuid}{bridge_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }});
}
$network_json .= " { \"address\":\"$ip_address_address\", \"on\":\"$say_on\", \"subnet_mask\":\"$ip_address_subnet_mask\", \"gateway\":\"$ip_address_gateway\", \"default_gateway\":\"$ip_address_default_gateway\", \"dns\":\"$ip_address_dns\" },\n";
$network_xml .= " <ip address=\"$ip_address_address\" on=\"$say_on\" subnet_mask=\"$ip_address_subnet_mask\" gateway=\"$ip_address_gateway\" default_gateway=\"$ip_address_default_gateway\" dns=\"$ip_address_dns\" />\n";
}
$network_json =~ s/,$//s;
$network_json .= "]}\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_json => $network_json }});
$network_xml .= "</network>\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_xml => $network_xml }});
# Write the JSON file, if we're a dashboard. Nodes and DR hosts don't have a WebUI, so they're not
# needed.
if ($anvil->Get->host_type eq "striker")
{
my $output_json = $anvil->data->{path}{directories}{html}."/status/network.json";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_json }});
$anvil->Storage->write_file({
backup => 0,
file => $output_json,
body => $network_json,
overwrite => 1,
mode => "0644",
user => "apache",
group => "apache"
});
# Write the XML file.
my $output_xml = $anvil->data->{path}{directories}{html}."/status/network.xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_xml }});
$anvil->Storage->write_file({
backup => 0,
file => $output_xml,
body => $network_xml,
overwrite => 1,
mode => "0644",
user => "apache",
group => "apache"
});
}
return(0);
}