* Updated DRBD->get_devices() to properly identify the peer node, when run on an actual node in the cluster (not DR or Striker).

* Created System->active_lv() that, surprise, activates an inactive logical volume. Also created ->check_storage() that parses out the LVM data.
* Fixed a bug in tools/fence_pacemaker that was preventing it from compiling and running.
* Updated ocf:alteeve:server to validate the target server's storage.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent 16f79ca244
commit 324ef351fe
  1. 7
      Anvil/Tools.pm
  2. 2
      Anvil/Tools/Account.pm
  3. 2
      Anvil/Tools/Alert.pm
  4. 2
      Anvil/Tools/Convert.pm
  5. 66
      Anvil/Tools/DRBD.pm
  6. 6
      Anvil/Tools/Database.pm
  7. 2
      Anvil/Tools/Get.pm
  8. 2
      Anvil/Tools/Job.pm
  9. 4
      Anvil/Tools/Log.pm
  10. 2
      Anvil/Tools/Remote.pm
  11. 21
      Anvil/Tools/Server.pm
  12. 2
      Anvil/Tools/Storage.pm
  13. 215
      Anvil/Tools/System.pm
  14. 2
      Anvil/Tools/Template.pm
  15. 2
      Anvil/Tools/Validate.pm
  16. 2
      Anvil/Tools/Words.pm
  17. 4
      cgi-bin/upload.pl
  18. 118
      ocf/alteeve/server
  19. 8
      share/words.xml
  20. 2
      tools/anvil-download-file
  21. 2
      tools/fence_pacemaker

@ -1041,6 +1041,9 @@ sub _set_paths
'iptables-save' => "/usr/sbin/iptables-save",
journalctl => "/usr/bin/journalctl",
logger => "/usr/bin/logger",
lvchange => "/usr/sbin/lvchange",
lvs => "/usr/sbin/lvs",
lvscan => "/usr/sbin/lvscan",
md5sum => "/usr/bin/md5sum",
'mkdir' => "/usr/bin/mkdir",
mv => "/usr/bin/mv",
@ -1053,6 +1056,8 @@ sub _set_paths
psql => "/usr/bin/psql",
'postgresql-setup' => "/usr/bin/postgresql-setup",
pwd => "/usr/bin/pwd",
pvs => "/usr/sbin/pvs",
pvscan => "/usr/sbin/pvscan",
rpm => "/usr/bin/rpm",
rsync => "/usr/bin/rsync",
sed => "/usr/bin/sed",
@ -1076,6 +1081,8 @@ sub _set_paths
usermod => "/usr/sbin/usermod",
uuidgen => "/usr/bin/uuidgen",
virsh => "/usr/bin/virsh",
vgs => "/usr/sbin/vgs",
vgscan => "/usr/sbin/vgscan",
wget => "/usr/bin/wget",
},
json => {

@ -69,7 +69,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -63,7 +63,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -69,7 +69,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -64,7 +64,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});
@ -166,8 +166,10 @@ sub get_devices
$anvil->nice_exit({exit_code => 1});
}
$anvil->data->{drbd}{'dump-xml'}{parsed} = $dump_xml;
#print Dumper $dump_xml;
$anvil->data->{drbd}{config}{'auto-promote'} = 0;
$anvil->data->{drbd}{host}{'local'} = "";
$anvil->data->{drbd}{host}{peer} = "";
foreach my $hash_ref (@{$dump_xml->{resource}})
{
@ -210,11 +212,11 @@ sub get_devices
{
### TODO: Handle external metadata
my $host = $host_href->{name};
my $local = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host }});
if (($host eq $anvil->_hostname) or ($host eq $anvil->_short_hostname))
{
$local = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'local' => $local }});
$anvil->data->{drbd}{host}{'local'} = $host;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'drbd::host::local' => $anvil->data->{drbd}{host}{'local'} }});
}
foreach my $volume_href (@{$host_href->{volume}})
{
@ -231,7 +233,7 @@ sub get_devices
"drbd::config::${this_resource}::volume::${volume}::meta-disk" => $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{'meta-disk'},
"drbd::config::${this_resource}::volume::${volume}::backing_lv" => $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{backing_lv},
}});
if ($local)
if (($anvil->data->{drbd}{host}{'local'}) && ($anvil->data->{drbd}{host}{'local'} eq $host))
{
$anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{on} = $lv_path;
$anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{resource} = $this_resource;
@ -244,6 +246,58 @@ sub get_devices
}
}
}
### NOTE: Connections are listed as 'host A <-> Host B (options), 'host A <-> Host C
### (options) and 'host B <-> Host C (options)'. So first we see which entry has
### fencing, and ignore the others. The one with real fencing, we figure out which is
### us (if any) and the other has to be the peer.
# Find my peer, if I am myself a node.
if (($anvil->data->{drbd}{host}{'local'}) && (not $anvil->data->{drbd}{host}{peer}))
{
#print Dumper $hash_ref->{connection};
foreach my $hash_ref (@{$hash_ref->{connection}})
{
# Look in 'section' for fencing data.
my $fencing = "";
my $protocol = "";
#print Dumper $hash_ref;
foreach my $section_ref (@{$hash_ref->{section}})
{
next if $section_ref->{name} ne "net";
foreach my $option_ref (@{$section_ref->{option}})
{
if ($option_ref->{name} eq "fencing")
{
$fencing = $option_ref->{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { fencing => $fencing }});
}
elsif ($option_ref->{name} eq "protocol")
{
$protocol = $option_ref->{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { protocol => $protocol }});
}
}
}
# If the protocol is 'resource-and-stonith', we care. Otherwise it's a
# connection involving DR and we don't.
next if $fencing ne "resource-and-stonith";
# If we're still alive, this should be our connection to our peer.
foreach my $host_ref (@{$hash_ref->{host}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'drbd::host::local' => $anvil->data->{drbd}{host}{'local'},
'host_ref->name' => $host_ref->{name},
}});
next if $host_ref->{name} eq $anvil->data->{drbd}{host}{'local'};
# Found the peer.
$anvil->data->{drbd}{host}{peer} = $host_ref->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'drbd::host::peer' => $anvil->data->{drbd}{host}{peer} }});
}
}
}
}
return(0);

@ -101,7 +101,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});
@ -6789,7 +6789,7 @@ ORDER BY
"sys::database::table::${table}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{last_updated},
"sys::database::table::${table}::uuid::${uuid}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{uuid}{$uuid}{last_updated},
}});
my $difference = $anvil->Convert->add_commas({number => ($anvil->data->{sys}{database}{table}{$table}{last_updated} - $anvil->data->{sys}{database}{table}{$table}{uuid}{$uuid}{last_updated}) });;
my $difference = $anvil->Convert->add_commas({number => ($anvil->data->{sys}{database}{table}{$table}{last_updated} - $anvil->data->{sys}{database}{table}{$table}{uuid}{$uuid}{last_updated}) });
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0106", variables => {
seconds => $difference,
table => $table,
@ -6808,7 +6808,7 @@ ORDER BY
"sys::database::table::${table}::row_count" => $anvil->data->{sys}{database}{table}{$table}{row_count},
"sys::database::table::${table}::uuid::${uuid}::row_count" => $anvil->data->{sys}{database}{table}{$table}{uuid}{$uuid}{row_count},
}});
my $difference = $anvil->Convert->add_commas({number => ($anvil->data->{sys}{database}{table}{$table}{row_count} - $anvil->data->{sys}{database}{table}{$table}{uuid}{$uuid}{row_count}) });;
my $difference = $anvil->Convert->add_commas({number => ($anvil->data->{sys}{database}{table}{$table}{row_count} - $anvil->data->{sys}{database}{table}{$table}{uuid}{$uuid}{row_count}) });
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0219", variables => {
missing => $difference,
table => $table,

@ -81,7 +81,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -69,7 +69,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -75,7 +75,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});
@ -691,7 +691,7 @@ sub variables
}
my $raw = "";
# NOTE: If you change this, be sure to update Tools.t
if ($entries <= 4)
if ($entries <= 3)
{
# Put all the entries on one line.
foreach my $key (sort {$a cmp $b} keys %{$list})

@ -70,7 +70,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -63,7 +63,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});
@ -208,7 +208,12 @@ sub get_status
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::disk::xml" => $anvil->data->{server}{$server}{disk}{xml},
}});
if ($anvil->data->{server}{$server}{from_disk}{xml})
if (($anvil->data->{server}{$server}{from_disk}{xml} eq "!!errer!!") or (not $anvil->data->{server}{$server}{from_disk}{xml}))
{
# Failed to read it.
$anvil->data->{server}{$server}{from_disk}{xml} = "";
}
else
{
$anvil->Server->_parse_definition({
debug => $debug,
@ -655,13 +660,13 @@ sub _parse_definition
"server::${server}::${source}::device::${device}::target::${device_target}::driver::cache" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{cache},
}});
$anvil->data->{server}{$server}{$source}{device}{$device_path}{on_lv} = defined $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{on} : "";
$anvil->data->{server}{$server}{$source}{device}{$device_path}{resource} = defined $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{resource} : "";
$anvil->data->{server}{$server}{$source}{device}{$device_path}{target} = $device_target;
$anvil->data->{server}{$server}{device}{$device_path}{on_lv} = defined $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{on} : "";
$anvil->data->{server}{$server}{device}{$device_path}{resource} = defined $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{resource} : "";
$anvil->data->{server}{$server}{device}{$device_path}{target} = $device_target;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::${device_path}::on_lv" => $anvil->data->{server}{$server}{$source}{device}{$device_path}{on_lv},
"server::${server}::${source}::device::${device_path}::resource" => $anvil->data->{server}{$server}{$source}{device}{$device_path}{resource},
"server::${server}::${source}::device::${device_path}::target" => $anvil->data->{server}{$server}{$source}{device}{$device_path}{target},
"server::${server}::device::${device_path}::on_lv" => $anvil->data->{server}{$server}{device}{$device_path}{on_lv},
"server::${server}::device::${device_path}::resource" => $anvil->data->{server}{$server}{device}{$device_path}{resource},
"server::${server}::device::${device_path}::target" => $anvil->data->{server}{$server}{device}{$device_path}{target},
}});
### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots".

@ -86,7 +86,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -15,11 +15,13 @@ our $VERSION = "3.0.0";
my $THIS_FILE = "System.pm";
### Methods;
# activate_lv
# call
# change_shell_user_password
# check_daemon
# check_if_configured
# check_memory
# check_storage
# get_bridges
# get_free_memory
# get_host_type
@ -93,7 +95,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});
@ -104,6 +106,61 @@ sub parent
# Public methods #
#############################################################################################################
=head2 activate_lv
This takes a logical volume path and tries to activate it. If it is successfully activated, C<< 1 >> is returned. If the activation fails for any reason, C<< 0 >> is returned.
my $activated = $anvil->System->activate_lv({path => "/dev/foo/bar"});
Parameters;
=head3 path (required)
This is the full path to the logical volume to activate.
=cut
sub activate_lv
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->call()" }});
my $path = defined $parameter->{path} ? $parameter->{path} : "";
my $activated = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => {
path => $path,
}});
if (not $path)
{
# Woops!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Systeme->activate_lv()", parameter => "path" }});
return($activated);
}
if ((not -e $path) or (not -b $path))
{
# Bad path
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0064", variables => { path => $path }});
}
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{lvchange}." --activate y ".$path});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => {
output => $output,
return_code => $return_code,
}});
# A non-zero return code indicates failure, but we'll check directly.
$anvil->System->check_storage({debug => $debug, scan => 2});
# Check if it worked.
$activated = $anvil->data->{lvm}{'local'}{lv}{$path}{active};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => { activated => $activated }});
return($activated);
}
=head2 call
This method makes a system call and returns the output (with the last new-line removed) and the return code. If there is a problem, 'C<< #!error!# >>' is returned and the error will be logged.
@ -543,7 +600,161 @@ sub check_memory
return($used_ram);
}
=hed2 get_bridges
=head2 check_storage
Thic gathers LVM data from the local system.
Parameters;
=head4 scan (optional, default '1')
Setting this to C<< 0 >> will disable scanning prior to data collection. When enabled, C<< pvscan; vgscan; lvscan >> are called before the C<< pvs >>, C<< vgs >> and C<< lvs >> calls used to collect the data this parses.
=cut
sub check_storage
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->check_storage()" }});
my $scan = defined $parameter->{scan} ? $parameter->{scan} : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { scan => $scan }});
# Do a scan, if requested.
if ($scan)
{
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pvscan}." && ".$anvil->data->{path}{exe}{vgscan}." && ".$anvil->data->{path}{exe}{lvscan}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
}
# Gather PV data.
my ($pvs_output, $pvs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pvs}." --units b --noheadings --separator \\\#\\\!\\\# -o pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pv_used,pv_uuid"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
pvs_output => $pvs_output,
pvs_return_code => $pvs_return_code,
}});
foreach my $line (split/\n/, $pvs_output)
{
$line = $anvil->Words->clean_spaces({string => $line});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
my ($this_pv, $used_by_vg, $format, $attributes, $total_size, $free_size, $used_size, $uuid) = (split /#!#/, $line);
$total_size =~ s/B$//;
$free_size =~ s/B$//;
$used_size =~ s/B$//;
$anvil->data->{lvm}{'local'}{pv}{$this_pv}{used_by_vg} = $used_by_vg;
$anvil->data->{lvm}{'local'}{pv}{$this_pv}{attributes} = $attributes;
$anvil->data->{lvm}{'local'}{pv}{$this_pv}{total_size} = $total_size;
$anvil->data->{lvm}{'local'}{pv}{$this_pv}{free_size} = $free_size;
$anvil->data->{lvm}{'local'}{pv}{$this_pv}{used_size} = $used_size;
$anvil->data->{lvm}{'local'}{pv}{$this_pv}{uuid} = $uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"lvm::local::pv::${this_pv}::used_by_vg" => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{used_by_vg},
"lvm::local::pv::${this_pv}::attributes" => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{attributes},
"lvm::local::pv::${this_pv}::total_size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{total_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{total_size}}).")",
"lvm::local::pv::${this_pv}::free_size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{free_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{free_size}}).")",
"lvm::local::pv::${this_pv}::used_size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{used_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{used_size}}).")",
"lvm::local::pv::${this_pv}::uuid" => $anvil->data->{lvm}{'local'}{pv}{$this_pv}{uuid},
}});
}
# Gather VG data.
my ($vgs_output, $vgs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{vgs}." --units b --noheadings --separator \\\#\\\!\\\# -o vg_name,vg_attr,vg_extent_size,vg_extent_count,vg_uuid,vg_size,vg_free_count,vg_free,pv_name"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
vgs_output => $vgs_output,
vgs_return_code => $vgs_return_code,
}});
foreach my $line (split/\n/, $vgs_output)
{
$line = $anvil->Words->clean_spaces({string => $line});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
my ($this_vg, $attributes, $pe_size, $total_pe, $uuid, $vg_size, $free_pe, $vg_free, $pv_name) = split /#!#/, $line;
$pe_size = "" if not defined $pe_size;
$vg_size = "" if not defined $vg_size;
$vg_free = "" if not defined $vg_free;
$attributes = "" if not defined $attributes;
$pe_size =~ s/B$//;
$vg_size =~ s/B$//;
$vg_free =~ s/B$//;
my $used_pe = 0;
if (($total_pe) && ($free_pe))
{
$used_pe = $total_pe - $free_pe;
}
my $used_space = 0;
if (($vg_size) && ($vg_free))
{
$used_space = $vg_size - $vg_free;
}
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{pe_size} = $pe_size;
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{total_pe} = $total_pe;
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{uuid} = $uuid;
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{size} = $vg_size;
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{used_pe} = $used_pe;
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{used_space} = $used_space;
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{free_pe} = $free_pe;
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{free_space} = $vg_free;
$anvil->data->{lvm}{'local'}{vg}{$this_vg}{pv_name} = $pv_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"lvm::local::vg::${this_vg}::pe_size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{pe_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{pe_size}}).")",
"lvm::local::vg::${this_vg}::total_pe" => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{total_pe},
"lvm::local::vg::${this_vg}::uuid" => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{uuid},
"lvm::local::vg::${this_vg}::size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{size}}).")",
"lvm::local::vg::${this_vg}::used_pe" => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{used_pe},
"lvm::local::vg::${this_vg}::used_space" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{used_space}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{used_space}}).")",
"lvm::local::vg::${this_vg}::free_pe" => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{free_pe},
"lvm::local::vg::${this_vg}::free_space" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{free_space}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{free_space}}).")",
"lvm::local::vg::${this_vg}::pv_name" => $anvil->data->{lvm}{'local'}{vg}{$this_vg}{pv_name},
}});
}
# And finally, the LV data.
my ($lvs_output, $lvs_return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{lvs}." --units b --noheadings --separator \\\#\\\!\\\# -o lv_name,vg_name,lv_attr,lv_size,lv_uuid,lv_path,devices"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
lvs_output => $lvs_output,
lvs_return_code => $lvs_return_code,
}});
foreach my $line (split/\n/, $lvs_output)
{
$line = $anvil->Words->clean_spaces({string => $line});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
my ($lv_name, $on_vg, $attributes, $total_size, $uuid, $path, $devices) = (split /#!#/, $line);
$total_size =~ s/B$//;
$devices =~ s/\(\d+\)//g; # Strip the starting PE number
$anvil->data->{lvm}{'local'}{lv}{$path}{name} = $lv_name;
$anvil->data->{lvm}{'local'}{lv}{$path}{on_vg} = $on_vg;
$anvil->data->{lvm}{'local'}{lv}{$path}{active} = ($attributes =~ /.{4}(.{1})/)[0] eq "a" ? 1 : 0;
$anvil->data->{lvm}{'local'}{lv}{$path}{attributes} = $attributes;
$anvil->data->{lvm}{'local'}{lv}{$path}{total_size} = $total_size;
$anvil->data->{lvm}{'local'}{lv}{$path}{uuid} = $uuid;
$anvil->data->{lvm}{'local'}{lv}{$path}{on_devices} = $devices;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"lvm::local::lv::${path}::name" => $anvil->data->{lvm}{'local'}{lv}{$path}{name},
"lvm::local::lv::${path}::on_vg" => $anvil->data->{lvm}{'local'}{lv}{$path}{on_vg},
"lvm::local::lv::${path}::active" => $anvil->data->{lvm}{'local'}{lv}{$path}{active},
"lvm::local::lv::${path}::attributes" => $anvil->data->{lvm}{'local'}{lv}{$path}{attributes},
"lvm::local::lv::${path}::total_size" => $anvil->Convert->add_commas({number => $anvil->data->{lvm}{'local'}{lv}{$path}{total_size}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{lvm}{'local'}{lv}{$path}{total_size}}).")",
"lvm::local::lv::${path}::uuid" => $anvil->data->{lvm}{'local'}{lv}{$path}{uuid},
"lvm::local::lv::${path}::on_devices" => $anvil->data->{lvm}{'local'}{lv}{$path}{on_devices},
}});
}
return(0);
}
=head2 get_bridges
This finds a list of bridges on the host. Bridges that are found are stored is '

@ -69,7 +69,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -73,7 +73,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -79,7 +79,7 @@ sub parent
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});

@ -63,8 +63,8 @@ if ($cgi->param())
### NOTE: The timing is a guide only. The AJAX does a lot of work before this script is invoked. It
### might be better to just remove the timing stuff entirely...
my $size = (stat($out_file))[7];
my $say_size_human = $anvil->Convert->add_commas({number => $size});
my $say_size_comma = $anvil->Convert->bytes_to_human_readable({'bytes' => $size});
my $say_size_human = $anvil->Convert->bytes_to_human_readable({'bytes' => $size});
my $say_size_comma = $anvil->Convert->add_commas({number => $size});
my $took = time - $start;
$took = 1 if not $took;
my $say_took = $anvil->Convert->add_commas({number => $took});

@ -391,9 +391,10 @@ sub validate_all
### if the server is running elsewhere.
# Read in an parse the server's XML.
$anvil->Server->get_status({debug => 2, server => $anvil->data->{environment}{OCF_RESKEY_name}});
$anvil->System->check_storage({debug => 3});
$anvil->Server->get_status({debug => 3, server => $anvil->data->{environment}{OCF_RESKEY_name}});
# Is the name in the definition file what we expect?
# Is the name in the definition file what we expect (and did we read the XML data at all)?
validate_name($anvil);
# Make sure the emulator it wants is the one we have.
@ -409,8 +410,8 @@ sub validate_all
# Validate bridges
validate_bridges($anvil);
# Which DRBD resources do I need?
# Validate storage (Disks and optical media)
validate_storage($anvil);
return(0);
}
@ -463,7 +464,54 @@ sub validate_storage
{
my ($anvil) = @_;
### TODO: When checking on a running server, use 'from_memory'.
my $server = $anvil->data->{environment}{OCF_RESKEY_name};
my $source = "from_disk";
if (exists $anvil->data->{server}{$server}{from_memory})
{
$source = "from_memory";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server => $server,
source => $source,
}});
### TODO: If we're called with a status and find an ISO file missing and eject it instead of failing.
### For now, we just fault out.
# Do the optical discs in the drive exist? If not, we'll eject it if we're about to boot and fail if
# we're about to migrate. We skip this check if we're migrating off or shutting down the server.
if ((exists $anvil->data->{server}{$server}{$source}{device}{cdrom}) && (not $anvil->data->{switches}{migrate_to}) && (not $anvil->data->{switches}{stop}))
{
foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{$source}{device}{cdrom}{target}})
{
if ($anvil->data->{server}{$server}{$source}{device}{cdrom}{target}{$device_target}{path})
{
my $file = $anvil->data->{server}{$server}{$source}{device}{cdrom}{target}{$device_target}{path};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }});
if (not -e $file)
{
# It doesn't exist. Exit with OCF_ERR_INSTALLED (5).
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0398", variables => { file => $file }});
$anvil->nice_exit({exit_code => 5});
}
elsif (not -r $file)
{
# We can't read it. Exit with OCF_ERR_PERM (4).
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0399", variables => { file => $file }});
$anvil->nice_exit({exit_code => 4});
}
else
{
# We're OK.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 2, key => "log_0400", variables => { file => $file }});
}
}
}
}
# Verify DRBD devices now
validate_storage_drbd($anvil);
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0367"});
return(0);
}
@ -474,7 +522,54 @@ sub validate_storage_drbd
{
my ($anvil) = @_;
# Now check storage.
my $server = $anvil->data->{environment}{OCF_RESKEY_name};
my $source = "from_disk";
foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{$source}{device}{disk}{target}})
{
my $drbd_device = $anvil->data->{server}{$server}{$source}{device}{disk}{target}{$device_target}{path};
my $drbd_resource = $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_device}{resource};
my $on_lv = $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_device}{on};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
drbd_device => $drbd_device,
drbd_resource => $drbd_resource,
on_lv => $on_lv,
}});
# If the logical volume here here and active?
if ((not $on_lv) or (not exists $anvil->data->{lvm}{'local'}{lv}{$on_lv}))
{
# LV not found
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 0, priority => "err", key => "log_0374", variables => { drbd_device => $drbd_device, lv_path => $on_lv }});
$anvil->nice_exit({exit_code => 5});
}
elsif (not $anvil->data->{lvm}{'local'}{lv}{$on_lv}{active})
{
# LV not active. If we're starting the server or we're the migration target, try to
# activate it.
my $active = $anvil->System->activate_lv({debug => 2, path => $on_lv});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { active => $active }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 1, key => "log_0413", variables => { lv_path => $on_lv }});
if (not $active)
{
# Boo :(
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 0, priority => "err", key => "log_0375", variables => { drbd_device => $drbd_device, lv_path => $on_lv }});
$anvil->nice_exit({exit_code => 5});
}
}
# LV is good if I am still alive.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 1, key => "log_0376", variables => {
drbd_device => $drbd_device,
lv_path => $on_lv,
}});
}
print "I am: [".$anvil->data->{drbd}{host}{'local'}."]. my peer is: [".$anvil->data->{drbd}{host}{peer}."]\n";
die;
return(0);
}
@ -536,13 +631,14 @@ sub validate_name
{
my ($anvil) = @_;
# Is the name in the definition file what we expect?
my $server = $anvil->data->{environment}{OCF_RESKEY_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server => $server,
"server::${server}::from_disk::info::name" => $anvil->data->{server}{$server}{from_disk}{info}{name},
}});
if ($server ne $anvil->data->{server}{$server}{from_disk}{info}{name})
# If we failed to read the XML, the server probably doesn't exist.
if (not $anvil->data->{server}{$server}{from_disk}{xml})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0403", variables => {
server => $server,
@ -550,6 +646,16 @@ sub validate_name
}});
$anvil->nice_exit({exit_code => 1});
}
# Is the name in the definition file what we expect?
if ($server ne $anvil->data->{server}{$server}{from_disk}{info}{name})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0403", variables => {
server => $server,
name => $anvil->data->{server}{$server}{from_disk}{info}{name},
}});
$anvil->nice_exit({exit_code => 1});
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0363"});
return(0);

@ -686,9 +686,9 @@ Output of: [#!variable!command!#] was;
<key name="log_0371">Recording the local connection details for the resource: [#!variable!resource!#] -> [#!variable!address!#:#!variable!port!#].</key>
<key name="log_0372">Recording the peer's connection details for the resource: [#!variable!resource!#] -> [#!variable!address!#:#!variable!port!#].</key>
<key name="log_0373">Checking that the DRBD device: [#!variable!device_path!#] is ready.</key>
<key name="log_0374">The server wants to use: [#!variable!device_path!#] as a hard drive, but we couldn't find the backing logical volume on this node.</key>
<key name="log_0375">The server wants to use: [#!variable!device_path!#] as a hard drive, but the backing logical volume: [#!variable!lv!#] doesn't exist on this node.</key>
<key name="log_0376">The server wants to use: [#!variable!device_path!#] as a hard drive, which is backed by the logical volume: [#!variable!lv!#]. Will check that is is ready.</key>
<key name="log_0374">The server wants to use: [#!variable!drbd_device!#] as a hard drive, but we couldn't find the backing logical volume: [#!variable!lv_path!#] on this node.</key>
<key name="log_0375">The server wants to use: [#!variable!drbd_device!#] as a hard drive, but the backing logical volume: [#!variable!lv_path!#] is inactive and an attempt to activate it failed.</key>
<key name="log_0376">The server wants to use: [#!variable!drbd_device!#] as a hard drive, which is backed by the logical volume: [#!variable!lv_path!#]. It is ready to use.</key>
<key name="log_0377">The attempt to read the DRBD status returned a non-zero code: [#!variable!return_code!#]. The returned output (if any) was: [#!variable!status_json!#].</key>
<key name="log_0378">The DRBD resource for this server is not running yet.</key>
<key name="log_0379">Bringing up the resource: [#!variable!resource!#] for the server's: [#!variable!device_path!#] disk.</key>
@ -730,6 +730,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a
====
</key>
<key name="log_0412">The server: [#!variable!server!#] is already on this node in the state: [#!variable!state!#], aborting the migration request.</key>
<key name="log_0413">The logical volume: [#!variable!lv_path!#] is inactive. Attempting to activate it now.</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>
@ -1014,6 +1015,7 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp
<key name="error_0061">The download job with UUID: [#!variable!job_uuid!#] is not valid.</key>
<key name="error_0062">The download job with UUID: [#!variable!job_uuid!#] is already being handled by another process.</key>
<key name="error_0063">Something went wrong trying to download: [#!variable!packages!#]. The return code should have been '0'. but: [#!variable!return_code!#] was received. Is a package missing upstream?</key>
<key name="error_0064">A request to active the logical volume: [#!variable!path!#] was made, but that path doesn't exist or isn't a block device.</key>
<!-- These are units, words and so on used when displaying information. -->
<key name="unit_0001">Yes</key>

@ -282,7 +282,7 @@ sub download_file
while(<$file_handle>)
{
chomp;
my $line = $anvil->Words->clean_spaces({string => $_});;
my $line = $anvil->Words->clean_spaces({string => $_});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0017", variables => { line => $line }});
# Check for problems

@ -556,7 +556,7 @@ sub kill_target
my $start_time = time;
my $end_time = $start_time + 300;
my $fenced = 0;
to_log($conf, {message => "start_time: [$start_time], end_time: [$return_code]", 'line' => __LINE__, level => 2});
to_log($conf, {message => "start_time: [$start_time], end_time: [$end_time]", 'line' => __LINE__, level => 2});
until ($fenced)
{
# This will exit

Loading…
Cancel
Save