#!/usr/bin/perl
#
# Exit codes;
# 0 == OK
# 1 == Host UUID not available yet.
#
# TODO:
# * Make the BCN count a thing, remove Striker user and make it statically 'admin'.
#
use strict;
use warnings;
use Anvil::Tools;
use Data::Dumper;
use NetAddr::IP;
use CGI::Carp "fatalsToBrowser";
# Turn off buffering
$| = 1;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
my $anvil = Anvil::Tools->new();
$anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1});
### NOTE: We'll print the headers only when we need to. If we print them here, it will block cookies being set.
# Setup some variables.
$anvil->data->{skin}{url} = $anvil->data->{path}{urls}{skins}."/".$anvil->Template->skin;
$anvil->data->{form}{body} = "";
$anvil->data->{form}{error_massage} = "";
$anvil->data->{form}{ok_message} = "";
$anvil->data->{form}{back_link} = "";
$anvil->data->{form}{refresh_link} = "";
# Read in any CGI variables, if needed.
$anvil->Get->cgi();
# If we're being asked to get a file, do so now.
if ($anvil->data->{cgi}{upload_file}{file_handle})
{
# Save and exit. We've got ajax handling the UI so this invocation only saves the file.
handle_upload($anvil);
$anvil->nice_exit({exit_code => 0});
}
# If the system hasn't initialized, there may be no host.uuid, and we'll need a better error to show the
# user.
if (not -e $anvil->data->{path}{data}{host_uuid})
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0002"}) }});
print_and_exit($anvil);
}
* 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>
5 years ago
$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.
print $anvil->Template->get({file => "shared.html", name => "http_headers"})."\n";
print $anvil->Template->get({file => "main.html", name => "header", variables => { language => $anvil->Words->language }});
print $anvil->Words->string({key => "error_0003"});
$anvil->nice_exit({exit_code => 2});
}
# If any jobs are pending/running, show the "unavailable" option.
my $configured = $anvil->System->check_if_configured;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { configured => $configured }});
### TODO: Something is causing fairly frequent resyncs, which results in Striker going in and out of
### maintenance mode.
my $available = $configured ? check_availability($anvil) : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {available => $available }});
if (not $configured)
{
# If there is no user account yet, then the system is new and needs to be reconfigured.
configure_striker($anvil);
}
elsif (not $available)
{
# Set the body to 'say::maintenance'.
$anvil->data->{form}{body} = $anvil->data->{say}{maintenance};
}
else
{
# Normal operation
process_task($anvil);
}
# Build the page to display
my $refresh_button = "";
if ($anvil->data->{form}{refresh_link})
{
$refresh_button = $anvil->Template->get({file => "main.html", name => "refresh_button_on", variables => { url => $anvil->data->{form}{refresh_link} }});
}
else
{
$refresh_button = $anvil->Template->get({file => "main.html", name => "refresh_button_off"});
}
print_and_exit($anvil);
#############################################################################################################
# Functions #
#############################################################################################################
# This handles uploading (downloading by our perspective)
sub handle_upload
{
my ($anvil) = @_;
# Get the file handle.
my $cgi_file_handle = $anvil->data->{cgi}{upload_file}{file_handle};
my $file_name = $anvil->data->{cgi}{upload_file}{file_name};
my $mime_type = $anvil->data->{cgi}{upload_file}{mime_type};
my $output_file = $anvil->data->{path}{directories}{shared}{incoming}."/".$file_name;
$output_file =~ s/\/\//\//g;
# TODO: Make sure characters like spaces and whatnot don't need to be escaped.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
cgi_file_handle => $cgi_file_handle,
file_name => $file_name,
mime_type => $mime_type,
output_file => $output_file,
}});
open (my $file_handle, ">", $output_file) or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0015", variables => { shell_call => $output_file, error => $! }});
binmode $file_handle;
while(<$file_handle>)
{
print $cgi_file_handle $_;
}
close $file_handle;
if (not -f $output_file)
{
# Something went wrong
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0257", variables => { file => $output_file }});
}
else
{
# Looks like we got it.
my $file_size = -s $output_file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_size => $file_size }});
if (not $file_size)
{
# Looks like we didn't actually get the file...
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "log_0258", variables => { file => $output_file }});
unlink $output_file;
}
else
{
my $say_size_in_bytes = $anvil->Convert->add_commas({number => $file_size});
my $say_human_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $file_size});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0256", variables => {
file => $output_file,
size_in_bytes => $say_size_in_bytes,
human_readable_size => $say_human_size,
}});
}
}
return(0);
}
sub print_and_exit
{
my ($anvil) = @_;
# Time for the header
my $header = $anvil->Template->get({file => "main.html", name => "header", variables => { language => $anvil->Words->language }});
my $back_button = "";
if ($anvil->data->{form}{back_link})
{
my $url = $THIS_FILE;
if ($anvil->data->{form}{back_link} ne "?")
{
# Turn on the back button,
$url = $anvil->data->{form}{back_link};
}
$back_button = $anvil->Template->get({file => "main.html", name => "back_button_on", variables => { url => $url }});
}
else
{
# Back is disabled.
$back_button = $anvil->Template->get({file => "main.html", name => "back_button_off"});
}
my $left_buttons = $anvil->Template->get({file => "main.html", name => "button_bar_left", variables => {
back_button => $back_button,
refresh_button => $refresh_button,
}});
# The jobs button is "on" when the user is logged in and there is one or more jobs on this system
# under 100% complete.
my $say_jobs_button = $anvil->Template->get({file => "main.html", name => "jobs_button_off"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_jobs_button => $say_jobs_button }});
if (($anvil->data->{sys}{users}{user_name}) && ($anvil->Job->running({debug => 3})))
{
$say_jobs_button = $anvil->Template->get({file => "main.html", name => "jobs_button_on"});
}
my $right_buttons = $anvil->Template->get({file => "main.html", name => "button_bar_right", variables => {
anvil_button => $anvil->data->{sys}{users}{user_name} ? $anvil->Template->get({file => "main.html", name => "anvil_button_on"}) : $anvil->Template->get({file => "main.html", name => "anvil_button_off"}),
configure_button => $anvil->data->{sys}{users}{user_name} ? $anvil->Template->get({file => "main.html", name => "configure_button_on"}) : $anvil->Template->get({file => "main.html", name => "configure_button_off"}),
files_button => $anvil->data->{sys}{users}{user_name} ? $anvil->Template->get({file => "main.html", name => "files_button_on"}) : $anvil->Template->get({file => "main.html", name => "files_button_off"}),
jobs_button => $say_jobs_button,
striker_button => $anvil->data->{sys}{users}{user_name} ? $anvil->Template->get({file => "main.html", name => "striker_button_on"}) : $anvil->Template->get({file => "main.html", name => "striker_button_off"}),
email_button => $anvil->data->{sys}{users}{user_name} ? $anvil->Template->get({file => "main.html", name => "email_button_on"}) : $anvil->Template->get({file => "main.html", name => "email_button_off"}),
user_button => $anvil->data->{sys}{users}{user_name} ? $anvil->Template->get({file => "main.html", name => "user_button_on"}) : $anvil->Template->get({file => "main.html", name => "user_button_off"}),
}});
my $footer = $anvil->Template->get({file => "main.html", name => "footer", variables => {
user => $anvil->data->{sys}{users}{user_name} ? "#!string!message_0034!#" : " ",
}});
# Display the page.
my $say_center_top_bar = " ";
if ($anvil->data->{form}{error_massage})
{
$say_center_top_bar = $anvil->data->{form}{error_massage};
}
elsif ($anvil->data->{form}{ok_message})
{
$say_center_top_bar = $anvil->data->{form}{ok_message};
}
my $body = $anvil->Template->get({file => "main.html", name => "master", variables => {
header => $header,
skin_url => $anvil->data->{path}{urls}{skins}."/".$anvil->Template->skin,
center_top_bar => $say_center_top_bar,
right_top_bar => $right_buttons,
left_top_bar => $left_buttons,
center_body => $anvil->data->{form}{body},
left_bottom_bar => " ",
center_bottom_bar => " ",
right_bottom_bar => " ",
footer => $footer,
}});
print $anvil->Template->get({file => "shared.html", name => "http_headers"})."\n";
print "$body";
$anvil->nice_exit({exit_code => 0});
return(0);
}
# This handles all the daily tasks of Striker.
sub process_task
{
my ($anvil) = @_;
# Is the user trying to log in?
my $logged_in = 0;
$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 => {
"cgi::login::value" => $anvil->data->{cgi}{login}{value},
"cgi::logout::value" => $anvil->data->{cgi}{logout}{value},
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
}});
if ($anvil->data->{cgi}{login}{value})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::login::value" => $anvil->data->{cgi}{login}{value} }});
# Woot!
my $failed = $anvil->Account->login({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }});
if (not $failed)
{
$logged_in = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { logged_in => $logged_in }});
}
}
elsif ($anvil->data->{cgi}{logout}{value})
{
# Bye now!
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::logout::value" => $anvil->data->{cgi}{logout}{value} }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0215"});
$anvil->Account->logout({debug => 2});
}
else
{
# Is the user logged in?
# 0 - The cookies were read, the account was validated and the user's details were loaded.
# 1 - No cookie was found or read. The user needs to log in
# 2 - There was a problem reading the user's UUID (it wasn't found in the database), so the
# cookies were deleted (via C<< Account->logout() >>. The user needs to log back in.
# 3 - There user's hash is invalid, it is probably expired. The user has been logged out and
# needs to log back in.
my $cookie_problem = $anvil->Account->read_cookies();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { cookie_problem => $cookie_problem }});
if (not $cookie_problem)
{
$logged_in = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { logged_in => $logged_in }});
}
}
# Show the login screen, if the user isn't logged in.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { logged_in => $logged_in }});
if (not $logged_in)
{
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "striker-login", variables => {
user => $anvil->data->{cgi}{username}{value},
password => "",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
return(0);
}
# If we're here, the user is logged in!
if ($anvil->data->{cgi}{striker}{value})
{
process_striker_menu($anvil);
}
elsif ($anvil->data->{cgi}{anvil}{value})
{
process_anvil_menu($anvil);
}
elsif ($anvil->data->{cgi}{files}{value})
{
process_file_menu($anvil);
}
elsif ($anvil->data->{cgi}{jobs}{value})
{
process_jobs_menu($anvil);
}
elsif ($anvil->data->{cgi}{email}{value})
{
process_email_menu($anvil);
}
else
{
# Load the main page.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "striker-welcome"});
}
# $anvil->data->{sys}{users}{user_name} = $user_name;
# $anvil->data->{sys}{users}{user_uuid} = $user_uuid;
# $anvil->data->{sys}{users}{user_password_hash} = $user_password_hash,
# $anvil->data->{sys}{users}{user_salt} = $user_salt,
# $anvil->data->{sys}{users}{user_algorithm} = $user_algorithm,
# $anvil->data->{sys}{users}{user_hash_count} = $user_hash_count,
# $anvil->data->{sys}{users}{user_language} = $user_language,
# $anvil->data->{sys}{users}{user_is_admin} = $user_is_admin,
# $anvil->data->{sys}{users}{user_is_experienced} = $user_is_experienced,
# $anvil->data->{sys}{users}{user_is_trusted} = $user_is_trusted,
return(0);
}
# This handles tasks related to email, mail servers and alert recipients.
sub process_email_menu
{
my ($anvil) = @_;
$anvil->data->{form}{back_link} = "?email=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->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::back_link" => $anvil->data->{form}{back_link},
"cgi::task::value" => $anvil->data->{cgi}{task}{value},
"cgi::action::value" => $anvil->data->{cgi}{action}{value},
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
}});
if ($anvil->data->{cgi}{task}{value} eq "email_server")
{
process_email_server_page($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "email_recipient")
{
process_email_recipient_page($anvil);
}
else
{
# What we show for the reboot icon and text depends on if a reboot is pending.
my $reboot_needed = $anvil->System->reboot_needed();
my $reboot_icon = $reboot_needed ? "reboot_needed_icon.png" : "reboot_icon.png";
my $reboot_message = $reboot_needed ? "#!string!striker_0093!#" : "#!string!striker_0092!#";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
reboot_needed => $reboot_needed,
reboot_icon => $reboot_icon,
reboot_message => $reboot_message,
}});
# The 'back' goes home
$anvil->data->{form}{back_link} = "?";
$anvil->data->{form}{refresh_link} = "?email=true";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "main-menu", variables => {
}});
}
return(0);
}
# This processes mail recipients.
sub process_email_recipient_page
{
my ($anvil) = @_;
my $recipient_uuid = defined $anvil->data->{cgi}{recipient_uuid}{value} ? $anvil->data->{cgi}{recipient_uuid}{value} : "";
my $recipient_name = defined $anvil->data->{cgi}{recipient_name}{value} ? $anvil->data->{cgi}{recipient_name}{value} : "";
my $recipient_email = defined $anvil->data->{cgi}{recipient_email}{value} ? $anvil->data->{cgi}{recipient_email}{value} : "";
my $recipient_language = defined $anvil->data->{cgi}{recipient_language}{value} ? $anvil->data->{cgi}{recipient_language}{value} : "en_CA";
my $recipient_units = defined $anvil->data->{cgi}{recipient_units}{value} ? $anvil->data->{cgi}{recipient_units}{value} : "metric";
my $recipient_new_level = defined $anvil->data->{cgi}{recipient_new_level}{value} ? $anvil->data->{cgi}{recipient_new_level}{value} : "2";
my $delete = defined $anvil->data->{cgi}{'delete'}{value} ? $anvil->data->{cgi}{'delete'}{value} : "";
my $back = defined $anvil->data->{cgi}{back}{value} ? $anvil->data->{cgi}{back}{value} : "";
my $save = defined $anvil->data->{cgi}{save}{value} ? $anvil->data->{cgi}{save}{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 => {
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_units => $recipient_units,
recipient_new_level => $recipient_new_level,
back => $back,
save => $save,
'delete' => $delete,
confirm => $confirm,
}});
if ($back)
{
$save = "";
$delete = "";
$confirm = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
save => $save,
'delete' => $delete,
confirm => $confirm,
}});
}
# If we have a recipient_uuid and we're not saving, load the information.
if (($recipient_uuid) && (not $save))
{
# Load. If we're deleting, we'll check 'mail_server_helo_domain' to see if it already was.
my $query = "
SELECT
recipient_name,
recipient_email,
recipient_language,
recipient_units,
recipient_new_level
FROM
recipients
WHERE
recipient_uuid = ".$anvil->Database->quote($recipient_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
$recipient_name = $row->[0];
$recipient_email = $row->[1];
$recipient_language = $row->[2];
$recipient_units = $row->[3];
$recipient_new_level = $row->[4];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_units => $recipient_units,
recipient_new_level => $recipient_new_level,
}});
if ($delete)
{
# Has the user confirmed?
if ($confirm)
{
# Delete.
$anvil->Database->insert_or_update_recipientss({
debug => 2,
'delete' => 1,
recipient_uuid => $recipient_uuid,
});
# Saved successfully.
my $ok_message = $anvil->Words->string({key => "ok_0003", variables => { recipient_email => $recipient_email }});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $ok_message }});
# Clear the form
$recipient_name = "";
$recipient_email = "";
$recipient_language = "en_CA";
$recipient_units = "metric";
$recipient_new_level = "2";
}
else
{
# Ask them to confirm.
$anvil->data->{form}{back_link} = $anvil->data->{sys}{cgi_string};
$anvil->data->{form}{back_link} =~ s/save=.*?&//;
$anvil->data->{form}{back_link} =~ s/save=.*?$//;
$anvil->data->{form}{refresh_link} = "";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "recipient-delete-confirm", variables => {
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_uuid => $recipient_uuid,
}});
return(0);
}
}
}
}
# If we're saving, make sure we have a valid email address and a name.
if ($save)
{
# Did the user give both an email address and name?
if ((not $recipient_name) or (not $recipient_name))
{
# Which was missing?
if (not $recipient_name)
{
$anvil->data->{cgi}{recipient_name}{alert} = 1;
}
if (not $recipient_email)
{
$anvil->data->{cgi}{recipient_email}{alert} = 1;
}
$save = "";
$confirm = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
save => $save,
confirm => $confirm,
}});
}
# Verify that the mail server and ports are sane.
if (not $anvil->Validate->is_email({email => $recipient_email}))
{
# Bad domain
my $error_message = $anvil->Words->string({key => "warning_0026"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{recipient_email}{alert} = 1;
$save = "";
$confirm = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
error_message => $error_message,
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::recipient_email::alert" => $anvil->data->{cgi}{recipient_email}{alert},
save => $save,
confirm => $confirm,
}});
}
}
# Are we still saving?
if ($save)
{
# Have we confirmed?
if ($confirm)
{
($recipient_uuid) = $anvil->Database->insert_or_update_recipients({
debug => 2,
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_units => $recipient_units,
recipient_new_level => $recipient_new_level,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { recipient_uuid => $recipient_uuid }});
if ($recipient_uuid)
{
# Saved successfully.
my $ok_message = $anvil->Words->string({key => "ok_0004"});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $ok_message }});
# Clear the form
$recipient_uuid = "";
$recipient_name = "";
$recipient_email = "";
$recipient_language = "en_CA";
$recipient_units = "metric";
$recipient_new_level = "2";
}
else
{
# Something went wrong...
my $error_message = $anvil->Words->string({key => "warning_0027"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
}
}
else
{
my $say_recipient_units = "#!string!unit_0027!#";
if ($recipient_language eq "imperial")
{
$say_recipient_units = "#!string!unit_0028!#";
}
# Ignore
my $say_recipient_new_level = "#!string!unit_0023!#";
if ($recipient_new_level eq "1")
{
# Critical
$say_recipient_new_level = "#!string!unit_0024!#";
}
elsif ($recipient_new_level eq "2")
{
# Warning
$say_recipient_new_level = "#!string!unit_0025!#";
}
elsif ($recipient_new_level eq "3")
{
# Notice
$say_recipient_new_level = "#!string!unit_0026!#";
}
my $say_recipient_language = $anvil->Words->language({iso => $recipient_language, long => 1});
$say_recipient_language = "???" if not $say_recipient_language;
# Ask the user to confirm
$anvil->data->{form}{back_link} = $anvil->data->{sys}{cgi_string};
$anvil->data->{form}{back_link} =~ s/save=.*?&//;
$anvil->data->{form}{back_link} =~ s/save=.*?$//;
$anvil->data->{form}{refresh_link} = "";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "recipient-confirm", variables => {
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
say_recipient_language => $say_recipient_language,
recipient_units => $recipient_units,
say_recipient_units => $say_recipient_units,
recipient_new_level => $recipient_new_level,
say_recipient_new_level => $say_recipient_new_level,
}});
return(0);
}
}
# Get a list of existing alert recipients.
my $query = "SELECT recipient_uuid, recipient_name, recipient_email FROM recipients WHERE recipient_name != 'DELETED' ORDER BY recipient_name ASC;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
my $recipients_form = "";
if ($count)
{
# Build the list of existing mail servers
$recipients_form .= $anvil->Template->get({file => "email.html", name => "recipient-entry-open"});;
foreach my $row (@{$results})
{
my $recipient_uuid = $row->[0];
my $recipient_name = $row->[1];
my $recipient_email = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
}});
$recipients_form .= $anvil->Template->get({file => "email.html", name => "recipient-entry", variables => {
name => $recipient_name." (".$recipient_email.")",
uuid => $recipient_uuid,
}});;
}
$recipients_form .= $anvil->Template->get({file => "email.html", name => "recipient-entry-close"});;
}
# Name
my $recipient_name_class = $anvil->data->{cgi}{recipient_name}{alert} ? "input_alert" : "input_clear";
my $recipient_name_form = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "recipient_name",
id => "recipient_name",
field => "#!string!striker_0194!#",
description => "#!string!striker_0195!#",
value => $recipient_name,
default_value => "",
class => $recipient_name_class,
extra => "",
}});
# Email
my $recipient_email_class = $anvil->data->{cgi}{recipient_email}{alert} ? "input_alert" : "input_clear";
my $recipient_email_form = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "recipient_email",
id => "recipient_email",
field => "#!string!striker_0196!#",
description => "#!string!striker_0197!#",
value => $recipient_email,
default_value => "",
class => $recipient_email_class,
extra => "",
}});
# Language (select)
$anvil->Words->language_list();
my $options = [];
foreach my $iso (sort {$a cmp $b} keys %{$anvil->data->{sys}{languages}})
{
push @{$options}, $iso."#!#".$anvil->data->{sys}{languages}{$iso};
}
my $recipient_language_select = $anvil->Template->select_form({
name => "recipient_language",
options => $options,
blank => 0,
selected => $recipient_language,
class => $anvil->data->{cgi}{recipient_language}{alert} ? "input_alert" : "input_clear",
});
# Units (select)
my $recipient_units_select = $anvil->Template->select_form({
name => "recipient_units",
options => [
"metric#!#".$anvil->Words->string({key => "unit_0027"}),
"imperial#!#".$anvil->Words->string({key => "unit_0028"}),
],
blank => 0,
selected => $recipient_units,
class => $anvil->data->{cgi}{recipient_units}{alert} ? "input_alert" : "input_clear",
});
# Log Level (select)
my $recipient_new_level_select = $anvil->Template->select_form({
name => "recipient_new_level",
options => [
"0#!#".$anvil->Words->string({key => "unit_0023"}),
"1#!#".$anvil->Words->string({key => "unit_0024"}),
"2#!#".$anvil->Words->string({key => "unit_0025"}),
"3#!#".$anvil->Words->string({key => "unit_0026"}),
],
blank => 0,
selected => $recipient_new_level,
class => $anvil->data->{cgi}{recipient_new_level}{alert} ? "input_alert" : "input_clear",
});
# Show the menu.
$anvil->data->{form}{back_link} = "?";
$anvil->data->{form}{refresh_link} = "?email=true&task=email_recipient";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "recipient-menu", variables => {
recipients => $recipients_form,
recipient_name => $recipient_name_form,
recipient_email => $recipient_email_form,
language => $recipient_language_select,
units => $recipient_units_select,
new_level => $recipient_new_level_select,
recipient_uuid => $recipient_uuid,
}});
return(0);
}
# This configures mail servers
sub process_email_server_page
{
my ($anvil) = @_;
# Prep the cgi variables.
my $mail_server_uuid = defined $anvil->data->{cgi}{mail_server_uuid}{value} ? $anvil->data->{cgi}{mail_server_uuid}{value} : "";
my $outgoing_mail_server = defined $anvil->data->{cgi}{outgoing_mail_server}{value} ? $anvil->data->{cgi}{outgoing_mail_server}{value} : "";
my $login_name = defined $anvil->data->{cgi}{login_name}{value} ? $anvil->data->{cgi}{login_name}{value} : "";
my $login_password = defined $anvil->data->{cgi}{login_password}{value} ? $anvil->data->{cgi}{login_password}{value} : "";
my $connection_security = defined $anvil->data->{cgi}{connection_security}{value} ? $anvil->data->{cgi}{connection_security}{value} : "ifn_link1";
my $authentication_method = defined $anvil->data->{cgi}{authentication_method}{value} ? $anvil->data->{cgi}{authentication_method}{value} : "normal_password";
my $port = defined $anvil->data->{cgi}{port}{value} ? $anvil->data->{cgi}{port}{value} : "143";
my $helo_domain = defined $anvil->data->{cgi}{helo_domain}{value} ? $anvil->data->{cgi}{helo_domain}{value} : "";
my $back = defined $anvil->data->{cgi}{back}{value} ? $anvil->data->{cgi}{back}{value} : "";
my $save = defined $anvil->data->{cgi}{save}{value} ? $anvil->data->{cgi}{save}{value} : "";
my $delete = defined $anvil->data->{cgi}{'delete'}{value} ? $anvil->data->{cgi}{'delete'}{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 => {
outgoing_mail_server => $outgoing_mail_server,
login_name => $login_name,
login_password => $login_password,
connection_security => $connection_security,
authentication_method => $authentication_method,
back => $back,
save => $save,
'delete' => $delete,
confirm => $confirm,
}});
if ($back)
{
$save = "";
$delete = "";
$confirm = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
save => $save,
'delete' => $delete,
confirm => $confirm,
}});
}
# Are we loading an existing record?
if (($mail_server_uuid) && not ($save))
{
# Load. If we're deleting, we'll check 'mail_server_helo_domain' to see if it already was.
my $query = "
SELECT
mail_server_address,
mail_server_authentication,
mail_server_helo_domain,
mail_server_password,
mail_server_port,
mail_server_security,
mail_server_username
FROM
mail_servers
WHERE
mail_server_uuid = ".$anvil->Database->quote($mail_server_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
$outgoing_mail_server = $row->[0];
$authentication_method = $row->[1];
$helo_domain = $row->[2];
$login_password = $row->[3];
$port = $row->[4];
$connection_security = $row->[5];
$login_name = $row->[6];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
outgoing_mail_server => $outgoing_mail_server,
authentication_method => $authentication_method,
helo_domain => $helo_domain,
login_password => $login_password,
port => $port,
connection_security => $connection_security,
login_name => $login_name,
}});
if ($delete)
{
# Has the user confirmed?
if ($confirm)
{
# Delete.
$anvil->Database->insert_or_update_mail_servers({
debug => 2,
'delete' => 1,
mail_server_uuid => $mail_server_uuid,
});
# Saved successfully.
my $ok_message = $anvil->Words->string({key => "ok_0002", variables => { mail_server => $outgoing_mail_server }});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $ok_message }});
# Clear the form
$mail_server_uuid = "";
$outgoing_mail_server = "";
$login_name = "";
$login_password = "";
$connection_security = "";
$authentication_method = "";
}
else
{
# Ask them to confirm.
$anvil->data->{form}{back_link} = $anvil->data->{sys}{cgi_string};
$anvil->data->{form}{back_link} =~ s/save=.*?&//;
$anvil->data->{form}{back_link} =~ s/save=.*?$//;
$anvil->data->{form}{refresh_link} = "";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "mail-server-delete-confirm", variables => {
outgoing_mail_server => $outgoing_mail_server,
mail_server_uuid => $mail_server_uuid,
}});
return(0);
}
}
}
}
# if the user put a port on the mail server, break it off now and override any passed in port.
# Normally, the port is set via a hidden variable when the security check box is changed.
my $test_outgoing_mail_server = $outgoing_mail_server;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_outgoing_mail_server => $test_outgoing_mail_server }});
if ($test_outgoing_mail_server =~ /^(.*):(\d+)$/)
{
$test_outgoing_mail_server = $1;
$port = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
test_outgoing_mail_server => $test_outgoing_mail_server,
port => $port,
}});
}
elsif (not $port)
{
# Port wasn't passed. Use '143' unless $connection_security is 'ssl_tls'
$port = 143;
if ($connection_security eq "ssl_tls")
{
$port = 993;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { port => $port }});
}
### NOTE: For now, the HELO domain is not configurable by the user.
# If we don't have $helo_domain, use the host's domain
if (not $helo_domain)
{
$helo_domain = $anvil->_domain_name();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { helo_domain => $helo_domain }});
}
# Sanity check our save
if ($save)
{
# Did the user give an outgoing mail server?
if (not $outgoing_mail_server)
{
# Just silently send them back to the form.
$save = "";
$confirm = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
save => $save,
confirm => $confirm,
}});
}
# Verify that the mail server and ports are sane.
if ((not $anvil->Validate->is_ipv4({ip => $test_outgoing_mail_server})) and
(not $anvil->Validate->is_domain_name({name => $test_outgoing_mail_server})))
{
# Bad domain
my $error_message = $anvil->Words->string({key => "warning_0023"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{outgoing_mail_server}{alert} = 1;
$save = "";
$confirm = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
error_message => $error_message,
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::outgoing_mail_server::alert" => $anvil->data->{cgi}{outgoing_mail_server}{alert},
save => $save,
confirm => $confirm,
}});
}
if (not $anvil->Validate->is_port({port => $port}))
{
# Bad port
my $error_message = $anvil->Words->string({key => "warning_0024"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{outgoing_mail_server}{alert} = 1;
$save = "";
$confirm = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
error_message => $error_message,
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::outgoing_mail_server::alert" => $anvil->data->{cgi}{outgoing_mail_server}{alert},
save => $save,
confirm => $confirm,
}});
}
}
# Still saving?
if ($save)
{
# Confirmed?
if ($confirm)
{
# Save!
($mail_server_uuid) = $anvil->Database->insert_or_update_mail_servers({
debug => 2,
mail_server_uuid => $mail_server_uuid,
mail_server_address => $test_outgoing_mail_server,
mail_server_authentication => $authentication_method,
mail_server_helo_domain => $helo_domain,
mail_server_password => $login_password,
mail_server_port => $port,
mail_server_security => $connection_security,
mail_server_username => $login_name,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mail_server_uuid => $mail_server_uuid }});
if ($mail_server_uuid)
{
# Saved successfully.
my $ok_message = $anvil->Words->string({key => "ok_0001"});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $ok_message }});
# Clear the form
$mail_server_uuid = "";
$outgoing_mail_server = "";
$login_name = "";
$login_password = "";
$connection_security = "";
$authentication_method = "";
}
else
{
# Something went wrong...
my $error_message = $anvil->Words->string({key => "warning_0025"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
}
}
else
{
# Ask the user to confirm
$anvil->data->{form}{back_link} = $anvil->data->{sys}{cgi_string};
$anvil->data->{form}{back_link} =~ s/save=.*?&//;
$anvil->data->{form}{back_link} =~ s/save=.*?$//;
$anvil->data->{form}{refresh_link} = "";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "mail-server-confirm", variables => {
say_outgoing_mail_server => $test_outgoing_mail_server.":".$port,
outgoing_mail_server => $outgoing_mail_server,
port => $port,
login_name => $login_name,
login_password => $login_password,
connection_security => $connection_security,
authentication_method => $authentication_method,
helo_domain => $helo_domain,
mail_server_uuid => $mail_server_uuid,
}});
return(0);
}
}
# Get a list of existing mail servers.
my $query = "SELECT mail_server_uuid, mail_server_address FROM mail_servers WHERE mail_server_helo_domain != 'DELETED' ORDER BY mail_server_address ASC;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
my $mail_servers_form = "";
if ($count)
{
# Build the list of existing mail servers
$mail_servers_form .= $anvil->Template->get({file => "email.html", name => "mail-server-entry-open"});;
foreach my $row (@{$results})
{
my $mail_server_uuid = $row->[0];
my $mail_server_address = $row->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
mail_server_uuid => $mail_server_uuid,
mail_server_address => $mail_server_address,
}});
$mail_servers_form .= $anvil->Template->get({file => "email.html", name => "mail-server-entry", variables => {
name => $mail_server_address,
uuid => $mail_server_uuid,
}});;
}
$mail_servers_form .= $anvil->Template->get({file => "email.html", name => "mail-server-entry-close"});;
}
# Outgoing mail server
my $outgoing_mail_server_class = $anvil->data->{cgi}{outgoing_mail_server}{alert} ? "input_alert" : "input_clear";
my $outgoing_mail_server_form = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "outgoing_mail_server",
id => "outgoing_mail_server",
field => "#!string!striker_0185!#",
description => "#!string!striker_0169!#",
value => $outgoing_mail_server,
default_value => "",
class => $outgoing_mail_server_class,
extra => "",
}});
# Login name
my $login_name_class = $anvil->data->{cgi}{login_name}{alert} ? "input_alert" : "input_clear";
my $login_name_form = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "login_name",
id => "login_name",
field => "#!string!striker_0170!#",
description => "#!string!striker_0171!#",
value => $login_name,
default_value => "",
class => $login_name_class,
extra => "",
}});
# Password
my $login_password_class = $anvil->data->{cgi}{login_password}{alert} ? "input_alert" : "input_clear";
my $login_password_form = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "login_password",
id => "login_password",
field => "#!string!striker_0172!#",
description => "#!string!striker_0173!#",
value => $login_password,
default_value => "",
class => $login_password_class,
extra => "",
}});
# connection security
my $connection_security_select = $anvil->Template->select_form({
name => "connection_security",
options => [
"none#!#".$anvil->Words->string({key => "striker_0174"}),
"ssl_tls#!#".$anvil->Words->string({key => "striker_0175"}),
"starttls#!#".$anvil->Words->string({key => "striker_0176"})
],
blank => 0,
selected => $connection_security,
class => $anvil->data->{cgi}{connection_security}{alert} ? "input_alert" : "input_clear",
});
# Authentication method
my $authentication_method_select = $anvil->Template->select_form({
name => "authentication_method",
options => [
"normal_password#!#".$anvil->Words->string({key => "striker_0177"}),
"encrypted_password#!#".$anvil->Words->string({key => "striker_0178"}),
"kerberos_gssapi#!#".$anvil->Words->string({key => "striker_0179"}),
"ntlm#!#".$anvil->Words->string({key => "striker_0180"}),
"tls_certificate#!#".$anvil->Words->string({key => "striker_0181"}),
"oauth2#!#".$anvil->Words->string({key => "striker_0182"})
],
blank => 0,
selected => $authentication_method,
class => $anvil->data->{cgi}{authentication_method}{alert} ? "input_alert" : "input_clear",
});
# Show the menu.
$anvil->data->{form}{back_link} = "?";
$anvil->data->{form}{refresh_link} = "?email=true&task=email_server";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "mail-server-menu", variables => {
mail_servers => $mail_servers_form,
outgoing_mail_server => $outgoing_mail_server_form,
login_name => $login_name_form,
login_password => $login_password_form,
connection_security => $connection_security_select,
authentication_method => $authentication_method_select,
mail_server_uuid => $mail_server_uuid,
port => $port,
}});
return(0);
}
# This handles the "Striker" menu items.
sub process_striker_menu
{
my ($anvil) = @_;
$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->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::back_link" => $anvil->data->{form}{back_link},
"cgi::task::value" => $anvil->data->{cgi}{task}{value},
"cgi::action::value" => $anvil->data->{cgi}{action}{value},
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
}});
if ($anvil->data->{cgi}{task}{value} eq "sync")
{
process_sync_page($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "reconfig")
{
process_reconfig_page($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "update")
{
process_update($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "install-target")
{
process_install_target($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "reboot")
{
process_power($anvil, "reboot");
}
elsif ($anvil->data->{cgi}{task}{value} eq "poweroff")
{
process_power($anvil, "poweroff");
}
elsif ($anvil->data->{cgi}{task}{value} eq "keys")
{
process_keys($anvil, "poweroff");
}
else
{
# What we show for the reboot icon and text depends on if a reboot is pending.
my $reboot_needed = $anvil->System->reboot_needed();
my $reboot_icon = $reboot_needed ? "reboot_needed_icon.png" : "reboot_icon.png";
my $reboot_message = $reboot_needed ? "#!string!striker_0093!#" : "#!string!striker_0092!#";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
reboot_needed => $reboot_needed,
reboot_icon => $reboot_icon,
reboot_message => $reboot_message,
}});
# What we show for the install target icon and text depends on if it is enabled or not.
my $install_target_title = "#!string!striker_0109!#";
my $install_target_icon = "install_target_disabled.png";
my $install_target_subtask = "unavailable";
my ($install_manifest_status, $variable_uuid, $modified_date) = $anvil->Database->read_variable({
variable_name => "install-target::enabled",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
install_manifest_status => $install_manifest_status,
variable_uuid => $variable_uuid,
modified_date => $modified_date,
}});
if ($install_manifest_status eq "enabled")
{
# Offer the button to disable it.
$install_target_title = "#!string!striker_0108!#";
$install_target_icon = "install_target_enabled.png";
$install_target_subtask = "disable";
}
elsif ($install_manifest_status eq "disabled")
{
# Offer the button to enable it.
$install_target_title = "#!string!striker_0107!#";
$install_target_subtask = "enable";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
install_target_title => $install_target_title,
install_target_icon => $install_target_icon,
install_target_subtask => $install_target_subtask,
}});
# Are there any bad keys?
my $query = "SELECT state_uuid, state_note FROM states WHERE state_name LIKE 'host_key_changed::%';";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
results => $results,
count => $count,
}});
my $broken_key_icon = $count ? "broken_key_icon_on.png" : "broken_key_icon_off.png";
my $broken_key_message = $count ? "#!string!striker_0132!#" : "#!string!striker_0131!#";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
broken_key_icon => $broken_key_icon,
broken_key_message => $broken_key_message,
}});
# The 'back' goes home
$anvil->data->{form}{back_link} = "?";
$anvil->data->{form}{refresh_link} = "?striker=true";
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "striker-setup", variables => {
reboot_icon => $reboot_icon,
reboot_message => $reboot_message,
install_target_icon => $install_target_icon,
install_target_title => $install_target_title,
install_target_subtask => $install_target_subtask,
broken_key_icon => $broken_key_icon,
broken_key_message => $broken_key_message,
}});
}
return(0);
}
# This shows the user any running jobs.
sub process_jobs_menu
{
my ($anvil) = @_;
$anvil->data->{form}{refresh_link} = "?jobs=true";
$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->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "jobs", variables => {
title_id => "",
message_id => "",
title => "#!string!striker_0096!#",
description => "#!string!striker_0115!#",
job_list => $anvil->Job->html_list({debug => 2, ended_within => 300}),
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'say::maintenance' => $anvil->data->{say}{maintenance} }});
return(0);
}
# This handles removing old keys.
sub process_keys
{
my ($anvil) = @_;
### NOTE: This doesn't update Striker (the Alteeve) stack yet, just the base OK.
my $show_list = 1;
$anvil->data->{cgi}{'delete'}{value} = "" if not defined $anvil->data->{cgi}{'delete'}{value};
if ($anvil->data->{cgi}{'delete'}{value})
{
# Record the job!
my $job_data = "";
foreach my $key (sort {$a cmp $b} keys %{$anvil->data->{cgi}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { key => $key }});
if ($key =~ /^state_uuid_(.*)$/)
{
my $state_uuid = $1;
$show_list = 0;
$job_data .= $state_uuid.",";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
state_uuid => $state_uuid,
show_list => $show_list,
job_data => $job_data,
}});
}
}
$job_data =~ s/,$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_data => $job_data }});
if ($job_data)
{
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-manage-keys'},
job_data => $job_data,
job_name => "manage::broken_keys",
job_title => "job_0056",
job_description => "job_0057",
job_progress => 0,
job_host_uuid => $anvil->data->{sys}{host_uuid},
});
$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,
title => "#!string!job_0056!#",
description => "#!string!job_0057!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { show_list => $show_list }});
if ($show_list)
{
# Get a list of bad keys we know about and ask the user which they want to remove
my $query = "
SELECT
a.state_uuid,
b.host_name,
a.state_name,
a.state_note
FROM
states a,
hosts b
WHERE
a.state_host_uuid = b.host_uuid
AND
a.state_name LIKE 'host_key_changed::%'
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
if (not $count)
{
# No bad keys found on this host.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "no-bad-keys"});
}
else
{
# Build a list of check-boxes / bad keys.
my $bad_key_list = "";
foreach my $row (@{$results})
{
my $state_uuid = $row->[0];
my $host_name = $row->[1];
my $state_name = $row->[2];
my $state_note = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
state_uuid => $state_uuid,
host_name => $host_name,
state_name => $state_name,
state_note => $state_note,
}});
my $bad_file = "";
my $bad_line = "";
foreach my $pair (split/,/, $state_note)
{
my ($variable, $value) = ($pair =~ /^(.*?)=(.*)$/);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pair => $pair,
variable => $variable,
value => $value,
}});
if ($variable eq "file")
{
$bad_file = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_file => $bad_file }});
}
if ($variable eq "line")
{
$bad_line = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_line => $bad_line }});
}
}
my ($target) = ($state_name =~ /host_key_changed::(.*)$/);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
target => $target,
bad_file => $bad_file,
bad_line => $bad_line,
}});
my $checkbox_key = "state_uuid_".$state_uuid;
my $checked = "";
if ((exists $anvil->data->{cgi}{$checkbox_key}) && ($anvil->data->{cgi}{$checkbox_key}{value}))
{
$checked = "checked";
}
$bad_key_list .= $anvil->Template->get({file => "striker.html", name => "broken-key-entry", variables => {
checkbox_name => $checkbox_key,
checkbox_checked => $checked,
target => $target,
file => $bad_file,
host => $host_name,
}});
}
#Show the screen the confirm the addition.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "broken-key-list", variables => {
bad_keys => $bad_key_list,
}});
}
}
return(0);
}
# This handles files.
sub process_file_menu
{
my ($anvil) = @_;
$anvil->data->{form}{refresh_link} = "striker?files=true";
#$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};
if ($anvil->data->{cgi}{task}{value} eq "upload")
{
#process_upload_page($anvil);
}
else
{
# The 'back' goes home
$anvil->data->{form}{back_link} = "?";
$anvil->data->{form}{body} = $anvil->Template->get({file => "files.html", name => "main-menu", variables => {
}});
}
return(0);
}
# This handles the "Anvil" menu items.
sub process_anvil_menu
{
my ($anvil) = @_;
$anvil->data->{form}{refresh_link} = "striker?anvil=true";
$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};
* 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>
5 years ago
$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 "prep-network")
* 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>
5 years ago
{
process_prep_network($anvil);
* 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>
5 years ago
}
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
elsif ($anvil->data->{cgi}{task}{value} eq "fences")
{
process_fences($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "create")
{
if ($anvil->data->{cgi}{subtask}{value} eq "manifest")
{
#process_manifest($anvil);
}
else
{
process_create($anvil);
}
}
else
{
# The 'back' goes home
$anvil->data->{form}{back_link} = "?";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "main-menu", variables => {
}});
}
return(0);
}
sub handle_new_manifest
{
my ($anvil) = @_;
return(0);
}
# This sanity checks the fence agent forms.
sub sanity_check_fence_agent_form
{
my ($anvil, $fence_agent) = @_;
my $sane = 1;
my $confirn_form = "";
foreach my $i (1..$anvil->data->{cgi}{fence_count}{value})
{
# Read in the parameters for this agent, and compare to see if the value passed in differs.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { i => $i }});
foreach my $name (sort {$a cmp $b} keys %{$anvil->data->{fences}{$fence_agent}{parameters}})
{
# We don't show deprecated or replaced options.
next if $anvil->data->{fences}{$fence_agent}{parameters}{$name}{replacement};
next if $anvil->data->{fences}{$fence_agent}{parameters}{$name}{deprecated};
my $option_key = $name."_".$i;
my $unique = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{unique};
my $required = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{required};
my $description = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{description};
my $type = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{content_type};
my $default = exists $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'} ? $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:name' => $name,
's2:option_key' => $option_key,
's3:unique' => $unique,
's4:required' => $required,
's5:description' => $description,
's6:type' => $type,
's7:default' => $default,
}});
# If this is 'boolean' and the default is '1', change the default to 'on' so that
# it matches what we get from the form.
if (($type eq "boolean") && ($default eq "1"))
{
$default = "on";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'default' => $default }});
}
my $is_default = 1;
my $passed_parameter_key = $name."_".$i;
my $passed_value = defined $anvil->data->{cgi}{$passed_parameter_key}{value} ? $anvil->data->{cgi}{$passed_parameter_key}{value} : "";
my $say_value = $passed_value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
passed_parameter_key => $passed_parameter_key,
passed_value => $passed_value,
'default' => $default,
}});
if ($type eq "boolean")
{
$say_value = "";
if (defined $passed_value)
{
# Yes No
$say_value = $passed_value ? "#!string!unit_0001!#" : "#!string!unit_0002!#";
}
else
{
# Yes No
$say_value = $default ? "#!string!unit_0001!#" : "#!string!unit_0002!#";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_value => $say_value }});
}
elsif ((($type eq "string") or ($type eq "select")) && ($passed_value eq ""))
{
$say_value = "--";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_value => $say_value }});
}
if ($passed_value ne $default)
{
# Something changed. Is it sane?
$is_default = 0;
if (($type eq "integer") or ($type eq "second"))
{
# Make sure the value is a bare integer
if ($passed_value =~ /\D/)
{
# Problem.
$sane = 0;
$anvil->data->{cgi}{$passed_parameter_key}{alert} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${passed_parameter_key}::alert" => $anvil->data->{cgi}{$passed_parameter_key}{alert},
sane => $sane,
}});
}
}
#
$anvil->data->{fence}{$fence_agent}{set}{$i}{parameter}{$name}{set} = $passed_value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"fence::${fence_agent}::set::${i}::parameter::${name}::set" => $anvil->data->{fence}{$fence_agent}{set}{$i}{parameter}{$name}{set},
}});
}
$anvil->data->{fence}{confirm_table}{data}{$name}{$i}{'default'} = $is_default;
$anvil->data->{fence}{confirm_table}{data}{$name}{$i}{value} = $say_value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"fence::confirm_table::data::${name}::${i}::default" => $anvil->data->{fence}{confirm_table}{data}{$name}{$i}{'default'},
"fence::confirm_table::data::${name}::${i}::value" => $anvil->data->{fence}{confirm_table}{data}{$name}{$i}{value},
}});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
return($sane);
}
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
# This allows the user to tell us about fence devices.
sub process_fences
{
my ($anvil) = @_;
# Read/process the unified fences metadata.
$anvil->Striker->get_fence_data({debug => 3});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
$anvil->data->{cgi}{fence_agent}{value} = "" if not defined $anvil->data->{cgi}{fence_agent}{value};
$anvil->data->{cgi}{fence_count}{value} = 2 if not defined $anvil->data->{cgi}{fence_count}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cgi::fence_agent::value" => $anvil->data->{cgi}{fence_agent}{value},
"cgi::fence_count::value" => $anvil->data->{cgi}{fence_count}{value},
}});
# Are we configuring an agent/device?
if ($anvil->data->{cgi}{fence_agent}{value})
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
my $fence_agent = $anvil->data->{cgi}{fence_agent}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { fence_agent => $fence_agent }});
# Are we going back to the form?
if ($anvil->data->{cgi}{back}{value})
{
$anvil->data->{cgi}{save}{value} = "";
$anvil->data->{cgi}{confirm}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
"cgi::confirm::value" => $anvil->data->{cgi}{confirm}{value},
}});
}
# Are we saving?
if ($anvil->data->{cgi}{save}{value})
{
# Sanity check
my $sane = sanity_check_fence_agent_form($anvil, $fence_agent);
if ($sane)
{
# Build the table and ask the user to confirm.
#print $anvil->Template->get({file => "shared.html", name => "http_headers"})."\n";
#print "<pre>\n";
#print Dumper $anvil->data->{fence}{confirm_table};
#print "</pre>\n";
my $header_columns = $anvil->Template->get({file => "anvil.html", name => "fence-agent-column", variables => {
class => "column_header",
value => " ",
}});
foreach my $i (1..$anvil->data->{cgi}{fence_count}{value})
{
$header_columns .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-column", variables => {
class => "column_header",
value => $anvil->Words->string({key => "striker_0220", variables => { number => $i }}),
}});
}
my $confirm_table = $anvil->Template->get({file => "anvil.html", name => "fence-agent-row", variables => {
columns => $header_columns,
}});
foreach my $name (sort {$a cmp $b} keys %{$anvil->data->{fence}{confirm_table}{data}})
{
my $entry_row = $anvil->Template->get({file => "anvil.html", name => "fence-agent-column", variables => {
class => "column_header",
value => $name,
}});
foreach my $i (sort {$a cmp $b} keys %{$anvil->data->{fence}{confirm_table}{data}{$name}})
{
my $is_default = $anvil->data->{fence}{confirm_table}{data}{$name}{$i}{'default'};
my $value = $anvil->data->{fence}{confirm_table}{data}{$name}{$i}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:name' => $name,
's2:i' => $i,
's3:is_default' => $is_default,
's4:value' => $value,
}});
$entry_row .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-column-hidden-value", variables => {
class => $is_default ? "default_value" : "changed_value",
name => $name."_".$i,
value => $value,
}});
}
$confirm_table .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-row", variables => {
columns => $entry_row,
}});
}
$anvil->data->{form}{back_link} = "?anvil=true&task=fences";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "fence-agent-confirm", variables => {
table => $confirm_table,
span_count => $anvil->data->{cgi}{fence_count}{value},
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
}
my $agent_description = format_fence_description($anvil, $fence_agent, $anvil->data->{fences}{$fence_agent}{description});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
# Walk through the list of options
my $option_form = "";
foreach my $i (1..$anvil->data->{cgi}{fence_count}{value})
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
my $say_device = $anvil->Words->string({key => "striker_0216", variables => { number => $i }});
my $device_options = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
i => $i,
say_device => $say_device,
}});
foreach my $name (sort {$a cmp $b} keys %{$anvil->data->{fences}{$fence_agent}{parameters}})
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
# We don't show deprecated or replaced options.
next if $anvil->data->{fences}{$fence_agent}{parameters}{$name}{replacement};
next if $anvil->data->{fences}{$fence_agent}{parameters}{$name}{deprecated};
my $option_key = $name."_".$i;
my $unique = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{unique};
my $required = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{required};
my $description = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{description};
my $type = $anvil->data->{fences}{$fence_agent}{parameters}{$name}{content_type};
my $default = exists $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'} ? $anvil->data->{fences}{$fence_agent}{parameters}{$name}{'default'} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
option_key => $option_key,
unique => $unique,
required => $required,
description => $description,
type => $type,
'default' => $default,
}});
# Set the cgi variable to the default, if not already set.
$anvil->data->{cgi}{$option_key}{alert} = "" if not defined $anvil->data->{cgi}{$option_key}{alert};
$anvil->data->{cgi}{$option_key}{value} = $default if not defined $anvil->data->{cgi}{$option_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cgi::".$option_key."::value" => $anvil->data->{cgi}{$option_key}{value},
}});
# Set the CGI default if not already set.
$anvil->data->{cgi}{$option_key}{value} = $default if not exists $anvil->data->{cgi}{$option_key}{value};
if ($type eq "select")
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
# Build the select box
my $options = [];
foreach my $option (sort {$a cmp $b} @{$anvil->data->{fences}{$fence_agent}{parameters}{$name}{options}})
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
push @{$options}, $option;
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
my $select_options = $anvil->Template->select_form({
name => $option_key,
options => $options,
blank => $required ? 0 : 1,
'sort' => 1,
selected => $anvil->data->{cgi}{$option_key}{value},
class => $anvil->data->{cgi}{$option_key}{alert} ? "input_alert" : "input_clear",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { select_options => $select_options }});
# Build the entry
my $select_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-option-entry", variables => {
name_class => $required ? "say_required" : "",
name => $name,
option => $select_options,
description => $description,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { select_form => $select_form }});
$device_options .= $select_form;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { device_options => $device_options }});
}
elsif ($type eq "boolean")
{
# Build the entry
my $checkbox_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-checkbox-entry", variables => {
name => $name,
name_class => $required ? "say_required" : "",
checkbox_name => $option_key,
checkbox_checked => $anvil->data->{cgi}{$option_key}{value} ? "checked" : "",
description => $description,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { checkbox_form => $checkbox_form }});
$device_options .= $checkbox_form;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { device_options => $device_options }});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
else
{
### String, Second or Integer.
# Build the entry
my $string_options .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-input-entry", variables => {
name => $name,
key => $option_key,
value => $anvil->data->{cgi}{$option_key}{value},
'default' => $default,
name_class => $required ? "say_required" : "",
input_class => $anvil->data->{cgi}{$option_key}{alert} ? "input_alert" : "input_clear",
description => $description,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { string_options => $string_options }});
$device_options .= $string_options;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { device_options => $device_options }});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
}
$option_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-option-menu", variables => {
device_name => $say_device,
device_options => $device_options,
}});
}
$anvil->data->{form}{back_link} = "?anvil=true&task=fences";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "fence-agent-configuration", variables => {
description => $agent_description,
options => $option_form,
note => $anvil->Words->string({key => "striker_0218", variables => { name => $fence_agent }}),
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
}
else
{
# For each agent, we'll create a <div> with it's options that will be shown/hidden basen on the agent
# select box.
my $agents = [];
my $description_form = "";
foreach my $fence_agent (sort {$a cmp $b} keys %{$anvil->data->{fences}})
{
# We don't care about IPMI-based fence agents here.
next if $fence_agent eq "fence_drac5";
next if $fence_agent eq "fence_idrac";
next if $fence_agent =~ /^fence_ilo/;
next if $fence_agent eq "fence_imm";
next if $fence_agent eq "fence_ipmilan";
next if $fence_agent eq "fence_redfish";
next if $fence_agent eq "fence_rsa";
push @{$agents}, $fence_agent;
my $agent_description = format_fence_description($anvil, $fence_agent, $anvil->data->{fences}{$fence_agent}{description});
$description_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-description", variables => {
name => $fence_agent,
description => $agent_description,
}});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
my $fence_agent_select = $anvil->Template->select_form({
name => "fence_agent",
options => $agents,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{fence_agent}{value} ? $anvil->data->{cgi}{fence_agent}{value} : "fence_apc_snmp",
class => "input_clear",
});
my $fence_count_select = $anvil->Template->select_form({
name => "fence_count",
options => [1, 2, 3, 4],
blank => 0,
'sort' => 0,
selected => $anvil->data->{cgi}{fence_count}{value},
class => "input_clear",
});
$anvil->data->{form}{back_link} = "?anvil=true&task=create";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "fence-agent-menu", variables => {
fence_select => $fence_agent_select,
fence_count => $fence_count_select,
descriptions => $description_form,
existing_fences => "",
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
}
return(0);
}
sub format_fence_description
{
my ($anvil, $fence_agent, $agent_description) = @_;
# Replace newlines with <br /> elements.
$agent_description =~ s/\n/<br \/>/gs;
$agent_description =~ s/<br \/>/<br \/>\n/gs;
# Handle fence_azure_arm.
if ($fence_agent eq "fence_azure_arm")
{
my $in_pre = 0;
my $break_number = 0;
my $new_desctiption = "";
foreach my $line (split/\n/, $agent_description)
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line =~ /\+---/)
{
$line =~ s/<br \/>//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { break_number => $break_number }});
if (not $break_number)
{
$in_pre = 1;
$new_desctiption .= "<pre>\n";
$new_desctiption .= $line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_desctiption => $new_desctiption }});
}
elsif ($break_number == 2)
{
$in_pre = 0;
$new_desctiption .= $line."\n";
$new_desctiption .= "</pre>\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_desctiption => $new_desctiption }});
}
else
{
$new_desctiption .= $line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_desctiption => $new_desctiption }});
}
$break_number++;
}
else
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
if ($in_pre)
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
$line =~ s/<br \/>//g;
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
$new_desctiption .= $line."\n";
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
}
$agent_description = $new_desctiption;
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
return($agent_description);
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
# This handles creating an Anvil! from an existing manifest
sub process_create
{
my ($anvil) = @_;
# Are we creating a new manifest?
if ($anvil->data->{cgi}{task}{value})
{
handle_new_manifest($anvil);
}
# Show existing manifests.
my $query = "
SELECT
manifest_uuid,
manifest_name,
manifest_last_ran,
manifest_xml,
manifest_note
FROM
manifests
ORDER BY
manifest_name ASC;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
results => $results,
count => $count,
}});
my $manifest_template = "";
if ($count)
{
foreach my $row (@{$results})
{
my $manifest_uuid = $row->[0];
my $manifest_name = $row->[1];
my $manifest_last_ran = $row->[2];
my $manifest_xml = $row->[3];
my $manifest_note = $row->[4];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
manifest_uuid => $manifest_uuid,
manifest_name => $manifest_name,
manifest_last_ran => $manifest_last_ran,
manifest_xml => $manifest_xml,
manifest_note => $manifest_note,
}});
$manifest_template .= $anvil->Template->get({file => "anvil.html", name => "existing-manifest-entry", variables => {
manifest_uuid => $manifest_uuid,
manifest_name => $manifest_name,
}});
}
}
# Store the previous CGI variables and display the new fields.
$anvil->data->{form}{back_link} = "?anvil=true";
$anvil->data->{cgi}{task}{value} = "" if not defined $anvil->data->{cgi}{task}{value};
$anvil->data->{cgi}{subtask}{value} = "" if not defined $anvil->data->{cgi}{subtask}{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 => "create-menu", variables => {
existing_manifests => $manifest_template,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
# This handles configuring a remote target's network interfaces (renaming them, bonding and bridging them).
sub process_prep_network
{
my ($anvil) = @_;
# Do I know which machine we're configuring?
if (not $anvil->data->{cgi}{host_uuid}{value})
{
# Nope, send the user back.
$anvil->data->{cgi}{task}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::task::value" => $anvil->data->{cgi}{task}{value} }});
process_anvil_menu($anvil);
return(0);
}
# Pull the host's data out of the JSON file.
$anvil->Striker->parse_all_status_json();
my $host_name = "";
foreach my $host (sort {$a cmp $b} keys %{$anvil->data->{json}{all_status}{hosts}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cgi::host_uuid::value" => $anvil->data->{cgi}{host_uuid}{value},
"json::all_status::hosts::${host}::host_uuid" => $anvil->data->{json}{all_status}{hosts}{$host}{host_uuid},
}});
if ($anvil->data->{cgi}{host_uuid}{value} eq $anvil->data->{json}{all_status}{hosts}{$host}{host_uuid})
{
# Found it.
$host_name = $host;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { host_name => $host_name }});
last;
}
}
if (not $host_name)
{
# Didn't find it.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0014", variables => { host_uuid => $anvil->data->{cgi}{host_uuid}{value} } }) }});
$anvil->data->{cgi}{task}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::task::value" => $anvil->data->{cgi}{task}{value},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
process_anvil_menu($anvil);
return(0);
}
# Is the user going back to the form?
if (($anvil->data->{cgi}{save}{value} eq "true") && ($anvil->data->{cgi}{back}{value}))
{
# User is going back.
$anvil->data->{cgi}{save}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::save::value" => $anvil->data->{cgi}{save}{value} }});
}
# How many actual interfaces do we have? We need at least six. For each two above that, we'll add an
# additional bond option per network.
my $interfaces = {};
my $interface_options = [];
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{interface}})
{
# if any interfaces are called 'virbrX-nic', ignore it as it will be removed. Likewise, ignore any 'vnetX' devices.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { interface => $interface }});
if (($interface =~ /^virbr\d+-nic/) or ($interface =~ /^vnet\d+/))
{
# Ignore it.
next;
}
# Store the mac used in the select box
my $mac_address = $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{interface}{$interface}{mac_address};
push @{$interface_options}, $mac_address."#!#".$interface." (".$mac_address.")";
# Store the mac address .
$interfaces->{$interface} = $mac_address;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "interfaces->{".$interface."}" => $interfaces->{$interface} }});
}
# Get the interface count
my $interface_count = keys %{$interfaces};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { interface_count => $interface_count }});
if ($interface_count < 6)
{
# Not enough interfaces.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0015", variables => { interface_count => $interface_count } }) }});
$anvil->data->{cgi}{task}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cgi::task::value" => $anvil->data->{cgi}{task}{value},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
process_anvil_menu($anvil);
}
# TODO: For now, we're only allowing one BCN and SN. So at this time, we'll show one BCN pair, one SN
# pair and N-IFN pairs.
my $bcn_pair_count = 1;
my $sn_pair_count = 1;
my $ifn_pair_count = int(($interface_count - 4) / 2);
$ifn_pair_count = 1 if $ifn_pair_count < 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
bcn_pair_count => $bcn_pair_count,
sn_pair_count => $sn_pair_count,
ifn_pair_count => $ifn_pair_count,
}});
### NOTE: The weird 'form::config_step2::<x>::value is from reusing the logic used back when
### Striker's config was made. It's not the best, but it does the job. Would be nice to redo
### the logic later.
# Are we saving?
if ($anvil->data->{cgi}{save}{value} eq "true")
{
# Clear the network map variable.
$anvil->Database->insert_or_update_variables({
variable_name => "config::map_network",
variable_value => 0,
variable_default => 0,
variable_description => "striker_0202",
variable_section => "config",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
# Is the form sane?
my $sane = 1;
my $interfaces = "";
my $error = 0;
my $gateway_interface = "";
if ($anvil->data->{cgi}{host_name}{value})
{
# Is the host name sane?
if (not $anvil->Validate->is_domain_name({name => $anvil->data->{cgi}{host_name}{value}}))
{
# Nope
my $error_message = $anvil->Words->string({key => "error_0012", variables => { host_name => $anvil->data->{cgi}{host_name}{value} }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{host_name}{alert} = 1;
}
else
{
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::host_name::value",
variable_value => $anvil->data->{cgi}{host_name}{value},
variable_default => "",
variable_description => "striker_0159",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
}
if ($anvil->data->{cgi}{gateway}{value})
{
# Is if valid?
if (not $anvil->Validate->is_ipv4({ip => $anvil->data->{cgi}{gateway}{value}}))
{
# Bad IP
my $error_message = $anvil->Words->string({key => "warning_0010", variables => { ip_address => $anvil->data->{cgi}{gateway}{value} }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{gateway}{alert} = 1;
}
else
{
# It's sane, record it.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::gateway::value",
variable_value => $anvil->data->{cgi}{gateway}{value},
variable_default => "",
variable_description => "striker_0036",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
}
if ($anvil->data->{cgi}{dns}{value})
{
foreach my $dns (split/,/, $anvil->data->{cgi}{dns}{value})
{
$dns =~ s/^\s+//;
$dns =~ s/\s+$//;
if (not $anvil->Validate->is_ipv4({ip => $dns}))
{
# Bad IP
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0010", variables => { ip_address => $anvil->data->{cgi}{dns}{value} }}) }});
$anvil->data->{cgi}{dns}{alert} = 1;
}
last if $anvil->data->{cgi}{dns}{alert};
}
if (not $anvil->data->{cgi}{dns}{alert})
{
# It's sane, record it.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::dns::value",
variable_value => $anvil->data->{cgi}{dns}{value},
variable_default => "",
variable_description => "striker_0038",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
}
foreach my $network ("bcn", "sn", "ifn")
{
my $count_key = $network."_count";
my $loops = $anvil->data->{cgi}{$count_key}{value};
# Store the network counts.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step1::".$count_key."::value",
variable_value => $anvil->data->{cgi}{$count_key}{value},
variable_default => "",
variable_description => "striker_0163",
variable_section => "config_step1",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
foreach my $i (1..$loops)
{
my $this_network = $network.$i;
my $bridge_key = $this_network."_create_bridge";
my $ip_key = $this_network."_ip";
my $subnet_key = $this_network."_subnet_mask";
my $link1_key = $this_network."_link1_mac_to_set";
my $link2_key = $this_network."_link2_mac_to_set";
my $say_network = $anvil->Words->string({key => "striker_0018", variables => { number => $i }});
if ($network eq "sn")
{
$say_network = $anvil->Words->string({key => "striker_0020", variables => { number => $i }});
}
elsif ($network eq "ifn")
{
$say_network = $anvil->Words->string({key => "striker_0022", variables => { number => $i }});
}
my $link1_interface = "";
my $link2_interface = "";
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{interface}})
{
my $mac_address = $anvil->data->{json}{all_status}{hosts}{$host_name}{network_interface}{interface}{$interface}{mac_address};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
interface => $interface,
mac_address => $mac_address,
}});
if ($mac_address eq $anvil->data->{cgi}{$link1_key}{value})
{
$link1_interface = $interface;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { link1_interface => $link1_interface }});
}
elsif ($mac_address eq $anvil->data->{cgi}{$link2_key}{value})
{
$link2_interface = $interface;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { link2_interface => $link2_interface }});
}
last if (($link1_interface) && ($link2_interface));
}
my $say_bridge = "#!string!unit_0002!#";
if ($anvil->data->{cgi}{$bridge_key}{value})
{
# We're making a bridge.
$say_bridge = "#!string!unit_0001!#";
}
my $say_ip_address = "#!string!striker_0152!#";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_ip_address => $say_ip_address }});
if (($anvil->data->{cgi}{$ip_key}{value}) && (not $anvil->Validate->is_ipv4({ip => $anvil->data->{cgi}{$ip_key}{value}})))
{
# Bad IP
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0010", variables => { ip_address => $anvil->data->{cgi}{$ip_key}{value} }}) }});
$anvil->data->{cgi}{$ip_key}{alert} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${ip_key}::alert" => $anvil->data->{cgi}{$ip_key}{alert},
}});
}
elsif (($anvil->data->{cgi}{$subnet_key}{value}) && (not $anvil->Validate->is_subnet_mask({subnet_mask => $anvil->data->{cgi}{$subnet_key}{value}})))
{
# Bad subnet
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0017"}) }});
$anvil->data->{cgi}{$subnet_key}{alert} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
}});
}
elsif (($anvil->data->{cgi}{$ip_key}{value}) && (not $anvil->data->{cgi}{$subnet_key}{value}))
{
# IP without a subnet
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0018"}) }});
$anvil->data->{cgi}{$subnet_key}{alert} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
}});
}
else
{
### Things are sane.
# Does this network have an IP or is it dhcp?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cgi::${ip_key}::value" => $anvil->data->{cgi}{$ip_key}{value} }});
if ($anvil->data->{cgi}{$ip_key}{value})
{
$say_ip_address = $anvil->data->{cgi}{$ip_key}{value}."/".$anvil->data->{cgi}{$subnet_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_ip_address => $say_ip_address }});
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$ip_key."::value",
variable_value => $anvil->data->{cgi}{$ip_key}{value},
variable_default => "",
variable_description => "striker_0153,!!say_network!".$say_network."!!",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$subnet_key."::value",
variable_value => $anvil->data->{cgi}{$subnet_key}{value},
variable_default => "",
variable_description => "striker_0154,!!say_network!".$say_network."!!",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
# Is this the network with the subnet mask?
if ((not $gateway_interface) &&
($anvil->data->{cgi}{gateway}{value}) &&
(not $anvil->data->{cgi}{gateway}{alert}) &&
($anvil->data->{cgi}{$ip_key}{value}))
{
my $match = $anvil->Network->match_gateway({
ip_address => $anvil->data->{cgi}{$ip_key}{value},
subnet_mask => $anvil->data->{cgi}{$subnet_key}{value},
gateway => $anvil->data->{cgi}{gateway}{value},
});
# Found the match!
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { match => $match }});
if ($match)
{
if ($anvil->data->{cgi}{$ip_key}{value})
{
$say_ip_address .= ",<br /> #!string!striker_0026!#: ".$anvil->data->{cgi}{gateway}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_ip_address => $say_ip_address }});
}
# DNS?
if (($anvil->data->{cgi}{dns}{value}) && (not $anvil->data->{cgi}{dns}{alert}) && ($anvil->data->{cgi}{$ip_key}{value}))
{
$say_ip_address .= ",<br /> #!string!striker_0037!#: ".$anvil->data->{cgi}{dns}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_ip_address => $say_ip_address }});
}
$gateway_interface = $this_network;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { gateway_interface => $gateway_interface }});
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::gateway_interface::value",
variable_value => $gateway_interface,
variable_default => "",
variable_description => "striker_0155",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
}
}
if (not $anvil->data->{cgi}{$ip_key}{value})
{
# Record this as DHCP.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$ip_key."::value",
variable_value => "dhcp",
variable_default => "",
variable_description => "striker_0160",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
# Last check, are the interfaces defined? All $i == 1 interfaces need to be
# defined. Any 2+ are allowed to be ignored, _IF_ neither link is selected
# AND neither the IP/subnet are blank.
if ((not $anvil->data->{cgi}{$link1_key}{value}) && (not $anvil->data->{cgi}{$link2_key}{value}))
{
# If this is network 1, both are required.
if ($i == 1)
{
# Required.
my $error_message = $anvil->Words->string({key => "warning_0021"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{$link1_key}{value} = 1;
$anvil->data->{cgi}{$link2_key}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${link1_key}::alert" => $anvil->data->{cgi}{$link1_key}{alert},
"cgi::${link2_key}::alert" => $anvil->data->{cgi}{$link2_key}{alert},
}});
}
}
elsif (not $anvil->data->{cgi}{$link1_key}{value})
{
# link 1 is missing.
my $error_message = $anvil->Words->string({key => "warning_0022"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{$link1_key}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${link1_key}::alert" => $anvil->data->{cgi}{$link1_key}{alert},
}});
}
elsif (not $anvil->data->{cgi}{$link2_key}{value})
{
# link 2 is missing.
my $error_message = $anvil->Words->string({key => "warning_0022"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{$link2_key}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${link2_key}::alert" => $anvil->data->{cgi}{$link2_key}{alert},
}});
}
elsif (($anvil->data->{cgi}{$ip_key}{value}) && (not $anvil->data->{cgi}{$link1_key}{value}))
{
# There's an IP address but no interfaces selected.
my $error_message = $anvil->Words->string({key => "warning_0022"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{$link1_key}{value} = 1;
$anvil->data->{cgi}{$link2_key}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${link1_key}::alert" => $anvil->data->{cgi}{$link1_key}{alert},
"cgi::${link2_key}::alert" => $anvil->data->{cgi}{$link2_key}{alert},
}});
}
# Now save the link info, if selected.
if ($anvil->data->{cgi}{$link1_key}{value})
{
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$link1_key."::value",
variable_value => $anvil->data->{cgi}{$link1_key}{value},
variable_default => "",
variable_description => "striker_0156",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
if ($anvil->data->{cgi}{$link2_key}{value})
{
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$link2_key."::value",
variable_value => $anvil->data->{cgi}{$link2_key}{value},
variable_default => "",
variable_description => "striker_0157",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
# Store the bridge key
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$bridge_key."::value",
variable_value => $anvil->data->{cgi}{$bridge_key}{value},
variable_default => "",
variable_description => "striker_0158",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
$interfaces .= $anvil->Template->get({file => "anvil.html", name => "interface-entry", variables => {
network => $say_network,
primary => $link1_interface." (".$anvil->data->{cgi}{$link1_key}{value}.")",
link1_key => $link1_key,
link1_value => $anvil->data->{cgi}{$link1_key}{value},
secondary => $link2_interface." (".$anvil->data->{cgi}{$link2_key}{value}.")",
link2_key => $link2_key,
link2_value => $anvil->data->{cgi}{$link2_key}{value},
bridge => $say_bridge,
say_ip => $say_ip_address,
ip_key => $ip_key,
ip_address => $anvil->data->{cgi}{$ip_key}{value},
subnet_key => $subnet_key,
subnet_mask => $anvil->data->{cgi}{$subnet_key}{value},
bridge_key => $bridge_key,
bridge_value => $anvil->data->{cgi}{$bridge_key}{value},
}});
}
}
# Did we see an error?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
if ($anvil->data->{form}{error_massage})
{
# Yup, not sane, send the user back to the form.
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
}
# Confirmed?
if (($anvil->data->{cgi}{confirm}{value}) && ($sane))
{
# Yes, save the job.
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 3,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => $anvil->data->{cgi}{host_uuid}{value},
job_command => $anvil->data->{path}{exe}{'anvil-configure-host'},
job_data => "form::config_step2",
job_name => "configure::network",
job_title => "job_0001",
job_description => "job_0071",
job_progress => 0,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 => "network_job_recorded", variables => {
reload_url => "/cgi-bin/".$THIS_FILE."?anvil=true",
title => "#!string!striker_0044!#",
description => "#!string!striker_0045!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
return(0);
}
else
{
# Show the confirmation box.
$anvil->data->{form}{back_link} = $anvil->data->{sys}{cgi_string};
$anvil->data->{form}{back_link} =~ s/step=step2//;
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "config-network-confirm", variables => {
host_name => $host_name,
host_uuid => $anvil->data->{cgi}{host_uuid}{value},
gateway_interface => $gateway_interface,
interfaces => $interfaces,
bcn_count => $bcn_pair_count,
sn_count => $sn_pair_count,
ifn_count => $ifn_pair_count,
gateway => $anvil->data->{cgi}{gateway}{value},
dns => $anvil->data->{cgi}{dns}{value},
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
}
else
{
# We're mapping
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "config::map_network",
variable_value => 1,
variable_default => 0,
variable_description => "striker_0202",
variable_section => "config",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
my $interface_form = "";
# NOTE: We don't assign IPs at this point, unless the user manually sets one. We'll set all to 'dhcp'
# until set during the Anvil! build later.
foreach my $network ("bcn", "sn", "ifn")
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network => $network }});
my $name_key = "";
my $description_key = "";
my $count = 1;
if ($network eq "bcn")
{
$name_key = "striker_0018";
$description_key = "striker_0019";
$count = $bcn_pair_count;
}
elsif ($network eq "sn")
{
$name_key = "striker_0020";
$description_key = "striker_0021";
$count = $sn_pair_count;
}
elsif ($network eq "ifn")
{
$name_key = "striker_0022";
$description_key = "striker_0023";
$count = $ifn_pair_count;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
name_key => $name_key,
description_key => $description_key,
count => $count,
}});
foreach my $i (1..$count)
{
my $this_ip_key = $network.$i."_ip";
my $this_subnet_mask_key = $network.$i."_subnet_mask";
my $this_iface1_key = $network.$i."_link1_mac_to_set";
my $this_iface2_key = $network.$i."_link2_mac_to_set";
my $this_ip = exists $anvil->data->{cgi}{$this_ip_key}{value} ? $anvil->data->{cgi}{$this_ip_key}{value} : "dhcp";
my $this_ip_class = $anvil->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear";
my $this_subnet_mask_class = $anvil->data->{cgi}{$this_subnet_mask_key}{alert} ? "input_alert" : "input_clear";
my $this_iface1_class = $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear";
my $this_iface2_class = $anvil->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
this_ip_key => $this_ip_key,
this_subnet_mask_key => $this_subnet_mask_key,
this_iface1_key => $this_iface1_key,
this_iface2_key => $this_iface2_key,
this_ip => $this_ip,
this_ip_class => $this_ip_class,
this_subnet_mask_class => $this_subnet_mask_class,
this_iface1_class => $this_iface1_class,
this_iface2_class => $this_iface2_class,
}});
# Build the interface select boxes...
my $this_iface1_form = $anvil->Template->select_form({
name => $this_iface1_key,
options => $interface_options,
blank => 1,
'sort' => 0,
selected => defined $anvil->data->{cgi}{$this_iface1_key}{value} ? $anvil->data->{cgi}{$this_iface1_key}{value} : "",
class => $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear",
});
my $this_iface2_form = $anvil->Template->select_form({
name => $this_iface2_key,
options => $interface_options,
blank => 1,
'sort' => 0,
selected => defined $anvil->data->{cgi}{$this_iface2_key}{value} ? $anvil->data->{cgi}{$this_iface2_key}{value} : "",
class => $anvil->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear",
});
# Assemble the form
$interface_form .= $anvil->Template->get({file => "anvil.html", name => "network_interface_form", variables => {
field => $anvil->Words->string({key => $name_key, variables => { number => $i }}),
description => "#!string!".$description_key."!#",
ip_key => $this_ip_key,
ip_value => defined $anvil->data->{cgi}{$this_ip_key}{value} ? $anvil->data->{cgi}{$this_ip_key}{value} : "",
ip_value_default => $this_ip,
ip_class => $this_ip_class,
subnet_mask_key => $this_subnet_mask_key,
subnet_mask_value => defined $anvil->data->{cgi}{$this_subnet_mask_key}{value} ? $anvil->data->{cgi}{$this_subnet_mask_key}{value} : "",
subnet_mask_value_default => $anvil->data->{defaults}{network}{bcn}{subnet_mask},
subnet_mask_class => $this_subnet_mask_class,
iface1_select => $this_iface1_form,
iface2_select => $this_iface2_form,
network_name => $network.$i,
create_bridge => $network eq "sn" ? 0 : 1,
}});
}
}
# Host name
my $say_host_name = defined $anvil->data->{cgi}{host_name}{value} ? $anvil->data->{cgi}{host_name}{value} : $host_name;
my $host_name_class = $anvil->data->{cgi}{host_name}{alert} ? "input_alert" : "input_clear";
my $host_name_form = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "host_name",
id => "host_name",
field => "#!string!striker_0016!#",
description => "#!string!striker_0143!#",
value => defined $anvil->data->{cgi}{host_name}{value} ? $anvil->data->{cgi}{host_name}{value} : $say_host_name,
default_value => "",
class => $host_name_class,
extra => "",
}});
### NOTE: We'll figure out the IFN this belongs to by matching the DG to one of the IFN IPs.
# Gateway
my $gateway_class = $anvil->data->{cgi}{gateway}{alert} ? "input_alert" : "input_clear";
my $say_gateway = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "gateway",
id => "gateway",
field => "#!string!striker_0035!#",
description => "#!string!striker_0144!#",
value => defined $anvil->data->{cgi}{gateway}{value} ? $anvil->data->{cgi}{gateway}{value} : "",
default_value => "",
class => $gateway_class,
extra => "",
}});
# DNS
my $dns_class = $anvil->data->{cgi}{dns}{alert} ? "input_alert" : "input_clear";
my $say_dns = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "dns",
id => "dns",
field => "#!string!striker_0037!#",
description => "#!string!striker_0038!#",
value => defined $anvil->data->{cgi}{dns}{value} ? $anvil->data->{cgi}{dns}{value} : "",
default_value => $anvil->data->{defaults}{network}{dns},
class => $dns_class,
extra => "",
}});
# Store the previous CGI variables and display the new fields.
$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 => "config-network-main", variables => {
interface_form => $interface_form,
gateway_form => $say_gateway,
dns_form => $say_dns,
host_name_form => $host_name_form,
bcn_count => $bcn_pair_count,
sn_count => $sn_pair_count,
ifn_count => $ifn_pair_count,
host_uuid => $anvil->data->{cgi}{host_uuid}{value},
host_name => $host_name, # This is the current host name, used to find the data in the all_status.json
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
# This handles installing our repo, installing the appropriate 'anvil-X' rpm, running OS updates if selected
# and configuring the network on a machine destined to be an Anvil! node or DR host.
sub process_prep_host_page
{
my ($anvil) = @_;
my $host_name = defined $anvil->data->{cgi}{host_name}{value} ? $anvil->data->{cgi}{host_name}{value} : "";
my $host_uuid = defined $anvil->data->{cgi}{host_uuid}{value} ? $anvil->data->{cgi}{host_uuid}{value} : "";
my $default_host_name = defined $anvil->data->{cgi}{default_host_name}{value} ? $anvil->data->{cgi}{default_host_name}{value} : "";
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} : "";
* 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>
5 years ago
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_name => $host_name,
host_uuid => $host_uuid,
default_host_name => $default_host_name,
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,
}});
# Is the IP or host name valid?
* 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>
5 years ago
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,
}});
* 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>
5 years ago
# 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'};
* 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>
5 years ago
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
job_command => $job_command,
password => $anvil->Log->is_secure($host_password),
}});
# Update the database to mark this machine as unconfigured (in case we're rebuilding a
# previously known system). This is needed to get the netweork link state info updating.
if ($host_uuid)
{
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "system::configured",
variable_source_uuid => $host_uuid,
variable_source_table => "hosts",
variable_value => 0,
update_value_only => 1,
});
}
# Are we setting a host name?
my $say_host_name = "host_name=\n";
if (($host_name) && ($host_name ne $default_host_name))
{
$say_host_name = "host_name=".$host_name."\n";
}
* 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>
5 years ago
# Store the peer's password as the job data
my $job_data = "password=".$host_password."\n";
$job_data .= "rh_password=".$rh_password."\n";
$job_data .= "rh_user=".$rh_user."\n";
$job_data .= "host_ip_address=".$host_ip_address."\n";
$job_data .= "ssh_port=".$ssh_port."\n";
$job_data .= "type=".$type."\n";
$job_data .= $say_host_name;
* 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>
5 years ago
$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 => "initialize::".$type."::".$host_ip_address,
job_title => $type eq "dr" ? "job_0021" : "job_0020",
job_description => "job_0022",
* 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>
5 years ago
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&",
* 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>
5 years ago
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 => "warning_0010", variables => { ip_address => $host_ip_address }}) }});
* 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>
5 years ago
}
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 => "warning_0011"}) }});
* 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>
5 years ago
}
else
{
# Can we connect?
my $target_host_name = "";
my $target_host_uuid = "";
my $has_internet = 0;
* 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>
5 years ago
my ($connected, $data) = $anvil->Striker->get_peer_data({
debug => 2,
* 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>
5 years ago
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 }});
}
if ($data->{internet})
{
$has_internet = $data->{internet};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { has_internet => $has_internet }});
}
* 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>
5 years ago
$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 $redhat_message = "";
my $redhat_form = "";
* 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>
5 years ago
if (($data->{host_os} =~ /^rhel/) && ($data->{os_registered} ne "yes"))
{
# If we don't have internet access, tell the user they can register later.
if ($has_internet)
{
$redhat_message = $anvil->Template->get({file => "anvil.html", name => "host-setup-redhat-message", variables => { message => "#!string!message_0148!#" }});
$redhat_form = $anvil->Template->get({file => "anvil.html", name => "host-setup-redhat-form", variables => {
rh_user => $rh_user,
rh_password => $rh_password,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
redhat_form => $redhat_form,
redhat_message => $redhat_message,
}});
}
else
{
$redhat_message = $anvil->Template->get({file => "anvil.html", name => "host-setup-redhat-message", variables => { message => "#!string!message_0151!#" }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { redhat_message => $redhat_message }});
}
}
elsif (not $has_internet)
{
$redhat_message = $anvil->Template->get({file => "anvil.html", name => "host-setup-redhat-message", variables => { message => "#!string!message_01512#" }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { redhat_message => $redhat_message }});
* 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>
5 years ago
}
# Did we connect?
* 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>
5 years ago
if (not $connected)
{
# Nope. Is it because the target's key is bad or has changed?
my $query = "SELECT state_uuid, state_note FROM states WHERE state_name LIKE ".$anvil->Database->quote("host_key_changed::".$host_ip_address).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
if ($count)
{
# Yup, key has changed.
my $state_uuid = $results->[0]->[0];
my $state_note = $results->[0]->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
state_uuid => $state_uuid,
state_note => $state_note,
}});
my $bad_file = "";
my $bad_line = "";
foreach my $pair (split/,/, $state_note)
{
my ($variable, $value) = ($pair =~ /^(.*?)=(.*)$/);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pair => $pair,
variable => $variable,
value => $value,
}});
if ($variable eq "file")
{
$bad_file = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_file => $bad_file }});
}
if ($variable eq "line")
{
$bad_line = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_line => $bad_line }});
}
}
my $error_message = $anvil->Words->string({key => "warning_0013", variables => {
file => $bad_file,
line => $bad_line,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { error_message => $error_message }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
}
else
{
# Nope, some other issue
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0012"}) }});
}
* 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>
5 years ago
}
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 => "warning_0005", variables => { uuid => $target_host_uuid }}) }});
* 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>
5 years ago
}
else
{
# Connected! Ask th euser to confirm.
my $new_host_name = "#!string!striker_0139!#";
if ((exists $anvil->data->{cgi}{host_name}) && ($anvil->data->{cgi}{host_name}{value}))
{
$new_host_name = $anvil->data->{cgi}{host_name}{value};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_host_name => $new_host_name }});
* 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>
5 years ago
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "confirm-initialize-host", variables => {
'package' => $type eq "dr" ? "anvil-dr" : "anvil-node",
redhat_message => $redhat_message,
redhat_form => $redhat_form,
access => "root\@".$host_ip_address.":".$ssh_port,
current_host_name => $target_host_name,
new_host_name => $new_host_name,
host_uuid => $target_host_uuid,
default_host_name => $default_host_name,
* 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>
5 years ago
}});
$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 $host_name = $anvil->_host_name;
$host_name =~ s/striker\d\d/xxx/;
my $default_host_name = $host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
default_host_name => $default_host_name,
host_name => $host_name,
}});
if ((exists $anvil->data->{cgi}{host_name}) && ($anvil->data->{cgi}{host_name}{value}))
{
$host_name = $anvil->data->{cgi}{host_name}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
}
* 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>
5 years ago
my $form_body = $anvil->Template->get({file => "anvil.html", name => "host-setup-menu1", variables => {
host_name => $host_name,
default_host_name => $default_host_name,
host_ip_address => $host_ip_address,
node_checked => $node_checked,
dr_checked => $dr_checked,
* 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>
5 years ago
}});
$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);
}
# This enables or disables the Install Target feature
sub process_install_target
{
my ($anvil) = @_;
# NOTE: We don't ask for confirmation, it's a low risk task.
# What are we doing?
$anvil->data->{cgi}{subtask}{value} = "" if not defined $anvil->data->{cgi}{subtask}{value};
if (($anvil->data->{cgi}{subtask}{value} eq "enable") or ($anvil->data->{cgi}{subtask}{value} eq "disable"))
{
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'striker-manage-install-target'}." --".$anvil->data->{cgi}{subtask}{value},
job_data => "",
job_name => "install-target::".$anvil->data->{cgi}{task}{value},
job_title => "job_0015",
job_description => "job_0016",
job_progress => 0,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
# Show the use that the job has been saved.
my $message = "striker_0111";
if ($anvil->data->{cgi}{subtask}{value} eq "enable")
{
$message = "striker_0112";
}
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "job recorded", variables => {
title_id => "",
message_id => "",
reload_url => "/cgi-bin/".$THIS_FILE."?striker=true",
title => "#!string!striker_0044!#",
description => "#!string!".$message."!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
}
else
{
# Just ignore it, someone's mucking with the subask value.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0009"}) }});
}
return(0);
}
# This handles powering off or rebooting this machine
sub process_power
{
my ($anvil, $task) = @_;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { task => $task }});
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value};
if ($anvil->data->{cgi}{confirm}{value})
{
# Record the job!
my $job_command = $anvil->data->{path}{exe}{'anvil-manage-power'}." --reboot -y";
my $job_title = "job_0009";
my $job_description = "job_0006";
my $say_title = "#!string!job_0005!#";
my $say_description = "#!string!job_0006!#";
if ($task eq "poweroff")
{
$job_command = $anvil->data->{path}{exe}{'anvil-manage-power'}." --poweroff -y";
$job_title = "job_0010";
$job_description = "job_0008";
$say_title = "#!string!job_0007!#";
$say_description = "#!string!job_0008!#";
}
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $job_command,
job_data => "",
job_name => "reboot::system",
job_title => $job_title,
job_description => $job_description,
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,
title => $say_title,
description => $say_description,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
# Log the user out, just to be safe.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0215"});
$anvil->Account->logout({debug => 2});
}
else
{
# Show the screen the confirm the addition.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-action", variables => {
title => $task eq "poweroff" ? "#!string!job_0007!#" : "#!string!job_0005!#",
message => $task eq "poweroff" ? "#!string!striker_0101!#" : "#!string!striker_0100!#",
hidden_fields => "",
}});
}
return(0);
}
# This handles updating this Striker.
sub process_update
{
my ($anvil) = @_;
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value};
if ($anvil->data->{cgi}{confirm}{value})
{
# Record the job!
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 1,
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-update-system'},
job_data => "",
job_name => "update::system",
job_title => "job_0003",
job_description => "job_0004",
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,
title => "#!string!striker_0044!#",
description => "#!string!striker_0088!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
# Set maintenance mode.
$anvil->System->maintenance_mode({set => 1});
}
else
{
# Show the screen the confirm the addition.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-action", variables => {
title => "#!string!striker_0078!#",
message => "#!string!striker_0086!#",
hidden_fields => "",
}});
}
return(0);
}
# This handles reconfiguring the Striker system.
sub process_reconfig_page
{
my ($anvil) = @_;
# Later, this will let each piece be recondigured. For now, it simple reset the "configured flag so
# the next load will trigger the initial config again.
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value};
if ($anvil->data->{cgi}{confirm}{value})
{
# Update the configured variable
$anvil->Database->insert_or_update_variables({
variable_name => "system::configured",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
variable_value => 0,
update_value_only => 1,
});
# Done.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "reconfig-done"});
}
else
{
# Show the screen the confirm the addition.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-reconfig"});
}
return(0);
}
# This handles tasks related to setting up peer Strikers.
sub process_sync_page
{
my ($anvil) = @_;
# Setup some CGI values we might use.
$anvil->data->{cgi}{new_peer_access}{value} = "" if not defined $anvil->data->{cgi}{new_peer_access}{value};
$anvil->data->{cgi}{new_peer_password}{value} = "" if not defined $anvil->data->{cgi}{new_peer_password}{value};
$anvil->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value};
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value};
# This handles checkboxes
if (defined $anvil->data->{cgi}{new_peer_ping}{value})
{
$anvil->data->{cgi}{new_peer_ping}{value} = "" if $anvil->data->{cgi}{new_peer_ping}{value} ne "on";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_ping::value" => $anvil->data->{cgi}{new_peer_ping}{value} }});
}
else
{
$anvil->data->{cgi}{new_peer_ping}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_ping::value" => $anvil->data->{cgi}{new_peer_ping}{value} }});
}
if (defined $anvil->data->{cgi}{new_peer_bidirection}{value})
{
$anvil->data->{cgi}{new_peer_bidirection}{value} = "" if $anvil->data->{cgi}{new_peer_bidirection}{value} ne "on";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_bidirection::value" => $anvil->data->{cgi}{new_peer_bidirection}{value} }});
}
else
{
$anvil->data->{cgi}{new_peer_bidirection}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_peer_bidirection::value" => $anvil->data->{cgi}{new_peer_bidirection}{value} }});
}
# Are we deleting or adding a new peer?
if ($anvil->data->{cgi}{'delete'}{value})
{
delete_sync_peer($anvil);
}
elsif (($anvil->data->{cgi}{new_peer_access}{value}) && ($anvil->data->{cgi}{new_peer_password}{value} ne ""))
{
add_sync_peer($anvil);
}
# If we've got a body now, return.
if ($anvil->data->{form}{body})
{
# We're done
return(0);
}
my $host_uuid = $anvil->Get->host_uuid;
$anvil->Network->get_ips();
# We'll want to show the user way to access the local machine. For that, we'll loop through our own IPs.
my $inbound_table = "";
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{'local'}{interface}})
{
next if (($interface !~ /^bcn/) && ($interface !~ /^ifn/));
next if not $anvil->Validate->is_ipv4({ip => $anvil->data->{network}{'local'}{interface}{$interface}{ip}});
next if not $anvil->Validate->is_subnet_mask({subnet_mask => $anvil->data->{network}{'local'}{interface}{$interface}{subnet_mask}});
my ($network_type, $network_number) = ($interface =~ /^(.*?)(\d+)_/);
my $database_user = $anvil->data->{database}{$host_uuid}{user} ? $anvil->data->{database}{$host_uuid}{user} : $anvil->data->{sys}{database}{user};
my $database_port = $anvil->data->{database}{$host_uuid}{port};
my $network_key = $network_type eq "bcn" ? "striker_0018" : "striker_0022";
my $say_network = $anvil->Words->string({key => $network_key, variables => { number => $network_number }});
# The user 'admin' and the port 5432 are default, so only show them if they're non-standard.
my $access_string = $database_user."\@".$anvil->data->{network}{'local'}{interface}{$interface}{ip}.":".$database_port;
if (($database_port eq "5432") && ($database_user eq "admin"))
{
$access_string = $anvil->data->{network}{'local'}{interface}{$interface}{ip};
}
elsif ($database_port eq "5432")
{
$access_string = $database_user."\@".$anvil->data->{network}{'local'}{interface}{$interface}{ip};
}
elsif ($database_user eq "admin")
{
$access_string = $anvil->data->{network}{'local'}{interface}{$interface}{ip}.":".$database_port;
}
$inbound_table .= $anvil->Template->get({file => "striker.html", name => "striker-sync-inbound", variables => {
access => $access_string,
note => $say_network,
}});
}
# This needs to be loaded into a hash by target, the sorted. We'll build the table on sort.
my $peer_table = "";
foreach my $uuid (keys %{$anvil->data->{database}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }});
next if not $anvil->Validate->is_uuid({uuid => $uuid});
next if $uuid eq $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }});
my $host = $anvil->data->{database}{$uuid}{host} ? $anvil->data->{database}{$uuid}{host} : ""; # This should fail
my $port = $anvil->data->{database}{$uuid}{port} ? $anvil->data->{database}{$uuid}{port} : 5432;
my $name = $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name};
my $user = $anvil->data->{database}{$uuid}{user} ? $anvil->data->{database}{$uuid}{user} : $anvil->data->{sys}{database}{user};
my $ping = $anvil->data->{database}{$uuid}{ping} ? $anvil->data->{database}{$uuid}{ping} : 1;
my $password = $anvil->data->{database}{$uuid}{password} ? $anvil->data->{database}{$uuid}{password} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host,
port => $port,
name => $name,
user => $user,
ping => $ping,
password => $anvil->Log->is_secure($password),
}});
# Store it by name.
$anvil->data->{peers}{$host}{port} = $port;
$anvil->data->{peers}{$host}{name} = $name;
$anvil->data->{peers}{$host}{user} = $user;
$anvil->data->{peers}{$host}{ping} = $ping;
$anvil->data->{peers}{$host}{uuid} = $uuid;
$anvil->data->{peers}{$host}{password} = $password;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"peers::${host}::port" => $anvil->data->{peers}{$host}{port},
"peers::${host}::name" => $anvil->data->{peers}{$host}{name},
"peers::${host}::ping" => $anvil->data->{peers}{$host}{ping},
"peers::${host}::uuid" => $anvil->data->{peers}{$host}{uuid},
"peers::${host}::password" => $anvil->Log->is_secure($anvil->data->{peers}{$host}{password}),
}});
}
# Now peers are sortable by host name.
foreach my $host (sort {$a cmp $b} keys %{$anvil->data->{peers}})
{
my $port = $anvil->data->{peers}{$host}{port};
my $name = $anvil->data->{peers}{$host}{name};
my $user = $anvil->data->{peers}{$host}{user};
my $ping = $anvil->data->{peers}{$host}{ping};
my $uuid = $anvil->data->{peers}{$host}{uuid};
my $password = $anvil->data->{peers}{$host}{password};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host,
port => $port,
name => $name,
user => $user,
ping => $ping,
uuid => $uuid,
password => $anvil->Log->is_secure($password),
}});
$anvil->data->{cgi}{new_peer_password}{value} = "" if not defined $anvil->data->{cgi}{new_peer_password}{value};
$peer_table .= $anvil->Template->get({file => "striker.html", name => "striker-sync-entry", variables => {
uuid => $uuid,
access => $port eq 5432 ? $user."\@".$host : $user."\@".$host.":".$port,
password => $anvil->data->{cgi}{new_peer_password}{value},
say_ping => $ping ? "#!string!unit_0001!#" : "#!string!unit_0002!#",
}});
}
# Build the menu.
$anvil->data->{form}{refresh_link} = "?striker=true&task=sync";
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "striker-sync", variables => {
inbound_table => $inbound_table,
peer_table => $peer_table,
new_peer_access => defined $anvil->data->{cgi}{new_peer_access}{value} ? $anvil->data->{cgi}{new_peer_access}{value} : "",
new_peer_password => defined $anvil->data->{cgi}{new_peer_password}{value} ? $anvil->data->{cgi}{new_peer_password}{value} : "",
}});
return(0);
}
# This deletes a sync peer.
sub delete_sync_peer
{
my ($anvil) = @_;
my $uuid = $anvil->data->{cgi}{'delete'}{value};
my $host_name = $anvil->Get->host_name({host_uuid => $uuid});
my $host = $anvil->data->{database}{$uuid}{host} ? $anvil->data->{database}{$uuid}{host} : ""; # This should fail
my $name = $anvil->data->{database}{$uuid}{name} ? $anvil->data->{database}{$uuid}{name} : $anvil->data->{sys}{database}{name};
my $user = $anvil->data->{database}{$uuid}{user} ? $anvil->data->{database}{$uuid}{user} : $anvil->data->{sys}{database}{user};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
uuid => $uuid,
host_name => $host_name,
host => $host,
name => $name,
user => $user,
}});
# Is the delete confirmed?
if ($anvil->data->{cgi}{confirm}{value})
{
# OK, save the job!
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 3,
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'striker-manage-peers'}." --remove --host-uuid ".$uuid,
job_data => "",
job_name => "striker-peer::remove",
job_title => "job_0013",
job_description => "job_0014",
job_progress => 0,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
# Show the use that the job has been saved.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "job recorded", variables => {
title_id => "",
message_id => "",
reload_url => "/cgi-bin/".$THIS_FILE."?striker=true&task=sync",
title => "#!string!striker_0044!#",
description => "#!string!striker_0104!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
}
else
{
# Show the screen the confirm the addition.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-action", variables => {
title => "#!string!job_0013!#",
message => $anvil->Words->string({key => "striker_0105", variables => { peer => $user."\@".$host_name }}),
hidden_fields => "<input type=\"hidden\" name=\"delete\" id=\"delete\" value=\"".$uuid."\" />",
}});
}
return(0);
}
# This adds a new peer to anvil.conf.
sub add_sync_peer
{
my ($anvil) = @_;
# Break up the user, host and port. If anything goes wrong, we'll set an error and send it back.
my $pgsql_user = $anvil->data->{sys}{database}{user};
my $host = $anvil->data->{cgi}{new_peer_access}{value};
my $password = $anvil->data->{cgi}{new_peer_password}{value};
my $db_name = $anvil->data->{sys}{database}{name};
my $ping = $anvil->data->{cgi}{new_peer_ping}{value} eq "on" ? 1 : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pgsql_user => $pgsql_user,
host => $host,
password => $anvil->Log->is_secure($password),
db_name => $db_name,
ping => $ping,
}});
my $pgsql_port = 5432;
my $ssh_port = 22;
my $peer_host_uuid = "";
my $peer_host_name = "";
my $use_ip = ""; # This will contain the local IP to use for the peer to setup comms with us
if ($host =~ /,ssh=(\d+)$/)
{
$ssh_port = $1;
$host =~ s/,ssh=\d+$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ssh_port => $ssh_port,
host => $host,
}});
}
if ($host =~ /^(.*?)\@(.*?):(\d+)$/)
{
$pgsql_user = $1;
$host = $2;
$pgsql_port = $3;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host,
pgsql_port => $pgsql_port,
pgsql_user => $pgsql_user,
}});
}
elsif ($host =~ /^(.*?)\@(.*?)$/)
{
$pgsql_user = $1;
$host = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host,
pgsql_user => $pgsql_user,
}});
}
elsif ($host =~ /^(.*?):(\d+)$/)
{
$host = $1;
$pgsql_port = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host,
pgsql_port => $pgsql_port,
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ssh_port => $ssh_port,
host => $host,
pgsql_port => $pgsql_port,
pgsql_user => $pgsql_user,
}});
# Is the host a domain or IP?
# If so, and 'bi-directional' is set, verify we can ssh into the peer.
my $is_domain = $anvil->Validate->is_domain_name({name => $host});
my $is_ipv4 = $anvil->Validate->is_ipv4({ip => $host});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
is_domain => $is_domain,
is_ipv4 => $is_ipv4,
pgsql_port => $pgsql_port,
}});
if (((not $is_domain) && (not $is_ipv4)) or ($pgsql_port < 1) or ($pgsql_port > 65536))
{
# Bad host.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0002"}) }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
else
{
* 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>
5 years ago
my ($connected, $data) = $anvil->Striker->get_peer_data({
debug => 2,
target => $host,
password => $password,
port => $ssh_port,
});
* 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>
5 years ago
if ($data->{host_name})
{
* 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>
5 years ago
# 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,
}});
* 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>
5 years ago
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 => "warning_0005", variables => { uuid => $peer_host_uuid }}) }});
}
# Lastly, if bi-directional is set, make sure we have a way to talk to it.
$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 host name, 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 }});
if ((not $use_ip) or ($use_ip eq "!!error!!"))
{
# Can't do bi-directional
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0008", variables => { host => $host }}) }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
}
}
# Now, verify we can access the peer database. This will involve writting out a .pgpass file, then making a local system call.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
if (not $anvil->data->{form}{error_massage})
{
my $pgpass_file = "/tmp/.pgpass";
$password =~ s/:/\:/g;
my $body = $host.":".$pgsql_port.":".$db_name.":".$pgsql_user.":".$password;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => {
body => $body,
}});
$anvil->Storage->write_file({
file => $pgpass_file,
body => $body,
mode => "0600",
secure => 1,
overwrite => 1,
});
# This will return '1' only, if it works.
my ($db_access, $return_code) = $anvil->System->call({shell_call => "PGPASSFILE=\"".$pgpass_file."\" ".$anvil->data->{path}{exe}{psql}." --host ".$host." --port ".$pgsql_port." --dbname ".$db_name." --username ".$pgsql_user." --no-password --tuples-only --no-align --command \"SELECT 1\""});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { db_access => $db_access, return_code => $return_code }});
if ($db_access ne "1")
{
# Failed to connect.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0004"}) }});
}
# Delete the pgpass file.
unlink $pgpass_file;
}
# If an error was set, clear the 'save' and 'confirm' values.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
if ($anvil->data->{form}{error_massage})
{
$anvil->data->{cgi}{save}{value} = "";
$anvil->data->{cgi}{confirm}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
"cgi::confirm::value" => $anvil->data->{cgi}{confirm}{value},
}});
}
else
{
# Things look good. Is the save confirmed?
if ($anvil->data->{cgi}{confirm}{value})
{
# OK, save the job!
my $job_command = $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$peer_host_uuid." --host ".$host." --port ".$pgsql_port." --ping ".$ping;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
job_command => $job_command,
password => $anvil->Log->is_secure($password),
}});
# The job data will always contain the password for the peer, but also contain the
# command for the peer to add us if 'bidirectional' was selected. This has to be
# stored separately and not added directly as a job, because the peer is likely not
# in 'hosts' yet, and thus we can't reference it in 'job_host_uuid' at this point.
my $job_data = "password=".$password;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { job_data => $job_data }});
# Are we adding ourselves to the peer?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { use_ip => $use_ip }});
if ($use_ip)
{
# See which of our IPs match theirs. If the peer is a host name, first
my $host_uuid = $anvil->Get->host_uuid;
my $sql_port = $anvil->data->{database}{$host_uuid}{port};
my $job_command = $anvil->data->{path}{exe}{'striker-manage-peers'}." --add --host-uuid ".$host_uuid." --host ".$use_ip." --port ".$sql_port." --ping ".$ping;
$job_data .= "\npeer_job_command=".$job_command;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
job_command => $job_command,
job_data => $anvil->Log->is_secure($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."?striker=true&task=sync",
title => "#!string!striker_0044!#",
description => $ping ? "#!string!striker_0103!#" : "#!string!striker_0102!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
}
else
{
# Show the screen the confirm the addition.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "confirm-new-peer", variables => {
access => $pgsql_user."@".$host.":".$pgsql_port,
ping => $anvil->data->{cgi}{new_peer_ping}{value} ? "#!string!unit_0001!#" : "#!string!unit_0002!#",
bidirectional => $anvil->data->{cgi}{new_peer_bidirection}{value} ? "#!string!unit_0001!#" : "#!string!unit_0002!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
}
}
return(0);
}
# This shows the menus for configuring Striker.
sub configure_striker
{
my ($anvil) = @_;
# This will be true when the dashboard is unconfigured.
if (not $anvil->data->{cgi}{step}{value})
{
$anvil->data->{form}{body} = config_step1($anvil);
}
elsif ($anvil->data->{cgi}{step}{value} eq "step1")
{
# Sanity check step1.
my $sane = sanity_check_step1($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { sane => $sane }});
if ($sane)
{
# Step 1 was sane, show step 2.
$anvil->data->{form}{body} = config_step2($anvil);
}
else
{
# No good
$anvil->data->{form}{body} = config_step1($anvil);
}
}
elsif ($anvil->data->{cgi}{step}{value} eq "step2")
{
# Sanity check step1.
my $sane = sanity_check_step2($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { sane => $sane }});
if ($sane)
{
# Step 2 was sane, show step 3.
$anvil->data->{form}{body} = config_step3($anvil);
}
else
{
# No good
$anvil->data->{form}{body} = config_step2($anvil);
}
}
elsif ($anvil->data->{cgi}{step}{value} eq "step3")
{
# User has confirmed, update the system!
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 3,
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-configure-host'},
job_data => "form::config_step2",
job_name => "configure::network",
job_title => "job_0001",
job_description => "job_0002",
job_progress => 0,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { job_uuid => $job_uuid }});
# Set maintenance mode.
$anvil->System->maintenance_mode({set => 1});
# 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 => "network_job_recorded", variables => {
title_id => "",
message_id => "",
reload_url => "/cgi-bin/".$THIS_FILE,
title => "#!string!striker_0044!#",
description => "#!string!striker_0045!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
}
else
{
$anvil->data->{form}{body} = get_network_details_form($anvil);
}
return(0);
}
# This checks to see if anything is running that requires Striker being unavailable. If not, this returns
# '1'. If there is a job pending/running, it returns '0'
sub check_availability
{
my ($anvil) = @_;
my $available = 1;
# Check maintenance mode.
my $maintenance_mode = $anvil->System->maintenance_mode({debug => 3});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { maintenance_mode => $maintenance_mode }});
if ($maintenance_mode)
{
$available = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { available => $available }});
# If we have any running or recently finished jobs, we'll desplay them below.
$anvil->data->{say}{maintenance} = $anvil->Template->get({file => "striker.html", name => "striker-offline", variables => {
title_id => "",
message_id => "",
title => "#!string!striker_0046!#",
description => $anvil->Words->string({key => "striker_0090", variables => {} }),
job_list => $anvil->Job->html_list({debug => 2, ended_within => 300}),
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'say::maintenance' => $anvil->data->{say}{maintenance} }});
}
# TODO: Phase this out
if ($available)
{
my $query = "
SELECT
job_progress,
modified_date,
extract(epoch from modified_date)
FROM
jobs
WHERE
job_name = 'configure::network'
AND
job_progress != 100
AND
job_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
results => $results,
count => $count,
}});
if ($count)
{
# We're waiting for the network configuration
my $percent = $results->[0]->[0];
my $timestamp = $results->[0]->[1];
my $unixtime = $results->[0]->[2];
my $seconds_ago = $anvil->Convert->add_commas({number => (time - $unixtime)});
$available = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
available => $available,
percent => $percent,
seconds_ago => $seconds_ago,
timestamp => $timestamp,
unixtime => $unixtime,
}});
$anvil->data->{say}{maintenance} = $anvil->Template->get({file => "striker.html", name => "striker-offline", variables => {
title_id => "",
message_id => "",
title => "#!string!striker_0046!#",
description => $anvil->Words->string({key => "striker_0047", variables => { percent => $percent, timestamp => $timestamp, seconds_ago => $seconds_ago }}),
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'say::maintenance' => $anvil->data->{say}{maintenance} }});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { available => $available }});
return($available);
}
# This shows the user what is about to be done and asks the user to confirm.
sub config_step3
{
my ($anvil) = @_;
# Read in all the variables from the database. We don't care what was passed, the data in the
# database has been tested and is more valid than, say, a manipulated URL.
my $cgi = "";
my $nets = {};
my $query = "
SELECT
variable_name,
variable_value
FROM
variables
WHERE
(variable_section = 'config_step1' OR variable_section = 'config_step2')
AND
variable_source_table = 'hosts'
AND
variable_source_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
ORDER BY
variable_name ASC;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $variable_name = $row->[0];
my $variable_value = $row->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
variable_name => $variable_name,
variable_value => $variable_value,
}});
if ($variable_name =~ /form::config_step2::(.*?)::value/)
{
my $variable = $1;
$cgi .= $variable.",";
$anvil->data->{cgi}{$variable}{value} = $variable_value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${variable}::value" => $anvil->data->{cgi}{$variable}{value} }});
if (($variable =~ /^(bcn\d+)_/) or ($variable =~ /^(ifn\d+)_/))
{
my $this_net = $1;
$nets->{$this_net} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "nets->this_net" => $nets->{$this_net} }});
}
}
}
#foreach my $key (sort {$a cmp $b} keys %ENV) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "ENV{$key}" => $ENV{$key} }}); }
# Get the list of current IPs so that we can warn the user if committing the changes will require
# reconnecting.
$anvil->Network->get_ips({debug => 2});
my $matched_ip = 0;
my $server_ip = $ENV{SERVER_ADDR};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_ip => $server_ip }});
# We'll need to show how networks will be configured. This depends on;
# 1. Is it a bonded or single interface?
# 2. Is it the interface with the gateway?
# 3. If no gateway or DNS was specified, alert that there will be no outside access.
get_network_details($anvil);
my $networks = "";
foreach my $this_net (sort {$a cmp $b} keys %{$nets})
{
my $ip_key = $this_net."_ip";
my $subnet_mask_key = $this_net."_subnet_mask";
my $iface1_key = $this_net."_link1_mac_to_set";
my $iface2_key = $this_net."_link2_mac_to_set";
my $ip = $anvil->data->{cgi}{$ip_key}{value};
my $subnet_mask = $anvil->data->{cgi}{$subnet_mask_key}{value};
my $iface1_mac = $anvil->data->{cgi}{$iface1_key}{value};
my $iface2_mac = ((defined $anvil->data->{cgi}{$iface2_key}{value}) && ($anvil->data->{cgi}{$iface2_key}{value})) ? $anvil->data->{cgi}{$iface2_key}{value} : "";
my $template = $iface2_mac ? "step3_bonded_interface" : "step3_single_interface";
my $gateway = $anvil->data->{cgi}{gateway_interface}{value} eq $this_net ? 1 : 0;
my $link_number = ($this_net =~ /n(\d+)$/)[0];
my $column = $this_net =~ /^bcn/ ? "striker_0018" : "striker_0022";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:nets->this_net" => $nets->{$this_net},
"s2:ip" => $ip,
"s3:subnet_mask" => $subnet_mask,
"s4:iface1_mac" => $iface1_mac,
"s5:iface2_mac" => $iface2_mac,
"s6:template" => $template,
"s7:gateway" => $gateway,
"s8:link_number" => $link_number,
}});
# Add to the networks template.
my $say_ip = $ip."/".$subnet_mask;
if (($gateway) && ($anvil->data->{cgi}{gateway}{value}))
{
$template .= "_with_gateway";
$anvil->data->{cgi}{dns}{value} = "--" if not $anvil->data->{cgi}{dns}{value};
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { template => $template }});
$networks .= $anvil->Template->get({file => "config.html", name => $template, variables => {
column => $anvil->Words->string({key => $column, variables => { number => $link_number }}),
ip_address => $say_ip,
ip => $ip,
subnet_mask => $subnet_mask,
primary => $iface1_mac,
backup => $iface2_mac,
gateway => $anvil->data->{cgi}{gateway}{value},
dns => $anvil->data->{cgi}{dns}{value},
}})."\n";
# Does this interface's IP match the active one?
if ($server_ip eq $ip)
{
# Yup! No need to warn the user
$matched_ip = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { matched_ip => $matched_ip }});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { networks => $networks }});
# If the IP is going to change, warn the user.
if (not $matched_ip)
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "warning_0001"}) }});
}
# We don't need to store anything as hidden variables, we'll read it back from the database later.
my $step3_body = $anvil->Template->get({file => "config.html", name => "config_step3", variables => {
step1_welcome_title_id => "",
step1_welcome_message_id => "",
organization => $anvil->data->{cgi}{organization}{value},
prefix => $anvil->data->{cgi}{prefix}{value},
host_name => $anvil->data->{cgi}{host_name}{value},
striker_user => $anvil->data->{cgi}{striker_user}{value},
striker_password => $anvil->data->{cgi}{striker_password}{value},
networks => $networks,
show_name => 1,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { step3_body => $step3_body }});
return($step3_body);
}
# This is step2 where the user maps their network.
sub config_step2
{
my ($anvil) = @_;
# If I am coming from stage 1, load any values from the database, if they exist.
if ($anvil->data->{cgi}{step}{value} eq "step1")
{
# First load. See if we can read old data. We don't know for sure what variables will have
# been set, so we'll load anything from the group 'config_step2'.
my $query = "
SELECT
variable_name,
variable_value
FROM
variables
WHERE
variable_section = 'config_step2'
AND
variable_source_table = 'hosts'
AND
variable_source_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)."
ORDER BY
variable_name ASC;";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $variable_name = $row->[0];
my $variable_value = $row->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
variable_name => $variable_name,
variable_value => $variable_value,
}});
if ($variable_name =~ /form::config_step2::(.*?)::value/)
{
my $variable = $1;
$anvil->data->{cgi}{$variable}{value} = $variable_value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${variable}::value" => $anvil->data->{cgi}{$variable}{value} }});
}
}
}
# We need to decide how many IFNs there is, decide if we have enough NICs and then build the form
# either complaining about insufficient NICs or a list of interfaces (single or bond, depending on
# iface count), the IPs to assign and mapping MACs to ifaces. We'll also offer an option to
# "blind-map" as we did in v2.
get_network_details($anvil);
my $required_interfaces_for_single = 1 + $anvil->data->{cgi}{ifn_count}{value};
my $required_interfaces_for_bonds = 2 * $required_interfaces_for_single;
my $interface_count = keys %{$anvil->data->{interfaces}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
required_interfaces_for_single => $required_interfaces_for_single,
required_interfaces_for_bonds => $required_interfaces_for_bonds,
interface_count => $interface_count,
}});
my $interface_options = [];
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{interfaces}})
{
my $this_mac = $anvil->data->{interfaces}{$interface}{mac};
push @{$interface_options}, $this_mac."#!#".$interface." (".$this_mac.")";
}
my $problem = 0;
my $interface_form = "";
my $cgi = "";
my $links = [];
if ($interface_count >= $required_interfaces_for_bonds)
{
### Show the bonded ifaces form.
# BCN
my $bcn_count = $anvil->data->{cgi}{bcn_count}{value} ? $anvil->data->{cgi}{bcn_count}{value} : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bcn_count => $bcn_count }});
foreach my $bcn (1..$bcn_count)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bcn => $bcn }});
push @{$links}, "bcn_link".$bcn;
my $this_ip_key = "bcn".$bcn."_ip";
my $this_subnet_mask_key = "bcn".$bcn."_subnet_mask";
my $this_iface1_key = "bcn".$bcn."_link1_mac_to_set";
my $this_iface2_key = "bcn".$bcn."_link2_mac_to_set";
$cgi .= $this_ip_key.",".$this_subnet_mask_key.",".$this_iface1_key.",".$this_iface2_key.",";
my $this_ip = generate_ip($anvil, "bcn", $bcn, $anvil->data->{cgi}{sequence}{value});
my $this_ip_class = $anvil->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear";
my $this_subnet_mask_class = $anvil->data->{cgi}{$this_subnet_mask_key}{alert} ? "input_alert" : "input_clear";
my $this_iface1_class = $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear";
my $this_iface2_class = $anvil->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear";
# Build the interface select boxes...
my $this_iface1_form = $anvil->Template->select_form({
name => $this_iface1_key,
options => $interface_options,
blank => 1,
'sort' => 0,
selected => defined $anvil->data->{cgi}{$this_iface1_key}{value} ? $anvil->data->{cgi}{$this_iface1_key}{value} : "",
class => $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear",
});
my $this_iface2_form = $anvil->Template->select_form({
name => $this_iface2_key,
options => $interface_options,
blank => 1,
'sort' => 0,
selected => defined $anvil->data->{cgi}{$this_iface2_key}{value} ? $anvil->data->{cgi}{$this_iface2_key}{value} : "",
class => $anvil->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear",
});
# Assemble the form
$interface_form .= $anvil->Template->get({file => "config.html", name => "bonded_interface_form", variables => {
field => $anvil->Words->string({key => "striker_0018", variables => { number => $bcn }}),
description => "#!string!striker_0019!#",
ip_key => $this_ip_key,
ip_value => defined $anvil->data->{cgi}{$this_ip_key}{value} ? $anvil->data->{cgi}{$this_ip_key}{value} : "",
ip_value_default => $this_ip,
ip_class => $this_ip_class,
subnet_mask_key => $this_subnet_mask_key,
subnet_mask_value => defined $anvil->data->{cgi}{$this_subnet_mask_key}{value} ? $anvil->data->{cgi}{$this_subnet_mask_key}{value} : "",
subnet_mask_value_default => $anvil->data->{defaults}{network}{bcn}{subnet_mask},
subnet_mask_class => $this_subnet_mask_class,
iface1_select => $this_iface1_form,
iface2_select => $this_iface2_form,
}});
}
# IFN
my $ifn_count = $anvil->data->{cgi}{ifn_count}{value} ? $anvil->data->{cgi}{ifn_count}{value} : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ifn_count => $ifn_count }});
foreach my $ifn (1..$ifn_count)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ifn => $ifn }});
push @{$links}, "ifn_link".$ifn;
my $this_ip_key = "ifn".$ifn."_ip";
my $this_subnet_mask_key = "ifn".$ifn."_subnet_mask";
my $this_iface1_key = "ifn".$ifn."_link1_mac_to_set";
my $this_iface2_key = "ifn".$ifn."_link2_mac_to_set";
$cgi .= $this_ip_key.",".$this_subnet_mask_key.",".$this_iface1_key.",".$this_iface2_key.",";
my $this_ip = generate_ip($anvil, "ifn", $ifn, $anvil->data->{cgi}{sequence}{value});
my $this_ip_class = $anvil->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear";
my $this_subnet_mask_class = $anvil->data->{cgi}{$this_subnet_mask_key}{alert} ? "input_alert" : "input_clear";
my $this_iface1_class = $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear";
my $this_iface2_class = $anvil->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear";
# Build the interface select boxes...
my $this_iface1_form = $anvil->Template->select_form({
name => $this_iface1_key,
options => $interface_options,
blank => 1,
selected => defined $anvil->data->{cgi}{$this_iface1_key}{value} ? $anvil->data->{cgi}{$this_iface1_key}{value} : "",
class => $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear",
});
my $this_iface2_form = $anvil->Template->select_form({
name => $this_iface2_key,
options => $interface_options,
blank => 1,
selected => defined $anvil->data->{cgi}{$this_iface2_key}{value} ? $anvil->data->{cgi}{$this_iface2_key}{value} : "",
class => $anvil->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear",
});
# Assemble the form
$interface_form .= $anvil->Template->get({file => "config.html", name => "bonded_interface_form", variables => {
field => $anvil->Words->string({key => "striker_0022", variables => { number => $ifn }}),
description => "#!string!striker_0023!#",
ip_key => $this_ip_key,
ip_value => defined $anvil->data->{cgi}{$this_ip_key}{value} ? $anvil->data->{cgi}{$this_ip_key}{value} : "",
ip_value_default => $this_ip,
ip_class => $this_ip_class,
subnet_mask_key => $this_subnet_mask_key,
subnet_mask_value => defined $anvil->data->{cgi}{$this_subnet_mask_key}{value} ? $anvil->data->{cgi}{$this_subnet_mask_key}{value} : "",
subnet_mask_value_default => $anvil->data->{defaults}{network}{ifn}{subnet_mask},
subnet_mask_class => $this_subnet_mask_class,
iface1_select => $this_iface1_form,
iface2_select => $this_iface2_form,
}});
}
}
else
{
### Show the single iface per network form.
# BCN
my $bcn_count = $anvil->data->{cgi}{bcn_count}{value} ? $anvil->data->{cgi}{bcn_count}{value} : 1;
foreach my $bcn (1..$bcn_count)
{
push @{$links}, "bcn_link".$bcn;
my $this_ip_key = "bcn".$bcn."_ip";
my $this_subnet_mask_key = "bcn".$bcn."_subnet_mask";
my $this_iface1_key = "bcn".$bcn."_link1_mac_to_set";
$cgi .= $this_ip_key.",".$this_subnet_mask_key.",".$this_iface1_key.",";
my $this_ip = generate_ip($anvil, "bcn", $bcn, $anvil->data->{cgi}{sequence}{value});
my $this_ip_class = $anvil->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear";
my $this_subnet_mask_class = $anvil->data->{cgi}{$this_subnet_mask_key}{alert} ? "input_alert" : "input_clear";
my $this_iface1_class = $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear";
# Build the interface select boxes...
my $this_iface1_form = $anvil->Template->select_form({
name => $this_iface1_key,
options => $interface_options,
blank => 1,
selected => defined $anvil->data->{cgi}{$this_iface1_key}{value} ? $anvil->data->{cgi}{$this_iface1_key}{value} : "",
class => $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear",
});
# Assemble the form
$interface_form .= $anvil->Template->get({file => "config.html", name => "single_interface_form", variables => {
field => $anvil->Words->string({key => "striker_0018", variables => { number => $bcn }}),
description => "#!string!striker_0019!#",
ip_key => $this_ip_key,
ip_value => defined $anvil->data->{cgi}{$this_ip_key}{value} ? $anvil->data->{cgi}{$this_ip_key}{value} : "",
ip_value_default => $this_ip,
ip_class => $this_ip_class,
subnet_mask_key => $this_subnet_mask_key,
subnet_mask_value => defined $anvil->data->{cgi}{$this_subnet_mask_key}{value} ? $anvil->data->{cgi}{$this_subnet_mask_key}{value} : $anvil->data->{defaults}{network}{bcn}{subnet_mask},
subnet_mask_value_default => $anvil->data->{defaults}{network}{bcn}{subnet_mask},
subnet_mask_class => $this_subnet_mask_class,
iface1_select => $this_iface1_form,
}});
}
# IFN
my $ifn_count = $anvil->data->{cgi}{ifn_count}{value} ? $anvil->data->{cgi}{ifn_count}{value} : 1;
foreach my $ifn (1..$ifn_count)
{
push @{$links}, "ifn_link".$ifn;
my $this_ip_key = "ifn".$ifn."_ip";
my $this_subnet_mask_key = "ifn".$ifn."_subnet_mask";
my $this_iface1_key = "ifn".$ifn."_link1_mac_to_set";
$cgi .= $this_ip_key.",".$this_subnet_mask_key.",".$this_iface1_key.",";
my $this_ip = generate_ip($anvil, "ifn", $ifn, $anvil->data->{cgi}{sequence}{value});
my $this_ip_class = $anvil->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear";
my $this_subnet_mask_class = $anvil->data->{cgi}{$this_subnet_mask_key}{alert} ? "input_alert" : "input_clear";
my $this_iface1_class = $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear";
# Build the interface select boxes...
my $this_iface1_form = $anvil->Template->select_form({
name => $this_iface1_key,
options => $interface_options,
blank => 1,
selected => defined $anvil->data->{cgi}{$this_iface1_key}{value} ? $anvil->data->{cgi}{$this_iface1_key}{value} : "",
class => $anvil->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear",
});
# Assemble the form
$interface_form .= $anvil->Template->get({file => "config.html", name => "single_interface_form", variables => {
field => $anvil->Words->string({key => "striker_0022", variables => { number => $ifn }}),
description => "#!string!striker_0023!#",
ip_key => $this_ip_key,
ip_value => defined $anvil->data->{cgi}{$this_ip_key}{value} ? $anvil->data->{cgi}{$this_ip_key}{value} : "",
ip_value_default => $this_ip,
ip_class => $this_ip_class,
subnet_mask_key => $this_subnet_mask_key,
subnet_mask_value => defined $anvil->data->{cgi}{$this_subnet_mask_key}{value} ? $anvil->data->{cgi}{$this_subnet_mask_key}{value} : $anvil->data->{defaults}{network}{ifn}{subnet_mask},
subnet_mask_value_default => $anvil->data->{defaults}{network}{ifn}{subnet_mask},
subnet_mask_class => $this_subnet_mask_class,
iface1_select => $this_iface1_form,
}});
}
}
### TODO: Add a form for Gateway, DNS and which interface to use
# Gateway
my $gateway_class = $anvil->data->{cgi}{gateway}{alert} ? "input_alert" : "input_clear";
my $say_gateway = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "gateway",
id => "gateway",
field => "#!string!striker_0035!#",
description => "#!string!striker_0036!#",
value => defined $anvil->data->{cgi}{gateway}{value} ? $anvil->data->{cgi}{gateway}{value} : "",
default_value => "",
class => $gateway_class,
extra => "",
}});
# DNS
my $dns_class = $anvil->data->{cgi}{dns}{alert} ? "input_alert" : "input_clear";
my $say_dns = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "dns",
id => "dns",
field => "#!string!striker_0037!#",
description => "#!string!striker_0038!#",
value => defined $anvil->data->{cgi}{dns}{value} ? $anvil->data->{cgi}{dns}{value} : "",
default_value => $anvil->data->{defaults}{network}{dns},
class => $dns_class,
extra => "",
}});
# Which interface gets the route?
my $default_dg_iface = defined $anvil->data->{cgi}{dg_iface}{value} ? $anvil->data->{cgi}{dg_iface}{value} : "ifn_link1";
my $dg_iface_select = $anvil->Template->select_form({
name => "dg_iface",
options => $links,
blank => 0,
selected => $default_dg_iface,
class => $anvil->data->{cgi}{dg_iface}{alert} ? "input_alert" : "input_clear",
});
### NOTE: I'll likely want this for choosing which interface to use as the default gateway when 2+
### IFNs are used.
# my $dg_iface_class = $anvil->data->{cgi}{dg_iface}{alert} ? "input_alert" : "input_clear";
# my $say_dg_iface = $anvil->Template->get({file => "main.html", name => "input_select_form", variables => {
# field => "#!string!striker_0039!#",
# description => "#!string!striker_0040!#",
# 'select' => "",
# }});
# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { say_dg_iface => $say_dg_iface }});
# Hostname
my $say_default_host_name = $anvil->data->{cgi}{prefix}{value}."-striker0".$anvil->data->{cgi}{sequence}{value}.".".$anvil->data->{cgi}{domain}{value};
my $host_name_class = $anvil->data->{cgi}{host_name}{alert} ? "input_alert" : "input_clear";
my $say_host_name = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "host_name",
id => "host_name",
field => "#!string!striker_0016!#",
description => "#!string!striker_0017!#",
value => defined $anvil->data->{cgi}{host_name}{value} ? $anvil->data->{cgi}{host_name}{value} : $say_default_host_name,
default_value => "",
class => $host_name_class,
extra => "",
}});
# Admin user
my $striker_user_class = $anvil->data->{cgi}{striker_user}{alert} ? "input_alert" : "input_clear";
my $say_striker_user = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "striker_user",
id => "striker_user",
field => "#!string!striker_0031!#",
description => "#!string!striker_0032!#",
value => defined $anvil->data->{cgi}{striker_user}{value} ? $anvil->data->{cgi}{striker_user}{value} : $anvil->data->{sys}{user}{name},
default_value => "",
class => $striker_user_class,
extra => "",
}});
# Password
my $striker_password_class = $anvil->data->{cgi}{striker_password}{alert} ? "input_alert" : "input_clear";
my $say_striker_password = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "striker_password",
id => "striker_password",
field => "#!string!striker_0033!#",
description => "#!string!striker_0034!#",
value => defined $anvil->data->{cgi}{striker_password}{value} ? $anvil->data->{cgi}{striker_password}{value} : "",
default_value => "",
class => $striker_password_class,
extra => "",
}});
# Get the table that shows the current interface states.
my $interface_states = get_network_details_form($anvil);
# Store the previous CGI variables and display the new fields.
my $step2_body = $anvil->Template->get({file => "config.html", name => "config_step2", variables => {
step1_welcome_title_id => "",
step1_welcome_message_id => "",
organization => $anvil->data->{cgi}{organization}{value},
prefix => $anvil->data->{cgi}{prefix}{value},
domain => $anvil->data->{cgi}{domain}{value},
sequence => $anvil->data->{cgi}{sequence}{value},
bcn_count => $anvil->data->{cgi}{bcn_count}{value},
ifn_count => $anvil->data->{cgi}{ifn_count}{value},
interface_form => $interface_form,
interface_states => $interface_states,
striker_user_form => $say_striker_user,
striker_password_form => $say_striker_password,
gateway_form => $say_gateway,
dns_form => $say_dns,
host_name_form => $say_host_name,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { step2_body => $step2_body }});
return($step2_body);
}
# This sanity-checks step 2 and returns '1' if there was a problem.
sub sanity_check_step2
{
my ($anvil) = @_;
# This will flip if we run into a problem.
my $sane = 1;
# Do we have a host name, striker user and password?
if (not $anvil->Validate->form_field({name => "host_name", type => "domain_name"}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0012"}) }});
$anvil->data->{cgi}{host_name}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }});
}
else
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::host_name::value",
variable_value => $anvil->data->{cgi}{host_name}{value},
variable_default => "",
variable_description => "striker_0017",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# The user name
if ((not defined $anvil->data->{cgi}{striker_user}{value}) or (not $anvil->data->{cgi}{striker_user}{value}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0013"}) }});
$anvil->data->{cgi}{striker_user}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::striker_user::alert" => $anvil->data->{cgi}{striker_user}{alert} }});
}
else
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::striker_user::value",
variable_value => $anvil->data->{cgi}{striker_user}{value},
variable_default => "",
variable_description => "striker_0032",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# The password
if ((not defined $anvil->data->{cgi}{striker_password}{value}) or (not $anvil->data->{cgi}{striker_password}{value}) or (length($anvil->data->{cgi}{striker_password}{value}) < 6))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0014"}) }});
$anvil->data->{cgi}{striker_password}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::striker_password::alert" => $anvil->data->{cgi}{striker_password}{alert} }});
}
else
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::striker_password::value",
variable_value => $anvil->data->{cgi}{striker_password}{value},
variable_default => "",
variable_description => "striker_0034",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# DNS can be multiple entries, comma-separated. It can also be blank, if the user doesn't need Internet access.
my $dns_ok = 1;
if ((defined $anvil->data->{cgi}{dns}{value}) and ($anvil->data->{cgi}{dns}{value}))
{
foreach my $ip (split/,/, $anvil->data->{cgi}{dns}{value})
{
$ip =~ s/^\s+//;
$ip =~ s/\s+$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip => $ip }});
if (not $anvil->Validate->is_ipv4({ip => $ip}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0015"}) }});
$anvil->data->{cgi}{dns}{alert} = 1;
$sane = 0;
$dns_ok = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, dns_ok => $dns_ok, "cgi::dns::alert" => $anvil->data->{cgi}{dns}{alert} }});
}
}
}
if ($dns_ok)
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::dns::value",
variable_value => $anvil->data->{cgi}{dns}{value},
variable_default => "",
variable_description => "striker_0038",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# Look for interfaces and sanity check them.
my $networks = {};
foreach my $network ("bcn", "ifn")
{
my $count_key = $network."_count";
my $network_count = $anvil->data->{cgi}{$count_key}{value} ? $anvil->data->{cgi}{$count_key}{value} : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
network => $network,
count_key => $count_key,
network_count => $network_count,
}});
foreach my $count (1..$network_count)
{
my $this_network = $network.$count;
my $this_ip_key = $this_network."_ip";
my $this_subnet_mask_key = $this_network."_subnet_mask";
my $this_iface1_key = $this_network."_link1_mac_to_set";
my $this_iface2_key = $this_network."_link2_mac_to_set";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
count => $count,
this_ip_key => $this_ip_key,
this_subnet_mask_key => $this_subnet_mask_key,
this_iface1_key => $this_iface1_key,
this_iface2_key => $this_iface2_key,
"cgi::${this_ip_key}::value" => $anvil->data->{cgi}{$this_ip_key}{value},
"cgi::${this_subnet_mask_key}::value" => $anvil->data->{cgi}{$this_subnet_mask_key}{value},
"cgi::${this_iface1_key}::value" => $anvil->data->{cgi}{$this_iface1_key}{value},
"cgi::${this_iface2_key}::value" => $anvil->data->{cgi}{$this_iface2_key}{value},
}});
# This will be used to tell the user which interface has a problem, if one exists.
my $network_key = $network =~ /^bcn/ ? "striker_0018" : "striker_0022";
my $say_network = $anvil->Words->string({key => $network_key, variables => { number => $count }});
# Is the IP sane?
my $ip_ok = 1;
if (not $anvil->Validate->form_field({name => $this_ip_key, type => "ipv4"}))
{
# Nope
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0016", variables => { network => $say_network}}) }});
$anvil->data->{cgi}{$this_ip_key}{alert} = 1;
$sane = 0;
$ip_ok = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, ip_ok => $ip_ok }});
}
else
{
# Save the IP
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::${this_ip_key}::value",
variable_value => $anvil->data->{cgi}{$this_ip_key}{value},
variable_default => "",
variable_description => "striker_0024",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# What about the subnet mask?
if (not $anvil->Validate->form_field({name => $this_subnet_mask_key, type => "subnet_mask"}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0016", variables => { network => $say_network }}) }});
$anvil->data->{cgi}{$this_subnet_mask_key}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }});
}
elsif ($ip_ok)
{
# We'll use the dotted-decimal subnet_mask. If it already is, great. If not, convert it.
my $say_subnet_mask = $anvil->data->{cgi}{$this_subnet_mask_key}{value} =~ /^\d{1,2}$/ ? $anvil->Convert->cide({cidr => $anvil->data->{cgi}{$this_subnet_mask_key}{value}}) : $anvil->data->{cgi}{$this_subnet_mask_key}{value};
my $full_ip = $anvil->data->{cgi}{$this_ip_key}{value}."/".$anvil->data->{cgi}{$this_subnet_mask_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_subnet_mask => $say_subnet_mask, full_ip => $full_ip }});
$networks->{$this_network} = $full_ip;
# Save the subnet mask
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::${this_subnet_mask_key}::value",
variable_value => $anvil->data->{cgi}{$this_subnet_mask_key}{value},
variable_default => "",
variable_description => "striker_0025",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# Interface 1 must be set
if (not $anvil->Validate->form_field({name => $this_iface1_key, type => "mac"}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0017", variables => { network => $say_network, 'link' => "1" }}) }});
$anvil->data->{cgi}{$this_iface1_key}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }});
}
else
{
# Valid MAC. Has it been assigned elsewhere?
my $mac_address = $anvil->data->{cgi}{$this_iface1_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { mac_address => $mac_address }});
if ((not exists $anvil->data->{network}{$mac_address}{set_as}) or (not $anvil->data->{network}{$mac_address}{set_as}))
{
$anvil->data->{network}{$mac_address}{set_as} = $this_iface1_key;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "network::${mac_address}::set_as" => $anvil->data->{network}{$mac_address}{set_as} }});
# Record the answer.
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::${this_iface1_key}::value",
variable_value => $anvil->data->{cgi}{$this_iface1_key}{value},
variable_default => "",
variable_description => "striker_0029",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
else
{
# Conflict! Set the alert for this interface and the conflicting one.
my $conflict_key = $anvil->data->{network}{$mac_address}{set_as};
$anvil->data->{cgi}{$conflict_key}{alert} = 1;
$anvil->data->{cgi}{$this_iface1_key}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0018"}) }});
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::${conflict_key}::alert" => $anvil->data->{cgi}{$conflict_key}{alert},
"cgi::${this_iface1_key}::alert" => $anvil->data->{cgi}{$this_iface1_key}{alert},
}});
}
}
# Interface 2 doesn't have to be set.
if ((defined $anvil->data->{cgi}{$this_iface2_key}{value}) && ($anvil->data->{cgi}{$this_iface2_key}{value}))
{
if (not $anvil->Validate->form_field({name => $this_iface2_key, type => "mac"}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0017", variables => { network => $say_network, 'link' => "2" }}) }});
$anvil->data->{cgi}{$this_iface2_key}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }});
}
else
{
# Valid MAC. Has it been assigned elsewhere?
my $mac_address = $anvil->data->{cgi}{$this_iface2_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { mac_address => $mac_address }});
if ((not exists $anvil->data->{network}{$mac_address}{set_as}) or (not $anvil->data->{network}{$mac_address}{set_as}))
{
$anvil->data->{network}{$mac_address}{set_as} = $this_iface2_key;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "network::${mac_address}::set_as" => $anvil->data->{network}{$mac_address}{set_as} }});
# Record the answer.
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::${this_iface2_key}::value",
variable_value => $anvil->data->{cgi}{$this_iface2_key}{value},
variable_default => "",
variable_description => "striker_0030",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
else
{
# Conflict! Set the alert for this interface and the conflicting one.
my $conflict_key = $anvil->data->{network}{$mac_address}{set_as};
$anvil->data->{cgi}{$conflict_key}{alert} = 1;
$anvil->data->{cgi}{$this_iface2_key}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0018"}) }});
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::${conflict_key}::alert" => $anvil->data->{cgi}{$conflict_key}{alert},
"cgi::${this_iface2_key}::alert" => $anvil->data->{cgi}{$this_iface2_key}{alert},
}});
}
}
}
}
}
# The gateway, this has to be after the interfaces so that we can match it to an interface (and error
# if not)
if (not $anvil->Validate->form_field({name => "gateway", type => "ipv4", empty_ok => 1}))
{
$anvil->data->{cgi}{gateway}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0019"}) }});
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }});
}
else
{
# Convert the gateway strings to binary.
my $gateway = defined $anvil->data->{cgi}{gateway}{value} ? $anvil->data->{cgi}{gateway}{value} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { gateway => $gateway }});
# If there is no gateway, that's OK, there just won't be any Internet access.
my $gateway_interface = "";
if ($gateway)
{
# Match this gateway to one of the interfaces.
foreach my $this_network (sort {$a cmp $b} keys %{$networks})
{
my ($this_ip, $this_subnet_mask) = ($networks->{$this_network} =~ /^(.*?)\/(.*)$/);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"s1:this_network" => $this_network,
"s2:networks->$this_network" => $networks->{$this_network},
"s3:this_ip" => $this_ip,
"s4:this_subnet_mask" => $this_subnet_mask,
}});
my $first = NetAddr::IP->new("$this_ip/$this_subnet_mask");
my $second = NetAddr::IP->new("$gateway/$this_subnet_mask");
if ($second->within($first))
{
$gateway_interface = $this_network;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { gateway_interface => $gateway_interface }});
}
}
if (not $gateway_interface)
{
# Explain the problem
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0004"}) }});
$anvil->data->{cgi}{gateway}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::gateway::alert" => $anvil->data->{cgi}{gateway}{alert} }});
}
}
# If no alert was raised, record the values.
if (not $anvil->data->{cgi}{gateway}{alert})
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::gateway::value",
variable_value => $anvil->data->{cgi}{gateway}{value},
variable_default => "",
variable_description => "striker_0036",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
# Record the gateway interface
$anvil->Database->insert_or_update_variables({
variable_name => "form::config_step2::gateway_interface::value",
variable_value => $gateway_interface,
variable_default => "",
variable_description => "",
variable_section => "config_step2",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { sane => $sane }});
return($sane);
}
# This sanity-checks step 1 and returns '1' if there was a problem.
sub sanity_check_step1
{
my ($anvil) = @_;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0131", variables => { function => "sanity_check_step1()" }});
# This will flip if we run into a problem.
my $sane = 1;
$anvil->data->{cgi}{organization}{value} = "" if not defined $anvil->data->{cgi}{organization}{value};
# Organization just needs *something*
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::organization::alert" => $anvil->data->{cgi}{organization}{alert},
}});
if (not $anvil->data->{cgi}{organization}{value})
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0020", variables => { field => "striker_0003" }}) }});
$anvil->data->{cgi}{organization}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::organization::alert" => $anvil->data->{cgi}{organization}{alert} }});
}
else
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step1::organization::value",
variable_value => $anvil->data->{cgi}{organization}{value},
variable_default => "",
variable_description => "striker_0004",
variable_section => "config_step1",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# The prefix needs to be alphanumeric and be between 1 ~ 5 chatacters.
if ((not $anvil->Validate->is_alphanumeric({string => $anvil->data->{cgi}{prefix}{value}})) or (length($anvil->data->{cgi}{prefix}{value}) > 5))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0021"}) }});
$anvil->data->{cgi}{prefix}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::prefix::alert" => $anvil->data->{cgi}{prefix}{alert} }});
}
else
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step1::prefix::value",
variable_value => $anvil->data->{cgi}{prefix}{value},
variable_default => "",
variable_description => "striker_0006",
variable_section => "config_step1",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# We can use Validate to check the domain.
if (not $anvil->Validate->form_field({name => "domain", type => "domain_name"}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0020", variables => { field => "striker_0007" }}) }});
$anvil->data->{cgi}{domain}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }});
}
else
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step1::domain::value",
variable_value => $anvil->data->{cgi}{domain}{value},
variable_default => "",
variable_description => "striker_0008",
variable_section => "config_step1",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
# The sequence and IFN count need to be integers.
if (not $anvil->Validate->is_positive_integer({number => $anvil->data->{cgi}{sequence}{value}}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0022", variables => { field => "striker_0009" }}) }});
$anvil->data->{cgi}{sequence}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::sequence::alert" => $anvil->data->{cgi}{sequence}{alert} }});
}
else
{
# Record the answer.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step1::sequence::value",
variable_value => $anvil->data->{cgi}{sequence}{value},
variable_default => "",
variable_description => "striker_0010",
variable_section => "config_step1",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
if (not $anvil->Validate->is_positive_integer({number => $anvil->data->{cgi}{ifn_count}{value}}))
{
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $anvil->Words->string({key => "error_0022", variables => { field => "striker_0011" }}) }});
$anvil->data->{cgi}{ifn_count}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::ifn_count::alert" => $anvil->data->{cgi}{ifn_count}{alert} }});
}
# Make sure we have enough interfaces.
get_network_details($anvil);
my $required_interfaces_for_single = 1 + $anvil->data->{cgi}{ifn_count}{value};
my $interface_count = keys %{$anvil->data->{interfaces}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
required_interfaces_for_single => $required_interfaces_for_single,
interface_count => $interface_count,
}});
if ($interface_count < $required_interfaces_for_single)
{
# Build the error message.
my $say_message = $anvil->Words->string({key => "error_0001", variables => {
interface_count => $interface_count,
required_interfaces_for_single => $required_interfaces_for_single,
}});
# Not enough interfaces found.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $say_message }});
$anvil->data->{cgi}{ifn_count}{alert} = 1;
$sane = 0;
}
else
{
# Sane, Record the answers.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step1::ifn_count::value",
variable_value => $anvil->data->{cgi}{ifn_count}{value},
variable_default => "",
variable_description => "striker_0012",
variable_section => "config_step1",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
return($sane);
}
# This is step 1 in asking the user how to configure Striker.
sub config_step1
{
my ($anvil) = @_;
if (not $anvil->data->{cgi}{'next'}{value})
{
# First load. See if we can read old data.
my ($organization) = $anvil->Database->read_variable({
variable_name => "form::config_step1::organization::value",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
my ($prefix) = $anvil->Database->read_variable({
variable_name => "form::config_step1::prefix::value",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
my ($domain) = $anvil->Database->read_variable({
variable_name => "form::config_step1::domain::value",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
my ($sequence) = $anvil->Database->read_variable({
variable_name => "form::config_step1::sequence::value",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
my ($ifn_count) = $anvil->Database->read_variable({
variable_name => "form::config_step1::ifn_count::value",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
organization => $organization,
prefix => $prefix,
domain => $domain,
sequence => $sequence,
ifn_count => $ifn_count,
}});
$anvil->data->{cgi}{organization}{value} = $organization ne "" ? $organization : "";
$anvil->data->{cgi}{prefix}{value} = $prefix ne "" ? $prefix : "";
$anvil->data->{cgi}{domain}{value} = $domain ne "" ? $domain : "";
$anvil->data->{cgi}{sequence}{value} = $sequence ne "" ? $sequence : "";
$anvil->data->{cgi}{ifn_count}{value} = $ifn_count ne "" ? $ifn_count : 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::organization::value' => $anvil->data->{cgi}{organization}{value},
'cgi::prefix::value' => $anvil->data->{cgi}{prefix}{value},
'cgi::domain::value' => $anvil->data->{cgi}{domain}{value},
'cgi::sequence::value' => $anvil->data->{cgi}{sequence}{value},
'cgi::ifn_count::value' => $anvil->data->{cgi}{ifn_count}{value},
}});
# If we don't have an organization name, prefix, domain name or sequence number, try to parse it from
# the current static and pretty host_names.
my ($traditional_host_name, $descriptive_host_name) = $anvil->System->host_name();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
traditional_host_name => $traditional_host_name,
descriptive_host_name => $descriptive_host_name,
}});
if ($descriptive_host_name =~ /^(.*?) - Striker (\d+)/)
{
my $organization = $1;
my $sequence = $2;
$sequence =~ s/^0+//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
organization => $organization,
sequence => $sequence,
}});
if (($organization) && ($anvil->data->{cgi}{organization}{value} eq ""))
{
$anvil->data->{cgi}{organization}{value} = $organization;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::organization::value' => $anvil->data->{cgi}{organization}{value},
}});
}
if (($sequence =~ /^\d+$/) && ($anvil->data->{cgi}{sequence}{value} eq ""))
{
$anvil->data->{cgi}{sequence}{value} = $sequence;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::sequence::value' => $anvil->data->{cgi}{sequence}{value},
}});
}
}
if ($traditional_host_name =~ /^(.*?)-striker\d+\.(.*)$/)
{
my $prefix = $1;
my $domain = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
prefix => $prefix,
domain => $domain,
}});
if (($prefix) && ($anvil->data->{cgi}{prefix}{value} eq ""))
{
$anvil->data->{cgi}{prefix}{value} = $prefix;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::prefix::value' => $anvil->data->{cgi}{prefix}{value},
}});
}
if (($domain) && ($anvil->data->{cgi}{domain}{value} eq ""))
{
$anvil->data->{cgi}{domain}{value} = $domain;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::domain::value' => $anvil->data->{cgi}{domain}{value},
}});
}
}
# If I still don't have a sequence number, set '1'.
if ($anvil->data->{cgi}{sequence}{value} eq "")
{
$anvil->data->{cgi}{sequence}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::sequence::value' => $anvil->data->{cgi}{sequence}{value},
}});
}
}
my $organization_class = $anvil->data->{cgi}{organization}{alert} ? "input_alert" : "input_clear";
my $say_organization = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "organization",
id => "organization",
field => "#!string!striker_0003!#",
description => "#!string!striker_0004!#",
value => defined $anvil->data->{cgi}{organization}{value} ? $anvil->data->{cgi}{organization}{value} : "",
default_value => "",
class => $organization_class,
extra => "",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_organization => $say_organization }});
my $prefix_class = $anvil->data->{cgi}{prefix}{alert} ? "input_alert" : "input_clear";
my $say_prefix = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "prefix",
id => "prefix",
field => "#!string!striker_0005!#",
description => "#!string!striker_0006!#",
value => defined $anvil->data->{cgi}{prefix}{value} ? $anvil->data->{cgi}{prefix}{value} : "",
default_value => "",
class => $prefix_class,
extra => "maxlength=\"5\"",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_prefix => $say_prefix }});
my $domain_class = $anvil->data->{cgi}{domain}{alert} ? "input_alert" : "input_clear";
my $say_domain = $anvil->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "domain",
id => "domain",
field => "#!string!striker_0007!#",
description => "#!string!striker_0008!#",
value => defined $anvil->data->{cgi}{domain}{value} ? $anvil->data->{cgi}{domain}{value} : "",
default_value => "",
class => $domain_class,
extra => "maxlength=\"255\"",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_domain => $say_domain }});
my $sequence_class = $anvil->data->{cgi}{sequence}{alert} ? "input_alert" : "input_clear";
my $say_sequence = $anvil->Template->get({file => "main.html", name => "input_number_form", variables => {
name => "sequence",
id => "sequence",
field => "#!string!striker_0009!#",
description => "#!string!striker_0010!#",
value => defined $anvil->data->{cgi}{sequence}{value} ? $anvil->data->{cgi}{sequence}{value} : "",
class => $sequence_class,
extra => "min=\"1\" max=\"24\"",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_domain => $say_domain }});
my $ifn_count_class = $anvil->data->{cgi}{ifn_count}{alert} ? "input_alert" : "input_clear";
my $say_ifn_count = $anvil->Template->get({file => "main.html", name => "input_number_form", variables => {
name => "ifn_count",
id => "ifn_count",
field => "#!string!striker_0011!#",
description => "#!string!striker_0012!#",
value => defined $anvil->data->{cgi}{ifn_count}{value} ? $anvil->data->{cgi}{ifn_count}{value} : "",
class => $ifn_count_class,
extra => "min=\"1\" max=\"24\"",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_ifn_count => $say_ifn_count }});
my $step1_body = $anvil->Template->get({file => "config.html", name => "config_step1", variables => {
step1_welcome_title_id => "",
step1_welcome_message_id => "",
organization_form => $say_organization,
prefix_form => $say_prefix,
domain_form => $say_domain,
sequence_form => $say_sequence,
ifn_count_form => $say_ifn_count,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { step1_body => $step1_body }});
return($step1_body);
}
# This reads the network status XML file and loads the data into $anvil->data->{network}{{...}.
sub get_network_details
{
my ($anvil) = @_;
### TODO: Daemonize this or solve selinux issues
### Refresh the network.xml
#$anvil->System->call({shell_call => $anvil->data->{path}{exe}{'anvil-update-states'}});
# Now read the network.xml
my $file = $anvil->data->{path}{directories}{html}."/status/network.xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $file }});
# Parse...
my $xml = XML::Simple->new();
my $data = "";
my $network = "";
eval { $data = $xml->XMLin($file, KeyAttr => { interface => 'name', key => 'name', ip => 'address' }, ForceArray => [ 'interface', 'key' ] ) };
if ($@)
{
chomp $@;
my $error = "[ Error ] - The was a problem reading: [$file]. The error was:\n";
$error .= "===========================================================\n";
$error .= $@."\n";
$error .= "===========================================================\n";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", raw => $error});
}
else
{
foreach my $interface (sort {$a cmp $b} keys %{$data->{interface}})
{
$anvil->data->{interfaces}{$interface} = {
bond => $data->{interface}{$interface}{bond},
bridge => $data->{interface}{$interface}{bridge},
duplex => $data->{interface}{$interface}{duplex},
'link' => $data->{interface}{$interface}{'link'},
mac => $data->{interface}{$interface}{mac},
media => $data->{interface}{$interface}{media},
mtu => $data->{interface}{$interface}{mtu},
order => $data->{interface}{$interface}{order},
speed => $data->{interface}{$interface}{speed},
'state' => $data->{interface}{$interface}{'state'},
};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"interfaces::${interface}::bond" => $anvil->data->{interfaces}{$interface}{bond},
"interfaces::${interface}::bridge" => $anvil->data->{interfaces}{$interface}{bridge},
"interfaces::${interface}::duplex" => $anvil->data->{interfaces}{$interface}{duplex},
"interfaces::${interface}::link" => $anvil->data->{interfaces}{$interface}{'link'},
"interfaces::${interface}::mac" => $anvil->data->{interfaces}{$interface}{mac},
"interfaces::${interface}::media" => $anvil->data->{interfaces}{$interface}{media},
"interfaces::${interface}::mtu" => $anvil->data->{interfaces}{$interface}{mtu},
"interfaces::${interface}::order" => $anvil->data->{interfaces}{$interface}{order},
"interfaces::${interface}::speed" => $anvil->data->{interfaces}{$interface}{speed},
"interfaces::${interface}::state" => $anvil->data->{interfaces}{$interface}{'state'},
}});
}
### TODO: Sort out how to read the XML using the proper KeyAttr to avoid this mess...
# If there is only one IP, the details will be stored directly under the 'ip' key. If two or
# more exist, each ip address will be the key after 'ip'.
if (exists $data->{ip}{address})
{
# Only one entry. Fix the hash.
my $address = $data->{ip}{address};
my $on = $data->{ip}{on};
my $subnet_mask = $data->{ip}{subnet_mask};
my $gateway = $data->{ip}{gateway};
my $default_gateway = $data->{ip}{default_gateway};
my $dns = $data->{ip}{dns};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
address => $address,
on => $on,
subnet_mask => $subnet_mask,
gateway => $gateway,
default_gateway => $default_gateway,
dns => $dns,
}});
$anvil->data->{ip}{$address} = {
on => $on,
subnet_mask => $subnet_mask,
gateway => $gateway,
default_gateway => $default_gateway,
dns => $dns,
};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"ip::${address}::on" => $anvil->data->{ip}{$address}{on},
"ip::${address}::subnet_mask" => $anvil->data->{ip}{$address}{subnet_mask},
"ip::${address}::gateway" => $anvil->data->{ip}{$address}{gateway},
"ip::${address}::default_gateway" => $anvil->data->{ip}{$address}{default_gateway},
"ip::${address}::dns" => $anvil->data->{ip}{$address}{dns},
}});
}
else
{
foreach my $address (sort {$a cmp $b} keys %{$data->{ip}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { address => $address }});
$anvil->data->{ip}{$address} = {
on => $data->{ip}{$address}{on},
subnet_mask => $data->{ip}{$address}{subnet_mask},
gateway => $data->{ip}{$address}{gateway},
default_gateway => $data->{ip}{$address}{default_gateway},
dns => $data->{ip}{$address}{dns},
};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"ip::${address}::on" => $anvil->data->{ip}{$address}{on},
"ip::${address}::subnet_mask" => $anvil->data->{ip}{$address}{subnet_mask},
"ip::${address}::gateway" => $anvil->data->{ip}{$address}{gateway},
"ip::${address}::default_gateway" => $anvil->data->{ip}{$address}{default_gateway},
"ip::${address}::dns" => $anvil->data->{ip}{$address}{dns},
}});
}
}
}
return(0);
}
sub get_network_details_form
{
my ($anvil) = @_;
my $file = $anvil->data->{path}{directories}{html}."/status/network.xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $file }});
my $xml = XML::Simple->new();
my $data = "";
my $network = "";
eval { $data = $xml->XMLin($file, KeyAttr => { interface => 'name', key => 'name' }, ForceArray => [ 'interface', 'key' ]) };
if ($@)
{
chomp $@;
my $error = "[ Error ] - The was a problem reading: [$file]. The error was:\n";
$error .= "===========================================================\n";
$error .= $@."\n";
$error .= "===========================================================\n";
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", raw => $error});
}
else
{
my $interface_list = "";
$network = $anvil->Template->get({file => "config.html", name => "network_header"});
foreach my $interface (sort {$a cmp $b} keys %{$data->{interface}})
{
$interface_list .= "$interface,";
$network .= $anvil->Template->get({file => "config.html", name => "network_entry", variables => {
mac => "",
mac_id => $interface."_mac",
name => $interface,
name_id => $interface."_name",
speed => "",
speed_id => $interface."_speed",
'link' => "",
link_id => $interface."_link",
order => "",
order_id => $interface."_order",
}});
}
$interface_list =~ s/,$//;
$network .= $anvil->Template->get({file => "config.html", name => "network_footer", variables => { interface_list => $interface_list }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network => $network }});
return($network);
}
=cut
Network planning;
10.x.y.z / 255.255.0.0
10.x.y.z / 255.255.0.0
x = Network;
- BCN = 200 + network
ie: BCN1 = 10.201.y.z
BCN2 = 10.202.y.z
- SN = 100 + network
ie: SN1 = 10.101.y.z
SN2 = 10.102.y.z
y = Device Type.
Foudation Pack;
1. Switches
2. PDUs
3. UPSes
4. Switches
5. Strikers
6. Striker IPMI (BCN only)
Anvil! systems;
1st - 10 = Node IP
11 = Node IPMI
2nd - 12 = Node IP
13 = Node IPMI
3rd - 14 = Node IP
15 = Node IPMI
N...
z = Device Sequence
- Foundation pack devices are simple sequence
- Anvils; .1 = node 1, .2 = node 2, .3 = DR host
=cut
# This is a rudimentary function for generating default Striker IPs.
sub generate_ip
{
my ($anvil, $network, $network_sequence, $device_sequence) = @_;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
network => $network,
network_sequence => $network_sequence,
device_sequence => $device_sequence,
}});
# An empty string is returned if we can't make a sane guess at what should be set.
my $ip = "";
# The subnet mask's second octet will be '+X' where 'X' is the sequence.
my $default_ip = $anvil->data->{defaults}{network}{$network}{network};
my $default_subnet_mask = $anvil->data->{defaults}{network}{$network}{subnet_mask};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
default_ip => $default_ip,
default_subnet_mask => $default_subnet_mask,
}});
if (($anvil->Validate->is_ipv4({ip => $default_ip})) && ($anvil->Validate->is_ipv4({ip => $default_subnet_mask})))
{
# Valid values.
my ($ip_octet1, $ip_octet2, $ip_octet3, $ip_octet4) = (split/\./, $default_ip);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
ip_octet1 => $ip_octet1,
ip_octet2 => $ip_octet2,
ip_octet3 => $ip_octet3,
ip_octet4 => $ip_octet4,
}});
if ($default_subnet_mask eq "255.255.0.0")
{
# We can work with this.
if ($network ne "ifn")
{
$ip_octet2 += $network_sequence;
}
$ip_octet3 = $anvil->data->{defaults}{network}{$network}{striker_octet3};
$ip_octet4 = $device_sequence;
$ip = $ip_octet1.".".$ip_octet2.".".$ip_octet3.".".$ip_octet4;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"s1:ip_octet2" => $ip_octet2,
"s2:ip_octet3" => $ip_octet3,
"s3:ip_octet4" => $ip_octet4,
"s4:ip" => $ip,
}});
}
}
else
{
# Something wrong with our defaults.
$ip = "#!error!#";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip => $ip }});
return($ip);
}