#!/usr/bin/perl
# 
# NOTE: This tool is NOT meant for production use! It is meant as a tool for CI/CD testing. 
# 
# If this is used for any other purpose, it is at he user's own risk. Please be sure to thoroughly test the 
# resulting Anvil! before going into production (which, honestly, you should do anyways).
# 

use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
use NetAddr::IP;

$| = 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();

# Before we read switches, set the debug file.
if (not -e $anvil->data->{path}{configs}{'anvil.debug'})
{
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "log_0843", variables => {
		file => $anvil->data->{path}{configs}{'anvil.debug'},
		host => $anvil->Get->short_host_name(), 
	}});
	my $problem = $anvil->Storage->write_file({
		file      => $anvil->data->{path}{configs}{'anvil.debug'}, 
		body      => "",
		overwrite => 1,
		user      => "root", 
		group     => "root", 
		mode      => "0666",
	});
}

# Read switches
$anvil->Get->switches({list => [
	"config", 
	"job-uuid", 
], 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, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});

$anvil->Database->connect;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
	# No databases, exit.
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003"});
	$anvil->nice_exit({exit_code => 1});
}

# Read in the config file
if ((not $anvil->data->{switches}{config}) or (not -f $anvil->data->{switches}{config}))
{
	# Print the usage.
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0240", variables => { program => $THIS_FILE }});
	$anvil->nice_exit({exit_code => 1});
}

# Load the config.
$anvil->Storage->read_config({file => $anvil->data->{switches}{config}});

# Check that 'prefix' is now set as a rough test that the file we read was useful.
if ((not exists $anvil->data->{base}{prefix}) or ($anvil->data->{base}{prefix} eq ""))
{
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0241", variables => { file => $anvil->data->{switches}{config} }});
	$anvil->nice_exit({exit_code => 1});
}

# Find myself
find_myself($anvil);
if (not $anvil->data->{i_am}{striker})
{
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0242", variables => { file => $anvil->data->{switches}{config} }});
	$anvil->nice_exit({exit_code => 1});
}

# If I am not configured, configure myself now.
my $configured = $anvil->System->check_if_configured;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configured => $configured }});
if ($configured)
{
	# If I am not Striker 1, I am done.
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "i_am::striker" => $anvil->data->{i_am}{striker} }});
	if ($anvil->data->{i_am}{striker} ne "1")
	{
		# We're done.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "message_0221", variables => { striker => $anvil->data->{i_am}{striker} }});
		$anvil->nice_exit({exit_code => 0});
	}
	striker_stage2($anvil);
}
else
{
	# Do the initial setup of ourselves.
	striker_stage1($anvil);
}

$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "log_0101", variables => { file => $THIS_FILE, rc => "0" }});
$anvil->nice_exit({exit_code => 0});



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

# This does the rest of the setup.
sub striker_stage2
{
	my ($anvil) = @_;
	
	# Merge my peer Striker.
	merge_peer_striker($anvil);
	
	# Add UPSes.
	add_upses($anvil);
	
	# Add fence devices
	add_fences($anvil);
	
	# Create manifest.
	create_manifest($anvil);
	
	# Initialize nodes and DR.
	initialize_machines($anvil);
	
	# Configure the network on the machines.
	configure_machine_networks($anvil);
	
	# Run the manifest(s).
	run_manifests($anvil);
	
	# Update NTP if needed
	update_ntp($anvil);
	
	return(0);
}

sub update_ntp
{
	my ($anvil) = @_;
	
	# If NTP is set, add a DB entry for all hosts to use the requested NTP server.
	$anvil->Database->get_hosts({debug => 2});
	my $network_ntp = $anvil->data->{base}{ntp};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_ntp => $network_ntp }});
	if ($network_ntp)
	{
		foreach my $host_type (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_type}})
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }});
			foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_type}{$host_type}{host_name}})
			{
				my $host_uuid = $anvil->data->{sys}{hosts}{by_type}{$host_type}{host_name}{$host_name}{host_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					host_name => $host_name,
					host_uuid => $host_uuid, 
				}});
				
				$anvil->Database->insert_or_update_variables({
					variable_name         => "network::ntp::servers", 
					variable_value        => $network_ntp, 
					variable_default      => "", 
					variable_description  => "striker_0002", 
					variable_section      => "network", 
					variable_source_uuid  => $host_uuid, 
					variable_source_table => "hosts", 
				});
			}
		}
	}
	
	return(0);
}

# This makes sure nodes and DR hosts have their networks configured.
sub configure_machine_networks
{
	my ($anvil) = @_;
	
	update_progress($anvil, 70, "job_0265");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0265"});
	
	my $job_uuids = [];
	foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_number => $anvil_number }});
		foreach my $machine_type ("node", "dr")
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_type => $machine_type }});
			foreach my $machine_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}})
			{
				my $key               = $machine_type.$machine_number;
				my $machine_host_uuid = $anvil->data->{process}{anvil}{$anvil_number}{$key}{host_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:key'               => $key, 
					's2:machine_host_uuid' => $machine_host_uuid,
				}});
				
				my $padded_sequence = $anvil_number;
				if (length($padded_sequence) == 1)
				{
					$padded_sequence = sprintf("%02d", $padded_sequence);
				}
				my $machine_suffix = $machine_type eq "node" ? "n".sprintf("%02d", $machine_number) : "dr".sprintf("%02d", $machine_number);
				my $name_prefix    = "a".$padded_sequence;
				my $host_name      = $anvil->data->{base}{prefix}."-".$name_prefix.$machine_suffix.".".$anvil->data->{base}{domain};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
				$anvil->Database->insert_or_update_variables({
					variable_name         => "form::config_step2::host_name::value", 
					variable_value        => $host_name, 
					variable_default      => "", 
					variable_description  => "striker_0159", 
					variable_section      => "config_step2", 
					variable_source_uuid  => $machine_host_uuid, 
					variable_source_table => "hosts", 
				});
				
				$anvil->data->{process}{anvil}{$anvil_number}{$key}{host_name} = $host_name;
				
				foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}})
				{
					# Record the network count.
					my $network_count = keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}};
					my $network_key   = $network."_count";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						's1:network'       => $network, 
						's2:network_key'   => $network_key, 
						's3:network_count' => $network_count, 
					}});
					
					# Store the network counts.
					$anvil->Database->insert_or_update_variables({
						variable_name         => "form::config_step1::".$network_key."::value", 
						variable_value        => $network_count, 
						variable_default      => "", 
						variable_description  => "striker_0163", 
						variable_section      => "config_step1", 
						variable_source_uuid  => $machine_host_uuid, 
						variable_source_table => "hosts", 
					});
					
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }});
					foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}})
					{
						my $network_name = $network.$network_number;
						my $ip_address   = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{ip};
						my $subnet_mask  = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{subnet_mask};
						my $link1_mac    = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac};
						my $link2_mac    = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{2}{mac};
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							's1:network_name' => $network_name, 
							's2:ip_address'   => $ip_address, 
							's3:subnet_mask'  => $subnet_mask, 
							's4:link1_mac'    => $link1_mac, 
							's5:link2_mac'    => $link2_mac,
						}});
						
						my $bridge_key    = $network_name."_create_bridge";
						my $ip_key        = $network_name."_ip";
						my $subnet_key    = $network_name."_subnet_mask";
						my $link1_key     = $network_name."_link1_mac_to_set";
						my $link2_key     = $network_name."_link2_mac_to_set";
						my $say_bridge    = "#!string!unit_0002!#";
						my $create_bridge = 0;
						if ($network ne "sn")
						{
							# We're making a bridge.
							$say_bridge    = "#!string!unit_0001!#";
							$create_bridge = 1;
						}
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							's1:bridge_key'    => $bridge_key, 
							's2:create_bridge' => $create_bridge, 
							's3:say_bridge'    => $say_bridge, 
							's4:ip_key'        => $ip_key, 
							's5:subnet_key'    => $subnet_key, 
							's6:link1_mac'     => $link1_mac, 
							's7:link2_mac'     => $link2_mac,
						}});
						
						# Store the link info
						$anvil->Database->insert_or_update_variables({
							variable_name         => "form::config_step2::".$link1_key."::value", 
							variable_value        => $link1_mac, 
							variable_default      => "", 
							variable_description  => "striker_0156", 
							variable_section      => "config_step2", 
							variable_source_uuid  => $machine_host_uuid, 
							variable_source_table => "hosts", 
						});
						$anvil->Database->insert_or_update_variables({
							variable_name         => "form::config_step2::".$link2_key."::value", 
							variable_value        => $link2_mac, 
							variable_default      => "", 
							variable_description  => "striker_0157", 
							variable_section      => "config_step2", 
							variable_source_uuid  => $machine_host_uuid, 
							variable_source_table => "hosts", 
						});
						
						# Store the bridge variables
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { create_bridge => $create_bridge }});
						$anvil->Database->insert_or_update_variables({
							variable_name         => "form::config_step2::".$bridge_key."::value", 
							variable_value        => $create_bridge, 
							variable_default      => "", 
							variable_description  => "striker_0158", 
							variable_section      => "config_step2", 
							variable_source_uuid  => $machine_host_uuid, 
							variable_source_table => "hosts", 
						});
						
						# Store the IP variables
						$anvil->Database->insert_or_update_variables({
							variable_name         => "form::config_step2::".$ip_key."::value", 
							variable_value        => $ip_address, 
							variable_default      => "", 
							variable_description  => "striker_0153,!!say_network!".$network_name."!!", 
							variable_section      => "config_step2", 
							variable_source_uuid  => $machine_host_uuid, 
							variable_source_table => "hosts", 
						});
						
						# Store the subnet mask variables
						$anvil->Database->insert_or_update_variables({
							variable_name         => "form::config_step2::".$subnet_key."::value", 
							variable_value        => $subnet_mask, 
							variable_default      => "", 
							variable_description  => "striker_0154,!!say_network!".$network_name."!!", 
							variable_section      => "config_step2", 
							variable_source_uuid  => $machine_host_uuid, 
							variable_source_table => "hosts", 
						});
						
						if ($network_name eq $anvil->data->{base}{gateway_network})
						{
							# This is the gateway network, store the gateway and DNS
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								network_name            => $network_name, 
								'base::gateway_network' => $anvil->data->{base}{gateway_network}, 
							}});
							$anvil->Database->insert_or_update_variables({
								variable_name         => "form::config_step2::gateway_interface::value", 
								variable_value        => $anvil->data->{base}{gateway_network}, 
								variable_default      => "", 
								variable_description  => "striker_0155", 
								variable_section      => "config_step2", 
								variable_source_uuid  => $machine_host_uuid, 
								variable_source_table => "hosts", 
							});
							
							# Gateway IP
							$anvil->Database->insert_or_update_variables({
								variable_name         => "form::config_step2::gateway::value", 
								variable_value        => $anvil->data->{base}{gateway}, 
								variable_default      => "", 
								variable_description  => "striker_0036", 
								variable_section      => "config_step2", 
								variable_source_uuid  => $machine_host_uuid, 
								variable_source_table => "hosts", 
							});
							
							$anvil->Database->insert_or_update_variables({
								variable_name         => "form::config_step2::dns::value", 
								variable_value        => $anvil->data->{base}{dns}, 
								variable_default      => "", 
								variable_description  => "striker_0038", 
								variable_section      => "config_step2", 
								variable_source_uuid  => $machine_host_uuid, 
								variable_source_table => "hosts", 
							});
						}
					}
				}
				
				my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
					debug           => 2,
					job_host_uuid   => $machine_host_uuid, 
					job_command     => $anvil->data->{path}{exe}{'anvil-configure-host'}." --debug ".$anvil->Log->switches, 
					job_data        => "form::config_step2", 
					job_name        => "configure::network", 
					job_title       => "job_0001", 
					job_description => "job_0071", 
					job_progress    => 0,
				});
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0266", variables => {
					host_name => $host_name,
					job_uuid  => $job_uuid, 
				}});
			}
		}
	}
	
	# Now wait until all the machines are accessible by the BCN1 IP.
	update_progress($anvil, 75, "job_0267");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0267"});
	
	my $waiting = 1;
	while ($waiting)
	{
		$waiting = 0;
		foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}})
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_number => $anvil_number }});
			foreach my $machine_type ("node", "dr")
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_type => $machine_type }});
				foreach my $machine_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}})
				{
					my $key       = $machine_type.$machine_number;
					my $host_uuid = $anvil->data->{process}{anvil}{$anvil_number}{$key}{host_uuid};
					my $host_name = $anvil->data->{process}{anvil}{$anvil_number}{$key}{host_name};
					my $bcn1_ip   = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{bcn}{1}{ip};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						key       => $key,
						host_uuid => $host_uuid, 
						host_name => $host_name, 
						bcn1_ip   => $bcn1_ip, 
					}});
					
					my $access = $anvil->Remote->test_access({
						debug    => 2,
						target   => $bcn1_ip,
						password => $anvil->data->{base}{password}{startup},
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});
					
					if (not $access)
					{
						# Try again with the new password, in case it's already 
						# updated.
						my $access = $anvil->Remote->test_access({
							debug    => 2,
							target   => $bcn1_ip,
							password => $anvil->data->{base}{password}{desired},
						});
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});
						
						if (not $access)
						{
							# Still nothing, keep waiting.
							$waiting = 1;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
							$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0268", variables => {
								host_name  => $host_name,
								ip_address => $bcn1_ip, 
							}});
						}
					}
				}
			}
		}
		
		if ($waiting)
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0269"});
			
			# Disconnect and reconnect in case a DB goes offline.
			$anvil->Database->disconnect();
			sleep 10;
			$anvil->refresh();
			$anvil->Database->connect();
		}
	}
	
	update_progress($anvil, 80, "job_0270");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0270"});
	
	return(0);
}

# By this point, all machines should be initialized and online.
sub run_manifests
{
	my ($anvil) = @_;
	
	update_progress($anvil, 85, "job_0257");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0257"});
	
	# Run the manifest now!
	my $job_uuids = [];
	foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}})
	{
		my $anvil_name      = $anvil->data->{process}{anvil}{$anvil_number}{name};
		my $manifest_uuid   = $anvil->data->{process}{anvil}{$anvil_number}{manifest_uuid};
		my $manifest_name   = $anvil->data->{process}{anvil}{$anvil_number}{manifest_name};
		my $node1_host_uuid = $anvil->data->{process}{anvil}{$anvil_number}{node1}{host_uuid};
		my $node2_host_uuid = $anvil->data->{process}{anvil}{$anvil_number}{node2}{host_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:anvil_number'    => $anvil_number, 
			's2:anvil_name'      => $anvil_name, 
			's3:manifest_name'   => $manifest_name, 
			's4:manifest_uuid'   => $manifest_uuid, 
			's5:node1_host_uuid' => $node1_host_uuid, 
			's6:node2_host_uuid' => $node2_host_uuid, 
		}});
		
		my ($anvil_uuid) = $anvil->Database->insert_or_update_anvils({
			debug                 => 2,
			anvil_description     => $anvil->data->{anvil}{$anvil_number}{description}, 
			anvil_name            => $anvil_name, 
			anvil_password        => $anvil->data->{base}{password}{desired}, 
			anvil_node1_host_uuid => $node1_host_uuid, 
			anvil_node2_host_uuid => $node2_host_uuid, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0258", variables => {
			anvil_name => $anvil_name, 
			anvil_uuid => $anvil_uuid, 
		}});
		
		# Tell node 1 to join.
		my ($node1_job_uuid) = $anvil->Database->insert_or_update_jobs({
			job_host_uuid   => $node1_host_uuid, 
			job_command     => $anvil->data->{path}{exe}{'anvil-join-anvil'}.$anvil->Log->switches, 
			job_data        => "as_machine=node1,manifest_uuid=".$manifest_uuid.",anvil_uuid=".$anvil_uuid, 
			job_name        => "join_anvil::node1", 
			job_title       => "job_0072", 
			job_description => "job_0073", 
			job_progress    => 0,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_job_uuid => $node1_job_uuid }});
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0259", variables => {
			machine_name => "node1",
			anvil_name   => $anvil_name, 
			host_uuid    => $node1_host_uuid, 
			job_uuid     => $node1_job_uuid, 
		}});
		push @{$job_uuids}, $node1_job_uuid;
		
		my ($node2_job_uuid) = $anvil->Database->insert_or_update_jobs({
			job_host_uuid   => $node2_host_uuid, 
			job_command     => $anvil->data->{path}{exe}{'anvil-join-anvil'}.$anvil->Log->switches, 
			job_data        => "as_machine=node2,manifest_uuid=".$manifest_uuid.",anvil_uuid=".$anvil_uuid, 
			job_name        => "join_anvil::node2", 
			job_title       => "job_0072", 
			job_description => "job_0073", 
			job_progress    => 0,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_job_uuid => $node2_job_uuid }});
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0259", variables => {
			machine_name => "node2",
			anvil_name   => $anvil_name, 
			host_uuid    => $node2_host_uuid, 
			job_uuid     => $node2_job_uuid, 
		}});
		push @{$job_uuids}, $node2_job_uuid;
	}
	
	update_progress($anvil, 90, "job_0257");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0257"});
	
	# Wait for jobs to complete.
	my $waiting = 1;
	while ($waiting)
	{
		$waiting = 0;
		foreach my $job_uuid (@{$job_uuids})
		{
			my $return       = $anvil->Database->get_job_details({job_uuid => $job_uuid});
			my $job_progress = $return->{job_progress};
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0261", variables => {
				job_uuid => $job_uuid, 
				progress => $job_progress, 
			}});
			
			if ($job_progress != 100)
			{
				# Still waiting
				$waiting = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
			}
		}
		
		if ($waiting)
		{
			# Wait a bit and check again.
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0262"});
			
			# Disconnect and reconnect in case a DB goes offline.
			$anvil->Database->disconnect();
			sleep 10;
			$anvil->refresh();
			$anvil->Database->connect();
		}
		else
		{
			# We're done.
			update_progress($anvil, 100, "job_0263");
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0263"});
		}
	}
	
	return(0);
}

# This initializes nodes and DR hosts. This also sets the 'cgi::<variable>::value' hashes that will be needed
# later to create the install manifest.
sub initialize_machines
{
	my ($anvil) = @_;
	
	update_progress($anvil, 60, "job_0246");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0245"});
	
	foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_number => $anvil_number }});
		foreach my $machine_type ("node", "dr")
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_type => $machine_type }});
			foreach my $machine_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}})
			{
				my $startup_ip = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{startup_ip};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					machine_number => $machine_number,
					startup_ip     => $startup_ip, 
				}});
				
				# Find the IP we can access the machine with and the machine's host_uuid.
				my $machine_host_uuid = "";
				my $machine_ips       = [];
				push @{$machine_ips}, $startup_ip;
				
				foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}})
				{
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }});
					foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}})
					{
						my $ip_address  = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{ip};
						my $subnet_mask = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{subnet_mask};
						my $link1_mac   = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac};
						my $link2_mac   = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{2}{mac};
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							's1:ip_address'  => $ip_address, 
							's2:subnet_mask' => $subnet_mask, 
							's3:link1_mac'   => $link1_mac, 
							's4:link2_mac'   => $link2_mac,
						}});
						
						# No sense pushing SN IPs
						if ($network !~ /^sn/)
						{
							push @{$machine_ips}, $ip_address;
							my $ip_count = @{$machine_ips};
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_count => $ip_count }});
						}
						
						if (not $machine_host_uuid)
						{
							$machine_host_uuid = get_host_uuid_from_mac($anvil, $link1_mac);
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }});
						}
						if (not $machine_host_uuid)
						{
							$machine_host_uuid = get_host_uuid_from_mac($anvil, $link2_mac);
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }});
						}
					}
				}
				
				# If I don't have a machine host uuid, initialize the machine.
				if ($machine_host_uuid)
				{
					# Already initialized
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0247", variables => {
						machine   => $machine_type.$machine_number, 
						host_uuid => $machine_host_uuid, 
					}});
				}
				else
				{
					# Which IP should be use to initialize?
					my $use_ip       = "";
					my $use_password = $anvil->data->{base}{password}{startup};
					until ($use_ip)
					{
						foreach my $ip_address (@{$machine_ips})
						{
							next if $use_ip;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address => $ip_address }});
							
							$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0248", variables => {
								machine => $machine_type.$machine_number, 
								ip      => $ip_address, 
							}});
							my $access = $anvil->Remote->test_access({
								target   => $ip_address,
								password => $use_password,
							});
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});
							if ($access)
							{
								$use_ip = $ip_address;
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_ip => $use_ip }});
								$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0250", variables => { ip => $use_ip }});
							}
							else
							{
								# Failed to log in, try again with the 
								# desired password, the machine might already
								# be updated.
								$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0249", variables => {
									machine => $machine_type.$machine_number, 
									ip      => $ip_address, 
								}});
								$access = $anvil->Remote->test_access({
									target   => $ip_address,
									password => $anvil->data->{base}{password}{desired},
								});
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});
								if ($access)
								{
									# The new password worked.
									$use_password = $anvil->data->{base}{password}{desired};
									$use_ip       = $ip_address;
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_ip => $use_ip }});
									$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0250", variables => { ip => $use_ip }});
								}
							}
						}
						if (not $use_ip)
						{
							# Sleep and try again.
							$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0251", variables => { machine => $machine_type.$machine_number }});
							sleep 10;
						}
					}
					
					# Now register a job to initialize the target.
					my $padded_sequence = $anvil_number;
					if (length($padded_sequence) == 1)
					{
						$padded_sequence = sprintf("%02d", $padded_sequence);
					}
					my $machine_suffix = $machine_type eq "node" ? "n".sprintf("%02d", $machine_number) : "dr".sprintf("%02d", $machine_number);
					my $name_prefix    = "a".$padded_sequence;
					my $say_host_name  = $anvil->data->{base}{prefix}."-".$name_prefix.$machine_suffix.".".$anvil->data->{base}{domain};
					
					# Store the peer's password as the job data
					my $job_data =  "password=".$anvil->data->{base}{password}{startup}."\n";
					   $job_data .= "rh_password=".$anvil->data->{base}{rhn}{password}."\n";
					   $job_data .= "rh_user=".$anvil->data->{base}{rhn}{user}."\n";
					   $job_data .= "host_ip_address=".$use_ip."\n";
					   $job_data .= "ssh_port=22\n";
					   $job_data .= "type=".$machine_type."\n"; 
					   $job_data .= "host_name=".$say_host_name; 
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { job_data => $job_data }});
					
					# Store the job
					my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
						debug           => 2,
						file            => $THIS_FILE, 
						line            => __LINE__, 
						job_command     => $anvil->data->{path}{exe}{'striker-initialize-host'}.$anvil->Log->switches, 
						job_data        => $job_data, 
						job_name        => "initialize::".$machine_type."::".$use_ip, 
						job_title       => $machine_type eq "dr" ? "job_0021" : "job_0020", 
						job_description => "job_0022", 
						job_progress    => 0,
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});

					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0246", variables => {
						host_name => $say_host_name, 
						ip        => $use_ip, 
						job_uuid  => $job_uuid, 
					}});
				}
			}
		}
	}
	
	update_progress($anvil, 65, "job_0253");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0253"});
	
	# Now wait until all machines are in the database.
	my $waiting         = 1;
	my $node1_host_uuid = "";
	my $node2_host_uuid = "";
	while($waiting)
	{
		$waiting = 0;
		foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}})
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_number => $anvil_number }});
			foreach my $machine_type ("node", "dr")
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_type => $machine_type }});
				foreach my $machine_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}})
				{
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_number => $machine_number }});
					my $machine_host_uuid = "";
					foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}})
					{
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }});
						foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}})
						{
							next if $machine_host_uuid;
							my $link1_mac = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac};
							my $link2_mac = $anvil->data->{anvil}{$anvil_number}{$machine_type}{$machine_number}{network}{$network}{$network_number}{'link'}{2}{mac};
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								's1:link1_mac' => $link1_mac, 
								's2:link2_mac' => $link2_mac,
							}});
							
							# No sense pushing SN IPs
							if (not $machine_host_uuid)
							{
								$machine_host_uuid = get_host_uuid_from_mac($anvil, $link1_mac);
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }});
							}
							if (not $machine_host_uuid)
							{
								$machine_host_uuid = get_host_uuid_from_mac($anvil, $link2_mac);
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }});
							}
						}
					}
					if ($machine_host_uuid)
					{
						# Ready
						my $key                                                           = $machine_type.$machine_number;
						   $anvil->data->{process}{anvil}{$anvil_number}{$key}{host_uuid} = $machine_host_uuid;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							"process::anvil::${anvil_number}::${key}::host_uuid" => $anvil->data->{process}{anvil}{$anvil_number}{$key}{host_uuid},
						}});
					}
					else
					{
						# At least one machine isn't up yet.
						$waiting = 1;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0254", variables => { machine => $machine_type.$machine_number }});
					}
				}
			}
		}
		if ($waiting)
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0255"});
			
			# Disconnect and reconnect in case a DB goes offline.
			$anvil->Database->disconnect();
			sleep 10;
			$anvil->refresh();
			$anvil->Database->connect();
		}
	}
	
	update_progress($anvil, 65, "job_0256");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0256"});
	
	return(0);
}

# This creates the manifests
sub create_manifest
{
	my ($anvil) = @_;
	
	# By here, the peer(s) are joined.
	update_progress($anvil, 50, "job_0243");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0243"});
	
	$anvil->Database->get_upses({debug => 2});
	$anvil->Database->get_fences({debug => 2});
	
	# This is common for all Anvil! systems we might be building
	### CGI is legacy
	$anvil->data->{cgi}{prefix}{value} = $anvil->data->{base}{prefix};
	$anvil->data->{cgi}{domain}{value} = $anvil->data->{base}{domain};
	$anvil->data->{cgi}{mtu}{value}    = $anvil->data->{base}{mtu};
	$anvil->data->{cgi}{dns}{value}    = $anvil->data->{base}{dns};
	$anvil->data->{cgi}{ntp}{value}    = $anvil->data->{base}{ntp};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"cgi::prefix::value" => $anvil->data->{cgi}{prefix}{value}, 
		"cgi::domain::value" => $anvil->data->{cgi}{domain}{value}, 
		"cgi::mtu::value"    => $anvil->data->{cgi}{mtu}{value}, 
		"cgi::dns::value"    => $anvil->data->{cgi}{dns}{value}, 
		"cgi::ntp::value"    => $anvil->data->{cgi}{ntp}{value}, 
	}});
	
	my $network_dns = $anvil->data->{base}{dns};
	my $domain      = $anvil->data->{base}{domain};
	my $network_mtu = $anvil->data->{base}{mtu};
	my $network_ntp = $anvil->data->{base}{ntp};
	my $name_prefix = $anvil->data->{base}{prefix};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		network_dns => $network_dns, 
		domain      => $domain, 
		network_mtu => $network_mtu, 
		network_ntp => $network_ntp, 
		name_prefix => $name_prefix, 
	}});
	
	foreach my $anvil_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}})
	{
		$anvil->data->{cgi}{sequence}{value} = $anvil_number;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"cgi::sequence::value" => $anvil->data->{cgi}{sequence}{value}, 
		}});
		
		my $padded_sequence = $anvil_number;
		if (length($padded_sequence) == 1)
		{
			$padded_sequence = sprintf("%02d", $padded_sequence);
		}
		my $anvil_name = $anvil->data->{cgi}{prefix}{value}."-anvil-".$padded_sequence;
		my $query      = "SELECT manifest_uuid FROM manifests WHERE manifest_name = ".$anvil->Database->quote($anvil_name).";";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
		
		$anvil->data->{process}{anvil}{$anvil_number}{name} = $anvil_name;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"process::anvil::${anvil_number}::name" => $anvil->data->{process}{anvil}{$anvil_number}{name},
		}});

		my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
		my $count   = @{$results};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			results => $results, 
			count   => $count, 
		}});
		if ($count)
		{
			$anvil->data->{cgi}{manifest_uuid}{value} = $results->[0]->[0];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"cgi::manifest_uuid::value" => $anvil->data->{cgi}{manifest_uuid}{value}, 
			}});
		}
		else
		{
			$anvil->data->{cgi}{manifest_uuid}{value} = "new";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"cgi::manifest_uuid::value" => $anvil->data->{cgi}{manifest_uuid}{value}, 
			}});
		}
		
		foreach my $machine_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{node}})
		{
			my $machine = "node".$machine_number;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				machine        => $machine, 
				machine_number => $machine_number,
			}});
			
			$anvil->data->{cgi}{bcn_count}{value} = keys %{$anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{bcn}};
			$anvil->data->{cgi}{sn_count}{value}  = keys %{$anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{sn}};
			$anvil->data->{cgi}{ifn_count}{value} = keys %{$anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{ifn}};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"cgi::bcn_count::value" => $anvil->data->{cgi}{bcn_count}{value}, 
				"cgi::sn_count::value"  => $anvil->data->{cgi}{sn_count}{value}, 
				"cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value}, 
			}});
			
			# The machine might already be initialized, so we'll look in our database for
			# any entries ith the same MAC addresses. If none are found, we'll wait to 
			# ping it on the startup IP and then initialize it.
			my $machine_host_uuid = "";
			my $machine_ips       = [];
			my $startup_ip        = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{startup_ip};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { startup_ip => $startup_ip }});
			
			foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}})
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }});
				foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{$network}})
				{
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_number => $network_number }});
					
					my $ip_address  = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{$network}{$network_number}{ip};
					my $subnet_mask = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{$network}{$network_number}{subnet_mask};
					my $link1_mac   = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{$network}{$network_number}{'link'}{1}{mac};
					my $link2_mac   = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{$network}{$network_number}{'link'}{2}{mac};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						's1:ip_address'  => $ip_address, 
						's2:subnet_mask' => $subnet_mask, 
						's3:link1_mac'   => $link1_mac, 
						's4:link2_mac'   => $link2_mac,
					}});
					push @{$machine_ips}, $ip_address."/".$subnet_mask;
					
					if (not $machine_host_uuid)
					{
						$machine_host_uuid = get_host_uuid_from_mac($anvil, $link1_mac);
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }});
					}
					if (not $machine_host_uuid)
					{
						$machine_host_uuid = get_host_uuid_from_mac($anvil, $link2_mac);
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine_host_uuid => $machine_host_uuid }});
					}
					
					my $network_name = $network.$network_number;
					my $network_key  = $network_name."_network";
					my $subnet_key   = $network_name."_subnet";
					my $gateway_key  = $network_name."_gateway";
					my $ip_key       = $machine."_".$network_name."_ip";
					$anvil->data->{cgi}{$network_key}{value} = $anvil->Network->get_network({ip => $ip_address, subnet_mask => $subnet_mask});
					$anvil->data->{cgi}{$subnet_key}{value}  = $subnet_mask;
					$anvil->data->{cgi}{$gateway_key}{value} = $anvil->data->{base}{gateway_network} eq $network_name ? $anvil->data->{base}{gateway} : "";
					$anvil->data->{cgi}{$ip_key}{value}      = $ip_address;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value}, 
						"cgi::${subnet_key}::value"  => $anvil->data->{cgi}{$subnet_key}{value}, 
						"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value}, 
						"cgi::${ip_key}::value"      => $anvil->data->{cgi}{$ip_key}{value}, 
					}});
					
					if ($network_name eq "bcn1")
					{
						my $ipmi_ip_key                             = $machine."_ipmi_ip";
						   $anvil->data->{cgi}{$ipmi_ip_key}{value} = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{network}{$network}{$network_number}{ipmi_ip};
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							"cgi::${ipmi_ip_key}::value" => $anvil->data->{cgi}{$ipmi_ip_key}{value}, 
						}});
						
						### Find the UPSes.
						# Preset all known UPSes to not used
						foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{upses}{ups_name}})
						{
							my $ups_key                             = $machine."_ups_".$ups_name;
							   $anvil->data->{cgi}{$ups_key}{value} = "";
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								"cgi::${ups_key}::value" => $anvil->data->{cgi}{$ups_key}{value}, 
							}});
						}
						# Now flip on the ones configured for use
						foreach my $ups_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{ups}})
						{
							my $ups_name = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{ups}{$ups_number}{name};
							my $ups_key  = $machine."_ups_".$ups_name;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								ups_number => $ups_number,
								ups_name   => $ups_name,
							}});
							
							$anvil->data->{cgi}{$ups_key}{value} = 1;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								"cgi::${ups_key}::value" => $anvil->data->{cgi}{$ups_key}{value}, 
							}});
						}
						
						### Find the Fence devices.
						# Preset all known fence devices to have no port.
						foreach my $fence_name (sort {$a cmp $b} keys %{$anvil->data->{fences}{fence_name}})
						{
							my $fence_key                             = $machine."_fence_".$fence_name;
							   $anvil->data->{cgi}{$fence_key}{value} = "" if not defined $anvil->data->{cgi}{$fence_key}{value};
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								"cgi::${fence_key}::value" => $anvil->data->{cgi}{$fence_key}{value}, 
							}});
						}
						foreach my $fence_number (sort {$a cmp $b} keys %{$anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{fence}})
						{
							my $fence_name = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{fence}{$fence_number}{name};
							my $fence_port = $anvil->data->{anvil}{$anvil_number}{node}{$machine_number}{fence}{$fence_number}{port};
							my $fence_key  = $machine."_fence_".$fence_name;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								fence_number => $fence_number,
								fence_name   => $fence_name,
								fence_port   => $fence_port,
							}});
							
							$anvil->data->{cgi}{$fence_key}{value} = $fence_port;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								"cgi::${fence_key}::value" => $anvil->data->{cgi}{$fence_key}{value}, 
							}});
						}
					}
				}
			}
		}
		
		# Now generate the manifest.
		my ($manifest_uuid, $manifest_name) = $anvil->Striker->generate_manifest({
			debug         => 2,
			manifest_uuid => "new",
			dns           => $network_dns,
			domain        => $domain, 
			mtu           => $network_mtu, 
			ntp           => $network_ntp, 
			prefix        => $name_prefix, 
			sequence      => $padded_sequence, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			manifest_uuid => $manifest_uuid, 
			manifest_name => $manifest_name, 
		}});
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0244", variables => {
			manifest_name => $manifest_name, 
			manifest_uuid => $manifest_uuid, 
		}});
		
		$anvil->data->{process}{anvil}{$anvil_number}{manifest_uuid} = $manifest_uuid;
		$anvil->data->{process}{anvil}{$anvil_number}{manifest_name} = $manifest_name;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"process::anvil::${anvil_number}::manifest_name" => $anvil->data->{process}{anvil}{$anvil_number}{manifest_name},
			"process::anvil::${anvil_number}::manifest_uuid" => $anvil->data->{process}{anvil}{$anvil_number}{manifest_uuid},
		}});
	}
	
	update_progress($anvil, 55, "job_0245");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0245"});
	
	return(0);
}

sub add_fences
{
	my ($anvil) = @_;
	
	# By here, the peer(s) are joined.
	update_progress($anvil, 40, "job_0240");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0240"});
	
	foreach my $fence_number (sort {$a cmp $b} keys %{$anvil->data->{fence}})
	{
		my $fence_name      = $anvil->data->{fence}{$fence_number}{name};
		my $fence_agent     = $anvil->data->{fence}{$fence_number}{agent};
		my $fence_arguments = $anvil->data->{fence}{$fence_number}{arguments};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:fence_number'    => $fence_number, 
			's2:fence_name'      => $fence_name, 
			's3:fence_agent'     => $fence_agent, 
			's4:fence_arguments' => $fence_arguments, 
		}});
		
		my ($fence_uuid) = $anvil->Database->insert_or_update_fences({
			fence_agent     => $fence_agent, 
			fence_arguments => $fence_arguments, 
			fence_name      => $fence_name, 
		});
		if (($fence_uuid) && ($anvil->Validate->uuid({uuid => $fence_uuid})))
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0241", variables => { 
				fence_name  => $fence_name,
				fence_agent => $fence_agent,
				fence_uuid  => $fence_uuid, 
			}});
		}
		else
		{
			# WTF?
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0249", variables => { 
				fence_name      => $fence_name,
				fence_arguments => $fence_arguments, 
				fence_agent     => $fence_agent,
			}});
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "job_0238"});
			update_progress($anvil, 100, "job_0238");
			
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "log_0101", variables => { file => $THIS_FILE, rc => "1" }});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	update_progress($anvil, 45, "job_0242");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0242"});
	
	return(0);
}

sub add_upses
{
	my ($anvil) = @_;
	
	# By here, the peer(s) are joined.
	update_progress($anvil, 30, "job_0236");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0236"});
	
	foreach my $ups_number (sort {$a cmp $b} keys %{$anvil->data->{ups}})
	{
		my $ups_name       = $anvil->data->{ups}{$ups_number}{name};
		my $ups_agent      = $anvil->data->{ups}{$ups_number}{agent};
		my $ups_ip_address = $anvil->data->{ups}{$ups_number}{ip_address};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:ups_number'     => $ups_number, 
			's2:ups_name'       => $ups_name, 
			's3:ups_agent'      => $ups_agent, 
			's4:ups_ip_address' => $ups_ip_address, 
		}});
		
		my ($ups_uuid) = $anvil->Database->insert_or_update_upses({
			ups_agent      => $ups_agent, 
			ups_ip_address => $ups_ip_address, 
			ups_name       => $ups_name, 
		});
		if (($ups_uuid) && ( $anvil->Validate->uuid({uuid => $ups_uuid})))
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0237", variables => { 
				ups_name       => $ups_name,
				ups_ip_address => $ups_ip_address, 
				ups_agent      => $ups_agent,
				ups_uuid       => $ups_uuid, 
			}});
		}
		else
		{
			# WTF?
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0248", variables => { 
				ups_name       => $ups_name,
				ups_ip_address => $ups_ip_address, 
				ups_agent      => $ups_agent,
			}});
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "job_0238"});
			update_progress($anvil, 100, "job_0238");
			
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "log_0101", variables => { file => $THIS_FILE, rc => "1" }});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	update_progress($anvil, 35, "job_0239");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0239"});
	
	return(0);
}

# This takes a MAC address and returns the host_uuid, if found.
sub get_host_uuid_from_mac
{
	my ($anvil, $mac_address) = @_;
	
	my $host_uuid = "";
	my $query     = "
SELECT 
    network_interface_host_uuid 
FROM 
    network_interfaces 
WHERE 
    network_interface_operational != 'DELETED' 
AND 
    network_interface_mac_address =  ".$anvil->Database->quote($mac_address)."
;";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 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 => 2, list => { 
		results => $results, 
		count   => $count, 
	}});
	if ($count)
	{
		$host_uuid = $results->[0]->[0]; 
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
	}
	
	return($host_uuid);
}

# Merge my peer Striker.
sub merge_peer_striker
{ 
	my ($anvil) = @_;
	
	# For each peer, see if we're already connected to it.
	update_progress($anvil, 0, "clear");
	update_progress($anvil, 10, "job_0234");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0234"});
	foreach my $striker_number (sort {$a cmp $b} keys %{$anvil->data->{striker}})
	{
		next if $striker_number !~ /^\d+$/;
		next if $striker_number == $anvil->data->{i_am}{striker};
		next if not exists $anvil->data->{striker}{$striker_number}{network};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { striker_number => $striker_number }});
		
		# Use the MAC address(es) to look for a host UUID. If we don't find one, we need to peer it. 
		my $peer_host_uuid = "";
		my $peer_ips       = [];
		foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}})
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }});
			foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}})
			{
				my $ip          = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip};
				my $subnet_mask = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask};
				push @{$peer_ips}, $ip."/".$subnet_mask;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					network_number => $network_number,
					ip             => $ip,
					subnet_mask    => $subnet_mask, 
				}});
				foreach my $link_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}})
				{
					next if $peer_host_uuid; 
					my $mac_address = lc($anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{$link_number}{mac});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						link_number => $link_number, 
						mac_address => $mac_address,
					}});
					$peer_host_uuid = get_host_uuid_from_mac($anvil, $mac_address);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_uuid => $peer_host_uuid }});
				}
			}
		}
		
		if ($peer_host_uuid)
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0264", variables => { 
				number         => $striker_number, 
				peer_host_name => $anvil->Database->get_host_from_uuid({host_uuid => $peer_host_uuid}),
			}});
			next;
		}
		else
		{
			### Add the peer.
			# First, wait for access.
			my $waiting = 1;
			my $joining = 0;
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0227", variables => { number => $striker_number }});
			
			while ($waiting)
			{
				foreach my $network (@{$peer_ips})
				{
					next if not $waiting;
					my ($ip, $subnet_mask) = ($network =~ /^(.*?)\/(.*)$/);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						ip          => $ip,
						subnet_mask => $subnet_mask, 
					}});
					
					# Try to read the host uuid.
					my $file = $anvil->data->{path}{data}{host_uuid};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }});
					my $shell_call = "
if [ -e ".$file." ];
then
    cat ".$file.";
else
    echo 0;
fi;
";
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0166", variables => { 
						shell_call  => $shell_call, 
						target      => $ip, 
						remote_user => "root",
					}});
					my ($host_uuid, $error, $return_code) = $anvil->Remote->call({
						debug      => 2,
						shell_call => $shell_call, 
						target     => $ip,
						password   => $anvil->data->{base}{password}{desired},
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						host_uuid   => $host_uuid,
						error       => $error,
						return_code => $return_code, 
					}});
					if (($host_uuid) && ($anvil->Validate->uuid({uuid => $host_uuid})))
					{
						# Success!
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0228", variables => { 
							number => $striker_number,
							ip     => $ip,
						}});
						
						$peer_host_uuid = $host_uuid;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_uuid => $peer_host_uuid }});
						
						# Find the IP we used to reach the peer.
						my $our_ip = "";
						until($our_ip)
						{
							$anvil->Network->load_ips({
								host      => "local",
								host_uuid => $anvil->Get->host_uuid(),
							});
							foreach my $interface_name (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}})
							{
								my $local_ip          = $anvil->data->{network}{'local'}{interface}{$interface_name}{ip};
								my $local_subnet_mask = $anvil->data->{network}{'local'}{interface}{$interface_name}{subnet_mask};
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
									interface_name    => $interface_name, 
									local_ip          => $local_ip, 
									local_subnet_mask => $local_subnet_mask, 
								}});
								next if $local_subnet_mask ne $subnet_mask;
								
								# See if this IP is in the same subnet.
								my $first  = NetAddr::IP->new($local_ip."/".$local_subnet_mask);
								my $second = NetAddr::IP->new($ip."/".$subnet_mask);
								if ($second->within($first))
								{
									# Found the IP to tell the peer to use
									$our_ip = $local_ip;
									$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { our_ip => $our_ip }});
									last;
								}
							}
							
							if (not $our_ip)
							{
								# One of the machines hasn't updated IP information yet.
								$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0271", variables => { 
									number => $striker_number,
									ip     => $ip,
								}});
								sleep 10;
							}
						}
						
						# Register a job and then wait for it to show up in our database.
						my $job_data    =  "password=".$anvil->data->{base}{password}{desired}."\n";
						   $job_data    .= "peer_job_command=".$anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$anvil->Get->host_uuid." --host ".$our_ip." --port 5432 --ping 1".$anvil->Log->switches;
						my $job_command =  $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$host_uuid." --host ".$ip." --port 5432 --ping 1".$anvil->Log->switches;
						   $waiting     =  0;
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							job_command => $job_command,
							job_data    => $anvil->Log->is_secure($job_data), 
							waiting     => $waiting, 
						}});
						my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
							job_command     => $job_command, 
							job_data        => $job_data, 
							job_name        => "striker-peer::remove", 
							job_title       => "job_0013", 
							job_description => "job_0014", 
							job_progress    => 0,
						});
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
					}
					else
					{
						# No access
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0229", variables => { 
							number => $striker_number,
							ip     => $ip,
						}});
					}
				}
				if ($waiting)
				{
					# Wait 30 seconds and try again
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0230", variables => { number => $striker_number }});
			
					# Disconnect and reconnect in case a DB goes offline.
					$anvil->Database->disconnect();
					sleep 30;
					$anvil->refresh();
					$anvil->Database->connect();
				}
			}
		}
		
		# Now wait until the peer is in our database.
		my $peer_host_name = "";
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0231", variables => { 
			number         => $striker_number, 
			peer_host_uuid => $peer_host_uuid,
		}});
		until ($peer_host_name)
		{
			my $query = "SELECT host_name FROM hosts WHERE host_uuid = ".$anvil->Database->quote($peer_host_uuid).";";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 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 => 2, list => { 
				results => $results, 
				count   => $count, 
			}});
			if ($count)
			{
				$peer_host_name = $results->[0]->[0]; 
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0232", variables => { 
					number         => $striker_number, 
					peer_host_name => $peer_host_name,
				}});
			}
			else
			{
				# Sleep for a bit.
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0233", variables => { 
					number         => $striker_number, 
					peer_host_uuid => $peer_host_uuid,
				}});
				sleep 5;
			}
		}
	}
	
	# By here, the peer(s) are joined.
	update_progress($anvil, 20, "job_0235");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0235"});
	
	return(0);
}

# This preps and requests the initial configuration job.
sub striker_stage1
{
	my ($anvil) = @_;
	
	# Validate
	if ((not defined $anvil->data->{base}{organization_name}) or (not $anvil->data->{base}{organization_name}))
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::organization_name' }});
		$anvil->nice_exit({exit_code => 1});
	}
	if ((not defined $anvil->data->{base}{prefix}) or (not $anvil->data->{base}{prefix}))
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::prefix' }});
		$anvil->nice_exit({exit_code => 1});
	}
	elsif (length($anvil->data->{base}{prefix}) > 5)
	{
		# Prefix is too long
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0244", variables => { 
			prefix   => $anvil->data->{base}{prefix},
			'length' => length($anvil->data->{base}{prefix}),
		}});
		$anvil->nice_exit({exit_code => 1});
	}
	if ((not defined $anvil->data->{base}{domain}) or (not $anvil->data->{base}{domain}))
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::domain' }});
		$anvil->nice_exit({exit_code => 1});
	}
	elsif (not $anvil->Validate->domain_name({name => $anvil->data->{base}{domain}}))
	{
		# Domain is not valid
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0117", variables => { name => $anvil->data->{base}{domain} }});
		$anvil->nice_exit({exit_code => 1});
	}
	if ((not defined $anvil->data->{base}{password}{desired}) or (not $anvil->data->{base}{password}{desired}))
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { variable => 'base::password::desired' }});
		$anvil->nice_exit({exit_code => 1});
	}
	if ((not defined $anvil->data->{base}{dns}) or (not $anvil->data->{base}{dns}))
	{
		$anvil->data->{base}{dns} = "8.8.8.8,8.8.4.4";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "base::dns" => $anvil->data->{base}{dns} }});
	}
	else
	{
		# Make sure any/all DNS are valid.
		foreach my $ip (split/,/, $anvil->data->{base}{dns})
		{
			if (not $anvil->Validate->ipv4({ip => $ip}))
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0245", variables => { ip => $ip }});
				$anvil->nice_exit({exit_code => 1});
			}
		}
	}
	if ((defined $anvil->data->{base}{gateway}) && ($anvil->data->{base}{gateway}))
	{
		if (not $anvil->Validate->ipv4({ip => $anvil->data->{base}{gateway}}))
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0246", variables => { ip => $anvil->data->{base}{gateway} }});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	my $striker_number    = $anvil->data->{i_am}{striker};
	my $organization_name = $anvil->data->{base}{organization_name};
	my $prefix            = $anvil->data->{base}{prefix};
	my $domain            = $anvil->data->{base}{domain};
	my $ifn_count         = keys %{$anvil->data->{striker}{$striker_number}{network}{ifn}};
	my $host_name         = $prefix."-striker0".$striker_number.".".$domain;
	my $new_password      = $anvil->data->{base}{password}{desired};
	my $dns               = $anvil->data->{base}{dns};
	my $gateway           = $anvil->data->{base}{gateway};
	my $gateway_network   = defined $anvil->data->{base}{gateway_network} ? $anvil->data->{base}{gateway_network} : "ifn1";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		striker_number    => $striker_number, 
		organization_name => $organization_name,
		prefix            => $prefix, 
		domain            => $domain, 
		ifn_count         => $ifn_count, 
		host_name         => $host_name, 
		new_password      => $anvil->Log->is_secure($new_password), 
		dns               => $dns, 
		gateway           => $gateway, 
		gateway_network   => $gateway_network, 
	}});
	
	# Load the variables.
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::organization::value'}{variable_value}            = $organization_name;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::organization::value'}{variable_description}      = "striker_0004";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::organization::value'}{variable_section}          = "config_step1";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::prefix::value'}{variable_value}                  = $prefix;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::prefix::value'}{variable_description}            = "striker_0006";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::prefix::value'}{variable_section}                = "config_step1";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::domain::value'}{variable_value}                  = $domain;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::domain::value'}{variable_description}            = "striker_0008";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::domain::value'}{variable_section}                = "config_step1";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::ifn_count::value'}{variable_value}               = $ifn_count;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::ifn_count::value'}{variable_description}         = "striker_0012";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::ifn_count::value'}{variable_section}             = "config_step1";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::sequence::value'}{variable_value}                = $striker_number;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::sequence::value'}{variable_description}          = "striker_0010";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step1::sequence::value'}{variable_section}              = "config_step1";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::host_name::value'}{variable_value}               = $host_name;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::host_name::value'}{variable_description}         = "striker_0017";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::host_name::value'}{variable_section}             = "config_step2";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_user::value'}{variable_value}            = "admin";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_user::value'}{variable_description}      = "striker_0032";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_user::value'}{variable_section}          = "config_step2";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_password::value'}{variable_value}        = $new_password;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_password::value'}{variable_description}  = "striker_0034";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::striker_password::value'}{variable_section}      = "config_step2";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::dns::value'}{variable_value}                     = $dns;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::dns::value'}{variable_description}               = "striker_0038";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::dns::value'}{variable_section}                   = "config_step2";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway::value'}{variable_value}                 = $gateway;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway::value'}{variable_description}           = "striker_0036";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway::value'}{variable_section}               = "config_step2";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway_interface::value'}{variable_value}       = $gateway_network;
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway_interface::value'}{variable_description} = "";
	$anvil->data->{striker}{stage1}{variables}{'form::config_step2::gateway_interface::value'}{variable_section}     = "config_step2";
	foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }});
		foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}})
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_number => $network_number }});
			if ((not defined $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip}) or (not $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip}))
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { 
					variable => "striker::${striker_number}::network::${network}::${network_number}::ip",
				}});
				$anvil->nice_exit({exit_code => 1});
			}
			elsif (not $anvil->Validate->ipv4({ip => $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip}}))
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0247", variables => { 
					variable => "striker::${striker_number}::network::${network}::${network_number}::ip", 
					value    => $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip},
				}});
				$anvil->nice_exit({exit_code => 1});
			}
			if ((not defined $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask}) or (not $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask}))
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { 
					variable => "striker::${striker_number}::network::${network}::${network_number}::subnet_mask",
				}});
				$anvil->nice_exit({exit_code => 1});
			}
			elsif (not $anvil->Validate->ipv4({ip => $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask}}))
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0247", variables => { 
					variable => "striker::${striker_number}::network::${network}::${network_number}::subnet_mask", 
					value    => $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask},
				}});
				$anvil->nice_exit({exit_code => 1});
			}
			if ((not defined $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{1}{mac}) or (not $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{1}{mac}))
			{
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { 
					variable => "striker::${striker_number}::network::${network}::${network_number}::link::1::mac",
				}});
				$anvil->nice_exit({exit_code => 1});
			}
			
			my $ip_key          = "form::config_step2::".$network.$network_number."_ip::value";
			my $ip              = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{ip};
			my $subnet_mask_key = "form::config_step2::".$network.$network_number."_subnet_mask::value";
			my $subnet_mask     = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{subnet_mask};
			my $link1_mac_key   = "form::config_step2::".$network.$network_number."_link1_mac_to_set::value";
			my $link1_mac       = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{1}{mac};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:ip_key'          => $ip_key, 
				's2:ip'              => $ip,
				's3:subnet_mask_key' => $subnet_mask_key, 
				's4:subnet_mask'     => $subnet_mask, 
				's4:link1_mac_key'   => $link1_mac_key, 
				's5:link1_mac'       => $link1_mac,
			}});
			
			$anvil->data->{striker}{stage1}{variables}{$ip_key}{variable_value}                = $ip;
			$anvil->data->{striker}{stage1}{variables}{$ip_key}{variable_description}          = "striker_0024";
			$anvil->data->{striker}{stage1}{variables}{$ip_key}{variable_section}              = "config_step2";
			$anvil->data->{striker}{stage1}{variables}{$subnet_mask_key}{variable_value}       = $subnet_mask;
			$anvil->data->{striker}{stage1}{variables}{$subnet_mask_key}{variable_description} = "striker_0025";
			$anvil->data->{striker}{stage1}{variables}{$subnet_mask_key}{variable_section}     = "config_step2";
			$anvil->data->{striker}{stage1}{variables}{$link1_mac_key}{variable_value}         = $link1_mac;
			$anvil->data->{striker}{stage1}{variables}{$link1_mac_key}{variable_description}   = "striker_0029";
			$anvil->data->{striker}{stage1}{variables}{$link1_mac_key}{variable_section}       = "config_step2";
			
			if (exists $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{2})
			{
				if ((not defined $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{2}{mac}) or (not $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{2}{mac}))
				{
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0243", variables => { 
						variable => "striker::${striker_number}::network::${network}::${network_number}::link::2::mac",
					}});
					$anvil->nice_exit({exit_code => 1});
				}
				my $link2_mac_key = "form::config_step2::".$network.$network_number."_link2_mac_to_set::value";
				my $link2_mac     = $anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{2}{mac};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:link2_mac_key' => $link2_mac_key, 
					's2:link2_mac'     => $link2_mac,
				}});
				$anvil->data->{striker}{stage1}{variables}{$link2_mac_key}{variable_value}       = $link2_mac;
				$anvil->data->{striker}{stage1}{variables}{$link2_mac_key}{variable_description} = "striker_0029";
				$anvil->data->{striker}{stage1}{variables}{$link2_mac_key}{variable_section}     = "config_step2";
			}
		}
	}
	
	# Now, for each variable, record it to the database.
	foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{striker}{stage1}{variables}})
	{
		my $value       = $anvil->data->{striker}{stage1}{variables}{$variable}{variable_value};
		my $description = $anvil->data->{striker}{stage1}{variables}{$variable}{variable_description};
		my $section     = $anvil->data->{striker}{stage1}{variables}{$variable}{variable_section};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:variable'    => $variable, 
			's2:value'       => $value,
			's3:description' => $description, 
			's4:section'     => $section,
		}});
		
		my ($variable_uuid) = $anvil->Database->insert_or_update_variables({
			variable_name         => $variable, 
			variable_value        => $value, 
			variable_default      => "", 
			variable_description  => $description, 
			variable_section      => $section, 
			variable_source_uuid  => $anvil->Get->host_uuid, 
			variable_source_table => "hosts", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }});
		
	}
	
	# Call anvil-configure-host now.
	my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
		debug           => 2,
		job_host_uuid   => $anvil->data->{cgi}{host_uuid}{value}, 
		job_command     => $anvil->data->{path}{exe}{'anvil-configure-host'}." --debug ".$anvil->Log->switches, 
		job_data        => "form::config_step2", 
		job_name        => "configure::network", 
		job_title       => "job_0001", 
		job_description => "job_0071", 
		job_progress    => 0,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
	
	# If we're striker 1, add a job to restart ourselves when ScanCore starts (after the reboot)
	if ($striker_number eq "1")
	{
		my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
			debug           => 2,
			job_host_uuid   => $anvil->data->{cgi}{host_uuid}{value}, 
			job_command     => $anvil->data->{path}{exe}{'striker-auto-initialize-all'}." --debug --config ".$anvil->data->{switches}{config}.$anvil->Log->switches, 
			job_data        => "", 
			job_name        => "configure::auto_initialize", 
			job_title       => "job_0225", 
			job_description => "job_0226", 
			job_status      => "anvil_startup",
			job_progress    => 0,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
	}
	
	return(0);
}

# This looks to see if we can map a 'striker::X::' to this machine.
sub find_myself
{
	my ($anvil) = @_;
	
	# Find my MAC addresses.
	my $short_host_name = $anvil->Get->short_host_name();
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { short_host_name => $short_host_name }});
	
	$anvil->Network->get_ips({debug => 3});
	
	$anvil->data->{i_am}{striker} = 0;
	foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$short_host_name}{interface}})
	{
		my $ip_address      = $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip};
		my $subnet_mask     = $anvil->data->{network}{$short_host_name}{interface}{$interface}{subnet_mask};
		my $mac_address     = $anvil->data->{network}{$short_host_name}{interface}{$interface}{mac_address};
		my $mtu             = $anvil->data->{network}{$short_host_name}{interface}{$interface}{mtu};
		my $default_gateway = $anvil->data->{network}{$short_host_name}{interface}{$interface}{default_gateway};
		my $gateway         = $anvil->data->{network}{$short_host_name}{interface}{$interface}{gateway};
		my $dns             = $anvil->data->{network}{$short_host_name}{interface}{$interface}{dns};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			interface       => $interface,
			ip_address      => $ip_address, 
			subnet_mask     => $subnet_mask, 
			mac_address     => $mac_address, 
			mtu             => $mtu, 
			default_gateway => $default_gateway,
			gateway         => $gateway, 
			dns             => $dns, 
		}});
		
		foreach my $striker_number (sort {$a cmp $b} keys %{$anvil->data->{striker}})
		{
			next if $striker_number !~ /^\d+$/;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { striker_number => $striker_number }});
			foreach my $network (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}})
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }});
				foreach my $network_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}})
				{
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_number => $network_number }});
					foreach my $link_number (sort {$a cmp $b} keys %{$anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}})
					{
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link_number => $link_number }});
						
						my $this_mac_address = lc($anvil->data->{striker}{$striker_number}{network}{$network}{$network_number}{'link'}{$link_number}{mac});
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							mac_address      => $mac_address, 
							this_mac_address => $this_mac_address,
						}});
						if ((not $anvil->data->{i_am}{striker}) && ($this_mac_address eq $mac_address))
						{
							# This is us.
							$anvil->data->{i_am}{striker} = $striker_number;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "i_am::striker" => $anvil->data->{i_am}{striker} }});
							return($anvil->data->{i_am}{striker});
						}
					}
				}
			}
		}
	}
	
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { i_am_striker => $anvil->data->{i_am}{striker} }});
	return($anvil->data->{i_am}{striker});
}


# If this is being called as a job, this will allow the progress to be updated.
sub update_progress
{
	my ($anvil, $progress, $message) = @_;

	$progress = 95 if $progress > 100;
	if (not $anvil->data->{switches}{'job-uuid'})
	{
		return(0);
	}
	
	$anvil->Job->update_progress({
		progress => $progress, 
		message  => $message,
		job_uuid => $anvil->data->{switches}{'job-uuid'},
	});
	
	return(0);
}
