Updated to set location constraints to minimize migrations

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 9 months ago
parent 8faeb10422
commit 371aaae6a8
  1. 190
      tools/fence_pacemaker

@ -80,6 +80,7 @@ my $conf = {
drbdadm => "/usr/sbin/drbdadm", drbdadm => "/usr/sbin/drbdadm",
echo => "/usr/bin/echo", echo => "/usr/bin/echo",
getent => "/usr/bin/getent", getent => "/usr/bin/getent",
hostnamectl => "/usr/bin/hostnamectl",
logger => "/usr/bin/logger", logger => "/usr/bin/logger",
pcs => "/usr/sbin/pcs", pcs => "/usr/sbin/pcs",
}, },
@ -296,6 +297,10 @@ sub create_constraint
if (lc($peer_rolee) ne "primary") if (lc($peer_rolee) ne "primary")
{ {
# Set the location constraint so that pacemaker doesn't migrate the server when it
# comes back up.
set_location_constraint($conf);
# We're good, fence is complete. # We're good, fence is complete.
to_log($conf, {message => "Resource: [".$target_server."] has been fenced via location constraint successfully!", 'line' => __LINE__, level => 1}); to_log($conf, {message => "Resource: [".$target_server."] has been fenced via location constraint successfully!", 'line' => __LINE__, level => 1});
@ -331,6 +336,175 @@ sub perform_fence
return(0); return(0);
} }
# This sets a location contraint so the server prefers our node.
sub set_location_constraint
{
my ($conf) = @_;
# Get the host names.
my ($local_host, $peer_host) = get_hostname($conf);
my $server = $conf->{environment}{DRBD_RESOURCE};
to_log($conf, {message => "server: [".$server."], local_host: [".$local_host."], peer_host: [".$peer_host."]", 'line' => __LINE__, level => 2});
if ((not $local_host) or (not $peer_host))
{
# We can't update the constraints.
return(1);
}
to_log($conf, {message => "Setting the pacemaker location constraint so that: [".$server."] prefers this host.", 'line' => __LINE__, level => 1});
my $shell_call = $conf->{path}{exe}{pcs}." constraint location ".$server." prefers ".$local_host."=200 ".$peer_host."=100";
to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n";
while(<$file_handle>)
{
# This should not generate output.
chomp;
my $line = $_;
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
}
close($file_handle);
return(0);
}
# This gets the local short hostname
sub get_hostname
{
my ($conf) = @_;
# This will store our name.
$conf->{cluster}{local_node} = "";
my $shell_call = $conf->{path}{exe}{hostnamectl}." --static";
to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n";
while(<$file_handle>)
{
# This should not generate output.
chomp;
my $line = $_;
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
if ((not $line) or ($line =~ /\s/))
{
# We can't trust this, it could be an error like "Could not get property: Refusing
# activation, D-Bus is shutting down.".
last;
}
else
{
$conf->{cluster}{local_node} = $line;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
last;
}
}
# If we didn't get the host name, try reading /etc/hostname
if (not $conf->{cluster}{local_node})
{
# Try reading the config file name.
my $shell_call = "/etc/hostname";
to_log($conf, {message => "Reading: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, "<", $shell_call) or warn "Failed to read: [".$shell_call.", error was: [".$!."]";
while(<$file_handle>)
{
### NOTE: Don't chop this, we want to record exactly what we read
my $line = $_;
to_log($conf, {message => "line: [".$line."]", 'line' => __LINE__, level => 2});
if ((not $line) or ($line =~ /\s/))
{
# We can't trust this.
last;
}
else
{
$conf->{cluster}{local_node} = $line;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
last;
}
}
close $file_handle;
}
# If we still didn't get the hostname, try calling 'hostnamectl --transient'
if (not $conf->{cluster}{local_node})
{
my $shell_call = $conf->{path}{exe}{hostnamectl}." --transient";
to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n";
while(<$file_handle>)
{
# This should not generate output.
chomp;
my $line = $_;
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
if ((not $line) or ($line =~ /\s/))
{
# We can't trust this, it could be an error like "Could not get property: Refusing
# activation, D-Bus is shutting down.".
last;
}
else
{
$conf->{cluster}{local_node} = $line;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
last;
}
}
}
# Make sure we've got a short hostname
$conf->{cluster}{local_node} =~ s/\..*$//;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
my $peer_host = $conf->{cluster}{target_node};
my $local_host = $conf->{cluster}{local_node};
to_log($conf, {message => "peer_host: [".$peer_host."], local_host: [".$local_host."]", 'line' => __LINE__, level => 2});
# Last, look through the pacemaker CIB to make sure we're going to use the names used in pacemaker.
if ((not exists $conf->{cluster}{cib}) or (not $conf->{cluster}{cib}))
{
read_cib($conf);
}
if ($conf->{cluster}{cib})
{
foreach my $line (split/\n/, $conf->{cluster}{cib})
{
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
if ($line =~ /<node .*>$/)
{
my $this_node_name = ($line =~ /uname="(.*?)"/)[0];
to_log($conf, {message => "this_node_name: [".$this_node_name."]", 'line' => __LINE__, level => 2});
if (($this_node_name eq $local_host) or ($this_node_name eq $peer_host))
{
# Name is accurate, we're good
next;
}
elsif ($this_node_name =~ /^$local_host\./)
{
# Update the host name
$conf->{cluster}{local_node} = $this_node_name;
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."]", 'line' => __LINE__, level => 2});
}
elsif ($this_node_name =~ /^$peer_host\./)
{
# Update the host name
$conf->{cluster}{target_node} = $this_node_name;
to_log($conf, {message => "cluster::target_node: [".$conf->{cluster}{target_node}."]", 'line' => __LINE__, level => 2});
}
}
}
}
to_log($conf, {message => "cluster::local_node: [".$conf->{cluster}{local_node}."], cluster::target_node: [".$conf->{cluster}{target_node}."]", 'line' => __LINE__, level => 2});
return($conf->{cluster}{local_node}, $conf->{cluster}{target_node});
}
# This reads the status of all resources. If we're not all UpToDate, check if the peer is. If the peer is, # This reads the status of all resources. If we're not all UpToDate, check if the peer is. If the peer is,
# abort. If not, proceed (someone is gouig to have a bad day, but maybe some servers will live) # abort. If not, proceed (someone is gouig to have a bad day, but maybe some servers will live)
@ -537,6 +711,10 @@ sub identify_peer
to_log($conf, {message => "Checking the status of target node: [".$node."].", 'line' => __LINE__, level => 1}); to_log($conf, {message => "Checking the status of target node: [".$node."].", 'line' => __LINE__, level => 1});
if (($join eq "down") && ($expected eq "down")) if (($join eq "down") && ($expected eq "down"))
{ {
# Set the location constraint so that pacemaker doesn't migrate the
# server when it comes back up.
set_location_constraint($conf);
# The node is out. # The node is out.
to_log($conf, {message => "The node: [".$node."] is already down. No actual fence needed.", 'line' => __LINE__, level => 1}); to_log($conf, {message => "The node: [".$node."] is already down. No actual fence needed.", 'line' => __LINE__, level => 1});
exit(7); exit(7);
@ -625,6 +803,9 @@ sub read_cib
exit(1); exit(1);
} }
# Cache the CIB.
$conf->{cluster}{cib} = $body;
return($body); return($body);
} }
@ -738,8 +919,12 @@ sub check_peer_is_fenced
to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2});
} }
close $file_handle; close $file_handle;
to_log($conf, {message => "Fence completed successfully!", 'line' => __LINE__, level => 1});
# Set the location constraint so that pacemaker doesn't migrate the server
# when it comes back up.
set_location_constraint($conf);
to_log($conf, {message => "Fence completed successfully!", 'line' => __LINE__, level => 1});
exit(7); exit(7);
} }
else else
@ -814,7 +999,8 @@ sub to_log
# Build the message. We log the line # Build the message. We log the line
if (($conf->{'log'}{line_numbers}) && ($line)) if (($conf->{'log'}{line_numbers}) && ($line))
{ {
$message = $line."; ".$message; # Record the PID as well to make it easier to separate parallel runs.
$message = "[".$$."]:".$line."; ".$message;
} }
my $priority_string = $facility; my $priority_string = $facility;

Loading…
Cancel
Save