* Fixed a bug in DRBD->get_next_resource() where reserved minor numbers were not being released. Also added a new parameter, "minor_only", that returns the next minor number but doesn't bother processing TCP ports.

* Did more work on adding support for adding new disk drives to servers in anvil-manage-server-storage.
* Updated anvil-manage-storage-groups To check for / delete duplicate storage groups with the same name.

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 2 years ago
parent 65af56d5bd
commit ea95d26cc5
  1. 58
      Anvil/Tools/DRBD.pm
  2. 5
      share/words.xml
  3. 4
      tools/anvil-manage-dr
  4. 711
      tools/anvil-manage-server-storage
  5. 93
      tools/anvil-manage-storage-groups
  6. 2
      tools/anvil-watch-drbd

@ -1757,6 +1757,10 @@ If set, the 'free_port' returned will be a comma-separated pair of TCP ports. Th
If set, the 'free_port' returned will be a comma-separated list of seven TCP ports needed for a full B<< Long Throw >> configuration. If set, the 'free_port' returned will be a comma-separated list of seven TCP ports needed for a full B<< Long Throw >> configuration.
=head3 minor_only (optional, default '0')
When set to C<< 1 >>, only a new minor number is returned. The tcp number will be an empty string.
=head3 resource_name (optional) =head3 resource_name (optional)
If this is set, and the resource is found to already exist, the first DRBD minor number and first used TCP port are returned. Alternatively, if C<< force_unique >> is set to C<< 1 >>, and the resource is found to exist, empty strings are returned. If this is set, and the resource is found to already exist, the first DRBD minor number and first used TCP port are returned. Alternatively, if C<< force_unique >> is set to C<< 1 >>, and the resource is found to exist, empty strings are returned.
@ -1780,12 +1784,14 @@ sub get_next_resource
my $anvil_uuid = defined $parameter->{anvil_uuid} ? $parameter->{anvil_uuid} : ""; my $anvil_uuid = defined $parameter->{anvil_uuid} ? $parameter->{anvil_uuid} : "";
my $dr_tcp_ports = defined $parameter->{dr_tcp_ports} ? $parameter->{dr_tcp_ports} : ""; my $dr_tcp_ports = defined $parameter->{dr_tcp_ports} ? $parameter->{dr_tcp_ports} : "";
my $long_throw_ports = defined $parameter->{long_throw_ports} ? $parameter->{long_throw_ports} : ""; my $long_throw_ports = defined $parameter->{long_throw_ports} ? $parameter->{long_throw_ports} : "";
my $minor_only = defined $parameter->{minor_only} ? $parameter->{minor_only} : "";
my $resource_name = defined $parameter->{resource_name} ? $parameter->{resource_name} : ""; my $resource_name = defined $parameter->{resource_name} ? $parameter->{resource_name} : "";
my $force_unique = defined $parameter->{force_unique} ? $parameter->{force_unique} : 0; my $force_unique = defined $parameter->{force_unique} ? $parameter->{force_unique} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid, anvil_uuid => $anvil_uuid,
dr_tcp_ports => $dr_tcp_ports, dr_tcp_ports => $dr_tcp_ports,
long_throw_ports => $long_throw_ports, long_throw_ports => $long_throw_ports,
minor_only => $minor_only,
resource_name => $resource_name, resource_name => $resource_name,
force_unique => $force_unique, force_unique => $force_unique,
}}); }});
@ -1931,8 +1937,13 @@ ORDER BY
# If I'm here, We'll look for the next minor number for this host. # If I'm here, We'll look for the next minor number for this host.
my $looking = 1; my $looking = 1;
my $free_minor = 0; my $free_minor = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
looking => $looking,
free_minor => $free_minor,
}});
while($looking) while($looking)
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { free_minor => $free_minor }});
if (exists $anvil->data->{drbd}{used_resources}{minor}{$free_minor}) if (exists $anvil->data->{drbd}{used_resources}{minor}{$free_minor})
{ {
$free_minor++; $free_minor++;
@ -1952,7 +1963,8 @@ ORDER BY
's3:variable_uuid' => $variable_uuid, 's3:variable_uuid' => $variable_uuid,
}}); }});
if (($variable_value) && ($variable_value !~ /^\d+$/)) # If the value set, a digit, and older than the current time?
if (($variable_value) && (($variable_value !~ /^\d+$/) or (time > $variable_value)))
{ {
# Bad value, clear it. # Bad value, clear it.
$variable_uuid = $anvil->Database->insert_or_update_variables({ $variable_uuid = $anvil->Database->insert_or_update_variables({
@ -1961,39 +1973,23 @@ ORDER BY
variable_value => "0", variable_value => "0",
update_value_only => "", update_value_only => "",
}); });
$variable_value = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable_uuid => $variable_uuid }});
# Clear the variable UUID for the next step.
$variable_uuid = "";
$variable_value = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
variable_uuid => $variable_uuid, variable_uuid => $variable_uuid,
variable_value => $variable_value variable_value => $variable_value
}}); }});
} }
if ($variable_uuid) if ($variable_uuid)
{ {
my $now_time = time; # This is being held, move on.
my $age = $now_time - $variable_value; $free_minor++;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { free_minor => $free_minor }});
age => $age, next;
now_time => $now_time,
}});
if (($variable_value) && ($now_time > $variable_value))
{
# This is being held, move on.
$free_minor++;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { free_minor => $free_minor }});
next;
}
else
{
# Either the hold is stale or invalid, delete it.
$variable_uuid = $anvil->Database->insert_or_update_variables({
debug => $debug,
variable_uuid => $variable_uuid,
variable_value => "0",
update_value_only => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable_uuid => $variable_uuid }});
}
} }
# To prevent race conditions, put a one minute hold on the minor number. # To prevent race conditions, put a one minute hold on the minor number.
@ -2014,6 +2010,14 @@ ORDER BY
} }
} }
# If they're only asking for a minor number, like adding a disk, we're done.
if ($minor_only)
{
# We're done.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { free_minor => $free_minor }});
return($free_minor, "");
}
# I need to find the next free TCP port. # I need to find the next free TCP port.
$looking = 1; $looking = 1;
my $check_port = 7788; my $check_port = 7788;

@ -466,7 +466,7 @@ Giving up.
<key name="error_0340"><![CDATA[Please specify the server to manager using '--server <name or uuid>'. Exiting.]]></key> <key name="error_0340"><![CDATA[Please specify the server to manager using '--server <name or uuid>'. Exiting.]]></key>
<key name="error_0341">Failed to find the server: [#!variable!server!#] by name or UUID? Exiting.</key> <key name="error_0341">Failed to find the server: [#!variable!server!#] by name or UUID? Exiting.</key>
<key name="error_0342">The protocol: [#!variable!protocol!#] is invalid. Please use '--help' for more information.</key> <key name="error_0342">The protocol: [#!variable!protocol!#] is invalid. Please use '--help' for more information.</key>
<key name="error_0343">The DR host: [#!variable!host_name!#] doesn't appear to be storage group: [#!variable!storage_group!#]. Unable to proceed.</key> <key name="error_0343">The DR host: [#!variable!host_name!#] doesn't appear to be in the storage group: [#!variable!storage_group!#]. Unable to proceed.</key>
<key name="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> <key name="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>
<key name="error_0345">[ Error ] - The check appears to have failed. Expected a return code of '0', but got: [#!variable!return_code!#] <key name="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 The output, if any, was
@ -2418,7 +2418,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="message_0018">What would you like the new password to be?</key> <key name="message_0018">What would you like the new password to be?</key>
<key name="message_0019">Please enter the password again to confirm.</key> <key name="message_0019">Please enter the password again to confirm.</key>
<key name="message_0020">About to update the local passwords (shell users, database and web interface).</key> <key name="message_0020">About to update the local passwords (shell users, database and web interface).</key>
<key name="message_0021">Proceed? [y/N]</key> <!-- Default Yes is at message_0206 --> <key name="message_0021">Proceed? [y/N]</key> <!-- Default No is at message_0206 -->
<key name="message_0022">Aborting.</key> <key name="message_0022">Aborting.</key>
<key name="message_0023">Auto-approved by command line switch, proceeding.</key> <key name="message_0023">Auto-approved by command line switch, proceeding.</key>
<key name="message_0024">Updating the Striker user: [#!variable!user!#] password... </key> <key name="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
<key name="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> <key name="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>
<key name="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> <key name="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>
<key name="warning_0157">[ Warning ] - Waiting for a bit, and then will check if files are ready.</key> <key name="warning_0157">[ Warning ] - Waiting for a bit, and then will check if files are ready.</key>
<key name="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>
</language> </language>
<!-- 日本語 --> <!-- 日本語 -->

@ -2221,10 +2221,6 @@ sub process_protect
this_size => $anvil->Convert->add_commas({number => $this_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $this_size}).")", this_size => $anvil->Convert->add_commas({number => $this_size})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $this_size}).")",
}}); }});
$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})) 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->data->{server}{drbd}{$resource}{$volume}{size} = $this_size;

@ -45,15 +45,16 @@ $anvil->Log->secure({set => 1});
# Read switches (target ([user@]host[:port]) and the file with the target's password. # Read switches (target ([user@]host[:port]) and the file with the target's password.
$anvil->Get->switches({list => [ $anvil->Get->switches({list => [
"add", "add",
"anvil", "anvil",
"confirm", "confirm",
"disk", "disk",
"eject", "eject",
"grow", "grow",
"insert", "insert",
"optical", "optical",
"server", "server",
"storage-group",
], man => $THIS_FILE}); ], man => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); $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->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});
@ -202,7 +203,7 @@ sub manage_disk
} }
} }
my $drbd_resource = load_storage($anvil); my $drbd_resource = load_storage($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }});
foreach my $host_type ("node", "dr") foreach my $host_type ("node", "dr")
{ {
@ -270,194 +271,329 @@ sub manage_disk
} }
} }
my $device_target = $anvil->data->{switches}{disk}; if (($anvil->data->{switches}{grow}) or ($anvil->data->{switches}{remove}))
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device_target => $device_target }});
if ($anvil->data->{switches}{disk} eq "#!SET!#")
{ {
# User didn't specify a device. my $device_target = $anvil->data->{switches}{disk};
show_server_details($anvil); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device_target => $device_target }});
print "\n[ Error ] - Please specify the disk drive target you want to work on.\n";
$anvil->nice_exit({exit_code => 1}); if ($anvil->data->{switches}{disk} eq "#!SET!#")
{
# User didn't specify a device.
show_server_details($anvil);
print "\n[ Error ] - Please specify the disk drive target you want to work on.\n";
$anvil->nice_exit({exit_code => 1});
}
elsif (not exists $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}{$device_target})
{
# Invalid device target
show_server_details($anvil);
print "\n[ Error ] - The disk drive target: [".$device_target."] wasn't found.\n";
$anvil->nice_exit({exit_code => 1});
}
my $device = "disk";
my $alias = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{alias};
my $boot_order = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{boot_order};
my $say_boot = $boot_order eq "99" ? "--" : sprintf("%02d", $boot_order);
my $type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{type};
my $address_type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{type};
my $address_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{bus};
my $driver_name = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{name};
my $device_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{device_bus};
my $driver_type = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{type};
my $address_domain = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{domain};
my $address_slot = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{slot};
my $address_function = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{function};
my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{path};
my $driver_io = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{io};
my $driver_cache = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{cache};
my $on_lv = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv};
my $drbd_volume = $anvil->data->{lvm}{host_name}{$short_host_name}{lv_path}{$on_lv}{drbd}{volume};
my $max_free_space = $anvil->data->{server_name}{$server_name}{drbd_resource}{$drbd_resource}{volume}{$drbd_volume}{free_space};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's01:device_target' => $device_target,
's02:alias' => $alias,
's03:boot_order' => $boot_order,
's04:say_boot' => $say_boot,
's05:type' => $type,
's06:address_type' => $address_type,
's07:address_bus' => $address_bus,
's08:driver_name' => $driver_name,
's09:device_bus' => $device_bus,
's10:driver_type' => $driver_type,
's11:address_domain' => $address_domain,
's12:address_slot' => $address_slot,
's13:address_function' => $address_function,
's14:device_path' => $device_path,
's15:driver_io' => $driver_io,
's16:driver_cache' => $driver_cache,
's17:on_lv' => $on_lv,
's18:drbd_volume' => $drbd_volume,
's19:max_free_space' => $max_free_space." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}).")",
}});
#print "- Target: [".$device_target."], boot: [".$say_boot."], path: [".$device_path."], cache: [".$driver_cache."], driver type: [".$driver_type."]\n";
print "- Target: [".$device_target."], boot: [".$say_boot."], path: [".$device_path."], Available space: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space})."]\n";
# What are we doing?
if ($anvil->data->{switches}{grow})
{
manage_disk_grow($anvil, $drbd_resource, $drbd_volume, $max_free_space);
}
} }
elsif (not exists $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{disk}{target}{$device_target}) elsif ($anvil->data->{switches}{add})
{ {
# Invalid device target manage_disk_add($anvil, $drbd_resource);
show_server_details($anvil);
print "\n[ Error ] - The disk drive target: [".$device_target."] wasn't found.\n";
$anvil->nice_exit({exit_code => 1});
} }
return(0);
}
my $device = "disk"; sub manage_disk_add
my $alias = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{alias}; {
my $boot_order = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{boot_order}; my ($anvil, $drbd_resource) = @_;
my $say_boot = $boot_order eq "99" ? "--" : sprintf("%02d", $boot_order); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }});
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 $anvil_uuid = defined $anvil->data->{switches}{anvil_uuid} ? $anvil->data->{switches}{anvil_uuid} : $anvil->Cluster->get_anvil_uuid();
my $address_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{address}{bus}; my $short_host_name = $anvil->Get->short_host_name;
my $driver_name = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{driver}{name}; my $server_name = $anvil->data->{switches}{server_name};
my $device_bus = $anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{device}{$device}{target}{$device_target}{device_bus}; my $from_source = get_definition_source($anvil);
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 => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's01:device_target' => $device_target, anvil_uuid => $anvil_uuid,
's02:alias' => $alias, short_host_name => $short_host_name,
's03:boot_order' => $boot_order, server_name => $server_name,
's04:say_boot' => $say_boot, from_source => $from_source,
's05:type' => $type,
's06:address_type' => $address_type,
's07:address_bus' => $address_bus,
's08:driver_name' => $driver_name,
's09:device_bus' => $device_bus,
's10:driver_type' => $driver_type,
's11:address_domain' => $address_domain,
's12:address_slot' => $address_slot,
's13:address_function' => $address_function,
's14:device_path' => $device_path,
's15:driver_io' => $driver_io,
's16:driver_cache' => $driver_cache,
's17:on_lv' => $on_lv,
's18:drbd_volume' => $drbd_volume,
's19:max_free_space' => $max_free_space." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space}).")",
}}); }});
#print "- Target: [".$device_target."], boot: [".$say_boot."], path: [".$device_path."], cache: [".$driver_cache."], driver type: [".$driver_type."]\n";
print "- Target: [".$device_target."], boot: [".$say_boot."], path: [".$device_path."], Available space: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $max_free_space})."]\n";
=cut # Are they asking for an available amount of space?
my $volume = ""; 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'.
|;
print "Sub-Nodes:\n"; # Do we have a storage group?
foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{device}}) if (not $anvil->data->{switches}{'storage-group'})
{ {
my $on_lv = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv}; print "Please specify a storage group to use to add the new drive to.\n";
$drbd_resource = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{resource}; short_storage_groups($anvil, $anvil_uuid);
my $device_target = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{target}; $anvil->nice_exit({exit_code => 1});
}
# Make sure that the passed
my $storage_group_switch = $anvil->data->{switches}{'storage-group'};
my $storage_group_uuid = "";
my $storage_group_name = "";
if (exists $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$storage_group_switch})
{
$storage_group_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$storage_group_switch}{storage_group_uuid};
$storage_group_name = $storage_group_switch;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:device_path' => $device_path, storage_group_uuid => $storage_group_uuid,
's2:on_lv' => $on_lv, storage_group_name => $storage_group_name,
's3:drbd_resource' => $drbd_resource,
's4:device_target' => $device_target,
}}); }});
} }
foreach my $drbd_resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{drbd}{resource}}) elsif (exists $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_switch})
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }}); $storage_group_uuid = $storage_group_switch;
$storage_group_name = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_switch}{group_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
storage_group_uuid => $storage_group_uuid,
storage_group_name => $storage_group_name,
}});
} }
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}; $add_size = $bytes;
$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 }});
's1:short_host_name' => $short_host_name, }
's2:host_uuid' => $host_uuid, else
}}); {
print " |- Name: [".$short_host_name."], UUID: [".$host_uuid."]\n"; # Not a valid size.
foreach my $volume_number (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}}) print "\n[ Error ] - The requested size: [".$add_size."] could not be interpreted.\n";
{ print $error_note."\n";
my $device_path = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_path}; $anvil->nice_exit({exit_code => 1});
my $device_minor = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_minor};
my $volume_size = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{volume_size};
my $backing_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{backing_disk};
my $meta_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{meta_disk};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:volume_number' => $volume_number,
's2:device_path' => $device_path,
's3:device_minor' => $device_minor,
's4:volume_size' => $volume_size,
's5:backing_disk' => $backing_disk,
's6:meta_disk' => $meta_disk,
}});
print " ^- Volume: [".$volume_number."], backing device: [".$backing_disk."], DRBD minor: [".$device_minor."], size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $volume_size})."]\n";
}
} }
} }
=cut
# What are we doing? # Get the next free minor number
if ($anvil->data->{switches}{grow}) my ($free_minor, undef) = $anvil->DRBD->get_next_resource({
{ debug => 2,
# Are they asking for an available amount of space? minor_only => 1,
my $error_note = q| 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. [ 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 - 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 - 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'. - 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 }}); $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 $add_size = $bytes;
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 }}); $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. # Not a valid size.
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 "\n[ Error ] - The requested size: [".$add_size."] could not be interpreted.\n";
print $error_note."\n"; print $error_note."\n";
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
elsif ($add_size !~ /^\d+$/) }
{
# Size is not in bytes, try to convert it. # Make sure they're asking for a reasonable size
my $bytes = $anvil->Convert->human_readable_to_bytes({ if ($add_size < 4194304)
debug => 2, {
size => $add_size, # 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";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'bytes' => $bytes }}); print $error_note."\n";
if ($bytes =~ /^\d+$/) $anvil->nice_exit({exit_code => 1});
{ }
$add_size = $bytes; elsif ($add_size > $max_free_space)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { add_size => $add_size }}); {
} # Not enough space.
else 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";
# Not a valid size. $anvil->nice_exit({exit_code => 1});
print "\n[ Error ] - The requested size: [".$add_size."] could not be interpreted.\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);
# Make sure they're asking for a reasonable size $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
if ($add_size < 4194304)
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. my $say_access = $anvil->data->{peer}{$short_host_name}{access_ip} ? "up." : "down!";
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 " - Peer: [".$short_host_name."] is ".$say_access."\n";
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
} }
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";
if (not $anvil->data->{switches}{confirm})
{
print $anvil->Words->string({key => "message_0021"})." ";
my $answer = <STDIN>;
chomp($answer);
if ($answer !~ /^y/i)
{ {
# Not enough space. print "Aborting.\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"; $anvil->nice_exit({exit_code => 0});
print $error_note."\n";
$anvil->nice_exit({exit_code => 1});
} }
### TODO: Make this work without the peer node being online. # Test that we've lost access while waiting for the answer.
# 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); 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 }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { all_online => $all_online }});
if (not $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}}) 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!"; 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}); $anvil->nice_exit({exit_code => 1});
} }
}
# Still here? We're good to go.
my $lv_command_size = 0; foreach my $host_type ("node", "dr")
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 }}); foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
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})
{ {
print $anvil->Words->string({key => "message_0059"})." "; my $host_uuid = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
my $answer = <STDIN>; my $backing_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$drbd_volume}{backing_disk};
chomp($answer); my $shell_call = $anvil->data->{path}{exe}{lvextend}." ".$add_size." ".$backing_disk;
if ($answer !~ /^y/i) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:host_uuid' => $host_uuid,
's3:backing_disk' => $backing_disk,
's4:shell_call' => $shell_call,
}});
if ($host_uuid eq $anvil->Get->host_uuid)
{ {
print "Aborting.\n"; print " - Extending local LV: [".$backing_disk."]...";
$anvil->nice_exit({exit_code => 0}); my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
print " Error!\n";
print "[ FAILED ] - When trying to grow the local logical volume: [".$backing_disk."]\n";
print "[ FAILED ] - using the command: [".$shell_call."]\n";
print "[ FAILED ] - The return code: [".$return_code."] was received, expected '0'. Output, if any:\n";
print "==========\n";
print $output."\n";
print "==========\n";
print "The extension of the resource is incomplete, manual intervention is required!!\n";
print "[ Warning ] - Do NOT re-run this command! The backing devices may not have mis-matched sized!\n";
$anvil->nice_exit({exit_code => 1});
}
else
{
print " Done!\n";
}
} }
else
# 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 ] - It would appear that we've lost access to a peer while waiting for the answer.\n"; my $use_ip = $anvil->data->{peer}{$short_host_name}{access}{ip};
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{peer}}) my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
print " - Extending peer: [".$short_host_name.":".$backing_disk."], via: [".$use_ip." (".$use_network.")]";
my ($output, $error, $return_code) = $anvil->Remote->call({
shell_call => $shell_call,
target => $use_ip,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
return_code => $return_code,
}});
if ($return_code)
{
print " Error!\n";
print "[ FAILED ] - When trying to grow the peer's logical volume: [".$backing_disk."]\n";
print "[ FAILED ] - using the command: [".$shell_call."]\n";
print "[ FAILED ] - The return code: [".$return_code."] was received, expected '0'. Output, if any:\n";
print "==] STDOUT [========\n";
print $output."\n";
print "==] STDERR [========\n";
print $error."\n";
print "====================\n";
print "The extension of the resource is incomplete, manual intervention is required!!\n";
print "[ Warning ] - Do NOT re-run this command! The backing devices may not have mis-matched sized!\n";
$anvil->nice_exit({exit_code => 1});
}
else
{ {
my $say_access = $anvil->data->{peer}{$short_host_name}{access_ip} ? "up." : "down!"; print " Done!\n";
print " - Peer: [".$short_host_name."] is ".$say_access."\n";
} }
$anvil->nice_exit({exit_code => 1});
} }
} }
}
# Locally, we'll call DRBD to resize.
print "- Extending backing devices complete. Now extending DRBD resource/volume... ";
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." resize ".$drbd_resource."/".$drbd_volume;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
print " Error!\n";
print "[ FAILED ] - When trying to grow the DRBD device: [".$drbd_resource."/".$drbd_volume."]\n";
print "[ FAILED ] - using the command: [".$shell_call."]\n";
print "[ FAILED ] - The return code: [".$return_code."] was received, expected '0'. Output, if any:\n";
print "==========\n";
print $output."\n";
print "==========\n";
print "The extension of the resource is incomplete, manual intervention is required!!\n";
print "[ Note ] - All backing devices have been grown. Manually resolving the drbd grow\n";
print "[ Note ] - error should complete the drive expansion!\n";
$anvil->nice_exit({exit_code => 1});
}
else
{
print " Done!\n";
}
# Call scan-lvm and scan-drbd to make sure the databases are updated.
print "- Calling scancore agents to ensure the database has the new storage config recorded.\n";
foreach my $agent ("scan-drbd", "scan-lvm")
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0740", variables => { agent => $agent }});
my $shell_call = $anvil->data->{path}{directories}{scan_agents}."/".$agent."/".$agent.$anvil->Log->switches();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
foreach my $host_type ("node", "dr") foreach my $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}}) foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
{ {
my $host_uuid = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid}; my $host_uuid = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
my $backing_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$drbd_volume}{backing_disk};
my $shell_call = $anvil->data->{path}{exe}{lvextend}." ".$add_size." ".$backing_disk;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name, 's1:short_host_name' => $short_host_name,
's2:host_uuid' => $host_uuid, 's2:host_uuid' => $host_uuid,
's3:backing_disk' => $backing_disk,
's4:shell_call' => $shell_call,
}}); }});
if ($host_uuid eq $anvil->Get->host_uuid) if ($host_uuid eq $anvil->Get->host_uuid)
{ {
print " - Extending local LV: [".$backing_disk."]..."; print " - Running scan agent: [".$agent."] locally...";
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output, output => $output,
return_code => $return_code, return_code => $return_code,
}}); }});
if ($return_code) print " Done!\n";
{
print " Error!\n";
print "[ FAILED ] - When trying to grow the local logical volume: [".$backing_disk."]\n";
print "[ FAILED ] - using the command: [".$shell_call."]\n";
print "[ FAILED ] - The return code: [".$return_code."] was received, expected '0'. Output, if any:\n";
print "==========\n";
print $output."\n";
print "==========\n";
print "The extension of the resource is incomplete, manual intervention is required!!\n";
print "[ Warning ] - Do NOT re-run this command! The backing devices may not have mis-matched sized!\n";
$anvil->nice_exit({exit_code => 1});
}
else
{
print " Done!\n";
}
} }
else else
{ {
my $use_ip = $anvil->data->{peer}{$short_host_name}{access}{ip}; my $use_ip = $anvil->data->{peer}{$short_host_name}{access}{ip};
my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network}; my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
print " - Extending peer: [".$short_host_name.":".$backing_disk."], via: [".$use_ip." (".$use_network.")]"; print " - Running scan agent: [".$agent."] on: [".$short_host_name."] via: [".$use_ip." (".$use_network.")]...";
my ($output, $error, $return_code) = $anvil->Remote->call({ my ($output, $error, $return_code) = $anvil->Remote->call({
shell_call => $shell_call, shell_call => $shell_call,
target => $use_ip, target => $use_ip,
@ -564,111 +749,17 @@ sub manage_disk
error => $error, error => $error,
return_code => $return_code, return_code => $return_code,
}}); }});
if ($return_code) print " Done!\n";
{
print " Error!\n";
print "[ FAILED ] - When trying to grow the peer's logical volume: [".$backing_disk."]\n";
print "[ FAILED ] - using the command: [".$shell_call."]\n";
print "[ FAILED ] - The return code: [".$return_code."] was received, expected '0'. Output, if any:\n";
print "==] STDOUT [========\n";
print $output."\n";
print "==] STDERR [========\n";
print $error."\n";
print "====================\n";
print "The extension of the resource is incomplete, manual intervention is required!!\n";
print "[ Warning ] - Do NOT re-run this command! The backing devices may not have mis-matched sized!\n";
$anvil->nice_exit({exit_code => 1});
}
else
{
print " Done!\n";
}
}
}
}
# Locally, we'll call DRBD to resize.
print "- Extending backing devices complete. Now extending DRBD resource/volume... ";
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." resize ".$drbd_resource."/".$drbd_volume;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
if ($return_code)
{
print " Error!\n";
print "[ FAILED ] - When trying to grow the DRBD device: [".$drbd_resource."/".$drbd_volume."]\n";
print "[ FAILED ] - using the command: [".$shell_call."]\n";
print "[ FAILED ] - The return code: [".$return_code."] was received, expected '0'. Output, if any:\n";
print "==========\n";
print $output."\n";
print "==========\n";
print "The extension of the resource is incomplete, manual intervention is required!!\n";
print "[ Note ] - All backing devices have been grown. Manually resolving the drbd grow\n";
print "[ Note ] - error should complete the drive expansion!\n";
$anvil->nice_exit({exit_code => 1});
}
else
{
print " Done!\n";
}
# Call scan-lvm and scan-drbd to make sure the databases are updated.
print "- Calling scancore agents to ensure the database has the new storage config recorded.\n";
foreach my $agent ("scan-drbd", "scan-lvm")
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0740", variables => { agent => $agent }});
my $shell_call = $anvil->data->{path}{directories}{scan_agents}."/".$agent."/".$agent.$anvil->Log->switches();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
foreach my $host_type ("node", "dr")
{
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
{
my $host_uuid = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:host_uuid' => $host_uuid,
}});
if ($host_uuid eq $anvil->Get->host_uuid)
{
print " - Running scan agent: [".$agent."] locally...";
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
return_code => $return_code,
}});
print " Done!\n";
}
else
{
my $use_ip = $anvil->data->{peer}{$short_host_name}{access}{ip};
my $use_network = $anvil->data->{peer}{$short_host_name}{access}{network};
print " - Running scan agent: [".$agent."] on: [".$short_host_name."] via: [".$use_ip." (".$use_network.")]...";
my ($output, $error, $return_code) = $anvil->Remote->call({
shell_call => $shell_call,
target => $use_ip,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
return_code => $return_code,
}});
print " Done!\n";
}
} }
} }
} }
print "[ Success ] - Expansion is complete!\n";
print "[ Note ] - Depending on your OS, you may need to power the server off, and then power it back on\n";
print "[ Note ] - for the new space to be visible. Typically, powering off the server from the guest OS\n";
print "[ Note ] - and waiting for the Anvil! to boot it back up will do the job nicely.\n";
} }
print "[ Success ] - Expansion is complete!\n";
print "[ Note ] - Depending on your OS, you may need to power the server off, and then power it back on\n";
print "[ Note ] - for the new space to be visible. Typically, powering off the server from the guest OS\n";
print "[ Note ] - and waiting for the Anvil! to boot it back up will do the job nicely.\n";
return(0); return(0);
} }

@ -568,7 +568,12 @@ FROM
sub get_storage_data sub get_storage_data
{ {
my ($anvil) = @_; my ($anvil) = @_;
if (exists $anvil->data->{duplicate_check})
{
delete $anvil->data->{duplicate_check};
}
my $query = " my $query = "
SELECT SELECT
storage_group_uuid, storage_group_uuid,
@ -577,11 +582,11 @@ SELECT
FROM FROM
storage_groups storage_groups
;"; ;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }}); $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 $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results}; my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results, results => $results,
count => $count, count => $count,
}}); }});
@ -590,19 +595,95 @@ FROM
my $storage_group_uuid = $row->[0]; my $storage_group_uuid = $row->[0];
my $storage_group_anvil_uuid = $row->[1]; my $storage_group_anvil_uuid = $row->[1];
my $storage_group_name = $row->[2]; my $storage_group_name = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
storage_group_uuid => $storage_group_uuid, storage_group_uuid => $storage_group_uuid,
storage_group_anvil_uuid => $storage_group_anvil_uuid, storage_group_anvil_uuid => $storage_group_anvil_uuid,
storage_group_name => $storage_group_name, storage_group_name => $storage_group_name,
}}); }});
# Check for duplicate groups.
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.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0158", variables => {
group_name => $storage_group_name,
keep_uuid => $storage_group_uuid,
delete_uuid => $other_storage_group_uuid,
}});
my $queries = [];
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__});
}
else
{
# Delete this one.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "warning_0158", variables => {
group_name => $storage_group_name,
keep_uuid => $other_storage_group_uuid,
delete_uuid => $storage_group_uuid,
}});
my $queries = [];
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.
$anvil->data->{duplicate_check}{$storage_group_name}{storage_group_uuid} = $storage_group_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"duplicate_check::${storage_group_name}::storage_group_uuid" => $anvil->data->{duplicate_check}{$storage_group_name}{storage_group_uuid},
}});
# Store the real data
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid} = $storage_group_uuid; $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid} = $storage_group_uuid;
$anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name} = $storage_group_name; $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name} = $storage_group_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_name::${storage_group_name}::storage_group_uuid" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid}, "storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_name::${storage_group_name}::storage_group_uuid" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid},
"storage_groups::storage_group_uuid::${storage_group_uuid}::storage_group_anvil_uuid::${storage_group_anvil_uuid}::storage_group_name" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{storage_group_anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name}, "storage_groups::storage_group_uuid::${storage_group_uuid}::storage_group_anvil_uuid::${storage_group_anvil_uuid}::storage_group_name" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{storage_group_anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name},
}}); }});
} }
delete $anvil->data->{duplicate_check};
return(0); return(0);
} }

@ -27,7 +27,7 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list
our $t = Term::Cap->Tgetent; our $t = Term::Cap->Tgetent;
# One shot or continuous? # One shot or continuous?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::watch' => $anvil->data->{switches}{watch}, 'switches::watch' => $anvil->data->{switches}{watch},
}}); }});
if ($anvil->data->{switches}{watch}) if ($anvil->data->{switches}{watch})

Loading…
Cancel
Save