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

8752 lines
390 KiB

#!/usr/bin/perl
#
# Exit codes;
# 0 == OK
# 1 == Host UUID not available yet.
#
# TODO:
# * Switch out XML::Simple to XML::Twig or libXML - Started in Cluster->parse_cib();
# - 15:05 < perlbot> XML::Simple commits the fatal flaw of trying to massage complicated and often
# irregular XML into the simple and highly regular world of perl data structures.
# Irregularities cause "not a hashref" sort of errors in your program. Use a real
# parser. see: xml
# - 15:06 < perlbot> Don't parse XML with regex! Use a real parser. Avoid XML::Simple (see the xml::simple
# factoid). Choices are ::Easy, ::TreeBuilder, ::Twig, Mojo::DOM (in XML mode) for
# simple stuff. LibXML is a good general purpose starting point. See also XML::All.
# http://perl-xml.sf.net/faq/
#
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 }});
# Are we in 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!#" : "&nbsp;",
}});
# Display the page.
my $say_center_top_bar = "&nbsp;";
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 => "&nbsp;",
center_bottom_bar => "&nbsp;",
right_bottom_bar => "&nbsp;",
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_level = defined $anvil->data->{cgi}{recipient_level}{value} ? $anvil->data->{cgi}{recipient_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_level => $recipient_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_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_level = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_level => $recipient_level,
}});
if ($delete)
{
# Has the user confirmed?
if ($confirm)
{
# Delete.
$anvil->Database->insert_or_update_recipients({
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_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->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_level => $recipient_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_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
{
# Ignore
my $say_recipient_level = "#!string!unit_0023!#";
if ($recipient_level eq "1")
{
# Critical
$say_recipient_level = "#!string!unit_0024!#";
}
elsif ($recipient_level eq "2")
{
# Warning
$say_recipient_level = "#!string!unit_0025!#";
}
elsif ($recipient_level eq "3")
{
# Notice
$say_recipient_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_level => $recipient_level,
say_recipient_level => $say_recipient_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",
});
# Log Level (select)
my $recipient_level_select = $anvil->Template->select_form({
name => "recipient_level",
options => [
"1#!#".$anvil->Words->string({key => "unit_0024"}),
"2#!#".$anvil->Words->string({key => "unit_0025"}),
"3#!#".$anvil->Words->string({key => "unit_0026"}),
"4#!#".$anvil->Words->string({key => "unit_0027"}),
"0#!#".$anvil->Words->string({key => "unit_0023"}),
],
'sort' => 0,
blank => 0,
selected => $recipient_level,
class => $anvil->data->{cgi}{recipient_level}{alert} ? "input_alert" : "input_clear",
});
# Show the menu.
$anvil->data->{form}{back_link} = "?email=true";
$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,
new_level => $recipient_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 '587' unless $connection_security is 'ssl_tls'
$port = 143;
if ($connection_security eq "ssl_tls")
{
$port = 465;
}
$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->Get->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->ipv4({ip => $test_outgoing_mail_server})) and
(not $anvil->Validate->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->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} = "?email=true";
$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 OS.
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;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
state_uuid => $state_uuid,
show_list => $show_list,
}});
my $query = "SELECT state_host_uuid FROM states WHERE state_uuid = ".$anvil->Database->quote($state_uuid).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $host_uuid = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$host_uuid = "" if not defined $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
next if not $host_uuid;
if (not exists $job_data->{$host_uuid})
{
$job_data->{$host_uuid} = "";
}
$job_data->{$host_uuid} .= $state_uuid.",";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"job_data->{$host_uuid}" => $job_data->{$host_uuid},
}});
}
}
my $show_template = 0;
foreach my $host_uuid (keys %{$job_data})
{
$job_data->{$host_uuid} =~ s/,$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"job_data->{$host_uuid}" => $job_data->{$host_uuid},
}});
if ($job_data->{$host_uuid})
{
$show_template = 1;
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-manage-keys'}.$anvil->Log->switches,
job_data => $job_data->{$host_uuid},
job_name => "manage::broken_keys",
job_title => "job_0056",
job_description => "job_0057",
job_progress => 0,
job_host_uuid => $host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
show_template => $show_template,
job_uuid => $job_uuid,
}});
}
}
if ($show_template)
{
# 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 processes changes to files, including deletions (purges).
sub process_file_change
{
my ($anvil) = @_;
# First, clear the 'save' and 'confirm' buttons.
$anvil->data->{cgi}{save}{value} = "";
$anvil->data->{cgi}{confirm}{value} = "";
# Are we being asked to purge a file?
$anvil->Database->get_anvils();
$anvil->Database->get_files();
$anvil->Database->get_file_locations();
my $file_uuid = $anvil->data->{cgi}{file_uuid}{value};
my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name};
my $file_type = $anvil->data->{files}{file_uuid}{$file_uuid}{file_type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
file_uuid => $file_uuid,
file_name => $file_name,
file_type => $file_type,
}});
if ($anvil->data->{cgi}{purge}{value})
{
# Update the file to set the file type to 'DELETED'.
my $old_file_type = $anvil->data->{files}{file_uuid}{$file_uuid}{file_type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_file_type => $old_file_type }});
if ($old_file_type ne "DELETED")
{
my $query = "
UPDATE
files
SET
file_type = 'DELETED',
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
file_uuid = ".$anvil->Database->quote($file_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
}
# Register jobs on all systems to remove this file.
$anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => "all",
job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}.$anvil->Log->switches,
job_data => "file_uuid=".$file_uuid,
job_name => "storage::purge",
job_title => "job_0136",
job_description => "job_0137",
job_progress => 0,
});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => "#!string!ok_0012!#" }});
}
else
{
### Nope, we're doing other things. Possibly multiple things.
# Did the file name change?
my $ok_messages = "";
if (($anvil->data->{cgi}{new_file_name}{value}) && ($anvil->data->{cgi}{new_file_name}{value} ne $file_name))
{
# Rename the file.
my $old_file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name};
my $new_file_name = $anvil->data->{cgi}{new_file_name}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
old_file_name => $old_file_name,
new_file_name => $new_file_name,
}});
if ($old_file_name ne $new_file_name)
{
my $query = "
UPDATE
files
SET
file_name = ".$anvil->Database->quote($new_file_name).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
file_uuid = ".$anvil->Database->quote($file_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
}
$anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => "all",
job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}.$anvil->Log->switches,
job_data => "file_uuid=".$file_uuid."\nold_name=".$file_name."\nnew_name=".$anvil->data->{cgi}{new_file_name}{value},
job_name => "storage::rename",
job_title => "job_0138",
job_description => "job_0139",
job_progress => 0,
});
$ok_messages .= "#!string!ok_0013!# ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ok_messages => $ok_messages }});
}
# Did the file type change?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::new_file_type::value" => $anvil->data->{cgi}{new_file_type}{value},
file_type => $file_type,
}});
if (($anvil->data->{cgi}{new_file_type}{value}) && ($anvil->data->{cgi}{new_file_type}{value} ne $file_type))
{
# Easy peasy, update the DBey.
my $query = "
UPDATE
files
SET
file_type = ".$anvil->Database->quote($anvil->data->{cgi}{new_file_type}{value}).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
file_uuid = ".$anvil->Database->quote($file_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
# Register a job on all machines (that have this file) to set the mode.
$anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => "all",
job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}.$anvil->Log->switches,
job_data => "file_uuid=".$file_uuid,
job_name => "storage::check_mode",
job_title => "job_0143",
job_description => "job_0144",
job_progress => 0,
});
$ok_messages .= "#!string!ok_0014!# ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ok_messages => $ok_messages }});
}
# Loop through the Anvil! systems and see if any have changed from sync to remove or vice
# versa.
foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{cgi}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }});
if ($variable =~ /anvil_uuid::(.*?)::sync/)
{
my $anvil_uuid = $1;
my $anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
my $sync_value = $anvil->data->{cgi}{$variable}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_uuid => $anvil_uuid,
sync_value => $sync_value,
}});
# Coming from the CGI, sync will be 'true' or 'false', while the 'active'
# value from the database is '1' or '0'. We'll convert the database version
# for comparison versions.
my $file_location_uuid = $anvil->data->{file_locations}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
my $old_file_location_active = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active} ? "true" : "false";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
file_location_uuid => $file_location_uuid,
old_file_location_active => $old_file_location_active,
}});
if ($sync_value ne $old_file_location_active)
{
# Update the database and create a job for the member nodes to purge
# the file.
my $new_active = "FALSE";
my $ok_key = "ok_0016";
my $job_type = "storage::purge";
my $job_title = "job_0136";
my $job_description = "job_0137";
if ($sync_value eq "true")
{
$new_active = "TRUE";
$ok_key = "ok_0015";
$job_type = "storage::pull_file";
$job_title = "job_0132";
$job_description = "job_0133";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
new_active => $new_active,
ok_key => $ok_key,
job_type => $job_type,
job_title => $job_title,
job_description => $job_description,
}});
$ok_messages .= $anvil->Words->string({key => $ok_key, variables => { anvil_name => $anvil_name }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ok_messages => $ok_messages }});
my $query = "
UPDATE
file_locations
SET
file_location_active = ".$anvil->Database->quote($new_active).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
file_location_uuid = ".$anvil->Database->quote($file_location_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
# Now create a job for each Anvil! member.
my $member_uuids = [];
push @{$member_uuids}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
push @{$member_uuids}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
if ($anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid})
{
push @{$member_uuids}, $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid};
}
foreach my $host_uuid (@{$member_uuids})
{
my $job_uuid = $anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => $host_uuid,
job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}.$anvil->Log->switches,
job_data => "file_uuid=".$file_uuid,
job_name => $job_type,
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 }});
}
}
}
}
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $ok_messages }});
}
return(0);
}
# This handles files.
sub process_file_menu
{
my ($anvil) = @_;
$anvil->data->{cgi}{action}{value} = "" if not defined $anvil->data->{cgi}{action}{value};
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value};
$anvil->data->{cgi}{file_uuid}{value} = "" if not defined $anvil->data->{cgi}{file_uuid}{value};
$anvil->data->{cgi}{purge}{value} = "" if not defined $anvil->data->{cgi}{purge}{value};
$anvil->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value};
$anvil->data->{cgi}{task}{value} = "" if not defined $anvil->data->{cgi}{task}{value};
$anvil->data->{form}{refresh_link} = "?files=true";
$anvil->Database->get_files();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::file_uuid::value" => $anvil->data->{cgi}{file_uuid}{value},
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
"cgi::confirm::value" => $anvil->data->{cgi}{confirm}{value},
}});
if (($anvil->data->{cgi}{file_uuid}{value}) && ($anvil->data->{cgi}{save}{value}) && ($anvil->data->{cgi}{confirm}{value}))
{
process_file_change($anvil);
}
# Make sure that all files are registered with all Anvil! systems, This also (re)loads the data.
$anvil->Database->check_file_locations({debug => 2});
# Build the list of existing files.
my $file_list = $anvil->Template->get({file => "files.html", name => "open-file-list"});
foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{files}{file_name}})
{
my $file_uuid = $anvil->data->{files}{file_name}{$file_name}{file_uuid};
my $file_size = $anvil->data->{files}{file_name}{$file_name}{file_size};
my $say_file_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $file_size});
my $file_md5sum = $anvil->data->{files}{file_name}{$file_name}{file_md5sum};
my $file_type = $anvil->data->{files}{file_name}{$file_name}{file_type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
file_name => $file_name,
file_uuid => $file_uuid,
file_size => $file_size." (".$say_file_size.")",
file_md5sum => $file_md5sum,
file_type => $file_type,
}});
$file_list .= $anvil->Template->get({file => "files.html", name => "file-list-entry", variables => {
file_uuid => $file_uuid,
file_name => $file_name,
file_type => $file_type,
file_size => $say_file_size,
md5sum => $file_md5sum,
}});
if ($anvil->data->{cgi}{file_uuid}{value} eq $file_uuid)
{
$anvil->data->{form}{refresh_link} = "?files=true&file_uuid=".$anvil->data->{cgi}{file_uuid}{value};
$anvil->data->{form}{back_link} = "?files=true";
$anvil->data->{cgi}{new_file_name}{value} = $file_name if not defined $anvil->data->{cgi}{new_file_name}{value};
$anvil->data->{cgi}{new_file_name}{alert} = "" if not defined $anvil->data->{cgi}{new_file_name}{alert};
$anvil->data->{cgi}{new_file_type}{value} = $file_type if not defined $anvil->data->{cgi}{new_file_type}{value};
# Build the file type select
my $file_type_options = [
"iso#!#".$anvil->Words->string({key => "type_0001"}),
"script#!#".$anvil->Words->string({key => "type_0002"}),
"other#!#".$anvil->Words->string({key => "type_0003"})
];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::new_file_type::value" => $anvil->data->{cgi}{new_file_type}{value} }});
my $select_file_type = $anvil->Template->select_form({
name => "new_file_type",
options => $file_type_options,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{new_file_type}{value},
class => "input_clear",
style => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { select_file_type => $select_file_type }});
# Build the anvil list
$anvil->Database->get_anvils({debug => 3});
$anvil->Database->get_file_locations({debug => 3});
my $say_save_confirm = "&nbsp;";
my $say_purge_confirm = "&nbsp;";
my $anvil_list = "";
if (not exists $anvil->data->{anvils}{anvil_name})
{
$anvil_list .= $anvil->Template->get({file => "files.html", name => "file-list-manager-no-anvils"});
}
else
{
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
{
my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
my $anvil_description = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description};
my $file_location_uuid = $anvil->data->{file_locations}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
my $synced = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active};
my $radio_key = "anvil_uuid::".$anvil_uuid."::sync";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:anvil_name" => $anvil_name,
"s2:anvil_uuid" => $anvil_uuid,
"s3:anvil_description" => $anvil_description,
"s4:file_location_uuid" => $file_location_uuid,
"s5:synced" => $synced,
"s6:radio_key" => $radio_key,
}});
$anvil->data->{cgi}{$radio_key}{value} = "" if not defined $anvil->data->{cgi}{$radio_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${radio_key}::value" => $anvil->data->{cgi}{$radio_key}{value},
}});
my $true_checked = "checked";
my $false_checked = "";
if ($anvil->data->{cgi}{$radio_key}{value})
{
if ($anvil->data->{cgi}{$radio_key}{value} eq "false")
{
$true_checked = "";
$false_checked = "checked";
}
}
elsif (not $synced)
{
$true_checked = "";
$false_checked = "checked";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:true_checked" => $true_checked,
"s2:false_checked" => $false_checked,
}});
if (($anvil->data->{cgi}{purge}{value}) && (not $anvil->data->{cgi}{confirm}{value}))
{
$say_purge_confirm = $anvil->Template->get({file => "files.html", name => "file-list-manager-confirm-purge-button", variables => {
url => "?files=true&file_uuid=".$file_uuid."&purge=true&&save=true&confirm=true",
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_save_confirm => $say_save_confirm }});
if (($anvil->data->{cgi}{save}{value}) && (not $anvil->data->{cgi}{confirm}{value}))
{
$say_save_confirm = $anvil->Template->get({file => "files.html", name => "file-list-manager-confirm-save-button"});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_save_confirm => $say_save_confirm }});
$anvil_list .= $anvil->Template->get({file => "files.html", name => "file-list-manager-anvil-entry", variables => {
anvil_name => $anvil_name,
anvil_description => $anvil_description,
radio_name => $radio_key,
true_checked => $true_checked,
false_checked => $false_checked,
}});
}
}
# Insert the file management section under the file entry.
$file_list .= $anvil->Template->get({file => "files.html", name => "file-list-manager", variables => {
file_uuid => $file_uuid,
new_file_name => $anvil->data->{cgi}{new_file_name}{value},
new_file_type => $select_file_type,
confirm_save_button => $say_save_confirm,
confirm_purge_button => $say_purge_confirm,
new_file_name_class => $anvil->data->{cgi}{new_file_name}{alert} ? "input_alert_fixed" : "input_clear_fixed",
anvil_list => $anvil_list,
}});
}
}
$file_list .= $anvil->Template->get({file => "files.html", name => "close-file-list"});
# The 'back' goes home
$anvil->data->{form}{back_link} = "?";
$anvil->data->{form}{body} = $anvil->Template->get({file => "files.html", name => "main-menu", variables => {
file_list => $file_list,
}});
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
}
elsif ($anvil->data->{cgi}{task}{value} eq "create")
{
# This handles the main "create an anvil" page.
process_create($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "fences")
{
process_fences($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "upses")
{
process_upses($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "manifests")
{
process_manifests($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);
}
# This handles all aspects of Install Manifests.
sub process_manifests
{
my ($anvil) = @_;
# Are we creating a new manifest?
$anvil->data->{cgi}{manifest_uuid}{value} = "" if not defined $anvil->data->{cgi}{manifest_uuid}{value};
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{alert};
$anvil->data->{cgi}{run}{value} = "" if not defined $anvil->data->{cgi}{run}{value};
$anvil->data->{cgi}{step}{value} = 1 if not defined $anvil->data->{cgi}{step}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'cgi::manifest_uuid::value' => $anvil->data->{cgi}{manifest_uuid}{value},
}});
# Are we running a manifest, or creating/editing one?
if (($anvil->data->{cgi}{run}{value}) && ($anvil->Validate->uuid({uuid => $anvil->data->{cgi}{manifest_uuid}{value}})))
{
run_manifest($anvil);
}
else
{
handle_manifest($anvil);
}
return(0);
}
# This is an extension to 'handle_manifests' that specifically handles running an install manifest.
sub run_manifest
{
my ($anvil) = @_;
$anvil->data->{cgi}{description}{value} = "" if not defined $anvil->data->{cgi}{description}{value};
$anvil->data->{cgi}{description}{alert} = 0 if not defined $anvil->data->{cgi}{description}{alert};
$anvil->data->{cgi}{password}{value} = "" if not defined $anvil->data->{cgi}{password}{value};
$anvil->data->{cgi}{password}{alert} = 0 if not defined $anvil->data->{cgi}{password}{alert};
$anvil->Database->get_hosts({debug => 2});
my $manifest_uuid = $anvil->data->{cgi}{manifest_uuid}{value};
my $problem = $anvil->Striker->load_manifest({
debug => 2,
manifest_uuid => $manifest_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
manifest_uuid => $manifest_uuid,
problem => $problem,
}});
if ($problem)
{
# Report a problem and send the user back to the manifests page.
my $message = $anvil->Words->string({key => "warning_0046", variables => { uuid => $manifest_uuid }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
my $anvil_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name};
my $prefix = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{prefix};
my $sequence = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{sequence};
my $domain = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{domain};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_name => $anvil_name,
prefix => $prefix,
sequence => $sequence,
domain => $domain,
}});
my $node1_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{name};
my $node2_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node2}{name};
my $dr1_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{dr1}{name};
if ($domain)
{
$node1_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{name}.".".$domain;
$node2_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node2}{name}.".".$domain;
$dr1_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{dr1}{name}.".".$domain;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
node1_name => $node1_name,
node2_name => $node2_name,
dr1_name => $dr1_name,
}});
my $bcn_count = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{bcn};
my $sn_count = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{sn};
my $ifn_count = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{ifn};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bcn_count => $bcn_count,
sn_count => $sn_count,
ifn_count => $ifn_count,
}});
# If confirmed, run!
$anvil->data->{cgi}{confirm}{value} = "" if not defined $anvil->data->{cgi}{confirm}{value};
if ($anvil->data->{cgi}{confirm}{value})
{
# Make sure the passwords match.
my $problem = 0;
if (not $anvil->data->{cgi}{password1}{value})
{
# Didn't set a password
$problem = 1;
$anvil->data->{cgi}{password1}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => "#!string!warning_0047!#" }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::password1::alert" => $anvil->data->{cgi}{password1}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
elsif (not $anvil->data->{cgi}{password2}{value})
{
# Missing both passwords
$problem = 1;
$anvil->data->{cgi}{password2}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => "#!string!warning_0048!#" }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::password2::alert" => $anvil->data->{cgi}{password2}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
elsif ($anvil->data->{cgi}{password1}{value} ne $anvil->data->{cgi}{password2}{value})
{
$problem = 1;
$anvil->data->{cgi}{password1}{alert} = 1;
$anvil->data->{cgi}{password2}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => "#!string!warning_0049!#" }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::password1::alert" => $anvil->data->{cgi}{password1}{alert},
"cgi::password2::alert" => $anvil->data->{cgi}{password2}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
# Check that the machines selected didn't get added to another anvil while looking.
my $node1_host_uuid = $anvil->data->{cgi}{node1_host}{value};
my $node1_host_name = $anvil->data->{sys}{hosts}{by_uuid}{$node1_host_uuid};
my $node1_anvil = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{anvil_name};
my $node2_host_uuid = $anvil->data->{cgi}{node2_host}{value};
my $node2_host_name = $anvil->data->{sys}{hosts}{by_uuid}{$node2_host_uuid};
my $node2_anvil = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{anvil_name};
my $dr1_host_uuid = $anvil->data->{cgi}{dr1_host}{value};
my $dr1_host_name = $dr1_host_uuid ? $anvil->data->{sys}{hosts}{by_uuid}{$dr1_host_uuid} : "";
my $dr1_anvil = $dr1_host_uuid ? $anvil->data->{hosts}{host_uuid}{$dr1_host_uuid}{anvil_name} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
node1_host_name => $node1_host_name,
node1_host_uuid => $node1_host_uuid,
node1_anvil => $node1_anvil,
node2_host_name => $node2_host_name,
node2_host_uuid => $node2_host_uuid,
node2_anvil => $node2_anvil,
dr1_host_name => $dr1_host_name,
dr1_host_uuid => $dr1_host_uuid,
dr1_anvil => $dr1_anvil,
}});
# Make sure the three options are unique.
if ($node1_host_uuid eq $node2_host_uuid)
{
my $message = $anvil->Words->string({key => "warning_0054"});
$problem = 1;
$anvil->data->{cgi}{node1_host}{alert} = 1;
$anvil->data->{cgi}{node2_host}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::node1_host::alert" => $anvil->data->{cgi}{node1_host}{alert},
"cgi::node2_host::alert" => $anvil->data->{cgi}{node2_host}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
if ($dr1_host_uuid)
{
if ($dr1_host_uuid eq $node1_host_uuid)
{
my $message = $anvil->Words->string({key => "warning_0055"});
$problem = 1;
$anvil->data->{cgi}{dr1_host}{alert} = 1;
$anvil->data->{cgi}{node1_host}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::dr1_host::alert" => $anvil->data->{cgi}{dr1_host}{alert},
"cgi::node1_host::alert" => $anvil->data->{cgi}{node1_host}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
elsif ($dr1_host_uuid eq $node2_host_uuid)
{
my $message = $anvil->Words->string({key => "warning_0056"});
$problem = 1;
$anvil->data->{cgi}{dr1_host}{alert} = 1;
$anvil->data->{cgi}{node2_host}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::dr1_host::alert" => $anvil->data->{cgi}{dr1_host}{alert},
"cgi::node2_host::alert" => $anvil->data->{cgi}{node2_host}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
}
if (($node1_anvil) && ($node1_anvil ne $anvil_name))
{
# The server belongs to another Anvil! system.
my $message = $anvil->Words->string({key => "warning_0050", variables => {
machine => $node1_host_name,
anvil => $anvil_name,
}});
$problem = 1;
$anvil->data->{cgi}{node1_host}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::node1_host::alert" => $anvil->data->{cgi}{node1_host}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
if (($node2_anvil) && ($node2_anvil ne $anvil_name))
{
# The server belongs to another Anvil! system.
my $message = $anvil->Words->string({key => "warning_0050", variables => {
machine => $node2_host_name,
anvil => $anvil_name,
}});
$problem = 1;
$anvil->data->{cgi}{node2_host}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::node2_host::alert" => $anvil->data->{cgi}{node2_host}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
if ($anvil->data->{cgi}{dr1_host}{value})
{
if (($dr1_anvil) && ($dr1_anvil ne $anvil_name))
{
# The server belongs to another Anvil! system.
my $message = $anvil->Words->string({key => "warning_0050", variables => {
machine => $dr1_host_name,
anvil => $anvil_name,
}});
$problem = 1;
$anvil->data->{cgi}{dr1_host}{alert} = 1;
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
problem => $problem,
"cgi::dr1_host::alert" => $anvil->data->{cgi}{dr1_host}{alert},
"form::error_massage" => $anvil->data->{form}{error_massage},
}});
}
}
if (not $problem)
{
# Record and entry in the 'anvils' table.
my ($anvil_uuid) = $anvil->Database->insert_or_update_anvils({
debug => 2,
anvil_description => $anvil->data->{cgi}{description}{value},
anvil_name => $anvil_name,
anvil_password => $anvil->data->{cgi}{password1}{value},
anvil_node1_host_uuid => $node1_host_uuid,
anvil_node2_host_uuid => $node2_host_uuid,
anvil_dr1_host_uuid => $dr1_host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
# Save the jobs!
my ($node1_job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => $node1_host_uuid,
job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'}.$anvil->Log->switches,
job_data => "as_machine=node1,manifest_uuid=".$manifest_uuid.",anvil_uuid=".$anvil_uuid,
job_name => "join_anvil::node1",
job_title => "job_0072",
job_description => "job_0073",
job_progress => 0,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node1_job_uuid => $node1_job_uuid }});
my ($node2_job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => $node2_host_uuid,
job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'}.$anvil->Log->switches,
job_data => "as_machine=node2,manifest_uuid=".$manifest_uuid.",anvil_uuid=".$anvil_uuid,
job_name => "join_anvil::node2",
job_title => "job_0072",
job_description => "job_0073",
job_progress => 0,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { node2_job_uuid => $node2_job_uuid }});
if ($anvil->data->{cgi}{dr1_host}{value})
{
my ($dr1_job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => $dr1_host_uuid,
job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'}.$anvil->Log->switches,
job_data => "as_machine=dr1,manifest_uuid=".$manifest_uuid.",anvil_uuid=".$anvil_uuid,
job_name => "join_anvil::dr1",
job_title => "job_0072",
job_description => "job_0073",
job_progress => 0,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr1_job_uuid => $dr1_job_uuid }});
}
# Tell them we're done and send them back to the main page.
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => "#!string!ok_0011!#" }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::ok_message" => $anvil->data->{form}{ok_message} }});
process_create($anvil);
return(0);
}
}
# Ask the user to choose the targets and confirm the manifest settings.
my $nodes = [];
my $dr_hosts = [];
foreach my $host_uuid (keys %{$anvil->data->{hosts}{host_uuid}})
{
my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
my $host_anvil = "";
if ((exists $anvil->data->{hosts}{host_uuid}{$host_uuid}) && ($anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name} ne $anvil_name))
{
$host_anvil = $anvil_name;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
host_name => $host_name,
host_type => $host_type,
host_anvil => $host_anvil,
}});
# Does this host belong to another Anvil! already?
if (($host_anvil) && ($host_anvil ne $anvil_name))
{
# yup, ignore it.
next;
}
if ($host_type eq "node")
{
push @{$nodes}, $host_uuid."#!#".$host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
if ((not defined $anvil->data->{cgi}{node1_host}{value}) && ($host_name eq $node1_name))
{
$anvil->data->{cgi}{node1_host}{value} = $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node1_host::value" => $anvil->data->{cgi}{node1_host}{value} }});
}
elsif ((not defined $anvil->data->{cgi}{node2_host}{value}) && ($host_name eq $node2_name))
{
$anvil->data->{cgi}{node2_host}{value} = $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node2_host::value" => $anvil->data->{cgi}{node2_host}{value} }});
}
}
elsif ($host_type eq "dr")
{
push @{$dr_hosts}, $host_uuid."#!#".$host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
if ((not defined $anvil->data->{cgi}{dr1_host}{value}) && ($host_name eq $dr1_name))
{
$anvil->data->{cgi}{dr1_host}{value} = $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::dr1_host::value" => $anvil->data->{cgi}{dr1_host}{value} }});
}
}
}
# We're going to need three selects; one for each node and one for DR. The DR is allowed to
# be unselected so it has an empty entry.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node1_host::value" => $anvil->data->{cgi}{node1_host}{value} }});
my $select_node1 = $anvil->Template->select_form({
debug => 2,
name => "node1_host",
options => $nodes,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{node1_host}{value},
class => $anvil->data->{cgi}{node1_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { select_node1 => $select_node1 }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node2_host::value" => $anvil->data->{cgi}{node2_host}{value} }});
my $select_node2 = $anvil->Template->select_form({
debug => 2,
name => "node2_host",
options => $nodes,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{node2_host}{value},
class => $anvil->data->{cgi}{node2_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { select_node2 => $select_node2 }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::dr1_host::value" => $anvil->data->{cgi}{dr1_host}{value} }});
my $select_dr1 = $anvil->Template->select_form({
debug => 2,
name => "dr1_host",
options => $dr_hosts,
blank => 1,
'sort' => 1,
selected => $anvil->data->{cgi}{dr1_host}{value},
class => $anvil->data->{cgi}{dr1_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { select_dr1 => $select_dr1 }});
# Show the networks.
my $networks = "";
my $default_seen = 0;
foreach my $network ("bcn", "sn", "ifn")
{
my $count = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{$network};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
network => $network,
count => $count,
}});
foreach my $i (1..$count)
{
my $network_name = $network.$i;
my $network_range = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{network};
my $subnet = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{subnet};
my $gateway = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{gateway};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
network_name => $network_name,
network_range => $network_range,
subnet => $subnet,
gateway => $gateway,
}});
my $say_default = "";
if (($network eq "ifn") && (not $default_seen) && ($gateway))
{
$default_seen = 1;
$say_default = "(#!string!striker_0249!#)";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
default_seen => $default_seen,
say_default => $say_default,
}});
}
my $network_key = "header_0036";
if ($network eq "sn") { $network_key = "header_0037"; }
elsif ($network eq "ifn") { $network_key = "header_0038"; }
$networks .= $anvil->Template->get({file => "anvil.html", name => "run-manifest-network", variables => {
name => $anvil->Words->string({key => $network_key, variables => { number => $i }}),
network => $network_range,
subnet => $subnet,
gateway => $gateway ? $gateway : "--",
'default' => $say_default,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { networks => $networks }});
}
}
# Pull out the IPs that will be assigned to servers.
my $machine_ips = "";
foreach my $network ("bcn", "sn", "ifn")
{
if ($network eq "sn")
{
# Inject the IPMI data.
my $node1_ipmi_ip = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{ipmi_ip};
my $node2_ipmi_ip = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node2}{ipmi_ip};
my $dr1_ipmi_ip = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{dr1}{ipmi_ip};
$machine_ips .= $anvil->Template->get({file => "anvil.html", name => "run-manifest-ip", variables => {
name => "#!string!striker_0258!#",
node1 => $node1_ipmi_ip ? $node1_ipmi_ip : "--",
node2 => $node2_ipmi_ip ? $node2_ipmi_ip : "--",
dr1 => $dr1_ipmi_ip ? $dr1_ipmi_ip : "--",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { networks => $networks }});
}
my $count = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{$network};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
network => $network,
count => $count,
}});
foreach my $i (1..$count)
{
my $network_name = $network.$i;
my $node1_ip = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{network}{$network_name}{ip};
my $node2_ip = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node2}{network}{$network_name}{ip};
my $dr1_ip = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{dr1}{network}{$network_name}{ip};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
network_name => $network_name,
node1_ip => $node1_ip,
node2_ip => $node2_ip,
dr1_ip => $dr1_ip,
}});
my $network_key = "header_0036";
if ($network eq "sn") { $network_key = "header_0037"; }
elsif ($network eq "ifn") { $network_key = "header_0038"; }
$machine_ips .= $anvil->Template->get({file => "anvil.html", name => "run-manifest-ip", variables => {
name => $anvil->Words->string({key => $network_key, variables => { number => $i }}),
node1 => $node1_ip ? $node1_ip : "--",
node2 => $node2_ip ? $node2_ip : "--",
dr1 => $dr1_ip ? $dr1_ip : "--",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { networks => $networks }});
}
}
my $dns = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{dns};
my $ntp = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{ntp};
my $mtu = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{mtu};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
dns => $dns,
ntp => $ntp,
mtu => $mtu,
}});
my $fences = "";
foreach my $fence_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{fence}})
{
my $node1_port = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{fence}{$fence_name}{port};
my $node2_port = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node2}{fence}{$fence_name}{port};
my $dr1_port = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{dr1}{fence}{$fence_name}{port};
$fences .= $anvil->Template->get({file => "anvil.html", name => "run-manifest-fence", variables => {
name => $fence_name,
node1 => $node1_port ? $node1_port : "--",
node2 => $node2_port ? $node2_port : "--",
dr1 => $dr1_port ? $dr1_port : "--",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { networks => $networks }});
}
my $upses = "";
foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{ups}})
{
my $node1_uses = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node1}{ups}{$ups_name}{used};
my $node2_uses = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{node2}{ups}{$ups_name}{used};
my $dr1_uses = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{dr1}{ups}{$ups_name}{used};
$upses .= $anvil->Template->get({file => "anvil.html", name => "run-manifest-ups", variables => {
name => $ups_name,
node1 => $node1_uses ? '<span class="available">#!string!unit_0001!#</span>' : '<span class="unavailable">#!string!unit_0002!#</span>',
node2 => $node2_uses ? '<span class="available">#!string!unit_0001!#</span>' : '<span class="unavailable">#!string!unit_0002!#</span>',
dr1 => $dr1_uses ? '<span class="available">#!string!unit_0001!#</span>' : '<span class="unavailable">#!string!unit_0002!#</span>',
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { networks => $networks }});
}
$anvil->data->{form}{back_link} = "?anvil=true&task=create";
$anvil->data->{form}{refresh_link} = "?anvil=true&task=manifests&run=true&manifest_uuid=".$anvil->data->{cgi}{manifest_uuid}{value};
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "run-manifest", variables => {
debug => 2,
title => $anvil->Words->string({key => "striker_0270", variables => { name => $anvil_name }}),
description => $anvil->data->{cgi}{description}{value},
description_class => $anvil->data->{cgi}{description}{alert} ? "input_alert" : "",
password => $anvil->data->{cgi}{password}{value},
password_class => $anvil->data->{cgi}{password}{alert} ? "input_alert" : "",
fences => $fences,
upses => $upses,
networks => $networks,
dns => $dns ? $dns : "8.8.8.8,8.8.4.4",
ntp => $ntp ? $ntp : "--",
mtu => $mtu ? $mtu : "1500",
select_node1 => $select_node1,
select_node2 => $select_node2,
select_dr1 => $select_dr1,
hostname_node1 => $node1_name,
hostname_node2 => $node2_name,
hostname_dr1 => $dr1_name,
machine_ips => $machine_ips,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
# This handles creating or editing an Install Manifest.
sub handle_manifest
{
my ($anvil) = @_;
$anvil->data->{cgi}{step}{value} = 1 if not defined $anvil->data->{cgi}{step}{value};
$anvil->data->{cgi}{prefix}{value} = "" if not defined $anvil->data->{cgi}{prefix}{value};
$anvil->data->{cgi}{prefix}{alert} = 0 if not defined $anvil->data->{cgi}{prefix}{alert};
$anvil->data->{cgi}{domain}{value} = "" if not defined $anvil->data->{cgi}{domain}{value};
$anvil->data->{cgi}{domain}{alert} = 0 if not defined $anvil->data->{cgi}{domain}{alert};
$anvil->data->{cgi}{sequence}{value} = "" if not defined $anvil->data->{cgi}{sequence}{value};
$anvil->data->{cgi}{sequence}{alert} = 0 if not defined $anvil->data->{cgi}{sequence}{alert};
$anvil->data->{cgi}{bcn_count}{value} = 0 if not defined $anvil->data->{cgi}{bcn_count}{value};
$anvil->data->{cgi}{bcn_count}{alert} = 0 if not defined $anvil->data->{cgi}{bcn_count}{alert};
$anvil->data->{cgi}{sn_count}{value} = 0 if not defined $anvil->data->{cgi}{sn_count}{value};
$anvil->data->{cgi}{sn_count}{alert} = 0 if not defined $anvil->data->{cgi}{sn_count}{alert};
$anvil->data->{cgi}{ifn_count}{value} = 0 if not defined $anvil->data->{cgi}{ifn_count}{value};
$anvil->data->{cgi}{ifn_count}{alert} = 0 if not defined $anvil->data->{cgi}{ifn_count}{alert};
$anvil->data->{cgi}{dns}{value} = "8.8.8.8,8.8.4.4" if not defined $anvil->data->{cgi}{dns}{value};
$anvil->data->{cgi}{dns}{alert} = 0 if not defined $anvil->data->{cgi}{dns}{alert};
$anvil->data->{cgi}{ntp}{value} = "" if not defined $anvil->data->{cgi}{ntp}{value};
$anvil->data->{cgi}{ntp}{alert} = 0 if not defined $anvil->data->{cgi}{ntp}{alert};
$anvil->data->{cgi}{mtu}{value} = 1500 if not defined $anvil->data->{cgi}{mtu}{value};
$anvil->data->{cgi}{mtu}{alert} = 0 if not defined $anvil->data->{cgi}{mtu}{alert};
$anvil->data->{cgi}{'delete'}{value} = "" if not defined $anvil->data->{cgi}{'delete'}{alert};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::step::value" => $anvil->data->{cgi}{step}{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::bcn_count::value" => $anvil->data->{cgi}{bcn_count}{value},
"cgi::sn_count::value" => $anvil->data->{cgi}{sn_count}{value},
"cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value},
"cgi::dns::value" => $anvil->data->{cgi}{dns}{value},
"cgi::ntp::value" => $anvil->data->{cgi}{ntp}{value},
"cgi::mtu::value" => $anvil->data->{cgi}{mtu}{value},
"cgi::delete::value" => $anvil->data->{cgi}{'delete'}{value},
}});
# Are we deleting a manifest?
if (($anvil->data->{cgi}{'delete'}{value}) && ($anvil->data->{cgi}{manifest_uuid}{value}))
{
# Verify that the UUID is valid.
$anvil->Database->get_manifests({debug => 2, include_deleted => 1});
my $manifest_uuid = $anvil->data->{cgi}{manifest_uuid}{value};
my $manifest_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{manifest_name};
my $manifest_last_ran = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{manifest_last_ran};
my $manifest_xml = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{manifest_xml};
my $manifest_note = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{manifest_note};
if (not exists $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid})
{
# Doesn't exist.
my $message = $anvil->Words->string({key => "warning_0043", variables => { uuid => $manifest_uuid }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
elsif ($anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{manifest_note} eq "DELETED")
{
# Already deleted.
my $message = $anvil->Words->string({key => "warning_0044", variables => {
name => $manifest_name,
uuid => $manifest_uuid,
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
# Has the user confirmed?
if ($anvil->data->{cgi}{confirm}{value})
{
# Delete it
my ($manifest_uuid) = $anvil->Database->insert_or_update_manifests({
debug => 2,
manifest_uuid => $manifest_uuid,
manifest_name => $manifest_name,
manifest_last_ran => $manifest_last_ran,
manifest_xml => $manifest_xml,
manifest_note => "DELETED",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { manifest_uuid => $manifest_uuid }});
if ($manifest_uuid)
{
# Deleted successfully
my $message = $anvil->Words->string({key => "ok_0010", variables => { name => $manifest_name }});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::ok_message" => $anvil->data->{form}{ok_message} }});
}
else
{
# Something went wrong.
my $message = $anvil->Words->string({key => "warning_0045", variables => {
name => $manifest_name,
uuid => $manifest_uuid,
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
# Go back to the main page.
process_create($anvil);
return(0);
}
else
{
# Ask the user to confirm.
my $say_manifest = $manifest_name;
if ($manifest_note)
{
$say_manifest = $manifest_name." : ".$manifest_note;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_manifest => $say_manifest }});
$anvil->data->{form}{back_link} = "?anvil=true&task=create";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "manifest-delete-confirm", variables => {
name => $manifest_name,
say_manifest => $say_manifest,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
}
if ($anvil->data->{cgi}{step}{value} > 1)
{
my ($sane) = sanity_check_manifest_step1($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
if (not $sane)
{
# Go back to the first page
$anvil->data->{cgi}{step}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::step::value" => $anvil->data->{cgi}{step}{value} }});
}
elsif ($anvil->data->{cgi}{step}{value} > 2)
{
my ($sane) = sanity_check_manifest_step2($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
if (not $sane)
{
# Go back to the second page
$anvil->data->{cgi}{step}{value} = 2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::step::value" => $anvil->data->{cgi}{step}{value} }});
}
elsif ($anvil->data->{cgi}{step}{value} > 3)
{
my ($sane) = sanity_check_manifest_step3($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
if (not $sane)
{
# Go back to the third page
$anvil->data->{cgi}{step}{value} = 3;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::step::value" => $anvil->data->{cgi}{step}{value} }});
}
else
{
# Save the manifest!
my ($manifest_uuid, $manifest_name) = $anvil->Striker->generate_manifest({debug => 2});
if ($manifest_uuid)
{
# Success!
my $message = $anvil->Words->string({key => "ok_0009", variables => { name => $manifest_name }});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::ok_message" => $anvil->data->{form}{ok_message} }});
# Go back to the main page.
process_create($anvil);
return(0);
}
else
{
# Something went wrong, go back to the third page
$anvil->data->{cgi}{step}{value} = 3;
my $message = $anvil->Words->string({key => "warning_0041"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
}
}
}
}
# If we have an actual manifest_uuid, load it and preset values.
if ((exists $anvil->data->{cgi}{manifest_uuid}) && ($anvil->data->{cgi}{manifest_uuid}{value} ne "new"))
{
my $manifest_uuid = $anvil->data->{cgi}{manifest_uuid}{value};
my $failed = $anvil->Striker->load_manifest({
debug => 2,
manifest_uuid => $manifest_uuid,
});
if (not $failed)
{
# Walk through the parsed manifest and set any undefined CGI.
if ($anvil->data->{cgi}{step}{value} eq "1")
{
if ($anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name} =~ /^(.*?)-anvil-(\d+)$/)
{
my $prefix = $1;
my $sequence = $2;
$sequence =~ s/^0+//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
prefix => $prefix,
sequence => $sequence,
}});
if (not $anvil->data->{cgi}{prefix}{value})
{
$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 (not $anvil->data->{cgi}{sequence}{value})
{
$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 (not $anvil->data->{cgi}{domain}{value})
{
$anvil->data->{cgi}{domain}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{domain};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::domain::value" => $anvil->data->{cgi}{domain}{value} }});
}
if (not $anvil->data->{cgi}{ifn_count}{value})
{
$anvil->data->{cgi}{ifn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{ifn};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value} }});
}
if (not $anvil->data->{cgi}{sn_count}{value})
{
$anvil->data->{cgi}{sn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{sn};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::sn_count::value" => $anvil->data->{cgi}{sn_count}{value} }});
}
if (not $anvil->data->{cgi}{bcn_count}{value})
{
$anvil->data->{cgi}{bcn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{bcn};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::bcn_count::value" => $anvil->data->{cgi}{bcn_count}{value} }});
}
}
elsif ($anvil->data->{cgi}{step}{value} eq "2")
{
if (not $anvil->data->{cgi}{dns}{value})
{
$anvil->data->{cgi}{dns}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{dns};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::dns::value" => $anvil->data->{cgi}{dns}{value} }});
}
if (not $anvil->data->{cgi}{ntp}{value})
{
$anvil->data->{cgi}{ntp}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{ntp};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::ntp::value" => $anvil->data->{cgi}{ntp}{value} }});
}
if (not $anvil->data->{cgi}{mtu}{value})
{
$anvil->data->{cgi}{mtu}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{mtu};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::mtu::value" => $anvil->data->{cgi}{mtu}{value} }});
}
foreach my $network ("bcn", "sn", "ifn")
{
my $count_key = $network."_count";
foreach my $i (1..$anvil->data->{cgi}{$count_key}{value})
{
my $network_name = $network.$i;
my $network_key = $network_name."_network";
my $subnet_key = $network_name."_subnet";
my $gateway_key = $network_name."_gateway";
if (not defined $anvil->data->{cgi}{$network_key}{value})
{
$anvil->data->{cgi}{$network_key}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{network};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value} }});
}
if (not defined $anvil->data->{cgi}{$subnet_key}{value})
{
$anvil->data->{cgi}{$subnet_key}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{subnet};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value} }});
}
if (not defined $anvil->data->{cgi}{$gateway_key}{value})
{
$anvil->data->{cgi}{$gateway_key}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{name}{$network_name}{gateway};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value} }});
}
}
}
}
elsif ($anvil->data->{cgi}{step}{value} eq "3")
{
foreach my $machine ("node1", "node2", "dr1")
{
my $ipmi_ip_key = $machine."_ipmi_ip";
if (not defined $anvil->data->{cgi}{$ipmi_ip_key}{value})
{
$anvil->data->{cgi}{$ipmi_ip_key}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ipmi_ip};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${ipmi_ip_key}::value" => $anvil->data->{cgi}{$ipmi_ip_key}{value} }});
}
foreach my $network ("bcn", "sn", "ifn")
{
my $count_key = $network."_count";
foreach my $i (1..$anvil->data->{cgi}{$count_key}{value})
{
my $network_name = $network.$i;
my $ip_key = $machine."_".$network_name."_ip";
if (not defined $anvil->data->{cgi}{$ip_key}{value})
{
$anvil->data->{cgi}{$ip_key}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{network}{$network_name}{ip};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${ip_key}::value" => $anvil->data->{cgi}{$ip_key}{value} }});
}
}
}
# UPSes
foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ups}})
{
my $checked = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ups}{$ups_name}{used} ? "checked" : "";
my $ups_key = $machine."_ups_".$ups_name;
if (not defined $anvil->data->{cgi}{$ups_key}{value})
{
$anvil->data->{cgi}{$ups_key}{value} = $checked;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${ups_key}::value" => $anvil->data->{cgi}{$ups_key}{value} }});
}
}
# Fences
foreach my $fence_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{fence}})
{
my $fence_key = $machine."_fence_".$fence_name;
if (not defined $anvil->data->{cgi}{$fence_key}{value})
{
$anvil->data->{cgi}{$fence_key}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{fence}{$fence_name}{port};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${fence_key}::value" => $anvil->data->{cgi}{$fence_key}{value} }});
}
}
}
}
}
}
# Step 1 is to ask for the sequence number, prefix, and the number of IFNs (and later, BCNs)
if ($anvil->data->{cgi}{step}{value} eq "1")
{
if ($anvil->data->{cgi}{manifest_uuid}{value} eq "new")
{
# Pre-load values
if (not $anvil->data->{cgi}{prefix}{value})
{
$anvil->data->{cgi}{prefix}{value} = $anvil->Get->short_host_name() =~ /-/ ? $anvil->Get->short_host_name() : "xx";
$anvil->data->{cgi}{prefix}{value} =~ s/-.*$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::prefix::value" => $anvil->data->{cgi}{prefix}{value} }});
}
if (not $anvil->data->{cgi}{domain}{value})
{
$anvil->data->{cgi}{domain}{value} = $anvil->Get->host_name() =~ /\./ ? $anvil->Get->host_name() : "example.com";
$anvil->data->{cgi}{domain}{value} =~ s/^.*?\.//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::domain::value" => $anvil->data->{cgi}{domain}{value} }});
}
if (not $anvil->data->{cgi}{sequence}{value})
{
# Default to 1
$anvil->data->{cgi}{sequence}{value} = 1;
# Count the number of existing manifests! systems with the default prefix to guess the next sequence.
my $query = "SELECT manifest_name FROM manifests WHERE manifest_name LIKE ".$anvil->Database->quote($anvil->data->{cgi}{prefix}{value}."-%")." ORDER BY manifest_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,
}});
if ($count)
{
# Yup, key has changed.
foreach my $row (@{$results})
{
my $manifest_name = $row->[0];
my $this_sequence = ($manifest_name =~ /-(\d+)$/)[0];
$this_sequence =~ s/^0//g;
$this_sequence = 0 if not $this_sequence;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
manifest_name => $manifest_name,
this_sequence => $this_sequence,
}});
if ($this_sequence >= $anvil->data->{cgi}{sequence}{value})
{
$anvil->data->{cgi}{sequence}{value} = $this_sequence + 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::sequence::value" => $anvil->data->{cgi}{sequence}{value} }});
}
}
}
}
if (not $anvil->data->{cgi}{ifn_count}{value})
{
$anvil->data->{cgi}{ifn_count}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value} }});
}
# NOTE: The user can't choose the BCN or SN yet, but that might change so we treat it as configurable now.
if (not $anvil->data->{cgi}{sn_count}{value})
{
$anvil->data->{cgi}{sn_count}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::sn_count::value" => $anvil->data->{cgi}{sn_count}{value} }});
}
if (not $anvil->data->{cgi}{bcn_count}{value})
{
$anvil->data->{cgi}{bcn_count}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::bcn_count::value" => $anvil->data->{cgi}{bcn_count}{value} }});
}
}
# Step 1 menu.
$anvil->data->{form}{back_link} = "?anvil=true&task=create";
$anvil->data->{form}{refresh_link} = "?anvil=true&task=manifests&manifest_uuid=".$anvil->data->{cgi}{manifest_uuid}{value}."&step=".$anvil->data->{cgi}{step}{value};
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "manifest-step1", variables => {
title => $anvil->Words->string({key => "striker_0226", variables => { number => 1 }}),
prefix => $anvil->data->{cgi}{prefix}{value},
prefix_class => $anvil->data->{cgi}{prefix}{alert} ? "input_alert" : "",
domain => $anvil->data->{cgi}{domain}{value},
domain_class => $anvil->data->{cgi}{domain}{alert} ? "input_alert" : "",
sequence => $anvil->data->{cgi}{sequence}{value},
sequence_class => $anvil->data->{cgi}{sequence}{alert} ? "input_alert" : "",
ifn_count => $anvil->data->{cgi}{ifn_count}{value},
ifn_count_class => $anvil->data->{cgi}{ifn_count}{alert} ? "input_alert" : "",
sn_count => $anvil->data->{cgi}{sn_count}{value},
sn_count_class => $anvil->data->{cgi}{sn_count}{alert} ? "input_alert" : "",
bcn_count => $anvil->data->{cgi}{bcn_count}{value},
bcn_count_class => $anvil->data->{cgi}{bcn_count}{alert} ? "input_alert" : "",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
}
elsif ($anvil->data->{cgi}{step}{value} eq "2")
{
### Ask for the network ranges.
# Eventually, we'll support user-set BCN count. So for now, we treat as such even though it
# will always be '1' for now.
my $network_form = "";
foreach my $i (1..$anvil->data->{cgi}{bcn_count}{value})
{
my $say_bcn = $anvil->Words->string({key => "striker_0018", variables => { number => $i }});
my $network_key = "bcn".$i."_network";
my $subnet_key = "bcn".$i."_subnet";
my $gateway_key = "bcn".$i."_gateway";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_bcn => $say_bcn,
network_key => $network_key,
subnet_key => $subnet_key,
gateway_key => $gateway_key,
}});
$anvil->data->{cgi}{$network_key}{value} = "10.20".$i.".0.0" if not defined $anvil->data->{cgi}{$network_key}{value};
$anvil->data->{cgi}{$network_key}{alert} = 0 if not defined $anvil->data->{cgi}{$network_key}{alert};
$anvil->data->{cgi}{$subnet_key}{value} = "255.255.0.0" if not defined $anvil->data->{cgi}{$subnet_key}{value};
$anvil->data->{cgi}{$subnet_key}{alert} = 0 if not defined $anvil->data->{cgi}{$subnet_key}{alert};
$anvil->data->{cgi}{$gateway_key}{value} = "" if not defined $anvil->data->{cgi}{$gateway_key}{value};
$anvil->data->{cgi}{$gateway_key}{alert} = 0 if not defined $anvil->data->{cgi}{$gateway_key}{alert};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value},
"cgi::${gateway_key}::alert" => $anvil->data->{cgi}{$gateway_key}{alert},
}});
my $select = $anvil->Template->select_form({
name => $subnet_key,
options => "subnet",
blank => 0,
'sort' => 0,
selected => $anvil->data->{cgi}{$subnet_key}{value},
class => $anvil->data->{cgi}{$subnet_key}{alert} ? "input_alert" : "input_clear",
style => "width: 15em;",
});
$network_form .= $anvil->Template->get({file => "anvil.html", name => "manifest-step2-network-entry", variables => {
network => $say_bcn,
network_name => $network_key,
network_class => $anvil->data->{cgi}{$network_key}{alert} ? "input_alert" : "",
network_value => $anvil->data->{cgi}{$network_key}{value},
subnet => $select,
}});
}
# There's only ever 1 SN. Just in case we change our mind later, we'll set it up as if it's
# variable.
foreach my $i (1..$anvil->data->{cgi}{bcn_count}{value})
{
my $say_sn = $anvil->Words->string({key => "striker_0020", variables => { number => '1' }});
my $network_key = "sn".$i."_network";
my $subnet_key = "sn".$i."_subnet";
my $gateway_key = "sn".$i."_gateway";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_sn => $say_sn,
network_key => $network_key,
subnet_key => $subnet_key,
gateway_key => $gateway_key,
}});
$anvil->data->{cgi}{$network_key}{value} = "10.10".$i.".0.0" if not defined $anvil->data->{cgi}{$network_key}{value};
$anvil->data->{cgi}{$network_key}{alert} = 0 if not defined $anvil->data->{cgi}{$network_key}{alert};
$anvil->data->{cgi}{$subnet_key}{value} = "255.255.0.0" if not defined $anvil->data->{cgi}{$subnet_key}{value};
$anvil->data->{cgi}{$subnet_key}{alert} = 0 if not defined $anvil->data->{cgi}{$subnet_key}{alert};
$anvil->data->{cgi}{$gateway_key}{value} = "" if not defined $anvil->data->{cgi}{$gateway_key}{value};
$anvil->data->{cgi}{$gateway_key}{alert} = 0 if not defined $anvil->data->{cgi}{$gateway_key}{alert};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value},
"cgi::${gateway_key}::alert" => $anvil->data->{cgi}{$gateway_key}{alert},
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::sn1_network::value" => $anvil->data->{cgi}{sn1_network}{value} }});
$network_form .= $anvil->Template->get({file => "anvil.html", name => "manifest-step2-network-entry", variables => {
network => $say_sn,
network_name => $network_key,
network_class => $anvil->data->{cgi}{$network_key}{alert} ? "input_alert" : "",
network_value => $anvil->data->{cgi}{$network_key}{value},
subnet => '255.255.0.0 <input type="hidden" name="'.$network_key.'" id="'.$network_key.'" value="'.$anvil->data->{cgi}{sn1_subnet}{value}.'" />',
}});
}
# Now IFNs
foreach my $i (1..$anvil->data->{cgi}{ifn_count}{value})
{
my $say_ifn = $anvil->Words->string({key => "striker_0022", variables => { number => $i }});
my $network_key = "ifn".$i."_network";
my $subnet_key = "ifn".$i."_subnet";
my $gateway_key = "ifn".$i."_gateway";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_bcn => $say_ifn,
network_key => $network_key,
subnet_key => $subnet_key,
gateway_key => $gateway_key,
}});
$anvil->data->{cgi}{$network_key}{value} = "" if not defined $anvil->data->{cgi}{$network_key}{value};
$anvil->data->{cgi}{$network_key}{alert} = 0 if not defined $anvil->data->{cgi}{$network_key}{alert};
$anvil->data->{cgi}{$subnet_key}{value} = "255.255.0.0" if not defined $anvil->data->{cgi}{$subnet_key}{value};
$anvil->data->{cgi}{$subnet_key}{alert} = 0 if not defined $anvil->data->{cgi}{$subnet_key}{alert};
$anvil->data->{cgi}{$gateway_key}{value} = "" if not defined $anvil->data->{cgi}{$gateway_key}{value};
$anvil->data->{cgi}{$gateway_key}{alert} = 0 if not defined $anvil->data->{cgi}{$gateway_key}{alert};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value},
"cgi::${gateway_key}::alert" => $anvil->data->{cgi}{$gateway_key}{alert},
}});
my $select = $anvil->Template->select_form({
name => $subnet_key,
options => "subnet",
blank => 0,
'sort' => 0,
selected => $anvil->data->{cgi}{$subnet_key}{value},
class => $anvil->data->{cgi}{$subnet_key}{alert} ? "input_alert" : "input_clear",
style => "width: 15em;",
});
$network_form .= $anvil->Template->get({file => "anvil.html", name => "manifest-step2-network-entry-gateway", variables => {
network => $say_ifn,
network_name => $network_key,
network_class => $anvil->data->{cgi}{$network_key}{alert} ? "input_alert" : "",
network_value => $anvil->data->{cgi}{$network_key}{value},
subnet => $select,
gateway_name => $gateway_key,
gateway_class => $anvil->data->{cgi}{$gateway_key}{alert} ? "input_alert" : "",
gateway_value => $anvil->data->{cgi}{$gateway_key}{value},
}});
}
my $back_link = $anvil->data->{sys}{cgi_string};
$back_link =~ s/step=2/step=1/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { back_link => $back_link}});
$anvil->data->{form}{back_link} = $back_link;
$anvil->data->{form}{refresh_link} = $anvil->data->{sys}{cgi_string};
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "manifest-step2", variables => {
title => $anvil->Words->string({key => "striker_0226", variables => { number => 2 }}),
networks => $network_form,
dns => $anvil->data->{cgi}{dns}{value},
dns_class => $anvil->data->{cgi}{dns}{alert} ? "input_alert" : "",
ntp => $anvil->data->{cgi}{ntp}{value},
ntp_class => $anvil->data->{cgi}{ntp}{alert} ? "input_alert" : "",
mtu => $anvil->data->{cgi}{mtu}{value},
mtu_class => $anvil->data->{cgi}{mtu}{alert} ? "input_alert" : "",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
}
elsif ($anvil->data->{cgi}{step}{value} eq "3")
{
# Build and show the main manifest page!
$anvil->data->{cgi}{node1_ipmi_ip}{value} = "" if not defined $anvil->data->{cgi}{node1_ipmi_ip}{value};
$anvil->data->{cgi}{node1_ipmi_ip}{alert} = 0 if not defined $anvil->data->{cgi}{node1_ipmi_ip}{alert};
$anvil->data->{cgi}{node2_ipmi_ip}{value} = "" if not defined $anvil->data->{cgi}{node2_ipmi_ip}{value};
$anvil->data->{cgi}{node2_ipmi_ip}{alert} = 0 if not defined $anvil->data->{cgi}{node2_ipmi_ip}{alert};
$anvil->data->{cgi}{dr1_ipmi_ip}{value} = "" if not defined $anvil->data->{cgi}{dr1_ipmi_ip}{value};
$anvil->data->{cgi}{dr1_ipmi_ip}{alert} = 0 if not defined $anvil->data->{cgi}{dr1_ipmi_ip}{alert};
my $sequence = $anvil->data->{cgi}{sequence}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sequence => $sequence }});
my $network_form = "";
my $network_note = "";
foreach my $network ("bcn", "sn", "ifn")
{
if ($network eq "sn")
{
# We've finished BCN, inject the IPMI.
$network_form .= $anvil->Template->get({file => "anvil.html", name => "manifest-step3-ipmi-entry", variables => {
node1_value => $anvil->data->{cgi}{node1_ipmi_ip}{value},
node1_class => $anvil->data->{cgi}{node1_ipmi_ip}{alert} ? "input_alert" : "",
node2_value => $anvil->data->{cgi}{node2_ipmi_ip}{value},
node2_class => $anvil->data->{cgi}{node2_ipmi_ip}{alert} ? "input_alert" : "",
dr1_value => $anvil->data->{cgi}{dr1_ipmi_ip}{value},
dr1_class => $anvil->data->{cgi}{dr1_ipmi_ip}{alert} ? "input_alert" : "",
}});
}
my $count_key = $network."_count";
foreach my $i (1..$anvil->data->{cgi}{$count_key}{value})
{
my $say_network_code = "striker_0018";
if ($network eq "sn") { $say_network_code = "striker_0020"; }
elsif ($network eq "ifn") { $say_network_code = "striker_0022"; }
my $say_network = $anvil->Words->string({key => $say_network_code, variables => { number => $i }});
my $network_key = $network.$i."_network";
my $subnet_key = $network.$i."_subnet";
my $gateway_key = $network.$i."_gateway";
my $node1_ip_key = "node1_".$network.$i."_ip";
my $node2_ip_key = "node2_".$network.$i."_ip";
my $dr1_ip_key = "dr1_".$network.$i."_ip";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_bcn => $say_network,
network_key => $network_key,
subnet_key => $subnet_key,
gateway_key => $gateway_key,
node1_ip_key => $node1_ip_key,
node2_ip_key => $node2_ip_key,
dr1_ip_key => $dr1_ip_key,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value},
"cgi::${gateway_key}::alert" => $anvil->data->{cgi}{$gateway_key}{alert},
}});
# The note also shows the network range.
my $message = $anvil->Words->string({key => "striker_0267", variables => { network => $anvil->data->{cgi}{$network_key}{value}."/".$anvil->data->{cgi}{$subnet_key}{value} }});
$network_note .= $anvil->Template->get({file => "anvil.html", name => "manifest-step3-network-note-entry", variables => {
name => $say_network,
message => $message,
}});
# On the BCN and SN, we can confidently take the first two octets from
# 'network' and add our guesses to the last two octets. We only guess the IFN
# if it's /16 or a larger subnet.
if ($anvil->data->{cgi}{$network_key}{value} =~ /^(\d{1,3}\.\d{1,3})\.0\.0/)
{
my $first_two_octets = $1;
my $ip_third_octet = 8 + (2 * $sequence); # Thanks to Leigh Nunan (@leighnunan) for this elegant sequence formula
my $host_ip = $first_two_octets.".".$ip_third_octet;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
first_two_octets => $first_two_octets,
ip_third_octet => $ip_third_octet,
host_ip => $host_ip,
}});
$anvil->data->{cgi}{$node1_ip_key}{value} = $host_ip.".1" if not defined $anvil->data->{cgi}{$node1_ip_key}{value};
$anvil->data->{cgi}{$node2_ip_key}{value} = $host_ip.".2" if not defined $anvil->data->{cgi}{$node2_ip_key}{value};
$anvil->data->{cgi}{$dr1_ip_key}{value} = $host_ip.".3" if not defined $anvil->data->{cgi}{$dr1_ip_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${node1_ip_key}::value" => $anvil->data->{cgi}{$node1_ip_key}{value},
"cgi::${node2_ip_key}::value" => $anvil->data->{cgi}{$node2_ip_key}{value},
"cgi::${dr1_ip_key}::value" => $anvil->data->{cgi}{$dr1_ip_key}{value},
}});
# If this is the BCN and $i = 1, build the IPMI IP guess.
if (($network eq "bcn") && ($i == 1))
{
my $ipmi_third_octet = 8 + (2 * $sequence) + 1;
my $ipmi_ip_guess = $first_two_octets.".".$ipmi_third_octet;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ipmi_third_octet => $ipmi_third_octet,
ipmi_ip_guess => $ipmi_ip_guess,
}});
$anvil->data->{cgi}{node1_ipmi_ip}{value} = $ipmi_ip_guess.".1" if not $anvil->data->{cgi}{node1_ipmi_ip}{value};
$anvil->data->{cgi}{node2_ipmi_ip}{value} = $ipmi_ip_guess.".2" if not $anvil->data->{cgi}{node2_ipmi_ip}{value};
$anvil->data->{cgi}{dr1_ipmi_ip}{value} = $ipmi_ip_guess.".3" if not $anvil->data->{cgi}{dr1_ipmi_ip}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::node1_ipmi_ip::value" => $anvil->data->{cgi}{node1_ipmi_ip}{value},
"cgi::node2_ipmi_ip::value" => $anvil->data->{cgi}{node2_ipmi_ip}{value},
"cgi::dr1_ipmi_ip::value" => $anvil->data->{cgi}{dr1_ipmi_ip}{value},
}});
}
}
# It should never happen, but in case the regex missed, set the guessed IPs to empty strings.
$anvil->data->{cgi}{$node1_ip_key}{value} = "" if not $anvil->data->{cgi}{$node1_ip_key}{value};
$anvil->data->{cgi}{$node2_ip_key}{value} = "" if not $anvil->data->{cgi}{$node2_ip_key}{value};
$anvil->data->{cgi}{$dr1_ip_key}{value} = "" if not $anvil->data->{cgi}{$dr1_ip_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${node1_ip_key}::value" => $anvil->data->{cgi}{$node1_ip_key}{value},
"cgi::${node2_ip_key}::value" => $anvil->data->{cgi}{$node2_ip_key}{value},
"cgi::${dr1_ip_key}::value" => $anvil->data->{cgi}{$dr1_ip_key}{value},
}});
$network_form .= $anvil->Template->get({file => "anvil.html", name => "manifest-step3-network-entry", variables => {
network => $say_network,
network_name => $network_key,
network_value => $anvil->data->{cgi}{$network_key}{value},
subnet_name => $subnet_key,
subnet_value => $anvil->data->{cgi}{$subnet_key}{value},
gateway_name => $gateway_key,
gateway_value => $anvil->data->{cgi}{$gateway_key}{value},
node1_ip_name => $node1_ip_key,
node1_ip_value => $anvil->data->{cgi}{$node1_ip_key}{value},
node1_ip_class => $anvil->data->{cgi}{$node1_ip_key}{alert} ? "input_alert" : "",
node2_ip_name => $node2_ip_key,
node2_ip_value => $anvil->data->{cgi}{$node2_ip_key}{value},
node2_ip_class => $anvil->data->{cgi}{$node2_ip_key}{alert} ? "input_alert" : "",
dr1_ip_name => $dr1_ip_key,
dr1_ip_value => $anvil->data->{cgi}{$dr1_ip_key}{value},
dr1_ip_class => $anvil->data->{cgi}{$dr1_ip_key}{alert} ? "input_alert" : "",
}});
}
}
# List any known fence devices.
my $fence_form = "";
$anvil->Database->get_fences({});
foreach my $fence_name (sort {$a cmp $b} keys %{$anvil->data->{fences}{fence_name}})
{
### NOTE: For now, we don't care about DR fencing. As such, the code to track it is
### commented out (in case we decide to track it someday down the road).
my $fence_uuid = $anvil->data->{fences}{fence_name}{$fence_name}{fence_uuid};
my $node1_fence_key = "node1_fence_".$fence_name;
my $node2_fence_key = "node2_fence_".$fence_name;
#my $dr1_fence_key = "dr1_fence_".$fence_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
fence_name => $fence_name,
fence_uuid => $fence_uuid,
node1_fence_key => $node1_fence_key,
node2_fence_key => $node2_fence_key,
# dr1_fence_key => $dr1_fence_key,
}});
$anvil->data->{cgi}{$node1_fence_key}{value} = "" if not defined $anvil->data->{cgi}{$node1_fence_key}{value};
$anvil->data->{cgi}{$node1_fence_key}{alert} = 0 if not defined $anvil->data->{cgi}{$node1_fence_key}{alert};
$anvil->data->{cgi}{$node2_fence_key}{value} = "" if not defined $anvil->data->{cgi}{$node2_fence_key}{value};
$anvil->data->{cgi}{$node2_fence_key}{alert} = 0 if not defined $anvil->data->{cgi}{$node2_fence_key}{alert};
#$anvil->data->{cgi}{$dr1_fence_key}{value} = "" if not defined $anvil->data->{cgi}{$dr1_fence_key}{value};
#$anvil->data->{cgi}{$dr1_fence_key}{alert} = 0 if not defined $anvil->data->{cgi}{$dr1_fence_key}{alert};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${node1_fence_key}::value" => $anvil->data->{cgi}{$node1_fence_key}{value},
"cgi::${node1_fence_key}::alert" => $anvil->data->{cgi}{$node1_fence_key}{alert},
"cgi::${node2_fence_key}::value" => $anvil->data->{cgi}{$node2_fence_key}{value},
"cgi::${node2_fence_key}::alert" => $anvil->data->{cgi}{$node2_fence_key}{alert},
# "cgi::${dr1_fence_key}::value" => $anvil->data->{cgi}{$dr1_fence_key}{value},
# "cgi::${dr1_fence_key}::alert" => $anvil->data->{cgi}{$dr1_fence_key}{alert},
}});
$fence_form .= $anvil->Template->get({file => "anvil.html", name => "manifest-step3-fence-entry", variables => {
name => $fence_name,
fence_uuid_name => "fence_".$fence_name,
fence_uuid_value => $fence_uuid,
node1_fence_name => $node1_fence_key,
node1_fence_value => $anvil->data->{cgi}{$node1_fence_key}{value},
node1_fence_class => $anvil->data->{cgi}{$node1_fence_key}{alert} ? "input_alert" : "",
node2_fence_name => $node2_fence_key,
node2_fence_value => $anvil->data->{cgi}{$node2_fence_key}{value},
node2_fence_class => $anvil->data->{cgi}{$node2_fence_key}{alert} ? "input_alert" : "",
# dr1_fence_name => $dr1_fence_key,
# dr1_fence_value => $anvil->data->{cgi}{$dr1_fence_key}{value},
# dr1_fence_class => $anvil->data->{cgi}{$dr1_fence_key}{alert} ? "input_alert" : "",
}});
}
my $ups_form = "";
$anvil->Database->get_upses({});
my $ups_count = keys %{$anvil->data->{upses}{ups_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_count => $ups_count }});
if (not $ups_count)
{
# No UPSes, add a blank entry.
$ups_form .= $anvil->Template->get({file => "anvil.html", name => "manifest-step3-ups-null-entry"});
}
foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{upses}{ups_name}})
{
### NOTE: For now, we don't care about DR UPSes. As such, the code to track it is
### commented out (in case we decide to track it someday down the road).
my $ups_uuid = $anvil->data->{upses}{ups_name}{$ups_name}{ups_uuid};
my $node1_ups_key = "node1_ups_".$ups_name;
my $node2_ups_key = "node2_ups_".$ups_name;
#my $dr1_ups_key = "dr1_ups_".$ups_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_name => $ups_name,
ups_uuid => $ups_uuid,
node1_ups_key => $node1_ups_key,
node2_ups_key => $node2_ups_key,
# dr1_ups_key => $dr1_ups_key,
}});
# Checkboxes that are not checked do not return anything at all. To deal with this,
# if we're reloading, we use 'undefined' as "not checked". Otherwise, "undefined" is
# "checked" (default).
if ((exists $anvil->data->{cgi}{reload}) && ($anvil->data->{cgi}{reload}{value}))
{
$anvil->data->{cgi}{$node1_ups_key}{value} = "" if not defined $anvil->data->{cgi}{$node1_ups_key}{value};
$anvil->data->{cgi}{$node2_ups_key}{value} = "" if not defined $anvil->data->{cgi}{$node2_ups_key}{value};
#$anvil->data->{cgi}{$dr1_ups_key}{value} = "" if not defined $anvil->data->{cgi}{$dr1_ups_key}{value};
}
else
{
$anvil->data->{cgi}{$node1_ups_key}{value} = "checked" if not defined $anvil->data->{cgi}{$node1_ups_key}{value};
$anvil->data->{cgi}{$node2_ups_key}{value} = "checked" if not defined $anvil->data->{cgi}{$node2_ups_key}{value};
#$anvil->data->{cgi}{$dr1_ups_key}{value} = "" if not defined $anvil->data->{cgi}{$dr1_ups_key}{value};
}
$anvil->data->{cgi}{$node1_ups_key}{value} = "checked" if $anvil->data->{cgi}{$node1_ups_key}{value} eq "on";
$anvil->data->{cgi}{$node2_ups_key}{value} = "checked" if $anvil->data->{cgi}{$node2_ups_key}{value} eq "on";
#$anvil->data->{cgi}{$dr1_ups_key}{value} = "checked" if $anvil->data->{cgi}{$dr1_ups_key}{value} eq "on";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${node1_ups_key}::value" => $anvil->data->{cgi}{$node1_ups_key}{value},
"cgi::${node2_ups_key}::value" => $anvil->data->{cgi}{$node2_ups_key}{value},
# "cgi::${dr1_ups_key}::value" => $anvil->data->{cgi}{$dr1_ups_key}{value},
}});
$ups_form .= $anvil->Template->get({file => "anvil.html", name => "manifest-step3-ups-entry", variables => {
name => $ups_name,
ups_uuid_name => "ups_".$ups_name,
ups_uuid_value => $ups_uuid,
node1_ups_name => $node1_ups_key,
node1_ups_checked => $anvil->data->{cgi}{$node1_ups_key}{value},
node2_ups_name => $node2_ups_key,
node2_ups_checked => $anvil->data->{cgi}{$node2_ups_key}{value},
# dr1_ups_name => $dr1_ups_key,
# dr1_ups_checked => $anvil->data->{cgi}{$dr1_ups_key}{value},
}});
}
my $back_link = $anvil->data->{sys}{cgi_string};
$back_link =~ s/step=3/step=2/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { back_link => $back_link}});
$anvil->data->{form}{back_link} = $back_link;
$anvil->data->{form}{refresh_link} = $anvil->data->{sys}{cgi_string};
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "manifest-step3", variables => {
title => $anvil->Words->string({key => "striker_0226", variables => { number => 3 }}),
networks => $network_form,
fences => $fence_form,
upses => $ups_form,
network_note => $network_note,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
}
return(0);
}
sub sanity_check_manifest_step3
{
my ($anvil) = @_;
my $sane = 1;
# Check the IPMI values. They're allowed to be blank. If they're set, they need to be in a BCN or
# IFN network.
foreach my $machine ("node1", "node2", "dr1")
{
my $key = $machine."_ipmi_ip";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
machine => $machine,
"cgi::${key}::value" => $anvil->data->{cgi}{$key}{value},
}});
if ($anvil->data->{cgi}{$key}{value})
{
# Is it a valid IPv4 address?
if (not $anvil->Validate->ipv4({ip => $anvil->data->{cgi}{$key}{value}}))
{
# Bad subnet
my $say_network = "#!string!striker_0255!#";
if ($machine eq "node2") { $say_network = "#!string!striker_0256!#"; }
elsif ($machine eq "dr1") { $say_network = "#!string!striker_0257!#"; }
my $message = $anvil->Words->string({key => "error_0125", variables => { network => $say_network }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$key}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::${key}::alert" => $anvil->data->{cgi}{$key}{alert},
"cgi::${key}::value" => $anvil->data->{cgi}{$key}{value},
}});
}
else
{
# It's a valid IP. Does it match any BCN or IFN network?
my $match_found = 0;
foreach my $network ("bcn", "sn", "ifn")
{
my $count_key = $network."_count";
foreach my $i (1..$anvil->data->{cgi}{$count_key}{value})
{
next if $match_found;
my $network_key = $network.$i."_network";
my $subnet_key = $network.$i."_subnet";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${key}::value" => $anvil->data->{cgi}{$key}{value},
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
}});
$match_found = $anvil->Network->is_ip_in_network({
debug => 2,
ip => $anvil->data->{cgi}{$key}{value},
network => $anvil->data->{cgi}{$network_key}{value},
subnet_mask => $anvil->data->{cgi}{$subnet_key}{value},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_found => $match_found }});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_found => $match_found }});
if (not $match_found)
{
# IP is valid, but not in any of the networks.
my $message = $anvil->Words->string({key => "error_0124", variables => { ip => $anvil->data->{cgi}{$key}{value} }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$key}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::${key}::alert" => $anvil->data->{cgi}{$key}{alert},
"cgi::${key}::value" => $anvil->data->{cgi}{$key}{value},
}});
}
}
}
# Now check that the IPs are sane.
foreach my $network ("bcn", "sn", "ifn")
{
my $count_key = $network."_count";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
network => $network,
count_key => $count_key,
"cgi::${count_key}::value" => $anvil->data->{cgi}{$count_key}{value},
}});
foreach my $i (1..$anvil->data->{cgi}{$count_key}{value})
{
my $say_network_code = "striker_0018";
if ($network eq "sn") { $say_network_code = "striker_0020"; }
elsif ($network eq "ifn") { $say_network_code = "striker_0022"; }
my $say_network = $anvil->Words->string({key => $say_network_code, variables => { number => $i }});
my $network_key = $network.$i."_network";
my $subnet_key = $network.$i."_subnet";
my $machine_ip_key = $machine."_".$network.$i."_ip";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_network => $say_network,
network_key => $network_key,
subnet_key => $subnet_key,
machine_ip_key => $machine_ip_key,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
"cgi::${machine_ip_key}::value" => $anvil->data->{cgi}{$machine_ip_key}{value},
"cgi::${machine_ip_key}::alert" => $anvil->data->{cgi}{$machine_ip_key}{alert},
}});
# Is the IP valid?
if (not $anvil->Validate->ipv4({ip => $anvil->data->{cgi}{$machine_ip_key}{value}, debug => 2}))
{
# Bad subnet
my $say_network = "#!string!striker_0255!#";
if ($machine eq "node2") { $say_network = "#!string!striker_0256!#"; }
elsif ($machine eq "dr1") { $say_network = "#!string!striker_0257!#"; }
my $message = $anvil->Words->string({key => "error_0016", variables => { network => $say_network }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$machine_ip_key}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::${machine_ip_key}::alert" => $anvil->data->{cgi}{$machine_ip_key}{alert},
"cgi::${machine_ip_key}::value" => $anvil->data->{cgi}{$machine_ip_key}{value},
}});
}
else
{
# It's a valid IP. Is it in the network?
my $match_found = $anvil->Network->is_ip_in_network({
debug => 2,
ip => $anvil->data->{cgi}{$machine_ip_key}{value},
network => $anvil->data->{cgi}{$network_key}{value},
subnet_mask => $anvil->data->{cgi}{$subnet_key}{value},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_found => $match_found }});
if (not $match_found)
{
# IP is valid, but not in any of the networks.
my $message = $anvil->Words->string({key => "error_0126", variables => {
ip => $anvil->data->{cgi}{$key}{value},
network => $anvil->data->{cgi}{$network_key}{value}."/".$anvil->data->{cgi}{$subnet_key}{value},
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$key}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::${key}::alert" => $anvil->data->{cgi}{$key}{alert},
"cgi::${key}::value" => $anvil->data->{cgi}{$key}{value},
}});
}
}
}
}
}
### TODO: We can't (at least yet) validate ports. They could be numeric or strings... To sanity check
### this, we'll need to look up the fence agent, look up the port type, and use that to decide
### how to check. That's more than we can do for 3.0.
return($sane);
}
sub sanity_check_manifest_step2
{
my ($anvil) = @_;
my $sane = 1;
foreach my $i (1..$anvil->data->{cgi}{bcn_count}{value})
{
my $say_bcn = $anvil->Words->string({key => "striker_0018", variables => { number => $i }});
my $network_key = "bcn".$i."_network";
my $subnet_key = "bcn".$i."_subnet";
my $gateway_key = "bcn".$i."_gateway";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
network_key => $network_key,
subnet_key => $subnet_key,
gateway_key => $gateway_key,
}});
# The BCN doesn't support setting the netmask (for now, anyway), so we'll set it here to /16.
# If later support is added, this will pick it up.
$anvil->data->{cgi}{$subnet_key}{value} = "255.255.0.0" if not defined $anvil->data->{cgi}{$subnet_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value},
}});
$sane = check_network($anvil, $sane, $say_bcn, $network_key, $subnet_key, $gateway_key);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
}
# There's only ever 1 SN
my $say_sn = $anvil->Words->string({key => "striker_0020", variables => { number => '1' }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_sn => $say_sn }});
# The storage network always uses the subnet /16 and has no gateway.
$anvil->data->{cgi}{sn1_subnet}{value} = "255.255.0.0" if not defined $anvil->data->{cgi}{sn1_subnet}{value};
$anvil->data->{cgi}{sn1_gateway}{value} = "" if not defined $anvil->data->{cgi}{sn1_gateway}{value};
$sane = check_network($anvil, $sane, $say_sn, "sn1_network", "sn1_subnet", "sn1_gateway");
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
# Now IFNs
foreach my $i (1..$anvil->data->{cgi}{ifn_count}{value})
{
my $say_ifn = $anvil->Words->string({key => "striker_0022", variables => { number => $i }});
my $network_key = "ifn".$i."_network";
my $subnet_key = "ifn".$i."_subnet";
my $gateway_key = "ifn".$i."_gateway";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
say_bcn => $say_ifn,
network_key => $network_key,
subnet_key => $subnet_key,
gateway_key => $gateway_key,
}});
$anvil->data->{cgi}{$network_key}{value} = "" if not defined $anvil->data->{cgi}{$network_key}{value};
$anvil->data->{cgi}{$network_key}{alert} = 0 if not defined $anvil->data->{cgi}{$network_key}{alert};
$anvil->data->{cgi}{$subnet_key}{value} = "255.255.0.0" if not defined $anvil->data->{cgi}{$subnet_key}{value};
$anvil->data->{cgi}{$subnet_key}{alert} = 0 if not defined $anvil->data->{cgi}{$subnet_key}{alert};
$anvil->data->{cgi}{$gateway_key}{value} = "" if not defined $anvil->data->{cgi}{$gateway_key}{value};
$anvil->data->{cgi}{$gateway_key}{alert} = 0 if not defined $anvil->data->{cgi}{$gateway_key}{alert};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value},
"cgi::${gateway_key}::alert" => $anvil->data->{cgi}{$gateway_key}{alert},
}});
$sane = check_network($anvil, $sane, $say_ifn, $network_key, $subnet_key, $gateway_key);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
}
# If DNS is specified, make sure it/they are valid.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::dns::value" => $anvil->data->{cgi}{dns}{value} }});
if ($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 => 2, list => { ip => $ip }});
if (not $anvil->Validate->ipv4({ip => $ip}))
{
# Bad network
my $message = $anvil->Words->string({key => "error_0015"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{dns}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
ip => $ip,
"cgi::dns::alert" => $anvil->data->{cgi}{dns}{alert},
"cgi::dns::value" => $anvil->data->{cgi}{dns}{value},
}});
}
}
}
# If NTP is specified, make sure it/they are valid.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::ntp::value" => $anvil->data->{cgi}{ntp}{value} }});
if ($anvil->data->{cgi}{ntp}{value})
{
foreach my $ip (split/,/, $anvil->data->{cgi}{ntp}{value})
{
$ip =~ s/^\s+//;
$ip =~ s/\s+$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip => $ip }});
if (not $anvil->Validate->ipv4({ip => $ip}))
{
# Bad network
my $message = $anvil->Words->string({key => "error_0122"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{ntp}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
ip => $ip,
"cgi::ntp::alert" => $anvil->data->{cgi}{ntp}{alert},
"cgi::ntp::value" => $anvil->data->{cgi}{ntp}{value},
}});
}
}
}
# Make sure the MTU is sane
if (not $anvil->Validate->positive_integer({number => $anvil->data->{cgi}{mtu}{value}}))
{
my $message = $anvil->Words->string({key => "error_0123"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{mtu}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::mtu::alert" => $anvil->data->{cgi}{mtu}{alert},
"cgi::mtu::value" => $anvil->data->{cgi}{mtu}{value},
}});
}
return($sane);
}
### TODO: Make this a Validate module
sub check_network
{
my ($anvil, $sane, $say_network, $network_key, $subnet_key, $gateway_key) = @_;
# Make sure the network and subnet are valid
my $local_sane = 1;
if (not $anvil->Validate->ipv4({ip => $anvil->data->{cgi}{$network_key}{value}}))
{
# Bad network
my $message = $anvil->Words->string({key => "error_0020", variables => { field => $say_network." - #!string!striker_0149!#" }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$network_key}{alert} = 1;
$sane = 0;
$local_sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
local_sane => $local_sane,
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
}});
}
if (not $anvil->Validate->ipv4({ip => $anvil->data->{cgi}{$subnet_key}{value}}))
{
# Bad subnet
my $message = $anvil->Words->string({key => "error_0020", variables => { field => $say_network." - #!string!striker_0025!#" }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$subnet_key}{alert} = 1;
$sane = 0;
$local_sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
local_sane => $local_sane,
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
}});
}
# The gateway can be blank
if (($anvil->data->{cgi}{$gateway_key}{value}) && (not $anvil->Validate->ipv4({ip => $anvil->data->{cgi}{$gateway_key}{value}})))
{
# It's not a valid IP.
my $message = $anvil->Words->string({key => "error_0118", variables => { ip => $anvil->data->{cgi}{$gateway_key}{value} }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$gateway_key}{alert} = 1;
$sane = 0;
$local_sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
local_sane => $local_sane,
"cgi::${gateway_key}::alert" => $anvil->data->{cgi}{$gateway_key}{alert},
"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value},
}});
}
# If I'm still sane, make sure that the network is actually the bottom of the subnet.
if ($local_sane)
{
my $test_network = $anvil->Network->get_network({ip => $anvil->data->{cgi}{$network_key}{value}, subnet_mask => $anvil->data->{cgi}{$subnet_key}{value}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { test_network => $test_network }});
if (not $test_network)
{
# Something is invalid.
my $message = $anvil->Words->string({key => "error_0120", variables => {
network => $anvil->data->{cgi}{$network_key}{value},
subnet => $anvil->data->{cgi}{$subnet_key}{value},
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$network_key}{alert} = 1;
$anvil->data->{cgi}{$subnet_key}{alert} = 1;
$sane = 0;
$local_sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
local_sane => $local_sane,
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
"cgi::${subnet_key}::alert" => $anvil->data->{cgi}{$subnet_key}{alert},
"cgi::${subnet_key}::value" => $anvil->data->{cgi}{$subnet_key}{value},
}});
}
elsif ($test_network ne $anvil->data->{cgi}{$network_key}{value})
{
# The user didn't give the base IP of the network.
my $message = $anvil->Words->string({key => "error_0119", variables => {
name => $say_network,
ip => $test_network,
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$network_key}{alert} = 1;
$sane = 0;
$local_sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
local_sane => $local_sane,
"cgi::${network_key}::alert" => $anvil->data->{cgi}{$network_key}{alert},
"cgi::${network_key}::value" => $anvil->data->{cgi}{$network_key}{value},
}});
}
# Lastly, if we've got a gateway, make sure it's in the network.
if (($local_sane) && ($anvil->data->{cgi}{$gateway_key}{value}))
{
my $base_ip = $anvil->Network->get_network({ip => $anvil->data->{cgi}{$gateway_key}{value}, subnet_mask => $anvil->data->{cgi}{$subnet_key}{value}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { base_ip => $base_ip }});
if ($base_ip ne $anvil->data->{cgi}{$network_key}{value})
{
# The gateway is not in the subnet
my $message = $anvil->Words->string({key => "error_0121", variables => {
gateway => $anvil->data->{cgi}{$gateway_key}{value},
network => $anvil->data->{cgi}{$network_key}{value},
subnet => $anvil->data->{cgi}{$subnet_key}{value},
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{$gateway_key}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::${gateway_key}::alert" => $anvil->data->{cgi}{$gateway_key}{alert},
"cgi::${gateway_key}::value" => $anvil->data->{cgi}{$gateway_key}{value},
}});
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
return($sane);
}
sub sanity_check_manifest_step1
{
my ($anvil) = @_;
my $sane = 1;
if ((not $anvil->Validate->alphanumeric({string => $anvil->data->{cgi}{prefix}{value}})) or (length($anvil->data->{cgi}{prefix}{value}) > 5))
{
my $message = $anvil->Words->string({key => "error_0020", variables => { field => "#!string!striker_0228!#" }});
if ($anvil->data->{cgi}{prefix}{value})
{
$message = $anvil->Words->string({key => "error_0021"});
}
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$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},
"cgi::prefix::value" => $anvil->data->{cgi}{prefix}{value},
}});
}
# We can use Validate to check the domain.
if (not $anvil->Validate->domain_name({name => $anvil->data->{cgi}{domain}{value}, debug => 2}))
{
my $message = $anvil->Words->string({key => "error_0020", variables => { field => "#!string!striker_0007!#" }});
if ($anvil->data->{cgi}{domain}{value})
{
$message = $anvil->Words->string({key => "error_0117", variables => { name => $anvil->data->{cgi}{domain}{value} }});
}
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->data->{cgi}{domain}{alert} = 1;
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
sane => $sane,
"cgi::domain::alert" => $anvil->data->{cgi}{domain}{alert},
"cgi::domain::value" => $anvil->data->{cgi}{domain}{value},
}});
}
# The sequence and IFN count need to be integers.
if (not $anvil->Validate->positive_integer({number => $anvil->data->{cgi}{sequence}{value}}))
{
my $message = $anvil->Words->string({key => "error_0020", variables => { field => "#!string!striker_0009!#" }});
if ($anvil->data->{cgi}{sequence}{value})
{
$message = $anvil->Words->string({key => "error_0022", variables => { field => "#!string!striker_0009!#" }});
}
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$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},
"cgi::sequence::value" => $anvil->data->{cgi}{sequence}{value},
}});
}
if (not $anvil->Validate->positive_integer({number => $anvil->data->{cgi}{ifn_count}{value}}))
{
my $message = $anvil->Words->string({key => "error_0020", variables => { field => "#!string!striker_0230!#" }});
if ($anvil->data->{cgi}{ifn_count}{value})
{
$message = $anvil->Words->string({key => "error_0022", variables => { field => "#!string!striker_0230!#" }});
}
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$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},
"cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value},
}});
}
return($sane);
}
# Show the create manifest (and Fence devices and UPSes) menu
sub process_create
{
my ($anvil) = @_;
# Show existing manifests.
$anvil->Database->get_manifests();
my $manifest_template = "";
foreach my $manifest_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_name}})
{
my $manifest_uuid = $anvil->data->{manifests}{manifest_name}{$manifest_name}{manifest_uuid};
my $manifest_last_ran = $anvil->data->{manifests}{manifest_name}{$manifest_name}{manifest_last_ran};
my $manifest_xml = $anvil->data->{manifests}{manifest_name}{$manifest_name}{manifest_xml};
my $manifest_note = $anvil->data->{manifests}{manifest_name}{$manifest_name}{manifest_note};
$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 => "create-menu-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->{form}{refresh_link} = "?anvil=true&task=create";
$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 allows the user to tell us about upses.
sub process_upses
{
my ($anvil) = @_;
# Pull the data of supported UPSes out of the specual 'ups_X' strings.
$anvil->Striker->get_ups_data({debug => 3});
foreach my $key (sort {$a cmp $b} keys %{$anvil->data->{ups_data}})
{
my $agent = $anvil->data->{ups_data}{$key}{agent};
my $brand = $anvil->data->{ups_data}{$key}{brand};
my $description = $anvil->data->{ups_data}{$key}{description};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"s1:key" => $key,
"s2:agent" => $anvil->data->{ups_data}{$key}{agent},
"s3:brand" => $anvil->data->{ups_data}{$key}{brand},
"s4:description" => $anvil->data->{ups_data}{$key}{description},
}});
}
$anvil->data->{cgi}{ups_agent}{value} = "" if not defined $anvil->data->{cgi}{ups_agent}{value};
$anvil->data->{cgi}{ups_count}{value} = 1 if not defined $anvil->data->{cgi}{ups_count}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::ups_agent::value" => $anvil->data->{cgi}{ups_agent}{value},
"cgi::ups_count::value" => $anvil->data->{cgi}{ups_count}{value},
}});
# Are we going back to the form?
if ($anvil->data->{cgi}{back}{value})
{
$anvil->data->{cgi}{save}{value} = "";
$anvil->data->{cgi}{confirm}{value} = "";
$anvil->data->{cgi}{delete_ups_uuid}{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},
"cgi::delete_ups_uuid::value" => $anvil->data->{cgi}{delete_ups_uuid}{value},
}});
}
# Are we deleting an agent?
if ((exists $anvil->data->{cgi}{delete_ups_uuid}) && ($anvil->data->{cgi}{delete_ups_uuid}{value}))
{
# Verify that the UUID is valid.
$anvil->Database->get_upses({debug => 2, include_deleted => 1});
my $ups_uuid = $anvil->data->{cgi}{delete_ups_uuid}{value};
my $ups_name = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_name};
my $ups_agent = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_agent};
if (not exists $anvil->data->{upses}{ups_uuid}{$ups_uuid})
{
# Doesn't exist.
my $message = $anvil->Words->string({key => "warning_0036", variables => { uuid => $ups_uuid }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
elsif ($anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_ip_address} eq "DELETED")
{
# Already deleted.
my $message = $anvil->Words->string({key => "warning_0037", variables => {
name => $ups_name,
uuid => $ups_uuid,
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
# Has the user confirmed?
if ((exists $anvil->data->{cgi}{confirm}) && ($anvil->data->{cgi}{confirm}{value}))
{
# Delete it
my ($ups_uuid) = $anvil->Database->insert_or_update_upses({
debug => 2,
ups_uuid => $ups_uuid,
ups_name => $ups_name,
ups_agent => $ups_agent,
ups_ip_address => "DELETED",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_uuid => $ups_uuid }});
if ($ups_uuid)
{
# Deleted successfully
my $message = $anvil->Words->string({key => "ok_0008", variables => { name => $ups_name }});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::ok_message" => $anvil->data->{form}{ok_message} }});
}
else
{
# Something went wrong.
my $message = $anvil->Words->string({key => "warning_0040", variables => {
name => $ups_name,
uuid => $ups_uuid,
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
# Show the main menu and return.
show_ups_config_main_menu($anvil);
return(0);
}
else
{
# Ask the user to confirm.
my $ups_name = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_name};
my $ups_ip_address = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_ip_address};
my $say_ups_device = $ups_name." - ".$ups_ip_address." (".$anvil->data->{ups_agent}{$ups_agent}{brand}.")";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_uuid => $ups_uuid,
ups_agent => $ups_agent,
ups_ip_address => $ups_ip_address,
say_ups_device => $say_ups_device,
}});
# Are we asking the user to confirm one or more?
$anvil->data->{form}{back_link} = "?anvil=true&task=upses";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "ups-delete-confirm", variables => {
name => $ups_name,
say_device => $say_ups_device,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
}
# Are we configuring an agent/device?
$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},
}});
if ($anvil->data->{cgi}{save}{value})
{
# Confirmed?
if ($anvil->data->{cgi}{confirm}{value})
{
# Confirmed.
my $success = 1;
my $message = "";
foreach my $i (1..$anvil->data->{cgi}{ups_count}{value})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { i => $i }});
my $ups_uuid_key = "ups_uuid_".$i;
my $ups_name_key = "ups_name_".$i;
my $ups_agent_key = "ups_agent_".$i;
my $ups_ip_address_key = "ups_ip_address_".$i;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_uuid_key => $ups_uuid_key,
ups_name_key => $ups_name_key,
ups_agent_key => $ups_agent_key,
ups_ip_address_key => $ups_ip_address_key,
}});
my $ups_uuid = $anvil->data->{cgi}{$ups_uuid_key}{value};
my $ups_name = $anvil->data->{cgi}{$ups_name_key}{value};
my $ups_agent = $anvil->data->{cgi}{$ups_agent_key}{value};
my $ups_ip_address = $anvil->data->{cgi}{$ups_ip_address_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:ups_uuid' => $ups_uuid,
's2:ups_name' => $ups_name,
's3:ups_agent' => $ups_agent,
's4:ups_ip_address' => $ups_ip_address,
}});
# Save it
($ups_uuid) = $anvil->Database->insert_or_update_upses({
debug => 2,
ups_uuid => $ups_uuid,
ups_name => $ups_name,
ups_agent => $ups_agent,
ups_ip_address => $ups_ip_address,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_uuid => $ups_uuid }});
if ($ups_uuid)
{
$message .= $anvil->Words->string({key => "ok_0007", variables => { name => $ups_name }})."<br />";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message => $message }});
# Clear CGI values so the form isn't pre-filled below.
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 =~ /_$i$/)
{
$anvil->data->{cgi}{$key}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${key}::value" => $anvil->data->{cgi}{$key}{value} }});
}
}
}
else
{
# Something went wrong.
$success = 0;
$message .= $anvil->Words->string({key => "warning_0038", variables => { name => $ups_name }})."<br />";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:success' => $success,
's2:message' => $message,
}});
}
}
# Show it in the top-center.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { success => $success }});
if ($success)
{
# Woot!
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::ok_message" => $anvil->data->{form}{ok_message} }});
# Show the main menu and return.
show_ups_config_main_menu($anvil);
return(0);
}
else
{
# Something went wrong.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
}
else
{
# Loop through the UPSes and ask for confirmation.
my $sane = 1;
my $upses_form = "";
foreach my $i (1..$anvil->data->{cgi}{ups_count}{value})
{
my $say_device = $anvil->Words->string({key => "striker_0239", variables => { number => $i }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
i => $i,
say_device => $say_device,
}});
my $ups_uuid_key = "ups_uuid_".$i;
my $ups_name_key = "ups_name_".$i;
my $ups_agent_key = "ups_agent_".$i;
my $ups_ip_address_key = "ups_ip_address_".$i;
my $agent = $anvil->data->{cgi}{$ups_agent_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_uuid_key => $ups_uuid_key,
ups_name_key => $ups_name_key,
ups_agent_key => $ups_agent_key,
ups_ip_address_key => $ups_ip_address_key,
agent => $agent,
}});
# Are any values insane?
if (not $anvil->Validate->host_name({name => $anvil->data->{cgi}{$ups_name_key}{value}, debug => 2}))
{
# Bad host name
$sane = 0;
$anvil->data->{cgi}{$ups_name_key}{alert} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${ups_name_key}::alert" => $anvil->data->{cgi}{$ups_name_key}{alert},
sane => $sane,
}});
}
if (not $anvil->Validate->ipv4({ip => $anvil->data->{cgi}{$ups_ip_address_key}{value}}))
{
# Bad IP address.
$sane = 0;
$anvil->data->{cgi}{$ups_name_key}{alert} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${ups_name_key}::alert" => $anvil->data->{cgi}{$ups_name_key}{alert},
sane => $sane,
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
if ($sane)
{
$upses_form .= $anvil->Template->get({file => "anvil.html", name => "ups-option-menu-confirm", variables => {
device => $say_device,
name_key => $ups_name_key,
name => $anvil->data->{cgi}{$ups_name_key}{value},
agent_key => $ups_agent_key,
agent => $anvil->data->{cgi}{$ups_agent_key}{value},
say_agent => $anvil->data->{ups_agent}{$agent}{brand},
ip_address_key => $ups_ip_address_key,
ip_address => $anvil->data->{cgi}{$ups_ip_address_key}{value},
ups_uuid_key => $ups_uuid_key,
ups_uuid => $anvil->data->{cgi}{$ups_uuid_key}{value},
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { upses_form => $upses_form }});
}
}
if ($sane)
{
$anvil->data->{form}{back_link} = "?anvil=true&task=upses";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "ups-configuration-confirm", variables => {
upses => $upses_form,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
else
{
# Send the user back to the form.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => "#!string!warning_0039!#" }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
}
}
if ($anvil->data->{cgi}{ups_agent}{value})
{
my $ups_agent = $anvil->data->{cgi}{ups_agent}{value};
my $ups_brand = $anvil->data->{ups_agent}{$ups_agent}{brand};
my $ups_description = $anvil->data->{ups_agent}{$ups_agent}{description};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_agent => $ups_agent,
ups_brand => $ups_brand,
ups_description => $ups_description,
}});
# 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},
}});
}
# This will be used in forms
my $brands = [];
my $description_form = "";
foreach my $key (sort {$a cmp $b} keys %{$anvil->data->{ups_data}})
{
my $agent = $anvil->data->{ups_data}{$key}{agent};
my $brand = $anvil->data->{ups_data}{$key}{brand};
my $description = $anvil->data->{ups_data}{$key}{description};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:key" => $key,
"s2:agent" => $anvil->data->{ups_data}{$key}{agent},
"s3:brand" => $anvil->data->{ups_data}{$key}{brand},
"s4:description" => $anvil->data->{ups_data}{$key}{description},
}});
push @{$brands}, $agent."#!#".$brand;
}
# Walk through the list of UPSes
$anvil->Database->get_upses({debug => 3});
my $upses_form = "";
if ((not exists $anvil->data->{cgi}{ups_brand}) or (not defined $anvil->data->{cgi}{ups_brand}{value}))
{
$anvil->data->{cgi}{ups_brand}{value} = $ups_brand;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::ups_brand::value" => $anvil->data->{cgi}{ups_brand}{value},
}});
}
foreach my $i (1..$anvil->data->{cgi}{ups_count}{value})
{
my $say_device = $anvil->Words->string({key => "striker_0239", variables => { number => $i }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
i => $i,
say_device => $say_device,
}});
my $ups_uuid_key = "ups_uuid_".$i;
my $ups_name_key = "ups_name_".$i;
my $ups_agent_key = "ups_agent_".$i;
my $ups_ip_address_key = "ups_ip_address_".$i;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_uuid_key => $ups_uuid_key,
ups_name_key => $ups_name_key,
ups_agent_key => $ups_agent_key,
ups_ip_address_key => $ups_ip_address_key
}});
# Make sure we don't get any undefined warnings
if ((not exists $anvil->data->{cgi}{$ups_name_key}) or (not defined $anvil->data->{cgi}{$ups_name_key}{value}))
{
$anvil->data->{cgi}{$ups_name_key}{value} = "";
}
if ((not exists $anvil->data->{cgi}{$ups_agent_key}) or (not defined $anvil->data->{cgi}{$ups_agent_key}{value}))
{
$anvil->data->{cgi}{$ups_agent_key}{value} = "";
}
if ((not exists $anvil->data->{cgi}{$ups_uuid_key}) or (not defined $anvil->data->{cgi}{$ups_uuid_key}{value}))
{
$anvil->data->{cgi}{$ups_uuid_key}{value} = "";
}
# If we have a ups_uuid_X, read in the details.
if ($anvil->data->{cgi}{$ups_uuid_key}{value})
{
my $ups_uuid = $anvil->data->{cgi}{$ups_uuid_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_uuid => $ups_uuid }});
if (exists $anvil->data->{upses}{ups_uuid}{$ups_uuid})
{
my $old_ups_name = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_name};
my $old_ups_agent = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_agent};
my $old_ups_ip_address = $anvil->data->{upses}{ups_uuid}{$ups_uuid}{ups_ip_address};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
old_ups_name => $old_ups_name,
old_ups_agent => $old_ups_agent,
old_ups_ip_address => $old_ups_ip_address,
ups_name_key => $ups_name_key,
ups_agent_key => $ups_agent_key,
ups_ip_address_key => $ups_ip_address_key,
}});
# Now if we don't have a value in CGI but do from the database, set the CGI.
if ((not $anvil->data->{cgi}{$ups_name_key}{value}) && ($old_ups_name))
{
$anvil->data->{cgi}{$ups_name_key}{value} = $old_ups_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${ups_name_key}::value" => $anvil->data->{cgi}{$ups_name_key}{value},
}});
}
if ((not $anvil->data->{cgi}{$ups_agent_key}{value}) && ($old_ups_agent))
{
$anvil->data->{cgi}{$ups_agent_key}{value} = $old_ups_agent;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${ups_agent_key}::value" => $anvil->data->{cgi}{$ups_agent_key}{value},
}});
}
if ((not $anvil->data->{cgi}{$ups_ip_address_key}{value}) && ($old_ups_ip_address))
{
$anvil->data->{cgi}{$ups_ip_address_key}{value} = $old_ups_ip_address;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${ups_ip_address_key}::value" => $anvil->data->{cgi}{$ups_ip_address_key}{value},
}});
}
}
}
my $ups_agent_select = $anvil->Template->select_form({
name => $ups_agent_key,
options => $brands,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{$ups_agent_key}{value} ? $anvil->data->{cgi}{$ups_agent_key}{value} : $anvil->data->{cgi}{ups_agent}{value},
class => "input_clear",
});
$upses_form .= $anvil->Template->get({file => "anvil.html", name => "ups-option-menu", variables => {
device => $say_device,
name_key => $ups_name_key,
name => $anvil->data->{cgi}{$ups_name_key}{value},
agent => $ups_agent_select,
ip_address_key => $ups_ip_address_key,
ip_address => $anvil->data->{cgi}{$ups_ip_address_key}{value},
ups_uuid_key => $ups_uuid_key,
ups_uuid => $anvil->data->{cgi}{$ups_uuid_key}{value},
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { upses_form => $upses_form }});
}
$anvil->data->{form}{back_link} = "?anvil=true&task=upses";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "ups-configuration", variables => {
description => $ups_description,
upses => $upses_form,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'form::body' => $anvil->data->{form}{body} }});
}
else
{
# Show the main menu
show_ups_config_main_menu($anvil);
}
return(0);
}
sub show_ups_config_main_menu
{
my ($anvil) = @_;
# Read in known UPSes
$anvil->Database->get_upses({debug => 3});
# Get a list of current ups agents.
my $existing_upses = "";
if (exists $anvil->data->{upses}{ups_uuid})
{
# How many do we have?
my $ups_count = keys %{$anvil->data->{upses}{ups_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ups_count => $ups_count }});
if ($ups_count)
{
# We've got devices.
my $ups_devices = "";
foreach my $ups_name (sort {$a cmp $b} keys %{$anvil->data->{upses}{ups_name}})
{
my $ups_uuid = $anvil->data->{upses}{ups_name}{$ups_name}{ups_uuid};
my $ups_agent = $anvil->data->{upses}{ups_name}{$ups_name}{ups_agent};
my $ups_ip_address = $anvil->data->{upses}{ups_name}{$ups_name}{ups_ip_address};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
ups_uuid => $ups_uuid,
ups_agent => $ups_agent,
ups_ip_address => $ups_ip_address,
}});
$ups_devices .= $anvil->Template->get({file => "anvil.html", name => "existing-ups-entry", variables => {
name => $ups_name,
ip_address => $ups_ip_address,
ups_agent => $ups_agent,
ups_uuid => $ups_uuid,
}});
}
$existing_upses .= $anvil->Template->get({file => "anvil.html", name => "existing-upses", variables => {
upses => $ups_devices,
}});
}
}
# For each agent, we'll create a <div> with it's options that will be shown/hidden basen on the agent
# select box.
my $brands = [];
my $description_form = "";
foreach my $key (sort {$a cmp $b} keys %{$anvil->data->{ups_data}})
{
my $agent = $anvil->data->{ups_data}{$key}{agent};
my $brand = $anvil->data->{ups_data}{$key}{brand};
my $description = $anvil->data->{ups_data}{$key}{description};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:key" => $key,
"s2:agent" => $anvil->data->{ups_data}{$key}{agent},
"s3:brand" => $anvil->data->{ups_data}{$key}{brand},
"s4:description" => $anvil->data->{ups_data}{$key}{description},
}});
push @{$brands}, $agent."#!#".$brand;
$description_form .= $anvil->Template->get({file => "anvil.html", name => "ups-agent-description", variables => {
name => $brand,
description => $description,
}});
}
my $ups_agent_select = $anvil->Template->select_form({
name => "ups_agent",
options => $brands,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{ups_agent}{value} ? $anvil->data->{cgi}{ups_agent}{value} : "scan-apc-ups",
class => "input_clear",
});
my $ups_count_select = $anvil->Template->select_form({
name => "ups_count",
options => [1, 2, 3, 4],
blank => 0,
'sort' => 0,
selected => $anvil->data->{cgi}{ups_count}{value},
class => "input_clear",
});
$anvil->data->{form}{back_link} = "?anvil=true&task=create";
$anvil->data->{form}{refresh_link} = "?anvil=true&task=upses";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "ups-agent-menu", variables => {
ups_select => $ups_agent_select,
ups_count => $ups_count_select,
descriptions => $description_form,
existing_upses => $existing_upses,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
# 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});
$anvil->data->{cgi}{fence_agent}{value} = "" if not defined $anvil->data->{cgi}{fence_agent}{value};
$anvil->data->{cgi}{fence_count}{value} = 1 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 deleting an agent?
if ((exists $anvil->data->{cgi}{delete_fence_uuid}) && ($anvil->data->{cgi}{delete_fence_uuid}{value}))
{
# Verify that the UUID is valid.
$anvil->Database->get_fences({debug => 2, include_deleted => 1});
my $fence_uuid = $anvil->data->{cgi}{delete_fence_uuid}{value};
my $fence_name = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_name};
my $fence_agent = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_agent};
if (not exists $anvil->data->{fences}{fence_uuid}{$fence_uuid})
{
# Doesn't exist.
my $message = $anvil->Words->string({key => "warning_0034", variables => { uuid => $fence_uuid }});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
elsif ($anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_arguments} eq "DELETED")
{
# Already deleted.
my $message = $anvil->Words->string({key => "warning_0033", variables => {
name => $fence_name,
uuid => $fence_uuid,
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
# Has the user confirmed?
if ((exists $anvil->data->{cgi}{confirm}) && ($anvil->data->{cgi}{confirm}{value}))
{
# Delete it
my ($fence_uuid) = $anvil->Database->insert_or_update_fences({
debug => 2,
fence_uuid => $fence_uuid,
fence_name => $fence_name,
fence_agent => $fence_agent,
fence_arguments => "DELETED",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { fence_uuid => $fence_uuid }});
if ($fence_uuid)
{
# Deleted successfully
my $message = $anvil->Words->string({key => "ok_0006", variables => { name => $fence_name }});
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::ok_message" => $anvil->data->{form}{ok_message} }});
}
else
{
# Something went wrong.
my $message = $anvil->Words->string({key => "warning_0035", variables => {
name => $fence_name,
uuid => $fence_uuid,
}});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
# Show the main menu and return.
show_fence_config_main_menu($anvil);
return(0);
}
else
{
# Ask the user to confirm.
my $fence_name = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_name};
my $fence_arguments = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_arguments};
my $say_fence_device = $fence_agent." ".$fence_arguments;
$say_fence_device =~ s/passw(\w+)="(.*?)"/passw$1="--"/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
fence_uuid => $fence_uuid,
fence_agent => $fence_agent,
fence_arguments => $fence_arguments =~ /passw=/ ? $anvil->Log->is_secure($fence_arguments) : $fence_arguments,
say_fence_device => $say_fence_device,
}});
# Are we asking the user to confirm one or more?
$anvil->data->{form}{back_link} = "?anvil=true&task=fences";
$anvil->data->{form}{body} = $anvil->Template->get({file => "anvil.html", name => "fence-agent-delete-confirm", variables => {
name => $fence_name,
say_device => $say_fence_device,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'form::body' => $anvil->data->{form}{body} }});
return(0);
}
}
# Are we configuring an agent/device?
if ($anvil->data->{cgi}{fence_agent}{value})
{
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);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
if ($sane)
{
my $success = 0;
if ($anvil->data->{cgi}{confirm}{value})
{
# Build the table and ask the user to confirm.
$success = 1;
my $message = "";
foreach my $i (sort {$a cmp $b} keys %{$anvil->data->{fence}{$fence_agent}{set}})
{
my $fence_name_key = "fence_name_".$i;
my $fence_uuid_key = "fence_uuid_".$i;
my $fence_name = defined $anvil->data->{cgi}{$fence_name_key}{value} ? $anvil->data->{cgi}{$fence_name_key}{value} : "";
my $fence_uuid = defined $anvil->data->{cgi}{$fence_uuid_key}{value} ? $anvil->data->{cgi}{$fence_uuid_key}{value} : "";
my $fence_arguments = "";
foreach my $name (sort {$a cmp $b} keys %{$anvil->data->{fence}{$fence_agent}{set}{$i}{parameter}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { name => $name }});
$fence_arguments .= $name."=\"".$anvil->data->{fence}{$fence_agent}{set}{$i}{parameter}{$name}{set}."\" ";
}
$fence_arguments =~ s/\s+$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:i' => $i,
's2:fence_agent' => $fence_agent,
's3:fence_name' => $fence_name,
's4:fence_uuid' => $fence_uuid,
's5:fence_arguments' => $fence_arguments,
}});
# Save it
($fence_uuid) = $anvil->Database->insert_or_update_fences({
debug => 2,
fence_name => $fence_name,
fence_agent => $fence_agent,
fence_arguments => $fence_arguments,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { fence_uuid => $fence_uuid }});
if ($fence_uuid)
{
$message .= $anvil->Words->string({key => "ok_0005", variables => { name => $fence_name }})."<br />";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { message => $message }});
# Clear CGI values so the form isn't pre-filled below.
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 =~ /_$i$/)
{
$anvil->data->{cgi}{$key}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::${key}::value" => $anvil->data->{cgi}{$key}{value} }});
}
}
}
else
{
# Something went wrong.
$success = 0;
$message .= $anvil->Words->string({key => "warning_0032", variables => { name => $fence_name }})."<br />";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:success' => $success,
's2:message' => $message,
}});
}
}
# Show it in the top-center.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { success => $success }});
if ($success)
{
# Woot!
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::ok_message" => $anvil->data->{form}{ok_message} }});
# Show the main menu and return.
show_fence_config_main_menu($anvil);
return(0);
}
else
{
# Something went wrong.
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
}
}
# Success is only true if confirm was set and we saved successfully.
if ((not $anvil->data->{cgi}{confirm}{value}) or (not $success))
{
my $header_columns = $anvil->Template->get({file => "anvil.html", name => "fence-agent-column", variables => {
class => "column_header",
value => "&nbsp;",
}});
foreach my $i (1..$anvil->data->{cgi}{fence_count}{value})
{
# We stash the fence_uuid here as well.
my $fence_uuid_key = "fence_uuid_".$i;
$header_columns .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-column-hidden-value", variables => {
class => "column_header",
say_value => $anvil->Words->string({key => "striker_0220", variables => { number => $i }}),
name => $fence_uuid_key,
value => $anvil->data->{cgi}{$fence_uuid_key}{value},
}});
}
my $confirm_table = $anvil->Template->get({file => "anvil.html", name => "fence-agent-row", variables => {
columns => $header_columns,
}});
# Make sure 'fence_name' is always at the top.
my $fence_name_seen = 0;
foreach my $name ("fence_name", sort {$a cmp $b} keys %{$anvil->data->{fence}{confirm_table}{data}})
{
if ($name eq "fence_name")
{
next if $fence_name_seen;
$fence_name_seen = 1;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { name => $name }});
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 $say_value = $anvil->data->{fence}{confirm_table}{data}{$name}{$i}{say_value};
$say_value =~ s/"/&quot;/g;
my $value = $anvil->data->{fence}{confirm_table}{data}{$name}{$i}{value};
$value =~ s/"/&quot;/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:name' => $name,
's2:i' => $i,
's3:is_default' => $is_default,
's4:value' => $value,
's5:say_value' => $say_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,
say_value => $say_value,
}});
}
$confirm_table .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-row", variables => {
columns => $entry_row,
}});
}
# Are we asking the user to confirm one or more?
my $confirm_string = $anvil->data->{cgi}{fence_count}{value} == 1 ? "#!string!striker_0222!#" : "#!string!striker_0221!#";
$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},
confirm_string => $confirm_string,
}});
$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->{fence_data}{$fence_agent}{description});
# We add in 'name'
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{unique} = "0";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{required} = "0";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{description} = "#!string!striker_0223!#";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{content_type} = "string";
$anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{'default'} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"fence_data::${fence_agent}::parameters::fence_name::unique" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{unique},
"fence_data::${fence_agent}::parameters::fence_name::required" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{required},
"fence_data::${fence_agent}::parameters::fence_name::description" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{description},
"fence_data::${fence_agent}::parameters::fence_name::content_type" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{content_type},
"fence_data::${fence_agent}::parameters::fence_name::default" => $anvil->data->{fence_data}{$fence_agent}{parameters}{fence_name}{'default'},
}});
# Walk through the list of options
my $option_form = "";
foreach my $i (1..$anvil->data->{cgi}{fence_count}{value})
{
my $say_device = $anvil->Words->string({key => "striker_0216", variables => { number => $i }});
my $device_options = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
i => $i,
say_device => $say_device,
}});
# If we have a fence_uuid_X, read in the details.
my $fence_uuid_key = "fence_uuid_".$i;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { fence_uuid_key => $fence_uuid_key }});
if ((exists $anvil->data->{cgi}{$fence_uuid_key}) && ($anvil->data->{cgi}{$fence_uuid_key}{value}))
{
$anvil->Database->get_fences({debug => 2});
my $fence_uuid = $anvil->data->{cgi}{$fence_uuid_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { fence_uuid => $fence_uuid }});
if (exists $anvil->data->{fences}{fence_uuid}{$fence_uuid})
{
my $old_fence_name = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_name};
my $old_fence_agent = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_agent};
my $old_fence_arguments = $anvil->data->{fences}{fence_uuid}{$fence_uuid}{fence_arguments};
my $fence_name_key = "fence_name_".$i;
my $fence_agent_key = "fence_agent_".$i;
my $fence_arguments_key = "fence_arguments_".$i;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
old_fence_name => $old_fence_name,
old_fence_agent => $old_fence_agent,
old_fence_arguments => $old_fence_arguments,
fence_name_key => $fence_name_key,
fence_agent_key => $fence_agent_key,
fence_arguments_key => $fence_arguments_key,
}});
# Make sure we don't get any undefined warnings
if ((not exists $anvil->data->{cgi}{$fence_name_key}) or (not defined $anvil->data->{cgi}{$fence_name_key}{value}))
{
$anvil->data->{cgi}{$fence_name_key}{value} = "";
}
if ((not exists $anvil->data->{cgi}{$fence_agent_key}) or (not defined $anvil->data->{cgi}{$fence_agent_key}{value}))
{
$anvil->data->{cgi}{$fence_agent_key}{value} = "";
}
# For arguments, we need to break up the arguments string, append the integer to the variable, and see if that CGI is set yet.
$old_fence_arguments =~ s/="(.*?)" /="$1",/;
foreach my $pair (split/,/, $old_fence_arguments)
{
$pair =~ s/^\s+//; $pair =~ s/\s+$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { pair => $pair }});
my ($variable, $value) = ($pair =~ /^(.*?)="(.*)"$/);
my $cgi_key = $variable."_".$i;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:variable' => $variable,
's2:value' => $variable =~ /passw=/ ? $anvil->Log->is_secure($value) : $value,
's3:cgi_key' => $cgi_key,
}});
if ((not defined $anvil->data->{cgi}{$cgi_key}{value}) or ($anvil->data->{cgi}{$cgi_key}{value} eq ""))
{
$anvil->data->{cgi}{$cgi_key}{value} = $value;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${cgi_key}::value" => $anvil->data->{cgi}{$cgi_key}{value},
}});
}
# Now if we don't have a value in CGI but do from the database, set the CGI.
if ((not $anvil->data->{cgi}{$fence_name_key}{value}) && ($old_fence_name))
{
$anvil->data->{cgi}{$fence_name_key}{value} = $old_fence_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${fence_name_key}::value" => $anvil->data->{cgi}{$fence_name_key}{value},
}});
}
if ((not $anvil->data->{cgi}{$fence_agent_key}{value}) && ($old_fence_agent))
{
$anvil->data->{cgi}{$fence_agent_key}{value} = $old_fence_agent;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${fence_agent_key}::value" => $anvil->data->{cgi}{$fence_agent_key}{value},
}});
}
if ((not $anvil->data->{cgi}{$fence_arguments_key}{value}) && ($old_fence_arguments))
{
$anvil->data->{cgi}{$fence_arguments_key}{value} = $old_fence_arguments;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::${fence_arguments_key}::value" => $anvil->data->{cgi}{$fence_arguments_key}{value},
}});
}
}
}
my $fence_name_seen = 0;
foreach my $name ("fence_name", sort {$a cmp $b} keys %{$anvil->data->{fence_data}{$fence_agent}{parameters}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
fence_agent => $fence_agent,
name => $name,
}});
# We don't show deprecated or replaced options.
next if $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{replacement};
next if $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{deprecated};
next if (($fence_name_seen) && ($name eq "fence_name"));
# If this is the 'fence_name', it's artificial so pump in some data
if ($name eq "fence_name")
{
$fence_name_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { fence_name_seen => $fence_name_seen }});
}
my $option_key = $name."_".$i;
my $unique = $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{unique};
my $required = $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{required};
my $description = $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{description};
my $type = $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type};
my $default = exists $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'} ? $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'} : "";
$default =~ s/"/&quot;/g;
$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."::alert" => $anvil->data->{cgi}{$option_key}{alert},
"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")
{
# Build the select box
my $options = [];
foreach my $option (sort {$a cmp $b} @{$anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{options}})
{
push @{$options}, $option;
}
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 }});
}
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 }});
}
}
$option_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-option-menu", variables => {
device_name => $say_device,
device_options => $device_options,
fence_uuid_key => $fence_uuid_key,
fence_uuid => defined $anvil->data->{cgi}{$fence_uuid_key}{value} ? $anvil->data->{cgi}{$fence_uuid_key}{value} : "",
}});
}
$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
{
# Show the main menu
show_fence_config_main_menu($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})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { i => $i }});
# Make sure there is a fence name.
my $fence_name_key = "fence_name_".$i;
if (not $anvil->data->{cgi}{$fence_name_key}{value})
{
$sane = 0;
$anvil->data->{cgi}{$fence_name_key}{alert} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cgi::${fence_name_key}::alert" => $anvil->data->{cgi}{$fence_name_key}{alert},
sane => $sane,
}});
}
else
{
# It's good, add it manually to the hash.
$anvil->data->{fence}{confirm_table}{data}{fence_name}{$i}{'default'} = 0;
$anvil->data->{fence}{confirm_table}{data}{fence_name}{$i}{value} = $anvil->data->{cgi}{$fence_name_key}{value};
$anvil->data->{fence}{confirm_table}{data}{fence_name}{$i}{say_value} = $anvil->data->{cgi}{$fence_name_key}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"fence::confirm_table::data::fence_name::${i}::default" => $anvil->data->{fence}{confirm_table}{data}{fence_name}{$i}{'default'},
"fence::confirm_table::data::fence_name::${i}::value" => $anvil->data->{fence}{confirm_table}{data}{fence_name}{$i}{value},
"fence::confirm_table::data::fence_name::${i}::say_value" => $anvil->data->{fence}{confirm_table}{data}{fence_name}{$i}{say_value},
}});
}
# Read in the parameters for this agent, and compare to see if the value passed in differs.
foreach my $name (sort {$a cmp $b} keys %{$anvil->data->{fence_data}{$fence_agent}{parameters}})
{
# We don't show deprecated or replaced options.
next if $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{replacement};
next if $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{deprecated};
my $option_key = $name."_".$i;
my $unique = $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{unique};
my $required = $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{required};
my $description = $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{description};
my $type = $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{content_type};
my $default = exists $anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{'default'} ? $anvil->data->{fence_data}{$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 => 3, 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 => 3, 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 => 3, list => { say_value => $say_value }});
}
# We always store the action, then anything else that isn't default.
if (($passed_value ne $default) or ($name eq "action"))
{
# 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 => 3, list => {
"cgi::${passed_parameter_key}::alert" => $anvil->data->{cgi}{$passed_parameter_key}{alert},
sane => $sane,
}});
}
}
# This will be used to assemble the base shell call later
$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} = $passed_value ? $passed_value : $default;
$anvil->data->{fence}{confirm_table}{data}{$name}{$i}{say_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},
"fence::confirm_table::data::${name}::${i}::say_value" => $anvil->data->{fence}{confirm_table}{data}{$name}{$i}{say_value},
}});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { sane => $sane }});
return($sane);
}
sub show_fence_config_main_menu
{
my ($anvil) = @_;
# Read in known fence devices
$anvil->Database->get_fences({debug => 3});
# Get a list of current fence agents.
my $existing_fences = "";
if (exists $anvil->data->{fences}{fence_uuid})
{
# How many do we have?
my $fence_count = keys %{$anvil->data->{fences}{fence_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { fence_count => $fence_count }});
if ($fence_count)
{
# We've got devices.
my $fence_devices = "";
foreach my $fence_name (sort {$a cmp $b} keys %{$anvil->data->{fences}{fence_name}})
{
my $fence_uuid = $anvil->data->{fences}{fence_name}{$fence_name}{fence_uuid};
my $fence_agent = $anvil->data->{fences}{fence_name}{$fence_name}{fence_agent};
my $fence_arguments = $anvil->data->{fences}{fence_name}{$fence_name}{fence_arguments};
my $say_fence_device = $fence_agent." ".$fence_arguments;
$say_fence_device =~ s/passw(\w+)="(.*?)"/passw$1="--"/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
fence_uuid => $fence_uuid,
fence_agent => $fence_agent,
fence_arguments => $fence_arguments =~ /passw=/ ? $anvil->Log->is_secure($fence_arguments) : $fence_arguments,
say_fence_device => $say_fence_device,
}});
$fence_devices .= $anvil->Template->get({file => "anvil.html", name => "existing-fence-device-entry", variables => {
name => $fence_name,
arguments => $say_fence_device,
fence_agent => $fence_agent,
fence_uuid => $fence_uuid,
}});
}
$existing_fences .= $anvil->Template->get({file => "anvil.html", name => "existing-fence-devices", variables => {
devices => $fence_devices,
}});
}
}
# 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->{fence_data}})
{
# We don't care about IPMI-based fence agents here.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { fence_agent => $fence_agent }});
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->{fence_data}{$fence_agent}{description});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { agent_description => $agent_description }});
$description_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-description", variables => {
name => $fence_agent,
description => $agent_description,
}});
}
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}{refresh_link} = "?anvil=true&task=fences";
$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_devices => $existing_fences,
}});
$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)
{
$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
{
if ($in_pre)
{
$line =~ s/<br \/>//g;
}
$new_desctiption .= $line."\n";
}
}
$agent_description = $new_desctiption;
}
return($agent_description);
}
# 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.
my $message = $anvil->Words->string({key => "warning_0014", variables => { host_uuid => $anvil->data->{cgi}{host_uuid}{value} } });
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $message }});
$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->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->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->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->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->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->is_ip_in_network({
network => $anvil->data->{cgi}{$ip_key}{value},
subnet_mask => $anvil->data->{cgi}{$subnet_key}{value},
ip => $anvil->data->{cgi}{gateway}{value},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { match => $match }});
if ($match)
{
# Found the match!
if ($anvil->data->{cgi}{$ip_key}{value})
{
$say_ip_address .= ",<br /> &nbsp; #!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 /> &nbsp; #!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'}.$anvil->Log->switches,
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'}.$anvil->Log->switches;
* 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->ipv4({ip => $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
{
# 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 the user 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->Get->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}.$anvil->Log->switches,
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".$anvil->Log->switches;
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".$anvil->Log->switches;
$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'}.$anvil->Log->switches,
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 = "";
my $local_host = $anvil->Get->short_host_name();
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}})
{
next if (($interface !~ /^bcn/) && ($interface !~ /^ifn/));
next if not $anvil->Validate->ipv4({ip => $anvil->data->{network}{$local_host}{interface}{$interface}{ip}});
next if not $anvil->Validate->subnet_mask({subnet_mask => $anvil->data->{network}{$local_host}{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_host}{interface}{$interface}{ip}.":".$database_port;
if (($database_port eq "5432") && ($database_user eq "admin"))
{
$access_string = $anvil->data->{network}{$local_host}{interface}{$interface}{ip};
}
elsif ($database_port eq "5432")
{
$access_string = $database_user."\@".$anvil->data->{network}{$local_host}{interface}{$interface}{ip};
}
elsif ($database_user eq "admin")
{
$access_string = $anvil->data->{network}{$local_host}{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->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_from_uuid({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.$anvil->Log->switches,
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->domain_name({name => $host});
my $is_ipv4 = $anvil->Validate->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->switches;
$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.$anvil->Log->switches;
$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 => 2, list => { sane => $sane }});
if ($sane)
{
# We're mapping, so tell anvil-daemon to
$anvil->Database->insert_or_update_variables({
debug => 2,
variable_name => "config::map_network",
variable_value => 1,
variable_default => 0,
variable_description => "striker_0202",
variable_section => "config",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
# 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 => 2, list => { sane => $sane }});
if ($sane)
{
# Also, we're done mapping
$anvil->Database->insert_or_update_variables({
debug => 2,
variable_name => "config::map_network",
variable_value => 0,
variable_default => 0,
variable_description => "striker_0202",
variable_section => "config",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
# 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'}.$anvil->Log->switches,
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->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->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->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->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({debug => 2});
$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'}.$anvil->Log->switches});
# 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...
local $@;
my $xml = XML::Simple->new();
my $data = "";
my $network = "";
my $test = eval { $data = $xml->XMLin($file, KeyAttr => { interface => 'name', key => 'name', ip => 'address' }, ForceArray => [ 'interface', 'key' ] ) };
if (not $test)
{
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 }});
local $@;
my $xml = XML::Simple->new();
my $data = "";
my $network = "";
my $test = eval { $data = $xml->XMLin($file, KeyAttr => { interface => 'name', key => 'name' }, ForceArray => [ 'interface', 'key' ]) };
if (not $test)
{
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->ipv4({ip => $default_ip})) && ($anvil->Validate->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);
}