#!/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!#" : " ",
}});
# Display the page.
my $say_center_top_bar = " ";
if ($anvil->data->{form}{error_massage})
{
$say_center_top_bar = $anvil->data->{form}{error_massage};
}
elsif ($anvil->data->{form}{ok_message})
{
$say_center_top_bar = $anvil->data->{form}{ok_message};
}
my $body = $anvil->Template->get({file => "main.html", name => "master", variables => {
header => $header,
skin_url => $anvil->data->{path}{urls}{skins}."/".$anvil->Template->skin,
center_top_bar => $say_center_top_bar,
right_top_bar => $right_buttons,
left_top_bar => $left_buttons,
center_body => $anvil->data->{form}{body},
left_bottom_bar => " ",
center_bottom_bar => " ",
right_bottom_bar => " ",
footer => $footer,
}});
print $anvil->Template->get({file => "shared.html", name => "http_headers"})."\n";
print "$body";
$anvil->nice_exit({exit_code => 0});
return(0);
}
# This handles all the daily tasks of Striker.
sub process_task
{
my ($anvil) = @_;
# Is the user trying to log in?
my $logged_in = 0;
$anvil->data->{cgi}{login}{value} = "" if not defined $anvil->data->{cgi}{login}{value};
$anvil->data->{cgi}{logout}{value} = "" if not defined $anvil->data->{cgi}{logout}{value};
$anvil->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"cgi::login::value" => $anvil->data->{cgi}{login}{value},
"cgi::logout::value" => $anvil->data->{cgi}{logout}{value},
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
}});
if ($anvil->data->{cgi}{login}{value})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::login::value" => $anvil->data->{cgi}{login}{value} }});
# Woot!
my $failed = $anvil->Account->login({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }});
if (not $failed)
{
$logged_in = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { logged_in => $logged_in }});
}
}
elsif ($anvil->data->{cgi}{logout}{value})
{
# Bye now!
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::logout::value" => $anvil->data->{cgi}{logout}{value} }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0215"});
$anvil->Account->logout({debug => 2});
}
else
{
# Is the user logged in?
# 0 - The cookies were read, the account was validated and the user's details were loaded.
# 1 - No cookie was found or read. The user needs to log in
# 2 - There was a problem reading the user's UUID (it wasn't found in the database), so the
# cookies were deleted (via C<< Account->logout() >>. The user needs to log back in.
# 3 - There user's hash is invalid, it is probably expired. The user has been logged out and
# needs to log back in.
my $cookie_problem = $anvil->Account->read_cookies();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { cookie_problem => $cookie_problem }});
if (not $cookie_problem)
{
$logged_in = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { logged_in => $logged_in }});
}
}
# Show the login screen, if the user isn't logged in.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { logged_in => $logged_in }});
if (not $logged_in)
{
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "striker-login", variables => {
user => $anvil->data->{cgi}{username}{value},
password => "",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
return(0);
}
# If we're here, the user is logged in!
if ($anvil->data->{cgi}{striker}{value})
{
process_striker_menu($anvil);
}
elsif ($anvil->data->{cgi}{anvil}{value})
{
process_anvil_menu($anvil);
}
elsif ($anvil->data->{cgi}{files}{value})
{
process_file_menu($anvil);
}
elsif ($anvil->data->{cgi}{jobs}{value})
{
process_jobs_menu($anvil);
}
elsif ($anvil->data->{cgi}{email}{value})
{
process_email_menu($anvil);
}
else
{
# Load the main page.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "striker-welcome"});
}
# $anvil->data->{sys}{users}{user_name} = $user_name;
# $anvil->data->{sys}{users}{user_uuid} = $user_uuid;
# $anvil->data->{sys}{users}{user_password_hash} = $user_password_hash,
# $anvil->data->{sys}{users}{user_salt} = $user_salt,
# $anvil->data->{sys}{users}{user_algorithm} = $user_algorithm,
# $anvil->data->{sys}{users}{user_hash_count} = $user_hash_count,
# $anvil->data->{sys}{users}{user_language} = $user_language,
# $anvil->data->{sys}{users}{user_is_admin} = $user_is_admin,
# $anvil->data->{sys}{users}{user_is_experienced} = $user_is_experienced,
# $anvil->data->{sys}{users}{user_is_trusted} = $user_is_trusted,
return(0);
}
# This handles tasks related to email, mail servers and alert recipients.
sub process_email_menu
{
my ($anvil) = @_;
$anvil->data->{form}{back_link} = "?email=true";
$anvil->data->{cgi}{task}{value} = "" if not defined $anvil->data->{cgi}{task}{value};
$anvil->data->{cgi}{action}{value} = "" if not defined $anvil->data->{cgi}{action}{value};
$anvil->data->{cgi}{save}{value} = "" if not defined $anvil->data->{cgi}{save}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::back_link" => $anvil->data->{form}{back_link},
"cgi::task::value" => $anvil->data->{cgi}{task}{value},
"cgi::action::value" => $anvil->data->{cgi}{action}{value},
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
}});
if ($anvil->data->{cgi}{task}{value} eq "email_server")
{
process_email_server_page($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "email_recipient")
{
process_email_recipient_page($anvil);
}
else
{
# What we show for the reboot icon and text depends on if a reboot is pending.
my $reboot_needed = $anvil->System->reboot_needed();
my $reboot_icon = $reboot_needed ? "reboot_needed_icon.png" : "reboot_icon.png";
my $reboot_message = $reboot_needed ? "#!string!striker_0093!#" : "#!string!striker_0092!#";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
reboot_needed => $reboot_needed,
reboot_icon => $reboot_icon,
reboot_message => $reboot_message,
}});
# The 'back' goes home
$anvil->data->{form}{back_link} = "?";
$anvil->data->{form}{refresh_link} = "?email=true";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "main-menu", variables => {
}});
}
return(0);
}
# This processes mail recipients.
sub process_email_recipient_page
{
my ($anvil) = @_;
my $recipient_uuid = defined $anvil->data->{cgi}{recipient_uuid}{value} ? $anvil->data->{cgi}{recipient_uuid}{value} : "";
my $recipient_name = defined $anvil->data->{cgi}{recipient_name}{value} ? $anvil->data->{cgi}{recipient_name}{value} : "";
my $recipient_email = defined $anvil->data->{cgi}{recipient_email}{value} ? $anvil->data->{cgi}{recipient_email}{value} : "";
my $recipient_language = defined $anvil->data->{cgi}{recipient_language}{value} ? $anvil->data->{cgi}{recipient_language}{value} : "en_CA";
my $recipient_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 OK.
my $show_list = 1;
$anvil->data->{cgi}{'delete'}{value} = "" if not defined $anvil->data->{cgi}{'delete'}{value};
if ($anvil->data->{cgi}{'delete'}{value})
{
# Record the job!
my $job_data = "";
foreach my $key (sort {$a cmp $b} keys %{$anvil->data->{cgi}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { key => $key }});
if ($key =~ /^state_uuid_(.*)$/)
{
my $state_uuid = $1;
$show_list = 0;
$job_data .= $state_uuid.",";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
state_uuid => $state_uuid,
show_list => $show_list,
job_data => $job_data,
}});
}
}
$job_data =~ s/,$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_data => $job_data }});
if ($job_data)
{
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-manage-keys'}.$anvil->Log->switches,
job_data => $job_data,
job_name => "manage::broken_keys",
job_title => "job_0056",
job_description => "job_0057",
job_progress => 0,
job_host_uuid => $anvil->data->{sys}{host_uuid},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
# We don't need to store anything as hidden variables, we'll read it back from the database
# later.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "job recorded", variables => {
title_id => "",
message_id => "",
reload_url => "/cgi-bin/".$THIS_FILE,
title => "#!string!job_0056!#",
description => "#!string!job_0057!#",
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "form::body" => $anvil->data->{form}{body} }});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { show_list => $show_list }});
if ($show_list)
{
# Get a list of bad keys we know about and ask the user which they want to remove
my $query = "
SELECT
a.state_uuid,
b.host_name,
a.state_name,
a.state_note
FROM
states a,
hosts b
WHERE
a.state_host_uuid = b.host_uuid
AND
a.state_name LIKE 'host_key_changed::%'
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
if (not $count)
{
# No bad keys found on this host.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "no-bad-keys"});
}
else
{
# Build a list of check-boxes / bad keys.
my $bad_key_list = "";
foreach my $row (@{$results})
{
my $state_uuid = $row->[0];
my $host_name = $row->[1];
my $state_name = $row->[2];
my $state_note = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
state_uuid => $state_uuid,
host_name => $host_name,
state_name => $state_name,
state_note => $state_note,
}});
my $bad_file = "";
my $bad_line = "";
foreach my $pair (split/,/, $state_note)
{
my ($variable, $value) = ($pair =~ /^(.*?)=(.*)$/);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
pair => $pair,
variable => $variable,
value => $value,
}});
if ($variable eq "file")
{
$bad_file = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_file => $bad_file }});
}
if ($variable eq "line")
{
$bad_line = $value;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bad_line => $bad_line }});
}
}
my ($target) = ($state_name =~ /host_key_changed::(.*)$/);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
target => $target,
bad_file => $bad_file,
bad_line => $bad_line,
}});
my $checkbox_key = "state_uuid_".$state_uuid;
my $checked = "";
if ((exists $anvil->data->{cgi}{$checkbox_key}) && ($anvil->data->{cgi}{$checkbox_key}{value}))
{
$checked = "checked";
}
$bad_key_list .= $anvil->Template->get({file => "striker.html", name => "broken-key-entry", variables => {
checkbox_name => $checkbox_key,
checkbox_checked => $checked,
target => $target,
file => $bad_file,
host => $host_name,
}});
}
#Show the screen the confirm the addition.
$anvil->data->{form}{body} = $anvil->Template->get({file => "striker.html", name => "broken-key-list", variables => {
bad_keys => $bad_key_list,
}});
}
}
return(0);
}
# This 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 = " ";
my $say_purge_confirm = " ";
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);
}
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
elsif ($anvil->data->{cgi}{task}{value} eq "fences")
{
process_fences($anvil);
}
elsif ($anvil->data->{cgi}{task}{value} eq "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);
}
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
# This allows the user to tell us about fence devices.
sub process_fences
{
my ($anvil) = @_;
# Read/process the unified fences metadata.
$anvil->Striker->get_fence_data({debug => 3});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
$anvil->data->{cgi}{fence_agent}{value} = "" if not defined $anvil->data->{cgi}{fence_agent}{value};
$anvil->data->{cgi}{fence_count}{value} = 1 if not defined $anvil->data->{cgi}{fence_count}{value};
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
$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})
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
my $fence_agent = $anvil->data->{cgi}{fence_agent}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { fence_agent => $fence_agent }});
# Are we going back to the form?
if ($anvil->data->{cgi}{back}{value})
{
$anvil->data->{cgi}{save}{value} = "";
$anvil->data->{cgi}{confirm}{value} = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"cgi::save::value" => $anvil->data->{cgi}{save}{value},
"cgi::confirm::value" => $anvil->data->{cgi}{confirm}{value},
}});
}
# Are we saving?
if ($anvil->data->{cgi}{save}{value})
{
# Sanity check
my $sane = sanity_check_fence_agent_form($anvil, $fence_agent);
$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 => " ",
}});
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/"/"/g;
my $value = $anvil->data->{fence}{confirm_table}{data}{$name}{$i}{value};
$value =~ s/"/"/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'},
}});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
# Walk through the list of options
my $option_form = "";
foreach my $i (1..$anvil->data->{cgi}{fence_count}{value})
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
my $say_device = $anvil->Words->string({key => "striker_0216", variables => { number => $i }});
my $device_options = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 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}})
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 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/"/"/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")
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
# Build the select box
my $options = [];
foreach my $option (sort {$a cmp $b} @{$anvil->data->{fence_data}{$fence_agent}{parameters}{$name}{options}})
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
push @{$options}, $option;
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
my $select_options = $anvil->Template->select_form({
name => $option_key,
options => $options,
blank => $required ? 0 : 1,
'sort' => 1,
selected => $anvil->data->{cgi}{$option_key}{value},
class => $anvil->data->{cgi}{$option_key}{alert} ? "input_alert" : "input_clear",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { select_options => $select_options }});
# Build the entry
my $select_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-option-entry", variables => {
name_class => $required ? "say_required" : "",
name => $name,
option => $select_options,
description => $description,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { select_form => $select_form }});
$device_options .= $select_form;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { device_options => $device_options }});
}
elsif ($type eq "boolean")
{
# Build the entry
my $checkbox_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-checkbox-entry", variables => {
name => $name,
name_class => $required ? "say_required" : "",
checkbox_name => $option_key,
checkbox_checked => $anvil->data->{cgi}{$option_key}{value} ? "checked" : "",
description => $description,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { checkbox_form => $checkbox_form }});
$device_options .= $checkbox_form;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { device_options => $device_options }});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
else
{
### String, Second or Integer.
# Build the entry
my $string_options .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-input-entry", variables => {
name => $name,
key => $option_key,
value => $anvil->data->{cgi}{$option_key}{value},
'default' => $default,
name_class => $required ? "say_required" : "",
input_class => $anvil->data->{cgi}{$option_key}{alert} ? "input_alert" : "input_clear",
description => $description,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { string_options => $string_options }});
$device_options .= $string_options;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { device_options => $device_options }});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
}
$option_form .= $anvil->Template->get({file => "anvil.html", name => "fence-agent-option-menu", variables => {
device_name => $say_device,
device_options => $device_options,
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,
}});
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
}
# 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,
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}});
}
my $fence_agent_select = $anvil->Template->select_form({
name => "fence_agent",
options => $agents,
blank => 0,
'sort' => 1,
selected => $anvil->data->{cgi}{fence_agent}{value} ? $anvil->data->{cgi}{fence_agent}{value} : "fence_apc_snmp",
class => "input_clear",
});
my $fence_count_select = $anvil->Template->select_form({
name => "fence_count",
options => [1, 2, 3, 4],
blank => 0,
'sort' => 0,
selected => $anvil->data->{cgi}{fence_count}{value},
class => "input_clear",
});
$anvil->data->{form}{back_link} = "?anvil=true&task=create";
$anvil->data->{form}{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)
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line =~ /\+---/)
{
$line =~ s/<br \/>//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { break_number => $break_number }});
if (not $break_number)
{
$in_pre = 1;
$new_desctiption .= "<pre>\n";
$new_desctiption .= $line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_desctiption => $new_desctiption }});
}
elsif ($break_number == 2)
{
$in_pre = 0;
$new_desctiption .= $line."\n";
$new_desctiption .= "</pre>\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_desctiption => $new_desctiption }});
}
else
{
$new_desctiption .= $line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { new_desctiption => $new_desctiption }});
}
$break_number++;
}
else
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
if ($in_pre)
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
{
$line =~ s/<br \/>//g;
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
$new_desctiption .= $line."\n";
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
}
$agent_description = $new_desctiption;
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
return($agent_description);
* Moved the fences_unified_metadata file from /tmp, which apache can not read, to /var/www/html/.
* Fixed a bug (well, made a work-around for an issue without a known reproducer) where, on some occassion, a record will end up in the public table without being copied into the history schema. When this happens, the next resync would crash out because the resynd reads in the history table only. Now, when about to INSERT a record into the public schema during a resync, an explicit check is made to see if the record alread
y exists. If it does, the INSERT is instead redirected to the history schema.
* Cleaned up the fence agent metadata when displaying to a user, converting the shell codes to underline a string with square brackets instead. We also now replace newlines with <br /> tags. Lastly, to help fence_azure_arm's metadata description to display cleanly, a check is made to format the table correctly.
* Began work on the Striker menu for handling fence device management
Signed-off-by: Digimer <digimer@alteeve.ca>
5 years ago
}
# This handles 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 /> #!string!striker_0026!#: ".$anvil->data->{cgi}{gateway}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_ip_address => $say_ip_address }});
}
# DNS?
if (($anvil->data->{cgi}{dns}{value}) && (not $anvil->data->{cgi}{dns}{alert}) && ($anvil->data->{cgi}{$ip_key}{value}))
{
$say_ip_address .= ",<br /> #!string!striker_0037!#: ".$anvil->data->{cgi}{dns}{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_ip_address => $say_ip_address }});
}
$gateway_interface = $this_network;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { gateway_interface => $gateway_interface }});
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::gateway_interface::value",
variable_value => $gateway_interface,
variable_default => "",
variable_description => "striker_0155",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
}
}
if (not $anvil->data->{cgi}{$ip_key}{value})
{
# Record this as DHCP.
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$ip_key."::value",
variable_value => "dhcp",
variable_default => "",
variable_description => "striker_0160",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
# Last check, are the interfaces defined? All $i == 1 interfaces need to be
# defined. Any 2+ are allowed to be ignored, _IF_ neither link is selected
# AND neither the IP/subnet are blank.
if ((not $anvil->data->{cgi}{$link1_key}{value}) && (not $anvil->data->{cgi}{$link2_key}{value}))
{
# If this is network 1, both are required.
if ($i == 1)
{
# Required.
my $error_message = $anvil->Words->string({key => "warning_0021"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{$link1_key}{value} = 1;
$anvil->data->{cgi}{$link2_key}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${link1_key}::alert" => $anvil->data->{cgi}{$link1_key}{alert},
"cgi::${link2_key}::alert" => $anvil->data->{cgi}{$link2_key}{alert},
}});
}
}
elsif (not $anvil->data->{cgi}{$link1_key}{value})
{
# link 1 is missing.
my $error_message = $anvil->Words->string({key => "warning_0022"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{$link1_key}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${link1_key}::alert" => $anvil->data->{cgi}{$link1_key}{alert},
}});
}
elsif (not $anvil->data->{cgi}{$link2_key}{value})
{
# link 2 is missing.
my $error_message = $anvil->Words->string({key => "warning_0022"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{$link2_key}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${link2_key}::alert" => $anvil->data->{cgi}{$link2_key}{alert},
}});
}
elsif (($anvil->data->{cgi}{$ip_key}{value}) && (not $anvil->data->{cgi}{$link1_key}{value}))
{
# There's an IP address but no interfaces selected.
my $error_message = $anvil->Words->string({key => "warning_0022"});
$anvil->data->{form}{error_massage} = $anvil->Template->get({file => "main.html", name => "error_message", variables => { error_message => $error_message }});
$anvil->data->{cgi}{$link1_key}{value} = 1;
$anvil->data->{cgi}{$link2_key}{value} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"form::error_massage" => $anvil->data->{form}{error_massage},
"cgi::${link1_key}::alert" => $anvil->data->{cgi}{$link1_key}{alert},
"cgi::${link2_key}::alert" => $anvil->data->{cgi}{$link2_key}{alert},
}});
}
# Now save the link info, if selected.
if ($anvil->data->{cgi}{$link1_key}{value})
{
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$link1_key."::value",
variable_value => $anvil->data->{cgi}{$link1_key}{value},
variable_default => "",
variable_description => "striker_0156",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
if ($anvil->data->{cgi}{$link2_key}{value})
{
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$link2_key."::value",
variable_value => $anvil->data->{cgi}{$link2_key}{value},
variable_default => "",
variable_description => "striker_0157",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
}
# Store the bridge key
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_name => "form::config_step2::".$bridge_key."::value",
variable_value => $anvil->data->{cgi}{$bridge_key}{value},
variable_default => "",
variable_description => "striker_0158",
variable_section => "config_step2",
variable_source_uuid => $anvil->data->{cgi}{host_uuid}{value},
variable_source_table => "hosts",
});
$interfaces .= $anvil->Template->get({file => "anvil.html", name => "interface-entry", variables => {
network => $say_network,
primary => $link1_interface." (".$anvil->data->{cgi}{$link1_key}{value}.")",
link1_key => $link1_key,
link1_value => $anvil->data->{cgi}{$link1_key}{value},
secondary => $link2_interface." (".$anvil->data->{cgi}{$link2_key}{value}.")",
link2_key => $link2_key,
link2_value => $anvil->data->{cgi}{$link2_key}{value},
bridge => $say_bridge,
say_ip => $say_ip_address,
ip_key => $ip_key,
ip_address => $anvil->data->{cgi}{$ip_key}{value},
subnet_key => $subnet_key,
subnet_mask => $anvil->data->{cgi}{$subnet_key}{value},
bridge_key => $bridge_key,
bridge_value => $anvil->data->{cgi}{$bridge_key}{value},
}});
}
}
# Did we see an error?
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "form::error_massage" => $anvil->data->{form}{error_massage} }});
if ($anvil->data->{form}{error_massage})
{
# Yup, not sane, send the user back to the form.
$sane = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
}
# Confirmed?
if (($anvil->data->{cgi}{confirm}{value}) && ($sane))
{
# Yes, save the job.
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
debug => 3,
file => $THIS_FILE,
line => __LINE__,
job_host_uuid => $anvil->data->{cgi}{host_uuid}{value},
job_command => $anvil->data->{path}{exe}{'anvil-configure-host'}.$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);
}