* Got the node/dr host initialization form to the point where it can test access and decide if it should show the Red Hat account form. Decided that for M3, node/dr host setup will now be a four-stage process; initial install (over PXE), initialization (install the proper anvil-{node,dr} RPM and connect to the database), setup/map the network, and then add to an Anvil! pair.
* Updated striker to no longer try to SSH to a remote machine. To enable this, we'd have to give apache a shell and an SSH key, which is dumb and dangerous when considered. * Created tools/striker-get-peer-data which is meant to be invoked as the 'admin' user (via a setuid c-wrapper). It collects basic data about a target machine and reports what it finds on STDOUT. It gets the password for the target via the database. * Updated anvil-daemon to check/create/update setuid c-wrapper(s), which for now is limited to call_striker-initialize-host. * Created Anvil/Tools/Striker.pm to store Striker web-specific methods, including get_peer_data() which calls tools/striker-initialize-host via the setuid admin call_striker-initialize-host c-wrapper. * In order to allow striker via apache to read a peer's anvil.version, which it can no longer do over SSH, any connection to a peer where the anvil.version is read is cached as /etc/anvil/anvil.<peer>.version. When Get->anvil_version is called as 'apache', this file is read instead. * Updated Database->resync_databases() and ->_find_behind_databases() to ignore the 'states' table. * Created tools/striker-initialize-host which will be called as a job to initialize a node/dr host. Signed-off-by: Digimer <digimer@alteeve.ca>main
parent
6f74ca376b
commit
badaa39b7a
17 changed files with 827 additions and 125 deletions
@ -0,0 +1,210 @@ |
|||||||
|
package Anvil::Tools::Striker; |
||||||
|
# |
||||||
|
# This module contains methods used to handle common Striker (webUI) tasks. |
||||||
|
# |
||||||
|
|
||||||
|
use strict; |
||||||
|
use warnings; |
||||||
|
use Data::Dumper; |
||||||
|
use Scalar::Util qw(weaken isweak); |
||||||
|
|
||||||
|
our $VERSION = "3.0.0"; |
||||||
|
my $THIS_FILE = "Striker.pm"; |
||||||
|
|
||||||
|
### Methods; |
||||||
|
# |
||||||
|
|
||||||
|
=pod |
||||||
|
|
||||||
|
=encoding utf8 |
||||||
|
|
||||||
|
=head1 NAME |
||||||
|
|
||||||
|
Anvil::Tools::Striker |
||||||
|
|
||||||
|
Provides all methods related to the Striker WebUI. |
||||||
|
|
||||||
|
=head1 SYNOPSIS |
||||||
|
|
||||||
|
use Anvil::Tools; |
||||||
|
|
||||||
|
# Get a common object handle on all Anvil::Tools modules. |
||||||
|
my $anvil = Anvil::Tools->new(); |
||||||
|
|
||||||
|
# Access to methods using '$anvil->Striker->X'. |
||||||
|
# |
||||||
|
# Example using 'system_call()'; |
||||||
|
|
||||||
|
|
||||||
|
=head1 METHODS |
||||||
|
|
||||||
|
Methods in this module; |
||||||
|
|
||||||
|
=cut |
||||||
|
sub new |
||||||
|
{ |
||||||
|
my $class = shift; |
||||||
|
my $self = {}; |
||||||
|
|
||||||
|
bless $self, $class; |
||||||
|
|
||||||
|
return ($self); |
||||||
|
} |
||||||
|
|
||||||
|
# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more |
||||||
|
# sense in this case to think of it as a parent. |
||||||
|
sub parent |
||||||
|
{ |
||||||
|
my $self = shift; |
||||||
|
my $parent = shift; |
||||||
|
|
||||||
|
$self->{HANDLE}{TOOLS} = $parent if $parent; |
||||||
|
|
||||||
|
# Defend against memory leads. See Scalar::Util'. |
||||||
|
if (not isweak($self->{HANDLE}{TOOLS})) |
||||||
|
{ |
||||||
|
weaken($self->{HANDLE}{TOOLS}); |
||||||
|
} |
||||||
|
|
||||||
|
return ($self->{HANDLE}{TOOLS}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
############################################################################################################# |
||||||
|
# Public methods # |
||||||
|
############################################################################################################# |
||||||
|
|
||||||
|
=head2 get_peer_data |
||||||
|
|
||||||
|
This calls the C<< call_striker-get-peer-data >> program to try to connect to the target (as C<< root >>). If successful, it will return the target's host UUID (either by reading C<< /etc/anvil/host.uuid >> if it exists, or using C<< dmidecode >> if not). |
||||||
|
|
||||||
|
This method will return a string variable with C<< 1 >> if the peer was reached, or C<< 0 >> if it was not. It will also return a hash reference containing the collected data. |
||||||
|
|
||||||
|
my ($connected, $data) = $anvil->Striker->get_peer_data({target => 10.255.1.218, password => "Initial1"}); |
||||||
|
if ($connected) |
||||||
|
{ |
||||||
|
print "Hostname: [".$data->{host_name}."], host UUID: [".$data->{host_uuid}."]\n"; |
||||||
|
} |
||||||
|
|
||||||
|
Parameters; |
||||||
|
|
||||||
|
=head3 password (required) |
||||||
|
|
||||||
|
This is the target machine's C<< root >> password. |
||||||
|
|
||||||
|
=head3 port (optional, default 22) |
||||||
|
|
||||||
|
This is the TCP port to use when connecting to the target |
||||||
|
|
||||||
|
=head3 target (required, IPv4 address) |
||||||
|
|
||||||
|
This is the current IP address of the target machine. |
||||||
|
|
||||||
|
=cut |
||||||
|
sub get_peer_data |
||||||
|
{ |
||||||
|
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 => "Striker->get_peer_data()" }}); |
||||||
|
|
||||||
|
my $target = defined $parameter->{target} ? $parameter->{target} : ""; |
||||||
|
my $password = defined $parameter->{password} ? $parameter->{password} : ""; |
||||||
|
my $port = defined $parameter->{port} ? $parameter->{port} : 22; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
target => $target, |
||||||
|
password => $anvil->Log->is_secure($password), |
||||||
|
port => $port, |
||||||
|
}}); |
||||||
|
|
||||||
|
# Store the password. |
||||||
|
my $connected = 0; |
||||||
|
my $data = { |
||||||
|
host_uuid => "", |
||||||
|
host_name => "", |
||||||
|
host_os => "", |
||||||
|
os_registered => "", |
||||||
|
}; |
||||||
|
|
||||||
|
if (not $target) |
||||||
|
{ |
||||||
|
# No target... |
||||||
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Striker->get_peer_data()", parameter => "target" }}); |
||||||
|
return($connected, $data); |
||||||
|
} |
||||||
|
|
||||||
|
my $state_uuid = $anvil->Database->insert_or_update_states({ |
||||||
|
debug => $debug, |
||||||
|
file => $THIS_FILE, |
||||||
|
line => __LINE__, |
||||||
|
state_name => "peer::".$target."::password", |
||||||
|
state_note => $password, |
||||||
|
uuid => $anvil->data->{sys}{host_uuid}, # Only write to our DB, no reason to store elsewhere |
||||||
|
}); |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { state_uuid => $state_uuid }}); |
||||||
|
my ($output, $error, $return_code) = $anvil->System->call({ |
||||||
|
debug => $debug, |
||||||
|
shell_call => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}." --target root\@".$target.":".$port." --state-uuid ".$state_uuid, |
||||||
|
}); |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||||
|
output => $output, |
||||||
|
error => $error, |
||||||
|
return_code => $return_code, |
||||||
|
}}); |
||||||
|
|
||||||
|
# Pull out the details |
||||||
|
foreach my $line (split/\n/, $output) |
||||||
|
{ |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); |
||||||
|
if ($line =~ /connected=(.*)$/) |
||||||
|
{ |
||||||
|
# We collect this, but apparently not for any real reason... |
||||||
|
$connected = $1; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connected => $connected }}); |
||||||
|
} |
||||||
|
if ($line =~ /host_name=(.*)$/) |
||||||
|
{ |
||||||
|
# We collect this, but apparently not for any real reason... |
||||||
|
$data->{host_name} = $1; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'data->{host_name}' => $data->{host_name} }}); |
||||||
|
} |
||||||
|
if ($line =~ /host_uuid=(.*)$/) |
||||||
|
{ |
||||||
|
$data->{host_uuid} = $1; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'data->{host_uuid}' => $data->{host_uuid} }}); |
||||||
|
} |
||||||
|
if ($line =~ /host_os=(.*)$/) |
||||||
|
{ |
||||||
|
$data->{host_os} = $1; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'data->{host_os}' => $data->{host_os} }}); |
||||||
|
} |
||||||
|
if ($line =~ /os_registered=(.*)$/) |
||||||
|
{ |
||||||
|
$data->{os_registered} = $1; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'data->{os_registered}' => $data->{os_registered} }}); |
||||||
|
} |
||||||
|
} |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||||
|
connected => $connected, |
||||||
|
'data->{host_name}' => $data->{host_name}, |
||||||
|
'data->{host_uuid}' => $data->{host_uuid}, |
||||||
|
'data->{host_os}' => $data->{host_os}, |
||||||
|
'data->{os_registered}' => $data->{os_registered}, |
||||||
|
}}); |
||||||
|
|
||||||
|
# Make sure the database entry is gone (striker-get-peer-data should have removed it, but lets be safe). |
||||||
|
my $query = "DELETE FROM states WHERE state_name = ".$anvil->Database->quote("peer::".$target."::password").";"; |
||||||
|
$anvil->Database->write({uuid => $anvil->data->{sys}{host_uuid}, debug => 3, query => $query, source => $THIS_FILE, line => __LINE__}); |
||||||
|
|
||||||
|
if (not $anvil->Validate->is_uuid({uuid => $data->{host_uuid}})) |
||||||
|
{ |
||||||
|
$data->{host_uuid} = ""; |
||||||
|
} |
||||||
|
|
||||||
|
return($connected, $data); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1; |
After Width: | Height: | Size: 25 KiB |
@ -0,0 +1,51 @@ |
|||||||
|
#!/usr/bin/perl |
||||||
|
# |
||||||
|
# This program is setuid 'admin' and calls a (new) peer to read its hostname and system UUID. It takes the |
||||||
|
# target's password in via a file. |
||||||
|
# |
||||||
|
# Exit codes; |
||||||
|
# 0 = Normal exit. |
||||||
|
# 1 = No database connection. |
||||||
|
# 2 = Password not found in the database. |
||||||
|
# 3 = Peer not accessible |
||||||
|
# 4 = Unable to find the peer's host UUID |
||||||
|
# 5 = |
||||||
|
# |
||||||
|
|
||||||
|
use strict; |
||||||
|
use warnings; |
||||||
|
use Anvil::Tools; |
||||||
|
|
||||||
|
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; |
||||||
|
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; |
||||||
|
if (($running_directory =~ /^\./) && ($ENV{PWD})) |
||||||
|
{ |
||||||
|
$running_directory =~ s/^\./$ENV{PWD}/; |
||||||
|
} |
||||||
|
|
||||||
|
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. |
||||||
|
$| = 1; |
||||||
|
|
||||||
|
my $anvil = Anvil::Tools->new(); |
||||||
|
$anvil->Log->level({set => 2}); |
||||||
|
$anvil->Log->secure({set => 1}); |
||||||
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); |
||||||
|
|
||||||
|
# Read switches (target ([user@]host[:port]) and the file with the target's password. |
||||||
|
$anvil->data->{switches}{target} = ""; |
||||||
|
$anvil->data->{switches}{'state-uuid'} = ""; |
||||||
|
$anvil->Get->switches; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { |
||||||
|
'switches::target' => $anvil->data->{switches}{target}, |
||||||
|
'switches::state-uuid' => $anvil->data->{switches}{'state-uuid'}, |
||||||
|
}}); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$anvil->nice_exit({code => 0}); |
||||||
|
|
||||||
|
|
||||||
|
############################################################################################################# |
||||||
|
# Functions # |
||||||
|
############################################################################################################# |
Loading…
Reference in new issue