#!/usr/bin/perl
# 
# This program is setuid 'admin' and calls a (new) peer to read its host name and system UUID. It takes the 
# target's password in via a file.
# 
# Exit codes;
# 0 = Normal exit.
# 1 = No database connection.
# 2 = Job UUID not passed and no unclaimed jobs found
# 3 = Job detauls not found in the database.
# 4 = Unable to connect to the target.
# 5 = Failed to install the anvil package.
# 6 = Failed to add our database to the target's anvil.conf file.
# 

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

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 => [
	"enterprise-uuid", 
	"host-ip-address", 
	"password", 
	"rh-password", 
	"rh-user", 
	"ssh-port", 
	"target", 
	"type"], 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 }});

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

$anvil->data->{job}{progress} = 0;
get_job_details($anvil);
wait_for_access($anvil);
set_host_name($anvil);
get_os_type($anvil);
add_repos($anvil);
configure_lvm($anvil);
add_databases($anvil);
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "job_0047"});
update_progress($anvil, 100, "job_0047");

$anvil->nice_exit({exit_code => 0});


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

# Get the 
sub get_os_type
{
	my ($anvil) = @_;
	
	($anvil->data->{data}{os_type}, $anvil->data->{data}{os_arch}) = $anvil->Get->os_type({
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root",
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"data::os_type" => $anvil->data->{data}{os_type}, 
		"data::os_arch" => $anvil->data->{data}{os_arch},
	}});
	
	return(0);
}

# This configures filtering on LVM
sub configure_lvm
{
	my ($anvil) = @_;
	
	my $problem = $anvil->Storage->manage_lvm_conf({
		debug       => 2,
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root",
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
	if ($problem)
	{
		$anvil->data->{job}{progress} += 5;
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0274"});
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0274");
	}
	else
	{
		$anvil->data->{job}{progress} += 5;
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0273"});
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0273");
	}
	
	# Check to see if we need to grow the PV.
	$anvil->data->{job}{progress} += 1;
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0341"});
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0341");
	my $shell_call = $anvil->data->{path}{exe}{'anvil-manage-host'}." --auto-grow-pv --confirm".$anvil->Log->switches;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	my ($output, $error, $return_code) = $anvil->Remote->call({
		debug       => 3,
		shell_call  => $shell_call, 
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root", 
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		error       => $error, 
		return_code => $return_code,
	}});
	
	return(0);
}

# Set the host name, if needed.
sub set_host_name
{
	my ($anvil) = @_;
	
	if ((not defined $anvil->data->{data}{host_name}) or (not $anvil->data->{data}{host_name}))
	{
		return(0);
	}
	$anvil->data->{job}{progress} += 5;
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0061", variables => { host_name => $anvil->data->{data}{host_name} }});
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0061,!!host_name!".$anvil->data->{data}{host_name}."!!");
	
	if (not $anvil->Validate->domain_name({name => $anvil->data->{data}{host_name}}))
	{
		# Bad host_name.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0062", variables => { host_name => $anvil->data->{data}{host_name} }});
		$anvil->data->{job}{progress} += 5;
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0062,!!host_name!".$anvil->data->{data}{host_name}."!!");
		return(1);
	}
	
	# Try to set the host name now.
	my ($host_name, $descriptive_host_name) = $anvil->System->host_name({
		debug       => 3, 
		set         => $anvil->data->{data}{host_name},
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root",
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		host_name             => $host_name,
		descriptive_host_name => $descriptive_host_name, 
	}});
	if ($host_name eq $anvil->data->{data}{host_name})
	{
		# Success!
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0034"});
		$anvil->data->{job}{progress} += 5;
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0034");
	}
	else
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0063", variables => { 
			host_name         => $anvil->data->{data}{host_name},
			current_host_name => $host_name, 
		}});
		$anvil->data->{job}{progress} += 5;
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0063,!!host_name!".$anvil->data->{data}{host_name}."!!,!!current_host_name!".$host_name."!!");
		return(1);
	}
	
	return(0);
}

# Add any databases we're using to the initialized host.
sub add_databases
{
	my ($anvil) = @_;
	
	# Normally, we'd use the BCN IPs to tell the peer how to reach our database, but it's entirely 
	# possible at this stage that the target doesn't have a BCN IP. So we need to figure out what IP it
	# has and we have that are on the same subnet. 
	# Scan our network and the target's network, then compare them.
	update_progress($anvil, ($anvil->data->{job}{progress} += 5), "job_0046");
	
	my $target = $anvil->data->{data}{host_ip_address};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target => $target }});
	
	$anvil->Network->get_ips({debug => 3});
	$anvil->Network->get_ips({
		debug       => 2,
		target      => $target,
		remote_user => "root",
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
	});
	my $local_host = $anvil->Get->short_host_name();
	my ($match)    = $anvil->Network->find_matches({
		debug  => 2,
		first  => $local_host,
		second => $target, 
		source => $THIS_FILE, 
		line   => __LINE__,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match => $match }});
	
	# We'll sort in reverse order, so if there is a BCN address, we'll use it.
	my $host_uuid   = $anvil->data->{sys}{host_uuid};
	my $db_host     = "";
	my $db_ping     = 1,
	my $db_port     = "";
	my $db_password = "";
	foreach my $interface (sort {$a cmp $b} keys %{$match->{$local_host}})
	{
		my $local_ip = $anvil->data->{network}{$local_host}{interface}{$interface}{ip};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			interface => $interface, 
			local_ip  => $local_ip,
		}});
		if (($local_ip) && ($anvil->Validate->ipv4({ip => $local_ip})))
		{
			$db_host     = $local_ip;
			$db_port     = $anvil->data->{database}{$host_uuid}{port};
			$db_password = $anvil->data->{database}{$host_uuid}{password};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				db_host     => $db_host,
				db_port     => $db_port, 
				db_password => $anvil->Log->is_secure($db_password),
			}});
		}
		last if $db_host;
	}
	
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { db_host => $db_host }});
	if ($db_host)
	{
		my $failed = $anvil->Database->manage_anvil_conf({
			debug        => 2, 
			target       => $target,
			remote_user  => "root",
			password     => $anvil->data->{data}{password}, 
			port         => $anvil->data->{data}{ssh_port}, 
			db_host_uuid => $anvil->data->{sys}{host_uuid}, 
			db_host      => $db_host,
			db_ping      => $db_ping, 
			db_port      => $db_port,
			db_password  => $db_password, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }});
		if ($failed)
		{
			# Something went wrong
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0076"});
			update_progress($anvil, 100, "error_0076");
			$anvil->nice_exit({exit_code => 6});
		}
		else
		{
			# Success! We're done!
			update_progress($anvil, $anvil->data->{job}{progress} += 5, "job_0047");
		}
	}
	else
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0084"});
		update_progress($anvil, 100, "error_0084");
		$anvil->nice_exit({exit_code => 6});
	}
	
	# Now add any peers we know about.
	foreach my $uuid (keys %{$anvil->data->{database}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:uuid'           => $uuid,
			's2:sys::host_uuid' => $anvil->data->{sys}{host_uuid},
		}});
		next if $uuid eq $anvil->data->{sys}{host_uuid};
		
		my $target_host = $anvil->Database->get_host_from_uuid({host_uuid => $uuid, short => 1});
		   $target_host = $target if not $target_host;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_host => $target_host }});
		
		update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0068,!!host_name!".$target_host."!!");
		
		# This is a peer.
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"database::${uuid}::host"     => $anvil->data->{database}{$uuid}{host},
			"database::${uuid}::port"     => $anvil->data->{database}{$uuid}{port},
			"database::${uuid}::password" => $anvil->Log->is_secure($anvil->data->{database}{$uuid}{password}),
			"database::${uuid}::ping"     => $anvil->data->{database}{$uuid}{ping},
		}});
		
		# The host being initialized may not be able to reach the 'host' as set in our config. So get the IPs
		# we know about for this host and see if we can find a match.
		my $peer_host     = "";
		my $peer_port     = $anvil->data->{database}{$uuid}{port};
		my $peer_ping     = $anvil->data->{database}{$uuid}{ping};
		my $peer_password = $anvil->data->{database}{$uuid}{password};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			peer_host     => $peer_host,
			peer_port     => $peer_port,
			peer_password => $anvil->Log->is_secure($peer_password),
			peer_ping     => $peer_ping,
		}});
		
		# Get the IP(s) for the Striker peer.
		$anvil->Network->load_ips({host_uuid => $uuid});
		
		# Find a match between the target and the peer.
		my ($match) = $anvil->Network->find_matches({
			debug  => 2,
			first  => $target,
			second => $uuid,
			source => $THIS_FILE, 
			line   => __LINE__,
		});
		my $keys = keys %{$match};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			match  => $match,
			'keys' => $keys,
		}});
		
		# Did we find a match?
		if ($keys)
		{
			# Yup!
			my $match_found = 0;
			foreach my $interface (sort {$a cmp $b} keys %{$match->{$uuid}})
			{
				# Get the IP
				$peer_host = $match->{$uuid}{$interface}{ip};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					interface => $interface, 
					peer_host => $peer_host,
				}});
				if ($peer_host)
				{
					my $failed = $anvil->Database->manage_anvil_conf({
						debug        => 2, 
						target       => $target,
						remote_user  => "root",
						password     => $anvil->data->{data}{password}, 
						port         => $anvil->data->{data}{ssh_port}, 
						db_host_uuid => $uuid, 
						db_host      => $peer_host,
						db_ping      => $peer_ping,
						db_port      => $peer_port,
						db_password  => $peer_password, 
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }});
					$anvil->data->{job}{progress} += 3;
					if ($failed)
					{
						# Something went wrong
						$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0076"});
						update_progress($anvil, $anvil->data->{job}{progress}, "job_0070");
					}
					else
					{
						# Success! We're done@
						$match_found = 1;
						update_progress($anvil, $anvil->data->{job}{progress}, "job_0034");
					}
					
					
					last;
				}
			}
			if (not $match_found)
			{
				# No (workable) match, not sure how this could happen though... Bug in 
				# 'Network->find_matches()'?
				$anvil->data->{job}{progress} += 3;
				update_progress($anvil, $anvil->data->{job}{progress}, "job_0069");
			}
		}
		else
		{
			# No match
			$anvil->data->{job}{progress} += 3;
			update_progress($anvil, $anvil->data->{job}{progress}, "job_0069");
		}
	}
	
	return(0);
}

# This adds this machine's repo, and if the internet is up on the target, we'll add the Anvil! repo as well.
sub add_repos
{
	my ($anvil) = @_;
	
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0028"});
	$anvil->data->{job}{progress} += 5;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0028");
	
	# Add the local repo.
	my $repo = $anvil->Striker->get_local_repo({debug => 2});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { repo => $repo }});
	
	# If this striker is an enterprise user, get the key for when we initialize targets.
	my $enterprise_key = "";
	if (-e $anvil->data->{path}{configs}{'alteeve-release.repo'})
	{
		# Read the file
		my $alteeve_repo = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'alteeve-release.repo'}});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alteeve_repo => $alteeve_repo }});
		foreach my $line (split/\n/, $alteeve_repo)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
			if ($line =~ /baseurl=.*?\/enterprise\/.*?\/(.*?)\//)
			{
				$enterprise_key = $1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { enterprise_key => $enterprise_key }});
				last;
			}
		}
	}
	
	# If the user set an enterprise key, use it, even if we found one on disk.
	if ($anvil->data->{data}{enterprise_uuid})
	{
		$enterprise_key = $anvil->data->{data}{enterprise_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"path::configs::alteeve-release.repo" => $anvil->data->{path}{configs}{'alteeve-release.repo'},
		}});
	}
	
	if ($repo)
	{
		# NOTE: We can't use Storage->write_file() because the target may not have 'rsync' installed
		#       yet.
		my $shell_call = "
".$anvil->data->{path}{exe}{cat}." > /etc/yum.repos.d/".$anvil->Get->short_host_name.".repo << EOF
$repo
EOF
";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		my ($output, $error, $return_code) = $anvil->Remote->call({
			debug       => 3, 
			shell_call  => $shell_call, 
			password    => $anvil->data->{data}{password}, 
			port        => $anvil->data->{data}{ssh_port}, 
			target      => $anvil->data->{data}{host_ip_address},
			remote_user => "root",
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			error       => $error,
			output      => $output,
			return_code => $return_code, 
		}});
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0029"});
		$anvil->data->{job}{progress} += 5;
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0029");
	}
	
	# If I have a Red Hat user and password, try to subscribe this system.
	if (($anvil->data->{data}{rh_user}) && ($anvil->data->{data}{rh_password}))
	{
		# If there's no internet, this will fail. If the network is up, we can see if the 
		# registration is still needed.
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0030"});
		$anvil->data->{job}{progress} += 5;
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0030");
		
		# We'll attach subscriptions if this is set
		my $subscribe  = 1;
		my $shell_call = $anvil->data->{path}{exe}{'subscription-manager'}." identity";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		my ($output, $error, $return_code) = $anvil->Remote->call({
			debug       => 3,
			shell_call  => $shell_call, 
			password    => $anvil->data->{data}{password}, 
			port        => $anvil->data->{data}{ssh_port}, 
			target      => $anvil->data->{data}{host_ip_address},
			remote_user => "root", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output, 
			error       => $error, 
			return_code => $return_code,
		}});
		if ($return_code eq "0")
		{
			# Already registered.
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0031"});
			$anvil->data->{job}{progress} += 5; 
			update_progress($anvil, $anvil->data->{job}{progress}, "job_0031");
		}
		elsif ($return_code eq "1")
		{
			# Registration is needed. This can take a while, so we give it a generous timeout.
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0033"});
			$anvil->data->{job}{progress} += 5;
			update_progress($anvil, $anvil->data->{job}{progress}, "job_0033");
			my $bash_password =  $anvil->data->{data}{rh_password};
			   $bash_password =~ s/'/\\\'/g;
			my $shell_call = $anvil->data->{path}{exe}{'subscription-manager'}." register --username ".$anvil->data->{data}{rh_user}." --password '".$bash_password."' --auto-attach --force";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			my ($output, $error, $return_code) = $anvil->Remote->call({
				debug       => 3,
				shell_call  => $shell_call,
				password    => $anvil->data->{data}{password}, 
				port        => $anvil->data->{data}{ssh_port}, 
				target      => $anvil->data->{data}{host_ip_address},
				remote_user => "root", 
				timeout     => 300,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output, 
				error       => $error, 
				return_code => $return_code,
			}});
			if ($return_code eq "70")
			{
				# No Internet (or can't reach the subscriion servers)
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0032"});
				$anvil->data->{job}{progress} += 5;
				update_progress($anvil, $anvil->data->{job}{progress}, "job_0032");
				$subscribe = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subscribe => $subscribe }});
			}
			elsif ($return_code)
			{
				# Something went wrong
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0035", variables => { 
					output      => $output, 
					error       => $error, 
					return_code => $return_code,
				}});
				$anvil->data->{job}{progress} += 5; 
				update_progress($anvil, $anvil->data->{job}{progress}, "job_0035,!!return_code!".$return_code."!!,!!output!".$output."!!,!!error!".$error."!!");
				$subscribe = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subscribe => $subscribe }});
			}
			else
			{
				# Success!
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0034"});
				$anvil->data->{job}{progress} += 5;
				update_progress($anvil, $anvil->data->{job}{progress}, "job_0034");
			}
		}
		elsif ($return_code eq "70")
		{
			# No Internet (or can't reach the subscriion servers)
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0032"});
			$anvil->data->{job}{progress} += 5;
			update_progress($anvil, $anvil->data->{job}{progress}, "job_0032");
			$subscribe = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subscribe => $subscribe }});
		}
		
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subscribe => $subscribe }});
		if ($subscribe)
		{
			# We're going to need these repos when it's all said and done. The first two are 
			# enabled by default.
			if ($anvil->data->{data}{os_type} eq "rhel9")
			{
				$anvil->data->{repos}{'rhel-9-for-x86_64-baseos-rpms'}            = 0;
				$anvil->data->{repos}{'rhel-9-for-x86_64-appstream-rpms'}         = 0;
				$anvil->data->{repos}{'codeready-builder-for-rhel-9-x86_64-rpms'} = 0;
				$anvil->data->{repos}{'rhel-9-for-x86_64-highavailability-rpms'}  = 0;
			}
			elsif ($anvil->data->{data}{os_type} eq "rhel8")
			{
				$anvil->data->{repos}{'rhel-8-for-x86_64-baseos-rpms'}            = 0;
				$anvil->data->{repos}{'rhel-8-for-x86_64-appstream-rpms'}         = 0;
				$anvil->data->{repos}{'codeready-builder-for-rhel-8-x86_64-rpms'} = 0;
				$anvil->data->{repos}{'rhel-8-for-x86_64-highavailability-rpms'}  = 0;
			}
			
			foreach my $repo (sort {$a cmp $b} keys %{$anvil->data->{repos}})
			{
				### NOTE: Not true, until we cache RPMs on Striker, we'll need to install HA 
				###       on all hosts to get fence agents.
				# Both target types need 'codeready-builder', but only nodes need 'highavailability-rpms'
				# We blindly subscribe, then we'll check that they're actually subscribed.
				#if (($repo =~ /highavailability-rpms/) && ($anvil->data->{data}{type} ne "node"))
				if (0)
				{
					$anvil->data->{repos}{$repo} = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"repos::${repo}" => $anvil->data->{repos}{$repo},
					}});
					next;
				}
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0036", variables => { repo => $repo }});
				$anvil->data->{job}{progress} += 5;
				update_progress($anvil, $anvil->data->{job}{progress}, "job_0036,!!repo!codeready-builder-for-rhel-8-x86_64-rpms!!");
				
				my $shell_call = $anvil->data->{path}{exe}{'subscription-manager'}." repos --enable ".$repo;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
				my ($output, $error, $return_code) = $anvil->Remote->call({
					debug       => 3,
					shell_call  => $shell_call,
					password    => $anvil->data->{data}{password}, 
					port        => $anvil->data->{data}{ssh_port}, 
					target      => $anvil->data->{data}{host_ip_address},
					remote_user => "root", 
					timeout     => 300,
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output, 
					error       => $error, 
					return_code => $return_code,
				}});
			}
			
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0037"});
			$anvil->data->{job}{progress} += 5;
			update_progress($anvil, $anvil->data->{job}{progress}, "job_0037");
			undef $output;
			undef $error;
			undef $return_code;
			undef $shell_call;
			$shell_call = $anvil->data->{path}{exe}{'subscription-manager'}." repos --list-enabled";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			($output, $error, $return_code) = $anvil->Remote->call({
				debug       => 3,
				shell_call  => $shell_call,
				password    => $anvil->data->{data}{password}, 
				port        => $anvil->data->{data}{ssh_port}, 
				target      => $anvil->data->{data}{host_ip_address},
				remote_user => "root", 
				timeout     => 300,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output, 
				error       => $error, 
				return_code => $return_code,
			}});
			foreach my $line (split/\n/, $output)
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
				if ($line =~ /Repo ID:\s+(.*)$/i)
				{
					my $repo = $1;
					$anvil->data->{repos}{$repo} = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "repos::${repo}" => $anvil->data->{repos}{$repo} }});
				}
			}
			
			# Are any still missing?
			foreach my $repo (sort {$a cmp $b} keys %{$anvil->data->{repos}})
			{
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "repos::${repo}" => $anvil->data->{repos}{$repo} }});
				if (not $anvil->data->{repos}{$repo})
				{
					# Well this is a problem...
					$anvil->data->{job}{progress} += 5;
					update_progress($anvil, $anvil->data->{job}{progress}, "job_0038,!!repo!".$repo."!!");
					$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0038", variables => { repo => $repo }});
				}
			}
		}
	}
	if ($anvil->data->{data}{os_type} !~ /rhel/)
	{
		# Enable the HA repo
		my $shell_call = $anvil->data->{path}{exe}{yum}." config-manager --set-enabled ha";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		my ($output, $error, $return_code) = $anvil->Remote->call({
			debug       => 3, 
			shell_call  => $shell_call, 
			password    => $anvil->data->{data}{password}, 
			port        => $anvil->data->{data}{ssh_port}, 
			target      => $anvil->data->{data}{host_ip_address},
			remote_user => "root",
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			error       => $error,
			output      => $output,
			return_code => $return_code, 
		}});
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0224"});
		$anvil->data->{job}{progress} += 2;
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0224");
	}
	
	### NOTE: This seems dumb without internet, but it's worth calling anyway in case the repo on the 
	###       Striker has newer packages. If we go right to installing packages and one of them is newer
	###       than an installed dependency, the install could fail. This prevents that.
	# Call an OS update.
	$anvil->data->{job}{progress} += 5;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0039");
	$anvil->data->{job}{progress} += 5;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0040");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0039"});
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0040"});
	
	my $shell_call = $anvil->data->{path}{exe}{'dnf'}." -y update";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	my ($output, $error, $return_code) = $anvil->Remote->call({
		debug       => 3,
		shell_call  => $shell_call,
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root", 
		timeout     => 3600,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		error       => $error, 
		return_code => $return_code,
	}});
	
	# Now remove biosdevname, if this is an EL8 machine
	if ($anvil->data->{data}{os_type} =~ /8$/)
	{
		$anvil->data->{job}{progress} += 5;
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0041");
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0041"});
		undef $output;
		undef $error;
		undef $return_code;
		undef $shell_call;
		$shell_call = $anvil->data->{path}{exe}{'dnf'}." -y remove biosdevname";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		($output, $error, $return_code) = $anvil->Remote->call({
			debug       => 3,
			shell_call  => $shell_call,
			password    => $anvil->data->{data}{password}, 
			port        => $anvil->data->{data}{ssh_port}, 
			target      => $anvil->data->{data}{host_ip_address},
			remote_user => "root", 
			timeout     => 300,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output, 
			error       => $error, 
			return_code => $return_code,
		}});
	}
	
	# In the CI, we'll have custom repos installed. So here we're looking to see if 'anvil-X' is already 
	# installed. If so, we won't add our repo.
	my $anvil_role_rpm = "";
	my $alteeve_repo   = 0;
	undef $output;
	undef $error;
	undef $return_code;
	undef $shell_call;
	$shell_call = $anvil->data->{path}{exe}{'dnf'}." list installed";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	($output, $error, $return_code) = $anvil->Remote->call({
		debug       => 3,
		shell_call  => $shell_call,
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root", 
		timeout     => 300,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
		output      => $output, 
		error       => $error, 
		return_code => $return_code,
	}});
	foreach my $line (split/\n/, $output)
	{
		next if $line =~ /Installed Packages/i;
		$line =~ s/\s.*$//;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
		
		next if $line =~ /anvil-core/;
		if ($line =~ /alteeve-release.noarch/)
		{
			$alteeve_repo = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alteeve_repo => $alteeve_repo }});
		}
		if ($line =~ /anvil-(.*).noarch/)
		{
			$anvil_role_rpm = $1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_role_rpm => $anvil_role_rpm }});
		}
		last if $anvil_role_rpm && $alteeve_repo;
	}
	
	# Install the Alteeve repo, if possible. There may be no Internet access, so it's OK if this fails.
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		alteeve_repo   => $alteeve_repo,
		anvil_role_rpm => $anvil_role_rpm,
	}});
	if (not $alteeve_repo)
	{
		if ($anvil_role_rpm)
		{
			# There's already an anvil RPM installed, so we're going to skip installing the repo.
			# Warn the user though.
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0042", variables => { 
				anvil_role_rpm => $anvil_role_rpm,
				alteeve_repo   => $anvil->data->{path}{urls}{alteeve_repo},
			}});
		}
		else
		{
			my ($alteeve_access) = $anvil->Network->check_internet({
				debug       => 2,
				domains     => ["alteeve.com"],
				password    => $anvil->data->{data}{password}, 
				port        => $anvil->data->{data}{ssh_port}, 
				target      => $anvil->data->{data}{host_ip_address},
				remote_user => "root", 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { alteeve_access => $alteeve_access }});
			if ($alteeve_access)
			{
				$shell_call = $anvil->data->{path}{exe}{'dnf'}." -y install ".$anvil->data->{path}{urls}{alteeve_repo};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
				($output, $error, $return_code) = $anvil->Remote->call({
					debug       => 3,
					shell_call  => $shell_call,
					password    => $anvil->data->{data}{password}, 
					port        => $anvil->data->{data}{ssh_port}, 
					target      => $anvil->data->{data}{host_ip_address},
					remote_user => "root", 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output, 
					error       => $error, 
					return_code => $return_code,
				}});
			}
		}
	}
	
	# Do we need to activate the Alteeve repo?
	if (not -e $anvil->data->{path}{configs}{'alteeve-release.repo'})
	{
		# We now need to configure the repo.
		my $shell_call = $anvil->data->{path}{exe}{'alteeve-repo-setup'}." --yes";
		if ($enterprise_key)
		{
			$shell_call = $anvil->data->{path}{exe}{'alteeve-repo-setup'}." --key ".$enterprise_key." --yes";
		}
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		my ($output, $error, $return_code) = $anvil->Remote->call({
			debug       => 2,
			shell_call  => $shell_call,
			password    => $anvil->data->{data}{password}, 
			port        => $anvil->data->{data}{ssh_port}, 
			target      => $anvil->data->{data}{host_ip_address},
			remote_user => "root", 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output, 
			error       => $error, 
			return_code => $return_code,
		}});
	}
	
	# If the target is RHEL, make sure they enable the needed add-ons.
	$anvil->data->{job}{progress}++;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0260");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0260"});
	my ($os_type, $os_arch) = $anvil->Get->os_type({
		debug       => 2,
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root", 
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		os_type => $os_type, 
		os_arch => $os_arch,
	}});
	
	my $package = $anvil->data->{data}{type} eq "dr" ? "anvil-dr" : "anvil-node";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'package' => $package }});
	if ($os_type =~ /rhel(\d+)/)
	{
		my $version = $1;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { version => $version }});
		
		my $ha_repo                                        = "rhel-".$version."-for-x86_64-highavailability-rpms"; 
		my $codeready_repo                                 = "codeready-builder-for-rhel-".$version."-x86_64-rpms";
		   $anvil->data->{repos}{$ha_repo}{enabled}        = 1;
		   $anvil->data->{repos}{$codeready_repo}{enabled} = 1;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"repos::${ha_repo}::enabled"        => $anvil->data->{repos}{$ha_repo}{enabled},
			"repos::${codeready_repo}::enabled" => $anvil->data->{repos}{$codeready_repo}{enabled},
		}});
		
		# Get the list of repos.
		my $repo_id    = "";
		my $shell_call = $anvil->data->{path}{exe}{'subscription-manager'}." repos";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		my ($output, $error, $return_code) = $anvil->Remote->call({
			debug       => 2,
			shell_call  => $shell_call,
			password    => $anvil->data->{data}{password}, 
			port        => $anvil->data->{data}{ssh_port}, 
			target      => $anvil->data->{data}{host_ip_address},
			remote_user => "root", 
			timeout     => 3600,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output, 
			error       => $error, 
			return_code => $return_code,
		}});
		
		my $this_repo = "";
		foreach my $line (split/\n/, $output)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
			if ($line =~ /Repo ID:\s+(.*)/)
			{
				$this_repo = $1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_repo => $this_repo }});
			}
			if ($line =~ /Enabled:\s+(\d)/)
			{
				$anvil->data->{repos}{$this_repo}{enabled} = $1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "repos::${this_repo}::enabled" => $anvil->data->{repos}{$this_repo}{enabled} }});
			}
		}
		
		# All systems need code-ready, subnodes only need HA
		foreach my $repo ($codeready_repo, $ha_repo)
		{
			next if (($package ne "anvil-node") && ($repo eq $ha_repo));
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"repos::${repo}::enabled" => $anvil->data->{repos}{$repo}{enabled}, 
			}});
			if (not $anvil->data->{repos}{$repo}{enabled})
			{
				# Enable the repo.
				$anvil->data->{job}{progress}++;
				update_progress($anvil, $anvil->data->{job}{progress}, "job_0340,!!repo!".$repo."!!");
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0340", variables => { repo => $repo }});
				
				my $shell_call = $anvil->data->{path}{exe}{'subscription-manager'}." repos --enable ".$repo;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
				my ($output, $error, $return_code) = $anvil->Remote->call({
					debug       => 2,
					shell_call  => $shell_call,
					password    => $anvil->data->{data}{password}, 
					port        => $anvil->data->{data}{ssh_port}, 
					target      => $anvil->data->{data}{host_ip_address},
					remote_user => "root", 
					timeout     => 3600,
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output, 
					error       => $error, 
					return_code => $return_code,
				}});
			}
		}
	}
	
	# Install the anvil package now.
	$anvil->data->{job}{progress} += 5;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0042,!!package!".$package."!!");
	$anvil->data->{job}{progress} += 5;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0040");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0042", variables => { 'package' => $package }});
	undef $output;
	undef $error;
	undef $return_code;
	undef $shell_call;
	$shell_call = $anvil->data->{path}{exe}{'dnf'}." -y install ".$package;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	($output, $error, $return_code) = $anvil->Remote->call({
		debug       => 2,
		shell_call  => $shell_call,
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root", 
		timeout     => 3600,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		error       => $error, 
		return_code => $return_code,
	}});
	
	# Check if the install failed because of missing add-on subscriptions.
	if ($error)
	{
		foreach my $line (split/\n/, $error)
		{
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
			if (($line =~ /nothing provides pcs/) or ($line =~ /nothing provides pacemaker/))
			{
				# Missing HA Add-on
				update_progress($anvil, 100, "error_0497,!!error!".$error."!!");
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0497", variables => { error => $error }});
				$anvil->nice_exit({exit_code => 6});
			}
		}
	}
	
	$anvil->data->{job}{progress} += 5;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0043");
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0043"});
	undef $output;
	undef $error;
	undef $return_code;
	undef $shell_call;
	$shell_call = $anvil->data->{path}{exe}{'dnf'}." list installed ".$package;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	($output, $error, $return_code) = $anvil->Remote->call({
		debug       => 3,
		shell_call  => $shell_call,
		password    => $anvil->data->{data}{password}, 
		port        => $anvil->data->{data}{ssh_port}, 
		target      => $anvil->data->{data}{host_ip_address},
		remote_user => "root", 
		timeout     => 3600,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output, 
		error       => $error, 
		return_code => $return_code,
	}});
	# The return code of '0' means found, '1' means not found
	if ($return_code)
	{
		# Failed...
		update_progress($anvil, 100, "job_0044");
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0044"});
		$anvil->nice_exit({exit_code => 6});
	}
	else
	{
		# Found it!
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0045"});
		$anvil->data->{job}{progress} += 5;
		update_progress($anvil, $anvil->data->{job}{progress}, "job_0045");
	}
	
	return(0);
}

# This goes into a loop until the target is accessible.
sub wait_for_access
{
	my ($anvil) = @_;
	
	### NOTE: If the machine is being rebuilt, the host key is likely to have changed. If we fail to 
	###       connect because of a bad host key, ignore the host key and see if we can connect using the
	###       given password. If so, update the key.
	### TODO: How secure is this? In theory, a user can't request to initialize a host without already
	###       having access, so an attacker shouldn't be able to call this without already being 
	###       authenticated.
	# Test access
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0023", variables => { target => $anvil->data->{data}{say_target} }});
	$anvil->data->{job}{progress} += 5;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0023,!!target!".$anvil->data->{data}{say_target}."!!");
	$anvil->data->{job}{progress} += 5;
	my $waiting    = 1;
	my $access     = 0;
	my $timeout    = time + 600;
	my $check_keys = 1;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { timeout => $timeout, 'time' => time }});
	while ($waiting)
	{
		$access = $anvil->Remote->test_access({
			password => $anvil->data->{data}{password}, 
			port     => $anvil->data->{data}{ssh_port}, 
			target   => $anvil->data->{data}{host_ip_address},
			user     => "root",
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});

		if ($access)
		{
			$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0024"});
			$anvil->data->{job}{progress} += 5;
			update_progress($anvil, $anvil->data->{job}{progress}, "job_0024");
			$waiting = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
		}
		else
		{
			my $time_left = $timeout - time;
			if ($time_left < 0)
			{
				$waiting = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
			}
			else
			{
				if ($check_keys)
				{
					my $bad_key = "";
					my $query   = "
SELECT 
    state_uuid, 
    state_note 
FROM 
    states 
WHERE 
    state_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." 
AND 
    state_name      = ".$anvil->Database->quote("host_key_changed::".$anvil->data->{data}{host_ip_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, 
					}});
					foreach my $row (@{$results})
					{
						my $state_uuid = $row->[0];
						my $state_note = $row->[1];
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							state_uuid => $state_uuid, 
							state_note => $state_note, 
						}});
						
						if ($state_note =~ /key=(.*?)$/)
						{
							$bad_key = $1;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_key => $bad_key }});
						}
					}
					
					if ($bad_key)
					{
						# Delete they key.
						my $job_uuid = $anvil->Database->insert_or_update_jobs({
							debug           => 2,
							file            => $THIS_FILE, 
							line            => __LINE__, 
							job_title       => "job_0056",
							job_description => "job_0057",
							job_host_uuid   => $anvil->Get->host_uuid, 
							job_data        => "bad_key=".$bad_key,
							job_command     => $anvil->data->{path}{exe}{'anvil-manage-keys'}.$anvil->Log->switches, 
							job_name        => "manage::broken_keys", 
							job_progress    => 0,
						});
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
					}
					
					$check_keys = 0;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { check_keys => $check_keys }});
				}
				
				$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0025", variables => {
					target  => $anvil->data->{data}{say_target},
					timeout => $time_left, 
				}});
				update_progress($anvil, $anvil->data->{job}{progress}, "job_0025,!!target!".$anvil->data->{data}{say_target}."!!,!!timeout!".$time_left."!!");
				sleep 5;
			}
		}
	}
	
	if (not $access)
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "job_0026"});
		update_progress($anvil, 100, "job_0026");
		$anvil->nice_exit({exit_code => 3});
	}
	
	return(0);
}

# This picks up the details for the job, so we know who to connect to.
sub get_job_details
{
	my ($anvil) = @_;
	
	# If we don't have a job-uuid, try to find one.
	if (not $anvil->data->{switches}{'job-uuid'})
	{
		my $return = $anvil->Database->get_jobs();
		foreach my $hash_ref (@{$return})
		{
			my $job_command  = $hash_ref->{job_command};
			my $job_progress = $hash_ref->{job_progress};
			my $job_uuid     = $hash_ref->{job_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
				job_command  => $job_command,
				job_progress => $job_progress,
				job_uuid     => $job_uuid, 
			}});
			next if $job_command ne $anvil->data->{path}{exe}{$THIS_FILE};
			next if $job_progress;
			
			# Still alive? found it!
			$anvil->data->{switches}{'job-uuid'} = $job_uuid;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'} }});
			last;
		}
	}
	
	my $return = 0;
	if ($anvil->data->{switches}{'job-uuid'})
	{
		$return = $anvil->Database->get_job_details({debug => 3, job_uuid => $anvil->data->{switches}{'job-uuid'}});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'return' => $return }});
	}

	# If the user used '--target', but not '--host-ip-address', set it.
	if ((not $anvil->data->{switches}{'host-ip-address'}) && ($anvil->data->{switches}{'target'}))
	{
		$anvil->data->{switches}{'host-ip-address'} = $anvil->data->{switches}{'target'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			'switches::host-ip-address' => $anvil->data->{switches}{'host-ip-address'},
		}});
	}
	
	# Set up all possible variables.
	$anvil->data->{data}{enterprise_uuid} = "";
	$anvil->data->{data}{host_ip_address} = "";
	$anvil->data->{data}{password}        = "";
	$anvil->data->{data}{rh_password}     = "";
	$anvil->data->{data}{rh_user}         = "";
	$anvil->data->{data}{ssh_port}        = "";
	$anvil->data->{data}{type}            = "";
	$anvil->data->{jobs}{job_uuid}        = "";
	
	# If we have a job_uuid, load the data.
	if ($return)
	{
		$anvil->data->{jobs}{job_uuid}    = $anvil->data->{switches}{'job-uuid'};
		$anvil->data->{jobs}{job_command} = $return->{job_command};
		$anvil->data->{jobs}{job_data}    = $return->{job_data};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
			'jobs::job_uuid'    => $anvil->data->{jobs}{job_uuid},
			'jobs::job_command' => $anvil->data->{jobs}{job_command},
			'jobs::job_data'    => $anvil->Log->is_secure($anvil->data->{jobs}{job_data}),
		}});
		
		foreach my $line (split/\n/, $anvil->data->{jobs}{job_data})
		{
			my $secure = $line =~ /passw/ ? 1 : 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => $secure, list => { line => $line }});
			
			my ($variable, $value) = ($line =~ /^(.*?)=(.*)$/);
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 
				variable => $variable,
				value    => $secure ? $anvil->Log->is_secure($value) : $value,
			}});
			
			$anvil->data->{data}{$variable} = $value;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"data::${variable}" => $secure ? $anvil->Log->is_secure($anvil->data->{data}{$variable}) : $anvil->data->{data}{$variable},
			}});
		}
	}

	# In job data: if 'target' is set, but not 'host_ip_address', set it.
	if ((not $anvil->data->{data}{host_ip_address}) && ($anvil->data->{data}{target}))
	{
		$anvil->data->{data}{host_ip_address} = $anvil->data->{data}{target};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
			"data::host_ip_address" => $anvil->data->{data}{host_ip_address},
		}});
	}

	# If the user set command line switches, they will override the values read from the job.
	if ($anvil->data->{switches}{'enterprise-uuid'})
	{
		$anvil->data->{data}{enterprise_uuid} = $anvil->data->{switches}{'enterprise-uuid'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"data::enterprise_uuid" => $anvil->data->{data}{enterprise_uuid},
		}});
	}
	if ($anvil->data->{switches}{'host-ip-address'})
	{
		$anvil->data->{data}{host_ip_address} = $anvil->data->{switches}{'host-ip-address'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"data::host_ip_address" => $anvil->data->{data}{host_ip_address},
		}});
	}
	if ($anvil->data->{switches}{'password'})
	{
		$anvil->data->{data}{password} = $anvil->data->{switches}{'password'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"data::password" => $anvil->Log->is_secure($anvil->data->{data}{password}),
		}});
	}
	if ($anvil->data->{switches}{'rh-password'})
	{
		$anvil->data->{data}{rh_password} = $anvil->data->{switches}{'rh-password'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"data::rh_password" => $anvil->Log->is_secure($anvil->data->{data}{rh_password}),
		}});
	}
	if ($anvil->data->{switches}{'rh-user'})
	{
		$anvil->data->{data}{rh_user} = $anvil->data->{switches}{'rh-user'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"data::rh_user" => $anvil->data->{data}{rh_user},
		}});
	}
	if ($anvil->data->{switches}{'ssh-port'})
	{
		$anvil->data->{data}{ssh_port} = $anvil->data->{switches}{'ssh-port'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"data::ssh_port" => $anvil->data->{data}{ssh_port},
		}});
	}
	if ($anvil->data->{switches}{'type'})
	{
		$anvil->data->{data}{type} = $anvil->data->{switches}{'type'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"data::type" => $anvil->data->{data}{type},
		}});
	}
	
	### Sanity checks.
	my $problem = 0;
	# Good type?
	if (($anvil->data->{data}{type} ne "node") && ($anvil->data->{data}{type} ne "dr"))
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0377", variables => { type => $anvil->data->{data}{type} }});
		update_progress($anvil, 100, "error_0377,!!type!".$anvil->data->{data}{type}."!!");
		$anvil->nice_exit({exit_code => 1});
	}
	# Valid enterprise UUID?
	if (($anvil->data->{data}{enterprise_uuid}) && (not $anvil->Validate->uuid({uuid => $anvil->data->{data}{enterprise_uuid}})))
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0378", variables => { uuid => $anvil->data->{data}{$anvil->data->{data}{enterprise_uuid}} }});
		update_progress($anvil, 100, "error_0378,!!uuid!".$anvil->data->{data}{enterprise_uuid}."!!");
		$anvil->nice_exit({exit_code => 1});
	}
	if (not $anvil->data->{data}{host_ip_address})
	{
		$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0379"});
		update_progress($anvil, 100, "error_0379");
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Create our target
	$anvil->data->{data}{say_target} = "root\@".$anvil->data->{data}{host_ip_address};
	if (($anvil->data->{data}{ssh_port}) && ($anvil->data->{data}{ssh_port} != 22))
	{
		$anvil->data->{data}{say_target} .= ":".$anvil->data->{data}{ssh_port};
	}
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"data::say_target" => $anvil->data->{data}{say_target},
	}});
	
	# Update that we've picked the job up.
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "job_0027", variables => { 'job-uuid' => $anvil->data->{switches}{'job-uuid'} }});
	update_progress($anvil, 0, "clear");
	$anvil->data->{job}{progress} += 5;
	update_progress($anvil, $anvil->data->{job}{progress}, "job_0027,!!job-uuid!".$anvil->data->{switches}{'job-uuid'}."!!");
	
	return(0);
}

# 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'})
	{
		if ($anvil->data->{jobs}{job_uuid})
		{
			$anvil->data->{switches}{'job-uuid'} = $anvil->data->{jobs}{job_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"switches::job-uuid" => $anvil->data->{switches}{'job-uuid'},
			}});
		}
		else
		{
			# Just return.
			return(0);
		}
	}
	
	$anvil->Job->update_progress({
		debug    => 3,
		progress => $progress, 
		message  => $message,
		job_uuid => $anvil->data->{switches}{'job-uuid'},
	});
	
	return(0);
}
