diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm
index b8f17509..533dfb1b 100644
--- a/Anvil/Tools.pm
+++ b/Anvil/Tools.pm
@@ -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 => {
diff --git a/Anvil/Tools/Account.pm b/Anvil/Tools/Account.pm
index 3d8a1ed4..41519144 100644
--- a/Anvil/Tools/Account.pm
+++ b/Anvil/Tools/Account.pm
@@ -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});
diff --git a/Anvil/Tools/Alert.pm b/Anvil/Tools/Alert.pm
index 158e8dd0..bb892809 100644
--- a/Anvil/Tools/Alert.pm
+++ b/Anvil/Tools/Alert.pm
@@ -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});
diff --git a/Anvil/Tools/Convert.pm b/Anvil/Tools/Convert.pm
index f1bdf484..43c4688d 100644
--- a/Anvil/Tools/Convert.pm
+++ b/Anvil/Tools/Convert.pm
@@ -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});
diff --git a/Anvil/Tools/DRBD.pm b/Anvil/Tools/DRBD.pm
index 8b0da831..806dd2b8 100755
--- a/Anvil/Tools/DRBD.pm
+++ b/Anvil/Tools/DRBD.pm
@@ -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);
diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm
index 90bb6a71..e6d11a62 100644
--- a/Anvil/Tools/Database.pm
+++ b/Anvil/Tools/Database.pm
@@ -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,
diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm
index a23dd1e3..16485238 100644
--- a/Anvil/Tools/Get.pm
+++ b/Anvil/Tools/Get.pm
@@ -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});
diff --git a/Anvil/Tools/Job.pm b/Anvil/Tools/Job.pm
index 4c96da28..021ba427 100644
--- a/Anvil/Tools/Job.pm
+++ b/Anvil/Tools/Job.pm
@@ -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});
diff --git a/Anvil/Tools/Log.pm b/Anvil/Tools/Log.pm
index cb6a3705..39d67fd8 100644
--- a/Anvil/Tools/Log.pm
+++ b/Anvil/Tools/Log.pm
@@ -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})
diff --git a/Anvil/Tools/Remote.pm b/Anvil/Tools/Remote.pm
index 72e9d0ab..1e4ccfcc 100644
--- a/Anvil/Tools/Remote.pm
+++ b/Anvil/Tools/Remote.pm
@@ -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});
diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm
index 3ffa42b1..3e51ce41 100755
--- a/Anvil/Tools/Server.pm
+++ b/Anvil/Tools/Server.pm
@@ -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".
diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm
index 8fb1adc3..853cd901 100644
--- a/Anvil/Tools/Storage.pm
+++ b/Anvil/Tools/Storage.pm
@@ -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});
diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm
index 832064ab..cfbd9a68 100644
--- a/Anvil/Tools/System.pm
+++ b/Anvil/Tools/System.pm
@@ -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 '
@@ -556,7 +767,7 @@ sub get_bridges
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->get_bridges()" }});
- my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{bridge}." -json -details link show"});
+ my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{bridge}." -json -details link show"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
diff --git a/Anvil/Tools/Template.pm b/Anvil/Tools/Template.pm
index 3e039d0d..19e709bb 100644
--- a/Anvil/Tools/Template.pm
+++ b/Anvil/Tools/Template.pm
@@ -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});
diff --git a/Anvil/Tools/Validate.pm b/Anvil/Tools/Validate.pm
index 0330c10a..0dffc9b2 100644
--- a/Anvil/Tools/Validate.pm
+++ b/Anvil/Tools/Validate.pm
@@ -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});
diff --git a/Anvil/Tools/Words.pm b/Anvil/Tools/Words.pm
index 724d4a15..e22e76f6 100644
--- a/Anvil/Tools/Words.pm
+++ b/Anvil/Tools/Words.pm
@@ -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});
diff --git a/cgi-bin/upload.pl b/cgi-bin/upload.pl
index 28c3eeec..65c7b0dd 100755
--- a/cgi-bin/upload.pl
+++ b/cgi-bin/upload.pl
@@ -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});
diff --git a/ocf/alteeve/server b/ocf/alteeve/server
index d60cde39..c38e2a23 100755
--- a/ocf/alteeve/server
+++ b/ocf/alteeve/server
@@ -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}});
-
- # Is the name in the definition file what we expect?
+ $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 (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);
diff --git a/share/words.xml b/share/words.xml
index a1e9450c..f9df9452 100644
--- a/share/words.xml
+++ b/share/words.xml
@@ -686,9 +686,9 @@ Output of: [#!variable!command!#] was;
Recording the local connection details for the resource: [#!variable!resource!#] -> [#!variable!address!#:#!variable!port!#].
Recording the peer's connection details for the resource: [#!variable!resource!#] -> [#!variable!address!#:#!variable!port!#].
Checking that the DRBD device: [#!variable!device_path!#] is ready.
- The server wants to use: [#!variable!device_path!#] as a hard drive, but we couldn't find the backing logical volume on this node.
- 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.
- 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.
+ 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.
+ 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.
+ 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.
The attempt to read the DRBD status returned a non-zero code: [#!variable!return_code!#]. The returned output (if any) was: [#!variable!status_json!#].
The DRBD resource for this server is not running yet.
Bringing up the resource: [#!variable!resource!#] for the server's: [#!variable!device_path!#] disk.
@@ -730,6 +730,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a
====
The server: [#!variable!server!#] is already on this node in the state: [#!variable!state!#], aborting the migration request.
+ The logical volume: [#!variable!lv_path!#] is inactive. Attempting to activate it now.
Test
@@ -1014,6 +1015,7 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp
The download job with UUID: [#!variable!job_uuid!#] is not valid.
The download job with UUID: [#!variable!job_uuid!#] is already being handled by another process.
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?
+ A request to active the logical volume: [#!variable!path!#] was made, but that path doesn't exist or isn't a block device.
Yes
diff --git a/tools/anvil-download-file b/tools/anvil-download-file
index 187cb61b..a0c38b8f 100755
--- a/tools/anvil-download-file
+++ b/tools/anvil-download-file
@@ -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
diff --git a/tools/fence_pacemaker b/tools/fence_pacemaker
index af70c447..8040fe5a 100755
--- a/tools/fence_pacemaker
+++ b/tools/fence_pacemaker
@@ -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