* Added 'fence_delay' fence agent to handle the corner cases where an IPMI BMC had crashed until a power cycle, and PDU fencing was effected, but failed to report as such.

* Updated Cluster->parse_cib() to take a CIB as a parameter.
* Fixed a bug in Database->get_hosts() where loading the host_ipmi value was filtered through Log->is_secure.
* Updated Striker->get_fence_data() to parse the switches to make it easier to map a fence agent's command line switches to STDIN arguments.
* Created System->parse_arguments() that converts a series of command line switches and their values into a hash. It's similar to Get->switches(), but works on any string.
* Continued work on anvil-join-anvil's fence configuration logic.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 4 years ago
parent d2d5d7b460
commit 3c2f25a860
  1. 41
      Anvil/Tools/Cluster.pm
  2. 2
      Anvil/Tools/Database.pm
  3. 6
      Anvil/Tools/Get.pm
  4. 25
      Anvil/Tools/Striker.pm
  5. 141
      Anvil/Tools/System.pm
  6. 2
      Anvil/Tools/Words.pm
  7. 30
      notes
  8. 107
      tools/anvil-join-anvil
  9. 447
      tools/fence_delay
  10. 195
      tools/test.pl

@ -251,6 +251,14 @@ sub get_peers
This reads in the CIB XML and parses it. On success, it returns C<< 0 >>. On failure (ie: pcsd isn't running), returns C<< 1 >>.
Parameters;
=head3 cib (optional)
B<< Note >>: Generally this should not be used.
By default, the CIB is read by calling C<< pcs cluster cib >>. However, this parameter can be used to pass in a CIB instead. If this is set, the live CIB is B<< NOT >> read.
=cut
sub parse_cib
{
@ -260,6 +268,11 @@ sub parse_cib
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Cluster->parse_cib()" }});
my $cib = defined $parameters->{cib} ? $parameters->{cib} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
cib => $cib,
}});
# If we parsed before, delete it.
if (exists $anvil->data->{cib}{parsed})
{
@ -271,15 +284,25 @@ sub parse_cib
delete $anvil->data->{cib}{data};
}
my $problem = 1;
my $shell_call = $anvil->data->{path}{exe}{pcs}." cluster cib";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($cib_data, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
cib_data => $cib_data,
return_code => $return_code,
}});
my $problem = 1;
my $cib_data = "";
my $return_code = 0;
if ($cib)
{
$cib_data = $cib;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { cib_data => $cib_data }});
}
else
{
my $shell_call = $anvil->data->{path}{exe}{pcs}." cluster cib";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
($cib_data, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
cib_data => $cib_data,
return_code => $return_code,
}});
}
if ($return_code)
{
# Failed to read the CIB.

@ -1951,7 +1951,7 @@ FROM
$anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name} = $host_name;
$anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type} = $host_type;
$anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key} = $host_key;
$anvil->data->{hosts}{host_uuid}{$host_uuid}{host_ipmi} = $anvil->Log->is_secure($host_ipmi);
$anvil->data->{hosts}{host_uuid}{$host_uuid}{host_ipmi} = $host_ipmi;
$anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name} = $anvil_name;
$anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid} = $anvil_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {

@ -1046,6 +1046,8 @@ The switches 'C<< -v >>', 'C<< -vv >>', 'C<< -vvv >>' and 'C<< -vvvv >>' will ca
Anything after 'C<< -- >>' is treated as a raw string and is not processed.
=cut
### TODO: This doesn't handle quoted values, System->parse_arguments() does. Switch to using it. Note that
### we'll still need to process '--raw' here (or make it work there)
sub switches
{
my $self = shift;
@ -1066,7 +1068,7 @@ sub switches
# If the argument is just '--', appeand everything after it to 'raw'.
if ($argument eq "--")
{
$last_argument = "raw";
$last_argument = "raw";
$anvil->data->{switches}{raw} = "";
}
else
@ -1089,7 +1091,7 @@ sub switches
if ($last_argument)
{
$anvil->data->{switches}{$last_argument} = $argument;
$last_argument = "";
$last_argument = "";
}
else
{

@ -340,6 +340,28 @@ sub get_fence_data
"fence_data::${fence_agent}::parameters::${name}::content_type" => $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type},
}});
# Make it easier to tranlate a switch to a parameter name.
if ($anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{switches})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
fence_agent => $fence_agent,
name => $name,
}});
foreach my $switch (split/,/, $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{switches})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { '>> switch' => $switch }});
$switch =~ s/=.*$//;
$switch =~ s/\s//g;
$switch =~ s/^-{1,2}//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { '<< switch' => $switch }});
$anvil->data->{fence_data}{$fence_agent}{switch}{$switch}{name} = $name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"fence_data::${fence_agent}::switch::${switch}::name" => $anvil->data->{fence_data}{$fence_agent}{switch}{$switch}{name},
}});
}
}
# 'action' is a string, but it has a set list of allowed values, so we manually switch it to a 'select' for the web interface
if ($name eq "action")
{
@ -872,6 +894,9 @@ WHERE
"manifests::name_to_uuid::${manifest_name}" => $anvil->data->{manifests}{name_to_uuid}{$manifest_name},
}});
# Whoever is calling us will want the fence data, so load it as well.
$anvil->Database->get_fences({debug => $debug});
# Parse the XML.
my $parsed_xml = "";
my $xml = XML::Simple->new();

@ -1849,6 +1849,9 @@ LIMIT 1
}
}
# Re-read the hosts so that it's updated.
$anvil->Database->get_hosts();
return($host_ipmi);
}
@ -3340,6 +3343,144 @@ sub pids
}
=head2 parse_arguments
This takes command-line switches, similar to how C<< Get->switches >> does, and breaks them up and stores them in a hash reference which is returned. The difference being that this processes any argument-like string instead of specific C<< @ARGV >>.
Switches without associated values are set to C<< #!SET!# >>. If there is a problem, and empty string is returned. On success, a hash reference is returned in the format C<< <switch> = <value> >>.
Parameters;
=head3 arguments (required)
This is a plain string of arguments to be broken up.
=cut
sub parse_arguments
{
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->parse_arguments()" }});
my $arguments = defined $parameter->{arguments} ? $parameter->{arguments} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
arguments => $arguments,
}});
my $hash = {};
my $quoted = "";
my $switch = "";
my $value = "";
foreach my $arg (split/ /, $arguments)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { arg => $arg }});
if (($arg =~ /^'/) or ($arg =~ /^"/))
{
# Store a quoted value.
$quoted .= $arg." ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { quoted => $quoted }});
}
elsif ($quoted)
{
if (($arg =~ /'$/) or ($arg =~ /"$/))
{
# Done
$quoted .= $arg;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { quoted => $quoted }});
if ($quoted =~ /^'(.*)'$/)
{
$value = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { value => $value }});
}
elsif ($quoted =~ /^"(.*)"$/)
{
$value = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { value => $value }});
}
$hash->{$switch} = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hash->{$switch}" => $hash->{$switch} }});
$quoted = "";
$switch = "";
$value = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
quoted => $quoted,
switch => $switch,
value => $value,
}});
}
else
{
$quoted .= $arg." ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { quoted => $quoted }});
}
}
elsif ($arg =~ /^-/)
{
if ($switch)
{
$value = "#!SET!#";
$hash->{$switch} = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hash->{$switch}" => $hash->{$switch} }});
$switch = "";
$value = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
switch => $switch,
value => $value,
}});
}
$quoted = "";
if ($arg =~ /^(.*?)=(.*)$/)
{
$switch = $1;
$value = $2;
$switch =~ s/^-{1,2}//g;
if (($value =~ /^'/) or ($value =~ /^"/))
{
$quoted .= $value." ";
}
else
{
$hash->{$switch} = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hash->{$switch}" => $hash->{$switch} }});
$switch = "";
$value = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
switch => $switch,
value => $value,
}});
}
}
else
{
$switch = $arg;
$switch =~ s/^-{1,2}//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { switch => $switch }});
}
}
else
{
$hash->{$switch} = $arg;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hash->{$switch}" => $hash->{$switch} }});
$switch = "";
$value = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
switch => $switch,
value => $value,
}});
}
}
return($hash);
}
=head2 read_ssh_config
This reads /etc/ssh/ssh_config and notes hosts with defined ports. When found, the associated port will be automatically used for a given host name or IP address.

@ -1,6 +1,6 @@
package Anvil::Tools::Words;
#
# This module contains methods used to handle storage related tasks
# This module contains methods used to handle message processing related to support of multi-lingual use.
#
use strict;

30
notes

@ -255,12 +255,39 @@ systemctl stop libvirtd.service
==== One node
pcs host auth el8-a01n01 el8-a01n02 -u hacluster -p "secret"
### VMs
pcs cluster setup m3-anvil-01 el8-a01n01 el8-a01n02
pcs cluster start --all
pcs stonith create virsh_node1 fence_virsh pcmk_host_list="el8-a01n01" ipaddr="192.168.122.1" passwd="secret" login="root" delay="15" port="el8-a01n01" op monitor interval="60"
pcs stonith create virsh_node2 fence_virsh pcmk_host_list="el8-a01n02" ipaddr="192.168.122.1" passwd="secret" login="root" port="el8-a01n02" op monitor interval="60"
### Real iron.
pcs stonith create ipmilan_node1 fence_ipmilan pcmk_host_list="mk-a02n01" ipaddr="10.201.13.1" password="another secret p" username="admin" delay="15" op monitor interval="60"
pcs stonith create ipmilan_node2 fence_ipmilan pcmk_host_list="mk-a02n02" ipaddr="10.201.13.2" password="another secret p" username="admin" op monitor interval="60"
pcs stonith level add 1 mk-a02n01 ipmilan_node1
pcs stonith level add 1 mk-a02n02 ipmilan_node2
pcs stonith create apc_snmp_node1_psu1 fence_apc_snmp pcmk_host_list="mk-a02n01" pcmk_off_action="reboot" ip="10.201.2.3" port="3" power_wait="5" op monitor interval="60"
pcs stonith create apc_snmp_node1_psu2 fence_apc_snmp pcmk_host_list="mk-a02n01" pcmk_off_action="reboot" ip="10.201.2.4" port="3" power_wait="5" op monitor interval="60"
pcs stonith create apc_snmp_node2_psu1 fence_apc_snmp pcmk_host_list="mk-a02n02" pcmk_off_action="reboot" ip="10.201.2.3" port="4" power_wait="5" op monitor interval="60"
pcs stonith create apc_snmp_node2_psu2 fence_apc_snmp pcmk_host_list="mk-a02n02" pcmk_off_action="reboot" ip="10.201.2.4" port="4" power_wait="5" op monitor interval="60"
pcs stonith level add 2 mk-a02n01 apc_snmp_node1_psu1,apc_snmp_node1_psu2
pcs stonith level add 2 mk-a02n02 apc_snmp_node2_psu1,apc_snmp_node2_psu2
pcs stonith create delay_node1 fence_delay pcmk_host_list="mk-a02n01" wait="60" op monitor interval="60"
pcs stonith create delay_node2 fence_delay pcmk_host_list="mk-a02n02" wait="60" op monitor interval="60"
pcs stonith level add 3 mk-a02n01 delay_node1
pcs stonith level add 3 mk-a02n02 delay_node2
# Either case
pcs property set stonith-max-attempts=INFINITY
pcs property set stonith-enabled=true
### No longer used.
pcs resource create hypervisor systemd:libvirtd op monitor interval=60
pcs resource clone hypervisor clone-max=2 notify="false"
pcs resource create drbd systemd:drbd op monitor interval=60
@ -274,6 +301,9 @@ pcs resource update test_server ocf:alteeve:server name="test_server" meta allow
stonith_admin --fence el8-a01n02 --verbose; crm_error $?
stonith-max-attempts=INFINITY
cluster-recheck-interval puts an upper bound on the "i give up" time
==== DRBD notes
* resources can contain an US-ASCII character, except for spaces

@ -368,9 +368,107 @@ sub configure_pacemaker
}
sleep 5 if not $both_online;
}
### Setup fencing!
my $delay_set = 0;
# IPMI first, if applicable.
foreach my $node ("node1", "node2")
{
my $host_name = $node eq "node1" ? $node1_host_name : $node2_host_name;
my $host_uuid = $node eq "node1" ? $node1_host_uuid : $node2_host_uuid;
my $host_ipmi = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_ipmi};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_name => $host_name,
host_uuid => $host_uuid,
host_ipmi => $host_ipmi =~ /passw/ ? $anvil->Log->is_secure($host_ipmi) : $host_ipmi,
}});
next if not $host_ipmi;
# If we're here, break up the command and turn it into the pcs call.
my ($fence_agent, $arguments) = ($host_ipmi =~ /^\/.*\/(.*?)\s+(.*)$/);
my $stonith_name = ($fence_agent =~ /^fence_(.*)$/)[0]."_".$node;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
fence_agent => $fence_agent,
arguments => $arguments =~ /passw/ ? $anvil->Log->is_secure($arguments) : $arguments,
stonith_name => $stonith_name,
}});
my $pcs_line = "pcs stonith create ".$stonith_name." ".$fence_agent." pcmk_host_list=\"".$host_name."\" ";
my $switches = $anvil->System->parse_arguments({arguments => $arguments});
foreach my $switch (sort {$a cmp $b} keys %{$switches})
{
# Find the variable=value version.
my $variable = $anvil->data->{fence_data}{$fence_agent}{switch}{$switch}{name};
my $value = $switches->{$switch};
$value =~ s/"/\"/g;
$pcs_line .= $variable."=\"".$value."\" ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
variable => $variable,
value => $variable =~ /passw/ ? $anvil->Log->is_secure($value) : $value,
pcs_line => $pcs_line =~ /passw/ ? $anvil->Log->is_secure($pcs_line) : $pcs_line,
}});
}
if (not $delay_set)
{
$delay_set = 1;
$pcs_line .= "delay=\"15\" ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
delay_set => $delay_set,
pcs_line => $pcs_line =~ /passw/ ? $anvil->Log->is_secure($pcs_line) : $pcs_line,
}});
}
$pcs_line .= "op monitor interval=\"60\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pcs_line => $pcs_line =~ /passw/ ? $anvil->Log->is_secure($pcs_line) : $pcs_line,
}});
$stonith_name = "";
$fence_agent = "";
foreach my $device (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$node}{fence}})
{
my $fence_uuid = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{fences}{$device}{uuid};
my $fence_arguments = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_arguments};
my $fence_agent = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_agent};
my $stonith_name = ($fence_agent =~ /^fence_(.*)$/)[0]."_".$node;
my $port = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$node}{fence}{$device}{port};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
device => $device,
fence_uuid => $fence_uuid,
fence_arguments => $fence_arguments =~ /passw/ ? $anvil->Log->is_secure($fence_arguments) : $fence_arguments,
stonith_name => $stonith_name,
port => $port,
}});
my $pcs_line = "pcs stonith create ".$stonith_name." ".$fence_agent." pcmk_host_list=\"".$host_name."\" ".$fence_arguments." ";
if (not $delay_set)
{
$delay_set = 1;
$pcs_line .= "delay=\"15\" ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
delay_set => $delay_set,
pcs_line => $pcs_line =~ /passw/ ? $anvil->Log->is_secure($pcs_line) : $pcs_line,
}});
}
if ($port)
{
$port =~ s/"/\"/g;
$pcs_line .= "port=\"".$port."\" ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pcs_line => $pcs_line =~ /passw/ ? $anvil->Log->is_secure($pcs_line) : $pcs_line,
}});
}
$pcs_line .= "op monitor interval=\"60\"";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pcs_line => $pcs_line =~ /passw/ ? $anvil->Log->is_secure($pcs_line) : $pcs_line,
}});
}
}
# Now setup any other fence agents.
}
# Setup fencing!
=cut
$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed};
@ -378,11 +476,6 @@ $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed};
909; xxx::upses::el8-ups02::uuid: [7ffb4dc2-8b96-4ca7-80bb-49e309fb2f5f]
918; xxx::fences::an-nas02::uuid: [4117a862-f58f-4676-991a-9ca257a3c612]
949; xxx::networks::name::bcn1::gateway: [], xxx::networks::name::bcn1::network: [10.201.0.0], xxx::networks::name::bcn1::subnet: [255.255.0.0]
949; xxx::networks::name::sn1::gateway: [], xxx::networks::name::sn1::network: [10.101.0.0], xxx::networks::name::sn1::subnet: [255.255.0.0]
949; xxx::networks::name::ifn1::gateway: [10.255.255.254], xxx::networks::name::ifn1::network: [10.255.0.0], xxx::networks::name::ifn1::subnet: [255.255.0.0]
961; xxx::networks::count::bcn: [1], xxx::networks::count::ifn: [1], xxx::networks::count::sn: [1]
971; xxx::machine::node1::ipmi_ip: [], xxx::machine::node1::type: [!!undef!!]
980; xxx::machine::node1::fence::an-nas02::port: [el8-a01n01]
980; xxx::machine::node1::fence::el8-pdu01::port: []
@ -1201,7 +1294,7 @@ sub load_job
"sys::anvil_uuid" => $anvil->data->{sys}{anvil_uuid},
}});
# Load in the manifest
# Load in the host info and the manifest.
$anvil->Database->get_hosts();
my $problem = $anvil->Striker->load_manifest({
debug => 2,

@ -0,0 +1,447 @@
#!/usr/bin/perl
#
# This is a passive agent that simply injects a delay. It is designed to be
# used at the end of a list of fence methods to give time for previous attempts
# to recover. Specifically, if PDU fencing cut power to the node but somehow
# reported as failed. The fence would move back up and try to fence via the
# IPMI BMC, but given it hasn't had time to boot, would fail, leaving the
# system stuck in a loop.
#
# Madison Kelly, mkelly@alteeve.ca
# http://alteeve.com/w
#
# This software is released under the GPL v2. See the LICENSE file in the
# configuration directory for a copy of the GPL v2.
#
# Bugs;
# - None known
#
# Warnings;
# - This is not a real fence agent, and it will always return failure. This is
# by design.
#
# Play safe!
use strict;
use warnings;
use IO::Handle;
# Catch signals for clean exits.
$SIG{INT} = \&_catch_sig;
$SIG{TERM} = \&_catch_sig;
# These are the default values and will be over-written by the config file's
# variables which in turn can, in some cases, be over-written by command line
# arguments.
my $conf = {
'system' => {
action => "off",
agent_version => "1.0",
log_level => 1,
wait => 60,
device => "",
list => "",
'log' => "/var/log/fence_delay.log",
monitor => "",
node_name => "", # My name, as reported by cman_tool
nodes => 0, # Number of nodes in the cluster
password => "",
quiet => 1,
version => 0,
},
path => {
},
};
# Log file for output.
my $log = IO::Handle->new();
open ($log, ">>".$conf->{'system'}{'log'}) || die "Failed to open: [".$conf->{'system'}{'log'}."] for writing; Error: $!\n";
# Set $log and STDOUT to hot (unbuffered) output.
if (1)
{
select $log;
$| = 1;
select STDOUT;
$| = 1;
}
record($conf, $log, "'fence_delay' called at: [".get_date_time($conf)."].\n", 2);
# Read in arguments from the command line.
read_cla($conf, $log);
# Now read in arguments from STDIN, which is how 'fenced' passes arguments.
read_stdin($conf, $log);
# If I've been asked to show the metadata XML, do so and then exit.
if ($conf->{'system'}{action} eq "metadata")
{
metadata($conf, $log);
do_exit($conf, $log, 0);
}
# If I've been asked to show the version information, do so and then exit.
if ($conf->{'system'}{version})
{
version($conf, $log);
do_exit($conf, $log, 0);
}
# When asked to 'monitor' or 'list'. being multi-port, this will return a CSV
# of ports and their current state.
record($conf, $log, "Requested action: [".$conf->{'system'}{action}."].\n", 2);
if (($conf->{'system'}{action} eq "monitor") or ($conf->{'system'}{action} eq "list"))
{
show_list($conf, $log);
do_exit($conf, $log, 0);
}
# Do it!
do_wait($conf, $log);
# Cleanup and exit.
do_exit($conf, $log, );
###############################################################################
# Here be functions. #
###############################################################################
# This cleanly exits the agent.
sub do_exit
{
my ($conf, $log, $exit_status) = @_;
$exit_status = 9 if not defined $exit_status;
# Close the log file handle, if it exists.
$log->close() if $log;
exit ($exit_status);
}
# This returns the 'help' message.
sub help
{
my ($conf, $log) = @_;
# Point the user at the man page.
print "
Passive fence agent used to inject a delay at the end of a list of fence
methods. Can take '--wait X' or 'wait=X' via the command line or STDIN
respectively. Otherwise, the default of '60' is used.
This method is meant to ensure that devices that require time to boot get that
time before the clusters starts working through the list again.
The genesis of this was a case where fencing was set as IPMI -> 2x PDUs, and a
firmware bug in the PDUs caused them to properly power cycle the node, but
failed to return success, causing the fence agent to consider it a failed
fence. The cluster would then try the IPMI interface again, but it had not
booted, so the IPMI failed and the PDUs were again cycled. This left the
cluster hung in a loop.
By adding this agent as a third method, it will introduce enough of a delay
that the IPMI BMC will have a chance to boot before fence_ipmilan (or the like)
are reinvoked.
\n";
do_exit($conf, $log, 0);
}
# This simply prints the 'metadata' XML data to STDOUT.
sub metadata
{
my ($conf, $log) = @_;
print q`<?xml version="1.0" ?>
<resource-agent name="fence_delay" shortdesc="Agent designed to pause at the end of a list of methods, before trying the first method again. Always returns 'failed' to the cluster.">
<longdesc>This is a passive agent that simply injects a delay. It is designed to be used at the end of a list of fence methods to give time for previous attempts to recover. Specifically, if PDU fencing cut power to the node but somehow reported as failed. The fence would move back up and try to fence via the IPMI BMC, but given it hasn't had time to boot, would fail, leaving the system stuck in a loop.</longdesc>
<vendor-url>http://www.alteeve.com</vendor-url>
<parameters>
<parameter name="action" unique="0">
<getopt mixed="-o, --action=[action]" />
<content type="string" default="off"/>
<shortdesc lang="en">Fencing action. The 'reboot' and 'off' actions trigger the wait.</shortdesc>
</parameter>
<parameter name="quiet" unique="0">
<getopt mixed="-q" />
<content type="boolean" />
<shortdesc lang="en">Supress all output to STDOUT, including critical messages. Check logfile if used. Default 1.</shortdesc>
</parameter>
<parameter name="debug" unique="0">
<getopt mixed="-d" />
<content type="boolean" />
<shortdesc lang="en">Print extensive debug information to STDOUT and to the log file.</shortdesc>
</parameter>
<parameter name="version" unique="0">
<getopt mixed="--version" />
<content type="boolean" />
<shortdesc lang="en">Prints the fence agent version and exits.</shortdesc>
</parameter>
<parameter name="wait" unique="0">
<getopt mixed="-w, --wait=[seconds]" />
<content type="string" />
<shortdesc lang="en">Set the time the agent waits before exiting. The default is 60 seconds.</shortdesc>
</parameter>
</parameters>
<actions>
<action name="on" />
<action name="off" />
<action name="reboot" />
<action name="status" />
<action name="list" />
<action name="monitor" />
<action name="metadata" />
</actions>
</resource-agent>
`;
# Done, exit.
do_exit($conf, $log, 0);
}
# This handles the actual actions.
sub do_wait
{
my ($conf, $log) = @_;
record($conf, $log, "In the 'do_wait' function.\n", 2);
# Make this more readable.
my $wait = $conf->{'system'}{wait} =~ /^\d+$/ ? $conf->{'system'}{wait} : 60;
my $action = $conf->{'system'}{action};
if (($action eq "off") or ($action eq "reboot"))
{
record($conf, $log, "Sleeping for: [".$wait."] seconds.\n", 1);
sleep $wait;
record($conf, $log, "Delay complete, exiting with failure code so fencing will try the next device in the list.\n", 1);
# Report a successful failure.
do_exit($conf, $log, 1);
}
elsif ($action eq "on")
{
# This is allowed to succeed.
record($conf, $log, "Asked to turn on, this is safe (and meaningless) so we'll exit with a success code.\n", 1);
do_exit($conf, $log, 0);
}
elsif ($action eq "status")
{
# This is allowed to succeed.
record($conf, $log, "Asked for a status, this is safe (and meaningless) so we'll exit with a success code.\n", 1);
do_exit($conf, $log, 0);
}
else
{
record($conf, $log, "[ Error ] - Action request: [$action] not recognized!\n", 0);
do_exit($conf, $log, 1);
}
return (0);
}
# Read in command line arguments
sub read_cla
{
my ($conf, $log) = @_;
# Loop through the passed arguments, if any.
record($conf, $log, "Got args:\n", 2);
my $set_next="";
foreach my $arg (@ARGV)
{
$conf->{'system'}{got_cla} = 1;
# If 'set_next' has a value, push this argument into the 'conf'
# hash.
if ($set_next)
{
# Record the values.
$conf->{'system'}{$set_next} = $arg;
record($conf, $log, "[ Debug ] - 'system::$set_next': [".$conf->{'system'}{$set_next}."]\n", 2);
# Clear it now for the next go-round.
$set_next = "";
next;
}
if ($arg =~ /-h/)
{
# Print the help message and then exit.
help($conf, $log);
}
elsif ($arg eq "--version")
{
# Print the version information and then exit.
$conf->{'system'}{version} = 1;
record($conf, $log, "[ Debug ] - 'system::version': [".$conf->{'system'}{version}."]\n", 2);
}
elsif (($arg eq "-q") or ($arg eq "--quiet"))
{
# Suppress all messages, including critical messages, from STDOUT.
$conf->{'system'}{log_level} = 0;
record($conf, $log, "[ Debug ] - 'system::log_level': [".$conf->{'system'}{quiet}."]\n", 2);
}
elsif ($arg eq "--debug")
{
# Enable debug mode.
$conf->{'system'}{log_level} = 2;
record($conf, $log, "[ Debug ] - 'system::log_level': [".$conf->{'system'}{log_level}."]\n", 2);
}
elsif (($arg eq "-w") or ($arg eq "--wait"))
{
# How long to wait before exiting.
$set_next = "wait";
record($conf, $log, "[ Debug ] - 'set_next': [".$set_next."]\n", 2);
}
elsif (($arg eq "-o") or ($arg eq "--action"))
{
# This is the action to take.
$set_next = "action";
record($conf, $log, "[ Debug ] - 'set_next': [".$set_next."]\n", 2);
}
else
{
# Bad argument.
record($conf, $log, "[ Warning ] - Argument: [".$arg."] is not valid arguments.\n", 2);
}
}
return(0);
}
# Read arguments from STDIN. This is adapted from the 'fence_brocade' agent.
sub read_stdin
{
my ($conf, $log) = @_;
return (0) if $conf->{'system'}{got_cla};
my $option;
my $line_count = 0;
while(defined (my $option=<>))
{
# Get rid of newlines.
chomp $option;
# Record the line for now, but comment this out before release.
record($conf, $log, "Processing option line: [$option]\n", 2);
# strip leading and trailing whitespace
$option =~ s/^\s*//;
$option =~ s/\s*$//;
# Increment my option line count.
$line_count++;
# skip comments
next if ($option=~ /^#/);
# Go to the next line if the option line is empty.
next if not $option;
# Split the option up into the name and the value.
my ($name, $value) = split /\s*=\s*/, $option;
# Record the line for now, but comment this out before release.
record ($conf, $log, "Name: [$name], value: [$value].\n");
# Set my variables depending on the veriable name.
if ($name eq "agent")
{
# This is only used by 'fenced', but I record it for
# potential debugging.
$conf->{'system'}{agent} = $value;
record($conf, $log, "[ Debug ] - 'system::agent': [".$conf->{'system'}{agent}."]\n", 2);
}
elsif ($name eq "action")
{
$conf->{'system'}{action} = $value;
record($conf, $log, "[ Debug ] - 'system::action': [".$conf->{'system'}{action}."]\n", 2);
}
elsif ($name eq "quiet")
{
$conf->{'system'}{log_level} = 0;
record($conf, $log, "[ Debug ] - 'system::log_level': [".$conf->{'system'}{log_level}."]\n", 2);
}
elsif ($name eq "debug")
{
$conf->{'system'}{log_level} = 2;
record($conf, $log, "[ Debug ] - 'system::log_level': [".$conf->{'system'}{log_level}."]\n", 2);
}
elsif ($name eq "wait")
{
$conf->{'system'}{wait} = $value;
record($conf, $log, "[ Debug ] - 'system::wait': [".$conf->{'system'}{wait}."]\n", 2);
}
else
{
record($conf, $log, "[ Warning ] - Unexpected name in option: [$option] at line: [$line_count]\n", 1);
}
}
return (0);
}
# This function simply prints messages to both the log and to stdout.
sub record
{
my ($conf, $log, $msg, $level) = @_;
$level = 1 if not defined $level;
#print "level: [".$level."], 'system::log_level': [".$conf->{'system'}{log_level}."], msg: [".$msg."]\n";
return if $level > $conf->{'system'}{log_level};
# Print to the log
print $log $msg;
# Print to the screen if we're not 'quiet'.
print $msg if not $conf->{'system'}{quiet};
return(0);
}
# When asked to 'monitor' or 'list', show a CSV of all nodes and their aliases,
# when found in the config file.
sub show_list
{
my ($conf, $log) = @_;
record($conf, $log, "This is not a multi-port device. The 'list' action is useless.\n", 2);
do_exit($conf, $log, 0);
}
# This prints the version information of this fence agent and of any configured
# fence devices.
sub version
{
my ($conf, $log) = @_;
# Print the Fence Agent version first.
record ($conf, $log, "Fence Agent ver. ".$conf->{'system'}{agent_version}."\n", 1);
do_exit($conf, $log, 0);
}
# This returns the current date and time.
sub get_date_time
{
my ($conf) = @_;
# Get the current date and time,
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
# Format it to 'YYYY-MM-DD HH:MM:SS'.
my $now = (1900 + $year)."-".sprintf("%02d", ($mon + 1))."-".sprintf("%02d", $mday)." ".sprintf("%02d", $hour).":".sprintf("%02d", $min).":".sprintf("%02d", $sec);
return($now);
}
# Catch SIG, move zig!
sub _catch_sig
{
my $signame = shift;
record($conf, $log, "fence_delay process with PID $$ Exiting on SIG".$signame.".\n", 1);
do_exit($conf, $log, 1);
}

@ -29,4 +29,197 @@ $anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, secure => 0, key => "log_0132"});
$anvil->Get->switches;
$anvil->System->check_ssh_keys({debug => 2});
my $xml = '<cib crm_feature_set="3.3.0" validate-with="pacemaker-3.2" epoch="28" num_updates="0" admin_epoch="0" cib-last-written="Wed Jul 29 23:45:47 2020" update-origin="mk-a02n01" update-client="cibadmin" update-user="root" have-quorum="1" dc-uuid="2">
<configuration>
<crm_config>
<cluster_property_set id="cib-bootstrap-options">
<nvpair id="cib-bootstrap-options-have-watchdog" name="have-watchdog" value="false"/>
<nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="2.0.3-5.el8_2.1-4b1f869f0f"/>
<nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="corosync"/>
<nvpair id="cib-bootstrap-options-cluster-name" name="cluster-name" value="mk-anvil-02"/>
<nvpair id="cib-bootstrap-options-stonith-max-attempts" name="stonith-max-attempts" value="INFINITY"/>
<nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="true"/>
</cluster_property_set>
</crm_config>
<nodes>
<node id="1" uname="mk-a02n01"/>
<node id="2" uname="mk-a02n02"/>
</nodes>
<resources>
<primitive class="stonith" id="ipmilan_node1" type="fence_ipmilan">
<instance_attributes id="ipmilan_node1-instance_attributes">
<nvpair id="ipmilan_node1-instance_attributes-delay" name="delay" value="15"/>
<nvpair id="ipmilan_node1-instance_attributes-ipaddr" name="ipaddr" value="10.201.13.1"/>
<nvpair id="ipmilan_node1-instance_attributes-password" name="password" value="another secret p"/>
<nvpair id="ipmilan_node1-instance_attributes-pcmk_host_list" name="pcmk_host_list" value="mk-a02n01"/>
<nvpair id="ipmilan_node1-instance_attributes-username" name="username" value="admin"/>
</instance_attributes>
<operations>
<op id="ipmilan_node1-monitor-interval-60" interval="60" name="monitor"/>
</operations>
</primitive>
<primitive class="stonith" id="ipmilan_node2" type="fence_ipmilan">
<instance_attributes id="ipmilan_node2-instance_attributes">
<nvpair id="ipmilan_node2-instance_attributes-ipaddr" name="ipaddr" value="10.201.13.2"/>
<nvpair id="ipmilan_node2-instance_attributes-password" name="password" value="another secret p"/>
<nvpair id="ipmilan_node2-instance_attributes-pcmk_host_list" name="pcmk_host_list" value="mk-a02n02"/>
<nvpair id="ipmilan_node2-instance_attributes-username" name="username" value="admin"/>
</instance_attributes>
<operations>
<op id="ipmilan_node2-monitor-interval-60" interval="60" name="monitor"/>
</operations>
</primitive>
<primitive class="stonith" id="apc_snmp_node1_psu1" type="fence_apc_snmp">
<instance_attributes id="apc_snmp_node1_psu1-instance_attributes">
<nvpair id="apc_snmp_node1_psu1-instance_attributes-ip" name="ip" value="10.201.2.3"/>
<nvpair id="apc_snmp_node1_psu1-instance_attributes-pcmk_host_list" name="pcmk_host_list" value="mk-a02n01"/>
<nvpair id="apc_snmp_node1_psu1-instance_attributes-pcmk_off_action" name="pcmk_off_action" value="reboot"/>
<nvpair id="apc_snmp_node1_psu1-instance_attributes-port" name="port" value="3"/>
<nvpair id="apc_snmp_node1_psu1-instance_attributes-power_wait" name="power_wait" value="5"/>
</instance_attributes>
<operations>
<op id="apc_snmp_node1_psu1-monitor-interval-60" interval="60" name="monitor"/>
</operations>
</primitive>
<primitive class="stonith" id="apc_snmp_node1_psu2" type="fence_apc_snmp">
<instance_attributes id="apc_snmp_node1_psu2-instance_attributes">
<nvpair id="apc_snmp_node1_psu2-instance_attributes-ip" name="ip" value="10.201.2.4"/>
<nvpair id="apc_snmp_node1_psu2-instance_attributes-pcmk_host_list" name="pcmk_host_list" value="mk-a02n01"/>
<nvpair id="apc_snmp_node1_psu2-instance_attributes-pcmk_off_action" name="pcmk_off_action" value="reboot"/>
<nvpair id="apc_snmp_node1_psu2-instance_attributes-port" name="port" value="3"/>
<nvpair id="apc_snmp_node1_psu2-instance_attributes-power_wait" name="power_wait" value="5"/>
</instance_attributes>
<operations>
<op id="apc_snmp_node1_psu2-monitor-interval-60" interval="60" name="monitor"/>
</operations>
</primitive>
<primitive class="stonith" id="apc_snmp_node2_psu1" type="fence_apc_snmp">
<instance_attributes id="apc_snmp_node2_psu1-instance_attributes">
<nvpair id="apc_snmp_node2_psu1-instance_attributes-ip" name="ip" value="10.201.2.3"/>
<nvpair id="apc_snmp_node2_psu1-instance_attributes-pcmk_host_list" name="pcmk_host_list" value="mk-a02n02"/>
<nvpair id="apc_snmp_node2_psu1-instance_attributes-pcmk_off_action" name="pcmk_off_action" value="reboot"/>
<nvpair id="apc_snmp_node2_psu1-instance_attributes-port" name="port" value="4"/>
<nvpair id="apc_snmp_node2_psu1-instance_attributes-power_wait" name="power_wait" value="5"/>
</instance_attributes>
<operations>
<op id="apc_snmp_node2_psu1-monitor-interval-60" interval="60" name="monitor"/>
</operations>
</primitive>
<primitive class="stonith" id="apc_snmp_node2_psu2" type="fence_apc_snmp">
<instance_attributes id="apc_snmp_node2_psu2-instance_attributes">
<nvpair id="apc_snmp_node2_psu2-instance_attributes-ip" name="ip" value="10.201.2.4"/>
<nvpair id="apc_snmp_node2_psu2-instance_attributes-pcmk_host_list" name="pcmk_host_list" value="mk-a02n02"/>
<nvpair id="apc_snmp_node2_psu2-instance_attributes-pcmk_off_action" name="pcmk_off_action" value="reboot"/>
<nvpair id="apc_snmp_node2_psu2-instance_attributes-port" name="port" value="4"/>
<nvpair id="apc_snmp_node2_psu2-instance_attributes-power_wait" name="power_wait" value="5"/>
</instance_attributes>
<operations>
<op id="apc_snmp_node2_psu2-monitor-interval-60" interval="60" name="monitor"/>
</operations>
</primitive>
<primitive class="stonith" id="delay_node1" type="fence_delay">
<instance_attributes id="delay_node1-instance_attributes">
<nvpair id="delay_node1-instance_attributes-pcmk_host_list" name="pcmk_host_list" value="mk-a02n01"/>
<nvpair id="delay_node1-instance_attributes-wait" name="wait" value="60"/>
</instance_attributes>
<operations>
<op id="delay_node1-monitor-interval-60" interval="60" name="monitor"/>
</operations>
</primitive>
<primitive class="stonith" id="delay_node2" type="fence_delay">
<instance_attributes id="delay_node2-instance_attributes">
<nvpair id="delay_node2-instance_attributes-pcmk_host_list" name="pcmk_host_list" value="mk-a02n02"/>
<nvpair id="delay_node2-instance_attributes-wait" name="wait" value="60"/>
</instance_attributes>
<operations>
<op id="delay_node2-monitor-interval-60" interval="60" name="monitor"/>
</operations>
</primitive>
</resources>
<constraints/>
<fencing-topology>
<fencing-level devices="ipmilan_node1" id="fl-mk-a02n01-1" index="1" target="mk-a02n01"/>
<fencing-level devices="ipmilan_node2" id="fl-mk-a02n02-1" index="1" target="mk-a02n02"/>
<fencing-level devices="apc_snmp_node1_psu1,apc_snmp_node1_psu2" id="fl-mk-a02n01-2" index="2" target="mk-a02n01"/>
<fencing-level devices="apc_snmp_node2_psu1,apc_snmp_node2_psu2" id="fl-mk-a02n02-2" index="2" target="mk-a02n02"/>
<fencing-level devices="delay_node1" id="fl-mk-a02n01-3" index="3" target="mk-a02n01"/>
<fencing-level devices="delay_node2" id="fl-mk-a02n02-3" index="3" target="mk-a02n02"/>
</fencing-topology>
</configuration>
<status>
<node_state id="2" uname="mk-a02n02" in_ccm="true" crmd="online" crm-debug-origin="do_update_resource" join="member" expected="member">
<lrm id="2">
<lrm_resources>
<lrm_resource id="ipmilan_node1" type="fence_ipmilan" class="stonith">
<lrm_rsc_op id="ipmilan_node1_last_0" operation_key="ipmilan_node1_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="7:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:7;7:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="5" rc-code="7" op-status="0" interval="0" last-rc-change="1596077508" last-run="1596077508" exec-time="2" queue-time="0" op-digest="94ccc3ba507c38b16a5ab5adad892afe" op-secure-params=" password passwd " op-secure-digest="30aa995f9bd3385e535d0a45b5b673c7"/>
</lrm_resource>
<lrm_resource id="ipmilan_node2" type="fence_ipmilan" class="stonith">
<lrm_rsc_op id="ipmilan_node2_last_0" operation_key="ipmilan_node2_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="15:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;15:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="26" rc-code="0" op-status="0" interval="0" last-rc-change="1596077508" last-run="1596077508" exec-time="87" queue-time="0" op-digest="e759a456df902485096d4a48725ed81c" op-secure-params=" password passwd " op-secure-digest="47989163387c397e63fa3acdbec0d274"/>
<lrm_rsc_op id="ipmilan_node2_monitor_60000" operation_key="ipmilan_node2_monitor_60000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="16:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;16:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="29" rc-code="0" op-status="0" interval="60000" last-rc-change="1596077509" exec-time="87" queue-time="0" op-digest="467ef5117cbb737e5c6fc23b58809791" op-secure-params=" password passwd " op-secure-digest="47989163387c397e63fa3acdbec0d274"/>
</lrm_resource>
<lrm_resource id="apc_snmp_node1_psu1" type="fence_apc_snmp" class="stonith">
<lrm_rsc_op id="apc_snmp_node1_psu1_last_0" operation_key="apc_snmp_node1_psu1_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="9:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:7;9:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="13" rc-code="7" op-status="0" interval="0" last-rc-change="1596077508" last-run="1596077508" exec-time="0" queue-time="0" op-digest="bf350e059a2283cb416a705205fcef98" op-secure-params=" password passwd " op-secure-digest="91abc2f7f37dfdd5f531054a74a66ced"/>
</lrm_resource>
<lrm_resource id="apc_snmp_node1_psu2" type="fence_apc_snmp" class="stonith">
<lrm_rsc_op id="apc_snmp_node1_psu2_last_0" operation_key="apc_snmp_node1_psu2_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="19:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;19:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="27" rc-code="0" op-status="0" interval="0" last-rc-change="1596077509" last-run="1596077509" exec-time="809" queue-time="0" op-digest="7ff7ebe3c6b94ef30b8074ffb385cacb" op-secure-params=" password passwd " op-secure-digest="a3c98981d6a0382ece4146587d008b5c"/>
<lrm_rsc_op id="apc_snmp_node1_psu2_monitor_60000" operation_key="apc_snmp_node1_psu2_monitor_60000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="20:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;20:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="31" rc-code="0" op-status="0" interval="60000" last-rc-change="1596077509" exec-time="775" queue-time="0" op-digest="534f24f08deb08c3f65872f2139ebf6b" op-secure-params=" password passwd " op-secure-digest="a3c98981d6a0382ece4146587d008b5c"/>
</lrm_resource>
<lrm_resource id="apc_snmp_node2_psu1" type="fence_apc_snmp" class="stonith">
<lrm_rsc_op id="apc_snmp_node2_psu1_last_0" operation_key="apc_snmp_node2_psu1_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="11:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:7;11:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="21" rc-code="7" op-status="0" interval="0" last-rc-change="1596077508" last-run="1596077508" exec-time="0" queue-time="0" op-digest="e4739b474ee5043eaf7233ee12ee51d3" op-secure-params=" password passwd " op-secure-digest="3f31fc0be92206a110435411ffb3caf8"/>
</lrm_resource>
<lrm_resource id="apc_snmp_node2_psu2" type="fence_apc_snmp" class="stonith">
<lrm_rsc_op id="apc_snmp_node2_psu2_last_0" operation_key="apc_snmp_node2_psu2_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="23:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;23:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="28" rc-code="0" op-status="0" interval="0" last-rc-change="1596077509" last-run="1596077509" exec-time="782" queue-time="0" op-digest="f3b985aa75b8f5fa0df015dc0b03b1f1" op-secure-params=" password passwd " op-secure-digest="26e92809fff4cf6b4cd47ff641d8276a"/>
<lrm_rsc_op id="apc_snmp_node2_psu2_monitor_60000" operation_key="apc_snmp_node2_psu2_monitor_60000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="24:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;24:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="30" rc-code="0" op-status="0" interval="60000" last-rc-change="1596077509" exec-time="745" queue-time="0" op-digest="0e4b4767fac04c243d40c582eb192994" op-secure-params=" password passwd " op-secure-digest="26e92809fff4cf6b4cd47ff641d8276a"/>
</lrm_resource>
<lrm_resource id="delay_node1" type="fence_delay" class="stonith">
<lrm_rsc_op id="delay_node1_last_0" operation_key="delay_node1_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="8:13:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:7;8:13:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="45" rc-code="7" op-status="0" interval="0" last-rc-change="1596080690" last-run="1596080690" exec-time="0" queue-time="0" op-digest="cc9e9045724a0f58a4c1e20e87fc27e0"/>
</lrm_resource>
<lrm_resource id="delay_node2" type="fence_delay" class="stonith">
<lrm_rsc_op id="delay_node2_last_0" operation_key="delay_node2_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="24:14:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;24:14:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="50" rc-code="0" op-status="0" interval="0" last-rc-change="1596080694" last-run="1596080694" exec-time="16" queue-time="0" op-digest="3c18f0bcefeff3c4b79dda97eed85b65"/>
<lrm_rsc_op id="delay_node2_monitor_60000" operation_key="delay_node2_monitor_60000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="25:14:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;25:14:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n02" call-id="51" rc-code="0" op-status="0" interval="60000" last-rc-change="1596080694" exec-time="16" queue-time="0" op-digest="28ef7d9656d3e7ad95f689543241ecf8"/>
</lrm_resource>
</lrm_resources>
</lrm>
</node_state>
<node_state id="1" uname="mk-a02n01" in_ccm="true" crmd="online" crm-debug-origin="do_update_resource" join="member" expected="member">
<lrm id="1">
<lrm_resources>
<lrm_resource id="ipmilan_node1" type="fence_ipmilan" class="stonith">
<lrm_rsc_op id="ipmilan_node1_last_0" operation_key="ipmilan_node1_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="13:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;13:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="26" rc-code="0" op-status="0" interval="0" last-rc-change="1596077509" last-run="1596077509" exec-time="93" queue-time="0" op-digest="94ccc3ba507c38b16a5ab5adad892afe" op-secure-params=" password passwd " op-secure-digest="30aa995f9bd3385e535d0a45b5b673c7"/>
<lrm_rsc_op id="ipmilan_node1_monitor_60000" operation_key="ipmilan_node1_monitor_60000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="14:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;14:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="29" rc-code="0" op-status="0" interval="60000" last-rc-change="1596077509" exec-time="84" queue-time="0" op-digest="8010b53c30280214d0b61d74406e67ec" op-secure-params=" password passwd " op-secure-digest="30aa995f9bd3385e535d0a45b5b673c7"/>
</lrm_resource>
<lrm_resource id="ipmilan_node2" type="fence_ipmilan" class="stonith">
<lrm_rsc_op id="ipmilan_node2_last_0" operation_key="ipmilan_node2_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="2:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:7;2:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="9" rc-code="7" op-status="0" interval="0" last-rc-change="1596077508" last-run="1596077508" exec-time="0" queue-time="0" op-digest="e759a456df902485096d4a48725ed81c" op-secure-params=" password passwd " op-secure-digest="47989163387c397e63fa3acdbec0d274"/>
</lrm_resource>
<lrm_resource id="apc_snmp_node1_psu1" type="fence_apc_snmp" class="stonith">
<lrm_rsc_op id="apc_snmp_node1_psu1_last_0" operation_key="apc_snmp_node1_psu1_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="17:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;17:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="27" rc-code="0" op-status="0" interval="0" last-rc-change="1596077509" last-run="1596077509" exec-time="783" queue-time="0" op-digest="bf350e059a2283cb416a705205fcef98" op-secure-params=" password passwd " op-secure-digest="91abc2f7f37dfdd5f531054a74a66ced"/>
<lrm_rsc_op id="apc_snmp_node1_psu1_monitor_60000" operation_key="apc_snmp_node1_psu1_monitor_60000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="18:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;18:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="30" rc-code="0" op-status="0" interval="60000" last-rc-change="1596077509" exec-time="729" queue-time="0" op-digest="baa323cdbcb6e29b8e4ab11e6ec3829a" op-secure-params=" password passwd " op-secure-digest="91abc2f7f37dfdd5f531054a74a66ced"/>
</lrm_resource>
<lrm_resource id="apc_snmp_node1_psu2" type="fence_apc_snmp" class="stonith">
<lrm_rsc_op id="apc_snmp_node1_psu2_last_0" operation_key="apc_snmp_node1_psu2_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="4:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:7;4:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="17" rc-code="7" op-status="0" interval="0" last-rc-change="1596077509" last-run="1596077509" exec-time="0" queue-time="0" op-digest="7ff7ebe3c6b94ef30b8074ffb385cacb" op-secure-params=" password passwd " op-secure-digest="a3c98981d6a0382ece4146587d008b5c"/>
</lrm_resource>
<lrm_resource id="apc_snmp_node2_psu1" type="fence_apc_snmp" class="stonith">
<lrm_rsc_op id="apc_snmp_node2_psu1_last_0" operation_key="apc_snmp_node2_psu1_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="21:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;21:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="28" rc-code="0" op-status="0" interval="0" last-rc-change="1596077509" last-run="1596077509" exec-time="808" queue-time="0" op-digest="e4739b474ee5043eaf7233ee12ee51d3" op-secure-params=" password passwd " op-secure-digest="3f31fc0be92206a110435411ffb3caf8"/>
<lrm_rsc_op id="apc_snmp_node2_psu1_monitor_60000" operation_key="apc_snmp_node2_psu1_monitor_60000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="22:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;22:0:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="31" rc-code="0" op-status="0" interval="60000" last-rc-change="1596077509" exec-time="766" queue-time="0" op-digest="69497c1e46db98fb718209f7a6a06515" op-secure-params=" password passwd " op-secure-digest="3f31fc0be92206a110435411ffb3caf8"/>
</lrm_resource>
<lrm_resource id="apc_snmp_node2_psu2" type="fence_apc_snmp" class="stonith">
<lrm_rsc_op id="apc_snmp_node2_psu2_last_0" operation_key="apc_snmp_node2_psu2_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="6:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:7;6:0:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="25" rc-code="7" op-status="0" interval="0" last-rc-change="1596077509" last-run="1596077509" exec-time="0" queue-time="0" op-digest="f3b985aa75b8f5fa0df015dc0b03b1f1" op-secure-params=" password passwd " op-secure-digest="26e92809fff4cf6b4cd47ff641d8276a"/>
</lrm_resource>
<lrm_resource id="delay_node1" type="fence_delay" class="stonith">
<lrm_rsc_op id="delay_node1_last_0" operation_key="delay_node1_start_0" operation="start" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="21:13:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;21:13:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="54" rc-code="0" op-status="0" interval="0" last-rc-change="1596080690" last-run="1596080690" exec-time="16" queue-time="0" op-digest="cc9e9045724a0f58a4c1e20e87fc27e0"/>
<lrm_rsc_op id="delay_node1_monitor_60000" operation_key="delay_node1_monitor_60000" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="22:13:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:0;22:13:0:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="55" rc-code="0" op-status="0" interval="60000" last-rc-change="1596080690" exec-time="15" queue-time="0" op-digest="76803906e86431fd72b35b182101783d"/>
</lrm_resource>
<lrm_resource id="delay_node2" type="fence_delay" class="stonith">
<lrm_rsc_op id="delay_node2_last_0" operation_key="delay_node2_monitor_0" operation="monitor" crm-debug-origin="do_update_resource" crm_feature_set="3.3.0" transition-key="8:14:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" transition-magic="0:7;8:14:7:b04a8d49-a133-4cd6-9d7e-6feeb76c5dcf" exit-reason="" on_node="mk-a02n01" call-id="59" rc-code="7" op-status="0" interval="0" last-rc-change="1596080694" last-run="1596080694" exec-time="0" queue-time="0" op-digest="3c18f0bcefeff3c4b79dda97eed85b65"/>
</lrm_resource>
</lrm_resources>
</lrm>
</node_state>
</status>
</cib>
';
$anvil->Cluster->parse_cib({
debug => 2,
cib => $xml,
});

Loading…
Cancel
Save