* Got ocf:alteeve:server working again to boot servers. It's now smarter, knowing when the server is running locally already (success), running on the other node (hard error) and running on DR (fatal error).

* Updated DRBD->get_devices() to store data all under 'drbd::config::<host>::x'.
* Created Server->find() that takes a target and collects the servers running on it.
* Updated System->check_storage() to redirect all calls STDERR to /dev/null to supress errors about failing to open /dev/drbdX when LVM's filter isn't setup.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent 324ef351fe
commit b1ddf945e2
  1. 115
      Anvil/Tools/DRBD.pm
  2. 149
      Anvil/Tools/Server.pm
  3. 42
      Anvil/Tools/System.pm
  4. 110
      ocf/alteeve/server
  5. 5
      share/words.xml

@ -78,7 +78,6 @@ sub parent
This finds all of the configured '/dev/drbdX' devices and maps them to their resource names.
Parameters;
=head3 password (optional)
@ -116,13 +115,8 @@ sub get_devices
target => $target,
}});
# Clear the hash where we'll store the data.
if (exists $anvil->data->{drbd}{'dump-xml'})
{
delete $anvil->data->{drbd}{'dump-xml'};
}
# Is this a local call or a remote call?
my $host = $anvil->_short_hostname;
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." dump-xml";
my $output = "";
if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname))
@ -136,7 +130,9 @@ sub get_devices
password => $password,
remote_user => $remote_user,
});
$host = $target;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host => $host,
error => $error,
output => $output,
"drbd::drbdadm-xml::return_code" => $anvil->data->{drbd}{'drbdadm-xml'}{return_code},
@ -152,6 +148,12 @@ sub get_devices
}});
}
# Clear the hash where we'll store the data.
if (exists $anvil->data->{drbd}{config}{$host})
{
delete $anvil->data->{drbd}{config}{$host};
}
my $xml = XML::Simple->new();
my $dump_xml = "";
eval { $dump_xml = $xml->XMLin($output, KeyAttr => {}, ForceArray => 1) };
@ -167,9 +169,10 @@ sub get_devices
}
#print Dumper $dump_xml;
$anvil->data->{drbd}{config}{'auto-promote'} = 0;
$anvil->data->{drbd}{host}{'local'} = "";
$anvil->data->{drbd}{host}{peer} = "";
$anvil->data->{drbd}{config}{$host}{'auto-promote'} = 0;
$anvil->data->{drbd}{config}{$host}{host} = "";
$anvil->data->{drbd}{config}{$host}{peer} = "";
$anvil->data->{drbd}{config}{$host}{nodes} = {};
foreach my $hash_ref (@{$dump_xml->{resource}})
{
@ -178,20 +181,20 @@ sub get_devices
{
foreach my $host_href (@{$connection_href->{host}})
{
my $host = $host_href->{name};
my $port = $host_href->{address}->[0]->{port};
my $ip_address = $host_href->{address}->[0]->{content};
$anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{ip_family} = $host_href->{address}->[0]->{family};
$anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{ip_address} = $host_href->{address}->[0]->{content};
$anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{port} = $port;
$anvil->data->{drbd}{ip_addresses}{$ip_address} = 1;
$anvil->data->{drbd}{tcp_ports}{$port} = 1;
my $this_host = $host_href->{name};
my $port = $host_href->{address}->[0]->{port};
my $ip_address = $host_href->{address}->[0]->{content};
$anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{ip_family} = $host_href->{address}->[0]->{family};
$anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{ip_address} = $host_href->{address}->[0]->{content};
$anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{port} = $port;
$anvil->data->{drbd}{config}{$host}{ip_addresses}{$ip_address} = $this_host;
$anvil->data->{drbd}{config}{$host}{tcp_ports}{$port} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"drbd::config::${this_resource}::connection::${host}::ip_family" => $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{ip_family},
"drbd::config::${this_resource}::connection::${host}::ip_address" => $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{ip_address},
"drbd::config::${this_resource}::connection::${host}::port" => $anvil->data->{drbd}{config}{$this_resource}{connection}{$host}{port},
"drbd::ip_addresses::${ip_address}" => $anvil->data->{drbd}{ip_addresses}{$ip_address},
"drbd::tcp_ports::${port}" => $anvil->data->{drbd}{tcp_ports}{$port},
"drbd::config::${host}::resource::${this_resource}::connection::${this_host}::ip_family" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{ip_family},
"drbd::config::${host}::resource::${this_resource}::connection::${this_host}::ip_address" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{ip_address},
"drbd::config::${host}::resource::${this_resource}::connection::${this_host}::port" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{connection}{$this_host}{port},
"drbd::config::${host}::ip_addresses::${ip_address}" => $anvil->data->{drbd}{config}{$host}{ip_addresses}{$ip_address},
"drbd::config::${host}::tcp_ports::${port}" => $anvil->data->{drbd}{config}{$host}{tcp_ports}{$port},
}});
}
foreach my $section_href (@{$connection_href->{section}})
@ -200,9 +203,9 @@ sub get_devices
foreach my $option_href (@{$section_href->{option}})
{
my $variable = $option_href->{name};
$anvil->data->{drbd}{config}{$this_resource}{section}{$section}{$variable} = $option_href->{value};
$anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{section}{$section}{$variable} = $option_href->{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"drbd::config::${this_resource}::section::${section}::${variable}" => $anvil->data->{drbd}{config}{$this_resource}{section}{$section}{$variable},
"drbd::config::${host}::resource::${this_resource}::section::${section}::${variable}" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{section}{$section}{$variable},
}});
}
}
@ -211,37 +214,41 @@ sub get_devices
foreach my $host_href (@{$hash_ref->{host}})
{
### TODO: Handle external metadata
my $host = $host_href->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host }});
if (($host eq $anvil->_hostname) or ($host eq $anvil->_short_hostname))
my $this_host = $host_href->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
this_host => $this_host,
'$anvil->_hostname' => $anvil->_hostname,
'$anvil->_short_hostname' => $anvil->_short_hostname,
}});
if (($this_host eq $anvil->_hostname) or ($this_host eq $anvil->_short_hostname))
{
$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'} }});
$anvil->data->{drbd}{config}{$host}{host} = $this_host;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "drbd::config::${host}::host" => $anvil->data->{drbd}{config}{$host}{host} }});
}
foreach my $volume_href (@{$host_href->{volume}})
{
my $volume = $volume_href->{vnr};
my $drbd_path = $volume_href->{device}->[0]->{content};
my $lv_path = $volume_href->{disk}->[0];
$anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{drbd_path} = $drbd_path;
$anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{drbd_minor} = $volume_href->{device}->[0]->{minor};
$anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{'meta-disk'} = $volume_href->{'meta-disk'}->[0];
$anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{backing_lv} = $lv_path;
my $volume = $volume_href->{vnr};
my $drbd_path = $volume_href->{device}->[0]->{content};
my $lv_path = $volume_href->{disk}->[0];
$anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path} = $drbd_path;
$anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_minor} = $volume_href->{device}->[0]->{minor};
$anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{'meta-disk'} = $volume_href->{'meta-disk'}->[0];
$anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{backing_lv} = $lv_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"drbd::config::${this_resource}::volume::${volume}::drbd_path" => $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{drbd_path},
"drbd::config::${this_resource}::volume::${volume}::drbd_minor" => $anvil->data->{drbd}{config}{$this_resource}{volume}{$volume}{drbd_minor},
"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},
"drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_path" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_path},
"drbd::config::${host}::resource::${this_resource}::volume::${volume}::drbd_minor" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{drbd_minor},
"drbd::config::${host}::resource::${this_resource}::volume::${volume}::meta-disk" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{'meta-disk'},
"drbd::config::${host}::resource::${this_resource}::volume::${volume}::backing_lv" => $anvil->data->{drbd}{config}{$host}{resource}{$this_resource}{volume}{$volume}{backing_lv},
}});
if (($anvil->data->{drbd}{host}{'local'}) && ($anvil->data->{drbd}{host}{'local'} eq $host))
if (($anvil->data->{drbd}{config}{$host}{host}) && ($anvil->data->{drbd}{config}{$host}{host} eq $this_host))
{
$anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{on} = $lv_path;
$anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{resource} = $this_resource;
$anvil->data->{drbd}{'local'}{lv_path}{$lv_path}{under} = $drbd_path;
$anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{on} = $lv_path;
$anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{resource} = $this_resource;
$anvil->data->{drbd}{config}{$host}{lv_path}{$lv_path}{under} = $drbd_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"drbd::local::drbd_path::${drbd_path}::on" => $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{on},
"drbd::local::drbd_path::${drbd_path}::resource" => $anvil->data->{drbd}{'local'}{drbd_path}{$drbd_path}{resource},
"drbd::local::lv_path::${lv_path}::under" => $anvil->data->{drbd}{'local'}{lv_path}{$lv_path}{under},
"drbd::config::${host}::drbd_path::${drbd_path}::on" => $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{on},
"drbd::config::${host}::drbd_path::${drbd_path}::resource" => $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{resource},
"drbd::config::${host}::lv_path::${lv_path}::under" => $anvil->data->{drbd}{config}{$host}{lv_path}{$lv_path}{under},
}});
}
}
@ -252,7 +259,7 @@ sub get_devices
### 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}))
if (($anvil->data->{drbd}{config}{$host}{host}) && (not $anvil->data->{drbd}{config}{$host}{peer}))
{
#print Dumper $hash_ref->{connection};
foreach my $hash_ref (@{$hash_ref->{connection}})
@ -287,14 +294,14 @@ sub get_devices
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},
"drbd::config::${host}::host" => $anvil->data->{drbd}{config}{$host}{host},
"host_ref->name" => $host_ref->{name},
}});
next if $host_ref->{name} eq $anvil->data->{drbd}{host}{'local'};
next if $host_ref->{name} eq $anvil->data->{drbd}{config}{$host}{host};
# 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} }});
$anvil->data->{drbd}{config}{$host}{peer} = $host_ref->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "drbd::config::${host}::peer" => $anvil->data->{drbd}{config}{$host}{peer} }});
}
}
}

@ -75,13 +75,107 @@ sub parent
=head2 find
This looks on an Anvil! for what servers are running where.
This will look on the local or a remote machine for the list of servers that are running.
The list is stored as;
server::location::<server>::status = <status>
server::location::<server>::host = <hostname>
Parameters;
=head3 password (optional)
This is the password to use when connecting to a remote machine. If not set, but C<< target >> is, an attempt to connect without a password will be made.
=head3 port (optional)
This is the TCP port to use when connecting to a remote machine. If not set, but C<< target >> is, C<< 22 >> will be used.
=head3 remote_user (optional, default 'root')
If C<< target >> is set, this will be the user we connect to the remote machine as.
=head3 target (optional)
This is the IP or host name of the machine to read the version of. If this is not set, the local system's version is checked.
=cut
sub find
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $password = defined $parameter->{password} ? $parameter->{password} : "";
my $port = defined $parameter->{port} ? $parameter->{port} : "";
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $target = defined $parameter->{target} ? $parameter->{target} : "local";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
password => $anvil->Log->secure ? $password : $anvil->Words->string({key => "log_0186"}),
port => $port,
remote_user => $remote_user,
target => $target,
}});
my $host_type = $anvil->System->get_host_type({debug => $debug});
my $host = $anvil->_hostname;
my $virsh_output = "";
my $return_code = "";
if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname))
{
# Remote call.
($host, my $error, my $host_return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static",
target => $target,
remote_user => "root",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host => $host,
error => $error,
host_return_code => $host_return_code,
}});
($virsh_output, $error, $return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{virsh}." list --all",
target => $target,
remote_user => "root",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
virsh_output => $virsh_output,
error => $error,
return_code => $return_code,
}});
}
else
{
($virsh_output, my $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{virsh}." list --all"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
virsh_output => $virsh_output,
return_code => $return_code,
}});
}
foreach my $line (split/\n/, $virsh_output)
{
$line = $anvil->Words->clean_spaces({string => $line});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^\d+ (.*) (.*?)$/)
{
my $server_name = $1;
$anvil->data->{server}{location}{$server_name}{status} = $2;
$anvil->data->{server}{location}{$server_name}{host} = $host;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::location::${server_name}::status" => $anvil->data->{server}{location}{$server_name}{status},
"server::location::${server_name}::host" => $anvil->data->{server}{location}{$server_name}{host},
}});
}
}
return(0);
}
=head2 get_status
@ -146,7 +240,13 @@ sub get_status
$anvil->data->{server}{$server}{from_memory}{host} = "";
# We're going to map DRBD devices to resources, so we need to collect that data now.
$anvil->DRBD->get_devices({debug => $debug});
$anvil->DRBD->get_devices({
debug => $debug,
password => $password,
port => $port,
remote_user => $remote_user,
target => $target,
});
# Is this a local call or a remote call?
my $shell_call = $anvil->data->{path}{exe}{virsh}." dumpxml ".$server;
@ -189,6 +289,7 @@ sub get_status
$anvil->data->{server}{$server}{from_memory}{host} = $host;
$anvil->Server->_parse_definition({
debug => $debug,
host => $host,
server => $server,
source => "from_memory",
definition => $anvil->data->{server}{$server}{from_memory}{xml},
@ -206,7 +307,7 @@ sub get_status
file => $anvil->data->{path}{directories}{shared}{definitions}."/".$server.".xml",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::disk::xml" => $anvil->data->{server}{$server}{disk}{xml},
"server::${server}::from_disk::xml" => $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}))
{
@ -217,6 +318,7 @@ sub get_status
{
$anvil->Server->_parse_definition({
debug => $debug,
host => $host,
server => $server,
source => "from_disk",
definition => $anvil->data->{server}{$server}{from_disk}{xml},
@ -249,9 +351,12 @@ sub _parse_definition
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $source = defined $parameter->{source} ? $parameter->{source} : "";
my $definition = defined $parameter->{definition} ? $parameter->{definition} : "";
my $host = defined $parameter->{host} ? $parameter->{host} : $anvil->_short_hostname;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server => $server,
source => $source,
definition => $definition,
host => $host,
}});
if (not $server)
@ -408,15 +513,15 @@ sub _parse_definition
my $address_port = $hash_ref->{address}->[0]->{port};
# Store
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode} = $hash_ref->{source}->[0]->{mode};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{path} = $hash_ref->{source}->[0]->{path};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode} = defined $hash_ref->{source}->[0]->{mode} ? $hash_ref->{source}->[0]->{mode} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{path} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{controller} = $address_controller;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{port} = $address_port;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{type} = $hash_ref->{target}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'} = $hash_ref->{target}->[0]->{'state'};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'} = defined $hash_ref->{target}->[0]->{'state'} ? $hash_ref->{target}->[0]->{'state'} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{name} = $hash_ref->{target}->[0]->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::channel::unix::source::mode" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode},
@ -447,13 +552,13 @@ sub _parse_definition
my $address_port = $hash_ref->{address}->[0]->{port};
# Store
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{controller} = $address_controller;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{port} = $address_port;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{type} = $hash_ref->{target}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'} = $hash_ref->{target}->[0]->{'state'};
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'} = defined $hash_ref->{target}->[0]->{'state'} ? $hash_ref->{target}->[0]->{'state'} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{name} = $hash_ref->{target}->[0]->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::channel::spicevmc::alias" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias},
@ -479,9 +584,9 @@ sub _parse_definition
foreach my $hash_ref (@{$server_xml->{devices}->[0]->{console}})
{
$anvil->data->{server}{$server}{$source}{device}{console}{type} = $hash_ref->{type};
$anvil->data->{server}{$server}{$source}{device}{console}{tty} = $hash_ref->{tty};
$anvil->data->{server}{$server}{$source}{device}{console}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->data->{server}{$server}{$source}{device}{console}{source} = $hash_ref->{source}->[0]->{path};
$anvil->data->{server}{$server}{$source}{device}{console}{tty} = defined $hash_ref->{tty} ? $hash_ref->{tty} : "";
$anvil->data->{server}{$server}{$source}{device}{console}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->data->{server}{$server}{$source}{device}{console}{source} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : "";
$anvil->data->{server}{$server}{$source}{device}{console}{target_type} = $hash_ref->{target}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{console}{target_port} = $hash_ref->{target}->[0]->{port};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -532,7 +637,7 @@ sub _parse_definition
}
# Store the data
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::controller::${type}::index::${index}::alias" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias},
}});
@ -594,7 +699,7 @@ sub _parse_definition
#print Dumper $hash_ref;
my $device = $hash_ref->{device};
my $type = $hash_ref->{type};
my $alias = $hash_ref->{alias}->[0]->{name};
my $alias = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
my $device_target = $hash_ref->{target}->[0]->{dev};
my $device_bus = $hash_ref->{target}->[0]->{bus};
my $address_type = $hash_ref->{address}->[0]->{type};
@ -660,15 +765,23 @@ 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}{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}{on_lv} = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} : "";
$anvil->data->{server}{$server}{device}{$device_path}{resource} = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{config}{$host}{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 => {
host => $host,
"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},
}});
# Keep a list of DRBD resources used by this server.
my $drbd_resource = $anvil->data->{server}{$server}{device}{$device_path}{resource};
$anvil->data->{server}{$server}{drbd}{resource}{$drbd_resource} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::drbd::resource::${drbd_resource}" => $anvil->data->{server}{$server}{drbd}{resource}{$drbd_resource},
}});
### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots".
# $anvil->data->{server}{$server}{$source}{address}{$device_bus}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain} = $address_domain;
# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -704,8 +817,8 @@ sub _parse_definition
my $mac = $hash_ref->{mac}->[0]->{address};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{bridge} = $hash_ref->{source}->[0]->{bridge};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target} = $hash_ref->{target}->[0]->{dev};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target} = defined $hash_ref->{target}->[0]->{dev} ? $hash_ref->{target}->[0]->{dev} : "";
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{model} = $hash_ref->{model}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{bus} = $hash_ref->{address}->[0]->{bus};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{domain} = $hash_ref->{address}->[0]->{domain};

@ -625,22 +625,46 @@ sub check_storage
# 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}});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{pvscan}." 2>/dev/null"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
output => $output,
return_code => $return_code,
redirect_stderr => 0,
}});
$output = "";
$return_code = "";
($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{vgscan}." 2>/dev/null"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
redirect_stderr => 0,
}});
$output = "";
$return_code = "";
($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{lvscan}." 2>/dev/null"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
redirect_stderr => 0,
}});
}
### NOTE: In case: 'lvm.conf -> filter = [ "r|/dev/drbd.*|" ]' isn't set, we'll get warnings about
### DRBD devices being "wrong medium type" when Secondary. We check for and ignore these
### warnings.
# 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"});
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 2>/dev/null"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
pvs_output => $pvs_output,
pvs_return_code => $pvs_return_code,
redirect_stderr => 0,
}});
foreach my $line (split/\n/, $pvs_output)
{
$line = $anvil->Words->clean_spaces({string => $line});
next if $line =~ /Wrong medium type/i;
$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);
@ -665,14 +689,16 @@ sub check_storage
}
# 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"});
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 2>/dev/null"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
vgs_output => $vgs_output,
vgs_return_code => $vgs_return_code,
redirect_stderr => 0,
}});
foreach my $line (split/\n/, $vgs_output)
{
$line = $anvil->Words->clean_spaces({string => $line});
next if $line =~ /Wrong medium type/i;
$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;
@ -718,14 +744,16 @@ sub check_storage
}
# 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"});
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 2>/dev/null"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
lvs_output => $lvs_output,
lvs_return_code => $lvs_return_code,
redirect_stderr => 0,
}});
foreach my $line (split/\n/, $lvs_output)
{
$line = $anvil->Words->clean_spaces({string => $line});
next if $line =~ /Wrong medium type/i;
$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);
@ -1502,7 +1530,7 @@ sub is_local
my $is_local = 0;
if (($host eq $anvil->_hostname) or
($host eq $anvil->_short_hostname) or
($host eq "localhost") or
($host eq "localhost") or
($host eq "127.0.0.1"))
{
# It's local

@ -315,6 +315,14 @@ sub start_server
# Make sure things are sane.
validate_all($anvil);
# Is the server already running somewhere?
find_server($anvil);
#$anvil->Server->find({server => $server});
### TODO:
my $host = $anvil->_short_hostname;
print "I am: [".$anvil->data->{drbd}{config}{$host}{host}."]. my peer is: [".$anvil->data->{drbd}{config}{$host}{peer}."]\n";
die;
# If we're still alive, then we didn't see the server in the list of running servers, which is really weird.
@ -322,6 +330,77 @@ sub start_server
$anvil->nice_exit({exit_code => 1});
}
# This uses the DRBD information to find other peers and see if the server is running on them.
sub find_server
{
my ($anvil) = @_;
my $server = $anvil->data->{environment}{OCF_RESKEY_name};
my $host = $anvil->_short_hostname;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0415", variables => { server => $server }});
foreach my $ip_address (sort {$a cmp $b} keys %{$anvil->data->{drbd}{config}{$host}{ip_addresses}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_address => $ip_address }});
$anvil->Server->find({
debug => 3,
target => $ip_address,
remote_user => "root",
});
}
foreach my $this_server (sort {$a cmp $b} keys %{$anvil->data->{server}{location}})
{
my $status = $anvil->data->{server}{location}{$this_server}{status};
my $host = $anvil->data->{server}{location}{$this_server}{host};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
this_server => $this_server,
status => $status,
host => $host,
}});
}
if ((exists $anvil->data->{server}{location}{$server}) && ($anvil->data->{server}{location}{$server}{host}))
{
# The server is running. If it is running here, exit with success. If it's running elsewhere,
# exit with a failure.
my $status = $anvil->data->{server}{location}{$server}{status};
my $host = $anvil->data->{server}{location}{$server}{host};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
status => $status,
host => $host,
}});
if ($host eq $anvil->_hostname)
{
# Already running, we're good, and we're done.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0416", variables => { server => $server }});
$anvil->nice_exit({exit_code => 0});
}
elsif ($host =~ /dr(\d+)$/)
{
# The server is running elsewhere. If the peer host is DR, exit with
# OCF_ERR_CONFIGURED (6) so that pacemaker doesn't try to also start the server on
# the other node, because we don't know the state of it here.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0417", variables => {
server => $server,
host => $host,
}});
$anvil->nice_exit({exit_code => 6});
}
else
{
# It looks like it's running on the peer. So we'll exit OCF_ERR_INSTALLED (5) to tell
# pacemaker to try to start it on our peer.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0418", variables => {
server => $server,
host => $host,
}});
$anvil->nice_exit({exit_code => 6});
}
}
return(0);
}
# This shuts down the server if possible.
sub stop_server
{
@ -350,7 +429,7 @@ sub server_status
{
# Set a sane default of 20 seconds.
$anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} = 20000;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "warn", key => "log_0331", variables => { logout => $anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "warn", key => "log_0331", variables => { timeout => $anvil->data->{environment}{OCF_RESKEY_CRM_meta_timeout} }});
}
$anvil->nice_exit({exit_code => 0});
@ -391,8 +470,8 @@ sub validate_all
### if the server is running elsewhere.
# Read in an parse the server's XML.
$anvil->System->check_storage({debug => 3});
$anvil->Server->get_status({debug => 3, server => $anvil->data->{environment}{OCF_RESKEY_name}});
$anvil->System->check_storage({debug => 2});
$anvil->Server->get_status({debug => 2, 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);
@ -525,12 +604,28 @@ sub validate_storage_drbd
# Now check storage.
my $server = $anvil->data->{environment}{OCF_RESKEY_name};
my $source = "from_disk";
my $host = $anvil->_short_hostname;
# Did I find a resource for each disk?
foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{device}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"server::${server}::device::${device_path}::resource" => $anvil->data->{server}{$server}{device}{$device_path}{resource},
}});
if (not $anvil->data->{server}{$server}{device}{$device_path}{resource})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 0, priority => "err", key => "log_0414", variables => { drbd_device => $device_path }});
$anvil->nice_exit({exit_code => 5});
}
}
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};
my $drbd_resource = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{resource};
my $on_lv = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{on};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host,
drbd_device => $drbd_device,
drbd_resource => $drbd_resource,
on_lv => $on_lv,
@ -567,9 +662,8 @@ sub validate_storage_drbd
}
print "I am: [".$anvil->data->{drbd}{host}{'local'}."]. my peer is: [".$anvil->data->{drbd}{host}{peer}."]\n";
die;
### NOTE: Checking/Managing firewall ports is expensive option, so DRBD ports are permanently opened
### when a resource is created.
return(0);
}

@ -731,6 +731,11 @@ 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>
<key name="log_0414">The DRBD device: [#!variable!drbd_device!#] wasn't found in any DRBD resources on this machine.</key>
<key name="log_0415">- Seeing if the server: [#!variable!server!#] is running already.</key>
<key name="log_0416">The server: [#!variable!server!#] is already running. Exiting successfully.</key>
<key name="log_0417">The server: [#!variable!server!#] is already running on: [#!variable!host!#]. This appears to be a DR host, which is outside pacemaker. Exiting with OCF_ERR_CONFIGURED (6) to prevent pacemaker from trying to start the server on the other node.</key>
<key name="log_0418">The server: [#!variable!server!#] is already running on: [#!variable!host!#]. This appears to be our peer. Exiting with OCF_ERR_INSTALLED (5) to tell pacemaker to try to start it on the other node.</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>

Loading…
Cancel
Save