Fence na
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. |