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.
 
 
 
 
 
 

1020 lines
51 KiB

#!/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->Log->level({set => 2});
$anvil->Log->secure({set => 0});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 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"});
# Generate our own time stamp
$anvil->data->{sys}{database}{timestamp} = $anvil->Get->date_and_time({use_utc => 1});
$anvil->data->{sys}{database}{timestamp} =~ s/\//-/g;
}
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({cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}});
foreach my $line (split/\n/, $body)
{
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 => 2, 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({debug => 3});
# We'll read through '/sys/class/net' looking for network interfaces.
# * 'network::local::interface::<iface_name>::ip' - If an IP address is set
# * 'network::local::interface::<iface_name>::subnet_mask' - 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} = {
interface => {},
bond => {},
bridge => {},
ip => {},
};
# 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 => 3, 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'}{interface}{$interface})
{
$ip_address = defined $anvil->data->{network}{'local'}{interface}{$interface}{ip} ? $anvil->data->{network}{'local'}{interface}{$interface}{ip} : "";
$subnet_mask = defined $anvil->data->{network}{'local'}{interface}{$interface}{subnet_mask} ? $anvil->data->{network}{'local'}{interface}{$interface}{subnet_mask} : "";
$type = defined $anvil->data->{network}{'local'}{interface}{$interface}{type} ? $anvil->data->{network}{'local'}{interface}{$interface}{type} : "interface";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 = 100000 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$//;
$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 => 3, 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 => 3, list => { "seen::ip::${ip_address}" => $anvil->data->{seen}{ip}{$ip_address} }});
}
# Store new information we found.
$anvil->data->{network}{'local'}{interface}{$interface}{active_interface} = $active_interface;
$anvil->data->{network}{'local'}{interface}{$interface}{bond_mode} = $bond_mode;
$anvil->data->{network}{'local'}{interface}{$interface}{bond_master} = $bond_master;
$anvil->data->{network}{'local'}{interface}{$interface}{bridge_id} = $bridge_id;
$anvil->data->{network}{'local'}{interface}{$interface}{bridge_stp_enabled} = $bridge_stp_enabled;
$anvil->data->{network}{'local'}{interface}{$interface}{down_delay} = $down_delay;
$anvil->data->{network}{'local'}{interface}{$interface}{duplex} = $duplex;
$anvil->data->{network}{'local'}{interface}{$interface}{ip} = $ip_address;
$anvil->data->{network}{'local'}{interface}{$interface}{link_state} = $link_state;
$anvil->data->{network}{'local'}{interface}{$interface}{mac_address} = $mac_address;
$anvil->data->{network}{'local'}{interface}{$interface}{media} = $media;
$anvil->data->{network}{'local'}{interface}{$interface}{mii_polling_interval} = $mii_polling_interval;
$anvil->data->{network}{'local'}{interface}{$interface}{mtu} = $mtu;
$anvil->data->{network}{'local'}{interface}{$interface}{operational} = $operational;
$anvil->data->{network}{'local'}{interface}{$interface}{primary_reselect} = $primary_reselect;
$anvil->data->{network}{'local'}{interface}{$interface}{primary_interface} = $primary_interface;
$anvil->data->{network}{'local'}{interface}{$interface}{speed} = $speed;
$anvil->data->{network}{'local'}{interface}{$interface}{subnet_mask} = $subnet_mask;
$anvil->data->{network}{'local'}{interface}{$interface}{type} = $type;
$anvil->data->{network}{'local'}{interface}{$interface}{up_delay} = $up_delay;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"network::local::interface::${interface}::active_interface" => $anvil->data->{network}{'local'}{interface}{$interface}{active_interface},
"network::local::interface::${interface}::bond_mode" => $anvil->data->{network}{'local'}{interface}{$interface}{bond_mode},
"network::local::interface::${interface}::bond_master" => $anvil->data->{network}{'local'}{interface}{$interface}{bond_master},
"network::local::interface::${interface}::bridge_id" => $anvil->data->{network}{'local'}{interface}{$interface}{bridge_id},
"network::local::interface::${interface}::bridge_stp_enabled" => $anvil->data->{network}{'local'}{interface}{$interface}{bridge_stp_enabled},
"network::local::interface::${interface}::down_delay" => $anvil->data->{network}{'local'}{interface}{$interface}{down_delay},
"network::local::interface::${interface}::duplex" => $anvil->data->{network}{'local'}{interface}{$interface}{duplex},
"network::local::interface::${interface}::ip" => $anvil->data->{network}{'local'}{interface}{$interface}{ip},
"network::local::interface::${interface}::link_state" => $anvil->data->{network}{'local'}{interface}{$interface}{link_state},
"network::local::interface::${interface}::mac_address" => $anvil->data->{network}{'local'}{interface}{$interface}{mac_address},
"network::local::interface::${interface}::media" => $anvil->data->{network}{'local'}{interface}{$interface}{media},
"network::local::interface::${interface}::mii_polling_interval" => $anvil->data->{network}{'local'}{interface}{$interface}{mii_polling_interval},
"network::local::interface::${interface}::mtu" => $anvil->data->{network}{'local'}{interface}{$interface}{mtu},
"network::local::interface::${interface}::operational" => $anvil->data->{network}{'local'}{interface}{$interface}{operational},
"network::local::interface::${interface}::primary_reselect" => $anvil->data->{network}{'local'}{interface}{$interface}{primary_reselect},
"network::local::interface::${interface}::primary_interface" => $anvil->data->{network}{'local'}{interface}{$interface}{primary_interface},
"network::local::interface::${interface}::speed" => $anvil->data->{network}{'local'}{interface}{$interface}{speed},
"network::local::interface::${interface}::subnet_mask" => $anvil->data->{network}{'local'}{interface}{$interface}{subnet_mask},
"network::local::interface::${interface}::type" => $anvil->data->{network}{'local'}{interface}{$interface}{type},
"network::local::interface::${interface}::up_delay" => $anvil->data->{network}{'local'}{interface}{$interface}{up_delay},
}});
# 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->data->{sys}{database}{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 => 3});
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'}})
{
$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'}{$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 => 3, list => { processing => $processing }});
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}})
{
# Skip if this isn't the device type we're working on.
next if not defined $anvil->data->{network}{'local'}{interface}{$interface}{type};
my $type = $anvil->data->{network}{'local'}{interface}{$interface}{type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:interface' => $interface,
's2:type' => $type,
's3:processing' => $processing,
}});
next if $processing ne $anvil->data->{network}{'local'}{interface}{$interface}{type};
my $active_interface = $anvil->data->{network}{'local'}{interface}{$interface}{active_interface};
my $bond_mode = $anvil->data->{network}{'local'}{interface}{$interface}{bond_mode};
my $bond_master = $anvil->data->{network}{'local'}{interface}{$interface}{bond_master};
my $bridge_id = $anvil->data->{network}{'local'}{interface}{$interface}{bridge_id};
my $bridge_stp_enabled = $anvil->data->{network}{'local'}{interface}{$interface}{bridge_stp_enabled};
my $down_delay = $anvil->data->{network}{'local'}{interface}{$interface}{down_delay};
my $duplex = $anvil->data->{network}{'local'}{interface}{$interface}{duplex};
my $ip_address = $anvil->data->{network}{'local'}{interface}{$interface}{ip};
my $link_state = $anvil->data->{network}{'local'}{interface}{$interface}{link_state};
my $mac_address = $anvil->data->{network}{'local'}{interface}{$interface}{mac_address};
my $media = $anvil->data->{network}{'local'}{interface}{$interface}{media};
my $mii_polling_interval = $anvil->data->{network}{'local'}{interface}{$interface}{mii_polling_interval};
my $mtu = $anvil->data->{network}{'local'}{interface}{$interface}{mtu};
my $operational = $anvil->data->{network}{'local'}{interface}{$interface}{operational};
my $primary_reselect = $anvil->data->{network}{'local'}{interface}{$interface}{primary_reselect};
my $primary_interface = $anvil->data->{network}{'local'}{interface}{$interface}{primary_interface};
my $speed = $anvil->data->{network}{'local'}{interface}{$interface}{speed};
my $subnet_mask = $anvil->data->{network}{'local'}{interface}{$interface}{subnet_mask};
my $up_delay = $anvil->data->{network}{'local'}{interface}{$interface}{up_delay};
my $default_gateway = $anvil->data->{network}{'local'}{interface}{$interface}{default_gateway};
my $gateway = $anvil->data->{network}{'local'}{interface}{$interface}{gateway};
my $dns = $anvil->data->{network}{'local'}{interface}{$interface}{dns};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, list => { bridge_uuid => $bridge_uuid }});
$anvil->data->{bridge_by_name}{$interface} = $bridge_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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({
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 => "",
});
}
}
}
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({
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 => "",
});
}
}
}
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 => 3, 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 => 3, list => { network_interface_bridge_uuid => $network_interface_bridge_uuid }});
}
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,
}});
}
if ($anvil->data->{sys}{database}{connections})
{
my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
debug => 3,
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 => 3, 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 => 3, 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({
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'}{interface}{$network_interface_name})
{
# 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->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->{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 => 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,
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({
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->System->get_host_type eq "dashboard")
{
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);
}