2c23c6beba
* Added a 'test' parameter to Log->entry, Storage->make_directory and Words->key to help debug in places that Log->x may not be usable. * Converted many $anvil->Log->x calls to print if $test to help prevent recursive loops, but not all fixed yet. * Added the new 'host_keys' database table to the schema for a possible new feature of removing passwords in favour if machines adding peers' public keys to their authorized_hosts file. * Cleaned up the opening calls to $anvil->Tools->new() in most tools. * Cleaned up some variables in tools/anvil-update-states after reading their values from files (clean trailing newlines). Signed-off-by: Digimer <digimer@alteeve.ca>
773 lines
39 KiB
Perl
Executable File
773 lines
39 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
#
|
|
# This is the master daemon that manages all periodically run processes on Striker dashboards and Anvil!
|
|
# nodes.
|
|
#
|
|
#
|
|
use strict;
|
|
use warnings;
|
|
use Anvil::Tools;
|
|
|
|
# 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->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
|
|
|
|
$anvil->Database->connect;
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
|
|
if (not $anvil->data->{sys}{database}{connections})
|
|
{
|
|
# No databases, exit.
|
|
print $anvil->Words->string({key => "error_0003"})."\n";
|
|
$anvil->nice_exit({exit_code => 2});
|
|
}
|
|
|
|
update_network($anvil);
|
|
|
|
$anvil->nice_exit({exit_code => 0});
|
|
|
|
|
|
#############################################################################################################
|
|
# Functions #
|
|
#############################################################################################################
|
|
|
|
# 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. The results will be stored in:
|
|
$anvil->System->get_ips();
|
|
|
|
# We'll read through '/sys/class/net' looking for network interfaces.
|
|
# * 'sys::network::interface::<iface_name>::ip' - If an IP address is set
|
|
# * 'sys::network::interface::<iface_name>::subnet' - If an IP is set
|
|
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} = {
|
|
interfaces => {},
|
|
bonds => {},
|
|
bridges => {},
|
|
};
|
|
|
|
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";
|
|
next if $file =~ /virbr\d/;
|
|
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";
|
|
|
|
# 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_slave = "";
|
|
my $primary_reselect = "";
|
|
my $active_slave = "";
|
|
my $mii_polling_interval = "";
|
|
my $up_delay = "";
|
|
my $down_delay = "";
|
|
my $bond_master = "";
|
|
|
|
if (exists $anvil->data->{sys}{network}{interface}{$interface})
|
|
{
|
|
$ip_address = $anvil->data->{sys}{network}{interface}{$interface}{ip} ? $anvil->data->{sys}{network}{interface}{$interface}{ip} : "";
|
|
$subnet_mask = $anvil->data->{sys}{network}{interface}{$interface}{subnet} ? $anvil->data->{sys}{network}{interface}{$interface}{subnet} : "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
ip_address => $ip_address,
|
|
subnet_mask => $subnet_mask,
|
|
}});
|
|
}
|
|
|
|
# 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});
|
|
$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/)
|
|
{
|
|
### Set some fake values.
|
|
# Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary.
|
|
$speed = 100000 if ((not $speed) or ($speed eq "-1"));
|
|
$duplex = "full" if not $duplex;
|
|
$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"});
|
|
$bond_mode =~ s/\s.*//;
|
|
$primary_slave = $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"});
|
|
$primary_reselect =~ s/\s.*//;
|
|
$active_slave = $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"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
active_slave => $active_slave,
|
|
bond_mode => $bond_mode,
|
|
mii_polling_interval => $mii_polling_interval,
|
|
primary_reselect => $primary_reselect,
|
|
primary_slave => $primary_slave,
|
|
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 => 2, list => {
|
|
target => $target,
|
|
bond_master => $bond_master,
|
|
}});
|
|
}
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
active_slave => $active_slave,
|
|
bond_master => $bond_master,
|
|
bond_mode => $bond_mode,
|
|
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_slave => $primary_slave,
|
|
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 $shell_call = $anvil->data->{path}{exe}{ethtool}." $interface";
|
|
my $ethtool = $anvil->System->call({shell_call => $shell_call});
|
|
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} }});
|
|
|
|
# Log
|
|
$anvil->data->{network}{interfaces}{by_name}{$interface} = {
|
|
active_slave => $active_slave,
|
|
bond_mode => $bond_mode,
|
|
bond_master => $bond_master,
|
|
down_delay => $down_delay,
|
|
duplex => $duplex,
|
|
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_slave => $primary_slave,
|
|
speed => $speed,
|
|
subnet_mask => $subnet_mask,
|
|
type => $type,
|
|
up_delay => $up_delay,
|
|
};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
|
|
"network::interfaces::by_name::${interface}::active_slave" => $anvil->data->{network}{interfaces}{by_name}{$interface}{active_slave},
|
|
"network::interfaces::by_name::${interface}::bond_mode" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode},
|
|
"network::interfaces::by_name::${interface}::bond_master" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_master},
|
|
"network::interfaces::by_name::${interface}::down_delay" => $anvil->data->{network}{interfaces}{by_name}{$interface}{down_delay},
|
|
"network::interfaces::by_name::${interface}::duplex" => $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex},
|
|
"network::interfaces::by_name::${interface}::ip_address" => $anvil->data->{network}{interfaces}{by_name}{$interface}{ip_address},
|
|
"network::interfaces::by_name::${interface}::link_state" => $anvil->data->{network}{interfaces}{by_name}{$interface}{link_state},
|
|
"network::interfaces::by_name::${interface}::mac_address" => $anvil->data->{network}{interfaces}{by_name}{$interface}{mac_address},
|
|
"network::interfaces::by_name::${interface}::media" => $anvil->data->{network}{interfaces}{by_name}{$interface}{media},
|
|
"network::interfaces::by_name::${interface}::mii_polling_interval" => $anvil->data->{network}{interfaces}{by_name}{$interface}{mii_polling_interval},
|
|
"network::interfaces::by_name::${interface}::mtu" => $anvil->data->{network}{interfaces}{by_name}{$interface}{mtu},
|
|
"network::interfaces::by_name::${interface}::operational" => $anvil->data->{network}{interfaces}{by_name}{$interface}{operational},
|
|
"network::interfaces::by_name::${interface}::primary_reselect" => $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_reselect},
|
|
"network::interfaces::by_name::${interface}::primary_slave" => $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_slave},
|
|
"network::interfaces::by_name::${interface}::speed" => $anvil->data->{network}{interfaces}{by_name}{$interface}{speed},
|
|
"network::interfaces::by_name::${interface}::subnet_mask" => $anvil->data->{network}{interfaces}{by_name}{$interface}{subnet_mask},
|
|
"network::interfaces::by_name::${interface}::type" => $anvil->data->{network}{interfaces}{by_name}{$interface}{type},
|
|
"network::interfaces::by_name::${interface}::up_delay" => $anvil->data->{network}{interfaces}{by_name}{$interface}{up_delay},
|
|
}});
|
|
}
|
|
}
|
|
closedir(DIRECTORY);
|
|
|
|
# We need to record bonds first so that their UUIDs are available when recording interfaces.
|
|
foreach my $processing ("bond", "interface")
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { processing => $processing }});
|
|
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{interfaces}{by_name}})
|
|
{
|
|
my $active_slave = $anvil->data->{network}{interfaces}{by_name}{$interface}{active_slave};
|
|
my $bond_mode = $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode};
|
|
my $bond_master = $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_master};
|
|
my $down_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{down_delay};
|
|
my $duplex = $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex};
|
|
my $ip_address = $anvil->data->{network}{interfaces}{by_name}{$interface}{ip_address};
|
|
my $link_state = $anvil->data->{network}{interfaces}{by_name}{$interface}{link_state};
|
|
my $mac_address = $anvil->data->{network}{interfaces}{by_name}{$interface}{mac_address};
|
|
my $media = $anvil->data->{network}{interfaces}{by_name}{$interface}{media};
|
|
my $mii_polling_interval = $anvil->data->{network}{interfaces}{by_name}{$interface}{mii_polling_interval};
|
|
my $mtu = $anvil->data->{network}{interfaces}{by_name}{$interface}{mtu};
|
|
my $operational = $anvil->data->{network}{interfaces}{by_name}{$interface}{operational};
|
|
my $primary_reselect = $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_reselect};
|
|
my $primary_slave = $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_slave};
|
|
my $speed = $anvil->data->{network}{interfaces}{by_name}{$interface}{speed};
|
|
my $subnet_mask = $anvil->data->{network}{interfaces}{by_name}{$interface}{subnet_mask};
|
|
my $type = $anvil->data->{network}{interfaces}{by_name}{$interface}{type};
|
|
my $up_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{up_delay};
|
|
my $default_gateway = $anvil->data->{sys}{network}{interface}{$interface}{default_gateway};
|
|
my $gateway = $anvil->data->{sys}{network}{interface}{$interface}{gateway};
|
|
my $dns = $anvil->data->{sys}{network}{interface}{$interface}{dns};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
|
|
active_slave => $active_slave,
|
|
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_slave => $primary_slave,
|
|
speed => $speed,
|
|
subnet_mask => $subnet_mask,
|
|
type => $type,
|
|
up_delay => $up_delay,
|
|
}});
|
|
|
|
if (($type eq $processing) && ($type eq "bond"))
|
|
{
|
|
my $bond_uuid = $anvil->Database->insert_or_update_bonds({
|
|
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_slave => $primary_slave,
|
|
bond_primary_reselect => $primary_reselect,
|
|
bond_active_slave => $active_slave,
|
|
bond_mii_polling_interval => $mii_polling_interval,
|
|
bond_up_delay => $up_delay,
|
|
bond_down_delay => $down_delay,
|
|
});
|
|
$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} }});
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_uuid => $bond_uuid }});
|
|
if (($bond_uuid) && ($ip_address))
|
|
{
|
|
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (($type eq $processing) && ($type eq "interface"))
|
|
{
|
|
my $say_bond_uuid = "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, list => {
|
|
"bond_by_name::${bond_master}" => $anvil->data->{bond_by_name}{$bond_master},
|
|
say_bond_uuid => $say_bond_uuid,
|
|
}});
|
|
}
|
|
my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
|
|
file => $THIS_FILE,
|
|
line => __LINE__,
|
|
network_interface_bond_uuid => $say_bond_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->data->{interface_by_name}{$interface} = $network_interface_uuid;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "interface_by_name::${interface}" => $anvil->data->{interface_by_name}{$interface} }});
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }});
|
|
if (($network_interface_uuid) && ($ip_address))
|
|
{
|
|
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
|
|
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,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# 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_slave,
|
|
bond_primary_reselect,
|
|
bond_active_slave,
|
|
bond_mii_polling_interval,
|
|
bond_up_delay,
|
|
bond_down_delay,
|
|
bond_mac_address,
|
|
bond_operational
|
|
FROM
|
|
bonds
|
|
WHERE
|
|
bond_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->Get->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_slave => $row->[4],
|
|
bond_primary_reselect => $row->[5],
|
|
bond_active_slave => $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_slave" => $anvil->data->{bonds}{$bond_uuid}{bond_primary_slave},
|
|
"bonds::${bond_uuid}::bond_primary_reselect" => $anvil->data->{bonds}{$bond_uuid}{bond_primary_reselect},
|
|
"bonds::${bond_uuid}::bond_active_slave" => $anvil->data->{bonds}{$bond_uuid}{bond_active_slave},
|
|
"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->data->{sys}{database}{use_handle}->quote($bond_uuid).";";
|
|
$anvil->Database->write({debug => 2, 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_stp_enabled
|
|
FROM
|
|
bridges
|
|
WHERE
|
|
bridge_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->Get->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];
|
|
$anvil->data->{bridges}{$bridge_uuid} = {
|
|
bridge_name => $bridge_name,
|
|
bridge_id => $row->[2],
|
|
bridge_stp_enabled => $row->[3],
|
|
};
|
|
$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_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->data->{sys}{database}{use_handle}->quote($bridge_uuid).";";
|
|
$anvil->Database->write({debug => 2, 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};
|
|
}
|
|
}
|
|
|
|
$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->data->{sys}{database}{use_handle}->quote($anvil->Get->host_uuid)."
|
|
AND
|
|
network_interface_operational != 'DELETED'
|
|
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->{seen}{interface}{$network_interface_name}) or (not $anvil->data->{seen}{interface}{$network_interface_name}))
|
|
{
|
|
# Mark it as deleted.
|
|
my $query = "UPDATE network_interfaces SET network_interface_operational = 'DELETED' WHERE network_interface_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($network_interface_uuid).";";
|
|
$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->{interfaces}{$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
|
|
FROM
|
|
ip_addresses
|
|
WHERE
|
|
ip_address_host_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($anvil->Get->host_uuid)."
|
|
AND
|
|
ip_address_on_type != '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 $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];
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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,
|
|
}});
|
|
|
|
# Did we see this IP on this scan? If not, set on_type to DELETEd.
|
|
my $found = 0;
|
|
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}})
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
|
|
interface => $interface,
|
|
ip_address_address => $ip_address_address,
|
|
"sys::network::interface::${interface}::ip" => $anvil->data->{sys}{network}{interface}{$interface}{ip},
|
|
}});
|
|
if ((defined $anvil->data->{sys}{network}{interface}{$interface}{ip}) && ($anvil->data->{sys}{network}{interface}{$interface}{ip} eq $ip_address_address))
|
|
{
|
|
$found = 1;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }});
|
|
last;
|
|
}
|
|
}
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }});
|
|
if ($found)
|
|
{
|
|
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\":\"$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=\"$ip_address_subnet_mask\" gateway=\"$ip_address_gateway\" default_gateway=\"$ip_address_default_gateway\" dns=\"$ip_address_dns\" />\n";
|
|
}
|
|
else
|
|
{
|
|
# Stale, mark it as deleted.
|
|
my $query = "UPDATE ip_addresses SET ip_address_on_type = 'DELETED' WHERE ip_address_uuid = ".$anvil->data->{sys}{database}{use_handle}->quote($ip_address_uuid).";";
|
|
$anvil->Database->write({debug => 2, query => $query, source => $THIS_FILE, line => __LINE__});
|
|
}
|
|
}
|
|
|
|
$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.
|
|
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({
|
|
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({
|
|
file => $output_xml,
|
|
body => $network_xml,
|
|
overwrite => 1,
|
|
mode => "0644",
|
|
user => "apache",
|
|
group => "apache"
|
|
});
|
|
|
|
return(0);
|
|
}
|