#!/usr/bin/perl
# 
# This program will manage server networking; Adding NICs to bridges, removing NICs, and un/plugging virtual 
# network cables.
# 
# Exit codes;
# 0 = Normal exit.
# 1 = No database connection.
# 
# TODO: 
# 
# USAGE:
# - Add a new NIC 
#   - anvil-manage-server-n --server srv01-test -add --bridge ifn1_link1 --mac aa:bb:cc:11:22:33 --model e1000e 
# - Delete a NIC 
#   - anvil-manage-server-n --server srv01-test -remove --mac aa:bb:cc:11:22:33
# - Unplug a NIC's virtual network cable
#   - anvil-manage-server-n --server srv01-test -unplug --mac aa:bb:cc:11:22:33
# - Plug in a NIC's virtual network cable
#   - anvil-manage-server-n --server srv01-test -unplug --mac aa:bb:cc:11:22:33
# 

use strict;
use warnings;
use Anvil::Tools;
require POSIX;
use Term::Cap;
use Data::Dumper;
use Sys::Virt;

my $THIS_FILE           =  ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory   =  ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
	$running_directory =~ s/^\./$ENV{PWD}/;
}

# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;

my $anvil = Anvil::Tools->new();

# Read switches (target ([user@]host[:port]) and the file with the target's password.
$anvil->Get->switches({list => [
	"add", 
	"bridge", 
	"confirm", 
	"mac", 
	"model", 
	"plug", 
	"remove", 
	"server", 
	"unplug", 
	], man => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});

# These will be set once we process the 'server' switch.
$anvil->data->{switches}{server_uuid} = "" if not defined $anvil->data->{switches}{server_uuid};
$anvil->data->{switches}{server_name} = "" if not defined $anvil->data->{switches}{server_name};

# Connect to the database(s). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks
# is to setup the database server.
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
	# No databases, update the job, sleep for a bit and then exit. The daemon will pick it up and try 
	# again after we exit.
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0305"});
	sleep 10;
	$anvil->nice_exit({exit_code => 1});
}

if ($anvil->data->{switches}{'job-uuid'})
{
	load_job($anvil);
}

$anvil->Database->get_hosts({debug => 2});
$anvil->Database->get_anvils({debug => 2});
$anvil->Database->get_servers({debug => 2});
$anvil->Database->get_bridges({debug => 2});

if ($anvil->data->{switches}{server})
{
	$anvil->Get->server_from_switch({server => $anvil->data->{switches}{server}});
	
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:switches::server_name' => $anvil->data->{switches}{server_name},
		's2:switches::server_uuid' => $anvil->data->{switches}{server_uuid},
	}});
	
	if ((not $anvil->data->{switches}{server_name}) or ($anvil->data->{switches}{server_name} eq "!!error!!"))
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0017", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server => $anvil->data->{switches}{server}, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}

	my $server_uuid = $anvil->data->{switches}{server_uuid};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_uuid => $server_uuid }});
	
	$anvil->data->{switches}{anvil_uuid} = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		'switches::anvil_uuid' => $anvil->data->{switches}{anvil_uuid},
	}});
	
}
else
{
	$anvil->data->{switches}{server_name} = "";
	$anvil->data->{switches}{server_uuid} = "";
	$anvil->data->{switches}{anvil_uuid}  = "";
}

if ($anvil->data->{switches}{add})
{
	handle_add($anvil);
}
elsif ($anvil->data->{switches}{remove})
{
	handle_remove($anvil);
}
elsif (($anvil->data->{switches}{plug}) or ($anvil->data->{switches}{unplug}))
{
	handle_plug_unplug($anvil);
}
else
{
	show_networks($anvil);
}





$anvil->Job->update_progress({
	progress => 100,
	message  => "job_0281", 
});
$anvil->nice_exit({exit_code => 0});


#############################################################################################################
# Functions                                                                                                 #
#############################################################################################################

sub update_definition
{
	my ($anvil) = @_;
	
	my $host_name    = $anvil->Get->short_host_name();
	my $server_uuid  = $anvil->data->{switches}{server_uuid};
	my $server_name  = $anvil->data->{switches}{server_name};
	my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:host_name'    => $host_name, 
		's2:server_uuid'  => $server_uuid, 
		's3:server_name'  => $server_name, 
		's4:server_state' => $server_state, 
	}});
	
	# Give a couple seconds for the changes to settle, then dump the new config.
	sleep 2;
	my $say_inactive = $server_state eq "running" ? "" : "--inactive ";
	my $shell_call   = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." dumpxml ".$say_inactive.$server_name;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	my ($virsh_definition, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		virsh_definition => $virsh_definition, 
		return_code      => $return_code,
	}});
	if ($return_code)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0235", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				shell_call  => $shell_call, 
				return_code => $return_code, 
				output      => $virsh_definition, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	$anvil->Job->update_progress({
		progress   => 80,
		message    => "message_0137", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server => $anvil->data->{switches}{server_name}, 
		},
	});
	
	# Push the new version out.
	my $problem = $anvil->Server->update_definition({
		debug              => 2, 
		server             => $server_uuid,
		new_definition_xml => $virsh_definition, 
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
	if ($problem)
	{
		# Failed!
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0266", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server => $anvil->data->{switches}{server_name}, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	return(0);
}

sub undefine_if_shut_off
{
	my ($anvil) = @_;
	
	my $server_uuid  = $anvil->data->{switches}{server_uuid};
	my $server_name  = $anvil->data->{switches}{server_name};
	my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:server_uuid'  => $server_uuid, 
		's2:server_name'  => $server_name, 
		's3:server_state' => $server_state, 
	}});
	
	# If we defined the server, undefine it now.
	if ($server_state ne "running")
	{
		$anvil->Job->update_progress({
			progress   => 95,
			message    => "message_0140", 
			log_level  => 1, 
			'print'    => 1, 
			variables  => {
				server => $anvil->data->{switches}{server_name}, 
			},
		});
		
		# We don't care if the undefine fails, scan-server will remove it later if needed.
		my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." undefine ".$server_name;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		
		my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output, 
			return_code => $return_code,
		}});
	}
	
	return(0);
}

sub define_if_shut_off
{
	my ($anvil) = @_;
	
	my $host_name        = $anvil->Get->short_host_name();
	my $host_uuid        = $anvil->Get->host_uuid();
	my $server_uuid      = $anvil->data->{switches}{server_uuid};
	my $server_name      = $anvil->data->{switches}{server_name};
	my $server_state     = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
	my $server_host_name = $server_host_uuid ? $anvil->Get->host_name_from_uuid({host_uuid => $server_host_uuid}) : "";
	my $anvil_uuid       = $anvil->data->{switches}{anvil_uuid};
	my $anvil_name       = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
	my $node1_host_uuid  = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
	my $node2_host_uuid  = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
	my $definition_file  = $anvil->data->{path}{directories}{shared}{definitions}."/".$server_name.".xml";
	my $task             = $anvil->data->{switches}{add} ? "add" : "remove";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's01:host_name'        => $host_name, 
		's02:host_uuid'        => $host_uuid, 
		's03:server_uuid'      => $server_uuid, 
		's04:server_name'      => $server_name, 
		's05:server_state'     => $server_state, 
		's06:server_host_uuid' => $server_host_uuid, 
		's07:server_host_name' => $server_host_name, 
		's08:anvil_uuid'       => $anvil_uuid, 
		's09:anvil_name'       => $anvil_name, 
		's10:node1_host_uuid'  => $node1_host_uuid, 
		's11:node2_host_uuid'  => $node2_host_uuid, 
		's12:definition_file'  => $definition_file, 
		's13:task'             => $task, 
	}});
	
	if ($server_state eq "shut off")
	{
		# Stopped, we can update it from either subnode.
		if (($host_uuid ne $node1_host_uuid) && ($host_uuid ne $node2_host_uuid))
		{
			# Reassign the job to node 1
			$anvil->Job->update_progress({
				progress   => 99,
				message    => $task eq "add" ? "job_0138" : "job_0139", 
				job_status => "reassigned", 
				log_level  => 1, 
				'print'    => 1, 
				variables  => {
					server    => $anvil->data->{switches}{server_name}, 
					anvil     => $anvil_name, 
					host_name => $anvil->Get->host_name_from_uuid({host_uuid => $node1_host_uuid}), 
				},
			});
			
			my $job_uuid = reassign_job($anvil, $server_uuid, $server_host_uuid);
			$anvil->Job->update_progress({
				progress   => 100,
				message    => "job_0137", 
				log_level  => 1, 
				'print'    => 1, 
				variables  => {
					host_name => $server_host_name,
					job_uuid  => $job_uuid, 
				},
			});
			
			$anvil->nice_exit({exit_code => 0});
		}
		
		# Does the definition file exist?
		if (not -e $definition_file)
		{
			$anvil->Job->update_progress({
				progress   => 100,
				message    => "error_0221", 
				job_status => "failed", 
				log_level  => 1, 
				'print'    => 1, 
				priority   => "err",
				variables  => {
					server => $anvil->data->{switches}{server_name}, 
					file   => $definition_file, 
				},
			});
			$anvil->nice_exit({exit_code => 1});
		}
		
		# Tell the user we're defining the server
		$anvil->Job->update_progress({
			progress   => 50,
			message    => "message_0132", 
			log_level  => 1, 
			'print'    => 1, 
			variables  => {
				server => $anvil->data->{switches}{server_name}, 
				file   => $definition_file, 
			},
		});
		
		# Define the server so we can update using virsh.
		my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." define ".$definition_file;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		
		my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output, 
			return_code => $return_code,
		}});
		if ($return_code)
		{
			$anvil->Job->update_progress({
				progress   => 100,
				message    => "error_0231", 
				job_status => "failed", 
				log_level  => 1, 
				'print'    => 1, 
				priority   => "err",
				variables  => {
					server      => $anvil->data->{switches}{server_name}, 
					file        => $definition_file, 
					return_code => $return_code, 
					output      => $output, 
				},
			});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	return(0);
}

sub wait_if_migrating
{
	my ($anvil) = @_;
	
	my $host_name        = $anvil->Get->short_host_name();
	my $host_uuid        = $anvil->Get->host_uuid();
	my $server_uuid      = $anvil->data->{switches}{server_uuid};
	my $server_state     = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
	my $server_host_name = $server_host_uuid ? $anvil->Get->host_name_from_uuid({host_uuid => $server_host_uuid}) : "";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:host_name'        => $host_name, 
		's2:host_uuid'        => $host_uuid, 
		's3:server_uuid'      => $server_uuid, 
		's4:server_state'     => $server_state, 
		's5:server_host_uuid' => $server_host_uuid, 
		's6:server_host_name' => $server_host_name, 
	}});
	
	if ($server_state eq "migrating")
	{
		# Loop until it's not migrating.
		$anvil->Job->update_progress({
			progress  => 20,
			message   => "message_0114", 
			log_level => 1, 
			'print'   => 1, 
			variables => {
				server => $anvil->data->{switches}{server_name}, 
			},
		});
		
		while ($server_state eq "migrating")
		{
			sleep 5;
			$anvil->Database->get_servers({debug => 2});
			
			$server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_name => $server_state }});
			
			if ($server_state ne "migrating")
			{
				$anvil->Job->update_progress({
					progress  => 40,
					message   => "message_0131", 
					log_level => 1, 
					'print'   => 1, 
					variables => {
						server => $anvil->data->{switches}{server_name}, 
					},
				});
			}
		}
	}
	
	return(0);
}

sub handle_add
{
	my ($anvil) = @_;
	
	my $host_name   = $anvil->Get->short_host_name();
	my $server_name = $anvil->data->{switches}{server_name};
	my $server_uuid = $anvil->data->{switches}{server_uuid};
	my $anvil_uuid  = $anvil->data->{switches}{anvil_uuid};
	my $mac_address = $anvil->data->{switches}{mac};
	my $model       = $anvil->data->{switches}{model};
	my $bridge      = $anvil->data->{switches}{bridge};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:host_name'   => $host_name, 
		's2:server_name' => $server_name,
		's3:server_uuid' => $server_uuid, 
		's4:anvil_uuid'  => $anvil_uuid, 
		's5:mac_address' => $mac_address, 
		's6:model'       => $model, 
		's7:bridge'      => $bridge, 
	}});
	
	if (not $server_name)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0131", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	my $anvil_name      = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
	my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
	my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
	my $host_uuid       = $anvil->Get->host_uuid();
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:anvil_name'      => $anvil_name,
		's2:node1_host_uuid' => $node1_host_uuid, 
		's3:node2_host_uuid' => $node2_host_uuid, 
		's4:host_uuid'       => $host_uuid, 
	}});
	
	if (not $bridge)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0232", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables => {
				server => $anvil->data->{switches}{server_name}, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	if ((not exists $anvil->data->{bridges}{bridge_host_uuid}{$node1_host_uuid}{bridge_name}{$bridge}) or
	    (not exists $anvil->data->{bridges}{bridge_host_uuid}{$node2_host_uuid}{bridge_name}{$bridge}))
	{
		# Bridge isn't on both subnodes.
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0233", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables => {
				server => $anvil->data->{switches}{server_name}, 
				bridge => $bridge, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	my $server_state     = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
	my $server_host_name = $server_host_uuid ? $anvil->Get->host_name_from_uuid({host_uuid => $server_host_uuid}) : "";
	my $definition_file  = $anvil->data->{path}{directories}{shared}{definitions}."/".$server_name.".xml";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:server_name'      => $server_state,
		's2:server_host_uuid' => $server_host_uuid, 
		's3:server_host_name' => $server_host_name, 
		's4:definition_file'  => $definition_file, 
	}});
	
	# If the server is running, add the interface on the host. If it's shut off, we can do it from 
	# either machine on the host Anvil.
	wait_if_migrating($anvil);
	
	# If the server is running on another host, reassign it.
	if (($server_state eq "running") && ($server_host_uuid ne $anvil->Get->host_uuid))
	{
		# Reassign the add to the host.
		$anvil->Job->update_progress({
			progress   => 99,
			message    => "job_0143", 
			job_status => "reassigned", 
			log_level  => 1, 
			'print'    => 1, 
			variables  => {
				server    => $anvil->data->{switches}{server_name}, 
				host_name => $server_host_name, 
				host_uuid => $server_host_uuid, 
			},
		});
		
		my $job_uuid = reassign_job($anvil, $server_uuid, $server_host_uuid);
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "job_0137", 
			log_level  => 1, 
			'print'    => 1, 
			variables  => {
				host_name => $server_host_name,
				job_uuid  => $job_uuid, 
			},
		});
		$anvil->nice_exit({exit_code => 0});
	}
	
	# Define the server if the server is off.
	define_if_shut_off($anvil);
	
	# Do the call to add the interface.
	$anvil->Job->update_progress({
		progress   => 60,
		message    => "message_0133", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server => $anvil->data->{switches}{server_name}, 
		},
	});
	
	### TODO: How does virt-manager implement 'hypervisor default'?
	# The model is required. If the user didn't specify, match any existing NIC's model. If none are found, emulate e10000e
	if (not $model)
	{
		$anvil->Server->parse_definition({
			debug      => 3,
			host       => $host_name,
			server     => $server_name, 
			source     => "from_db",
			definition => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml}, 
		});
		foreach my $mac_address (sort {$a cmp $b} keys %{$anvil->data->{server}{$host_name}{$server_name}{from_db}{device}{interface}})
		{
			$model = $anvil->data->{server}{$host_name}{$server_name}{from_db}{device}{interface}{$mac_address}{model};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"s1:mac_address" => $mac_address, 
				"s2:model"       => $model, 
			}});
			last;
		}
	}
	if (not $model)
	{
		$model = "e1000e";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { model => $model }});
	}
	
	# If it's running, don't use '--persistent'
	my $say_persistent = $server_state eq "running" ? "" : "--persistent ";
	my $shell_call     = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." attach-interface ".$say_persistent.$server_name." bridge ".$bridge." --model ".$model;
	if ($mac_address)
	{
		$shell_call .= " --mac ".$mac_address;
	}
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	if ($return_code)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0234", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				bridge      => $bridge, 
				shell_call  => $shell_call, 
				return_code => $return_code, 
				output      => $output, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	$anvil->Job->update_progress({
		progress   => 70,
		message    => "message_0136", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server => $anvil->data->{switches}{server_name}, 
		},
	});
	
	# Update the definition around the cluster
	update_definition($anvil);
	
	# Undfine the server if the server is off.
	undefine_if_shut_off($anvil);
	
	# Done!
	$anvil->Job->update_progress({
		progress   => 100,
		message    => "message_0139", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server => $anvil->data->{switches}{server_name}, 
			model  => $model,
			bridge => $bridge, 
		},
	});
	$anvil->nice_exit({exit_code => 0});
	
	return(0);
}

sub handle_remove
{
	my ($anvil) = @_;
	
	my $host_name   = $anvil->Get->short_host_name();
	my $server_name = $anvil->data->{switches}{server_name};
	my $server_uuid = $anvil->data->{switches}{server_uuid};
	my $anvil_uuid  = $anvil->data->{switches}{anvil_uuid};
	my $mac_address = lc($anvil->data->{switches}{mac});
	my $model       = $anvil->data->{switches}{model};
	my $bridge      = $anvil->data->{switches}{bridge};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:host_name'   => $host_name, 
		's2:server_name' => $server_name,
		's3:server_uuid' => $server_uuid, 
		's4:anvil_uuid'  => $anvil_uuid, 
		's5:mac_address' => $mac_address, 
		's6:model'       => $model, 
		's7:bridge'      => $bridge, 
	}});
	
	if (not $server_name)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0278", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	my $anvil_name      = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
	my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
	my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
	my $host_uuid       = $anvil->Get->host_uuid();
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:anvil_name'      => $anvil_name,
		's2:node1_host_uuid' => $node1_host_uuid, 
		's3:node2_host_uuid' => $node2_host_uuid, 
		's4:host_uuid'       => $host_uuid, 
	}});
	
	if (not $mac_address)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0307", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables => {
				server => $anvil->data->{switches}{server_name}, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Get the XML
	my $server_definition_xml = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_definition_xml => $server_definition_xml }});
	
	# This could be delayed from what's actually happening, but we have to take the DB as the source of 
	# truth.
	my $problem = $anvil->Server->parse_definition({
		debug      => 2,
		host       => $host_name,
		server     => $server_name, 
		source     => "from_db",
		definition => $server_definition_xml, 
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
	
	# Make sure the MAC address is valid for this server.
	my $found = 0;
	foreach my $this_mac_address (sort {$a cmp $b} keys %{$anvil->data->{server}{$host_name}{$server_name}{from_db}{device}{interface}})
	{
		my $bridge = $anvil->data->{server}{$host_name}{$server_name}{from_db}{device}{interface}{$this_mac_address}{bridge};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"s1:this_mac_address" => $this_mac_address, 
			"s2:bridge"           => $bridge, 
		}});
		
		if ($this_mac_address eq $mac_address)
		{
			$found = 1;
			$anvil->Job->update_progress({
				progress   => 10,
				message    => "message_0141", 
				log_level  => 1, 
				'print'    => 1, 
				variables  => {
					server      => $anvil->data->{switches}{server_name}, 
					mac_address => $mac_address, 
					bridge      => $bridge, 
				},
			});
		}
	}
	if (not $found)
	{
		# Bad MAC.
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0314", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables => {
				server => $anvil->data->{switches}{server_name}, 
				mac    => $mac_address, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# If the server is running, add the interface on the host. If it's shut off, we can do it from 
	# either machine on the host Anvil.
	wait_if_migrating($anvil);
	
	# Define the server if the server is off.
	define_if_shut_off($anvil);
	
	# Do the call to add the interface.
	$anvil->Job->update_progress({
		progress   => 60,
		message    => "message_0133", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server => $anvil->data->{switches}{server_name}, 
		},
	});
	
	my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." detach-interface --persistent ".$server_name." bridge ".$mac_address;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	if ($return_code)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0315", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				mac         => $mac_address, 
				shell_call  => $shell_call, 
				return_code => $return_code, 
				output      => $output, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	$anvil->Job->update_progress({
		progress   => 70,
		message    => "message_0142", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server => $anvil->data->{switches}{server_name}, 
		},
	});
	
	# Update the definition around the cluster
	update_definition($anvil);
	
	# Undfine the server if the server is off.
	undefine_if_shut_off($anvil);
	
	# Done!
	$anvil->Job->update_progress({
		progress   => 100,
		message    => "message_0143", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server => $anvil->data->{switches}{server_name}, 
			mac    => $mac_address, 
		},
	});
	$anvil->nice_exit({exit_code => 0});
	return(0);
}

sub handle_plug_unplug
{
	my ($anvil) = @_;
	
	my $task         = $anvil->data->{switches}{plug} ? "plug" : "unplug";
	my $host_name    = $anvil->Get->short_host_name();
	my $server_name  = $anvil->data->{switches}{server_name};
	my $server_uuid  = $anvil->data->{switches}{server_uuid};
	my $anvil_uuid   = $anvil->data->{switches}{anvil_uuid};
	my $mac_address  = $anvil->data->{switches}{mac};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:tast'        => $task,
		's2:host_name'   => $host_name, 
		's3:server_name' => $server_name,
		's4:server_uuid' => $server_uuid, 
		's5:anvil_uuid'  => $anvil_uuid, 
		's6:mac_address' => $mac_address, 
	}});
	
	if (not $server_name)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => $task eq "plug" ? "error_0036" : "error_0018", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
		});
		$anvil->nice_exit({exit_code => 1});
	}
	if (not $mac_address)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => $task eq "plug" ? "error_0054" : "error_0019", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server => $anvil->data->{switches}{server_name}, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	my $server_state     = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
	my $server_host_name = $server_host_uuid ? $anvil->Get->host_name_from_uuid({host_uuid => $server_host_uuid}) : "";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:server_name'      => $server_state,
		's2:server_host_uuid' => $server_host_uuid, 
		's3:server_host_name' => $server_host_name, 
	}});
	
	# Is the server running?
	if ($server_state ne "running")
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => $task eq "plug" ? "error_0074" : "error_0020", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server       => $anvil->data->{switches}{server_name}, 
				server_state => $server_state, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Lastly, are we the host?
	if ($server_host_uuid ne $anvil->Get->host_uuid)
	{
		# No, reassign the job.
		$anvil->Job->update_progress({
			progress   => 99,
			message    => $task eq "plug" ? "message_0148" : "message_0147", 
			job_status => "reassigned", 
			log_level  => 1, 
			'print'    => 1, 
			variables  => {
				server    => $anvil->data->{switches}{server_name}, 
				host_name => $server_host_name, 
				host_uuid => $server_host_uuid, 
			},
		});
		
		my $job_uuid = reassign_job($anvil, $server_uuid, $server_host_uuid);
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "job_0137", 
			log_level  => 1, 
			'print'    => 1, 
			variables  => {
				host_name => $server_host_name,
				job_uuid  => $job_uuid, 
			},
		});
		$anvil->nice_exit({exit_code => 0});
	}
	
	# Get the XML
	my $server_definition_xml = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_definition_xml => $server_definition_xml }});
	
	# This could be delayed from what's actually happening, but we have to take the DB as the source of 
	# truth.
	my $problem = $anvil->Server->parse_definition({
		debug      => 2,
		host       => $host_name,
		server     => $server_name, 
		source     => "from_db",
		definition => $server_definition_xml, 
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
	
	if ($problem)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => $task eq "plug" ? "error_0078" : "error_0022", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server    => $anvil->data->{switches}{server_name}, 
				host_uuid => $server_host_uuid, 
				host_name => $server_host_name, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Do we know the MAC?
	if (not exists $anvil->data->{servers}{server_uuid}{$server_uuid}{mac_address}{$mac_address})
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => $task eq "plug" ? "error_0119" : "error_0118", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				mac_address => $mac_address, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Last, is the cable already in the requested state?
	my $vnet_device         = $anvil->data->{servers}{server_uuid}{$server_uuid}{mac_address}{$mac_address}{server_network_vnet_device};
	my $link_state          = $anvil->data->{servers}{server_uuid}{$server_uuid}{mac_address}{$mac_address}{server_network_link_state};
	my $server_network_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{mac_address}{$mac_address}{server_network_uuid}; 
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:vnet_device'         => $vnet_device,
		's2:link_state'          => $link_state, 
		's3:server_network_uuid' => $server_network_uuid, 
	}});
	
	if (not $vnet_device)
	{
		# Can't work without a vnet device
		$anvil->Job->update_progress({
			progress   => 100,
			message    => $task eq "plug" ? "error_0121" : "error_0120", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				mac_address => $mac_address, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	if (($task eq "plug") && ($link_state eq "up"))
	{
		# Already plugged in, nothing to do.
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "message_0108", 
			log_level  => 1, 
			'print'    => 1, 
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				mac_address => $mac_address, 
				vnet_device => $vnet_device, 
			},
		});
		$anvil->nice_exit({exit_code => 0});
	}
	if (($task eq "unplug") && ($link_state eq "down"))
	{
		# Already unplugged, nothing to do.
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "message_0109", 
			log_level  => 1, 
			'print'    => 1, 
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				mac_address => $mac_address, 
				vnet_device => $vnet_device, 
			},
		});
		$anvil->nice_exit({exit_code => 0});
	}
	
	# Still alive? Do the things.
	my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." domif-setlink ".$server_name." --interface ".$vnet_device." ";
	if ($task eq "plug")
	{
		$shell_call .= "up";
	}
	else
	{
		$shell_call .= "down";
	}
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	$anvil->Job->update_progress({
		progress   => 50,
		message    => $task eq "plug" ? "message_0112" : "message_0113", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server      => $anvil->data->{switches}{server_name}, 
			mac_address => $mac_address, 
			vnet_device => $vnet_device, 
		},
	});
	
	my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	if ($return_code)
	{
		$anvil->Job->update_progress({
			progress   => 100,
			message    => $task eq "plug" ? "error_0123" : "error_0122", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				shell_call  => $shell_call, 
				return_code => $return_code, 
				output      => $output, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Verify.
	sleep 2;
	$shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." domif-getlink ".$server_name." --interface ".$vnet_device." ";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		return_code => $return_code,
	}});
	
	if ($output =~ /^$vnet_device (.*)$/)
	{
		my $status = $1;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { status => $status }});
		
		if ($status eq "up")
		{
			if ($task eq "plug")
			{
				# Success! Update the database.
				$anvil->Job->update_progress({
					progress   => 90,
					message    => "message_0110", 
					log_level  => 1, 
					'print'    => 1, 
					variables  => {
						server      => $anvil->data->{switches}{server_name}, 
						mac_address => $mac_address, 
						vnet_device => $vnet_device, 
					},
				});
				
				# Update the database.
				$anvil->Database->insert_or_update_server_networks({
					debug                      => 2, 
					server_network_uuid        => $server_network_uuid, 
					server_network_server_uuid => $server_uuid, 
					server_network_mac_address => $mac_address, 
					server_network_vnet_device => $vnet_device, 
					server_network_link_state  => "up", 
				});
			}
			else
			{
				# Failed
				$anvil->Job->update_progress({
					progress   => 100,
					message    => "error_0124", 
					job_status => "failed", 
					log_level  => 1, 
					'print'    => 1, 
					priority   => "err",
					variables  => {
						server      => $anvil->data->{switches}{server_name}, 
						mac_address => $mac_address, 
						vnet_device => $vnet_device, 
					},
				});
				$anvil->nice_exit({exit_code => 1});
			}
		}
		elsif ($status eq "down")
		{
			if ($task eq "unplug")
			{
				# Success! Update the database.
				$anvil->Job->update_progress({
					progress   => 90,
					message    => "message_0111", 
					log_level  => 1, 
					'print'    => 1, 
					variables  => {
						server      => $anvil->data->{switches}{server_name}, 
						mac_address => $mac_address, 
						vnet_device => $vnet_device, 
					},
				});
				
				# Update the database.
				$anvil->Database->insert_or_update_server_networks({
					debug                      => 2, 
					server_network_uuid        => $server_network_uuid, 
					server_network_server_uuid => $server_uuid, 
					server_network_mac_address => $mac_address, 
					server_network_vnet_device => $vnet_device, 
					server_network_link_state  => "down", 
				});
			}
			else
			{
				# Failed
				$anvil->Job->update_progress({
					progress   => 100,
					message    => "error_0125", 
					job_status => "failed", 
					log_level  => 1, 
					'print'    => 1, 
					priority   => "err",
					variables  => {
						server      => $anvil->data->{switches}{server_name}, 
						mac_address => $mac_address, 
						vnet_device => $vnet_device, 
					},
				});
				$anvil->nice_exit({exit_code => 1});
			}
		}
		else
		{
			# Wat?
			$anvil->Job->update_progress({
				progress   => 100,
				message    => "error_0126", 
				job_status => "failed", 
				log_level  => 1, 
				'print'    => 1, 
				priority   => "err",
				variables  => {
					server      => $anvil->data->{switches}{server_name}, 
					mac_address => $mac_address, 
					vnet_device => $vnet_device, 
					status      => $status, 
				},
			});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	else
	{
		# Unexpected output.
		$anvil->Job->update_progress({
			progress   => 100,
			message    => "error_0130", 
			job_status => "failed", 
			log_level  => 1, 
			'print'    => 1, 
			priority   => "err",
			variables  => {
				server      => $anvil->data->{switches}{server_name}, 
				mac_address => $mac_address, 
				vnet_device => $vnet_device, 
				return_code => $return_code, 
				output      => $output, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Tell the user we're done.
	$anvil->Job->update_progress({
		progress   => 100,
		message    => "job_0281", 
		log_level  => 1, 
		'print'    => 1, 
		variables  => {
			server      => $anvil->data->{switches}{server_name}, 
			mac_address => $mac_address, 
			vnet_device => $vnet_device, 
		},
	});
	$anvil->nice_exit({exit_code => 0});
	
	return(0);
}

sub reassign_job
{
	my ($anvil, $server_uuid, $host_uuid) = @_;

	my $say_add    =  $anvil->data->{switches}{add}    ? "true" : "";
	my $say_plug   =  $anvil->data->{switches}{plug}   ? "true" : "";
	my $say_remove =  $anvil->data->{switches}{remove} ? "true" : ""; 
	my $say_unplug =  $anvil->data->{switches}{unplug} ? "true" : "";
	my $job_data   =  "add=".$say_add."\n";
	   $job_data   .= "bridge=".$anvil->data->{switches}{bridge}."\n"; 
	   $job_data   .= "confirm=true\n";
	   $job_data   .= "mac=".$anvil->data->{switches}{mac}."\n";
	   $job_data   .= "model=".$anvil->data->{switches}{model}."\n";
	   $job_data   .= "plug=".$say_plug."\n";
	   $job_data   .= "remove=".$say_remove."\n";
	   $job_data   .= "server=".$anvil->data->{switches}{server}."\n";
	   $job_data   .= "unplug=".$say_unplug;
	my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
		debug           => 2,
		job_command     => $anvil->data->{path}{exe}{$THIS_FILE}.$anvil->Log->switches,
		job_data        => $job_data, 
		job_host_uuid   => $host_uuid, 
		job_progress    => 0, 
		job_name        => "server::".$server_uuid."::set_interface_state", 
		job_title       => "job_0505", 
		job_description => "job_0506", 
	});

	return($job_uuid);
}

sub show_networks
{
	my ($anvil) = @_;
	
	my $host_name = $anvil->Get->short_host_name();
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
	foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
	{
		my $anvil_uuid        = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
		my $anvil_description = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description};
		my $node1_host_uuid   = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node1_host_uuid};
		my $node2_host_uuid   = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node2_host_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:host_name'         => $anvil_name,
			's2:anvil_uuid'        => $anvil_uuid, 
			's3:anvil_description' => $anvil_description, 
			's4:node1_host_uuid'   => $node1_host_uuid." (".$anvil->Get->host_name_from_uuid({host_uuid => $node1_host_uuid}).")", 
			's5:node2_host_uuid'   => $node2_host_uuid." (".$anvil->Get->host_name_from_uuid({host_uuid => $node2_host_uuid}).")", 
		}});
		next if (($anvil->data->{switches}{anvil_uuid}) && ($anvil->data->{switches}{anvil_uuid} ne $anvil_uuid));
		print "-=] Anvil! Node: [".$anvil_name."] - ".$anvil_description."\n";
		
		foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{bridges}{bridge_host_uuid}{$node1_host_uuid}{bridge_name}})
		{
			# Make sure this bridge is also on node 2.
			if (($node2_host_uuid) && (not $anvil->data->{bridges}{bridge_host_uuid}{$node2_host_uuid}{bridge_name}{$bridge_name}))
			{
				# Skip it.
				next;
			}
			print "- Bridge: [".$bridge_name."]\n";
		}
		print "\n-=] Servers on: [".$anvil_name."]\n";
		
		# Now show the servers on this Anvil! node and what interfaces they have.
		foreach my $server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}})
		{
			my $server_uuid           = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}{server_uuid};
			my $server_definition_xml = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:server_name'           => $server_name,
				's2:server_uuid'           => $server_uuid, 
				's3:server_definition_xml' => $server_definition_xml, 
			}});
			next if (($anvil->data->{switches}{server_uuid}) && ($server_uuid ne $anvil->data->{switches}{server_uuid}));
			
			# This could be delayed from what's actually happening, but we have to take the DB as
			# the source of truth.
			$anvil->Server->parse_definition({
				debug      => 2,
				host       => $host_name,
				server     => $server_name, 
				source     => "from_db",
				definition => $server_definition_xml, 
			});
			
			# Sort the interfaces by bridge
			foreach my $mac_address (sort {$a cmp $b} keys %{$anvil->data->{server}{$host_name}{$server_name}{from_db}{device}{interface}})
			{
				my $bridge = $anvil->data->{server}{$host_name}{$server_name}{from_db}{device}{interface}{$mac_address}{bridge};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"s1:mac_address" => $mac_address, 
					"s2:bridge"      => $bridge, 
				}});
				
				$anvil->data->{servers}{server_uuid}{$server_uuid}{bridges}{$bridge}{mac_address} = $mac_address;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"servers::server_uuid::${server_uuid}::bridges::${bridge}::mac_address" => $anvil->data->{servers}{server_uuid}{$server_uuid}{bridges}{$bridge}{mac_address}, 
				}});
			}
			
			print "Server: [".$server_name."], uuid: [".$server_uuid."], interfaces;\n";
			foreach my $bridge (sort {$a cmp $b} keys %{$anvil->data->{servers}{server_uuid}{$server_uuid}{bridges}})
			{
				my $mac_address      = $anvil->data->{servers}{server_uuid}{$server_uuid}{bridges}{$bridge}{mac_address};
				my $model            = $anvil->data->{server}{$host_name}{$server_name}{from_db}{device}{interface}{$mac_address}{model};
				my $ip_address       = $anvil->Network->get_ip_from_mac({mac => $mac_address});
				my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
				my $server_host_name = $server_host_uuid ? $anvil->Get->host_name_from_uuid({host_uuid => $server_host_uuid}) : "";
				my $server_state     = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
				my $vnet_device      = "--";
				my $link_state       = "down";
				if (($server_state ne "shut off") && ($server_state ne "DELETED"))
				{
					$vnet_device = $anvil->data->{servers}{server_uuid}{$server_uuid}{mac_address}{$mac_address}{server_network_vnet_device};
					$link_state  = $anvil->data->{servers}{server_uuid}{$server_uuid}{mac_address}{$mac_address}{server_network_link_state};
				}
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's01:bridge'           => $server_name,
					's02:mac_address'      => $mac_address, 
					's03:model'            => $model, 
					's04:link_state'       => $link_state, 
					's05:ip_address'       => $ip_address,
					's06:server_host_uuid' => $server_host_uuid, 
					's07:server_host_name' => $server_host_name, 
					's08:server_state'     => $server_state, 
					's09:vnet_device'      => $vnet_device, 
					's10:link_state'       => $link_state, 
				}});
				print "- Bridge: [".$bridge."], MAC: [".$mac_address."], state: [".$link_state."], model: [".$model."], last known IP: [".$ip_address."]\n";
			}
		}
		
		print "\n";
	}
	
	return(0);
}

sub load_job
{
	my ($anvil) = @_;
	
	if ($anvil->data->{switches}{'job-uuid'})
	{
		# Assume confirmation given
		$anvil->data->{switches}{confirm} = 1;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			'jobs::confirm' => $anvil->data->{jobs}{confirm}, 
		}});
	}
	else
	{
		# Not a job.
		return(0);
	}
	
	$anvil->Job->clear({
		debug    => 2,
		job_uuid => $anvil->data->{switches}{'job-uuid'}, 
	});
	$anvil->Job->get_job_details({
		debug    => 2,
		job_uuid => $anvil->data->{switches}{'job-uuid'}, 
	});
	
	# Job data comes as command line switches for now.
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		'jobs::job_data' => $anvil->data->{jobs}{job_data}, 
	}});
	foreach my $line (split/\n/, $anvil->data->{jobs}{job_data})
	{
		my ($variable, $value) =  ($line =~ /^(.*)=(.*)$/);
		   $value              =~ s/^"(.*)\"/$1/;
		   $value              =~ s/^'(.*)\'/$1/;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:line'     => $line, 
			's2:variable' => $variable, 
			's3:value'    => $value, 
		}});
		
		$anvil->data->{switches}{$variable} = $value;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"switches::${variable}" => $anvil->data->{switches}{$variable}, 
		}});
	}
	
	# Convert the 'server' to 'server_name' and 'server_uuid'.
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"switches::server" => $anvil->data->{switches}{server}, 
	}});
	if ($anvil->data->{switches}{server})
	{
		$anvil->Get->server_from_switch({debug => 2});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"switches::server_name" => $anvil->data->{switches}{server_name},
			"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
		}});
	}
	
	$anvil->Job->update_progress({
		progress         => 1,
		job_picked_up_by => $$, 
		job_picked_up_at => time, 
		message          => "message_0354", 
	});
	
	return(0);
}
