#!/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"});
	
	# 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({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        => {},
	};
	
	# 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_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 => 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  = 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 => 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_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->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_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 => 3, 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 => 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({
							debug                      => 3,
							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                      => 3,
							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 => 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({
							debug                      => 3,
							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 => 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->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);
}
