#!/usr/bin/perl
# 
# This program will manage servers; Changing RAM, CPU cores, Growing virtual disks, adding virtual disks, 
# inserting and ejecting ISO images into virtual optical media.
# 
# Exit codes;
# 0 = Normal exit.
# 1 = No database connection.
# 
# USAGE:
# - Show
#   - anvil-manage-server-storage --server srv01-fs37
# - ISO
#   - anvil-manage-server-storage --server srv01-fs37 --optical sda --insert /mnt/shared/files/CentOS-5.11-x86_64-bin-DVD-1of2.iso
#   - anvil-manage-server-storage --server srv01-fs37 --optical sda --eject
# - Disk
#   - anvil-manage-server-storage --server srv01-fs37 --disk vdb --grow {+10%,150GiB}
#   - anvil-manage-server-storage --server srv01-fs37 --add 50G --storage-group "Storage group 1"
# 

use strict;
use warnings;
use Anvil::Tools;
require POSIX;
use Term::Cap;
use Text::Diff;
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
$anvil->Get->switches({list => [
	"add", 
	"anvil", 
	"ci-test", 
	"confirm", 
	"disk", 
	"eject", 
	"job-uuid", 
	"grow", 
	"insert", 
	"machine",
	"optical", 
	"server", 
	"storage-group", 
	], 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). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks
# is to setup the database server.
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
	# No databases, update the job, sleep for a bit and then exit. The daemon will pick it up and try 
	# again after we exit.
	$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0305"});
	sleep 10;
	$anvil->nice_exit({exit_code => 1});
}

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

if ($anvil->data->{switches}{'ci-test'})
{
	$anvil->data->{switches}{confirm} = "#!SET!#";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"switches::confirm" => $anvil->data->{switches}{confirm},
	}});
}

$anvil->Database->get_hosts();
$anvil->Database->get_anvils();
$anvil->Database->get_servers();
$anvil->Database->get_dr_links();

if ($anvil->data->{switches}{anvil})
{
	# Make sure they asked for a real anvil.
	$anvil->Get->anvil_from_switch({string => $anvil->data->{switches}{anvil}});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"switches::anvil_name" => $anvil->data->{switches}{anvil_name},
		"switches::anvil_uuid" => $anvil->data->{switches}{anvil_uuid},
	}});
}

if (not $anvil->data->{switches}{server})
{
	# Show the list of servers.
	show_server_list($anvil);
	$anvil->Job->update_progress({
		progress => 100,
		message  => "error_0456", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		priority  => "err",
	});
	$anvil->nice_exit({exit_code => 0});
}

validate_server($anvil);

if (($anvil->data->{switches}{optical}) or ($anvil->data->{switches}{eject}))
{
	manage_optical($anvil);
}
elsif (($anvil->data->{switches}{disk}) or ($anvil->data->{switches}{add}))
{
	manage_disk($anvil);
}
else
{
	show_server_details($anvil, 1);
}

# If we connected a peer, take it down.
if (exists $anvil->data->{connected_resource})
{
	my $short_host_name = $anvil->Get->short_host_name;
	my $server_name     = $anvil->data->{switches}{server_name};
	foreach my $peer_name (sort {$a cmp $b} keys %{$anvil->data->{connected_resource}})
	{
		# We need to connect the DRBD resource
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 1}),
			message   => "job_0092", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			variables => {
				host_name => $peer_name, 
			},
		});
		
		my $target_ip   = $anvil->data->{peer}{$peer_name}{access}{ip};
		my $shell_call  = $anvil->data->{path}{exe}{drbdsetup}." status ".$server_name." || ".$anvil->data->{path}{exe}{drbdadm}." down ".$server_name;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:server_name' => $server_name, 
			's2:target_ip'   => $target_ip, 
			's3:shell_call'  => $shell_call,
		}});
		my ($output, $error, $return_code) = $anvil->Remote->call({
			target     => $target_ip, 
			shell_call => $shell_call,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			error       => $error,
			output      => $output,
			return_code => $return_code, 
		}});
	}
}

$anvil->Job->update_progress({
	progress => 100,
	message  => "job_0281", 
	log_level => 1, 
	'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
});
$anvil->nice_exit({exit_code => 0});


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

sub load_storage
{
	my ($anvil) = @_;
	
	# Host and server
	my $short_host_name = $anvil->Get->short_host_name;
	my $server_name     = $anvil->data->{switches}{server_name};
	
	# We need to know which volume groups the disks are on so that we can report how much free space is 
	# available for either growing or adding a disk.
	$anvil->Get->available_resources({
		debug      => 2,
		anvil_uuid => $anvil->data->{switches}{anvil_uuid},
	});
	
	# Load LVM and Storage Group data
	$anvil->Database->get_lvm_data({debug => 2});
	
	# Load DRBD data from the database.
	$anvil->Database->get_drbd_data({debug => 2});
	
	# Load DRBD resource data so that we can map DRBD resources / volumes to volume groups.
	my $drbd_resource = "";
	foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{device}})
	{
		my $on_lv         = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv};
		   $drbd_resource = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{resource};
		my $device_target = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{target};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:device_path'   => $device_path, 
			's2:on_lv'         => $on_lv,
			's3:drbd_resource' => $drbd_resource, 
			's4:device_target' => $device_target, 
		}});
	}
	# There should only ever be one, but it's not impossible for there to be multiple.
	foreach my $drbd_resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{drbd}{resource}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }});
		
		# Get the DRBD volume data
		load_drbd_data($anvil, $drbd_resource);
	}
	
	return($drbd_resource);
}

sub manage_disk
{
	my ($anvil) = @_;
	
	my $anvil_uuid      = defined $anvil->data->{switches}{anvil_uuid} ? $anvil->data->{switches}{anvil_uuid} : "";
	my $short_host_name = $anvil->Get->short_host_name;
	my $server_name     = $anvil->data->{switches}{server_name};
	my $server_uuid     = $anvil->data->{switches}{server_uuid};
	my $from_source     = get_definition_source($anvil);
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		anvil_uuid      => $anvil_uuid, 
		short_host_name => $short_host_name,
		server_name     => $server_name, 
		server_uuid     => $server_uuid, 
		from_source     => $from_source, 
	}});
	
	if (not $anvil_uuid)
	{
		$anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
	}
	
	if (not $anvil->data->{switches}{disk})
	{
		# If there's only one disk drive, select it automatically
		my $count = keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		if ($count == 1)
		{
			foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}})
			{
				$anvil->data->{switches}{disk} = $device_target;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"switches::drive" => $anvil->data->{switches}{disk},
				}});
				last;
			}
		}
		
		if (not $anvil->data->{switches}{disk})
		{
			# Can't proceed.
			show_server_details($anvil, 1);
			$anvil->Job->update_progress({
				progress => 100,
				message  => "error_0457", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
			});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	# Are they asking for an available amount of space?
	my $say_up   = $anvil->Words->string({key => 'message_0331'});
	my $say_down = $anvil->Words->string({key => 'message_0332'});
	
	### TODO: Make this work without the peer node being online.
	# The server is allowed to be running, but both nodes and any DR hosts this is replicating to
	# needs to be online.
	my $all_online = check_drbd_peer_access($anvil);
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
	
	if (not $all_online)
	{
		# Adding a new disk requires all peers to be online. We'll exit with the progress under 100,
		# so anvil-daemon will kick it back off in a minute.
		$anvil->Job->update_progress({
			progress => $anvil->Job->bump_progress({steps => 10}),
			message  => "error_0427", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
		});
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{peer}})
		{
			# Record the access
			my $say_access = $anvil->data->{peer}{$short_host_name}{access_ip} ? $say_up : $say_down;
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 10}),
				message   => "error_0428", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
				variables => {
					host_name => $short_host_name,
					access    => $say_access,
				},
			});
		}
		$anvil->nice_exit({exit_code => 1});
	}
	
	my $drbd_resource = load_storage($anvil);
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }});
	foreach my $host_type ("node", "dr")
	{
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
		{
			my $host_uuid       = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
			my $this_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
			my $dr_link_uuid    = exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid} ? $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}{dr_link_uuid} : "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:short_host_name' => $short_host_name,
				's2:host_uuid'       => $host_uuid, 
				's3:this_anvil_uuid' => $this_anvil_uuid, 
				's4:dr_link_uuid'    => $dr_link_uuid, 
			}});
			
			# If this host is from another node or unrelated DR host, skip it. 
			next if (($host_type eq "node") && ($anvil_uuid ne $this_anvil_uuid));
			next if (($host_type eq "dr") && (not $dr_link_uuid));
			
			foreach my $volume_number (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}})
			{
				next if not defined $volume_number or $volume_number eq "";
				my $device_path = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_path};
				next if $device_path eq "DELETED";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:volume_number' => $volume_number,
					's2:device_path'   => $device_path, 
				}});
				
				my $device_minor = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_minor};
				my $volume_size  = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{volume_size};
				my $backing_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{backing_disk};
				my $meta_disk    = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{meta_disk};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:device_minor'  => $device_minor, 
					's2:volume_size'   => $volume_size, 
					's3:backing_disk'  => $backing_disk, 
					's4:meta_disk'     => $meta_disk, 
				}});
				
				# Which volume group is the backing device in?
				foreach my $this_scan_lvm_lv_name (sort {$a cmp $b} keys %{$anvil->data->{lvm}{host_name}{$short_host_name}{lv}})
				{
					next if not $this_scan_lvm_lv_name;
					my $this_scan_lvm_lv_path  = $anvil->data->{lvm}{host_name}{$short_host_name}{lv}{$this_scan_lvm_lv_name}{scan_lvm_lv_path}; 
					my $this_scan_lvm_lv_on_vg = $anvil->data->{lvm}{host_name}{$short_host_name}{lv}{$this_scan_lvm_lv_name}{scan_lvm_lv_on_vg}; 
					my $this_scan_lvm_lv_uuid  = $anvil->data->{lvm}{host_name}{$short_host_name}{lv}{$this_scan_lvm_lv_name}{scan_lvm_lv_uuid};
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						's1:this_scan_lvm_lv_name'  => $this_scan_lvm_lv_name, 
						's2:this_scan_lvm_lv_path'  => $this_scan_lvm_lv_path,
						's3:this_scan_lvm_lv_on_vg' => $this_scan_lvm_lv_on_vg, 
						's4:this_scan_lvm_lv_uuid'  => $this_scan_lvm_lv_uuid, 
					}});
					
					if ($backing_disk eq $this_scan_lvm_lv_path)
					{
						# What's the VG's UUID? 
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							's1:short_host_name'        => $short_host_name, 
							's2:this_scan_lvm_lv_on_vg' => $this_scan_lvm_lv_on_vg, 
						}});
						if (exists $anvil->data->{lvm}{host_name}{$short_host_name}{vg}{$this_scan_lvm_lv_on_vg})
						{
							my $scan_lvm_vg_uuid   = $anvil->data->{lvm}{host_name}{$short_host_name}{vg}{$this_scan_lvm_lv_name}{scan_lvm_vg_uuid};
							my $storage_group_uuid = $anvil->data->{lvm}{host_name}{$short_host_name}{vg}{$this_scan_lvm_lv_name}{storage_group_uuid};
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
								's1:scan_lvm_vg_uuid'   => $scan_lvm_vg_uuid, 
								's2:storage_group_uuid' => $storage_group_uuid, 
							}});
						}
					}
				}
				
				# How much space can this LV grow into (this factors DR is already protected).
				$anvil->data->{server_name}{$server_name}{drbd_resource}{$drbd_resource}{volume}{$volume_number}{free_space} = get_max_free_space($anvil, $drbd_resource, $volume_number);
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"server_name::${server_name}::drbd_resource::${drbd_resource}::volume::${volume_number}::free_space" => $anvil->data->{server_name}{$server_name}{drbd_resource}{$drbd_resource}{volume}{$volume_number}{free_space}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{server_name}{$server_name}{drbd_resource}{$drbd_resource}{volume}{$volume_number}{free_space}}).")", 
				}});
			}
		}
	}
	
	if (($anvil->data->{switches}{grow}) or ($anvil->data->{switches}{remove}))
	{
		my $device_target = $anvil->data->{switches}{disk};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device_target => $device_target }});
		
		if (($anvil->data->{switches}{disk} eq "#!SET!#") or ($anvil->data->{switches}{disk} eq "1"))
		{
			# User didn't specify a device.
			show_server_details($anvil, 1);
			$anvil->Job->update_progress({
				progress => 100,
				message  => "error_0458", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
			});
			$anvil->nice_exit({exit_code => 1});
		}
		elsif (not exists $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}{$device_target})
		{
			# Invalid device target
			show_server_details($anvil, 1);
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "error_0459", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
				variables => {
					device_target => $device_target, 
				},
			});
			$anvil->nice_exit({exit_code => 1});
		}

		my $device           = "disk";
		my $alias            = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{alias};
		my $boot_order       = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{boot_order};
		my $say_boot         = $boot_order eq "99" ? "--" : sprintf("%02d", $boot_order);
		my $type             = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{type};
		my $address_type     = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{type};
		my $address_bus      = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{bus};
		my $driver_name      = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{name};
		my $device_bus       = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{device_bus};
		my $driver_type      = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{type};
		my $address_domain   = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{domain};
		my $address_slot     = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{slot};
		my $address_function = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{function};
		my $device_path      = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{path};
		my $driver_io        = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{io};
		my $driver_cache     = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{cache};
		my $on_lv            = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv};
		my $drbd_volume      = $anvil->data->{lvm}{host_name}{$short_host_name}{lv_path}{$on_lv}{drbd}{volume};
		my $max_free_space   = $anvil->data->{server_name}{$server_name}{drbd_resource}{$drbd_resource}{volume}{$drbd_volume}{free_space};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's01:device_target'    => $device_target,
			's02:alias'            => $alias, 
			's03:boot_order'       => $boot_order,
			's04:say_boot'         => $say_boot, 
			's05:type'             => $type, 
			's06:address_type'     => $address_type, 
			's07:address_bus'      => $address_bus, 
			's08:driver_name'      => $driver_name, 
			's09:device_bus'       => $device_bus, 
			's10:driver_type'      => $driver_type, 
			's11:address_domain'   => $address_domain,
			's12:address_slot'     => $address_slot, 
			's13:address_function' => $address_function, 
			's14:device_path'      => $device_path, 
			's15:driver_io'        => $driver_io, 
			's16:driver_cache'     => $driver_cache, 
			's17:on_lv'            => $on_lv, 
			's18:drbd_volume'      => $drbd_volume, 
			's19:max_free_space'   => $max_free_space." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}).")",
		}});
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 10}),
			message   => "log_0749", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			variables => {
			device_target  => $device_target, 
			say_boot       => $say_boot, 
			device_path    => $device_path, 
			max_free_space => $anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}), 
			},
		});
		
		# What are we doing?
		if ($anvil->data->{switches}{grow})
		{
			# If the volume is '0', it's the boot disk. The server needs to be off.
			if ($drbd_volume eq "0")
			{
				# Make sure the server is off.
				my $server_uuid  = $anvil->data->{switches}{server_uuid};
				my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:server_uuid'  => $server_uuid,
					's2:server_state' => $server_state, 
				}});
				
				if ($server_state ne "shut off")
				{
					# Wait until it is off.
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 5}),
						message   => "log_0113", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						variables => {
							server_name  => $server_name, 
							server_state => $server_state, 
						}, 
					});
					
					# If this is a CI test, abort.
					$anvil->System->_abort_if_ci();
					
					my $is_off        = 0;
					my $update_period = 120;
					my $next_update   = time + $update_period;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						's1:update_period' => $update_period,
						's2:next_update'   => $next_update, 
					}});
					until ($is_off)
					{
						sleep 5;
						$anvil->Database->get_servers({debug => 3});
						my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_state => $server_state }});
						
						if ($server_state eq "shut off")
						{
							# We're done, we can proceed.
							$is_off = 1;
							$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { is_off => $is_off }});
							$anvil->Job->update_progress({
								progress  => $anvil->Job->bump_progress({steps => 3}),
								message   => "log_0114", 
								log_level => 1, 
								'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
								variables => {
									server_name  => $server_name, 
								}, 
							});
						}
						else
						{
							# Not off yet.
							if (time > $next_update)
							{
								# Update the job.
								$next_update = time + $update_period;
								$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { next_update => $next_update }});
								$anvil->Job->update_progress({
									progress  => $anvil->Job->bump_progress({steps => 2}),
									message   => "log_0121", 
									log_level => 1, 
									'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
									variables => {
										timestamp    => $anvil->Get->date_and_time({time_only => 1}),
										server_name  => $server_name, 
										server_state => $server_state, 
									}, 
								});
							}
							else
							{
								# Just log it so we don't flood the DB
								$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0121", variables => { 
									timestamp    => $anvil->Get->date_and_time({time_only => 1}),
									server_name  => $server_name, 
									server_state => $server_state, 
								}});
							}
						}
					}
				}
			}
			manage_disk_grow($anvil, $drbd_resource, $drbd_volume, $max_free_space);
		}
	}
	elsif ($anvil->data->{switches}{add})
	{
		manage_disk_add($anvil, $drbd_resource);
	}
	
	return(0);
}

sub manage_disk_add
{
	my ($anvil, $drbd_resource) = @_;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }});
	
	my $anvil_uuid      = defined $anvil->data->{switches}{anvil_uuid} ? $anvil->data->{switches}{anvil_uuid} : "";
	my $short_host_name = $anvil->Get->short_host_name;
	my $server_name     = $anvil->data->{switches}{server_name};
	my $server_uuid     = $anvil->data->{switches}{server_uuid};
	my $from_source     = get_definition_source($anvil);
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		anvil_uuid      => $anvil_uuid, 
		short_host_name => $short_host_name,
		server_name     => $server_name, 
		server_uuid     => $server_uuid, 
		from_source     => $from_source, 
	}});
	
	if (not $anvil_uuid)
	{
		$anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
	}
	
	# Do we have a storage group?
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		'switches::storage-group' => $anvil->data->{switches}{'storage-group'}, 
	}});
	if (not $anvil->data->{switches}{'storage-group'})
	{
		$anvil->Job->update_progress({
			progress => 100,
			message  => "warning_0168", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "alert",
		});
		show_storage_groups($anvil);
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Are they asking for an available amount of space?
	my $say_up   = $anvil->Words->string({key => 'message_0331'});
	my $say_down = $anvil->Words->string({key => 'message_0332'});
	
	# Make sure that the passed
	my $storage_group_switch = $anvil->data->{switches}{'storage-group'};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { storage_group_switch => $storage_group_switch }});
	
	my $storage_group_uuid = "";
	my $storage_group_name = "";
	if (exists $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$storage_group_switch})
	{
		$storage_group_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$storage_group_switch}{storage_group_uuid};
		$storage_group_name = $storage_group_switch;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			storage_group_uuid => $storage_group_uuid, 
			storage_group_name => $storage_group_name, 
		}});
	}
	elsif (exists $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_switch})
	{
		$storage_group_uuid = $storage_group_switch;
		$storage_group_name = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_switch}{group_name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			storage_group_uuid => $storage_group_uuid, 
			storage_group_name => $storage_group_name, 
		}});
	}
	else
	{
		# Bad storage group.
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "error_0437", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				storage_group => $storage_group_switch
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Did we get a valid disk size?
	my $free_space = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{free_space};
	my $add_size   = $anvil->data->{switches}{add};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
	if ($add_size =~ /^(\d+)%$/)
	{
		# This is valid
		my $percent = ".".$1;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { percent => $percent }});
		
		$add_size = int($free_space * $percent);
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
	}
	elsif ($add_size !~ /\d/)
	{
		# No digits, probably didn't set a value at all.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 10}),
			message   => "error_0423", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				free_space => $anvil->Convert->bytes_to_human_readable({'bytes' => $free_space}), 
			},
		});
		$anvil->Job->update_progress({
			progress => 100,
			message  => "message_0330", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		$anvil->nice_exit({exit_code => 1});
	}
	elsif ($add_size !~ /^\d+$/)
	{
		# Size is not in bytes, try to convert it.
		my $bytes = $anvil->Convert->human_readable_to_bytes({
			debug => 2,
			size  => $add_size,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'bytes' => $bytes }});
		if ($bytes =~ /^\d+$/)
		{
			$add_size = $bytes;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
		}
		else
		{
			# Not a valid size.
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 10}),
				message   => "error_0424", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
				variables => {
					add_size => $add_size
				},
			});
			$anvil->Job->update_progress({
				progress => 100,
				message  => "message_0330", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	# Still here? We're good to go.
	my $lv_command_size = 0;
	my $hr_size         = $anvil->Convert->bytes_to_human_readable({'bytes' => $add_size});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hr_size => $hr_size }});
	if ($add_size eq "100%")
	{
		# This is valid
		$add_size = "-l +100\%FREE";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
	}
	else
	{
		$hr_size  =~ s/\s+//g;
		$add_size =  "-L +".$hr_size;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
	}
	
	# What's the next free drive in the system, and what's the next free volume number?
	my $new_device_target = "";
	my $target_prefix     = "";
	my $disk_device_bus   = "";
	my $disk_cache        = "";
	my $disk_io_policy    = "";
	my $drive_letter      = "a";
	foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}})
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device_target => $device_target }});
		if (not $disk_device_bus)
		{
			$target_prefix   = ($device_target =~ /^(\w+)\w$/)[0];
			$disk_device_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}{$device_target}{device_bus};
			$disk_io_policy  = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}{$device_target}{driver}{io};
			$disk_cache      = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}{$device_target}{driver}{cache};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				target_prefix   => $target_prefix, 
				disk_device_bus => $disk_device_bus,
				disk_io_policy  => $disk_io_policy, 
				disk_cache      => $disk_cache, 
			}});
			last;
		}
	}
	for (0..25)
	{
		my $test_device = $target_prefix.$drive_letter;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_device => $test_device }});
		if (not exists $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}{$test_device})
		{
			# Found a free one.
			$new_device_target = $test_device;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_device_target => $new_device_target }});
			last;
		}
		$drive_letter++;
	}
	
	if (not $new_device_target)
	{
		# Failed to find a new target device name
		$anvil->Job->update_progress({
			progress => 100,
			message  => "error_0425", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	my $next_drbd_volume = "";
	foreach my $this_host (sort {$a cmp $b} keys %{$anvil->data->{drbd}{drbd_node}})
	{
		my $host_uuid       = $anvil->Get->host_uuid_from_name({host_name => $this_host});
		my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:this_host'       => $this_host, 
			's2:host_uuid'       => $host_uuid, 
			's3:short_host_name' => $short_host_name, 
		}});
		
		if ($next_drbd_volume eq "")
		{
			my $test_drbd_volume = 0;
			for (0..100)
			{
				if (not $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$test_drbd_volume}{backing_disk})
				{
					# This is free.
					$next_drbd_volume = $test_drbd_volume;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { next_drbd_volume => $next_drbd_volume }});
					last;
				}
				$test_drbd_volume++;
				next;
			}
		}
		
		if ($next_drbd_volume eq "")
		{
			# Failed to find a new DRBD volume to use.
			$anvil->Job->update_progress({
				progress => 100,
				message  => "error_0426", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
			});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	# Still alive? Ask the user to confirm.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "message_0333", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		variables => {
			new_device_target  => $new_device_target,
			hr_size            => $hr_size,
			disk_device_bus    => $disk_device_bus, 
			disk_cache         => $disk_cache, 
			disk_io_policy     => $disk_io_policy, 
			drbd_resource      => $drbd_resource, 
			next_drbd_volume   => $next_drbd_volume, 
			storage_group_name => $storage_group_name, 
		},
	});
	if ((not $anvil->data->{switches}{confirm}) && (not $anvil->data->{switches}{'job-uuid'}))
	{
		$anvil->System->_abort_if_ci();
		print $anvil->Words->string({key => "message_0021"})." ";
		my $answer = <STDIN>;
		chomp($answer);
		if ($answer !~ /^y/i)
		{
			print $anvil->Words->string({key => "message_0022"})."\n";
			$anvil->nice_exit({exit_code => 0});
		}
		
		# Test that we've lost access while waiting for the answer.
		my $all_online = check_drbd_peer_access($anvil);
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
		
		if (not $all_online)
		{
			# It would appear that we've lost access to a peer while waiting for the answer.
			$anvil->Job->update_progress({
				progress => $anvil->Job->bump_progress({steps => 10}),
				message  => "error_0429", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
			});
			foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{peer}})
			{
				# Record the access
				my $say_access = $anvil->data->{peer}{$short_host_name}{access_ip} ? $say_up : $say_down;
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 1}),
					message   => "error_0428", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
					variables => {
						host_name => $short_host_name,
						access    => $say_access,
					},
				});
			}
			$anvil->Job->update_progress({
				progress => 100,
				message  => "job_0471", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	# Get the next free minor number
	my ($free_minor, undef) = $anvil->DRBD->get_next_resource({
		debug      => 2, 
		minor_only => 1,
		anvil_uuid => $anvil_uuid,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { free_minor => $free_minor }});
	
	# Create the new LVs
	foreach my $host_type ("node", "dr")
	{
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
		{
			my $host_uuid       = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
			my $this_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
			my $dr_link_uuid    = exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid} ? $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}{dr_link_uuid} : "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:short_host_name' => $short_host_name,
				's2:host_uuid'       => $host_uuid, 
				's3:this_anvil_uuid' => $this_anvil_uuid, 
				's4:dr_link_uuid'    => $dr_link_uuid, 
			}});
			
			# If this host is from another node or unrelated DR host, skip it. 
			next if (($host_type eq "node") && ($anvil_uuid ne $this_anvil_uuid));
			next if (($host_type eq "dr") && (not $dr_link_uuid));
			
			my $vg_name          = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_name};
			my $vg_internal_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{vg_internal_uuid};
			my $new_lv_name      = $server_name."_".$next_drbd_volume;
			my $backing_disk     = "/dev/".$vg_name."/".$new_lv_name;
			my $shell_call       = "if [ -e '".$backing_disk."' ]; then echo 'LV: [".$backing_disk."] already exists.'; else ".$anvil->data->{path}{exe}{lvcreate}." ".$add_size." -n ".$new_lv_name." ".$vg_name."; fi;";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:vg_name'          => $vg_name, 
				's2:vg_internal_uuid' => $vg_internal_uuid, 
				's3:new_lv_name'      => $new_lv_name, 
				's4:backing_disk'     => $backing_disk, 
				's5:shell_call'       => $shell_call, 
			}});
			
			# Record this for updating the DRBD resource.
			$anvil->data->{new_drbd}{$short_host_name}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{minor}        = $free_minor;
			$anvil->data->{new_drbd}{$short_host_name}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{backing_disk} = $backing_disk;
			$anvil->data->{new_drbd}{$short_host_name}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{seen}         = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"new_drbd::${short_host_name}::resource::${drbd_resource}::volume::${next_drbd_volume}::minor"        => $anvil->data->{new_drbd}{$short_host_name}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{minor},
				"new_drbd::${short_host_name}::resource::${drbd_resource}::volume::${next_drbd_volume}::backing_disk" => $anvil->data->{new_drbd}{$short_host_name}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{backing_disk},
				"new_drbd::${short_host_name}::resource::${drbd_resource}::volume::${next_drbd_volume}::seen"         => $anvil->data->{new_drbd}{$short_host_name}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{seen},
			}});
			
			# This lets us insert the new volume as needed.
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			}});
			if ($host_uuid eq $anvil->Get->host_uuid)
			{
				# Creating the new local LV
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0748", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						backing_disk => $backing_disk
					},
				});
				my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output,
					return_code => $return_code, 
				}});
				if ($return_code)
				{
					$anvil->Job->update_progress({
						progress  => 100,
						message   => "error_0460", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						priority  => "err",
						variables => {
							backing_disk => $backing_disk,
							shell_call   => $shell_call,
							return_code  => $return_code, 
							output       => $output, 
						},
					});
					$anvil->nice_exit({exit_code => 1});
				}
				else
				{
					# Done!
					$anvil->Job->update_progress({
						progress => $anvil->Job->bump_progress({steps => 2}),
						message  => "log_0750", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					});
				}
			}
			else
			{
				my $use_ip      = $anvil->data->{peer}{$short_host_name}{access}{ip};
				my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0756", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						host_name    => $short_host_name, 
						backing_disk => $backing_disk, 
						use_ip       => $use_ip, 
						use_network  => $use_network, 
					},
				});
				my ($output, $error, $return_code) = $anvil->Remote->call({
					shell_call => $shell_call, 
					target     => $use_ip,
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output, 
					error       => $error,
					return_code => $return_code,
				}});
				if ($return_code)
				{
					$anvil->Job->update_progress({
						progress  => 100,
						message   => "error_0461", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						priority  => "err",
						variables => {
							host_name    => $short_host_name, 
							backing_disk => $backing_disk,
							shell_call   => $shell_call,
							return_code  => $return_code, 
							output       => $output, 
							error        => $error, 
						},
					});
					$anvil->nice_exit({exit_code => 1});
				}
				else
				{
					# Done!
					$anvil->Job->update_progress({
						progress => $anvil->Job->bump_progress({steps => 2}),
						message  => "log_0750", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					});
				}
			}
		}
	}
	
	# Update the DRBD config file.
	my $new_res_file  = "";
	my $drbd_res_file = $anvil->data->{path}{directories}{drbd_resources}."/".$drbd_resource.".res";
	my $drbd_res_body = $anvil->Storage->read_file({file => $drbd_res_file});
	my $in_on_host    = "";
	my $in_volume     = "";
	foreach my $line (split /\n/, $drbd_res_body)
	{
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
		if ($line =~ /on\s+(.*?)\s/)
		{
			$in_on_host = $1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
			
			$new_res_file .= $line."\n";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_res_file => $new_res_file }});
			next;
		}
		
		if (($in_on_host) && ($line =~ /volume\s+(\d+)\s/))
		{
			$in_volume = $1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_volume => $in_volume }});
			
			$new_res_file .= $line."\n";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_res_file => $new_res_file }});
			
			$anvil->data->{new_drbd}{$in_on_host}{resource}{$drbd_resource}{volume}{$in_volume}{seen} = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"new_drbd::${in_on_host}::resource::${drbd_resource}::volume::${in_volume}::seen" => $anvil->data->{new_drbd}{$in_on_host}{resource}{$drbd_resource}{volume}{$in_volume}{seen},
			}});
			next;
		}
		
		if ($line =~ /}/)
		{
			if ($in_volume)
			{
				$in_volume = "";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_volume => $in_volume }});
			}
			elsif ($in_on_host)
			{
				# This is where we insert the new volume, if we've not seen it yet.
				if (not $anvil->data->{new_drbd}{$in_on_host}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{seen})
				{
					# Insert the line.
					$new_res_file .= $line."

                volume ".$next_drbd_volume." {
                        device    minor ".$anvil->data->{new_drbd}{$short_host_name}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{minor}.";
                        disk      ".$anvil->data->{new_drbd}{$in_on_host}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{backing_disk}.";
                        meta-disk internal;
                }
";
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_res_file => $new_res_file }});
					
					$anvil->data->{new_drbd}{$in_on_host}{resource}{$drbd_resource}{volume}{$next_drbd_volume}{seen} = 1;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"new_drbd::${in_on_host}::resource::${drbd_resource}::volume::${in_volume}::seen" => $anvil->data->{new_drbd}{$in_on_host}{resource}{$drbd_resource}{volume}{$in_volume}{seen},
					}});
					next;
				}
			}
		}
		
		$new_res_file .= $line."\n";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_res_file => $new_res_file }});
	}
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_res_file => $new_res_file }});
	
	my $difference = diff \$drbd_res_body, \$new_res_file, { STYLE => 'Unified' };
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }});
	
	# Write the file to a test file and verify it's sane,
	my $test_file = $anvil->data->{path}{directories}{temp}."/test-".$drbd_resource.".res";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }});
	my ($problem) = $anvil->Storage->write_file({
		debug     => 2,
		backup    => 0,
		overwrite => 1,
		file      => $test_file, 
		body      => $new_res_file,
		user      => "root", 
		group     => "root", 
		mode      => "0644",
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
	
	# Validate.
	$anvil->Job->update_progress({
		progress => $anvil->Job->bump_progress({steps => 2}),
		message  => "log_0751", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	my $shell_call = $anvil->data->{path}{exe}{drbdadm}." --config-to-test ".$test_file." --config-to-exclude ".$drbd_res_file." sh-nop";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output,
		return_code => $return_code, 
	}});
	if ($return_code)
	{
		# Something went wrong.
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "error_0430", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				test_file   => $test_file,
				return_code => $return_code,
				output      => $output, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	# Success!
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0752", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	
	# Remove the test file.
	unlink $test_file;
	
	# Backup the res file so we can tell the user where the current config was backed up to in case they
	# need to restore it.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0757", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	my ($backup_file) = $anvil->Storage->backup({file => $drbd_res_file});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { backup_file => $backup_file }});
	
	# Write out the new file.
	($problem) = $anvil->Storage->write_file({
		debug     => 2,
		backup    => 0,
		overwrite => 1,
		file      => $drbd_res_file, 
		body      => $new_res_file,
		user      => "root", 
		group     => "root", 
		mode      => "0644",
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { backup_file => $backup_file }});
	
	# Copy this to our peers.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0753", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	foreach my $host_type ("node", "dr")
	{
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
		{
			my $host_uuid       = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
			my $this_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
			my $dr_link_uuid    = exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid} ? $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}{dr_link_uuid} : "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:short_host_name' => $short_host_name,
				's2:host_uuid'       => $host_uuid, 
				's3:this_anvil_uuid' => $this_anvil_uuid, 
				's4:dr_link_uuid'    => $dr_link_uuid, 
			}});
			
			# If this host is from another node or unrelated DR host, skip it. 
			next if $host_uuid eq $anvil->Get->host_uuid;
			next if (($host_type eq "node") && ($anvil_uuid ne $this_anvil_uuid));
			next if (($host_type eq "dr") && (not $dr_link_uuid));
			
			my $use_ip      =  $anvil->data->{peer}{$short_host_name}{access}{ip};
			my $destination =  "root\@".$use_ip.":".$anvil->data->{path}{directories}{drbd_resources}."/";
			   $destination =~ s/\/\//\//g;
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0754", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				variables => {
					resource_file => $drbd_res_file, 
					host_name     => $short_host_name, 
					destination   => $destination, 
					use_ip        => $use_ip, 
				},
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				use_ip      => $use_ip,
				destination => $destination, 
			}});
			   
			my $failed = $anvil->Storage->rsync({
				debug       => 2, 
				destination => $destination,
				source      => $drbd_res_file,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }});
			
			if ($failed)
			{
				# There was a problem copying the new config file!
				$anvil->Job->update_progress({
					progress  => 100,
					message   => "error_0431", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				});
				$anvil->nice_exit({exit_code => 1});
			}
		}
	}
	
	# Create the metadata.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0755", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	foreach my $host_type ("node", "dr")
	{
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
		{
			my $host_uuid       = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
			my $this_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
			my $dr_link_uuid    = exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid} ? $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}{dr_link_uuid} : "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:short_host_name' => $short_host_name,
				's2:host_uuid'       => $host_uuid, 
				's3:this_anvil_uuid' => $this_anvil_uuid, 
				's4:dr_link_uuid'    => $dr_link_uuid, 
			}});
			
			# If this host is from another node or unrelated DR host, skip it. 
			next if (($host_type eq "node") && ($anvil_uuid ne $this_anvil_uuid));
			next if (($host_type eq "dr") && (not $dr_link_uuid));
			
			my $shell_call = $anvil->data->{path}{exe}{drbdadm}." --force create-md --max-peers=3 ".$drbd_resource."/".$next_drbd_volume;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			
			# Create the metadata, but don't exit on failure in case the metadata was created in
			# a previous pass.
			if ($host_uuid eq $anvil->Get->host_uuid)
			{
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0758", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						next_drbd_volume => $next_drbd_volume
					},
				});
				my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output,
					return_code => $return_code, 
				}});
				
				### Return codes
				# 0 == Success
				# 1 == ?
				# 3 == Configuration not found.
				if ($return_code)
				{
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "warning_0160", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						priority  => "alert",
						variables => {
							drbd_resource    => $drbd_resource, 
							next_drbd_volume => $next_drbd_volume, 
							shell_call       => $shell_call, 
							return_code      => $return_code, 
							output           => $output, 
						},
					});
				}
				else
				{
					# Done!
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "log_0750", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					});
				}
			}
			else
			{
				# Create the meta-data on the peer
				my $use_ip      = $anvil->data->{peer}{$short_host_name}{access}{ip};
				my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0759", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						host_name        => $short_host_name, 
						drbd_resource    => $drbd_resource, 
						next_drbd_volume => $next_drbd_volume, 
						use_ip           => $use_ip, 
						use_network      => $use_network, 
					},
				});
				my ($output, $error, $return_code) = $anvil->Remote->call({
					shell_call => $shell_call, 
					target     => $use_ip,
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output, 
					error       => $error,
					return_code => $return_code,
				}});
				if ($return_code)
				{
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "warning_0161", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						priority  => "alert",
						variables => {
							host_name        => $short_host_name, 
							drbd_resource    => $drbd_resource, 
							next_drbd_volume => $next_drbd_volume,
							shell_call       => $shell_call, 
							return_code      => $return_code, 
							output           => $output, 
							error            => $error, 
						},
					});
				}
				else
				{
					# Done!
					$anvil->Job->update_progress({
						progress => $anvil->Job->bump_progress({steps => 2}),
						message  => "log_0750", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					});
				}
			}
		}
	}
	
	### NOTE: The call to 'drbdadm adjust <res>' hangs, hard, until the same command is run on the peers.
	###       To deal with this, we register jobs to run 'anvil-special-operations' on the peers, then we
	###       call adjust here. 
	# Adjust to start/connect.
	foreach my $host_type ("node", "dr")
	{
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
		{
			my $host_uuid       = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
			my $this_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
			my $dr_link_uuid    = exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid} ? $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}{dr_link_uuid} : "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:short_host_name' => $short_host_name,
				's2:host_uuid'       => $host_uuid, 
				's3:this_anvil_uuid' => $this_anvil_uuid, 
				's4:dr_link_uuid'    => $dr_link_uuid, 
			}});
			
			# If this host is from another node or unrelated DR host, skip it. 
			next if $host_uuid eq $anvil->Get->host_uuid;
			next if (($host_type eq "node") && ($anvil_uuid ne $this_anvil_uuid));
			next if (($host_type eq "dr") && (not $dr_link_uuid));
			
			my $shell_call = $anvil->data->{path}{exe}{'anvil-special-operations'}." --task refresh-drbd-resource --resource ".$drbd_resource.$anvil->Log->switches;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			
			my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
				debug           => 2, 
				job_command     => $shell_call, 
				job_data        => "adjust=".$drbd_resource, 
				job_name        => "server::add_disk::rescan", 
				job_title       => "job_0465", 
				job_description => "job_0466", 
				job_progress    => 0,
				job_host_uuid   => $host_uuid, 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
			
			# Record that we registered the job to reload the resource
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0760", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				variables => {
					host_name => $short_host_name, 
					job_uuid  => $job_uuid, 
				},
			});
		}
	}
	
	# Warn the user to check that anvil-daemon is running in case this hangs.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0761", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		variables => {
			drbd_resource => $drbd_resource
		},
	});
	$shell_call = $anvil->data->{path}{exe}{drbdadm}." adjust ".$drbd_resource;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	($output, $return_code) = $anvil->System->call({
		background => 1,
		shell_call => $shell_call,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output,
		return_code => $return_code, 
	}});
	
	sleep 5;
	# Update our view of the DRBD resources on all hosts.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "job_0110", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	my $peer_count     = 0;
	my $scan_drbd_call = $anvil->data->{path}{directories}{'scan_agents'}."/scan-drbd".$anvil->Log->switches;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_drbd_call => $scan_drbd_call }});
	($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output,
		return_code => $return_code,
	}});
	
	foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{peer}})
	{
		my $use_ip      = $anvil->data->{peer}{$short_host_name}{access}{ip};
		my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
		my $host_uuid   = $anvil->data->{peer}{$short_host_name}{host_uuid};
		   $peer_count++;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"s1:short_host_name" => $short_host_name, 
			"s2:use_ip"          => $use_ip, 
			"s3:use_network"     => $use_network, 
			"s4:host_uuid"       => $host_uuid, 
			"s5:peer_count"      => $peer_count,
		}});
	
		# The resource is primary on the peer, force Primary over there.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "job_0111", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			variables => {
				host_name   => $short_host_name, 
				use_ip      => $use_ip, 
				use_network => $use_network, 
			},
		});
		my ($output, $error, $return_code) = $anvil->Remote->call({
			shell_call => $shell_call, 
			target     => $use_ip,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"s1:output"      => $output, 
			"s2:error"       => $error, 
			"s3:return_code" => $return_code,
		}});
	}
	
	# Find which node is currently Primary and use that host to force primary to start sync. If none, 
	# force here.
	$anvil->Job->update_progress({
		progress => $anvil->Job->bump_progress({steps => 2}),
		message  => "log_0762", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	my $waiting    = 1;
	my $wait_until = time + 300;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wait_until => $wait_until }});
	while ($waiting)
	{
		# Update our view of DRBD resources.
		$anvil->DRBD->get_status({debug => 2});
		
		my $peers_connected = 1;
		my $disks_ready     = 0;
		my $drbd_peer_count = keys %{$anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_peer_count => $drbd_peer_count }});
		if ($drbd_peer_count ne $peer_count)
		{
			$peers_connected = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peers_connected => $peers_connected }});
		}
		foreach my $this_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}})
		{
			my $host_uuid = $anvil->Get->host_uuid_from_name({host_name => $this_host_name}); 
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:this_host_name' => $this_host_name, 
				's2:host_uuid'      => $host_uuid, 
			}});
			next if $host_uuid eq $anvil->Get->host_uuid;
			
			my $connection_state = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$this_host_name}{'connection-state'};
			my $node_id          = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$this_host_name}{'peer-node-id'};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:connection_state' => $connection_state, 
				's2:node_id'          => $node_id,
			}});

			if (lc($connection_state) ne "connected")
			{
				$peers_connected = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peers_connected => $peers_connected }});
			}
		}
		
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peers_connected => $peers_connected }});
		if ($peers_connected)
		{
			# Make sure all disks are attached.
			$disks_ready                                        = 1;
			$anvil->data->{peers}{$short_host_name}{disk_state} = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{devices}{volume}{$next_drbd_volume}{'disk-state'};
			$anvil->data->{peers}{$short_host_name}{role}       = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{role};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"peers::${short_host_name}::disk_state" => $anvil->data->{peers}{$short_host_name}{disk_state},
				"peers::${short_host_name}::role"       => $anvil->data->{peers}{$short_host_name}{role},
			}});
			foreach my $peer_name (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}})
			{
				next if not defined $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$peer_name}{volume}{$next_drbd_volume}{'peer-disk-state'};
				my $peer_disk_state   = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$peer_name}{volume}{$next_drbd_volume}{'peer-disk-state'};
				my $replication_state = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$peer_name}{volume}{$next_drbd_volume}{'replication-state'};
				my $role              = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$peer_name}{'peer-role'};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:peer_name'         => $peer_name, 
					's2:peer_disk_state'   => $peer_disk_state, 
					's3:replication_state' => $replication_state,
					's4:role'              => $role, 
				}});
				
				# If the volume is 'Negotiating', disconnect and reconnect the peer.
				if (lc($peer_disk_state) eq "negotiating")
				{
					print "- Problem!\n";
					($peer_disk_state, $role) = reconnect_resource($anvil, $short_host_name, $peer_name, $drbd_resource, $next_drbd_volume);
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						peer_disk_state => $peer_disk_state,
						role            => $role,
					}});
					
					$disks_ready = 0;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disks_ready => $disks_ready }});
				}
				
				# If it's not established, keep waiting
				if (lc($replication_state) ne "established")
				{
					$disks_ready = 0;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disks_ready => $disks_ready }});
				}
				if ((not $peer_disk_state) or (lc($peer_disk_state) eq "diskless"))
				{
					$disks_ready = 0;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disks_ready => $disks_ready }});
				}
				
				$anvil->data->{peers}{$peer_name}{disk_state} = $peer_disk_state;
				$anvil->data->{peers}{$peer_name}{role}       = $role;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"peers::${peer_name}::disk_state" => $anvil->data->{peers}{$peer_name}{disk_state},
				}});
			}
		}
		
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disks_ready => $disks_ready }});
		if ($disks_ready)
		{
			$waiting = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
		}
		else
		{
			if (time > $wait_until)
			{
				# The peers did not connect in the expected period of time.
				$anvil->Job->update_progress({
					progress => 100,
					message  => "error_0432", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
				});
				$anvil->nice_exit({exit_code => 1});
			}
			sleep 2;
		}
	}
	
	# Peers are connected! Checking if the new volume requires initial sync.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0763", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	my $all_inconsistent = 1;
	my $primary_on_host  = "";
	foreach my $peer_name (sort {$a cmp $b} keys %{$anvil->data->{peers}})
	{
		my $disk_state = $anvil->data->{peers}{$peer_name}{disk_state};
		my $role       = $anvil->data->{peers}{$peer_name}{role};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			peer_name  => $peer_name, 
			disk_state => $disk_state,
			role       => $role, 
		}});
		
		if (lc($disk_state) ne "inconsistent")
		{
			$all_inconsistent = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_inconsistent => $all_inconsistent }});
		}
		if (lc($role) eq "primary")
		{
			$primary_on_host = $peer_name;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { primary_on_host => $primary_on_host }});
		}
	}
	
	if ($all_inconsistent)
	{
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0764", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		
		my $shell_call = $anvil->data->{path}{exe}{drbdadm}." new-current-uuid --force-resync ".$drbd_resource."/".$next_drbd_volume;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		
		# Which node should be forced primary?
		my $already_primary = 1;
		if (not $primary_on_host)
		{
			# We'll make it primary.
			$primary_on_host = $short_host_name;
			$already_primary = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				primary_on_host => $primary_on_host, 
				already_primary => $already_primary,
			}});
		}
		
		my $primary_on_host_uuid = $anvil->Get->host_uuid_from_name({host_name => $primary_on_host});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { primary_on_host_uuid => $primary_on_host_uuid }});
		if ($primary_on_host_uuid eq $anvil->Get->host_uuid)
		{
			# Forcing primary locally...
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0765", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output,
				return_code => $return_code,
			}});
			# Return code of '0' is success.
			if ($return_code)
			{
				# There was a problem trying to force the new volume to Primary.
				$anvil->Job->update_progress({
					progress  => 100,
					message   => "error_0430", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
					variables => {
						drbd_resource    => $drbd_resource, 
						next_drbd_volume => $next_drbd_volume,
						shell_call       => $shell_call,
						return_code      => $return_code,
						output           => $output, 
					},
				});
				$anvil->nice_exit({exit_code => 1});
			}
			
			# Now demote it again.
			$shell_call = $anvil->data->{path}{exe}{drbdadm}." secondary ".$drbd_resource;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			
			($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output,
				return_code => $return_code,
			}});
			# Success!
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0752", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
		}
		else
		{
			my $use_ip      = $anvil->data->{peer}{$short_host_name}{access}{ip};
			my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				use_ip      => $use_ip,
				use_network => $use_network,
			}});
			# The resource is primary on the peer, force Primary over there.
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0766", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				variables => {
					host_name   => $short_host_name, 
					use_ip      => $use_ip, 
					use_network => $use_network, 
				},
			});
			my ($output, $error, $return_code) = $anvil->Remote->call({
				shell_call => $shell_call, 
				target     => $use_ip,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output, 
				error       => $error,
				return_code => $return_code,
			}});
			if ($return_code)
			{
				$anvil->Job->update_progress({
					progress  => 100,
					message   => "error_0430", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
					variables => {
						drbd_resource    => $drbd_resource, 
						next_drbd_volume => $next_drbd_volume,
						shell_call       => $shell_call,
						return_code      => $return_code,
						output           => $output, 
					},
				});
				$anvil->nice_exit({exit_code => 1});
			}
			
			# Now demote it again.
			$shell_call = $anvil->data->{path}{exe}{drbdadm}." secondary ".$drbd_resource;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			($output, $error, $return_code) = $anvil->Remote->call({
				shell_call => $shell_call, 
				target     => $use_ip,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output, 
				error       => $error,
				return_code => $return_code,
			}});
			# Success!
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0752", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
		}
	}
	else
	{
		# Initial sync does not appear to be required.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0767", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
	}
	
	# Is the server running? If so, where.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0768", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	my $server_host = "";
	foreach my $host_type ("node", "dr")
	{
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
		{
			my $host_uuid       = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
			my $this_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
			my $dr_link_uuid    = exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid} ? $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}{dr_link_uuid} : "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:short_host_name' => $short_host_name,
				's2:host_uuid'       => $host_uuid, 
				's3:this_anvil_uuid' => $this_anvil_uuid, 
				's4:dr_link_uuid'    => $dr_link_uuid, 
			}});
			
			# If this host is from another node or unrelated DR host, skip it. 
			next if (($host_type eq "node") && ($anvil_uuid ne $this_anvil_uuid));
			next if (($host_type eq "dr") && (not $dr_link_uuid));
			
			my $shell_call = $anvil->data->{path}{exe}{'anvil-special-operations'}." --task refresh-drbd-resource --resource ".$drbd_resource.$anvil->Log->switches;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			
			if ($host_uuid eq $anvil->Get->host_uuid)
			{
				$anvil->Server->find();
			}
			else
			{
				my $use_ip = $anvil->data->{peer}{$short_host_name}{access}{ip};
				$anvil->Server->find({target => $use_ip });
			}
			
			if ((exists $anvil->data->{server}{location}{$server_name}) && 
			    ($anvil->data->{server}{location}{$server_name}{host_name}))
			{
				my $this_host     = defined $anvil->data->{server}{location}{$server_name}{host_name} ? $anvil->data->{server}{location}{$server_name}{host_name} : "";
				my $server_status = defined $anvil->data->{server}{location}{$server_name}{status}    ? $anvil->data->{server}{location}{$server_name}{status}    : "";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					this_host     => $this_host, 
					server_status => $server_status, 
				}});
				if ($server_status eq "running")
				{
					# Found it.
					$server_host = $this_host;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_host => $server_host }});
					if ($host_uuid eq $anvil->Get->host_uuid)
					{
						# The server is running on this host, we'll attach the disk here.
						$anvil->Job->update_progress({
							progress  => $anvil->Job->bump_progress({steps => 2}),
							message   => "log_0769", 
							log_level => 1, 
							'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						});
					}
					else
					{
						# The server is running on the peer, we'll attach the disk there.
						$anvil->Job->update_progress({
							progress  => $anvil->Job->bump_progress({steps => 2}),
							message   => "log_0770", 
							log_level => 1, 
							'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
							variables => {
								server_host => $server_host, 
							},
						});
					}
					last;
				}
			}
		}
	}
	
	my $offline = 0;
	if (not $server_host)
	{
		# The server isn't running anywhere, we'll attach the disk offline on this host.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0771", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		$server_host = $short_host_name;
		$offline     = 1;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			server_host => $server_host, 
			offline     => $offline, 
		}});
	}
	
	$shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." attach-disk ".$server_name." ";
	$shell_call .= "/dev/drbd/by-res/".$drbd_resource."/".$next_drbd_volume." ".$new_device_target." ";
	$shell_call .= "--persistent --targetbus ".$disk_device_bus." ";
	$shell_call .= "--cache ".$disk_cache." ";
	$shell_call .= "--io ".$disk_io_policy." ";
	$shell_call .= "--sourcetype block --subdriver raw";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		offline    => $offline, 
		shell_call => $shell_call,
	}});
	if ($offline)
	{
		# Define the VM, if needed, then add the drive, dump the config and push it out.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0772", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			variables => {
				server_name => $server_name, 
			},
		});
		update_definition($anvil, "define", "");
		
		# Update the definition.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0773", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output,
			return_code => $return_code,
		}});
		
		# Read the new virsh definition
		$shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." dumpxml --inactive ".$server_name;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		
		(my $virsh_definition, $return_code) = $anvil->System->call({shell_call => $shell_call});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			virsh_definition => $virsh_definition,
			return_code      => $return_code,
		}});
		
		# Make sure the definition we read is sane.
		my $problem = $anvil->Server->parse_definition({
			server     => $server_name,
			source     => "from_virsh", 
			definition => $virsh_definition, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
		if ($problem)
		{
			# Failed?!
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "error_0434", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
			});
			$anvil->nice_exit({exit_code => 1});
		}
		
		# Updating the stored definition and undefining the server now...
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0774", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		update_definition($anvil, "undefine", $virsh_definition);
		
		# Copy the new definition to the other host(s)
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0808", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		$anvil->Server->update_definition({
			debug              => 2,
			server             => $server_name,
			new_definition_xml => $virsh_definition, 
		});
		
		# Done!
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "log_0750", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		$anvil->nice_exit({exit_code => 0});
	}
	else
	{
		# Add the drive live, dump the new definition and push it out.
		my $host_uuid = $anvil->Get->host_uuid_from_name({host_name => $server_host}); 
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
		if ($host_uuid eq $anvil->Get->host_uuid)
		{
			# Do the add here.
			update_definition($anvil, "define", "");
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0775", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output,
				return_code => $return_code,
			}});
			if ($return_code)
			{
				# Something went wrong.
				$anvil->Job->update_progress({
					progress  => 100,
					message   => "error_0138", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
					variables => {
						shell_call  => $shell_call,
						return_code => $return_code,
						output      => $output, 
					},
				});
				$anvil->nice_exit({exit_code => 1});
			}
			
			# Get the new XML
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0776", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." dumpxml --inactive ".$server_name;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			
			(my $virsh_definition, $return_code) = $anvil->System->call({shell_call => $shell_call});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				virsh_definition => $virsh_definition,
				return_code      => $return_code,
			}});
			
			# Make sure the $output is valid XML.
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0777", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			my $problem = $anvil->Server->parse_definition({
				server     => $server_name,
				source     => "from_virsh", 
				definition => $virsh_definition, 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
			
			if ($problem)
			{
				# Failed?!
				$anvil->Job->update_progress({
					progress  => 100,
					message   => "error_0434", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
				});
				$anvil->nice_exit({exit_code => 1});
			}
		
			# Update the stored definition and undefining the server
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0778", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			update_definition($anvil, "undefine", $virsh_definition);
			
			# Copy the new definition to the other host(s)
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0808", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$anvil->Server->update_definition({
				debug              => 2,
				server             => $server_name,
				new_definition_xml => $virsh_definition, 
			});
		
			# Done!
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "log_0750", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$anvil->nice_exit({exit_code => 0});
		}
		else
		{
			# Do the add on the target.
			my $use_ip = $anvil->data->{peer}{$short_host_name}{access}{ip};
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0779", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				variables => {
					server_host => $server_host, 
					use_ip      => $use_ip, 
				},
			});
			my ($output, $error, $return_code) = $anvil->Remote->call({
				shell_call => $shell_call, 
				target     => $use_ip,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				output      => $output, 
				error       => $error,
				return_code => $return_code,
			}});
			
			# Get the updated definition file.
			my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." dumpxml --inactive ".$server_name;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
			(my $virsh_definition, $error, $return_code) = $anvil->Remote->call({
				shell_call => $shell_call, 
				target     => $use_ip,
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				virsh_definition => $virsh_definition, 
				error            => $error,
				return_code      => $return_code,
			}});
			
			# Make sure the $output is valid XML.
			my $problem = $anvil->Server->parse_definition({
				server     => $server_name,
				source     => "from_virsh", 
				definition => $virsh_definition, 
			});
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
			
			if ($problem)
			{
				# Failed?!
				$anvil->Job->update_progress({
					progress  => 100,
					message   => "error_0435", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
				});
				$anvil->nice_exit({exit_code => 1});
			}
			
			$anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{xml} = $virsh_definition;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"server::${short_host_name}::${server_name}::from_virsh::xml" => $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{xml},
			}});
		
			# Updating the stored definition and undefining the server
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0780", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			update_definition($anvil, "undefine", $virsh_definition);
			
			# Done!
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "log_0750", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$anvil->nice_exit({exit_code => 0});
		}
	}
	
	return(0);
}

sub reconnect_resource
{
	my ($anvil, $short_host_name, $peer_name, $drbd_resource, $next_drbd_volume) = @_;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		short_host_name  => $short_host_name, 
		peer_name        => $peer_name, 
		drbd_resource    => $drbd_resource, 
		next_drbd_volume => $next_drbd_volume, 
	}});
	
	my $peer_disk_state = "";
	my $role            = "";
	
	# Log into the peer and disconnect, then reconnect. Then wait for the disk state to update, and 
	# return the disk state.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0781", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		variables => {
			peer_name => $peer_name, 
		},
	});
	
	my $use_ip     = $anvil->data->{peer}{$peer_name}{access}{ip};
	my $shell_call = $anvil->data->{path}{exe}{drbdadm}." disconnect ".$drbd_resource;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		use_ip     => $use_ip,
		shell_call => $shell_call, 
	}});
	my ($output, $error, $return_code) = $anvil->Remote->call({
		shell_call => $shell_call, 
		target     => $use_ip,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output,
		error       => $error, 
		return_code => $return_code, 
	}});
	
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0782", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	sleep 1;
	$shell_call = $anvil->data->{path}{exe}{drbdadm}." connect ".$drbd_resource;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		use_ip     => $use_ip,
		shell_call => $shell_call, 
	}});
	($output, $error, $return_code) = $anvil->Remote->call({
		shell_call => $shell_call, 
		target     => $use_ip,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output,
		error       => $error, 
		return_code => $return_code, 
	}});
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0750", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	
	# Now wait
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0783", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	my $waiting    = 1;
	my $wait_until = time + 300;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wait_until => $wait_until }});
	while ($waiting)
	{
		$anvil->DRBD->get_status({debug => 2});
		my $disks_ready      = 1;
		my $connection_state = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$peer_name}{'connection-state'};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_state => $connection_state }});
		if (lc($connection_state) eq "connected")
		{
			# Connected, what's the disk state for the new volume now?
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0784", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				variables => {
					drbd_resource    => $drbd_resource,
					next_drbd_volume => $next_drbd_volume, 
				},
			});
			   $peer_disk_state   = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$peer_name}{volume}{$next_drbd_volume}{'peer-disk-state'};
			my $replication_state = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$peer_name}{volume}{$next_drbd_volume}{'replication-state'};
			    $role             = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$drbd_resource}{connection}{$peer_name}{'peer-role'};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:peer_disk_state'   => $peer_disk_state, 
				's2:replication_state' => $replication_state,
				's3:role'              => $role, 
			}});
			
			if (lc($replication_state) ne "established")
			{
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0785", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				});
				$disks_ready = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disks_ready => $disks_ready }});
			}
			elsif ((not $peer_disk_state) or (lc($peer_disk_state) eq "diskless"))
			{
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0786", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				});
				$disks_ready = 0;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disks_ready => $disks_ready }});
			}
			
			if ($disks_ready)
			{
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0787", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						peer_disk_state => $peer_disk_state, 
					},
				});
				$waiting                                      = 0;
				$anvil->data->{peers}{$peer_name}{disk_state} = $peer_disk_state;
				$anvil->data->{peers}{$peer_name}{role}       = $role;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					waiting                           => 0,
					"peers::${peer_name}::disk_state" => $anvil->data->{peers}{$peer_name}{disk_state},
					"peers::${peer_name}::role"       => $anvil->data->{peers}{$peer_name}{role},
				}});
				
				return($peer_disk_state, $role);
			}
		}
		
		if (time > $wait_until)
		{
			# Timed out waiting for the peer to connect.
			$waiting = 0;
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 2}),
				message   => "log_0788", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			return($peer_disk_state, $role);
		}
		sleep 3;
	}
	
	return($peer_disk_state, $role);
}

sub manage_disk_grow
{
	my ($anvil, $drbd_resource, $drbd_volume, $max_free_space) = @_;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:drbd_resource'  => $drbd_resource,
		's2:drbd_volume'    => $drbd_volume, 
		's3:max_free_space' => $max_free_space, 
	}});
	
	my $anvil_uuid      = defined $anvil->data->{switches}{anvil_uuid} ? $anvil->data->{switches}{anvil_uuid} : "";
	my $short_host_name = $anvil->Get->short_host_name;
	my $server_name     = $anvil->data->{switches}{server_name};
	my $server_uuid     = $anvil->data->{switches}{server_uuid};
	my $from_source     = get_definition_source($anvil);
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		anvil_uuid      => $anvil_uuid, 
		short_host_name => $short_host_name,
		server_name     => $server_name, 
		server_uuid     => $server_uuid, 
		from_source     => $from_source, 
	}});
	
	if (not $anvil_uuid)
	{
		$anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
	}
	
	# Are they asking for an available amount of space?
	my $add_size =  $anvil->data->{switches}{grow};
	   $add_size =~ s/^\+//;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
	if ($add_size =~ /^(\d+)%$/)
	{
		# This is valid
		my $percent = ".".$1;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { percent => $percent }});
		
		$add_size = int($max_free_space * $percent);
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
	}
	elsif ($add_size !~ /\d/)
	{
		# No digits, probably didn't set a value at all.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 10}),
			message   => "error_0436", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				max_free_space => $anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}), 
			},
		});
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "log_0789", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		$anvil->nice_exit({exit_code => 1});
	}
	elsif ($add_size !~ /^\d+$/)
	{
		# Size is not in bytes, try to convert it.
		my $bytes = $anvil->Convert->human_readable_to_bytes({
			debug => 2,
			size  => $add_size,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'bytes' => $bytes }});
		if ($bytes =~ /^\d+$/)
		{
			$add_size = $bytes;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
		}
		else
		{
			# Not a valid size.
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 10}),
				message   => "error_0424", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
			});
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "log_0789", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	# Make sure they're asking for a reasonable size
	if ($add_size < 4194304)
	{
		# Must be a typo, this is less than the size of a single extent.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 10}),
			message   => "error_0438", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				add_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $add_size}), 
			},
		});
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "log_0789", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		$anvil->nice_exit({exit_code => 1});
	}
	elsif ($add_size > $max_free_space)
	{
		# Not enough space.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 10}),
			message   => "error_0439", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				add_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $add_size}), 
				max_free_space => $anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}), 
			},
		});
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "log_0789", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Are they asking for an available amount of space?
	my $say_up   = $anvil->Words->string({key => 'message_0331'});
	my $say_down = $anvil->Words->string({key => 'message_0332'});
	
	### TODO: Make this work without the peer node being online.
	# The server is allowed to be running, but both nodes and any DR hosts this is replicating to
	# needs to be online.
	my $all_online = check_drbd_peer_access($anvil);
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
	
	if (not $all_online)
	{
		# All peers have to be online.
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 10}),
			message   => "error_0440", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
		});
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{peer}})
		{
			my $say_access = $anvil->data->{peer}{$short_host_name}{access_ip} ? $say_up : $say_down;
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 1}),
				message   => "error_0428", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
				variables => {
					host_name => $short_host_name,
					access    => $say_access,
				},
			});
		}
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "job_0471", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Still here? We're good to go.
	my $lv_command_size = 0;
	my $hr_size         = $anvil->Convert->bytes_to_human_readable({'bytes' => $add_size});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hr_size => $hr_size }});
	if ($add_size eq "100%")
	{
		# This is valid
		$add_size = "-l +100\%FREE";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
	}
	else
	{
		$hr_size  =~ s/\s+//g;
		$add_size =  "-L +".$hr_size;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
	}
	
	# Preparing to grow the storage
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 5}),
		message   => "log_0790", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		variables => {
			size => $hr_size, 
		},
	});
	if ((not $anvil->data->{switches}{confirm}) && (not $anvil->data->{switches}{'job-uuid'}))
	{
		$anvil->System->_abort_if_ci();
		print $anvil->Words->string({key => "message_0021"})." ";
		my $answer = <STDIN>;
		chomp($answer);
		if ($answer !~ /^y/i)
		{
			# Abort
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "message_0022", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$anvil->nice_exit({exit_code => 0});
		}
		
		# Test that we've lost access while waiting for the answer.
		my $all_online = check_drbd_peer_access($anvil);
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
		
		if (not $all_online)
		{
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 5}),
				message   => "error_0441", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{peer}})
			{
				my $say_access = $anvil->data->{peer}{$short_host_name}{access_ip} ? $say_up : $say_down;
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 1}),
					message   => "error_0428", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
					variables => {
						host_name => $short_host_name,
						access    => $say_access,
					},
				});
			}
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "job_0471", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			});
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	foreach my $host_type ("node", "dr")
	{
		foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
		{
			my $host_uuid       = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
			my $this_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
			my $dr_link_uuid    = exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid} ? $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}{dr_link_uuid} : "";
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:short_host_name' => $short_host_name,
				's2:host_uuid'       => $host_uuid, 
				's3:this_anvil_uuid' => $this_anvil_uuid, 
				's4:dr_link_uuid'    => $dr_link_uuid, 
			}});
			
			# If this host is from another node or unrelated DR host, skip it. 
			next if (($host_type eq "node") && ($anvil_uuid ne $this_anvil_uuid));
			next if (($host_type eq "dr") && (not $dr_link_uuid));
			
			my $backing_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$drbd_volume}{backing_disk};
			my $shell_call   = $anvil->data->{path}{exe}{lvextend}." ".$add_size." ".$backing_disk;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:backing_disk' => $backing_disk, 
				's2:shell_call'   => $shell_call, 
			}});
			if ($host_uuid eq $anvil->Get->host_uuid)
			{
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 1}),
					message   => "log_0791", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						backing_disk => $backing_disk, 
					},
				});
				my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output,
					return_code => $return_code, 
				}});
				if ($return_code)
				{
					$anvil->Job->update_progress({
						progress  => 100,
						message   => "error_0442", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						priority  => "err",
						variables => {
							backing_disk => $backing_disk, 
							shell_call   => $shell_call, 
							return_code  => $return_code, 
							output       => $output, 
						},
					});
					$anvil->nice_exit({exit_code => 1});
				}
				else
				{
					# Done
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "log_0750", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					});
				}
			}
			else
			{
				my $use_ip      = $anvil->data->{peer}{$short_host_name}{access}{ip};
				my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0792", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						host_name    => $short_host_name, 
						backing_disk => $backing_disk,
						use_ip       => $use_ip, 
						use_network  => $use_network, 
					},
				});
				my ($output, $error, $return_code) = $anvil->Remote->call({
					shell_call => $shell_call, 
					target     => $use_ip,
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					output      => $output, 
					error       => $error,
					return_code => $return_code,
				}});
				if ($return_code)
				{
					$anvil->Job->update_progress({
						progress  => 100,
						message   => "error_0443", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						priority  => "err",
						variables => {
							backing_disk => $backing_disk, 
							shell_call   => $shell_call, 
							return_code  => $return_code, 
							output       => $output, 
							error        => $error, 
						},
					});
					$anvil->nice_exit({exit_code => 1});
				}
				else
				{
					# Done
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "log_0750", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					});
				}
			}
		}
	}
	
	# Locally, we'll call DRBD to resize.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0793", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	my $shell_call = $anvil->data->{path}{exe}{drbdadm}." resize ".$drbd_resource."/".$drbd_volume;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		output      => $output,
		return_code => $return_code, 
	}});
	if ($return_code)
	{
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "error_0444", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				drbd_resource => $drbd_resource, 
				drbd_volume   => $drbd_volume, 
				shell_call    => $shell_call, 
				return_code   => $return_code, 
				output        => $output, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	else
	{
		# Done
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0750", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		});
	}
	
	# Call scan-lvm and scan-drbd to make sure the databases are updated.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 2}),
		message   => "log_0794", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	foreach my $agent ("scan-drbd", "scan-lvm")
	{
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 2}),
			message   => "log_0740", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			variables => {
				agent => $agent, 
			},
		});
		
		my $shell_call = $anvil->data->{path}{directories}{scan_agents}."/".$agent."/".$agent.$anvil->Log->switches();
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		foreach my $host_type ("node", "dr")
		{
			foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
			{
				my $host_uuid       = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
				my $this_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
				my $dr_link_uuid    = exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid} ? $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}{dr_link_uuid} : "";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:short_host_name' => $short_host_name,
					's2:host_uuid'       => $host_uuid, 
					's3:this_anvil_uuid' => $this_anvil_uuid, 
					's4:dr_link_uuid'    => $dr_link_uuid, 
				}});
				
				# If this host is from another node or unrelated DR host, skip it. 
				next if (($host_type eq "node") && ($anvil_uuid ne $this_anvil_uuid));
				next if (($host_type eq "dr") && (not $dr_link_uuid));
				
				if ($host_uuid eq $anvil->Get->host_uuid)
				{
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "log_0795", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						variables => {
							agent => $agent, 
						},
					});
					my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						output      => $output,
						return_code => $return_code, 
					}});
					
					# Done
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "log_0750", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					});
				}
				else
				{
					my $use_ip      = $anvil->data->{peer}{$short_host_name}{access}{ip};
					my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "log_0796", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						variables => {
							agent       => $agent,
							host_name   => $short_host_name, 
							use_ip      => $use_ip, 
							use_network => $use_network, 
						},
					});
					my ($output, $error, $return_code) = $anvil->Remote->call({
						shell_call => $shell_call, 
						target     => $use_ip,
					});
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						output      => $output, 
						error       => $error,
						return_code => $return_code,
					}});
					
					# Done
					$anvil->Job->update_progress({
						progress  => $anvil->Job->bump_progress({steps => 2}),
						message   => "log_0750", 
						log_level => 1, 
						'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					});
				}
			}
		}
	}
	
	# Success!
	$anvil->Job->update_progress({
		progress  => 100,
		message   => "log_0797", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	
	return(0);
}

sub manage_optical
{
	my ($anvil) = @_;
	
	my $short_host_name = $anvil->Get->short_host_name;
	my $server_name     = $anvil->data->{switches}{server_name};
	my $server_uuid     = $anvil->data->{switches}{server_uuid};
	my $from_source     = get_definition_source($anvil);
	my $anvil_uuid      = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		short_host_name => $short_host_name,
		server_name     => $server_name, 
		server_uuid     => $server_uuid, 
		from_source     => $from_source, 
		anvil_uuid      => $anvil_uuid, 
	}});
	
	if (not $anvil->data->{switches}{optical})
	{
		# If there's only one optical drive, select it automatically
		my $count = keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
		if ($count == 1)
		{
			foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}})
			{
				$anvil->data->{switches}{optical} = $device_target;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"switches::drive" => $anvil->data->{switches}{optical},
				}});
				last;
			}
		}
		else
		{
			foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}})
			{
				my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{path};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					device_target => $device_target,
					device_path   => $device_path, 
				}});
			}
		}
		
		if (not $anvil->data->{switches}{optical})
		{
			# Can't proceed.
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "error_0445", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
			});
			show_server_details($anvil, 1);
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	# If the device target isn't specified but there's only one disc drive, select it.
	if ((not $anvil->data->{switches}{optical}) or ($anvil->data->{switches}{optical} eq "#!SET!#"))
	{
		my $device_count = keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device_count => $device_count }});
		
		if ($device_count == 1)
		{
			foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}})
			{
				$anvil->data->{switches}{optical} = $device_target; 
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"switches::optical" => $anvil->data->{switches}{optical},
				}});
				last;
			}
		}
	}
	
	# If the user specified a disc to insert using just the file name, prepend the directory.
	if ($anvil->data->{switches}{insert})
	{
		my $iso = $anvil->data->{switches}{insert};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { iso => $iso }});
		if ($iso !~ /^\//)
		{
			foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}})
			{
				my $file_location_file_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid};
				my $file_directory          = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_directory};
				my $full_path               = $file_directory."/".$file_name;
				my $file_size               = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_size};
				my $file_md5sum             = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_md5sum};
				my $file_type               = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_type};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:file_name'      => $file_name, 
					's2:file_directory' => $file_directory,
					's3:full_path'      => $full_path,
					's4:file_size'      => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")", 
					's5:file_md5sum'    => $file_md5sum,
					's6:file_type'      => $file_type, 
				}});
				next if $iso ne $file_name;
				next if $file_type ne "iso";
				
				if (-f $full_path)
				{
					# Use this.
					$anvil->data->{switches}{insert} = $full_path;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						"switches::insert" => $anvil->data->{switches}{insert},
					}});
					last;
				}
			}
		}
	}
	
	my $device_target = $anvil->data->{switches}{optical};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device_target => $device_target }});
	
	if ((not $anvil->data->{switches}{optical}) or ($anvil->data->{switches}{optical} eq "#!SET!#"))
	{
		# User didn't specify a device.
		show_server_details($anvil, 0);
		show_files($anvil);
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "error_0446", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
		});
		$anvil->nice_exit({exit_code => 1});
	}
	elsif (not exists $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target})
	{
		# Invalid device target
		show_server_details($anvil, 0);
		show_files($anvil);
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "error_0447", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				device_target => $device_target, 
			},
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	my $eject_first        = 0;
	my $alias              = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{alias};
	my $boot_order         = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{boot_order};
	my $say_boot           = $boot_order eq "99" ? "--" : sprintf("%02d", $boot_order);
	my $type               = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{type};
	my $address_type       = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{address}{type};
	my $address_bus        = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{address}{bus};
	my $driver_name        = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{driver}{name};
	my $device_bus         = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{device_bus};
	my $driver_type        = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{driver}{type};
	my $address_controller = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{address}{controller};
	my $address_unit       = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{address}{unit};
	my $address_target     = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{address}{target};
	my $device_path        = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{cdrom}{target}{$device_target}{path};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's01:device_target'      => $device_target,
		's02:alias'              => $alias, 
		's03:boot_order'         => $boot_order,
		's04:say_boot'           => $say_boot, 
		's05:type'               => $type, 
		's06:address_type'       => $address_type, 
		's07:address_bus'        => $address_bus, 
		's08:driver_name'        => $driver_name, 
		's09:device_bus'         => $device_bus, 
		's10:driver_type'        => $driver_type, 
		's11:address_controller' => $address_controller,
		's12:address_unit'       => $address_unit, 
		's13:address_target'     => $address_target, 
		's14:device_path'        => $device_path, 
	}});
	
	# Without a --source, the result is an eject.
	my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." change-media ".$server_name." --path ".$device_target." --update --live --config";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	if ($anvil->data->{switches}{insert})
	{
		# Make sure the new target exists.
		my $iso = $anvil->data->{switches}{insert};
		if (not -f $iso)
		{
			update_definition($anvil, "undefine", "");
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "error_0448", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
				variables => {
					iso => $iso, 
				},
			});
			$anvil->nice_exit({exit_code => 1});
		}
		else
		{
			$shell_call .= " --source ".$anvil->data->{switches}{insert};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		}
	}
	
	# If the server is running, update the on-disk and in-DB definition.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 5}),
		message   => "log_0798", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		variables => {
			server_name => $server_name, 
		},
	});
	update_definition($anvil, "define", "");
	
	# Now we can modify the server using virsh.
	if ($anvil->data->{switches}{insert})
	{
		# Inserting 
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 5}),
			message   => "log_0799", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			variables => {
				insert        => $anvil->data->{switches}{insert}, 
				device_target => $device_target, 
			},
		});
	}
	elsif ($anvil->data->{switches}{eject})
	{
		# Ejecting
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 5}),
			message   => "log_0800", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			variables => {
				device_path   => $device_path, 
				device_target => $device_target, 
			},
		});
	}
	else
	{
		# Show the ISO in the drive.
		if ($device_path)
		{
			# Disc is already in the drive
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "error_0449", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
				variables => {
					device_target => $device_target, 
					device_path   => $device_path, 
				},
			});
		}
		else
		{
			# Drive has no disc in it.
			$anvil->Job->update_progress({
				progress  => 100,
				message   => "error_0450", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				priority  => "err",
				variables => {
					device_target => $device_target, 
				},
			});
		}
		$anvil->nice_exit({exit_code => 0});
	}
	my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:output'      => $output,
		's2:return_code' => $return_code, 
	}});
	
	# Updating the stored definition and undefining the server now
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 5}),
		message   => "log_0801", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	update_definition($anvil, "undefine", "");
	
	# Done
	$anvil->Job->update_progress({
		progress  => 100,
		message   => "log_0750", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	
	return(0);
}

sub get_definition_source
{
	my ($anvil) = @_;
	
	my $short_host_name  = $anvil->Get->short_host_name;
	my $server_name      = $anvil->data->{switches}{server_name};
	my $server_uuid      = $anvil->data->{switches}{server_uuid};
	my $server_state     = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
	my $from_source      = "";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		short_host_name => $short_host_name,
		server_name     => $server_name, 
		server_uuid     => $server_uuid, 
		server_state    => $server_state, 
		from_source     => $from_source, 
	}});
	
	$anvil->data->{server}{$short_host_name}{$server_name}{from_virsh} = "" if not exists $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh};
	$anvil->data->{server}{$short_host_name}{$server_name}{from_disk}  = "" if not exists $anvil->data->{server}{$short_host_name}{$server_name}{from_disk};
	$anvil->data->{server}{$short_host_name}{$server_name}{from_db}    = "" if not exists $anvil->data->{server}{$short_host_name}{$server_name}{from_db};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"server::${short_host_name}::${server_name}::from_virsh" => $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh},
		"server::${short_host_name}::${server_name}::from_disk"  => $anvil->data->{server}{$short_host_name}{$server_name}{from_disk},
		"server::${short_host_name}::${server_name}::from_db"    => $anvil->data->{server}{$short_host_name}{$server_name}{from_db},
	}});
	
	if (($server_state eq "running")                    && 
	    ($server_host_uuid eq $anvil->Get->host_uuid()) && 
	    (exists $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}))
	{
		$from_source = "from_virsh";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { from_source => $from_source }});
	}
	elsif (exists $anvil->data->{server}{$short_host_name}{$server_name}{from_disk})
	{
		$from_source = "from_disk";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { from_source => $from_source }});
	}
	else
	{
		$from_source = "from_db";
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { from_source => $from_source }});
	}

	return($from_source);
}

sub show_server_details
{
	my ($anvil, $show_nodes) = @_;
	
	my $short_host_name = $anvil->Get->short_host_name;
	my $host_uuid       = $anvil->Get->host_uuid;
	my $server_name     = $anvil->data->{switches}{server_name};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:short_host_name' => $short_host_name,
		's2:host_uuid'       => $host_uuid,
		's3:server_name'     => $server_name, 
		's4:show_nodes'      => $show_nodes, 
	}});
	
	# Load storage data
	my $drbd_resource = load_storage($anvil);
	
	my $from_source = get_definition_source($anvil);
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { from_source => $from_source }});
	foreach my $device ("disk", "cdrom")
	{
		if ($device eq "disk")
		{
			# Disk drives
			if (not $anvil->data->{switches}{machine})
			{
				print "\n".$anvil->Words->string({key => "message_0334"})."\n";
			}
		}
		else
		{
			# Optical drives
			if (not $anvil->data->{switches}{machine})
			{
				print "\n".$anvil->Words->string({key => "message_0335"})."\n";
			}
		}
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }});
		next if $device ne "cdrom" &&  $device ne "disk";
		foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}})
		{
			my $alias        = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{alias};
			my $boot_order   = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{boot_order};
			my $say_boot     = $boot_order eq "99" ? "--" : sprintf("%02d", $boot_order);
			my $type         = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{type};
			my $address_type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{type};
			my $address_bus  = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{bus};
			my $driver_name  = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{name};
			my $device_bus   = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{device_bus};
			my $driver_type  = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{type};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's01:device_target' => $device_target,
				's02:alias'         => $alias, 
				's03:boot_order'    => $boot_order,
				's04:say_boot'      => $say_boot, 
				's05:type'          => $type, 
				's06:address_type'  => $address_type, 
				's07:address_bus'   => $address_bus, 
				's08:driver_name'   => $driver_name, 
				's09:device_bus'    => $device_bus, 
				's10:driver_type'   => $driver_type, 
			}});
			if ($device eq "disk")
			{
				my $address_domain   = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{domain};
				my $address_slot     = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{slot};
				my $address_function = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{function};
				my $device_path      = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{path};
				my $driver_io        = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{io};
				my $driver_cache     = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{cache};
				my $on_lv            = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv};
				my $drbd_resource    = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{resource};
				my $drbd_volume      = $anvil->data->{lvm}{host_name}{$short_host_name}{lv_path}{$on_lv}{drbd}{volume};
				next if not defined $drbd_volume or $drbd_volume eq "";
				my $resource_size    = $anvil->data->{drbd}{host_name}{$short_host_name}{resource_name}{$drbd_resource}{volume}{$drbd_volume}{volume_size};
				my $lv_name          = $anvil->data->{lvm}{host_name}{$short_host_name}{lv_path}{$on_lv}{scan_lvm_lv_name};
				my $lv_size          = $anvil->data->{lvm}{host_name}{$short_host_name}{lv}{$lv_name}{scan_lvm_lv_size};
				my $metadata_size    = $lv_size - $resource_size;
				my $max_free_space   = get_max_free_space($anvil, $drbd_resource, $drbd_volume);
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's01:address_domain'   => $address_domain,
					's02:address_slot'     => $address_slot, 
					's03:address_function' => $address_function, 
					's04:device_path'      => $device_path, 
					's05:driver_io'        => $driver_io, 
					's06:driver_cache'     => $driver_cache, 
					's07:on_lv'            => $on_lv, 
					's08:lv_name'          => $lv_name, 
					's09:drbd_resource'    => $drbd_resource, 
					's10:drbd_volume'      => $drbd_volume, 
					's11:resource_size'    => $anvil->Convert->bytes_to_human_readable({'bytes' => $resource_size})." (".$anvil->Convert->add_commas({number => $resource_size}).")", 
					's12:lv_size'          => $anvil->Convert->bytes_to_human_readable({'bytes' => $lv_size})."] (".$anvil->Convert->add_commas({number => $lv_size}).")", 
					's13:metadata_size'    => $anvil->Convert->bytes_to_human_readable({'bytes' => $metadata_size})."] (".$anvil->Convert->add_commas({number => $metadata_size}).")",
					's14:max_free_space'   => $max_free_space." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}).")",
				}});
				
				if ($anvil->data->{switches}{machine})
				{
					$anvil->data->{xml}{body} .= "\t<disk target=\"".$anvil->Words->escape_xml({string => $device_target})."\" ";
					$anvil->data->{xml}{body} .= "boot-order=\"".$anvil->Words->escape_xml({string => $say_boot})."\" ";
					$anvil->data->{xml}{body} .= "drbd-resource=\"".$anvil->Words->escape_xml({string => $drbd_resource})."\" ";
					$anvil->data->{xml}{body} .= "drbd-volume=\"".$anvil->Words->escape_xml({string => $drbd_volume})."\" ";
					$anvil->data->{xml}{body} .= "resource-size=\"".$anvil->Words->escape_xml({string => $resource_size})."B\" ";
					$anvil->data->{xml}{body} .= "lv-size=\"".$anvil->Words->escape_xml({string => $lv_size})."B\" ";
					$anvil->data->{xml}{body} .= "metadata-size=\"".$anvil->Words->escape_xml({string => $metadata_size})."B\" />\n";
				}
				else
				{
					print $anvil->Words->string({key => "message_0336", variables => {
						device_target => $device_target, 
						say_boot      => $say_boot, 
						drbd_resource => $drbd_resource, 
						drbd_volume   => $drbd_volume, 
					}})."\n";
					print $anvil->Words->string({key => "message_0337", variables => {
						resource_size  => $anvil->Convert->bytes_to_human_readable({'bytes' => $resource_size}), 
						lv_size        => $anvil->Convert->bytes_to_human_readable({'bytes' => $lv_size}),
						metadata_size  => $anvil->Convert->bytes_to_human_readable({'bytes' => $metadata_size}), 
						max_free_space => $anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}), 
					}})."\n";
				}
			}
			else
			{
				my $address_controller = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{controller};
				my $address_unit       = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{unit};
				my $address_target     = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{target};
				my $device_path        = "<empty>";
				if (defined $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{path})
				{
					$device_path = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{path};
				}
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:address_controller' => $address_controller,
					's2:address_unit'       => $address_unit, 
					's3:address_target'     => $address_target, 
					's4:device_path'        => $device_path, 
				}});
				if ($anvil->data->{switches}{machine})
				{
					$anvil->data->{xml}{body} .= "\t<optical target=\"".$anvil->Words->escape_xml({string => $device_target})."\" ";
					$anvil->data->{xml}{body} .= "boot-order=\"".$anvil->Words->escape_xml({string => $say_boot})."\" ";
					$anvil->data->{xml}{body} .= "iso=\"".$anvil->Words->escape_xml({string => $device_path})."\" />\n";
				}
				else
				{
					print $anvil->Words->string({key => "message_0338", variables => {
						device_target => $device_target, 
						say_boot      => $say_boot, 
						device_path   => $device_path, 
					}})."\n";
				}
			}
		}
	}
	if (not $anvil->data->{switches}{machine})
	{
		print "\n";
	}
	
	if ($show_nodes)
	{
		if (not $anvil->data->{switches}{machine})
		{
			print $anvil->Words->string({key => "message_0339"})."\n";
		}
		show_volume($anvil, $drbd_resource, "node");
		
		my $dr_count = keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{dr}{short_host_name}};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr_count => $dr_count }});
		if ($dr_count)
		{
			if (not $anvil->data->{switches}{machine})
			{
				print $anvil->Words->string({key => "message_0340"})."\n";
			}
			show_volume($anvil, $drbd_resource, "dr");
		}
	}
	if ($anvil->data->{switches}{machine})
	{
		$anvil->data->{xml}{body} .= "</server>\n";
		print $anvil->data->{xml}{body};
	}
	
	return(0);
}

sub check_drbd_peer_access
{
	my ($anvil) = @_;
	
	# Report that we're going to test access and that this could take some time.
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 1}),
		message   => "job_0016", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
	});
	
	my $all_online = 1;
	foreach my $this_host (sort {$a cmp $b} keys %{$anvil->data->{drbd}{drbd_node}})
	{
		my $host_uuid       = $anvil->Get->host_uuid_from_name({host_name => $this_host});
		my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:this_host'       => $this_host, 
			's2:host_uuid'       => $host_uuid, 
			's3:short_host_name' => $short_host_name, 
		}});
		next if $host_uuid eq $anvil->Get->host_uuid;
		
		$anvil->Job->update_progress({
			progress  => $anvil->Job->bump_progress({steps => 1}),
			message   => "job_0018", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			variables => {
				host_name => $short_host_name, 
			},
		});
		
		# This is used to store the IP we used to access the peer. If no access is available, this 
		# shows which hosts are not available.
		$anvil->data->{peer}{$short_host_name}{access}{ip}      = "";
		$anvil->data->{peer}{$short_host_name}{access}{network} = "";
		$anvil->data->{peer}{$short_host_name}{host_uuid}       = $host_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"s1:peer::${short_host_name}::host_uuid" => $anvil->data->{peer}{$short_host_name}{host_uuid}, 
		}});
		
		my $access    = 0;
		my ($target_ip, $target_network) = $anvil->Network->find_target_ip({
			host_uuid   => $host_uuid, 
			networks    => "bcn,mn,ifn,sn,any", 
			ping        => 1,
			test_access => 1, 
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			target_ip      => $target_ip,
			target_network => $target_network,
		}});
		
		if ($target_ip)
		{
			# We're good.
			$access                                                 = 1;
			$anvil->data->{peer}{$short_host_name}{access}{ip}      = $target_ip;
			$anvil->data->{peer}{$short_host_name}{access}{network} = $target_network;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:access'                                    => $access, 
				"s2:peer::${short_host_name}::access::ip"      => $anvil->data->{peer}{$short_host_name}{access}{ip}, 
				"s3:peer::${short_host_name}::access::network" => $anvil->data->{peer}{$short_host_name}{access}{network}, 
			}});
			
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 1}),
				message   => "job_0019", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				variables => {
					host_name => $short_host_name, 
					target_ip => $target_ip, 
					network   => $target_network,
				},
			});
		}
		else
		{
			$all_online = 0;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
			$anvil->Job->update_progress({
				progress  => $anvil->Job->bump_progress({steps => 1}),
				message   => "job_0058", 
				log_level => 1, 
				'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
				variables => {
					host_name => $short_host_name, 
				},
			});
		}
	}
	
	# If there's a DR host, make sure the DRBD resource is up. If not, mark that we're connecting it so 
	# we can disconnect it when we're done.
	if ($all_online)
	{
		$anvil->DRBD->get_status({debug => 2});
		my $short_host_name = $anvil->Get->short_host_name;
		my $server_name     = $anvil->data->{switches}{server_name};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:short_host_name' => $short_host_name,
			's2:server_name'     => $server_name,
		}});
		foreach my $peer_name (sort {$a cmp $b} keys %{$anvil->data->{drbd}{status}{$short_host_name}{resource}{$server_name}{connection}})
		{
			my $connection_state = $anvil->data->{drbd}{status}{$short_host_name}{resource}{$server_name}{connection}{$peer_name}{'connection-state'};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:peer_name'        => $peer_name,
				's2:connection_state' => $connection_state,
			}});
			if ($connection_state !~ /Connected/i)
			{
				# We need to connect the DRBD resource
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 1}),
					message   => "job_0053", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						host_name => $peer_name, 
					},
				});
				
				my $target_ip  = $anvil->data->{peer}{$peer_name}{access}{ip};
				my $shell_call = $anvil->data->{path}{exe}{drbdsetup}." status ".$server_name." || ".$anvil->data->{path}{exe}{drbdadm}." up ".$server_name;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:target_ip'  => $target_ip, 
					's2:shell_call' => $shell_call,
				}});
				my ($output, $error, $return_code) = $anvil->Remote->call({
					target     => $target_ip, 
					shell_call => $shell_call,
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					error       => $error,
					output      => $output,
					return_code => $return_code, 
				}});
				
				$anvil->data->{connected_resource}{$peer_name} = 1;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					"connected_resource::${peer_name}" => $anvil->data->{connected_resource}{$peer_name},
				}});
			}
		}
	}
	
	return($all_online);
}

sub get_max_free_space
{
	my ($anvil, $drbd_resource, $drbd_volume) = @_;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's01:drbd_resource' => $drbd_resource,
		's02:drbd_volume'   => $drbd_volume,
	}});
	
	my $max_free_space = 0;
	foreach my $this_host (sort {$a cmp $b} keys %{$anvil->data->{drbd}{drbd_node}})
	{
		my $drbd_path        = $anvil->data->{drbd}{drbd_node}{$this_host}{config}{resource}{$drbd_resource}{volume}{$drbd_volume}{drbd_path};
		my $drbd_path_by_res = $anvil->data->{drbd}{drbd_node}{$this_host}{config}{resource}{$drbd_resource}{volume}{$drbd_volume}{drbd_path_by_res};
		my $backing_lv       = $anvil->data->{drbd}{drbd_node}{$this_host}{config}{resource}{$drbd_resource}{volume}{$drbd_volume}{backing_lv};
		my $lv_name          = $anvil->data->{lvm}{host_name}{$this_host}{lv_path}{$backing_lv}{scan_lvm_lv_name} ? $anvil->data->{lvm}{host_name}{$this_host}{lv_path}{$backing_lv}{scan_lvm_lv_name} : "";
		my $on_vg            = $anvil->data->{lvm}{host_name}{$this_host}{lv}{$lv_name}{scan_lvm_lv_on_vg}        ? $anvil->data->{lvm}{host_name}{$this_host}{lv}{$lv_name}{scan_lvm_lv_on_vg}        : "";
		my $vg_free_space    = $anvil->data->{lvm}{host_name}{$this_host}{vg}{$on_vg}{scan_lvm_vg_free}           ? $anvil->data->{lvm}{host_name}{$this_host}{vg}{$on_vg}{scan_lvm_vg_free}           : 0;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's01:this_host'        => $this_host,
			's02:drbd_path'        => $drbd_path, 
			's03:drbd_path_by_res' => $drbd_path_by_res, 
			's04:backing_lv'       => $backing_lv, 
			's05:on_vg'            => $on_vg, 
			's06:vg_free_space'    => $vg_free_space." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $vg_free_space}).")",
		}});
		if ((not $max_free_space) or ($vg_free_space < $max_free_space))
		{
			$max_free_space = $vg_free_space;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				max_free_space => $max_free_space." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}).")",
			}});
		}
	}
	
	return($max_free_space);
}

sub load_drbd_data
{
	my ($anvil, $drbd_resource) = @_;
	
	my $query = "
SELECT 
    a.host_uuid, 
    b.scan_drbd_resource_xml, 
    c.scan_drbd_volume_number, 
    c.scan_drbd_volume_device_path, 
    c.scan_drbd_volume_device_minor, 
    c.scan_drbd_volume_size 
FROM 
    hosts a, 
    scan_drbd_resources b, 
    scan_drbd_volumes c 
WHERE 
    a.host_uuid = b.scan_drbd_resource_host_uuid 
AND 
    b.scan_drbd_resource_uuid = c.scan_drbd_volume_scan_drbd_resource_uuid 
AND 
    b.scan_drbd_resource_name = ".$anvil->Database->quote($drbd_resource)."
;";
	$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 $host_uuid               = $row->[0];
		my $short_host_name         = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
		my $host_type               = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
		my $scan_drbd_volume_number = $row->[2];
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:host_uuid'               => $host_uuid, 
			's2:host_type'               => $host_type, 
			's3:short_host_name'         => $short_host_name, 
			's4:scan_drbd_volume_number' => $scan_drbd_volume_number, 
		}});
		
		$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_path}  = $row->[3];
		$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_minor} = $row->[4];
		$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{volume_size}  = $row->[5];
		$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid}          = $host_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"s1:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::device_path"  => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_path}, 
			"s2:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::device_minor" => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_minor}, 
			"s3:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::volume_size"  => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{volume_size}, 
			"s4:drbd_resource::${drbd_resource}::host_type::${host_type}::short_host_name::${short_host_name}::host_uuid"          => $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid}, 
		}});
		
		if (not exists $anvil->data->{drbd_resource}{$drbd_resource}{xml})
		{
			$anvil->data->{drbd_resource}{$drbd_resource}{xml} = $row->[1];
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				"drbd_resource::${drbd_resource}::xml" => $anvil->data->{drbd_resource}{$drbd_resource}{xml}, 
			}});
			$anvil->DRBD->parse_resource({
				debug => 2, 
				xml   => $anvil->data->{drbd_resource}{$drbd_resource}{xml}, 
			});
		}
	}
	
	return(0);
}

sub show_volume
{
	my ($anvil, $drbd_resource, $host_type) = @_;
	
	my $anvil_uuid  = defined $anvil->data->{switches}{anvil_uuid} ? $anvil->data->{switches}{anvil_uuid} : "";
	my $server_name = $anvil->data->{switches}{server_name};
	my $server_uuid = $anvil->data->{switches}{server_uuid};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		anvil_uuid  => $anvil_uuid, 
		server_name => $server_name, 
		server_uuid => $server_uuid, 
	}});
	
	if (not $anvil_uuid)
	{
		$anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
	}
	
	if ($anvil->data->{switches}{machine})
	{
		$anvil->data->{xml}{body} .= "\t<hosts>\n";
	}
	foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
	{
		my $host_uuid = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:short_host_name' => $short_host_name,
			's2:host_uuid'       => $host_uuid, 
		}});
		if ($anvil->data->{switches}{machine})
		{
			my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
			$anvil->data->{xml}{body} .= "\t\t<host name=\"".$anvil->Words->escape_xml({string => $short_host_name})."\" ";
			$anvil->data->{xml}{body} .= "type=\"".$anvil->Words->escape_xml({string => $host_type})."\" ";
			$anvil->data->{xml}{body} .= "uuid=\"".$anvil->Words->escape_xml({string => $host_uuid})."\">\n";
		}
		else
		{
			print $anvil->Words->string({key => "message_0341", variables => {
				host_name => $short_host_name, 
				host_uuid => $host_uuid, 
			}})."\n";
		}
		foreach my $volume_number (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}})
		{
			next if $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_path} eq "DELETED";
			my $device_path        = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_path};
			my $device_minor       = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_minor};
			my $volume_size        = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{volume_size};
			my $backing_disk       = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{backing_disk};
			next if not defined $backing_disk or $backing_disk eq "";
			my $meta_disk          = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{meta_disk};
			my $storage_group_uuid = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{storage_group_uuid};
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:volume_number'      => $volume_number,
				's2:device_path'        => $device_path, 
				's3:device_minor'       => $device_minor, 
				's4:volume_size'        => $volume_size, 
				's5:backing_disk'       => $backing_disk, 
				's6:meta_disk'          => $meta_disk, 
				's7:storage_group_uuid' => $storage_group_uuid, 
			}});
			
			my $storage_group_name       = "<unknown>";
			my $storage_group_size       = 0;
			my $storage_group_free_space = 0;
			if (($storage_group_uuid) && ($anvil_uuid) && (exists $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}))
			{
				$storage_group_name       = $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{storage_group_name};
				$storage_group_size       = $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{vg_size};
				$storage_group_free_space = $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size};
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
				's1:storage_group_size'       => $storage_group_size,
				's2:storage_group_free_space' => $storage_group_free_space, 
			}});
			if ($anvil->data->{switches}{machine})
			{
				$anvil->data->{xml}{body} .= "\t\t\t<disk drbd-volume=\"".$anvil->Words->escape_xml({string => $volume_number})."\" ";
				$anvil->data->{xml}{body} .= "backing-lv=\"".$anvil->Words->escape_xml({string => $backing_disk})."\" ";
				$anvil->data->{xml}{body} .= "lv-size=\"".$anvil->Words->escape_xml({string => $volume_size})."B\" ";
				$anvil->data->{xml}{body} .= "sg-name=\"".$anvil->Words->escape_xml({string => $storage_group_name})."\" ";
				$anvil->data->{xml}{body} .= "sg-uuid=\"".$anvil->Words->escape_xml({string => $storage_group_uuid})."\" />\n";
			}
			else
			{
				print $anvil->Words->string({key => "message_0342", variables => {
					volume_number            => $volume_number, 
					backing_disk             => $backing_disk, 
					device_minor             => $device_minor, 
					volume_size              => $anvil->Convert->bytes_to_human_readable({'bytes' => $volume_size}), 
					storage_group_name       => $storage_group_name, 
					storage_group_size       => $anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_size}), 
					storage_group_free_space => $anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free_space}), 
					
				}})."\n";
			}
			
			# How much space is available in the storage group this volume is in?
			foreach my $this_scan_lvm_lv_name (sort {$a cmp $b} keys %{$anvil->data->{lvm}{host_name}{$short_host_name}{lv}})
			{
				my $this_scan_lvm_lv_path  = $anvil->data->{lvm}{host_name}{$short_host_name}{lv}{$this_scan_lvm_lv_name}{scan_lvm_lv_path}; 
				my $this_scan_lvm_lv_on_vg = $anvil->data->{lvm}{host_name}{$short_host_name}{lv}{$this_scan_lvm_lv_name}{scan_lvm_lv_on_vg}; 
				my $this_scan_lvm_lv_uuid  = $anvil->data->{lvm}{host_name}{$short_host_name}{lv}{$this_scan_lvm_lv_name}{scan_lvm_lv_uuid};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:this_scan_lvm_lv_name'  => $this_scan_lvm_lv_name, 
					's2:this_scan_lvm_lv_path'  => $this_scan_lvm_lv_path,
					's3:this_scan_lvm_lv_on_vg' => $this_scan_lvm_lv_on_vg, 
					's4:this_scan_lvm_lv_uuid'  => $this_scan_lvm_lv_uuid, 
				}});
				if ($backing_disk eq $this_scan_lvm_lv_path)
				{
					# What's the VG's UUID? 
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
						's1:short_host_name'        => $short_host_name, 
						's2:this_scan_lvm_lv_on_vg' => $this_scan_lvm_lv_on_vg, 
					}});
					if (exists $anvil->data->{lvm}{host_name}{$short_host_name}{vg}{$this_scan_lvm_lv_on_vg})
					{
						my $scan_lvm_vg_internal_uuid = $anvil->data->{lvm}{host_name}{$short_host_name}{vg}{$this_scan_lvm_lv_on_vg}{scan_lvm_vg_internal_uuid};
						my $storage_group_uuid        = $anvil->data->{lvm}{host_name}{$short_host_name}{vg}{$this_scan_lvm_lv_on_vg}{storage_group_uuid};
						$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
							's1:scan_lvm_vg_internal_uuid' => $scan_lvm_vg_internal_uuid, 
							's2:storage_group_uuid'        => $storage_group_uuid, 
						}});
						
						if ($storage_group_uuid)
						{
							my $vg_size   = $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{vg_size};
							my $free_size = $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size};
						}
					}
				}
			}
		}
		if ($anvil->data->{switches}{machine})
		{
			$anvil->data->{xml}{body} .= "\t\t</host>\n";
		}
	}
	if ($anvil->data->{switches}{machine})
	{
		$anvil->data->{xml}{body} .= "\t</hosts>\n";
	}
	
	return(0);
}

sub validate_server
{
	my ($anvil) = @_;
	
	$anvil->Get->server_from_switch({
		debug      => 2, 
		string     => $anvil->data->{switches}{server},
		anvil_uuid => $anvil->data->{switches}{anvil_uuid},
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"switches::server_name" => $anvil->data->{switches}{server_name},
		"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
	}});
	
	if (not $anvil->data->{switches}{server_uuid})
	{
		show_server_list($anvil);
		my $key = "";
		if ($anvil->data->{switches}{anvil_uuid})
		{
			# Not found on the requested Anvil! node.
			$key = "error_0451";
		}
		else
		{
			# Not found at all.
			$key = "error_0452";
		}
		$anvil->Job->update_progress({
			progress  => 100,
			message   => $key, 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				server => $anvil->data->{switches}{server}, 
				anvil  => $anvil->data->{switches}{anvil_name}, 
			}, 
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	if ($anvil->data->{switches}{machine})
	{
		$anvil->data->{xml}{body} = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
		$anvil->data->{xml}{body} .= "<server name=\"".$anvil->Words->escape_xml({string => $anvil->data->{switches}{server_name}})."\" ";
		$anvil->data->{xml}{body} .= "uuid=\"".$anvil->Words->escape_xml({string => $anvil->data->{switches}{server_uuid}})."\" >\n";
	}
	$anvil->Job->update_progress({
		progress  => $anvil->Job->bump_progress({steps => 1}),
		message   => "log_0802", 
		log_level => 1, 
		'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
		variables => {
			server_name => $anvil->data->{switches}{server_name}, 
			server_uuid => $anvil->data->{switches}{server_uuid}, 
		}, 
	});
	my $short_host_name   = $anvil->Get->short_host_name;
	my $server_name       = $anvil->data->{switches}{server_name};
	my $server_uuid       = $anvil->data->{switches}{server_uuid};
	my $server_definition = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml};
	my $server_host_uuid  = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
	my $server_state      = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	my $anvil_uuid        = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:short_host_name'   => $short_host_name, 
		's2:server_name'       => $server_name, 
		's3:server_uuid'       => $server_uuid, 
		's4:server_definition' => $server_definition,
		's5:server_host_uuid'  => $server_host_uuid, 
		's6:server_state'      => $server_state, 
		's7:anvil_uuid'        => $anvil_uuid, 
	}});
	if (not $anvil->data->{switches}{anvil_uuid})
	{
		$anvil->data->{switches}{anvil_uuid} = $anvil_uuid;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:switches::anvil_uuid' => $anvil->data->{switches}{anvil_uuid}, 
		}});
	}
	
	if ($server_state eq "DELETED")
	{
		# The server has been deleted
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "error_0453", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err", 
			variables => {
				server => $server_name, 
			}, 
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Parse the definition.
	$anvil->Server->parse_definition({
		debug      => 3,
		host       => $short_host_name,
		server     => $server_name, 
		source     => "from_db",
		definition => $server_definition, 
	});
	
	# Can we read the XML definition?
	$anvil->Server->get_status({
		debug  => 2,
		server => $server_name,
		host   => $short_host_name,
	});
	
	if (not $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{xml})
	{
		# The server isn't actually running... Not here anyway, or the database data is stale. If 
		# we're just displaying info, proceed, but if we're doing something, reassign.
		if (($server_state eq "running")                  && 
		    ($server_host_uuid ne $anvil->Get->host_uuid) &&
		    (($anvil->data->{switches}{add})   or 
		     ($anvil->data->{switches}{eject}) or 
		     ($anvil->data->{switches}{grow})  or 
		     ($anvil->data->{switches}{insert})))
		{
			my $server_host_name = $anvil->Database->get_host_from_uuid({
				short     => 1,
				host_uuid => $server_host_uuid,
			});
			
			# Reassign the job to the host.
			if ($server_host_uuid)
			{
				# What kind of job is it? Default to 'grow'
				my $job_title       = "job_0499";
				my $job_description = "job_0500";
				my $job_name        = "server::".$anvil->data->{switches}{server_uuid}."::grow_disk";
				if ($anvil->data->{switches}{add})
				{
					# Adding a disk
					$job_title       = "job_0497";
					$job_description = "job_0498";
					$job_name        = "server::".$anvil->data->{switches}{server_uuid}."::add_disk";
				}
				elsif ($anvil->data->{switches}{optical})
				{
					# Changing an optical disc
					$job_title       = "job_0501";
					$job_description = "job_0502";
					$job_name        = "server::".$anvil->data->{switches}{server_uuid}."::change_iso";
				}
				
				# Reassign the job.
				my $job_data =  "add=".$anvil->data->{switches}{add}."\n";
				   $job_data .= "anvil=".$anvil->data->{switches}{anvil}."\n";
				   $job_data .= "confirm=true\n";
				   $job_data .= "disk=".$anvil->data->{switches}{disk}."\n";
				   $job_data .= "eject=".$anvil->data->{switches}{eject}."\n";
				   $job_data .= "grow=".$anvil->data->{switches}{grow}."\n";
				   $job_data .= "insert=".$anvil->data->{switches}{insert}."\n";
				   $job_data .= "machine=".$anvil->data->{switches}{machine}."\n";
				   $job_data .= "optical=".$anvil->data->{switches}{optical}."\n";
				   $job_data .= "server=".$anvil->data->{switches}{server}."\n";
				   $job_data .= "storage-group=".$anvil->data->{switches}{'storage-group'}."\n";
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_data => $job_data }});
				
				# If this is a grow, add or delete job, ask the user to confirm.
				$anvil->Job->update_progress({
					progress  => $anvil->Job->bump_progress({steps => 2}),
					message   => "log_0349", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						host            => $server_host_name, 
						job_data        => $job_data, 
						job_name        => $job_name, 
						job_title       => "#!string!".$job_title."!#", 
						job_description => "#!string!".$job_description."!#", 
					},
				});
				
				# Confirmation set by '--ci-test' so don't abort if --ci-test in use, just re-assign.
				if ((not $anvil->data->{switches}{confirm}) && (not $anvil->data->{switches}{'job-uuid'}))
				{
					print $anvil->Words->string({key => "message_0021"})." ";
					my $answer = <STDIN>;
					chomp($answer);
					if ($answer !~ /^y/i)
					{
						# Abort
						$anvil->Job->update_progress({
							progress  => 100,
							message   => "message_0022", 
							log_level => 1, 
							'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
						});
						$anvil->nice_exit({exit_code => 0});
					}
				}
				
				my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
					debug           => 2,
					job_command     => $anvil->data->{path}{exe}{$THIS_FILE}.$anvil->Log->switches,
					job_data        => $job_data, 
					job_host_uuid   => $server_host_uuid, 
					job_progress    => 0, 
					job_name        => $job_name, 
					job_title       => $job_title, 
					job_description => $job_description, 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
				
				# Close this job.
				$anvil->Job->update_progress({
					progress  => 100,
					message   => "job_0136", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					variables => {
						server    => $server_name, 
						host_name => $server_host_name,
						job_uuid  => $job_uuid, 
					}, 
				});
			}
			else
			{
				# Invalid host?! 
				$anvil->Job->update_progress({
					progress  => 100,
					message   => "error_0454", 
					log_level => 1, 
					'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
					priority  => "err",
					variables => {
						server    => $server_name, 
						host_name => $server_host_name,
					}, 
				});
			}
			$anvil->nice_exit({exit_code => 1});
		}
	}
	
	return(0);
}

# Update the definition on disk and in the DB, and define or undefine if requested.
sub update_definition
{
	my ($anvil, $task, $definition) = @_;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		task       => $task,
		definition => $definition, 
	}});
	
	my $short_host_name     = $anvil->Get->short_host_name;
	my $server_name         = $anvil->data->{switches}{server_name};
	my $server_uuid         = $anvil->data->{switches}{server_uuid};
	my $server_host_uuid    = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid};
	my $server_state        = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
	my $definition_file     = $anvil->data->{path}{directories}{shared}{definitions}."/".$server_name.".xml";
	my $server_running_here = 0;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:short_host_name'   => $short_host_name, 
		's2:server_name'       => $server_name, 
		's3:server_uuid'       => $server_uuid, 
		's5:server_host_uuid'  => $server_host_uuid, 
		's6:server_state'      => $server_state, 
		's7:definition_file'   => $definition_file, 
	}});
	
	# See if the server is running locally
	my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." list --name";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
	
	my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:output'      => $output,
		's2:return_code' => $return_code, 
	}});
	foreach my $this_server (split/\n/, $output)
	{
		$this_server = $anvil->Words->clean_spaces({string => $this_server});
		next if not $this_server;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_server => $this_server }});
		
		if ($this_server eq $server_name)
		{
			$server_running_here = 1;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_running_here => $server_running_here }});
			last;
		}
	}
	
	my $disk_definition  = $anvil->data->{server}{$short_host_name}{$server_name}{from_disk}{xml}  ? $anvil->data->{server}{$short_host_name}{$server_name}{from_disk}{xml}  : "";
	my $virsh_definition = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{xml} ? $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{xml} : "";
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:disk_definition'  => $disk_definition,
		's2:virsh_definition' => $virsh_definition, 
	}});
	my $use_definition = "";
	if ($definition)
	{
		# Use the passed in definition.
		$use_definition = $definition;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_definition => $use_definition }});
	}
	elsif ($virsh_definition)
	{
		$use_definition = $virsh_definition;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_definition => $use_definition }});
	}
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_definition => $use_definition }});
	if (not $use_definition)
	{
		if (($server_running_here) or (($server_state eq "running") && ($virsh_definition)))
		{
			# Get the live definition
			if ($server_running_here)
			{
				my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." dumpxml --inactive ".$server_name;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
				
				my ($live_virsh_definition, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					live_virsh_definition => $live_virsh_definition, 
					return_code           => $return_code,
				}});
				
				my ($problem) = $anvil->Server->parse_definition({
					server     => $server_name,
					source     => "from_virsh", 
					definition => $live_virsh_definition, 
				});
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
				if (not $problem)
				{
					$use_definition = $live_virsh_definition;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_definition => $use_definition }});
					
					$anvil->Server->parse_definition({
						debug      => 3,
						host       => $short_host_name,
						server     => $server_name, 
						source     => "from_virsh",
						definition => $live_virsh_definition, 
					});
				}
				else
				{
					$use_definition = $virsh_definition;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_definition => $use_definition }});
					
					$anvil->Server->parse_definition({
						debug      => 3,
						host       => $short_host_name,
						server     => $server_name, 
						source     => "from_virsh",
						definition => $use_definition, 
					});
				}
			}
			else
			{
				$use_definition = $virsh_definition;
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_definition => $use_definition }});
				
				$anvil->Server->parse_definition({
					debug      => 3,
					host       => $short_host_name,
					server     => $server_name, 
					source     => "from_virsh",
					definition => $use_definition, 
				});
			}
		}
		else
		{
			$use_definition = $disk_definition;
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_definition => $use_definition }});
			
			$anvil->Server->parse_definition({
				debug      => 3,
				host       => $short_host_name,
				server     => $server_name, 
				source     => "from_disk",
				definition => $use_definition, 
			});
		}
	}
	
	if (not $use_definition)
	{
		# What?!
		$anvil->Job->update_progress({
			progress  => 100,
			message   => "error_0455", 
			log_level => 1, 
			'print'   => $anvil->data->{switches}{machine} ? 0 : 1, 
			priority  => "err",
			variables => {
				server => $server_name, 
			}, 
		});
		$anvil->nice_exit({exit_code => 1});
	}
	
	# Update the stored definition
	$anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml} = $use_definition;
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		"servers::server_uuid::${server_uuid}::server_definition_xml" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml},
	}});
	
	# Update the on-disk definition
	my ($failed) = $anvil->Storage->write_file({
		secure    => 1, 
		file      => $definition_file, 
		body      => $use_definition, 
		overwrite => 1,
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }});
	my $server_definition_uuid = $anvil->Database->insert_or_update_server_definitions({
		debug                         => 2,
		server_definition_xml         => $use_definition,  
		server_definition_server_uuid => $server_uuid, 
	});
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { server_definition_uuid => $server_definition_uuid }});
	
	if ($task eq "define")
	{
		# Define the server.
		my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." define ".$definition_file,
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		
		my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output, 
			return_code => $return_code,
		}});
	}
	elsif ($task eq "undefine")
	{
		# Undefine the server.
		my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." undefine ".$server_name;
		if ($anvil->data->{server}{$short_host_name}{$server_name}{from_disk}{nvram}{data})
		{
			$shell_call .= " --nvram";
		}
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
		
		my ($output, $return_code) = $anvil->System->call({
			debug      => 2,
			shell_call => $shell_call, 
			source     => $THIS_FILE, 
			line       => __LINE__,
		});
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			output      => $output, 
			return_code => $return_code,
		}});
	}
	
	return(0);
}

sub show_server_list
{
	my ($anvil) = @_;
	
	# Loop through all Anvil! nodes, then all server in that Anvil!
	if ($anvil->data->{switches}{machine})
	{
		$anvil->data->{xml}{body} = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
		$anvil->data->{xml}{body} .= "<anvil>\n";
	}
	foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
	{
		my $anvil_uuid        = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
		my $anvil_description = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			anvil_name        => $anvil_name, 
			anvil_uuid        => $anvil_uuid,
			anvil_description => $anvil_description,
		}});
		if (($anvil->data->{switches}{anvil_uuid}) && ($anvil->data->{switches}{anvil_uuid} ne $anvil_uuid))
		{
			next;
		}
		if ($anvil->data->{switches}{machine})
		{
			$anvil_description =~ s/"/\"/g;
			$anvil->data->{xml}{body} .= "\t<node name=\"".$anvil->Words->escape_xml({string => $anvil_name})."\" ";
			$anvil->data->{xml}{body} .= "uuid=\"".$anvil->Words->escape_xml({string => $anvil_uuid})."\" ";
			$anvil->data->{xml}{body} .= "description=\"".$anvil->Words->escape_xml({string => $anvil_description})."\" >\n";
		}
		else
		{
			print "\n".$anvil->Words->string({key => "message_0343", variables => {
				anvil_name        => $anvil_name, 
				anvil_uuid        => $anvil_uuid, 
				anvil_description => $anvil_description, 
			}})."\n";
		}
		
		my $server_count = 0;
		if (exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name})
		{
			foreach my $server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}})
			{
				my $server_uuid  = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}{server_uuid};
				my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					's1:server_name'  => $server_name,
					's2:server_uuid'  => $server_uuid, 
					's3:server_state' => $server_state, 
				}});
				if ($server_state ne "DELETED")
				{
					$server_count++;
					$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }});
				}
			}
			$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }});
		}
		if (not $server_count)
		{
			if ($anvil->data->{switches}{machine})
			{
				$anvil->data->{xml}{body} .= "\t\t<server count=\"0\" />\n";
			}
			else
			{
				print $anvil->Words->string({key => "message_0344"})."\n";
			}
		}
		else
		{
			if ($anvil->data->{switches}{machine})
			{
				$anvil->data->{xml}{body} .= "\t\t<server count=\"".$server_count."\" />\n";
			}
			foreach my $server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}})
			{
				my $server_uuid  = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}{server_uuid};
				my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
				$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
					server_name  => $server_name, 
					server_uuid  => $server_uuid, 
					server_state => $server_state,
				}});
				next if $server_state eq "DELETED";
				if ($anvil->data->{switches}{machine})
				{
					$anvil->data->{xml}{body} .= "\t\t<server name=\"".$server_name."\" uuid=\"".$server_uuid."\" />\n";
				}
				else
				{
					print $anvil->Words->string({key => "message_0345", variables => {
						server_name => $server_name, 
						server_uuid => $server_uuid, 
					}})."\n";
				}
			}
		}
		if ($anvil->data->{switches}{machine})
		{
			$anvil->data->{xml}{body} .= "\t<\/node>\n";
		}
	}
	if ($anvil->data->{switches}{machine})
	{
		$anvil->data->{xml}{body} .= "<\/anvil>\n";
		print $anvil->data->{xml}{body};
	}
	
	return(0);
}

sub show_files
{
	my ($anvil) = @_;
	
	my $server_name = $anvil->data->{switches}{server_name};
	my $server_uuid = $anvil->data->{switches}{server_uuid};
	my $anvil_uuid  = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
	my $anvil_name  = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:server_name' => $server_name, 
		's2:server_uuid' => $server_uuid, 
		's3:anvil_uuid'  => $anvil_uuid,
		's4:anvil_name'  => $anvil_name, 
	}});
	
	$anvil->Database->get_anvils;
	
	# Show the files available on this node.
	print $anvil->Words->string({key => 'message_0346'})."\n";
	foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}})
	{
		my $file_location_file_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid};
		my $file_size               = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_size};
		my $file_md5sum             = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_md5sum};
		my $file_type               = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_type};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:file_name'   => $file_name, 
			's2:file_size'   => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")", 
			's3:file_md5sum' => $file_md5sum,
			's4:file_type'   => $file_type, 
		}});
		next if $file_type ne "iso";
		print $anvil->Words->string({key => 'message_0347', variables => {
			file_name => $file_name, 
			file_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}), 
			md5sum    => $file_md5sum, 
		}})."\n";
	}
	
	return(0);
}

sub show_storage_groups
{
	my ($anvil) = @_;
	
	my $server_name = $anvil->data->{switches}{server_name};
	my $server_uuid = $anvil->data->{switches}{server_uuid};
	my $anvil_uuid  = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid};
	my $anvil_name  = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		's1:server_name' => $server_name, 
		's2:server_uuid' => $server_uuid, 
		's3:anvil_uuid'  => $anvil_uuid,
		's4:anvil_name'  => $anvil_name, 
	}});
	
	print $anvil->Words->string({key => 'message_0348'})."\n";
	foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}})
	{
		my $storage_group_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid};
		my $free_space         = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{free_space};
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:storage_group_name' => $storage_group_name, 
			's2:storage_group_uuid' => $storage_group_uuid, 
			's3:free_space'         => $free_space." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $free_space}).")", 
		}});
		print $anvil->Words->string({key => 'message_0349', variables => {
			storage_group_name => $storage_group_name, 
			storage_group_uuid => $storage_group_uuid, 
			free_space         => $anvil->Convert->bytes_to_human_readable({'bytes' => $free_space}), 
		}})."\n";
	}
	
	return(0);
}

sub load_job
{
	my ($anvil) = @_;
	
	$anvil->Job->clear({
		debug    => 2,
		job_uuid => $anvil->data->{switches}{'job-uuid'}, 
	});
	$anvil->Job->get_job_details({
		debug    => 2,
		job_uuid => $anvil->data->{switches}{'job-uuid'}, 
	});
	
	$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
		'jobs::job_data' => $anvil->data->{jobs}{job_data}, 
	}});
	foreach my $line (split/\n/, $anvil->data->{jobs}{job_data})
	{
		my ($variable, $value) =  ($line =~ /^(.*)=(.*)$/);
		   $value              =~ s/^"(.*)\"/$1/;
		   $value              =~ s/^'(.*)\'/$1/;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			's1:line'     => $line, 
			's2:variable' => $variable, 
			's3:value'    => $value, 
		}});
		
		$anvil->data->{switches}{$variable} = $value;
		$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 
			"switches::${variable}" => $anvil->data->{switches}{$variable}, 
		}});
	}
	
	# Preparing to relocate the server.
	$anvil->Job->update_progress({
		progress         => $anvil->Job->bump_progress({set => 1}),
		job_picked_up_by => $$, 
		job_picked_up_at => time, 
		message          => "message_0369", 
		log_level        => 1,
	});
	
	return(0);
}
