You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3741 lines
152 KiB
3741 lines
152 KiB
#!/usr/bin/perl |
|
# |
|
# This manages if a server is backed up to a DR host or not. When enabled, it can start or stop replication. |
|
# |
|
# NOTE: Unlike most jobs, this one will directly work on the peer node and the DR host using SSH connections. |
|
# This behaviour is likely to change later as it's not ideal. |
|
# |
|
# TODO: --remove is not yet implemented, this needs to be done. Use anvil-delete-server for methods to delete. |
|
# EXAMPLES: |
|
# - anvil-manage-dr --link --dr-host vm-a01dr02 --anvil vm-anvil-01 |
|
# |
|
# Exit codes; |
|
# 0 = Normal exit. |
|
# 1 = Any problem that causes an early exit. |
|
# |
|
|
|
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(); |
|
|
|
$anvil->Get->switches({list => [ |
|
"anvil", |
|
"connect", |
|
"disconnect", |
|
"dr-host", |
|
"job-uuid", |
|
"license-file", |
|
"link", |
|
"protect", |
|
"protocol", |
|
"remove", |
|
"server", |
|
"show", |
|
"unlink", |
|
"update", |
|
"Yes"], 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 }}); |
|
|
|
$anvil->Database->connect(); |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 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_0306"}); |
|
sleep 10; |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Are we linking or unlinking? |
|
if (($anvil->data->{switches}{'link'}) or ($anvil->data->{switches}{'unlink'})) |
|
{ |
|
handle_links($anvil); |
|
} |
|
|
|
# If we've got a job UUID, load the job details. |
|
if ($anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
load_job($anvil); |
|
} |
|
elsif ($anvil->data->{switches}{list}) |
|
{ |
|
# If '--list' was used, show all Nodes, DR hosts and servers. |
|
show_list($anvil); |
|
} |
|
|
|
my $terminal = ""; |
|
if (not $anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
my $termios = new POSIX::Termios; |
|
$termios->getattr; |
|
my $ospeed = $termios->getospeed; |
|
$terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed }; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { terminal => $terminal }}); |
|
|
|
$terminal->Trequire(qw/ce ku kd/); |
|
print $terminal->Tputs('cl'); |
|
} |
|
|
|
sanity_check($anvil, $terminal); |
|
|
|
|
|
$anvil->nice_exit({exit_code => 0}); |
|
|
|
|
|
############################################################################################################# |
|
# Functions # |
|
############################################################################################################# |
|
|
|
sub show_list |
|
{ |
|
my ($anvil) = @_; |
|
|
|
# Show Anvil! nodes |
|
$anvil->Database->get_hosts(); |
|
$anvil->Database->get_storage_group_data({debug => 2}); |
|
$anvil->Database->get_dr_links({debug => 2}); |
|
$anvil->Database->get_servers(); |
|
|
|
# Show Anvil! nodes. |
|
print $anvil->Words->string({key => "header_0081"})."\n"; |
|
my $anvil_count = keys %{$anvil->data->{anvils}{anvil_name}}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_count => $anvil_count }}); |
|
if ($anvil_count) |
|
{ |
|
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}}) |
|
{ |
|
my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid}; |
|
my $anvil_description = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description}; |
|
my $dr_link_count = keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
anvil_name => $anvil_name, |
|
anvil_uuid => $anvil_uuid, |
|
anvil_description => $anvil_description, |
|
dr_link_count => $dr_link_count, |
|
}}); |
|
print $anvil->Words->string({key => "message_0364", variables => { |
|
anvil_name => $anvil_name, |
|
description => $anvil_description, |
|
}})."\n"; |
|
if ($dr_link_count) |
|
{ |
|
foreach my $dr_link_host_name (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}}) |
|
{ |
|
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}{$dr_link_host_name}{dr_link_uuid}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
dr_link_host_name => $dr_link_host_name, |
|
dr_link_uuid => $dr_link_uuid, |
|
}}); |
|
print $anvil->Words->string({key => "message_0365", variables => { |
|
host_name => $dr_link_host_name, |
|
link_uuid => $dr_link_uuid, |
|
}})."\n"; |
|
} |
|
} |
|
else |
|
{ |
|
# No DR hosts yet |
|
print $anvil->Words->string({key => "message_0366"})."\n"; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
# No nodes yet |
|
print $anvil->Words->string({key => "message_0367"})."\n"; |
|
} |
|
|
|
# DR Hosts |
|
print "\n".$anvil->Words->string({key => "header_0115"})."\n"; |
|
my $dr_host_count = keys %{$anvil->data->{sys}{hosts}{by_type}{dr}{host_name}}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr_host_count => $dr_host_count }}); |
|
if ($dr_host_count) |
|
{ |
|
# TODO: Show free space of VGs, available RAM and CPU core count and type/speed |
|
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_type}{dr}{host_name}}) |
|
{ |
|
print $anvil->Words->string({key => "message_0368", variables => { host_name => $host_name }})."\n"; |
|
} |
|
} |
|
else |
|
{ |
|
# No DR hosts yet |
|
print $anvil->Words->string({key => "message_0366"})."\n"; |
|
} |
|
|
|
# DR Hosts |
|
print "\n".$anvil->Words->string({key => "header_0116"})."\n"; |
|
my $server_count = keys %{$anvil->data->{servers}{server_uuid}}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }}); |
|
if ($server_count) |
|
{ |
|
# If there's servers, there has to be Anvil! nodes. |
|
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}}) |
|
{ |
|
# TODO: Show each server's disk(s) size, RAM and CPU core count |
|
my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid}; |
|
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_name = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name}; |
|
print $anvil->Words->string({key => "message_0370", variables => { |
|
server_name => $server_name, |
|
anvil_name => $anvil_name, |
|
}})."\n"; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
# No servers yet exist |
|
print $anvil->Words->string({key => "message_0371"})."\n"; |
|
} |
|
$anvil->nice_exit({exit_code => 0}); |
|
|
|
return(0); |
|
} |
|
|
|
sub handle_links |
|
{ |
|
my ($anvil) = @_; |
|
|
|
# Get a list of DR hosts. |
|
$anvil->Database->get_dr_links(); |
|
|
|
# Do we habe an Anvil! and a DR host? |
|
my $anvil_uuid = $anvil->Database->get_anvil_uuid_from_string({string => $anvil->data->{switches}{anvil}}); |
|
my $host_uuid = $anvil->Database->get_host_uuid_from_string({string => $anvil->data->{switches}{'dr-host'}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
anvil_uuid => $anvil_uuid, |
|
host_uuid => $host_uuid, |
|
}}); |
|
|
|
my $problem = 0; |
|
if (not $anvil_uuid) |
|
{ |
|
$problem = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); |
|
if ($anvil->data->{switches}{anvil}) |
|
{ |
|
print $anvil->Words->string({key => "error_0405", variables => { anvil => $anvil->data->{switches}{anvil} }})."\n"; |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "error_0406"})."\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}; |
|
print "- ".$anvil_name." - ".$anvil_description."\n"; |
|
} |
|
} |
|
|
|
my $show_hosts = 0; |
|
if ($host_uuid) |
|
{ |
|
# Is it a DR host. |
|
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); |
|
if ($host_type ne "dr") |
|
{ |
|
$show_hosts = 1; |
|
$problem = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
show_hosts => $show_hosts, |
|
problem => $problem, |
|
}}); |
|
print $anvil->Words->string({key => "error_0408", variables => { host => $anvil->data->{switches}{'dr-host'} }})."\n"; |
|
} |
|
} |
|
else |
|
{ |
|
$show_hosts = 1; |
|
$problem = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
show_hosts => $show_hosts, |
|
problem => $problem, |
|
}}); |
|
if ($anvil->data->{switches}{anvil}) |
|
{ |
|
print "\n".$anvil->Words->string({key => "error_0407", variables => { host => $anvil->data->{switches}{'dr-host'} }})."\n"; |
|
} |
|
else |
|
{ |
|
print "\n".$anvil->Words->string({key => "error_0409"})."\n"; |
|
} |
|
} |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { show_hosts => $show_hosts }}); |
|
if ($show_hosts) |
|
{ |
|
$anvil->Database->get_hosts(); |
|
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }}); |
|
my $this_host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name}; |
|
my $short_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $host_type = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{host_type}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
this_host_uuid => $this_host_uuid, |
|
host_name => $host_name, |
|
short_host_name => $short_host_name, |
|
host_type => $host_type, |
|
}}); |
|
next if $host_type ne "dr"; |
|
print "- ".$short_host_name."\n"; |
|
} |
|
} |
|
|
|
if ($problem) |
|
{ |
|
print "\n".$anvil->Words->string({key => "error_0410"})."\n"; |
|
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}}) |
|
{ |
|
my $this_anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid}; |
|
my $anvil_description = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description}; |
|
print "- ".$anvil_name." - ".$anvil_description."\n"; |
|
|
|
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$this_anvil_uuid}{dr_link_host_name}}) |
|
{ |
|
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$this_anvil_uuid}{dr_link_host_name}{$host_name}{dr_link_uuid}; |
|
print " ^-> ".$host_name."\n"; |
|
} |
|
} |
|
print "\n"; |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Still alivee? Update! |
|
my $dr_link_uuid = ""; |
|
if (exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$host_uuid}) |
|
{ |
|
$dr_link_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 => { dr_link_uuid => $dr_link_uuid }}); |
|
} |
|
|
|
if ($anvil->data->{switches}{'link'}) |
|
{ |
|
my $returned_dr_link_uuid = $anvil->Database->insert_or_update_dr_links({ |
|
debug => 2, |
|
dr_link_host_uuid => $host_uuid, |
|
dr_link_anvil_uuid => $anvil_uuid, |
|
dr_link_note => "user-created", |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { returned_dr_link_uuid => $returned_dr_link_uuid }}); |
|
|
|
print "\n".$anvil->Words->string({key => "log_0734", variables => { |
|
host => $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name}, |
|
anvil => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name}, |
|
}})."\n"; |
|
} |
|
elsif ($anvil->data->{switches}{'unlink'}) |
|
{ |
|
if ($dr_link_uuid) |
|
{ |
|
# Delete |
|
$anvil->Database->insert_or_update_dr_links({ |
|
debug => 2, |
|
dr_link_uuid => $dr_link_uuid, |
|
'delete' => 1, |
|
}); |
|
print "\n".$anvil->Words->string({key => "log_0735", variables => { |
|
host => $anvil->data->{hosts}{host_uuid}{$host_uuid}{shost_host_name}, |
|
anvil => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name}, |
|
}})."\n"; |
|
} |
|
else |
|
{ |
|
# Link didn't exist, nothing to unlink. |
|
print "\n".$anvil->Words->string({key => "log_0736", variables => { |
|
host => $anvil->data->{hosts}{host_uuid}{$host_uuid}{shost_host_name}, |
|
anvil => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name}, |
|
}})."\n"; |
|
} |
|
} |
|
$anvil->nice_exit({exit_code => 0}); |
|
|
|
return(0); |
|
} |
|
|
|
sub sanity_check |
|
{ |
|
my ($anvil, $terminal) = @_; |
|
|
|
# Begin sanity checks |
|
$anvil->Job->update_progress({ |
|
progress => 10, |
|
message => "job_0358", |
|
}); |
|
|
|
# Somehow, duplicate entries are being created in dr_links. Look for and purge them. |
|
check_for_duplicate_dr_links($anvil); |
|
|
|
# Are we a node or DR? |
|
my $host_type = $anvil->Get->host_type(); |
|
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
host_type => $host_type, |
|
anvil_uuid => $anvil_uuid, |
|
}}); |
|
|
|
if ($host_type eq "striker") |
|
{ |
|
# This has to be run on an Anvil! sub-node. (For now at least. We need to make a menu to let |
|
# the user select a VM interactively). |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0404"}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0404", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# If we're protecting, removing, connecting, disconnecting, or update, we need to have a server. |
|
$anvil->Database->get_servers(); |
|
my $server_name = ""; |
|
my $server_uuid = ""; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
'switches::connect' => $anvil->data->{switches}{'connect'}, |
|
'switches::disconnect' => $anvil->data->{switches}{'disconnect'}, |
|
'switches::protect' => $anvil->data->{switches}{protect}, |
|
'switches::remove' => $anvil->data->{switches}{remove}, |
|
'switches::update' => $anvil->data->{switches}{update}, |
|
}}); |
|
if (($anvil->data->{switches}{'connect'}) or |
|
($anvil->data->{switches}{'disconnect'}) or |
|
($anvil->data->{switches}{protect}) or |
|
($anvil->data->{switches}{remove}) or |
|
($anvil->data->{switches}{update})) |
|
{ |
|
# Were we given a server? |
|
if (not $anvil->data->{switches}{server}) |
|
{ |
|
# Please specify the server to manager using '--server <name or uuid>'. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0340"}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0340", |
|
job_status => "failed", |
|
}); |
|
|
|
# Show the servers on this anvil and exit. |
|
show_servers($anvil, $anvil_uuid); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
$server_uuid = $anvil->Database->get_server_uuid_from_string({ |
|
debug => 2, |
|
string => $anvil->data->{switches}{server}, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_uuid => $server_uuid }}); |
|
if (not $server_uuid) |
|
{ |
|
my $variables = { server => $anvil->data->{switches}{server} }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0411", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0411", |
|
variables => $variables, |
|
job_status => "failed", |
|
}); |
|
|
|
# Show the servers on this anvil and exit. |
|
show_servers($anvil, $anvil_uuid); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Lastly, is this server on this Anvil! node? |
|
$server_name = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name}; |
|
my $host_anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
server_name => $server_name, |
|
host_anvil_uuid => $host_anvil_uuid." (".$anvil->data->{anvils}{anvil_uuid}{$host_anvil_uuid}{anvil_name}.")", |
|
}}); |
|
|
|
if ($anvil_uuid ne $host_anvil_uuid) |
|
{ |
|
# Server isn't here. |
|
my $variables = { |
|
server => $server_name, |
|
this_anvil => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name}, |
|
on_anvil => $anvil->data->{anvils}{anvil_uuid}{$host_anvil_uuid}{anvil_name}, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0412", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0412", |
|
variables => $variables, |
|
job_status => "failed", |
|
}); |
|
|
|
# Show the servers on this anvil and exit. |
|
show_servers($anvil, $anvil_uuid); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
# If we're (dis}connecting, is the server being protected in the first place? |
|
if (($anvil->data->{switches}{'connect'}) or ($anvil->data->{switches}{'disconnect'})) |
|
{ |
|
# Is this server configured to be protected? |
|
my $config_file = $anvil->data->{path}{directories}{drbd_resources}."/".$server_name.".res"; |
|
$config_file =~ s/\/\//\//g; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { config_file => $config_file }}); |
|
if (not -e $config_file) |
|
{ |
|
# Can't connect an unprotected server. |
|
my $variables = { |
|
server => $server_name, |
|
config_file => $config_file, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0371", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0371", |
|
variables => $variables, |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
# If we're doing a --protect or --remove, make sure we're a node, the cluster is up, and both nodes |
|
# are ready. |
|
if (($anvil->data->{switches}{protect}) or ($anvil->data->{switches}{remove})) |
|
{ |
|
# Make sure we're in an Anvil! if we're a node (DR link will be checked later). |
|
if (($host_type eq "node") && (not $anvil_uuid)) |
|
{ |
|
# This must be run on a node active in the cluster hosting the server being managed. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0332"}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0332", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# If we're a node, make sure we're in a cluster. |
|
if ($host_type eq "node") |
|
{ |
|
# Can we parse the CIB? |
|
my ($problem) = $anvil->Cluster->parse_cib(); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); |
|
if ($problem) |
|
{ |
|
# No. Clear the job, |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0336"}); |
|
$anvil->Job->update_progress({ |
|
progress => 0, |
|
message => "error_0336", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Both nodes need to be in the cluster, are they? |
|
if (not $anvil->data->{cib}{parsed}{'local'}{ready}) |
|
{ |
|
# We're not a full member of the cluster yet. Please try again once we're fully in. Exiting. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0337"}); |
|
$anvil->Job->update_progress({ |
|
progress => 0, |
|
message => "error_0337", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
if ($anvil->data->{switches}{protect}) |
|
{ |
|
if (not $anvil->data->{switches}{protocol}) |
|
{ |
|
$anvil->data->{switches}{protocol} = "short-throw"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
'switches::protocol' => $anvil->data->{switches}{protocol}, |
|
}}); |
|
} |
|
elsif (($anvil->data->{switches}{protocol} ne "sync") && |
|
($anvil->data->{switches}{protocol} ne "short-throw") && |
|
($anvil->data->{switches}{protocol} ne "long-throw")) |
|
{ |
|
# The protocol is invalid. Please use '--help' for more information. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0342", variables => { protocol => $anvil->data->{switches}{protocol} }}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0341,!!protocol!".$anvil->data->{switches}{protocol}."!!", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
if ($anvil->data->{switches}{protocol} eq "long-throw") |
|
{ |
|
# If there isn't a license file, make sure it's being provided. |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
'path::config::drbd-proxy.license' => $anvil->data->{path}{configs}{'drbd-proxy.license'}, |
|
}}); |
|
if (not -e $anvil->data->{path}{configs}{'drbd-proxy.license'}) |
|
{ |
|
if (not $anvil->data->{switches}{'license-file'}) |
|
{ |
|
# Proxy wouldn't work. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0373"}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0373", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
elsif (not -f $anvil->data->{switches}{'license-file'}) |
|
{ |
|
# It was passed, but doesn't point to the file. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0374", variables => { file => $anvil->data->{switches}{'license-file'} }}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0374,!!file!".$anvil->data->{switches}{'license-file'}."!!", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Still here? Copy the license file. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0429", variables => { file => $anvil->data->{switches}{'license-file'} }}); |
|
my $failed = $anvil->Storage->copy_file({ |
|
source_file => $anvil->data->{switches}{'license-file'}, |
|
target_file => $anvil->data->{path}{configs}{'drbd-proxy.license'}, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); |
|
} |
|
|
|
# Lastly, read in the license file to make sure it _looks_ ok. |
|
my $problem = $anvil->DRBD->check_proxy_license({debug => 2}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); |
|
if ($problem) |
|
{ |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0375"}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0375", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
# Get the Anvil! details. |
|
$anvil->Database->get_hosts(); |
|
$anvil->Database->get_storage_group_data({debug => 2}); |
|
$anvil->Database->get_dr_links({debug => 2}); |
|
|
|
# Does this Anvil! have at least one DR node? If there's only one, use it. If more than one, we need |
|
# a '--dr-host' switch. |
|
my $dr_host_uuid = ""; |
|
if ($anvil->data->{switches}{'dr-host'}) |
|
{ |
|
$dr_host_uuid = $anvil->Database->get_host_uuid_from_string({string => $anvil->data->{switches}{'dr-host'}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr_host_uuid => $dr_host_uuid }}); |
|
if (not $dr_host_uuid) |
|
{ |
|
# Bad host. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0400", variables => { |
|
dr_host => $anvil->data->{switches}{'dr-host'}, |
|
}}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0400,!!dr_host!".$anvil->data->{switches}{'dr-host'}."!!", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
# If I don't have a dr_host_uuid yet, see which are available. If only one, use it. If two or more, |
|
# and if the server is already being protected, determine which to use from it's config. Otherwise, |
|
# tell the user they need to specify which. |
|
if (not $dr_host_uuid) |
|
{ |
|
my $dr_count = keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
anvil_uuid => $anvil_uuid, |
|
dr_count => $dr_count, |
|
}}); |
|
|
|
if (not $dr_count) |
|
{ |
|
print $anvil->Words->string({key => "error_0333"})."\n"; |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0333", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
if ($dr_count eq "1") |
|
{ |
|
# Only one, use it. |
|
foreach my $host_uuid (keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}}) |
|
{ |
|
$dr_host_uuid = $host_uuid; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr_host_uuid => $dr_host_uuid }}); |
|
} |
|
} |
|
else |
|
{ |
|
# Two or more. Is the server already protected? If so, try to find which DR it's |
|
# using. |
|
if (($anvil->data->{switches}{'connect'}) or ($anvil->data->{switches}{'disconnect'})) |
|
{ |
|
# Read the config. |
|
my $config_file = $anvil->data->{path}{directories}{drbd_resources}."/".$server_name.".res"; |
|
$config_file =~ s/\/\//\//g; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { config_file => $config_file }}); |
|
|
|
my $resource_config = $anvil->Storage->read_file({file => $config_file}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { resource_config => $resource_config }}); |
|
foreach my $line (split/\n/, $resource_config) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { lineg => $line }}); |
|
|
|
} |
|
} |
|
} |
|
} |
|
|
|
# If I still don't have a DR host, fail out. |
|
if (not $dr_host_uuid) |
|
{ |
|
print $anvil->Words->string({key => "error_0402"})."\n"; |
|
foreach my $dr_link_host_name (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}}) |
|
{ |
|
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}{$dr_link_host_name}{dr_link_uuid}; |
|
my $dr_link_host_uuid = $anvil->data->{dr_links}{dr_link_uuid}{$dr_link_uuid}{dr_link_host_uuid}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
dr_link_host_name => $dr_link_host_name, |
|
dr_link_uuid => $dr_link_uuid, |
|
dr_link_host_uuid => $dr_link_host_uuid, |
|
}}); |
|
print $anvil->Words->string({key => "error_0403", variables => { |
|
host_name => $dr_link_host_name, |
|
host_uuid => $dr_link_host_uuid, |
|
}})."\n"; |
|
} |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0402", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
my $dr_host_name = $anvil->data->{hosts}{host_uuid}{$dr_host_uuid}{host_name}; |
|
my $dr_short_host_name = $anvil->data->{hosts}{host_uuid}{$dr_host_uuid}{short_host_name}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
dr_host_name => $dr_host_name, |
|
dr_short_host_name => $dr_short_host_name, |
|
}}); |
|
|
|
# Last check, we've got a dr_host_uuid, is it associated with this Anvil! node? |
|
if (not exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$dr_host_uuid}) |
|
{ |
|
# Bad requested DR host. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0401", variables => { |
|
dr_host => $dr_host_name, |
|
}}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0401,!!dr_host!".$dr_host_name."!!", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
$anvil->data->{sys}{dr_host_uuid} = $dr_host_uuid; |
|
$anvil->data->{sys}{dr_host_name} = $dr_host_name; |
|
$anvil->data->{sys}{dr_short_host_name} = $dr_short_host_name; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"sys::dr_host_uuid" => $anvil->data->{sys}{dr_host_uuid}, |
|
"sys::dr_host_name" => $anvil->data->{sys}{dr_host_name}, |
|
"sys::dr_short_host_name" => $anvil->data->{sys}{dr_short_host_name}, |
|
}}); |
|
|
|
### TODO: Switch to: my $target_ip = $anvil->Network->find_target_ip({}); |
|
# Can we access DR, if we're not the DR host? |
|
$anvil->Database->get_ip_addresses({debug => 2}); |
|
my $password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; |
|
my $dr_ip = $anvil->System->find_matching_ip({ |
|
debug => 2, |
|
host => $dr_host_name, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
password => $anvil->Log->is_secure($password), |
|
dr_ip => $dr_ip, |
|
}}); |
|
if ($dr_host_uuid ne $anvil->Get->host_uuid) |
|
{ |
|
if ((not $dr_ip) or ($dr_ip eq "!!error!!")) |
|
{ |
|
# Failed to find an IP we can access the DR host. Has it been configured? Is it running? Exiting. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, secure => 0, key => "error_0334", variables => { host_name => $dr_host_name }}); |
|
$anvil->Job->update_progress({ |
|
progress => 0, |
|
message => "error_0334,!!host_name!".$dr_host_name."!!", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Test access. |
|
my $access = $anvil->Remote->test_access({ |
|
target => $dr_ip, |
|
password => $password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); |
|
if (not $access) |
|
{ |
|
# Failed to access the DR host. Is it running? Exiting. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0335", variables => { |
|
host_name => $dr_host_name, |
|
ip_address => $dr_ip, |
|
}}); |
|
$anvil->Job->update_progress({ |
|
progress => 0, |
|
message => "error_0335,!!host_name!".$dr_host_name."!!,!!ip_address!".$dr_ip."!!", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
### TODO: We can queue a job to update the peer later, there's no real need, in the long run, |
|
### for the peer to be online. |
|
# If we're protecting or removing a server from DR, the peer needs to be up. |
|
if ((($anvil->data->{switches}{protect}) or |
|
($anvil->data->{switches}{remove}) or |
|
($anvil->data->{switches}{protocol})) && |
|
(not $anvil->data->{cib}{parsed}{peer}{ready})) |
|
{ |
|
if ($anvil->data->{switches}{protect}) |
|
{ |
|
# We can't setup a server to be protected unless both nodes are up, and the |
|
# peer isn't at this time. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0338"}); |
|
$anvil->Job->update_progress({ |
|
progress => 0, |
|
message => "error_0338", |
|
job_status => "failed", |
|
}); |
|
} |
|
else |
|
{ |
|
# We can't remove a server from DR unless both nodes are up, and the peer |
|
# isn't at this time. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0339"}); |
|
$anvil->Job->update_progress({ |
|
progress => 0, |
|
message => "error_0339", |
|
job_status => "failed", |
|
}); |
|
} |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
# Verify we found the server. |
|
$anvil->data->{server}{'server-name'} = ""; |
|
$anvil->data->{server}{'server-uuid'} = ""; |
|
$anvil->data->{server}{'anvil-uuid'} = $anvil_uuid; |
|
if (not $anvil->data->{switches}{server}) |
|
{ |
|
} |
|
else |
|
{ |
|
my $server = $anvil->data->{switches}{server}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server => $server }}); |
|
|
|
if (exists $anvil->data->{servers}{server_uuid}{$server}) |
|
{ |
|
$anvil->data->{server}{'server-uuid'} = $server; |
|
$anvil->data->{server}{'server-name'} = $anvil->data->{servers}{server_uuid}{$server}{server_name}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
'server::server-uuid' => $anvil->data->{server}{'server-uuid'}, |
|
'server::server-name' => $anvil->data->{server}{'server-name'}, |
|
}}); |
|
} |
|
if (exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server}) |
|
{ |
|
$anvil->data->{server}{'server-name'} = $server; |
|
$anvil->data->{server}{'server-uuid'} = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server}{server_uuid}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
'server::server-uuid' => $anvil->data->{server}{'server-uuid'}, |
|
'server::server-name' => $anvil->data->{server}{'server-name'}, |
|
}}); |
|
} |
|
} |
|
|
|
# Get and parse the server's definition to find the DRBD devices. |
|
if ((not $anvil->data->{server}{'server-uuid'}) or (not $anvil->data->{server}{'server-name'})) |
|
{ |
|
# Failed to find the server by name or UUID. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0341", variables => { server => $anvil->data->{switches}{server} }}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0341,!!server!".$anvil->data->{switches}{server}."!!", |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Are we being asked to actuall do something? |
|
if (((not $anvil->data->{switches}{'connect'}) && |
|
(not $anvil->data->{switches}{disconnect}) && |
|
(not $anvil->data->{switches}{protect}) && |
|
(not $anvil->data->{switches}{remove}) && |
|
(not $anvil->data->{switches}{update})) or |
|
($anvil->data->{switches}{help}) or |
|
($anvil->data->{switches}{h})) |
|
{ |
|
# Show the man page. |
|
system($anvil->data->{path}{exe}{man}." ".$THIS_FILE); |
|
if (($anvil->data->{switches}{help}) or ($anvil->data->{switches}{h})) |
|
{ |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
else |
|
{ |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
# Sanity checks complete! |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0359"}); |
|
$anvil->Job->update_progress({ |
|
progress => 20, |
|
message => "job_0359", |
|
}); |
|
|
|
# If we've got a got job-uuid, wait for / make sure all machines are online. |
|
if ($anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
# Loop until we have access to both the peer machines. |
|
my $waiting = 1; |
|
my $wait_for = 10; |
|
while ($waiting) |
|
{ |
|
# This will get set to 1 if we have to keep waiting. |
|
$waiting = 0; |
|
my $password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; |
|
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; |
|
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; |
|
my $dr_host_uuid = $anvil->data->{sys}{dr_host_uuid}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
password => $anvil->Log->is_secure($password), |
|
node1_host_uuid => $node1_host_uuid, |
|
node2_host_uuid => $node2_host_uuid, |
|
dr_host_uuid => $dr_host_uuid, |
|
}}); |
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid, $dr_host_uuid) |
|
{ |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $this_host_name = $anvil->Get->host_name_from_uuid({host_uuid => $this_host_uuid}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
this_host_uuid => $this_host_uuid, |
|
this_host_name => $this_host_name, |
|
}}); |
|
|
|
# We'll try the SN, then the BCN and finally the IFN to see which, if any, network we |
|
# can reach the peer on. This is needed because the DR host could be on a totally |
|
# different network. |
|
$anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip} = ""; |
|
$anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_subnet} = ""; |
|
$anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_network} = ""; |
|
foreach my $check_network ("sn", "bcn", "mn", "ifn") |
|
{ |
|
last if $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { check_network => $check_network }}); |
|
foreach my $this_network (sort {$a cmp $b} keys %{$anvil->data->{hosts}{host_uuid}{$this_host_uuid}{network}}) |
|
{ |
|
next if $this_network !~ /^$check_network/; |
|
my $this_ip = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{network}{$this_network}{ip_address}; |
|
my $this_subnet = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{network}{$this_network}{subnet_mask}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_ip' => $this_ip, |
|
's2:this_network' => $this_network, |
|
's3:this_subnet' => $this_subnet, |
|
}}); |
|
|
|
# Test access. |
|
my $access = $anvil->Remote->test_access({ |
|
target => $this_ip, |
|
password => $password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); |
|
if ($access) |
|
{ |
|
$anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip} = $this_ip; |
|
$anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_subnet} = $this_subnet; |
|
$anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_network} = $this_network; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"hosts::host_uuid::${this_host_uuid}::network::use_ip" => $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}, |
|
"hosts::host_uuid::${this_host_uuid}::network::use_subnet" => $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_subnet}, |
|
"hosts::host_uuid::${this_host_uuid}::network::use_network" => $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_network}, |
|
}}); |
|
} |
|
} |
|
} |
|
|
|
if (not $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}) |
|
{ |
|
# No access |
|
my $variables = { |
|
waiting => $wait_for, |
|
host_name => $this_host_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0404", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 12, |
|
message => "job_0404", |
|
variables => $variables, |
|
}); |
|
|
|
$waiting = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); |
|
} |
|
} |
|
|
|
# If we're waiting for a peer, record as such. |
|
sleep $wait_for; |
|
} |
|
} |
|
|
|
# If we're protecting, make sure there's enough space on the DR host. |
|
if ($anvil->data->{switches}{protect}) |
|
{ |
|
process_protect($anvil, $terminal); |
|
} |
|
elsif ($anvil->data->{switches}{remove}) |
|
{ |
|
process_remove($anvil, $terminal); |
|
} |
|
elsif ($anvil->data->{switches}{'connect'}) |
|
{ |
|
process_connect($anvil, $terminal); |
|
} |
|
elsif ($anvil->data->{switches}{disconnect}) |
|
{ |
|
process_disconnect($anvil, $terminal); |
|
} |
|
elsif ($anvil->data->{switches}{update}) |
|
{ |
|
process_update($anvil, $terminal); |
|
} |
|
|
|
return(0); |
|
} |
|
|
|
sub process_update |
|
{ |
|
my ($anvil, $terminal) = @_; |
|
|
|
# Parse out the DRBD resource's backing the server and get their LV sizes. |
|
$anvil->Database->get_server_definitions(); |
|
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); |
|
my $anvil_password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; |
|
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; |
|
my $node1_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{host_name}; |
|
my $node1_short_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{short_host_name}; |
|
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; |
|
my $node2_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{host_name}; |
|
my $node2_short_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{short_host_name}; |
|
my $dr_host_uuid = $anvil->data->{sys}{dr_host_uuid}; |
|
my $dr_host_name = $anvil->data->{sys}{dr_host_name}; |
|
my $dr_short_host_name = $anvil->data->{hosts}{host_uuid}{$dr_host_uuid}{short_host_name}; |
|
my $server_name = $anvil->data->{server}{'server-name'}; |
|
my $server_uuid = $anvil->data->{server}{'server-uuid'}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
anvil_uuid => $anvil_uuid, |
|
anvil_password => $anvil->Log->is_secure($anvil_password), |
|
node1_host_uuid => $node1_host_uuid, |
|
node1_host_name => $node1_host_name, |
|
node1_short_host_name => $node1_short_host_name, |
|
node2_host_uuid => $node2_host_uuid, |
|
node2_host_name => $node2_host_name, |
|
node2_short_host_name => $node2_short_host_name, |
|
dr_host_uuid => $dr_host_uuid, |
|
dr_host_name => $dr_host_name, |
|
dr_short_host_name => $dr_short_host_name, |
|
server_name => $server_name, |
|
server_uuid => $server_uuid, |
|
}}); |
|
|
|
### NOTE: 'Yes' is set when a job is picked up, so this won't re-register the job. |
|
my $record_job = 0; |
|
if (not $anvil->data->{switches}{Yes}) |
|
{ |
|
my $variables = { |
|
server => $server_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0395", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 25, |
|
message => "job_0395", |
|
variables => $variables, |
|
}); |
|
|
|
# Ask the user to confirm. |
|
print "\n".$anvil->Words->string({key => "message_0021"})."\n"; |
|
my $answer = <STDIN>; |
|
chomp $answer; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); |
|
|
|
if ($answer =~ /^y/i) |
|
{ |
|
print $anvil->Words->string({key => "message_0175"})."\n"; |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0022"})."\n"; |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
} |
|
elsif (not $anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
|
|
if ($record_job) |
|
{ |
|
my $job_data = "server=".$anvil->data->{switches}{server}."\n"; |
|
$job_data .= "update=1\n"; |
|
|
|
# Register the job with the DR host. |
|
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ |
|
debug => 2, |
|
job_command => $anvil->data->{path}{exe}{'anvil-manage-dr'}.$anvil->Log->switches, |
|
job_data => $job_data, |
|
job_name => "server::dr", |
|
job_title => "job_0384", |
|
job_description => "job_0385", |
|
job_progress => 0, |
|
job_host_uuid => $dr_host_uuid, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); |
|
|
|
# Report the job UUID. |
|
print $anvil->Words->string({key => "job_0383", variables => { job_uuid => $job_uuid }})."\n"; |
|
|
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
|
|
# If the resource is down, bring it up. |
|
my $variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0387", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 50, |
|
message => "job_0387", |
|
variables => $variables, |
|
}); |
|
|
|
# Bring up the connection locally, and then also bring up the connection on the nodes, in case the |
|
# server is down. |
|
my $drbd_up_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 => { drbd_up_call => $drbd_up_call }}); |
|
my ($output, $return_code) = $anvil->System->call({shell_call => $drbd_up_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0388", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 60, |
|
message => "job_0388", |
|
}); |
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid, $dr_host_uuid) |
|
{ |
|
# "Peer" in this context is either/both nodes |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $peer_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $peer_ip = $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_host_uuid' => $this_host_uuid, |
|
's2:peer_host_name' => $peer_host_name, |
|
's3:peer_ip' => $peer_ip, |
|
}}); |
|
|
|
my $variables = { host_name => $peer_host_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0389", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 70, |
|
message => "job_0389", |
|
variables => $variables, |
|
}); |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
shell_call => $drbd_up_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
} |
|
|
|
# Now watch until out volume(s) are UpToDate |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0390"}); |
|
$anvil->Job->update_progress({ |
|
progress => 70, |
|
message => "job_0390", |
|
}); |
|
|
|
my $waiting = 1; |
|
while ($waiting) |
|
{ |
|
$anvil->DRBD->gather_data({debug => 2}); |
|
$waiting = 0; |
|
my $time_to_sync = ""; |
|
my $sync_speed = ""; |
|
my $sync_source = ""; |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{volume}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { volume => $volume }}); |
|
foreach my $peer (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}}) |
|
{ |
|
my $replication_speed = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{replication_speed}; |
|
my $peer_role = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{peer_role}; |
|
my $peer_disk_state = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{peer_disk_state}; |
|
my $estimated_time_to_sync = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync}; |
|
my $local_disk_state = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{local_disk_state}; |
|
my $connection_state = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{connection_state}; |
|
my $local_role = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{local_role}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
peer => $peer, |
|
replication_speed => $replication_speed, |
|
peer_role => $peer_role, |
|
peer_disk_state => $peer_disk_state, |
|
estimated_time_to_sync => $estimated_time_to_sync, |
|
local_disk_state => $local_disk_state, |
|
connection_state => $connection_state, |
|
local_role => $local_role, |
|
}}); |
|
|
|
if ($connection_state eq "synctarget") |
|
{ |
|
$sync_source = $peer; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sync_source => $sync_source }}); |
|
} |
|
if ($replication_speed) |
|
{ |
|
$sync_speed = $anvil->Convert->bytes_to_human_readable({'bytes' => $replication_speed}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sync_speed => $sync_speed }}); |
|
} |
|
if ($estimated_time_to_sync) |
|
{ |
|
$time_to_sync = $anvil->Convert->time({'time' => $estimated_time_to_sync, translate => 1}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { time_to_sync => $time_to_sync }}); |
|
} |
|
|
|
if ($local_disk_state ne "uptodate") |
|
{ |
|
$waiting = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); |
|
} |
|
} |
|
} |
|
if ($waiting) |
|
{ |
|
if ($sync_source) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
sync_source => $sync_source, |
|
sync_speed => $sync_speed, |
|
time_to_sync => $time_to_sync, |
|
}}); |
|
my $variables = { |
|
sync_source => $sync_source, |
|
sync_speed => $sync_speed, |
|
time_to_sync => $time_to_sync, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0396", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 80, |
|
message => "job_0396", |
|
variables => $variables, |
|
}); |
|
} |
|
else |
|
{ |
|
$anvil->Job->update_progress({ |
|
progress => 75, |
|
message => "job_0398", |
|
variables => $variables, |
|
}); |
|
} |
|
sleep 5; |
|
} |
|
} |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0397", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 90, |
|
message => "job_0397", |
|
variables => $variables, |
|
}); |
|
|
|
# Bring down the connection. |
|
my $drbd_down_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 => { drbd_down_call => $drbd_down_call }}); |
|
($output, $return_code) = $anvil->System->call({shell_call => $drbd_down_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
|
|
# Done! |
|
$variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0391", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "job_0391", |
|
variables => $variables, |
|
}); |
|
|
|
return(0); |
|
} |
|
|
|
sub process_disconnect |
|
{ |
|
my ($anvil, $terminal) = @_; |
|
|
|
# Parse out the DRBD resource's backing the server and get their LV sizes. |
|
$anvil->Database->get_server_definitions(); |
|
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); |
|
my $anvil_password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; |
|
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; |
|
my $node1_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{host_name}; |
|
my $node1_short_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{short_host_name}; |
|
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; |
|
my $node2_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{host_name}; |
|
my $node2_short_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{short_host_name}; |
|
my $dr_host_uuid = $anvil->data->{sys}{dr_host_uuid}; |
|
my $dr_host_name = $anvil->data->{sys}{dr_host_name}; |
|
my $dr_short_host_name = $anvil->data->{hosts}{host_uuid}{$dr_host_uuid}{short_host_name}; |
|
my $server_name = $anvil->data->{server}{'server-name'}; |
|
my $server_uuid = $anvil->data->{server}{'server-uuid'}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
anvil_uuid => $anvil_uuid, |
|
anvil_password => $anvil->Log->is_secure($anvil_password), |
|
node1_host_uuid => $node1_host_uuid, |
|
node1_host_name => $node1_host_name, |
|
node1_short_host_name => $node1_short_host_name, |
|
node2_host_uuid => $node2_host_uuid, |
|
node2_host_name => $node2_host_name, |
|
node2_short_host_name => $node2_short_host_name, |
|
dr_host_uuid => $dr_host_uuid, |
|
dr_host_name => $dr_host_name, |
|
dr_short_host_name => $dr_short_host_name, |
|
server_name => $server_name, |
|
server_uuid => $server_uuid, |
|
}}); |
|
|
|
### NOTE: 'Yes' is set when a job is picked up, so this won't re-register the job. |
|
my $record_job = 0; |
|
if (not $anvil->data->{switches}{Yes}) |
|
{ |
|
my $variables = { |
|
server => $server_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0392", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 25, |
|
message => "job_0392", |
|
variables => $variables, |
|
}); |
|
|
|
# Ask the user to confirm. |
|
print "\n".$anvil->Words->string({key => "message_0021"})."\n"; |
|
my $answer = <STDIN>; |
|
chomp $answer; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); |
|
|
|
if ($answer =~ /^y/i) |
|
{ |
|
print $anvil->Words->string({key => "message_0175"})."\n"; |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0022"})."\n"; |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
} |
|
elsif (not $anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
|
|
if ($record_job) |
|
{ |
|
my $job_data = "server=".$anvil->data->{switches}{server}."\n"; |
|
$job_data .= "disconnect=1\n"; |
|
|
|
# Register the job with the DR host. |
|
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ |
|
debug => 2, |
|
job_command => $anvil->data->{path}{exe}{'anvil-manage-dr'}.$anvil->Log->switches, |
|
job_data => $job_data, |
|
job_name => "server::dr", |
|
job_title => "job_0384", |
|
job_description => "job_0385", |
|
job_progress => 0, |
|
job_host_uuid => $dr_host_uuid, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); |
|
|
|
# Report the job UUID. |
|
print $anvil->Words->string({key => "job_0383", variables => { job_uuid => $job_uuid }})."\n"; |
|
|
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
|
|
# If the resource is up, bring it down. |
|
my $variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0393", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 50, |
|
message => "job_0393", |
|
variables => $variables, |
|
}); |
|
|
|
# Bring up the connection locally, and then also bring up the connection on the nodes, in case the |
|
# server is down. |
|
my $drbd_down_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 => { drbd_down_call => $drbd_down_call }}); |
|
my ($output, $return_code) = $anvil->System->call({shell_call => $drbd_down_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
|
|
# Done! |
|
$variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0394", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "job_0394", |
|
variables => $variables, |
|
}); |
|
|
|
return(0); |
|
} |
|
|
|
sub process_connect |
|
{ |
|
my ($anvil, $terminal) = @_; |
|
|
|
# Parse out the DRBD resource's backing the server and get their LV sizes. |
|
$anvil->Database->get_server_definitions(); |
|
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); |
|
my $anvil_password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; |
|
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; |
|
my $node1_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{host_name}; |
|
my $node1_short_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{short_host_name}; |
|
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; |
|
my $node2_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{host_name}; |
|
my $node2_short_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{short_host_name}; |
|
my $dr_host_uuid = $anvil->data->{sys}{dr_host_uuid}; |
|
my $dr_host_name = $anvil->data->{sys}{dr_host_name}; |
|
my $dr_short_host_name = $anvil->data->{hosts}{host_uuid}{$dr_host_uuid}{short_host_name}; |
|
my $server_name = $anvil->data->{server}{'server-name'}; |
|
my $server_uuid = $anvil->data->{server}{'server-uuid'}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
anvil_uuid => $anvil_uuid, |
|
anvil_password => $anvil->Log->is_secure($anvil_password), |
|
node1_host_uuid => $node1_host_uuid, |
|
node1_host_name => $node1_host_name, |
|
node1_short_host_name => $node1_short_host_name, |
|
node2_host_uuid => $node2_host_uuid, |
|
node2_host_name => $node2_host_name, |
|
node2_short_host_name => $node2_short_host_name, |
|
dr_host_uuid => $dr_host_uuid, |
|
dr_host_name => $dr_host_name, |
|
dr_short_host_name => $dr_short_host_name, |
|
server_name => $server_name, |
|
server_uuid => $server_uuid, |
|
}}); |
|
|
|
### NOTE: 'Yes' is set when a job is picked up, so this won't re-register the job. |
|
my $record_job = 0; |
|
if (not $anvil->data->{switches}{Yes}) |
|
{ |
|
my $variables = { |
|
server => $server_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0386", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 25, |
|
message => "job_0386", |
|
variables => $variables, |
|
}); |
|
|
|
# Ask the user to confirm. |
|
print "\n".$anvil->Words->string({key => "message_0021"})."\n"; |
|
my $answer = <STDIN>; |
|
chomp $answer; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); |
|
|
|
if ($answer =~ /^y/i) |
|
{ |
|
print $anvil->Words->string({key => "message_0175"})."\n"; |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0022"})."\n"; |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
} |
|
elsif (not $anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
|
|
if ($record_job) |
|
{ |
|
my $job_data = "server=".$anvil->data->{switches}{server}."\n"; |
|
$job_data .= "connect=1\n"; |
|
|
|
# Register the job with the DR host. |
|
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ |
|
debug => 2, |
|
job_command => $anvil->data->{path}{exe}{'anvil-manage-dr'}.$anvil->Log->switches, |
|
job_data => $job_data, |
|
job_name => "server::dr", |
|
job_title => "job_0384", |
|
job_description => "job_0385", |
|
job_progress => 0, |
|
job_host_uuid => $dr_host_uuid, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); |
|
|
|
# Report the job UUID. |
|
print $anvil->Words->string({key => "job_0383", variables => { job_uuid => $job_uuid }})."\n"; |
|
|
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
|
|
# If the resource is down, bring it up. |
|
my $variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0387", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 50, |
|
message => "job_0387", |
|
variables => $variables, |
|
}); |
|
|
|
# Bring up the connection locally, and then also bring up the connection on the nodes, in case the |
|
# server is down. |
|
my $drbd_up_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 => { drbd_up_call => $drbd_up_call }}); |
|
my ($output, $return_code) = $anvil->System->call({shell_call => $drbd_up_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
|
|
# If this was an error, abort. |
|
if ($return_code) |
|
{ |
|
# Failed. |
|
my $variables = { |
|
return_code => $return_code, |
|
output => $output, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0370", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0370", |
|
variables => $variables, |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0388", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 60, |
|
message => "job_0388", |
|
}); |
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid, $dr_host_uuid) |
|
{ |
|
# "Peer" in this context is either/both nodes |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $peer_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $peer_ip = $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_host_uuid' => $this_host_uuid, |
|
's2:peer_host_name' => $peer_host_name, |
|
's3:peer_ip' => $peer_ip, |
|
}}); |
|
|
|
$variables = { host_name => $peer_host_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0389", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 70, |
|
message => "job_0389", |
|
variables => $variables, |
|
}); |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
shell_call => $drbd_up_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
} |
|
|
|
# Now watch until we connect to at least one peer. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0390"}); |
|
$anvil->Job->update_progress({ |
|
progress => 80, |
|
message => "job_0390", |
|
}); |
|
my $waiting = 1; |
|
while($waiting) |
|
{ |
|
sleep 5; |
|
$anvil->DRBD->gather_data({debug => 2}); |
|
|
|
$waiting = 0; |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{volume}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { volume => $volume }}); |
|
my $volume_up = 0; |
|
foreach my $peer (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}}) |
|
{ |
|
my $replication_speed = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{replication_speed}; |
|
my $peer_role = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{peer_role}; |
|
my $peer_disk_state = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{peer_disk_state}; |
|
my $estimated_time_to_sync = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{estimated_time_to_sync}; |
|
my $local_disk_state = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{local_disk_state}; |
|
my $connection_state = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{connection_state}; |
|
my $local_role = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$peer}{local_role}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
peer => $peer, |
|
replication_speed => $replication_speed, |
|
peer_role => $peer_role, |
|
peer_disk_state => $peer_disk_state, |
|
estimated_time_to_sync => $estimated_time_to_sync, |
|
local_disk_state => $local_disk_state, |
|
connection_state => $connection_state, |
|
local_role => $local_role, |
|
}}); |
|
|
|
if ($connection_state eq "established") |
|
{ |
|
$volume_up = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { volume_up => $volume_up }}); |
|
} |
|
last if $volume_up; |
|
} |
|
|
|
if (not $volume_up) |
|
{ |
|
$waiting = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); |
|
} |
|
} |
|
|
|
if (not $waiting) |
|
{ |
|
# We're ready. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0379"}); |
|
$anvil->Job->update_progress({ |
|
progress => 95, |
|
message => "job_0379", |
|
}); |
|
$waiting = 0; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); |
|
} |
|
} |
|
|
|
# Done! |
|
$variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0391", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "job_0391", |
|
variables => $variables, |
|
}); |
|
|
|
return(0); |
|
} |
|
|
|
sub process_remove |
|
{ |
|
my ($anvil, $terminal) = @_; |
|
|
|
# Parse out the DRBD resource's backing the server and get their LV sizes. |
|
$anvil->Database->get_server_definitions(); |
|
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); |
|
my $anvil_password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; |
|
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; |
|
my $node1_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{host_name}; |
|
my $node1_short_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{short_host_name}; |
|
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; |
|
my $node2_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{host_name}; |
|
my $node2_short_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{short_host_name}; |
|
my $dr_host_uuid = $anvil->data->{sys}{dr_host_uuid}; |
|
my $dr_host_name = $anvil->data->{sys}{dr_host_name}; |
|
my $dr_short_host_name = $anvil->data->{hosts}{host_uuid}{$dr_host_uuid}{short_host_name}; |
|
my $server_name = $anvil->data->{server}{'server-name'}; |
|
my $server_uuid = $anvil->data->{server}{'server-uuid'}; |
|
my $short_host_name = $anvil->Get->short_host_name(); |
|
my $server_definition_xml = $anvil->data->{server_definitions}{server_definition_server_uuid}{$server_uuid}{server_definition_xml}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
anvil_uuid => $anvil_uuid, |
|
anvil_password => $anvil->Log->is_secure($anvil_password), |
|
node1_host_uuid => $node1_host_uuid, |
|
node1_host_name => $node1_host_name, |
|
node1_short_host_name => $node1_short_host_name, |
|
node2_host_uuid => $node2_host_uuid, |
|
node2_host_name => $node2_host_name, |
|
node2_short_host_name => $node2_short_host_name, |
|
dr_host_uuid => $dr_host_uuid, |
|
dr_host_name => $dr_host_name, |
|
dr_short_host_name => $dr_short_host_name, |
|
server_name => $server_name, |
|
server_uuid => $server_uuid, |
|
server_definition_xml => $server_definition_xml, |
|
short_host_name => $short_host_name, |
|
}}); |
|
|
|
### NOTE: 'Yes' is set when a job is picked up, so this won't re-register the job. |
|
my $record_job = 0; |
|
if (not $anvil->data->{switches}{Yes}) |
|
{ |
|
my $variables = { |
|
server => $server_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0407", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 25, |
|
message => "job_0407", |
|
variables => $variables, |
|
}); |
|
|
|
# Ask the user to confirm. |
|
print "\n".$anvil->Words->string({key => "message_0021"})."\n"; |
|
my $answer = <STDIN>; |
|
chomp $answer; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); |
|
|
|
if ($answer =~ /^y/i) |
|
{ |
|
print $anvil->Words->string({key => "message_0175"})."\n"; |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0022"})."\n"; |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
} |
|
elsif (not $anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
|
|
if ($record_job) |
|
{ |
|
my $job_data = "server=".$anvil->data->{switches}{server}."\n"; |
|
$job_data .= "remove=1\n"; |
|
|
|
# Register the job with the DR host. |
|
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ |
|
debug => 2, |
|
job_command => $anvil->data->{path}{exe}{'anvil-manage-dr'}.$anvil->Log->switches, |
|
job_data => $job_data, |
|
job_name => "server::dr", |
|
job_title => "job_0384", |
|
job_description => "job_0385", |
|
job_progress => 0, |
|
job_host_uuid => $dr_host_uuid, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); |
|
|
|
# Report the job UUID. |
|
print $anvil->Words->string({key => "job_0383", variables => { job_uuid => $job_uuid }})."\n"; |
|
|
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
|
|
# Sanity checks complete! |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0406", variables => { server => $anvil->data->{server}{'server-name'} }}); |
|
$anvil->Job->update_progress({ |
|
progress => 30, |
|
message => "job_0406,!!server!".$anvil->data->{server}{'server-name'}."!!", |
|
}); |
|
|
|
# Bring down the resource, if it's up. |
|
my $variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0393", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 40, |
|
message => "job_0393", |
|
variables => $variables, |
|
}); |
|
|
|
# Bring down the connection locally |
|
my $drbd_down_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 => { drbd_down_call => $drbd_down_call }}); |
|
my ($output, $return_code) = $anvil->System->call({shell_call => $drbd_down_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
|
|
# Read through the local DRBD config file, and remove any LVs that are found to still exist. |
|
$anvil->DRBD->gather_data({debug => 2}); |
|
|
|
my $config_file = $anvil->data->{new}{resource}{$server_name}{config_file} ? $anvil->data->{new}{resource}{$server_name}{config_file} : ""; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { config_file => $config_file }}); |
|
|
|
# If we don't have a config file, we could be re-running and the file was wiped. We need this though, |
|
# so try to pull it from a node. |
|
if (not $config_file) |
|
{ |
|
# Try to read it from node 1. |
|
$config_file = $anvil->data->{path}{directories}{drbd_resources}."/".$server_name.".res"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { config_file => $config_file }}); |
|
|
|
my $variables = { |
|
config_file => $config_file, |
|
source => $node1_short_host_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0417", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 45, |
|
message => "job_0417", |
|
variables => $variables, |
|
}); |
|
|
|
# Rsync it over. |
|
my $source = "root\@".$anvil->data->{lookup}{host_uuid}{$node1_host_uuid}{network}{use_ip}.":".$config_file; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { source => $source }}); |
|
$anvil->Storage->rsync({ |
|
source => $source, |
|
destination => $anvil->data->{path}{directories}{drbd_resources}."/", |
|
}); |
|
|
|
# Rescan DRBD |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0418"}); |
|
$anvil->Job->update_progress({ |
|
progress => 50, |
|
message => "job_0418", |
|
}); |
|
$anvil->DRBD->gather_data({debug => 2}); |
|
} |
|
|
|
# Read the old config file. |
|
my $old_resource_config = $anvil->Storage->read_file({file => $config_file}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_resource_config => $old_resource_config }}); |
|
|
|
my $progress = "50"; |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{volume}}) |
|
{ |
|
my $local_lv = $anvil->data->{new}{resource}{$server_name}{host}{$dr_short_host_name}{volume}{$volume}{backing_disk}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
volume => $volume, |
|
local_lv => $local_lv, |
|
}}); |
|
|
|
$progress++; |
|
my $variables = { |
|
server => $server_name, |
|
volume => $volume, |
|
local_lv => $local_lv, |
|
}; |
|
if (-e $local_lv) |
|
{ |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0408", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => $progress, |
|
message => "job_0408", |
|
variables => $variables, |
|
}); |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0591", variables => { device_path => $local_lv }}); |
|
my $return_code = $anvil->DRBD->remove_backing_lv({ |
|
debug => 2, |
|
backing_disk => $local_lv, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { return_code => $return_code }}); |
|
if ($return_code) |
|
{ |
|
# Should have been '0' |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0368", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0368", |
|
variables => $variables, |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
else |
|
{ |
|
# Gone. |
|
$progress++; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0410"}); |
|
$anvil->Job->update_progress({ |
|
progress => $progress, |
|
message => "job_0410", |
|
}); |
|
} |
|
} |
|
else |
|
{ |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0409", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => $progress, |
|
message => "job_0409", |
|
variables => $variables, |
|
}); |
|
} |
|
} |
|
|
|
# Tell the user we're generationg the new resource config now. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0411"}); |
|
$anvil->Job->update_progress({ |
|
progress => 70, |
|
message => "job_0411", |
|
}); |
|
|
|
### If we're here, we can now update the resource config file to remove the DR host. |
|
# Refresh the IP info (usually scrubbed by this point) |
|
$anvil->Database->get_ip_addresses({debug => 2}); |
|
|
|
# First loop to build the node sections, then we'll loop to build the connections |
|
my $node1_volumes = ""; |
|
my $node2_volumes = ""; |
|
my $node1_ip_address = ""; |
|
my $node1_tcp_port = ""; |
|
my $node2_ip_address = ""; |
|
my $node2_tcp_port = ""; |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{volume}}) |
|
{ |
|
# Find the node 1 backing device, drbd device and minor numbers. |
|
my $node1_device_path = $anvil->data->{new}{resource}{$server_name}{host}{$node1_short_host_name}{volume}{$volume}{device_path}; |
|
my $node1_backing_disk = $anvil->data->{new}{resource}{$server_name}{host}{$node1_short_host_name}{volume}{$volume}{backing_disk}; |
|
my $node1_device_minor = $anvil->data->{new}{resource}{$server_name}{host}{$node1_short_host_name}{volume}{$volume}{device_minor}; |
|
my $node1_meta_disk = $anvil->data->{new}{resource}{$server_name}{host}{$node1_short_host_name}{volume}{$volume}{meta_disk}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:node1_device_path' => $node1_device_path, |
|
's2:node1_backing_disk' => $node1_backing_disk, |
|
's3:node1_device_minor' => $node1_device_minor, |
|
's4:node1_meta_disk' => $node1_meta_disk, |
|
}}); |
|
|
|
$node1_volumes .= $anvil->Words->string({key => "file_0004", variables => { |
|
volume => $volume, |
|
drbd_path => $node1_device_path, |
|
minor => $node1_device_minor, |
|
lv_path => $node1_backing_disk, |
|
meta_data => $node1_meta_disk, |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_volumes => $node1_volumes }}); |
|
|
|
my $node2_device_path = $anvil->data->{new}{resource}{$server_name}{host}{$node2_short_host_name}{volume}{$volume}{device_path}; |
|
my $node2_backing_disk = $anvil->data->{new}{resource}{$server_name}{host}{$node2_short_host_name}{volume}{$volume}{backing_disk}; |
|
my $node2_device_minor = $anvil->data->{new}{resource}{$server_name}{host}{$node2_short_host_name}{volume}{$volume}{device_minor}; |
|
my $node2_meta_disk = $anvil->data->{new}{resource}{$server_name}{host}{$node2_short_host_name}{volume}{$volume}{meta_disk}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:node2_device_path' => $node2_device_path, |
|
's2:node2_backing_disk' => $node2_backing_disk, |
|
's3:node2_device_minor' => $node2_device_minor, |
|
's4:node2_meta_disk' => $node2_meta_disk, |
|
}}); |
|
|
|
$node2_volumes .= $anvil->Words->string({key => "file_0004", variables => { |
|
volume => $volume, |
|
drbd_path => $node2_device_path, |
|
minor => $node2_device_minor, |
|
lv_path => $node2_backing_disk, |
|
meta_data => $node2_meta_disk, |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_volumes => $node2_volumes }}); |
|
|
|
if (not $node1_ip_address) |
|
{ |
|
$node1_ip_address = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$node1_short_host_name}{$node2_short_host_name}{host1_ip_address}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_ip_address => $node1_ip_address }}); |
|
} |
|
if (not $node1_tcp_port) |
|
{ |
|
$node1_tcp_port = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$node1_short_host_name}{$node2_short_host_name}{host1_tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_tcp_port => $node1_tcp_port }}); |
|
} |
|
if (not $node2_ip_address) |
|
{ |
|
$node2_ip_address = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$node1_short_host_name}{$node2_short_host_name}{host2_ip_address}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_ip_address => $node2_ip_address }}); |
|
} |
|
if (not $node2_tcp_port) |
|
{ |
|
$node2_tcp_port = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$node1_short_host_name}{$node2_short_host_name}{host2_tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_tcp_port => $node2_tcp_port }}); |
|
} |
|
} |
|
|
|
# Put together the nodes section. |
|
my $hosts = $anvil->Words->string({key => "file_0003", variables => { |
|
short_host_name => $node1_short_host_name, |
|
node_id => "0", |
|
volumes => $node1_volumes, |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hosts => $hosts }}); |
|
|
|
$hosts .= $anvil->Words->string({key => "file_0003", variables => { |
|
short_host_name => $node2_short_host_name, |
|
node_id => "1", |
|
volumes => $node2_volumes, |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hosts => $hosts }}); |
|
|
|
# Build the connections now |
|
my $connections = $anvil->Words->string({key => "file_0005", variables => { |
|
host1_short_name => $node1_short_host_name, |
|
host1_ip => $node1_ip_address, |
|
tcp_port => $node1_tcp_port, |
|
host2_short_name => $node2_short_host_name, |
|
host2_ip => $node2_ip_address, |
|
tcp_port => $node2_tcp_port, |
|
'c-rate-maximum' => 500, |
|
protocol => "C", |
|
fencing => "resource-and-stonith" |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connections => $connections }}); |
|
|
|
my $new_resource_config = $anvil->Words->string({key => "file_0006", variables => { |
|
server => $server_name, |
|
hosts => $hosts, |
|
connections => $connections, |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_resource_config => $new_resource_config }}); |
|
|
|
my $difference = diff \$old_resource_config, \$new_resource_config, { STYLE => 'Unified' }; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); |
|
|
|
# Write out a test file. |
|
my $test_file = $anvil->data->{path}{directories}{temp}."/test-".$server_name.".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_resource_config, |
|
user => "root", |
|
group => "root", |
|
mode => "0644", |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); |
|
|
|
# Validate. |
|
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." --config-to-test ".$test_file." --config-to-exclude ".$config_file." sh-nop"; |
|
$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, |
|
}}); |
|
if ($return_code) |
|
{ |
|
# Something went wrong. |
|
my $variables = { |
|
return_code => $return_code, |
|
output => $output, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0345", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0345", |
|
variables => $variables, |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Remove the test file. |
|
unlink $test_file; |
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0412"}); |
|
$anvil->Job->update_progress({ |
|
progress => 72, |
|
message => "job_0412", |
|
}); |
|
|
|
# Copy the new config to the peers. |
|
$progress = 72; |
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid) |
|
{ |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $peer_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $peer_ip = $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_host_uuid' => $this_host_uuid, |
|
's2:peer_host_name' => $peer_host_name, |
|
's3:peer_ip' => $peer_ip, |
|
}}); |
|
|
|
my $variables = { |
|
file => $config_file, |
|
host_name => $peer_host_name, |
|
ip_address => $peer_ip, |
|
}; |
|
$progress += 2; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0369", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => $progress, |
|
message => "job_0369", |
|
variables => $variables, |
|
}); |
|
my ($problem) = $anvil->Storage->write_file({ |
|
debug => 2, |
|
backup => 1, |
|
overwrite => 1, |
|
file => $config_file, |
|
body => $new_resource_config, |
|
user => "root", |
|
group => "root", |
|
mode => "0644", |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); |
|
|
|
# Make sure the file exists now. |
|
my $check_resource_config = $anvil->Storage->read_file({ |
|
file => $config_file, |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { check_resource_config => $check_resource_config }}); |
|
|
|
my $difference = diff \$new_resource_config, \$check_resource_config, { STYLE => 'Unified' }; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); |
|
|
|
# Failed to write the file. |
|
if ($difference) |
|
{ |
|
$variables = { |
|
host_name => $peer_host_name, |
|
file => $config_file, |
|
difference => $difference, |
|
new_resource_config => $new_resource_config, |
|
check_resource_config => $check_resource_config, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0405", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "job_0405", |
|
variables => $variables, |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
# Call 'drbdadm adjust <server>' to update the running configs. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0413"}); |
|
$anvil->Job->update_progress({ |
|
progress => 76, |
|
message => "job_0413", |
|
}); |
|
|
|
my $drbdadm_call = $anvil->data->{path}{directories}{drbdadm}." adjust ".$server_name.$anvil->Log->switches(); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbdadm_call => $drbdadm_call }}); |
|
($output, $return_code) = $anvil->System->call({shell_call => $drbdadm_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid, $dr_host_uuid) |
|
{ |
|
# "Peer" in this context is either a node or a DR host |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $peer_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $peer_ip = $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_host_uuid' => $this_host_uuid, |
|
's2:peer_host_name' => $peer_host_name, |
|
's3:peer_ip' => $peer_ip, |
|
}}); |
|
|
|
my $variables = { host_name => $peer_host_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0414", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 77, |
|
message => "job_0414", |
|
variables => $variables, |
|
}); |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
shell_call => $drbdadm_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
} |
|
|
|
# Now delete our resource config file. |
|
$variables = { config_file => $config_file }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0415", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 80, |
|
message => "job_0415", |
|
variables => $variables, |
|
}); |
|
|
|
if (-e $config_file) |
|
{ |
|
my $problem = $anvil->Storage->delete_file({file => $config_file}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); |
|
|
|
if ($problem) |
|
{ |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0369", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0369", |
|
variables => $variables |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
# Done! |
|
$variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0416", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "job_0416", |
|
variables => $variables, |
|
}); |
|
|
|
return(0); |
|
} |
|
|
|
sub process_protect |
|
{ |
|
my ($anvil, $terminal) = @_; |
|
|
|
# Parse out the DRBD resource's backing the server and get their LV sizes. |
|
$anvil->Database->get_server_definitions(); |
|
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid(); |
|
my $anvil_password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; |
|
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; |
|
my $node1_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{host_name}; |
|
my $node1_short_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{short_host_name}; |
|
my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; |
|
my $node2_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{host_name}; |
|
my $node2_short_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{short_host_name}; |
|
my $dr_host_uuid = $anvil->data->{sys}{dr_host_uuid}; |
|
my $dr_host_name = $anvil->data->{sys}{dr_host_name}; |
|
my $dr_short_host_name = $anvil->data->{hosts}{host_uuid}{$dr_host_uuid}{short_host_name}; |
|
my $server_name = $anvil->data->{server}{'server-name'}; |
|
my $server_uuid = $anvil->data->{server}{'server-uuid'}; |
|
my $short_host_name = $anvil->Get->short_host_name(); |
|
my $server_definition_xml = $anvil->data->{server_definitions}{server_definition_server_uuid}{$server_uuid}{server_definition_xml}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
anvil_uuid => $anvil_uuid, |
|
anvil_password => $anvil->Log->is_secure($anvil_password), |
|
node1_host_uuid => $node1_host_uuid, |
|
node1_host_name => $node1_host_name, |
|
node1_short_host_name => $node1_short_host_name, |
|
node2_host_uuid => $node2_host_uuid, |
|
node2_host_name => $node2_host_name, |
|
node2_short_host_name => $node2_short_host_name, |
|
dr_host_uuid => $dr_host_uuid, |
|
dr_host_name => $dr_host_name, |
|
dr_short_host_name => $dr_short_host_name, |
|
server_name => $server_name, |
|
server_uuid => $server_uuid, |
|
server_definition_xml => $server_definition_xml, |
|
short_host_name => $short_host_name, |
|
}}); |
|
|
|
# Sanity checks complete! |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0360", variables => { server => $anvil->data->{server}{'server-name'} }}); |
|
$anvil->Job->update_progress({ |
|
progress => 30, |
|
message => "job_0360,!!server!".$anvil->data->{server}{'server-name'}."!!", |
|
}); |
|
|
|
$anvil->Server->parse_definition({ |
|
debug => 2, |
|
host => $short_host_name, |
|
server => $anvil->data->{server}{'server-name'}, |
|
source => "from_db", |
|
definition => $server_definition_xml, |
|
}); |
|
|
|
$anvil->DRBD->gather_data({debug => 2}); |
|
|
|
my $server_ram = $anvil->data->{server}{$short_host_name}{$server_name}{'from_db'}{memory}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
server_ram => $anvil->Convert->add_commas({number => $server_ram})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $server_ram}).")", |
|
}}); |
|
|
|
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{drbd}{resource}}) |
|
{ |
|
next if $resource eq ""; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { resource => $resource }}); |
|
|
|
foreach my $this_host_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{host}}) |
|
{ |
|
my $this_host_uuid = $anvil->Get->host_uuid_from_name({host_name => $this_host_name}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
this_host_name => $this_host_name, |
|
this_host_uuid => $this_host_uuid, |
|
}}); |
|
|
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}}) |
|
{ |
|
# Always get the LV sizes, as that factors metadata. DRBD size is |
|
# minus metadata, and 0 when down. |
|
my $device_path = $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{device_path}; |
|
my $backing_disk = $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{backing_disk}; |
|
my $device_minor = $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{device_minor}; |
|
my $tcp_port = $anvil->data->{new}{resource}{$resource}{peer}{$this_host_name}{tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"s1:volume" => $volume, |
|
"s2:device_path" => $device_path, |
|
"s3:backing_disk" => $backing_disk, |
|
"s4:device_minor" => $device_minor, |
|
}}); |
|
|
|
my $this_size = $anvil->Storage->get_size_of_block_device({debug => 2, host_uuid => $this_host_uuid, path => $backing_disk}); |
|
if ($this_size eq "") |
|
{ |
|
# DRBD config file was updated, but LV not created yet. |
|
next; |
|
} |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
this_size => $anvil->Convert->add_commas({number => $this_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $this_size}).")", |
|
}}); |
|
|
|
if ((not exists $anvil->data->{server}{drbd}{$resource}{$volume}{size}) or (not $anvil->data->{server}{drbd}{$resource}{$volume}{size})) |
|
{ |
|
$anvil->data->{server}{drbd}{$resource}{$volume}{size} = $this_size; |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"server::drbd::${resource}::${volume}::size" => $anvil->data->{server}{drbd}{$resource}{$volume}{size}, |
|
}}); |
|
} |
|
|
|
if (not exists $anvil->data->{server}{drbd}{$resource}{$volume}{storage_group_uuid}) |
|
{ |
|
$anvil->data->{server}{drbd}{$resource}{$volume}{storage_group_uuid} = ""; |
|
} |
|
|
|
### NOTE: This check make sense only under the assumption that the DRBD minor |
|
### is common across both nodes. This should be the case, but doesn't |
|
### strictly have to be so. |
|
if ((not exists $anvil->data->{server}{drbd}{$resource}{$volume}{minor_number}) or |
|
(not defined $anvil->data->{server}{drbd}{$resource}{$volume}{minor_number}) or |
|
($anvil->data->{server}{drbd}{$resource}{$volume}{minor_number} eq "")) |
|
{ |
|
$anvil->data->{server}{drbd}{$resource}{$volume}{minor_number} = $device_minor; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"server::drbd::${resource}::${volume}::minor_number" => $anvil->data->{server}{drbd}{$resource}{$volume}{minor_number}, |
|
}}); |
|
} |
|
|
|
if ((not exists $anvil->data->{server}{drbd}{$resource}{$volume}{tcp_port}) or |
|
(not defined $anvil->data->{server}{drbd}{$resource}{$volume}{tcp_port}) or |
|
($anvil->data->{server}{drbd}{$resource}{$volume}{tcp_port} eq "")) |
|
{ |
|
$anvil->data->{server}{drbd}{$resource}{$volume}{tcp_port} = $tcp_port; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"server::drbd::${resource}::${volume}::tcp_port" => $anvil->data->{server}{drbd}{$resource}{$volume}{tcp_port}, |
|
}}); |
|
} |
|
|
|
# What storage group does this belong to? |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"server::drbd::${resource}::${volume}::storage_group_uuid" => $anvil->data->{server}{drbd}{$resource}{$volume}{storage_group_uuid}, |
|
}}); |
|
if (not $anvil->data->{server}{drbd}{$resource}{$volume}{storage_group_uuid}) |
|
{ |
|
my $storage_key = $resource."/".$volume; |
|
my $storage_group_uuid = $anvil->Storage->get_storage_group_from_path({ |
|
debug => 2, |
|
anvil_uuid => $anvil_uuid, |
|
path => $backing_disk, |
|
}); |
|
my $storage_group_name = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{group_name}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
storage_key => $storage_key, |
|
storage_group_uuid => $storage_group_uuid, |
|
storage_group_name => $storage_group_name, |
|
}}); |
|
|
|
# We'll need to sum up the volumes on each storage group, as |
|
# it's possible the volumes are on different SGs. |
|
$anvil->data->{server}{drbd}{$resource}{$volume}{storage_group_uuid} = $storage_group_uuid; |
|
$anvil->data->{server}{storage_groups}{$storage_group_name}{used_by}{$storage_key} = 1; |
|
$anvil->data->{server}{storage_groups}{$storage_group_name}{storage_group_uuid} = $storage_group_uuid; |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"server::drbd::${resource}::${volume}::storage_group_uuid" => $anvil->data->{server}{drbd}{$resource}{$volume}{storage_group_uuid}, |
|
"server::storage_groups::${storage_group_name}::used_by::${storage_key}" => $anvil->data->{server}{storage_groups}{$storage_group_name}{used_by}{$storage_key}, |
|
"server::storage_groups::${storage_group_name}::storage_group_uuid" => $anvil->data->{server}{storage_groups}{$storage_group_name}{storage_group_uuid}, |
|
}}); |
|
} |
|
|
|
if ($this_size > $anvil->data->{server}{drbd}{$resource}{$volume}{size}) |
|
{ |
|
$anvil->data->{server}{drbd}{$resource}{$volume}{size} = $this_size; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"server::drbd::${resource}::${volume}::size" => $anvil->Convert->add_commas({number => $anvil->data->{server}{drbd}{$resource}{$volume}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{server}{drbd}{$resource}{$volume}{size}}).")", |
|
}}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
# Make sure there is enough space on DR for the volumes under this VM. |
|
my $problem = 0; |
|
my $config_file = ""; |
|
foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{server}{storage_groups}}) |
|
{ |
|
my $storage_group_uuid = $anvil->data->{server}{storage_groups}{$storage_group_name}{storage_group_uuid}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
storage_group_name => $storage_group_name, |
|
storage_group_uuid => $storage_group_uuid, |
|
}}); |
|
|
|
# First, is this SG on DR? |
|
if (not exists $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$dr_host_uuid}) |
|
{ |
|
# The DR host doesn't appear to be storage group. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0343", variables => { |
|
host_name => $dr_host_name, |
|
storage_group => $storage_group_name, |
|
}}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0343,!!host_name!".$dr_host_name."!!,!!storage_group!".$storage_group_name."!!", |
|
}); |
|
$problem = 1; |
|
} |
|
|
|
my $space_needed = 0; |
|
foreach my $resource_key (sort {$a cmp $b} keys %{$anvil->data->{server}{storage_groups}{$storage_group_name}{used_by}}) |
|
{ |
|
my ($resource, $volume) = ($resource_key =~ /^(.*)\/(\d+)$/); |
|
my $volume_size = $anvil->data->{server}{drbd}{$resource}{$volume}{size}; |
|
$space_needed += $volume_size, |
|
$config_file = $anvil->data->{new}{resource}{$resource}{config_file}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
config_file => $config_file, |
|
resource_key => $resource_key, |
|
resource => $resource, |
|
volume => $volume, |
|
volume_size => $anvil->Convert->add_commas({number => $volume_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $volume_size}).")", |
|
space_needed => $anvil->Convert->add_commas({number => $space_needed})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $space_needed}).")", |
|
}}); |
|
|
|
} |
|
|
|
# Is there enough space on DR? |
|
my $space_on_dr = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$dr_host_uuid}{vg_free}; |
|
if ((not defined $space_on_dr) or ($space_on_dr !~ /^\d+$/)) |
|
{ |
|
# The DR host doesn't have a VG in the SG. |
|
my $variables = { |
|
space_needed => $anvil->Convert->bytes_to_human_readable({'bytes' => $space_needed}), |
|
space_needed_bytes => $anvil->Convert->add_commas({number => $space_needed}), |
|
storage_group => $storage_group_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0468", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0344", |
|
variables => $variables |
|
}); |
|
$problem = 1; |
|
} |
|
else |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
space_on_dr => $anvil->Convert->add_commas({number => $space_on_dr})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $space_on_dr}).")", |
|
space_needed => $anvil->Convert->add_commas({number => $space_needed})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $space_needed}).")", |
|
}}); |
|
if ($space_needed > $space_on_dr) |
|
{ |
|
my $variables = { |
|
space_needed => $anvil->Convert->bytes_to_human_readable({'bytes' => $space_needed}), |
|
space_needed_bytes => $anvil->Convert->add_commas({number => $space_needed}), |
|
storage_group => $storage_group_name, |
|
space_on_dr => $anvil->Convert->bytes_to_human_readable({'bytes' => $space_on_dr}), |
|
space_on_dr_bytes => $anvil->Convert->add_commas({number => $space_on_dr}), |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0344", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0344", |
|
variables => $variables |
|
}); |
|
$problem = 1; |
|
} |
|
} |
|
} |
|
if ($problem) |
|
{ |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Have we already configured the DR? If so, what ports are already allocated. |
|
my $node1_to_dr_port = ""; |
|
my $node1_to_dr_port_inside = ""; |
|
my $node1_to_dr_port_outside = ""; |
|
my $node2_to_dr_port = ""; |
|
my $node2_to_dr_port_inside = ""; |
|
my $node2_to_dr_port_outside = ""; |
|
foreach my $host1_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{host1_to_host2}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host1_name => $host1_name }}); |
|
foreach my $host2_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host2_name => $host2_name }}); |
|
next if (($host1_name ne $dr_short_host_name) && ($host2_name ne $dr_short_host_name)); |
|
|
|
if (($host1_name eq $node1_short_host_name) or ($host2_name eq $node1_short_host_name)) |
|
{ |
|
$node1_to_dr_port = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}{$host2_name}{host1_tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_to_dr_port => $node1_to_dr_port }}); |
|
|
|
if (exists $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_tcp_port}) |
|
{ |
|
$node1_to_dr_port_inside = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_tcp_port}; |
|
$node1_to_dr_port_outside = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
node1_to_dr_port_inside => $node1_to_dr_port_inside, |
|
node1_to_dr_port_outside => $node1_to_dr_port_outside, |
|
}}); |
|
} |
|
} |
|
else |
|
{ |
|
$node2_to_dr_port = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}{$host2_name}{host1_tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_to_dr_port => $node2_to_dr_port }}); |
|
|
|
if (exists $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_tcp_port}) |
|
{ |
|
$node2_to_dr_port_inside = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_tcp_port}; |
|
$node2_to_dr_port_outside = $anvil->data->{new}{resource}{$server_name}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
node2_to_dr_port_inside => $node2_to_dr_port_inside, |
|
node2_to_dr_port_outside => $node2_to_dr_port_outside, |
|
}}); |
|
} |
|
} |
|
} |
|
} |
|
|
|
# Get net next pair of TCP ports, if needed. |
|
my $dr_tcp_ports = 1; |
|
my $long_throw_ports = 0; |
|
if ($anvil->data->{switches}{protocol} eq "long-throw") |
|
{ |
|
$dr_tcp_ports = 0; |
|
$long_throw_ports = 1; |
|
} |
|
my (undef, $tcp_ports) = $anvil->DRBD->get_next_resource({ |
|
debug => 2, |
|
dr_tcp_ports => $dr_tcp_ports, |
|
long_throw_ports => $long_throw_ports, |
|
}); |
|
my @free_ports = split/,/, $tcp_ports; |
|
my $i = 0; |
|
|
|
if ($node1_to_dr_port eq "") |
|
{ |
|
$node1_to_dr_port = $free_ports[$i++]; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_to_dr_port => $node1_to_dr_port }}); |
|
} |
|
|
|
if (($long_throw_ports) && (not $node1_to_dr_port_inside)) |
|
{ |
|
$node1_to_dr_port_inside = $free_ports[$i++]; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_to_dr_port_inside => $node1_to_dr_port_inside }}); |
|
} |
|
if (($long_throw_ports) && (not $node1_to_dr_port_outside)) |
|
{ |
|
$node1_to_dr_port_outside = $free_ports[$i++]; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_to_dr_port_outside => $node1_to_dr_port_outside }}); |
|
} |
|
|
|
if ($node2_to_dr_port eq "") |
|
{ |
|
$node2_to_dr_port = $free_ports[$i]; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_to_dr_port => $node2_to_dr_port }}); |
|
} |
|
if (($long_throw_ports) && (not $node2_to_dr_port_inside)) |
|
{ |
|
$node2_to_dr_port_inside = $free_ports[$i++]; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_to_dr_port_inside => $node2_to_dr_port_inside }}); |
|
} |
|
if (($long_throw_ports) && (not $node2_to_dr_port_outside)) |
|
{ |
|
$node2_to_dr_port_outside = $free_ports[$i++]; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_to_dr_port_outside => $node2_to_dr_port_outside }}); |
|
} |
|
|
|
# Show what we're doing |
|
my $variables = { |
|
protocol => $anvil->data->{switches}{protocol}, |
|
node1_to_dr_port => $node1_to_dr_port, |
|
node1_to_dr_port_inside => $node1_to_dr_port_inside, |
|
node1_to_dr_port_outside => $node1_to_dr_port_outside, |
|
node2_to_dr_port => $node2_to_dr_port, |
|
node2_to_dr_port_inside => $node2_to_dr_port_inside, |
|
node2_to_dr_port_outside => $node2_to_dr_port_outside, |
|
config_file => $config_file, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0361", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 40, |
|
message => "job_0361", |
|
variables => $variables, |
|
}); |
|
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{drbd}}) |
|
{ |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{server}{drbd}{$resource}}) |
|
{ |
|
my $variables = { |
|
resource => $resource, |
|
volume => $volume, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0362", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 43, |
|
message => "job_0362", |
|
variables => $variables, |
|
}); |
|
my $lv_size = $anvil->data->{server}{drbd}{$resource}{$volume}{size}; |
|
my $storage_group_uuid = $anvil->data->{server}{drbd}{$resource}{$volume}{storage_group_uuid}; |
|
my $dr_lv_name = $resource."_".$volume; |
|
my $dr_vg_name = $anvil->Storage->get_vg_name({ |
|
debug => 3, |
|
storage_group_uuid => $storage_group_uuid, |
|
host_uuid => $dr_host_uuid, |
|
}); |
|
my $dr_lv_path = "/dev/".$dr_vg_name."/".$dr_lv_name; |
|
my $extent_size = $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$dr_host_uuid}{vg_extent_size}; |
|
my $extent_count = int($lv_size / $extent_size); |
|
my $shell_call = $anvil->data->{path}{exe}{lvcreate}." -l ".$extent_count." -n ".$dr_lv_name." ".$dr_vg_name." -y"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"s01:resource" => $resource, |
|
"s02:volume" => $volume, |
|
"s03:lv_size" => $anvil->Convert->add_commas({number => $lv_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $lv_size}).")", , |
|
"s04:storage_group_uuid" => $storage_group_uuid, |
|
"s05:dr_lv_name" => $dr_lv_name, |
|
"s06:dr_vg_name" => $dr_vg_name, |
|
"s07:dr_lv_path" => $dr_lv_path, |
|
"s08:extent_size" => $anvil->Convert->add_commas({number => $extent_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $extent_size}).")", |
|
"s09:extent_count" => $extent_count, |
|
"s10:shell_call" => $shell_call, |
|
}}); |
|
|
|
$anvil->data->{server}{dr}{volumes}{$resource}{$volume}{lvcreate_call} = $shell_call; |
|
$anvil->data->{server}{dr}{volumes}{$resource}{$volume}{lv_path} = $dr_lv_path; |
|
$anvil->data->{server}{dr}{volumes}{$resource}{$volume}{storage_group_uuid} = $storage_group_uuid; |
|
$anvil->data->{server}{dr}{volumes}{$resource}{$volume}{drbd_tcp_port} = $anvil->data->{server}{drbd}{$resource}{$volume}{tcp_port}; |
|
$anvil->data->{server}{dr}{volumes}{$resource}{$volume}{drbd_minor} = $anvil->data->{server}{drbd}{$resource}{$volume}{minor_number}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"server::dr::volumes::${resource}::${volume}::lvcreate_call" => $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{lvcreate_call}, |
|
"server::dr::volumes::${resource}::${volume}::lv_path" => $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{lv_path}, |
|
"server::dr::volumes::${resource}::${volume}::storage_group_uuid" => $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{storage_group_uuid}, |
|
"server::dr::volumes::${resource}::${volume}::drbd_tcp_port" => $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{drbd_tcp_port}, |
|
"server::dr::volumes::${resource}::${volume}::drbd_minor" => $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{drbd_minor}, |
|
}}); |
|
|
|
# Get the VG name that this volume will be created on. |
|
$variables = { |
|
lv_path => $dr_lv_path, |
|
lv_size => $anvil->Convert->bytes_to_human_readable({'bytes' => $lv_size}), |
|
lv_size_bytes => $anvil->Convert->add_commas({number => $lv_size}), |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0363", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 47, |
|
message => "job_0363", |
|
variables => $variables, |
|
}); |
|
} |
|
} |
|
|
|
### NOTE: 'Yes' is set when a job is picked up, so this won't re-register the job. |
|
my $record_job = 0; |
|
if (not $anvil->data->{switches}{Yes}) |
|
{ |
|
# If there's no config file, this might be being run from DR which doesn't have info about |
|
# the resource yet. |
|
if ((not $config_file) && (not $anvil->data->{switches}{'job-uuid'})) |
|
{ |
|
# Bail out. |
|
print $anvil->Words->string({key => "message_0308"})."\n"; |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Ask the user to confirm. |
|
print "\n".$anvil->Words->string({key => "message_0021"})."\n"; |
|
my $answer = <STDIN>; |
|
chomp $answer; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); |
|
|
|
if ($answer =~ /^y/i) |
|
{ |
|
print $anvil->Words->string({key => "message_0175"})."\n"; |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
else |
|
{ |
|
print $anvil->Words->string({key => "message_0022"})."\n"; |
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
} |
|
elsif (not $anvil->data->{switches}{'job-uuid'}) |
|
{ |
|
$record_job = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { record_job => $record_job }}); |
|
} |
|
|
|
if ($record_job) |
|
{ |
|
my $job_data = "server=".$anvil->data->{switches}{server}."\n"; |
|
$job_data .= "protect=1\n"; |
|
$job_data .= "dr-host=".$anvil->data->{sys}{dr_host_name}."\n"; |
|
$job_data .= "protocol=".$anvil->data->{switches}{protocol}."\n"; |
|
|
|
# We always record the job against node 1, as it has to use cluster info to run this, so we |
|
# can't run it on the DR itself. |
|
my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_host_uuid => $node1_host_uuid }}); |
|
|
|
# Register the job with this host |
|
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ |
|
debug => 2, |
|
job_command => $anvil->data->{path}{exe}{'anvil-manage-dr'}.$anvil->Log->switches, |
|
job_data => $job_data, |
|
job_name => "server::dr", |
|
job_title => "job_0384", |
|
job_description => "job_0385", |
|
job_progress => 0, |
|
job_host_uuid => $node1_host_uuid, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); |
|
|
|
# Report the job UUID. |
|
print $anvil->Words->string({key => "job_0383", variables => { job_uuid => $job_uuid }})."\n"; |
|
|
|
|
|
$anvil->nice_exit({exit_code => 0}); |
|
} |
|
|
|
### If we're still here, time to get started. |
|
# Read in the old config and update it. |
|
my $old_resource_config = $anvil->Storage->read_file({file => $config_file}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { old_resource_config => $old_resource_config }}); |
|
|
|
# Pull the data out of the old file |
|
my $hosts = ""; |
|
my $nodes_tcp_port = ""; |
|
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{drbd}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { resource => $resource }}); |
|
my $dr_seen = 0; |
|
foreach my $this_host_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{host}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_host_name => $this_host_name }}); |
|
my $node_id = ""; |
|
if (($this_host_name eq $node1_short_host_name) or ($this_host_name eq $node1_host_name)) |
|
{ |
|
$node_id = 0; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node_id => $node_id }}); |
|
|
|
if ((not $nodes_tcp_port) && |
|
(exists $anvil->data->{new}{resource}{$resource}{peer}{$this_host_name}) && |
|
($anvil->data->{new}{resource}{$resource}{peer}{$this_host_name}{tcp_port})) |
|
{ |
|
$nodes_tcp_port = $anvil->data->{new}{resource}{$resource}{peer}{$this_host_name}{tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nodes_tcp_port => $nodes_tcp_port }}); |
|
} |
|
} |
|
elsif (($this_host_name eq $node2_short_host_name) or ($this_host_name eq $node2_host_name)) |
|
{ |
|
$node_id = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node_id => $node_id }}); |
|
|
|
if ((not $nodes_tcp_port) && |
|
(exists $anvil->data->{new}{resource}{$resource}{peer}{$this_host_name}) && |
|
($anvil->data->{new}{resource}{$resource}{peer}{$this_host_name}{tcp_port})) |
|
{ |
|
$nodes_tcp_port = $anvil->data->{new}{resource}{$resource}{peer}{$this_host_name}{tcp_port}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nodes_tcp_port => $nodes_tcp_port }}); |
|
} |
|
} |
|
elsif (($this_host_name eq $dr_short_host_name) or ($this_host_name eq $dr_host_name)) |
|
{ |
|
$node_id = 2; |
|
$dr_seen = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
node_id => $node_id, |
|
dr_seen => $dr_seen, |
|
}}); |
|
} |
|
my $volumes = ""; |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{server}{drbd}{$resource}}) |
|
{ |
|
my $device_path = $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{device_path}; |
|
my $backing_disk = $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{backing_disk}; |
|
my $device_minor = $anvil->data->{new}{resource}{$resource}{host}{$this_host_name}{volume}{$volume}{device_minor}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"s1:device_path" => $device_path, |
|
"s2:backing_disk" => $backing_disk, |
|
"s3:device_minor" => $device_minor, |
|
}}); |
|
|
|
$volumes .= $anvil->Words->string({key => "file_0004", variables => { |
|
volume => $volume, |
|
drbd_path => $device_path, |
|
minor => $device_minor, |
|
lv_path => $backing_disk, |
|
meta_data => "internal", |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { volumes => $volumes }}); |
|
|
|
# Record the DRBD device for adding DR. |
|
if (not exists $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{device_path}) |
|
{ |
|
$anvil->data->{server}{dr}{volumes}{$resource}{$volume}{device_path} = $device_path; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"server::dr::volumes::${resource}::${volume}::device_path" => $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{device_path}, |
|
}}); |
|
} |
|
} |
|
$hosts .= $anvil->Words->string({key => "file_0003", variables => { |
|
short_host_name => $this_host_name, |
|
node_id => $node_id, |
|
volumes => $volumes, |
|
}}); |
|
} |
|
if (not $dr_seen) |
|
{ |
|
# Inject the DR. |
|
my $volumes = ""; |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{server}{dr}{volumes}{$resource}}) |
|
{ |
|
my $device_path = $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{device_path}; |
|
my $backing_disk = $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{lv_path}; |
|
my $device_minor = $anvil->data->{server}{dr}{volumes}{$resource}{$volume}{drbd_minor}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"s1:device_path" => $device_path, |
|
"s2:backing_disk" => $backing_disk, |
|
"s3:device_minor" => $device_minor, |
|
}}); |
|
|
|
$volumes .= $anvil->Words->string({key => "file_0004", variables => { |
|
volume => $volume, |
|
drbd_path => $device_path, |
|
minor => $device_minor, |
|
lv_path => $backing_disk, |
|
meta_data => "internal", |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { volumes => $volumes }}); |
|
} |
|
$hosts .= $anvil->Words->string({key => "file_0003", variables => { |
|
short_host_name => $dr_short_host_name, |
|
node_id => "2", |
|
volumes => $volumes, |
|
}}); |
|
} |
|
} |
|
|
|
# Refresh the IP info (usually scrubbed by this point) |
|
$anvil->Database->get_ip_addresses({debug => 2}); |
|
|
|
# The connections. Node 1 to 2 always uses the BCN, Either node to DR needs |
|
my $storage_network = "sn1"; |
|
my $dr_network = $anvil->data->{lookup}{host_uuid}{$dr_host_uuid}{network}{use_network}; |
|
my $dr_ip = $anvil->data->{lookup}{host_uuid}{$dr_host_uuid}{network}{use_ip}; |
|
my $node1_sn_ip = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{network}{$storage_network}{ip_address}; |
|
my $node1_dr_ip = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{network}{$dr_network}{ip_address}; |
|
my $node2_sn_ip = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{network}{$storage_network}{ip_address}; |
|
my $node2_dr_ip = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{network}{$dr_network}{ip_address}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's01:storage_network' => $storage_network, |
|
's02:dr_host_uuid' => $dr_host_uuid, |
|
's03:dr_network' => $dr_network, |
|
's04:dr_ip' => $dr_ip, |
|
's05:node1_host_uuid' => $node1_host_uuid, |
|
's06:node1_sn_ip' => $node1_sn_ip, |
|
's07:node1_dr_ip' => $node1_dr_ip, |
|
's08:node2_host_uuid' => $node2_host_uuid, |
|
's09:node2_sn_ip' => $node2_sn_ip, |
|
's10:node2_dr_ip' => $node2_dr_ip, |
|
}}); |
|
|
|
# Choose the DR protocol |
|
my $use_drbd_proxy = 0; |
|
my $dr_protocol = "A"; |
|
if ($anvil->data->{switches}{protocol} eq "sync") |
|
{ |
|
$dr_protocol = "C"; |
|
} |
|
elsif ($anvil->data->{switches}{protocol} eq "long-throw") |
|
{ |
|
$use_drbd_proxy = 1; |
|
} |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
dr_protocol => $dr_protocol, |
|
use_drbd_proxy => $use_drbd_proxy, |
|
}}); |
|
|
|
# Node 1 to Node 2 first |
|
my $proxy = ""; |
|
my $max_c_rate = 500; |
|
my $file_key = "file_0005"; |
|
if ($use_drbd_proxy) |
|
{ |
|
$proxy = $anvil->Words->string({key => "file_0008", variables => { memlimit => 256 }}); |
|
$max_c_rate = 100; |
|
$file_key = "file_0007"; |
|
} |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
proxy => $proxy, |
|
max_c_rate => $max_c_rate, |
|
file_key => $file_key, |
|
}}); |
|
|
|
# Node 1 to 2 |
|
my $connections = $anvil->Words->string({key => "file_0005", variables => { |
|
host1_short_name => $node1_short_host_name, |
|
host1_ip => $node1_sn_ip, |
|
host2_short_name => $node2_short_host_name, |
|
host2_ip => $node2_sn_ip, |
|
tcp_port => $nodes_tcp_port, |
|
'c-rate-maximum' => $max_c_rate, |
|
protocol => "C", |
|
fencing => "resource-and-stonith" |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connections => $connections }}); |
|
|
|
# Node 1 to DR |
|
$connections .= $anvil->Words->string({key => $file_key, variables => { |
|
host1_short_name => $node1_short_host_name, |
|
host1_ip => $node1_dr_ip, |
|
host2_short_name => $dr_short_host_name, |
|
host2_ip => $dr_ip, |
|
tcp_port => $node1_to_dr_port, |
|
inside_tcp_port => $node1_to_dr_port_inside, |
|
outside_tcp_port => $node1_to_dr_port_outside, |
|
'c-rate-maximum' => $max_c_rate, |
|
protocol => $dr_protocol, |
|
fencing => "dont-care" |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connections => $connections }}); |
|
|
|
# Node 2 to DR |
|
$connections .= $anvil->Words->string({key => $file_key, variables => { |
|
host1_short_name => $node2_short_host_name, |
|
host1_ip => $node2_dr_ip, |
|
host2_short_name => $dr_short_host_name, |
|
host2_ip => $dr_ip, |
|
tcp_port => $node2_to_dr_port, |
|
inside_tcp_port => $node2_to_dr_port_inside, |
|
outside_tcp_port => $node2_to_dr_port_outside, |
|
'c-rate-maximum' => $max_c_rate, |
|
protocol => $dr_protocol, |
|
fencing => "dont-care" |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connections => $connections }}); |
|
|
|
my $new_resource_config = $anvil->Words->string({key => "file_0006", variables => { |
|
server => $server_name, |
|
proxy => $proxy, |
|
hosts => $hosts, |
|
connections => $connections, |
|
}}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_resource_config => $new_resource_config }}); |
|
|
|
# Is the new res file the same as the old one? |
|
my $difference = diff \$old_resource_config, \$new_resource_config, { STYLE => 'Unified' }; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); |
|
|
|
# Is there a difference on the local version? There might be a difference on peers, but we'll deel |
|
# with that below. |
|
if (not $difference) |
|
{ |
|
# The resource file doesn't need to be updated. |
|
my $variables = { |
|
file => $config_file, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0364", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 50, |
|
message => "job_0364", |
|
variables => $variables, |
|
}); |
|
} |
|
else |
|
{ |
|
# Write out a test file. |
|
my $test_file = $anvil->data->{path}{directories}{temp}."/test-".$server_name.".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_resource_config, |
|
user => "root", |
|
group => "root", |
|
mode => "0644", |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); |
|
|
|
# Validate. |
|
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." --config-to-test ".$test_file." --config-to-exclude ".$config_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. |
|
my $variables = { |
|
return_code => $return_code, |
|
output => $output, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0345", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0345", |
|
variables => $variables, |
|
}); |
|
$anvil->nice_exit({exit_code => 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. |
|
my ($backup_file) = $anvil->Storage->backup({file => $config_file}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { backup_file => $backup_file }}); |
|
my $variables = { backup_file => $backup_file }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0365", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 60, |
|
message => "job_0365", |
|
variables => $variables, |
|
}); |
|
|
|
# Write out the new file. |
|
($problem) = $anvil->Storage->write_file({ |
|
debug => 2, |
|
backup => 0, |
|
overwrite => 1, |
|
file => $config_file, |
|
body => $new_resource_config, |
|
user => "root", |
|
group => "root", |
|
mode => "0644", |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { backup_file => $backup_file }}); |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0366"}); |
|
$anvil->Job->update_progress({ |
|
progress => 65, |
|
message => "job_0366", |
|
}); |
|
|
|
# Call 'drbdadm dump-xml' to check that it's OK. |
|
($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{drbdadm}." dump-xml"}); |
|
if ($return_code) |
|
{ |
|
# Something went wrong. |
|
my $variables = { |
|
return_code => $return_code, |
|
output => $output, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0345", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 70, |
|
message => "error_0345", |
|
variables => $variables, |
|
}); |
|
|
|
# Restoring the old config now. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0346"}); |
|
$anvil->Job->update_progress({ |
|
progress => 75, |
|
message => "error_0346", |
|
}); |
|
|
|
# Backup the bad file and worn the user. |
|
my ($backup_file) = $anvil->Storage->backup({file => $config_file}); |
|
$variables = { file => $backup_file }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0347", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 80, |
|
message => "error_0347", |
|
variables => $variables, |
|
}); |
|
|
|
# Write out the new file. |
|
my ($problem) = $anvil->Storage->write_file({ |
|
debug => 2, |
|
backup => 1, |
|
overwrite => 1, |
|
file => $config_file, |
|
body => $old_resource_config, |
|
user => "root", |
|
group => "root", |
|
mode => "0644", |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { backup_file => $backup_file }}); |
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0348"}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0348", |
|
variables => $variables, |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# New config is good! Update the file on the peers. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0367"}); |
|
$anvil->Job->update_progress({ |
|
progress => 70, |
|
message => "job_0367", |
|
}); |
|
} |
|
|
|
# New config is good! Update the file on the peers. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0368"}); |
|
$anvil->Job->update_progress({ |
|
progress => 72, |
|
message => "job_0368", |
|
}); |
|
|
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid, $dr_host_uuid) |
|
{ |
|
# "Peer" in this context is either a node or a DR host. It's not uncommon for the DR host to |
|
# not have a connection over the SN or even the BCN. So we'll use the IFN1 to move files. |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $peer_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $peer_ip = $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_host_uuid' => $this_host_uuid, |
|
's2:peer_host_name' => $peer_host_name, |
|
's3:peer_ip' => $peer_ip, |
|
}}); |
|
|
|
my $variables = { |
|
file => $config_file, |
|
host_name => $peer_host_name, |
|
ip_address => $peer_ip, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0369", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 75, |
|
message => "job_0369", |
|
variables => $variables, |
|
}); |
|
my ($problem) = $anvil->Storage->write_file({ |
|
debug => 2, |
|
backup => 1, |
|
overwrite => 1, |
|
file => $config_file, |
|
body => $new_resource_config, |
|
user => "root", |
|
group => "root", |
|
mode => "0644", |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); |
|
|
|
# Make sure the file exists now. |
|
my $check_resource_config = $anvil->Storage->read_file({ |
|
file => $config_file, |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { check_resource_config => $check_resource_config }}); |
|
|
|
my $difference = diff \$new_resource_config, \$check_resource_config, { STYLE => 'Unified' }; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); |
|
|
|
# Failed to write the file. |
|
if ($difference) |
|
{ |
|
$variables = { |
|
host_name => $peer_host_name, |
|
file => $config_file, |
|
difference => $difference, |
|
new_resource_config => $new_resource_config, |
|
check_resource_config => $check_resource_config, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0405", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "job_0405", |
|
variables => $variables, |
|
job_status => "failed", |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
} |
|
|
|
# Immediately call scan-drbd on all machines to ensure that if another run is about to happen for a |
|
# different server, it knows the used ports list is updated. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0381"}); |
|
$anvil->Job->update_progress({ |
|
progress => 76, |
|
message => "job_0381", |
|
}); |
|
|
|
my $scan_drbd_call = $anvil->data->{path}{directories}{scan_agents}."/scan-drbd/scan-drbd --force ".$anvil->Log->switches(); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { scan_drbd_call => $scan_drbd_call }}); |
|
my ($output, $return_code) = $anvil->System->call({shell_call => $scan_drbd_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid, $dr_host_uuid) |
|
{ |
|
# "Peer" in this context is either a node or a DR host |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $peer_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $peer_ip = $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_host_uuid' => $this_host_uuid, |
|
's2:peer_host_name' => $peer_host_name, |
|
's3:peer_ip' => $peer_ip, |
|
}}); |
|
|
|
my $variables = { host_name => $peer_host_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0382", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 77, |
|
message => "job_0382", |
|
variables => $variables, |
|
}); |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
shell_call => $scan_drbd_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
} |
|
|
|
# Create the LV and MD on DR. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0370"}); |
|
$anvil->Job->update_progress({ |
|
progress => 78, |
|
message => "job_0370", |
|
}); |
|
my $create_md = 0; |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{server}{drbd}{$server_name}}) |
|
{ |
|
my $dr_ip = $anvil->data->{lookup}{host_uuid}{$dr_host_uuid}{network}{use_ip}; |
|
my $lv_path = $anvil->data->{server}{dr}{volumes}{$server_name}{$volume}{lv_path}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:volume' => $volume, |
|
's2:dr_ip' => $dr_ip, |
|
's3:lv_path' => $lv_path, |
|
}}); |
|
|
|
my $variables = { |
|
volume => $volume, |
|
lv_path => $lv_path, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0371", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 80, |
|
message => "job_0371", |
|
variables => $variables, |
|
}); |
|
|
|
my $lv_check_call = " |
|
if [ -e '".$lv_path."' ]; |
|
then |
|
echo exists; |
|
else |
|
echo create; |
|
fi"; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { lv_check_call => $lv_check_call }}); |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $dr_ip, |
|
password => $anvil_password, |
|
shell_call => $lv_check_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
if ($output eq "exists") |
|
{ |
|
my $variables = { lv_path => $lv_path }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0372", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 80, |
|
message => "job_0372", |
|
variables => $variables, |
|
}); |
|
next; |
|
} |
|
|
|
# Create the LV. |
|
my $lvcreate_call = $anvil->data->{server}{dr}{volumes}{$server_name}{$volume}{lvcreate_call}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { lvcreate_call => $lvcreate_call }}); |
|
($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $dr_ip, |
|
password => $anvil_password, |
|
shell_call => $lvcreate_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
|
|
sleep 1; |
|
# Does it exist now? |
|
($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $dr_ip, |
|
password => $anvil_password, |
|
shell_call => $lv_check_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
if ($output eq "create") |
|
{ |
|
my $variables = { lv_path => $lv_path }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0349", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "error_0349", |
|
variables => $variables, |
|
}); |
|
$anvil->nice_exit({exit_code => 1}); |
|
} |
|
|
|
# Create the DRBD meta data now. |
|
$create_md = 1; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { create_md => $create_md }}); |
|
} |
|
|
|
if ($create_md) |
|
{ |
|
my $dr_ip = $anvil->data->{lookup}{host_uuid}{$dr_host_uuid}{network}{use_ip}; |
|
my $drbd_md_call = $anvil->data->{path}{exe}{drbdadm}." --force create-md --max-peers=3 ".$server_name; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:dr_ip' => $dr_ip, |
|
's2:drbd_md_call' => $drbd_md_call, |
|
}}); |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $dr_ip, |
|
password => $anvil_password, |
|
shell_call => $drbd_md_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
} |
|
|
|
# Reload the config. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0373"}); |
|
$anvil->Job->update_progress({ |
|
progress => 85, |
|
message => "job_0373", |
|
}); |
|
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." adjust ".$server_name; |
|
$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, |
|
}}); |
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid, $dr_host_uuid) |
|
{ |
|
# "Peer" in this context is either a node or a DR host |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $peer_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $peer_ip = $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_host_uuid' => $this_host_uuid, |
|
's2:peer_host_name' => $peer_host_name, |
|
's3:peer_ip' => $peer_ip, |
|
}}); |
|
|
|
my $variables = { |
|
server => $server_name, |
|
host_name => $peer_host_name, |
|
}; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0374", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 85, |
|
message => "job_0374", |
|
variables => $variables, |
|
}); |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
shell_call => $shell_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
} |
|
|
|
# If the resource is down, bring it up. |
|
$variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0375", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 88, |
|
message => "job_0375", |
|
variables => $variables, |
|
}); |
|
my $drbd_up_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 => { drbd_up_call => $drbd_up_call }}); |
|
($output, $return_code) = $anvil->System->call({shell_call => $drbd_up_call}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
foreach my $this_host_uuid ($node1_host_uuid, $node2_host_uuid, $dr_host_uuid) |
|
{ |
|
# "Peer" in this context is either a node or a DR host |
|
next if $this_host_uuid eq $anvil->Get->host_uuid(); |
|
my $peer_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; |
|
my $peer_ip = $anvil->data->{lookup}{host_uuid}{$this_host_uuid}{network}{use_ip}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
's1:this_host_uuid' => $this_host_uuid, |
|
's2:peer_host_name' => $peer_host_name, |
|
's3:peer_ip' => $peer_ip, |
|
}}); |
|
|
|
$variables = { host_name => $peer_host_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0376", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 90, |
|
message => "job_0376", |
|
variables => $variables, |
|
}); |
|
my ($output, $error, $return_code) = $anvil->Remote->call({ |
|
target => $peer_ip, |
|
password => $anvil_password, |
|
shell_call => $drbd_up_call, |
|
}); |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
error => $error, |
|
output => $output, |
|
return_code => $return_code, |
|
}}); |
|
} |
|
|
|
# Now watch until the DR host shows up |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0377"}); |
|
$anvil->Job->update_progress({ |
|
progress => 92, |
|
message => "job_0377", |
|
}); |
|
my $waiting = 1; |
|
while($waiting) |
|
{ |
|
sleep 5; |
|
$anvil->DRBD->gather_data({debug => 2}); |
|
|
|
my $dr_seen = 1; |
|
foreach my $volume (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$server_name}{volume}}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { volume => $volume }}); |
|
if (exists $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$dr_short_host_name}) |
|
{ |
|
my $local_role = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$dr_short_host_name}{local_role}; |
|
my $local_disk_state = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$dr_short_host_name}{local_disk_state}; |
|
my $peer_role = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$dr_short_host_name}{peer_role}; |
|
my $peer_disk_state = $anvil->data->{new}{resource}{$server_name}{volume}{$volume}{peer}{$dr_short_host_name}{peer_disk_state}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
local_role => $local_role, |
|
local_disk_state => $local_disk_state, |
|
peer_role => $peer_role, |
|
peer_disk_state => $peer_disk_state, |
|
}}); |
|
} |
|
else |
|
{ |
|
# Not up yet. |
|
my $next_check = $anvil->Get->date_and_time({offset => 5, time_only => 1}); |
|
my $variables = { next_check => $next_check }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0378", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 95, |
|
message => "job_0378", |
|
variables => $variables, |
|
}); |
|
$dr_seen = 0; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr_seen => $dr_seen }}); |
|
last; |
|
} |
|
} |
|
|
|
if ($dr_seen) |
|
{ |
|
# We're ready. |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0379"}); |
|
$anvil->Job->update_progress({ |
|
progress => 98, |
|
message => "job_0379", |
|
}); |
|
$waiting = 0; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); |
|
} |
|
} |
|
|
|
# Done! |
|
$variables = { server => $server_name }; |
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0380", variables => $variables}); |
|
$anvil->Job->update_progress({ |
|
progress => 100, |
|
message => "job_0380", |
|
variables => $variables, |
|
}); |
|
|
|
return(0); |
|
} |
|
|
|
sub load_job |
|
{ |
|
my ($anvil) = @_; |
|
|
|
$anvil->Job->clear(); |
|
$anvil->Job->get_job_details(); |
|
$anvil->Job->update_progress({ |
|
progress => 1, |
|
job_picked_up_by => $$, |
|
job_picked_up_at => time, |
|
message => "message_0267", |
|
}); |
|
|
|
print "Loading the job: [".$anvil->data->{switches}{'job-uuid'}."]...\n"; |
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"jobs::job_command" => $anvil->data->{jobs}{job_command}, |
|
"jobs::job_data" => $anvil->data->{jobs}{job_data}, |
|
"jobs::job_progress" => $anvil->data->{jobs}{job_progress}, |
|
"jobs::job_status" => $anvil->data->{jobs}{job_status}, |
|
}}); |
|
|
|
# Break up the job data into switches. |
|
$anvil->data->{switches}{Yes} = 1; |
|
print "- Set the switch: [--Yes] to true.\n"; |
|
foreach my $line (split/\n/, $anvil->data->{jobs}{job_data}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); |
|
if ($line =~ /(.*?)=(.*)$/) |
|
{ |
|
my $key = $1; |
|
my $value = $2; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
key => $key, |
|
value => $value, |
|
}}); |
|
|
|
$anvil->data->{switches}{$key} = $value; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"switches::${key}" => $anvil->data->{switches}{$key}, |
|
}}); |
|
|
|
print "* Set the switch: [--".$key."] to: [".$value."]\n"; |
|
} |
|
} |
|
print "Job loaded successfully.\n\n"; |
|
|
|
return(0); |
|
} |
|
|
|
sub check_for_duplicate_dr_links |
|
{ |
|
my ($anvil) = @_; |
|
|
|
if (exists $anvil->data->{dr_links}) |
|
{ |
|
delete $anvil->data->{dr_links}; |
|
} |
|
my $query = " |
|
SELECT |
|
dr_link_uuid, |
|
dr_link_host_uuid, |
|
dr_link_anvil_uuid, |
|
dr_link_note |
|
FROM |
|
dr_links |
|
ORDER BY |
|
modified_date DESC;"; |
|
$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 $dr_link_uuid = $row->[0]; |
|
my $dr_link_host_uuid = $row->[1]; |
|
my $dr_link_anvil_uuid = $row->[2]; |
|
my $dr_link_note = $row->[3]; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
dr_link_uuid => $dr_link_uuid, |
|
dr_link_host_uuid => $dr_link_host_uuid, |
|
dr_link_anvil_uuid => $dr_link_anvil_uuid, |
|
dr_link_note => $dr_link_note, |
|
}}); |
|
|
|
if (exists $anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_note}) |
|
{ |
|
# Duplicate! |
|
my $previous_note = $anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_note}; |
|
my $this_note = $dr_link_note; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
previous_note => $previous_note, |
|
this_note => $this_note, |
|
}}); |
|
|
|
# If the previous note was "DELETED", delete it. Otherwise we'll delete this one. |
|
if ($previous_note eq "DELETED") |
|
{ |
|
# Delete the previous one. |
|
my $old_dr_link_uuid = $anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_uuid}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_dr_link_uuid => $old_dr_link_uuid }}); |
|
|
|
my $queries = []; |
|
push @{$queries}, "DELETE FROM history.dr_links WHERE dr_link_uuid = ".$anvil->Database->quote($old_dr_link_uuid).";"; |
|
push @{$queries}, "DELETE FROM dr_links WHERE dr_link_uuid = ".$anvil->Database->quote($old_dr_link_uuid).";"; |
|
foreach my $query (@{$queries}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); |
|
} |
|
$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); |
|
|
|
# Update the local record to store this one. |
|
$anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_uuid} = $dr_link_uuid; |
|
$anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_note} = $dr_link_note; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"dr_links::host_uuid::${dr_link_host_uuid}::${dr_link_anvil_uuid}::dr_link_uuid" => $anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_uuid}, |
|
"dr_links::host_uuid::${dr_link_host_uuid}::${dr_link_anvil_uuid}::dr_link_note" => $anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_note}, |
|
}}); |
|
} |
|
else |
|
{ |
|
# Delete this one. |
|
my $queries = []; |
|
push @{$queries}, "DELETE FROM history.dr_links WHERE dr_link_uuid = ".$anvil->Database->quote($dr_link_uuid).";"; |
|
push @{$queries}, "DELETE FROM dr_links WHERE dr_link_uuid = ".$anvil->Database->quote($dr_link_uuid).";"; |
|
foreach my $query (@{$queries}) |
|
{ |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); |
|
} |
|
$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__}); |
|
} |
|
} |
|
else |
|
{ |
|
$anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_uuid} = $dr_link_uuid; |
|
$anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_note} = $dr_link_note; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
|
"dr_links::host_uuid::${dr_link_host_uuid}::${dr_link_anvil_uuid}::dr_link_uuid" => $anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_uuid}, |
|
"dr_links::host_uuid::${dr_link_host_uuid}::${dr_link_anvil_uuid}::dr_link_note" => $anvil->data->{dr_links}{host_uuid}{$dr_link_host_uuid}{$dr_link_anvil_uuid}{dr_link_note}, |
|
}}); |
|
} |
|
} |
|
|
|
# Done, reload dr_links. |
|
delete $anvil->data->{dr_links}; |
|
$anvil->Database->get_dr_links(); |
|
} |
|
|
|
sub show_servers |
|
{ |
|
my ($anvil, $anvil_uuid) = @_; |
|
|
|
my $server_count = keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}}; |
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }}); |
|
if ($server_count > 0) |
|
{ |
|
print $anvil->Words->string({key => "error_0413"})."\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}; |
|
print "- ".$server_name." (".$server_uuid.")\n"; |
|
} |
|
print "\n"; |
|
} |
|
}
|
|
|