Local modifications to ClusterLabs/Anvil by Alteeve
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

343 lines
12 KiB

#!/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. If the password is
# passed directly, it will be used. Otherwise, the password will be read from the database.
$anvil->data->{switches}{target} = "";
$anvil->data->{switches}{'state-uuid'} = "";
$anvil->data->{switches}{password} = "";
$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'},
'switches::password' => $anvil->Log->is_secure($anvil->data->{switches}{password}),
}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0435", variables => {
program => $THIS_FILE,
real_user => getpwuid($<),
real_uid => $<,
effective_user => getpwuid($>),
effective_uid => $>,
}});
$anvil->data->{target}{user} = "admin";
$anvil->data->{target}{host} = $anvil->data->{switches}{target};
$anvil->data->{target}{port} = 22;
$anvil->data->{target}{password} = get_password($anvil);
if ($anvil->data->{target}{host} =~ /^(.*?)@/)
{
$anvil->data->{target}{user} = $1;
$anvil->data->{target}{host} =~ s/^(.*?)@//;
}
if ($anvil->data->{target}{host} =~ /:(\d+)$/)
{
$anvil->data->{target}{port} = $1;
$anvil->data->{target}{host} =~ s/:(\d+)$//;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'target::user' => $anvil->data->{target}{user},
'target::target' => $anvil->data->{target}{host},
'target::port' => $anvil->data->{target}{port},
'target::password' => $anvil->Log->is_secure($anvil->data->{target}{password}),
}});
my ($host_uuid) = get_host_uuid($anvil);
my ($host_name) = get_host_name($anvil);
my ($host_os,, $os_registered) = get_host_os($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
host_name => $host_name,
host_os => $host_os,
os_registered => $os_registered,
}});
print "connected=1\n";
print "host_name=".$host_name."\n";
print "host_uuid=".$host_uuid."\n";
print "host_os=".$host_os."\n";
print "os_registered=".$os_registered."\n";
$anvil->nice_exit({code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
# This tries to read the target's OS
sub get_host_os
{
my ($anvil) = @_;
my $host_os = "unknown";
my $os_registered = "n/a";
# We can't assume that rsync exists, so we'll cat the file.
my $shell_call = "
if [ -e '".$anvil->data->{path}{data}{'redhat-release'}."' ];
then
".$anvil->data->{path}{exe}{cat}." ".$anvil->data->{path}{data}{'redhat-release'}."
fi;
";
my ($file_body, $error, $return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $shell_call,
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
file_body => $file_body,
error => $error,
return_code => $return_code,
}});
$file_body =~ s/\n$//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_body => $file_body }});
if ($file_body)
{
if ($file_body =~ /Red Hat .*? release (\d+\.\d+) /)
{
$host_os = "rhel ".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_os => $host_os }});
}
}
# If the OS is 'rhel', see if it is registered.
if ($host_os =~ /^rhel /)
{
# Is it subscribed? This isn't the best call to make, but it seems to be the one that returns
# the fastest. Return code of '0' is registered, return code of '1' is not or not verified.
my ($output, $error, $return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{'subscription-manager'}." identity",
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
output => $output,
error => $error,
return_code => $return_code,
}});
# Possible output;
=cut
system identity: 3a9065a1-625a-48e1-86f4-97a3eac4b730
name: el8-striker01.digimer.ca
org name: xxx
org ID: yyy
# rc:0
This system is not yet registered. Try 'subscription-manager register --help' for more information.
# rc:1
Network error, unable to connect to server. Please see /var/log/rhsm/rhsm.log for more information.
# rc:70
=cut
if ($return_code eq "0")
{
$os_registered = "yes";
}
elsif ($return_code eq "1")
{
$os_registered = "no";
}
elsif ($return_code eq "70")
{
# Unable to check, maybe, maybe not?
$os_registered = "offline";
}
}
return($host_os, $os_registered);
}
# This tries to read the target's UUID either via host.uuid or via dmidecode.
sub get_host_name
{
my ($anvil) = @_;
my ($host_name, $error, $return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{hostnamectl}." --static",
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_name => $host_name,
error => $error,
return_code => $return_code,
}});
return($host_name);
}
# This tries to read the target's UUID either via host.uuid or via dmidecode.
sub get_host_uuid
{
my ($anvil) = @_;
# This is the first thing called, so start by verifying we can talk to the target at all.
my $access = $anvil->Remote->test_access({
debug => 2,
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});
if (not $access)
{
print "connected=0\n";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0069", variables => {
host => $anvil->data->{target}{user}.'@'.$anvil->data->{target}{host}.':'.$anvil->data->{target}{port},
}});
$anvil->nice_exit({exit_code => 3});
}
# Try to read the host.uuid file on the target, if possible.
# We can't assume that rsync exists, so we'll cat the file.
my $shell_call = "
if [ -e '".$anvil->data->{path}{data}{host_uuid}."' ];
then
".$anvil->data->{path}{exe}{cat}." ".$anvil->data->{path}{data}{host_uuid}."
fi;
";
my ($file_body, $error, $return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $shell_call,
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
file_body => $file_body,
error => $error,
return_code => $return_code,
}});
$file_body =~ s/\n$//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_body => $file_body }});
my $host_uuid = "";
if ((not $file_body) or (not $anvil->Validate->is_uuid({uuid => $file_body})))
{
# No good, Try dmidecode.
my ($output, $error, $return_code) = $anvil->Remote->call({
debug => 2,
shell_call => $anvil->data->{path}{exe}{dmidecode}." --string system-uuid",
user => $anvil->data->{target}{user},
target => $anvil->data->{target}{host},
port => $anvil->data->{target}{port},
password => $anvil->data->{target}{password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
output => $output,
error => $error,
return_code => $return_code,
}});
if ($anvil->Validate->is_uuid({uuid => $output}))
{
# Got it.
$host_uuid = $output;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
}
}
else
{
$host_uuid = $file_body;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
}
# Exit out if I failed to get the host's UUID.
if (not $host_uuid)
{
print "connected=0\n";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0070", variables => {
host => $anvil->data->{target}{user}.'@'.$anvil->data->{target}{host}.':'.$anvil->data->{target}{port},
}});
$anvil->nice_exit({exit_code => 4});
}
return($host_uuid);
}
# This reads in the password from the password file, if possible.
sub get_password
{
my ($anvil) = @_;
# If we were given the password directly, use it.
if ($anvil->data->{switches}{password})
{
return($anvil->data->{switches}{password});
}
# We'll pick up the peer's password from the database.
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
# No databases, exit.
print "connected=0\n";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0067"});
$anvil->nice_exit({exit_code => 1});
}
my $query = "SELECT state_note FROM states WHERE state_uuid=".$anvil->Database->quote($anvil->data->{switches}{'state-uuid'}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
my $password = $anvil->Database->query({uuid => $anvil->data->{sys}{host_uuid}, debug => 3, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$password = "" if not defined $password;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { password => $password }});
if (not $password)
{
# Well poo.
print "connected=0\n";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0068"});
$anvil->nice_exit({exit_code => 2});
}
else
{
# We have the password. Delete the entry now.
my $query = "DELETE FROM states WHERE state_uuid=".$anvil->Database->quote($anvil->data->{switches}{'state-uuid'}).";";
$anvil->Database->write({uuid => $anvil->data->{sys}{host_uuid}, debug => 3, query => $query, source => $THIS_FILE, line => __LINE__});
}
return($password);
}