<keyname="error_0340"><![CDATA[Please specify the server to manager using '--server <name or uuid>'. Exiting.]]></key>
<keyname="error_0341">Failed to find the server: [#!variable!server!#] by name or UUID? Exiting.</key>
<keyname="error_0342">The protocol: [#!variable!protocol!#] is invalid. Please use '--help' for more information.</key>
<keyname="error_0343">The DR host: [#!variable!host_name!#] doesn't appear to be storage group: [#!variable!storage_group!#]. Unable to proceed.</key>
<keyname="error_0343">The DR host: [#!variable!host_name!#] doesn't appear to be in the storage group: [#!variable!storage_group!#]. Unable to proceed.</key>
<keyname="error_0344">We need: [#!variable!space_needed!# (#!variable!space_needed_bytes!# Bytes)] from the storage group: [#!variable!storage_group!#], but only: [#!variable!space_on_dr!# (#!variable!space_on_dr_bytes!# bytes)] is available on DR. Unable to proceed.</key>
<keyname="error_0345">[ Error ] - The check appears to have failed. Expected a return code of '0', but got: [#!variable!return_code!#]
The output, if any, was
@ -2418,7 +2418,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<keyname="message_0018">What would you like the new password to be?</key>
<keyname="message_0019">Please enter the password again to confirm.</key>
<keyname="message_0020">About to update the local passwords (shell users, database and web interface).</key>
<keyname="message_0021">Proceed? [y/N]</key><!-- Default Yes is at message_0206 -->
<keyname="message_0021">Proceed? [y/N]</key><!-- Default No is at message_0206 -->
<keyname="message_0022">Aborting.</key>
<keyname="message_0023">Auto-approved by command line switch, proceeding.</key>
<keyname="message_0024">Updating the Striker user: [#!variable!user!#] password... </key>
@ -3625,6 +3625,7 @@ We will wait: [#!variable!waiting!#] seconds and then try again. We'll give up i
<keyname="warning_0155">[ Warning ] - The file: [#!variable!file_path!#] needed to provision the server: [#!variable!server_name!#] was not found in the database as being on this host yet.</key>
<keyname="warning_0156">[ Warning ] - The file: [#!variable!file_path!#] needed to provision the server: [#!variable!server_name!#] was found, but it's not ready yet.</key>
<keyname="warning_0157">[ Warning ] - Waiting for a bit, and then will check if files are ready.</key>
<keyname="warning_0158">[ Warning ] - There is a duplicate storage group named: [#!variable!group_name!#]. Keeping the group with UUID: [#!variable!keep_uuid!#], and deleting the group with the UUID: [#!variable!delete_uuid!#]</key>
my $type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{type};
my $address_type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{type};
my $address_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{bus};
my $driver_name = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{name};
my $device_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{device_bus};
my $driver_type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{type};
my $address_domain = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{domain};
my $address_slot = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{slot};
my $address_function = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{function};
my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{path};
my $driver_io = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{io};
my $driver_cache = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{cache};
my $on_lv = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv};
my $drbd_volume = $anvil->data->{lvm}{host_name}{$short_host_name}{lv_path}{$on_lv}{drbd}{volume};
my $max_free_space = $anvil->data->{server_name}{$server_name}{drbd_resource}{$drbd_resource}{volume}{$drbd_volume}{free_space};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
my $type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{type};
my $address_type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{type};
my $address_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{bus};
my $driver_name = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{name};
my $device_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{device_bus};
my $driver_type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{type};
my $address_domain = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{domain};
my $address_slot = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{slot};
my $address_function = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{function};
my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{path};
my $driver_io = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{io};
my $driver_cache = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{cache};
my $on_lv = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv};
my $drbd_volume = $anvil->data->{lvm}{host_name}{$short_host_name}{lv_path}{$on_lv}{drbd}{volume};
my $max_free_space = $anvil->data->{server_name}{$server_name}{drbd_resource}{$drbd_resource}{volume}{$drbd_volume}{free_space};
return(0);
}
sub manage_disk_add
{
my ($anvil, $drbd_resource) = @_;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }});
my $anvil_uuid = defined $anvil->data->{switches}{anvil_uuid} ? $anvil->data->{switches}{anvil_uuid} : $anvil->Cluster->get_anvil_uuid();
my $short_host_name = $anvil->Get->short_host_name;
my $server_name = $anvil->data->{switches}{server_name};
my $from_source = get_definition_source($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
storage_group_uuid => $storage_group_uuid,
storage_group_name => $storage_group_name,
}});
}
foreach my $host_type ("node", "dr")
# Did we get a valid disk size?
my $free_space = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{free_space};
my $add_size = $anvil->data->{switches}{add};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
if ($add_size =~ /^(\d+)%$/)
{
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
# This is valid
my $percent = ".".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { percent => $percent }});
$add_size = int($free_space * $percent);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
}
elsif ($add_size !~ /\d/)
{
# No digits, probably didn't set a value at all.
print "\n[ Error ] - Please specify the size you would like to grow this disk by. The maximum size is: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $free_space})."].\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
}
elsif ($add_size !~ /^\d+$/)
{
# Size is not in bytes, try to convert it.
my $bytes = $anvil->Convert->human_readable_to_bytes({
debug => 2,
size => $add_size,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'bytes' => $bytes }});
if ($bytes =~ /^\d+$/)
{
my $host_uuid = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
}
else
{
# Not a valid size.
print "\n[ Error ] - The requested size: [".$add_size."] could not be interpreted.\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
}
}
=cut
# What are we doing?
if ($anvil->data->{switches}{grow})
{
# Are they asking for an available amount of space?
my $error_note = q|
# Get the next free minor number
my ($free_minor, undef) = $anvil->DRBD->get_next_resource({
debug => 2,
minor_only => 1,
anvil_uuid => $anvil_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { free_minor => $free_minor }});
return(0);
}
sub manage_disk_grow
{
my ($anvil, $drbd_resource, $drbd_volume, $max_free_space) = @_;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:drbd_resource' => $drbd_resource,
's2:drbd_volume' => $drbd_volume,
's3:max_free_space' => $max_free_space,
}});
my $anvil_uuid = defined $anvil->data->{switches}{anvil_uuid} ? $anvil->data->{switches}{anvil_uuid} : $anvil->Cluster->get_anvil_uuid();
my $short_host_name = $anvil->Get->short_host_name;
my $server_name = $anvil->data->{switches}{server_name};
my $from_source = get_definition_source($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_uuid => $anvil_uuid,
short_host_name => $short_host_name,
server_name => $server_name,
from_source => $from_source,
}});
# Are they asking for an available amount of space?
my $error_note = q|
[ Note ] - The size can be in percent, ie: '50%' or '100%', a number in bytes, or a human-readable size.
- Human readable sizes must NOT have a space between the number and letter suffix. Also, base2
- vs base10 notation! Ie: '1GiB' = 1,073,741,824 bytes', '1GB' == '1,000,000,000 bytes'. A single
- letter used to denote size will be interpreted as base2. ie: '1G == 1GiB'.
|;
my $add_size = $anvil->data->{switches}{grow};
my $add_size = $anvil->data->{switches}{grow};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
if ($add_size =~ /^(\d+)%$/)
{
# This is valid
my $percent = ".".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { percent => $percent }});
$add_size = int($max_free_space * $percent);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
if ($add_size =~ /^(\d+)%$/)
}
elsif ($add_size !~ /\d/)
{
# No digits, probably didn't set a value at all.
print "\n[ Error ] - Please specify the size you would like to grow this disk by. The maximum size is: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space})."].\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
}
elsif ($add_size !~ /^\d+$/)
{
# Size is not in bytes, try to convert it.
my $bytes = $anvil->Convert->human_readable_to_bytes({
debug => 2,
size => $add_size,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'bytes' => $bytes }});
if ($bytes =~ /^\d+$/)
{
# This is valid
my $percent = ".".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { percent => $percent }});
$add_size = int($max_free_space * $percent);
$add_size = $bytes;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
}
elsif ($add_size !~ /\d/)
else
{
# No digits, probably didn't set a value at all.
print "\n[ Error ] - Please specify the size you would like to grow this disk by. The maximum size is: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space})."].\n";
# Not a valid size.
print "\n[ Error ] - The requested size: [".$add_size."] could not be interpreted.\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
}
elsif ($add_size !~ /^\d+$/)
{
# Size is not in bytes, try to convert it.
my $bytes = $anvil->Convert->human_readable_to_bytes({
debug => 2,
size => $add_size,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'bytes' => $bytes }});
if ($bytes =~ /^\d+$/)
{
$add_size = $bytes;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
}
else
{
# Not a valid size.
print "\n[ Error ] - The requested size: [".$add_size."] could not be interpreted.\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
}
}
}
# Make sure they're asking for a reasonable size
if ($add_size < 4194304)
# Make sure they're asking for a reasonable size
if ($add_size < 4194304)
{
# Must be a typo, this is less than the size of a single extent.
print "\n[ Error ] - The requested size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $add_size})."] is too small, it's less than an single extent.\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
}
elsif ($add_size > $max_free_space)
{
# Not enough space.
print "\n[ Error ] - The requested size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $add_size})."] is too large. The available size is: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space})."]\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
}
### TODO: Make this work without the peer node being online.
# The server is allowed to be running, but both nodes and any DR hosts this is replicating to
# needs to be online.
my $all_online = check_drbd_peer_access($anvil, $from_source, $drbd_volume);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
if (not $all_online)
{
print "\n[ Error ] - Growing the storage requires all peers to be online.\n";
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{peer}})
{
# Must be a typo, this is less than the size of a single extent.
print "\n[ Error ] - The requested size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $add_size})."] is too small, it's less than an single extent.\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
my $say_access = $anvil->data->{peer}{$short_host_name}{access_ip} ? "up." : "down!";
print " - Peer: [".$short_host_name."] is ".$say_access."\n";
}
elsif ($add_size > $max_free_space)
$anvil->nice_exit({exit_code => 1});
}
# Still here? We're good to go.
my $lv_command_size = 0;
my $hr_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $add_size});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hr_size => $hr_size }});
if ($add_size eq "100%")
{
# This is valid
$add_size = "-l +100\%FREE";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
}
else
{
$hr_size =~ s/\s+//g;
$add_size = "-L +".$hr_size;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
}
print "- Preparing to grow the storage by: [".$hr_size."]...\n";
print "\n[ Error ] - The requested size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $add_size})."] is too large. The available size is: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space})."]\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
print "Aborting.\n";
$anvil->nice_exit({exit_code => 0});
}
### TODO: Make this work without the peer node being online.
# The server is allowed to be running, but both nodes and any DR hosts this is replicating to
# needs to be online.
# Test that we've lost access while waiting for the answer.
my $all_online = check_drbd_peer_access($anvil, $from_source, $drbd_volume);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
if (not $all_online)
{
print "\n[ Error ] - Growing the storage requires all peers to be online.\n";
print "\n[ Error ] - It would appear that we've lost access to a peer while waiting for the answer.\n";
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{peer}})
{
my $say_access = $anvil->data->{peer}{$short_host_name}{access_ip} ? "up." : "down!";
@ -465,96 +601,145 @@ sub manage_disk
}
$anvil->nice_exit({exit_code => 1});
}
}
# Still here? We're good to go.
my $lv_command_size = 0;
my $hr_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $add_size});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hr_size => $hr_size }});
if ($add_size eq "100%")
{
# This is valid
$add_size = "-l +100\%FREE";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
}
else
{
$hr_size =~ s/\s+//g;
$add_size = "-L +".$hr_size;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }});
}
print "- Preparing to grow the storage by: [".$hr_size."]...\n";
if (not $anvil->data->{switches}{confirm})
foreach my $host_type ("node", "dr")
{
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
if (exists $anvil->data->{duplicate_check}{$storage_group_name})
{
# Pick one to delete. Does one of the groups have DR and the other doesn't?
my $other_storage_group_uuid = $anvil->data->{duplicate_check}{$storage_group_name}{storage_group_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { other_storage_group_uuid => $other_storage_group_uuid }});
my $this_query = "SELECT COUNT(*) FROM storage_group_members WHERE storage_group_member_storage_group_uuid = ".$anvil->Database->quote($storage_group_uuid).";";
my $other_query = "SELECT COUNT(*) FROM storage_group_members WHERE storage_group_member_storage_group_uuid = ".$anvil->Database->quote($other_storage_group_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
this_query => $this_query,
other_query => $other_query,
}});
my $this_member_count = $anvil->Database->query({query => $this_query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
my $other_member_count = $anvil->Database->query({query => $other_query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
this_member_count => $this_member_count,
other_member_count => $other_member_count,
}});
# We'll delete this storage group uuid, UNLESS we've got more members.
if ($this_member_count > $other_member_count)
{
# We have more members, we need to delete the other.
push @{$queries}, "DELETE FROM history.storage_group_members WHERE storage_group_member_storage_group_uuid = ".$anvil->Database->quote($other_storage_group_uuid).";";
push @{$queries}, "DELETE FROM storage_group_members WHERE storage_group_member_storage_group_uuid = ".$anvil->Database->quote($other_storage_group_uuid).";";
push @{$queries}, "DELETE FROM history.storage_groups WHERE storage_group_uuid = ".$anvil->Database->quote($other_storage_group_uuid).";";
push @{$queries}, "DELETE FROM storage_groups WHERE storage_group_uuid = ".$anvil->Database->quote($other_storage_group_uuid).";";
foreach my $query (@{$queries})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, list => { query => $query }});
}
$anvil->Database->write({query => $queries, source => $THIS_FILE, line => __LINE__});
push @{$queries}, "DELETE FROM history.storage_group_members WHERE storage_group_member_storage_group_uuid = ".$anvil->Database->quote($storage_group_uuid).";";
push @{$queries}, "DELETE FROM storage_group_members WHERE storage_group_member_storage_group_uuid = ".$anvil->Database->quote($storage_group_uuid).";";
push @{$queries}, "DELETE FROM history.storage_groups WHERE storage_group_uuid = ".$anvil->Database->quote($storage_group_uuid).";";
push @{$queries}, "DELETE FROM storage_groups WHERE storage_group_uuid = ".$anvil->Database->quote($storage_group_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__});
# We don't want to clobber the previously read data, so move on to the next group now.
next;
}
}
# Used to check for duplicates. We can't use the real data as it could have been loaded before here.