Fence na: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
(2 intermediate revisions by the same user not shown) | |||
Line 3: | Line 3: | ||
This is the core fence agent that exists in <span class="code">/sbin/</span>. | This is the core fence agent that exists in <span class="code">/sbin/</span>. | ||
* Download the [http://nodeassassin.org/files/sbin/fence_na source code]. | |||
<source lang="perl"> | <source lang="perl"> | ||
#!/usr/bin/perl | #!/usr/bin/perl | ||
Line 8: | Line 9: | ||
# Node Assassin - Fence Agent | # Node Assassin - Fence Agent | ||
# Digimer; digimer@alteeve.com | # Digimer; digimer@alteeve.com | ||
# | # Jun. 27, 2010 | ||
# Version: 1.1. | # Version: 1.1.5 | ||
# | |||
# This software is released under the GPL v2. See the LICENSE file in the | |||
# configuration directory for a copy of the GPL v2. | |||
# | # | ||
# Bugs; | # Bugs; | ||
# - None known, many expected | # - None known, many expected | ||
# | # | ||
# Play safe! | # Play safe! | ||
use strict; | use strict; | ||
use warnings; | use warnings; | ||
# Load | |||
require '/etc/ | # Load our library. | ||
# | require '/etc/fence_na/fence_na.lib'; | ||
# IO::Handle is used for logging and Net::Telnet is used for communicating with | |||
# the Node Assassin(s). | |||
use IO::Handle; | use IO::Handle; | ||
use Net::Telnet; | use Net::Telnet; | ||
# | # 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. | |||
# Please see '/etc/na/fence_na.conf' for details on each option. | |||
my $conf={ | my $conf={ | ||
'system' => { | 'system' => { | ||
max_valid_state => 3, | max_valid_state => 3, | ||
conf_file => "/etc/ | conf_file => "/etc/fence_na/fence_na.conf", | ||
quiet => "", | quiet => "", | ||
version => 0, | version => 0, | ||
list => "", | list => "", | ||
monitor => "", | monitor => "", | ||
na_id => 0, | na_id => 0, | ||
got_cla => 0, # This is set if command line arguments are read. | got_cla => 0, # This is set if command line arguments are read. | ||
debug => 0, | |||
}, | }, | ||
na => { | na => { | ||
ipaddr => "", | ipaddr => "", | ||
tcp_port => "", | tcp_port => "238", | ||
port => " | port => "", | ||
login => "", | login => "", | ||
passwd => "", | passwd => "", | ||
Line 159: | Line 61: | ||
handle => "", | handle => "", | ||
max_node => 0, | max_node => 0, | ||
set_state => [], # This | set_state => [], # This array will store the states to set based on the action passed for the proper ports. | ||
} | } | ||
}; | }; | ||
# This method can't pass in the '$log' handle, obviously, as it does not yet | # This method can't pass in the '$log' handle, obviously, as it does not yet | ||
# exist. | # exist. | ||
Line 168: | Line 71: | ||
# Log file for output. | # Log file for output. | ||
my $log=IO::Handle->new(); | my $log=IO::Handle->new(); | ||
print "Opening: [$conf->{'system'}{'log'}] for logging.\n" if $conf->{'system'}{debug}; | |||
open ($log, ">$conf->{'system'}{'log'}") || die "Failed to open: [$conf->{'system'}{'log'}] for writing; Error: $!\n"; | open ($log, ">$conf->{'system'}{'log'}") || die "Failed to open: [$conf->{'system'}{'log'}] for writing; Error: $!\n"; | ||
# Set STDOUT and $log to hot. | # Set STDOUT and $log to hot (unbuffered) output. | ||
if (1) | if (1) | ||
{ | { | ||
Line 188: | Line 92: | ||
($bad)=read_stdin($conf, $log, $bad); | ($bad)=read_stdin($conf, $log, $bad); | ||
# This makes sure the node ID is zero-padded or '00'. | # This makes sure the node ID is either zero-padded or '00'. | ||
$conf->{na}{port}=$conf->{na}{port} ? $conf->{na}{port}=sprintf("%02d", $conf->{na}{port}) : "00"; | $conf->{na}{port}=$conf->{na}{port} ? $conf->{na}{port}=sprintf("%02d", $conf->{na}{port}) : "00"; | ||
record($conf, $log, "Will use port: [$conf->{na}{port}]\n") if $conf->{'system'}{debug}; | |||
# Find the TCP port from the config file. | # Find the TCP port from the config file. | ||
Line 198: | Line 102: | ||
{ | { | ||
$conf->{'system'}{na_id}=$i; | $conf->{'system'}{na_id}=$i; | ||
record($conf, $log, __LINE__."; system::na_id: [$conf->{'system'}{na_id}]\n") if $conf->{'system'}{debug}; | |||
$conf->{na}{tcp_port}=$conf->{na}{$i}{tcp_port}; | $conf->{na}{tcp_port}=$conf->{na}{$i}{tcp_port}; | ||
record($conf, $log, __LINE__."; na::tcp_port: [$conf->{na}{tcp_port}]\n") if $conf->{'system'}{debug}; | |||
$conf->{na}{na_name}=$conf->{na}{$i}{na_name} ? $conf->{na}{$i}{na_name} : "Node Assassin #$i"; | $conf->{na}{na_name}=$conf->{na}{$i}{na_name} ? $conf->{na}{$i}{na_name} : "Node Assassin #$i"; | ||
record($conf, $log, __LINE__."; na::na_name: [$conf->{na}{na_name}]\n") if $conf->{'system'}{debug}; | |||
$conf->{na}{max_nodes}=$conf->{na}{$i}{max_nodes}; | $conf->{na}{max_nodes}=$conf->{na}{$i}{max_nodes}; | ||
record($conf, $log, __LINE__."; na::max_nodes: [$conf->{na}{max_nodes}]\n") if $conf->{'system'}{debug}; | |||
} | } | ||
} | } | ||
die "Exiting on errors.\n" if $bad; | die "Exiting on errors.\n" if $bad; | ||
my @ny=("no", "yes"); | |||
record($conf, $log, "Node Assassin: . [$conf->{na}{ipaddr}].\n"); | record($conf, $log, "Node Assassin: . [$conf->{na}{ipaddr}].\n"); | ||
record($conf, $log, "TCP Port: ...... [$conf->{na}{tcp_port}].\n"); | record($conf, $log, "TCP Port: ...... [$conf->{na}{tcp_port}].\n"); | ||
Line 215: | Line 120: | ||
record($conf, $log, "Password: ...... [$conf->{na}{passwd}].\n"); | record($conf, $log, "Password: ...... [$conf->{na}{passwd}].\n"); | ||
record($conf, $log, "Action: ........ [$conf->{na}{action}].\n"); | record($conf, $log, "Action: ........ [$conf->{na}{action}].\n"); | ||
record($conf, $log, "Version Request: [$conf->{'system'}{version}].\n"); | record($conf, $log, "Version Request: [".$ny[$conf->{'system'}{version}]."].\n"); | ||
record($conf, $log, "Done reading args.\n"); | record($conf, $log, "Done reading args.\n"); | ||
# If I've been asked to show the version information, do so and then exit. | # If I've been asked to show the version information, do so and then exit. | ||
record($conf, $log, "Version: ..... [$conf->{'system'}{version}].\n") if $conf->{'system'}{debug}; | |||
if ($conf->{'system'}{version}) | if ($conf->{'system'}{version}) | ||
{ | { | ||
Line 234: | Line 139: | ||
if (($conf->{na}{login} ne $conf->{'system'}{username}) or ($conf->{na}{passwd} ne $conf->{'system'}{password})) | if (($conf->{na}{login} ne $conf->{'system'}{username}) or ($conf->{na}{passwd} ne $conf->{'system'}{password})) | ||
{ | { | ||
record($conf, $log, "Username and/or password | record($conf, $log, "Username and/or password invalid. Did you use the command line switches properly?\n"); | ||
do_exit($conf, $log, 8); | do_exit($conf, $log, 8); | ||
} | } | ||
Line 242: | Line 147: | ||
############################################################################### | ############################################################################### | ||
# When asked to 'monitor' or 'list'. being multi-port, this will return a CSV | |||
# of nodes and their aliases where found in the config file. | |||
record($conf, $log, "Action: ........ [$conf->{na}{action}].\n") if $conf->{'system'}{debug}; | |||
# When asked to 'monitor' or 'list', | |||
# | |||
if (($conf->{na}{action} eq "monitor") or ($conf->{na}{action} eq "list")) | if (($conf->{na}{action} eq "monitor") or ($conf->{na}{action} eq "list")) | ||
{ | { | ||
record($conf, $log, "Calling the 'show_list' function.\n"); | record($conf, $log, "Calling the 'show_list' function.\n") if $conf->{'system'}{debug}; | ||
show_list($conf, $log | show_list($conf, $log); | ||
do_exit($conf, $log, 0); | do_exit($conf, $log, 0); | ||
} | } | ||
Line 264: | Line 159: | ||
# If I made it this far, I am setting a state. Sort out what state from the | # If I made it this far, I am setting a state. Sort out what state from the | ||
# values in my conf->{na} hash. | # values in my conf->{na} hash. | ||
record($conf, $log, "Setting node: [$conf->{na}{port}] to action: [$conf->{na}{action}] using the Node Assassin: [$conf->{na}{ipaddr}] using the login: [$conf->{na}{login}]\n") if $conf->{'system'}{debug}; | |||
# Convert the action into Node Assassin protocol arguments. | # Convert the action into Node Assassin protocol arguments. | ||
Line 271: | Line 166: | ||
# Now execute the action plan. | # Now execute the action plan. | ||
my $exit_code=do_actions($conf, $log); | my $exit_code=do_actions($conf, $log); | ||
record($conf, $log, "All calls complete, exiting.\n") if $conf->{'system'}{debug}; | |||
# Cleanup and exit. | # Cleanup and exit. |
Latest revision as of 17:03, 25 August 2010
Node Assassin :: Fence na |
This is the core fence agent that exists in /sbin/.
- Download the source code.
#!/usr/bin/perl
#
# Node Assassin - Fence Agent
# Digimer; digimer@alteeve.com
# Jun. 27, 2010
# Version: 1.1.5
#
# 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, many expected
#
# Play safe!
use strict;
use warnings;
# Load our library.
require '/etc/fence_na/fence_na.lib';
# IO::Handle is used for logging and Net::Telnet is used for communicating with
# the Node Assassin(s).
use IO::Handle;
use Net::Telnet;
# 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.
# Please see '/etc/na/fence_na.conf' for details on each option.
my $conf={
'system' => {
max_valid_state => 3,
conf_file => "/etc/fence_na/fence_na.conf",
quiet => "",
version => 0,
list => "",
monitor => "",
na_id => 0,
got_cla => 0, # This is set if command line arguments are read.
debug => 0,
},
na => {
ipaddr => "",
tcp_port => "238",
port => "",
login => "",
passwd => "",
port => "",
set_state => "",
passwd_script => "",
action => "",
agent => "", # This is only used by 'fenced'
na_name => "", # This is used for the 'list' function.
handle => "",
max_node => 0,
set_state => [], # This array will store the states to set based on the action passed for the proper ports.
}
};
# This method can't pass in the '$log' handle, obviously, as it does not yet
# exist.
read_conf($conf);
# Log file for output.
my $log=IO::Handle->new();
print "Opening: [$conf->{'system'}{'log'}] for logging.\n" if $conf->{'system'}{debug};
open ($log, ">$conf->{'system'}{'log'}") || die "Failed to open: [$conf->{'system'}{'log'}] for writing; Error: $!\n";
# Set STDOUT and $log to hot (unbuffered) output.
if (1)
{
select $log;
$|=1;
select STDOUT;
$|=1;
}
# If this gets set in the next two function, the agent will exit.
my $bad=0;
# Read in arguments from the command line.
($bad)=read_cla($conf, $log, $bad);
# Now read in arguments from STDIN, which is how 'fenced' passes arguments.
($bad)=read_stdin($conf, $log, $bad);
# This makes sure the node ID is either zero-padded or '00'.
$conf->{na}{port}=$conf->{na}{port} ? $conf->{na}{port}=sprintf("%02d", $conf->{na}{port}) : "00";
record($conf, $log, "Will use port: [$conf->{na}{port}]\n") if $conf->{'system'}{debug};
# Find the TCP port from the config file.
foreach my $i (1..$conf->{'system'}{na_num})
{
if ((lc($conf->{na}{$i}{ipaddr}) eq lc($conf->{na}{ipaddr})))
{
$conf->{'system'}{na_id}=$i;
record($conf, $log, __LINE__."; system::na_id: [$conf->{'system'}{na_id}]\n") if $conf->{'system'}{debug};
$conf->{na}{tcp_port}=$conf->{na}{$i}{tcp_port};
record($conf, $log, __LINE__."; na::tcp_port: [$conf->{na}{tcp_port}]\n") if $conf->{'system'}{debug};
$conf->{na}{na_name}=$conf->{na}{$i}{na_name} ? $conf->{na}{$i}{na_name} : "Node Assassin #$i";
record($conf, $log, __LINE__."; na::na_name: [$conf->{na}{na_name}]\n") if $conf->{'system'}{debug};
$conf->{na}{max_nodes}=$conf->{na}{$i}{max_nodes};
record($conf, $log, __LINE__."; na::max_nodes: [$conf->{na}{max_nodes}]\n") if $conf->{'system'}{debug};
}
}
die "Exiting on errors.\n" if $bad;
my @ny=("no", "yes");
record($conf, $log, "Node Assassin: . [$conf->{na}{ipaddr}].\n");
record($conf, $log, "TCP Port: ...... [$conf->{na}{tcp_port}].\n");
record($conf, $log, "Node: .......... [$conf->{na}{port}].\n");
record($conf, $log, "Login: ......... [$conf->{na}{login}].\n");
record($conf, $log, "Password: ...... [$conf->{na}{passwd}].\n");
record($conf, $log, "Action: ........ [$conf->{na}{action}].\n");
record($conf, $log, "Version Request: [".$ny[$conf->{'system'}{version}]."].\n");
record($conf, $log, "Done reading args.\n");
# If I've been asked to show the version information, do so and then exit.
record($conf, $log, "Version: ..... [$conf->{'system'}{version}].\n") if $conf->{'system'}{debug};
if ($conf->{'system'}{version})
{
version($conf, $log);
do_exit($conf, $log, 0);
}
# Connect to the Node Assassin.
connect_to_na($conf, $log);
# Validate credentials.
# NOTE: Checking before the telnet fails on the exit. Also, this will be moved
# into the Node Assassin soon anyway.
if (($conf->{na}{login} ne $conf->{'system'}{username}) or ($conf->{na}{passwd} ne $conf->{'system'}{password}))
{
record($conf, $log, "Username and/or password invalid. Did you use the command line switches properly?\n");
do_exit($conf, $log, 8);
}
###############################################################################
# What do? #
###############################################################################
# When asked to 'monitor' or 'list'. being multi-port, this will return a CSV
# of nodes and their aliases where found in the config file.
record($conf, $log, "Action: ........ [$conf->{na}{action}].\n") if $conf->{'system'}{debug};
if (($conf->{na}{action} eq "monitor") or ($conf->{na}{action} eq "list"))
{
record($conf, $log, "Calling the 'show_list' function.\n") if $conf->{'system'}{debug};
show_list($conf, $log);
do_exit($conf, $log, 0);
}
# If I made it this far, I am setting a state. Sort out what state from the
# values in my conf->{na} hash.
record($conf, $log, "Setting node: [$conf->{na}{port}] to action: [$conf->{na}{action}] using the Node Assassin: [$conf->{na}{ipaddr}] using the login: [$conf->{na}{login}]\n") if $conf->{'system'}{debug};
# Convert the action into Node Assassin protocol arguments.
process_action($conf, $log);
# Now execute the action plan.
my $exit_code=do_actions($conf, $log);
record($conf, $log, "All calls complete, exiting.\n") if $conf->{'system'}{debug};
# Cleanup and exit.
do_exit($conf, $log, $exit_code);
Input, advice, complaints and meanderings all welcome! | ||||
Digimer | digimer@alteeve.ca | https://alteeve.ca/w | legal stuff: | |
All info is provided "As-Is". Do not use anything here unless you are willing and able to take resposibility for your own actions. © 1997-2013 | ||||
Naming credits go to Christopher Olah! | ||||
In memory of Kettle, Tonia, Josh, Leah and Harvey. In special memory of Hannah, Jack and Riley. |