diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 71d5a770..b1f9f20a 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -48,6 +48,7 @@ use Anvil::Tools::Job; use Anvil::Tools::Log; use Anvil::Tools::Remote; use Anvil::Tools::Server; +use Anvil::Tools::Striker; use Anvil::Tools::Storage; use Anvil::Tools::System; use Anvil::Tools::Template; @@ -127,6 +128,7 @@ sub new JOB => Anvil::Tools::Job->new(), REMOTE => Anvil::Tools::Remote->new(), SERVER => Anvil::Tools::Server->new(), + STRIKER => Anvil::Tools::Striker->new(), STORAGE => Anvil::Tools::Storage->new(), SYSTEM => Anvil::Tools::System->new(), TEMPLATE => Anvil::Tools::Template->new(), @@ -166,6 +168,7 @@ sub new $anvil->Job->parent($anvil); $anvil->Remote->parent($anvil); $anvil->Server->parent($anvil); + $anvil->Striker->parent($anvil); $anvil->Storage->parent($anvil); $anvil->System->parent($anvil); $anvil->Template->parent($anvil); @@ -535,6 +538,18 @@ sub Server return ($self->{HANDLE}{SERVER}); } +=head2 Striker + +Access the C methods via 'C<< $anvil->Striker->method >>'. + +=cut +sub Striker +{ + my $self = shift; + + return ($self->{HANDLE}{STRIKER}); +} + =head2 Storage Access the C methods via 'C<< $anvil->Storage->method >>'. @@ -975,6 +990,7 @@ sub _set_paths 'redhat-release' => "/etc/redhat-release", }, directories => { + anvil => "/etc/anvil", backups => "/root/anvil-backups", 'cgi-bin' => "/var/www/cgi-bin", firewalld_services => "/usr/lib/firewalld/services", @@ -1014,6 +1030,7 @@ sub _set_paths 'anvil-update-system' => "/usr/sbin/anvil-update-system", bridge => "/usr/sbin/bridge", 'call_striker-get-peer-data' => "/usr/sbin/call_striker-get-peer-data", + cat => "/usr/bin/cat", 'chmod' => "/usr/bin/chmod", 'chown' => "/usr/bin/chown", cibadmin => "/usr/sbin/cibadmin", @@ -1076,6 +1093,7 @@ sub _set_paths 'striker-prep-database' => "/usr/sbin/striker-prep-database", stty => "/usr/bin/stty", su => "/usr/bin/su", + 'subscription-manager' => "/usr/sbin/subscription-manager", systemctl => "/usr/bin/systemctl", timeout => "/usr/bin/timeout", touch => "/usr/bin/touch", diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 3667f43e..17577ba8 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -867,8 +867,9 @@ sub connect password => $password, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - remote_version => $remote_version, - local_version => $local_version, + 's1:host' => $host, + 's2:remote_version' => $remote_version, + 's3:local_version' => $local_version, }}); # TODO: Periodically, we fail to get the remote version. For now, we proceed if # everything else is OK. Might be better to pause a re-try... To be determined. @@ -5925,6 +5926,9 @@ sub resync_databases # 'sys::database::check_tables' foreach my $table (@{$anvil->data->{sys}{database}{check_tables}}) { + # We don't sync 'states' as it's transient and sometimes per-DB. + next if $table eq "states"; + # If the 'schema' is 'public', there is no table in the history schema. If there is a host # column, the resync will be restricted to entries from this host uuid. my $schema = $anvil->data->{sys}{database}{table}{$table}{schema}; @@ -6095,12 +6099,12 @@ sub resync_databases die $THIS_FILE." ".__LINE__."; This row's modified_date wasn't the first column returned in query: [$query]\n" if not $modified_date; die $THIS_FILE." ".__LINE__."; This row's UUID column: [$uuid_column] wasn't the second column returned in query: [$query]\n" if not $row_uuid; - # Record this in the unified and local hashes. # This table isn't restricted to given hosts. + # Record this in the unified and local hashes. $anvil->data->{db_data}{unified}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value; - $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value; + $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name} = $column_value; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "db_data::unified::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}::${column_name}" => $anvil->data->{db_data}{unified}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name}, - "db_data::${uuid}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}::${column_name}" => $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name}, + "db_data::${uuid}::${table}::modified_date::${modified_date}::${uuid_column}::${row_uuid}::${column_name}" => $anvil->data->{db_data}{$uuid}{$table}{modified_date}{$modified_date}{$uuid_column}{$row_uuid}{$column_name}, }}); } } @@ -6110,7 +6114,6 @@ sub resync_databases foreach my $modified_date (sort {$b cmp $a} keys %{$anvil->data->{db_data}{unified}{$table}{modified_date}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { modified_date => $modified_date }}); - foreach my $row_uuid (sort {$a cmp $b} keys %{$anvil->data->{db_data}{unified}{$table}{modified_date}{$modified_date}{$uuid_column}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { row_uuid => $row_uuid }}); @@ -6281,7 +6284,7 @@ sub resync_databases to_write => $to_write_count, host_name => $anvil->Get->host_name({host_uuid => $uuid}), }}); - $anvil->Database->write({uuid => $uuid, query => $merged, source => $THIS_FILE, line => __LINE__}); + $anvil->Database->write({debug => $debug, uuid => $uuid, query => $merged, source => $THIS_FILE, line => __LINE__}); undef $merged; } } @@ -6714,6 +6717,9 @@ sub _find_behind_databases # behind and a resync will be needed. foreach my $table (@{$anvil->data->{sys}{database}{check_tables}}) { + # We don't sync 'states' as it's transient and sometimes per-DB. + next if $table eq "states"; + # Does this table exist yet? my $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = 'public' AND table_name = ".$anvil->Database->quote($table).";"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); @@ -6811,6 +6817,9 @@ ORDER BY # databases. If it has, trigger a resync. foreach my $table (sort {$a cmp $b} keys %{$anvil->data->{sys}{database}{table}}) { + # We don't sync 'states' as it's transient and sometimes per-DB. + next if $table eq "states"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::table::${table}::last_updated" => $anvil->data->{sys}{database}{table}{$table}{last_updated}, "sys::database::table::${table}::row_count" => $anvil->data->{sys}{database}{table}{$table}{row_count}, diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 9d10b8f6..85247b6f 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -138,8 +138,27 @@ sub anvil_version # Is this a local call or a remote call? if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) { - # Remote call. - my $shell_call = " + # Remote call. If we're running as the apache user, we need to read the cached version for + # the peer. otherwise, after we read the version, will write the cached version. + my $user = getpwuid($<); + my $cache_file = $anvil->data->{path}{directories}{anvil}."/anvil.".$target.".version"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + cache_file => $cache_file, + user => $user, + }}); + if ($user eq "apache") + { + # Try to read the local cached version. + if (-e $cache_file) + { + # Read it in. + $version = $anvil->Storage->read_file({file => $cache_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }}); + } + } + else + { + my $shell_call = " if [ -e ".$anvil->data->{path}{configs}{'anvil.version'}." ]; then cat ".$anvil->data->{path}{configs}{'anvil.version'}."; @@ -147,22 +166,60 @@ else echo 0; fi; "; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); - my ($output, $error, $return_code) = $anvil->Remote->call({ - debug => $debug, - shell_call => $shell_call, - target => $target, - port => $port, - password => $password, - remote_user => $remote_user, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - error => $error, - output => $output, - }}); - - $version = defined $output ? $output : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0166", variables => { shell_call => $shell_call, target => $target, remote_user => $remote_user }}); + my ($output, $error, $return_code) = $anvil->Remote->call({ + debug => $debug, + shell_call => $shell_call, + target => $target, + port => $port, + password => $password, + remote_user => $remote_user, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + error => $error, + output => $output, + }}); + + $version = defined $output ? $output : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }}); + + # Create/Update the cache file. + if ($version) + { + my $update_cache = 1; + my $old_version = ""; + if (-e $cache_file) + { + $old_version = $anvil->Storage->read_file({file => $cache_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_version => $old_version }}); + if ($old_version eq $version) + { + # No need to update + $update_cache = 0; + } + else + { + + } + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { update_cache => $update_cache }}); + if ($update_cache) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0437", variables => { + target => $target, + file => $cache_file, + }}); + $anvil->Storage->write_file({ + debug => $debug, + file => $cache_file, + body => $version, + mode => "0666", + overwrite => 1, + }); + } + } + } } else { diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index e6656990..ff8d8d97 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -1638,7 +1638,7 @@ sub read_file { # Something went wrong... $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0162", variables => { - remote_file => $remote_user."\@".$target.$file, + remote_file => $remote_user."\@".$target.":".$file, local_file => $temp_file, }}); return("!!error!!"); diff --git a/Anvil/Tools/Striker.pm b/Anvil/Tools/Striker.pm new file mode 100644 index 00000000..334f8ab0 --- /dev/null +++ b/Anvil/Tools/Striker.pm @@ -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; diff --git a/cgi-bin/striker b/cgi-bin/striker index c784850a..7603b1f7 100755 --- a/cgi-bin/striker +++ b/cgi-bin/striker @@ -57,8 +57,8 @@ if (not -e $anvil->data->{path}{data}{host_uuid}) print_and_exit($anvil); } -$anvil->Database->connect(); -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"}); +$anvil->Database->connect({debug => 3}); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); if (not $anvil->data->{sys}{database}{connections}) { # No databases, exit. @@ -257,7 +257,7 @@ sub process_task $anvil->data->{cgi}{login}{value} = "" if not defined $anvil->data->{cgi}{login}{value}; $anvil->data->{cgi}{logout}{value} = "" if not defined $anvil->data->{cgi}{logout}{value}; $anvil->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::login::value" => $anvil->data->{cgi}{login}{value}, "cgi::logout::value" => $anvil->data->{cgi}{logout}{value}, "cgi::save::value" => $anvil->data->{cgi}{save}{value}, @@ -503,11 +503,19 @@ sub process_anvil_menu $anvil->data->{form}{back_link} = "?striker=true"; $anvil->data->{cgi}{task}{value} = "" if not defined $anvil->data->{cgi}{task}{value}; $anvil->data->{cgi}{action}{value} = "" if not defined $anvil->data->{cgi}{action}{value}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 'cgi::task::value' => $anvil->data->{cgi}{task}{value}, + 'cgi::action::value' => $anvil->data->{cgi}{action}{value}, + }}); if ($anvil->data->{cgi}{task}{value} eq "prep-host") { process_prep_host_page($anvil); } + elsif ($anvil->data->{cgi}{task}{value} eq "configure-network") + { + #process_configure_network($anvil); + } elsif ($anvil->data->{cgi}{task}{value} eq "manifest") { #process_manifest_page($anvil); @@ -529,25 +537,181 @@ sub process_prep_host_page { my ($anvil) = @_; - my $ip_address = defined $anvil->data->{cgi}{ip_address}{value} ? $anvil->data->{cgi}{ip_address}{value} : ""; - my $rh_user = defined $anvil->data->{cgi}{rh_user}{value} ? $anvil->data->{cgi}{rh_user}{value} : ""; - my $rh_password = defined $anvil->data->{cgi}{rh_password}{value} ? $anvil->data->{cgi}{rh_password}{value} : ""; - my $node_checked = "checked"; - my $dr_checked = ""; - my $form_body = $anvil->Template->get({file => "anvil.html", name => "host-setup-menu1", variables => { - ip_address => $ip_address, - node_checked => $node_checked, - dr_checked => $dr_checked, + my $host_ip_address = defined $anvil->data->{cgi}{host_ip_address}{value} ? $anvil->data->{cgi}{host_ip_address}{value} : ""; + my $host_password = defined $anvil->data->{cgi}{host_password}{value} ? $anvil->data->{cgi}{host_password}{value} : ""; + my $rh_user = defined $anvil->data->{cgi}{rh_user}{value} ? $anvil->data->{cgi}{rh_user}{value} : ""; + my $rh_password = defined $anvil->data->{cgi}{rh_password}{value} ? $anvil->data->{cgi}{rh_password}{value} : ""; + my $type = defined $anvil->data->{cgi}{type}{value} ? $anvil->data->{cgi}{type}{value} : ""; + my $connect = defined $anvil->data->{cgi}{'connect'}{value} ? $anvil->data->{cgi}{'connect'}{value} : ""; + my $confirm = defined $anvil->data->{cgi}{confirm}{value} ? $anvil->data->{cgi}{confirm}{value} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host_ip_address => $host_ip_address, + host_password => $anvil->Log->is_secure($host_password), + rh_user => $rh_user, + rh_password => $anvil->Log->is_secure($rh_password), + type => $type, + 'connect' => $connect, + confirm => $confirm, }}); - $anvil->data->{form}{refresh_link} = "?anvil=true&task=prep-host"; - $anvil->data->{form}{back_link} = "?anvil=true"; - $anvil->data->{cgi}{task}{value} = "" if not defined $anvil->data->{cgi}{task}{value}; - $anvil->data->{cgi}{action}{value} = "" if not defined $anvil->data->{cgi}{action}{value}; - $anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "prep-host-main", variables => { - form => $form_body, + # Is the IP or hostname valid? + my $ssh_port = 22; + if ($host_ip_address =~ /:(\d+)$/) + { + $ssh_port = $1; + $host_ip_address =~ s/:(\d+)$//; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ssh_port => $ssh_port, + host_ip_address => $host_ip_address, }}); + # If we've been passed 'connect', verify we can connect. + if (($connect) && ($confirm)) + { + # Save the job + my $job_command = $anvil->data->{path}{exe}{'striker-initialize-host'}." --target root\@".$host_ip_address.":".$ssh_port." --type".$type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + job_command => $job_command, + password => $anvil->Log->is_secure($host_password), + }}); + + # Store the peer's password as the job data + my $job_data = "password=".$host_password; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { job_data => $job_data }}); + + # Store the job + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + debug => 3, + file => $THIS_FILE, + line => __LINE__, + job_command => $job_command, + job_data => $job_data, + job_name => "striker-peer::add", + job_title => "job_0011", + job_description => "job_0012", + job_progress => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + + # We don't need to store anything as hidden variables, we'll read it back from the database + # later. + $anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "job recorded", variables => { + title_id => "", + message_id => "", + reload_url => "/cgi-bin/".$THIS_FILE."?anvil=true&task=prep-host", + title => "#!string!striker_0044!#", + description => "#!string!striker_0129!#", + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }}); + } + elsif ($connect) + { + if (not $anvil->Validate->is_ipv4({ip => $host_ip_address})) + { + # Bad IP + $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0010"}) }}); + } + elsif (($ssh_port < 1) or ($ssh_port > 65535)) + { + # Bad port + $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0011"}) }}); + } + else + { + # Can we connect? + my $target_host_name = ""; + my $target_host_uuid = ""; + my ($connected, $data) = $anvil->Striker->get_peer_data({ + debug => 3, + target => $host_ip_address, + password => $host_password, + port => $ssh_port, + }); + foreach my $key (sort {$a cmp $b} keys %{$data}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "data->{$key}" => $data->{$key} }}); + } + if ($data->{host_name}) + { + # We collect this, but apparently not for any real reason... + $target_host_name = $data->{host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_host_name => $target_host_name }}); + } + if ($data->{host_uuid}) + { + $target_host_uuid = $data->{host_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_host_uuid => $target_host_uuid }}); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + target_host_name => $target_host_name, + target_host_uuid => $target_host_uuid, + }}); + + # If the target is RHEL and it is not registered, offer the user to provide the RH user and password. + my $rh_template = ""; + if (($data->{host_os} =~ /^rhel/) && ($data->{os_registered} ne "yes")) + { + $rh_template = $anvil->Template->get({file => "anvil.html", name => "host-setup-redhat", variables => { + rh_user => $rh_user, + rh_password => $rh_password, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { rh_template => $rh_template }}); + } + + if (not $connected) + { + $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0012"}) }}); + } + elsif (not $target_host_uuid) + { + $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0005", variables => { uuid => $target_host_uuid }}) }}); + } + else + { + # Connected! Ask th euser to confirm. + $anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "confirm-initialize-host", variables => { + 'package' => $type eq "dr" ? "anvil-dr" : "anvil-node", + redhat => $rh_template, + access => "root\@".$host_ip_address.":".$ssh_port, + host_name => $target_host_name, + host_uuid => $target_host_uuid, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }}); + } + } + } + + if ((not $anvil->data->{form}{body}) or ($anvil->data->{form}{error_massage})) + { + my $node_checked = "checked"; + my $dr_checked = ""; + if ($type eq "dr") + { + $node_checked = ""; + $dr_checked = "checked"; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + node_checked => $node_checked, + dr_checked => $dr_checked, + }}); + + my $form_body = $anvil->Template->get({file => "anvil.html", name => "host-setup-menu1", variables => { + host_ip_address => $host_ip_address, + node_checked => $node_checked, + dr_checked => $dr_checked, + }}); + + $anvil->data->{form}{refresh_link} = "?anvil=true&task=prep-host"; + $anvil->data->{form}{back_link} = "?anvil=true"; + $anvil->data->{cgi}{task}{value} = "" if not defined $anvil->data->{cgi}{task}{value}; + $anvil->data->{cgi}{action}{value} = "" if not defined $anvil->data->{cgi}{action}{value}; + $anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "prep-host-main", variables => { + form => $form_body, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }}); + } + return(0); } @@ -1057,52 +1221,29 @@ sub add_sync_peer } else { - my $state_uuid = $anvil->Database->insert_or_update_states({ - debug => 3, - file => $THIS_FILE, - line => __LINE__, - state_name => "peer::".$host."::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 => 2, list => { state_uuid => $state_uuid }}); - - my ($output, $error, $return_code) = $anvil->System->call({ - debug => 2, - shell_call => $anvil->data->{path}{exe}{'call_striker-get-peer-data'}." --target root\@".$host.":".$ssh_port." --state-uuid ".$state_uuid, + my ($connected, $data) = $anvil->Striker->get_peer_data({ + debug => 2, + target => $host, + password => $password, + port => $ssh_port, }); - $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) + if ($data->{host_name}) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /host_name=(.*)$/) - { - # We collect this, but apparently not for any real reason... - $peer_host_name = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_name => $peer_host_name }}); - } - if ($line =~ /host_uuid=(.*)$/) - { - $peer_host_uuid = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_uuid => $peer_host_uuid }}); - } + # We collect this, but apparently not for any real reason... + $peer_host_name = $data->{host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_name => $peer_host_name }}); + } + if ($data->{host_uuid}) + { + $peer_host_uuid = $data->{host_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_uuid => $peer_host_uuid }}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { peer_host_name => $peer_host_name, peer_host_uuid => $peer_host_uuid, }}); - # 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::".$host."::password").";"; - $anvil->Database->write({uuid => $anvil->data->{sys}{host_uuid}, debug => 2, query => $query, source => $THIS_FILE, line => __LINE__}); - - if (not $anvil->Validate->is_uuid({uuid => $peer_host_uuid})) + if ((not $connected) or (not $peer_host_uuid)) { $anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "striker_warning_0005", variables => { uuid => $peer_host_uuid }}) }}); } @@ -1111,7 +1252,7 @@ sub add_sync_peer $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_bidirection::value" => $anvil->data->{cgi}{new_peer_bidirection}{value} }}); if ($anvil->data->{cgi}{new_peer_bidirection}{value} eq "on") { - # See which of our IPs match theirs. If the peer is a hostname, first + # See which of our IPs match theirs. If the peer is a hostname, first, find the IP. $use_ip = $anvil->System->find_matching_ip({host => $host}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_ip => $use_ip }}); diff --git a/html/skins/alteeve/anvil.html b/html/skins/alteeve/anvil.html index 786314cb..c4288c17 100644 --- a/html/skins/alteeve/anvil.html +++ b/html/skins/alteeve/anvil.html @@ -20,7 +20,15 @@ - #!string!striker_0116!# + #!string!striker_0116!# + + + + + + + + #!string!striker_0130!# @@ -66,7 +74,7 @@ #!variable!form!# - + @@ -76,13 +84,13 @@
- #!string!message_0146!#" + #!string!message_0146!# - #!string!message_0116!#"
- #!string!message_0117!#" + #!string!message_0116!#
+ #!string!message_0117!# @@ -92,12 +100,12 @@ - #!string!message_0147!#" + #!string!message_0147!# - +   @@ -106,7 +114,7 @@ - + @@ -116,30 +124,113 @@ - #!string!message_0148!#" + + + +
+ + + + + + + + - + + + + #!variable!redhat!# + + +
- +
 
- + +
+
+ + + + + + + + + + + + + + + + + + + + + + +
+ #!string!striker_0125!#: + + #!variable!access!# +
+ #!string!striker_0126!#: + + #!variable!host_name!# +
+ #!string!striker_0127!#: + + #!variable!host_uuid!# +
+ #!string!striker_0098!# + + +
+ + + - -   + + + + + + + + + + + + + +
+ #!string!message_0148!# +
+ + +   + + +
+   +
- - + +   - - - + diff --git a/html/skins/alteeve/images/configure-network.png b/html/skins/alteeve/images/configure-network.png new file mode 100644 index 00000000..9c4ccb46 Binary files /dev/null and b/html/skins/alteeve/images/configure-network.png differ diff --git a/html/skins/alteeve/images/sources.txt b/html/skins/alteeve/images/sources.txt index adfe1ae5..293da6c5 100644 --- a/html/skins/alteeve/images/sources.txt +++ b/html/skins/alteeve/images/sources.txt @@ -30,7 +30,7 @@ Refresh by Denis Klyuchnikov from the Noun Project (https://thenounproject.com/t - refresh.png configure by Gregor Cresnar from the Noun Project (https://thenounproject.com/term/configure/485294/) -- striker_configure.png +- striker_configure.png / configure-network.png customize by Trusted Icons from the Noun Project (https://thenounproject.com/term/customize/538026/) - configure_icon.png diff --git a/html/skins/alteeve/pxe.txt b/html/skins/alteeve/pxe.txt index 4c6c42a1..76dd0c30 100644 --- a/html/skins/alteeve/pxe.txt +++ b/html/skins/alteeve/pxe.txt @@ -73,6 +73,7 @@ selinux --permissive %packages @^minimal-environment alteeve-el8-repo +rsync %end diff --git a/html/skins/alteeve/striker.html b/html/skins/alteeve/striker.html index 9b907e97..664a006b 100644 --- a/html/skins/alteeve/striker.html +++ b/html/skins/alteeve/striker.html @@ -198,10 +198,7 @@   - - +   diff --git a/rpm/SPECS/anvil.spec b/rpm/SPECS/anvil.spec index b88c4cd0..524284b7 100644 --- a/rpm/SPECS/anvil.spec +++ b/rpm/SPECS/anvil.spec @@ -84,6 +84,7 @@ Requires: dhcp-server Requires: firefox Requires: gcc Requires: gdm +Requires: gnome-terminal Requires: httpd Requires: kernel-core Requires: nmap diff --git a/share/anvil.sql b/share/anvil.sql index 153c1161..6d81b0e5 100644 --- a/share/anvil.sql +++ b/share/anvil.sql @@ -1410,6 +1410,7 @@ CREATE TABLE alert_sent ( ALTER TABLE updated OWNER TO admin; +-- NOTE: We don't resync this table! It's meant to be a transient data store, sometimes on a per-DB basis -- This stores state information, like the whether migrations are happening and so on. CREATE TABLE states ( state_uuid uuid not null primary key, diff --git a/share/words.xml b/share/words.xml index cad26a2a..ff2e7b92 100644 --- a/share/words.xml +++ b/share/words.xml @@ -218,7 +218,7 @@ NOTE: Please be patient! Striker Dashboard Anvil! Node - Dsaster Recovery (DR) Host + Disaster Recovery (DR) Host Regenerating the source repository metadata. [ Error ] - The comps.xml file: [#!variable!comps_xml!#] was not found. This provides package group information required for Install Target guests. Is the 'anvil-striker-extra' package installed? @@ -252,7 +252,7 @@ About to try to download aproximately: [#!variable!packages!#] packages needed t Red Hat password What kind of machine will this host be? current IP address and password?]]> - you can enter your Red Hat subscription credentials below.
If needed, the host will be subscribed during setup.]]>
+ You can enter your Red Hat subscription credentials below.
The host will be subscribed during setup.]]>
Starting: [#!variable!program!#]. @@ -759,6 +759,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a - The DRBD resource: [#!variable!resource!#] is in the role: [#!variable!role!#] already, no need to bring it up. Program: [#!variable!program!#] running as the real user: [#!variable!real_user!# (#!variable!real_uid!#)] and effective user: [#!variable!effective_user!# (#!variable!effective_uid!#)]. The setuid c-wrapper: [#!variable!wrapper!#] already exists, no need to create it. + The anvil version cache file: [#!variable!file!#] for: [#!variable!target!#] needs to be created/updated. Test @@ -913,13 +914,21 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st Anvil! Configuration and Management. Create a new Anvil! system. Any running jobs, or jobs that have ended recently, are displayed below. - Prepare a host for use as an Anvil! node or disaster recovery target. + Initialize an Anvil! node or disaster recovery target. Initial host configuration. Prepare a new machine for use as an Anvil! node or DR (disaster recovery) host. This process will setup the repository, install the appropriate anvil packages and link it to the Anvil! databases on the Strikers you choose. Anvil! File Manager. Saving File... Prepare Node or DR Host Please enter the IP address and root password of the target machine you want to configure. + 'root' Password + If you initialize, the target will have the Alteeve repo added and: [#!variable!package!#] installed.
The target will be configured to use this and our peer's databases.]]>
+ Initialize Host + Current host name + Host UUID + Initialize + The target will now be initialized. How long this takes will depend on how fast files can be downloaded and, when needed, how long it takes to register with Red Hat and add the needed repositories. + Configure the network on a node or DR host. #!variable!number!#/sec @@ -965,6 +974,9 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st The job: [#!variable!command!#] was picked up by: [#!variable!pid!#], but that process is not running and it appears to only be: [#!variable!percent!# %] complete. Restarting the job. Unable to find a local IP on the same subnet as the IP/host: [#!variable!host!#] given for the target. Bi-directional setup not currently possible. The subtask request for manipulating the 'Install Target' feature is not valid. It should be 'enabled' or 'disabled' + The IP address is not a valid IPv4 address + The SSH port is not a valid (usually it is 22, but it has to be between 1 ~ 65536) + Failed to log into the host. Is the IP or root user's password right? There are not enough network interfaces on this machine. You have: [#!variable!interface_count!#] interface(s), and you need at least: [#!variable!required_interfaces_for_single!#] interfaces to connect to the requested networks (one for Back-Channel and one for each Internet-Facing network). diff --git a/tools/anvil-daemon b/tools/anvil-daemon index fdd1b745..a6b4b7e0 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -830,7 +830,7 @@ sub check_setuid_wrappers if (-e $anvil->data->{path}{exe}{'call_striker-get-peer-data'}) { # Exists, skipping. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0436", variables => { wrapper => $anvil->data->{path}{exe}{'call_striker-get-peer-data'} }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0436", variables => { wrapper => $anvil->data->{path}{exe}{'call_striker-get-peer-data'} }}); } else { diff --git a/tools/striker-get-peer-data b/tools/striker-get-peer-data index 2b532245..2c22ca75 100755 --- a/tools/striker-get-peer-data +++ b/tools/striker-get-peer-data @@ -69,14 +69,20 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list '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_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_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}); @@ -85,6 +91,96 @@ $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 { @@ -122,6 +218,7 @@ sub get_host_uuid $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}, }}); @@ -129,18 +226,31 @@ sub get_host_uuid } # Try to read the host.uuid file on the target, if possible. - my $host_uuid = ""; - my $file_body = $anvil->Storage->read_file({ - debug => 3, - file => $anvil->data->{path}{data}{host_uuid}, - user => $anvil->data->{target}{user}, - target => $anvil->data->{target}{host}, - port => $anvil->data->{target}{port}, - password => $anvil->data->{target}{password}, + # 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 }}); - if (($file_body eq "!!error!!") or (not $anvil->Validate->is_uuid({uuid => $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({ @@ -172,6 +282,7 @@ sub get_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}, }}); @@ -192,6 +303,7 @@ sub get_password 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}); } @@ -199,12 +311,13 @@ sub get_password 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 => 2, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + 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}); } diff --git a/tools/striker-initialize-host b/tools/striker-initialize-host new file mode 100755 index 00000000..8c55edf6 --- /dev/null +++ b/tools/striker-initialize-host @@ -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 # +#############################################################################################################