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

385 lines
16 KiB

#!/usr/bin/perl
#
use strict;
use warnings;
use AN::Tools;
use Data::Dumper;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
my $an = AN::Tools->new();
# Print the html headers, with a new line to break the header from the body.
print $an->Template->get({file => "shared.html", name => "http_headers"})."\n";
# Set the log level to 2
$an->Log->level({set => 2});
# Read in our words file.
$an->Words->read({file => $an->data->{path}{directories}{'cgi-bin'}."/words.xml"});
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;
# Read in any CGI variables, if needed.
$an->Get->cgi();
$an->data->{skin}{url} = $an->data->{path}{urls}{skins}."/".$an->Template->skin;
my $header = $an->Template->get({file => "main.html", name => "header", variables => { language => $an->Words->language }});
my $body = "";
# This will be true when the dashboard is unconfigured.
if (not $an->data->{cgi}{step}{value})
{
$body = config_step1($an);
}
elsif ($an->data->{cgi}{step}{value} eq "step1")
{
# Sanity check step1.
my $sane = sanity_check_step1($an);
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { sane => $sane }});
if ($sane)
{
# Step 1 was sanem show step 2.
$body = config_step2($an);
}
else
{
# No good
$body = config_step1($an);
}
}
else
{
$body = get_network_details_form($an);
}
my $buttons = $an->Template->get({file => "main.html", name => "button_bar"});
my $footer = $an->Template->get({file => "main.html", name => "footer"});
# Display the page.
my $template = $an->Template->get({file => "main.html", name => "master", variables => {
header => $header,
skin_url => $an->data->{path}{urls}{skins}."/".$an->Template->skin,
left_top_bar => " ",
center_top_bar => " ",
right_top_bar => $buttons,
center_body => $body,
left_bottom_bar => " ",
center_bottom_bar => " ",
right_bottom_bar => " ",
footer => $footer,
}});
print $template;
exit(0);
#############################################################################################################
# Functions #
#############################################################################################################
# This is step2 where the user maps their network.
sub config_step2
{
my ($an) = @_;
# 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($an);
my $required_interfaces_for_single = 1 + $an->data->{cgi}{ifn_count}{value};
my $required_interfaces_for_bonds = 2 * $required_interfaces_for_single;
my $interface_count = keys %{$an->data->{interfaces}};
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
required_interfaces_for_single => $required_interfaces_for_single,
required_interfaces_for_bonds => $required_interfaces_for_bonds,
interface_count => $interface_count,
}});
my $problem = 0;
my $interface_form = "";
if ($interface_count < $required_interfaces_for_single)
{
# Build the error message.
my $say_message = $an->Words->string({key => "striker_error_0001", variables => {
interface_count => $interface_count,
required_interfaces_for_single => $required_interfaces_for_single,
}});
# Not enough interfaces found.
$problem = 1;
$interface_form = $an->Template->get({file => "main.html", name => "error_message", variables => { error_message => $say_message }});
}
elsif ($interface_count >= $required_interfaces_for_bonds)
{
# Show the bonded ifaces form.
}
else
{
# Show the single iface per network form.
}
my $say_default_hostname = $an->data->{cgi}{prefix}{value}."-striker0".$an->data->{cgi}{sequence}{value}.".".$an->data->{cgi}{domain}{value};
my $hostname_class = $an->data->{cgi}{hostname}{alert} ? "input_alert" : "input_clear";
my $say_hostname = $an->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "hostname",
id => "hostname",
field => "#!string!striker_0016!#",
description => "#!string!striker_0017!#",
value => defined $an->data->{cgi}{hostname}{value} ? $an->data->{cgi}{hostname}{value} : $say_default_hostname,
class => $hostname_class,
extra => "",
}});
my $step2_body = $an->Template->get({file => "main.html", name => "config_step2", variables => {
step1_welcome_title_id => "",
step1_welcome_message_id => "",
organization => $an->data->{cgi}{organization}{value},
prefix => $an->data->{cgi}{prefix}{value},
domain => $an->data->{cgi}{domain}{value},
sequence => $an->data->{cgi}{sequence}{value},
ifn_count => $an->data->{cgi}{ifn_count}{value},
interface_form => $interface_form,
hostname_form => $say_hostname,
cgi_list => "hostname",
}});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { step2_body => $step2_body }});
return($step2_body);
}
# This sanity-checks step 1 and returns '1' if there was a problem.
sub sanity_check_step1
{
my ($an) = @_;
# This will flip if we run into a problem.
my $sane = 1;
# Organization just needs *something*
if ((not defined $an->data->{cgi}{organization}{value}) or (not $an->data->{cgi}{organization}{value}))
{
$an->data->{cgi}{organization}{alert} = 1;
$sane = 0;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::organization::alert" => $an->data->{cgi}{organization}{alert} }});
}
# The prefix needs to be alphanumeric and be between 1 ~ 5 chatacters.
if ((not $an->Validate->is_alphanumeric({string => $an->data->{cgi}{prefix}{value}})) or (length($an->data->{cgi}{prefix}{value}) > 5))
{
$an->data->{cgi}{prefix}{alert} = 1;
$sane = 0;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::prefix::alert" => $an->data->{cgi}{prefix}{alert} }});
}
# We can use Validate to check the domain.
if (not $an->Validate->is_domain_name({name => $an->data->{cgi}{domain}{value}}))
{
$an->data->{cgi}{domain}{alert} = 1;
$sane = 0;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::domain::alert" => $an->data->{cgi}{domain}{alert} }});
}
# The sequence and IFN count need to be integers.
if (not $an->Validate->is_positive_integer({number => $an->data->{cgi}{sequence}{value}}))
{
$an->data->{cgi}{sequence}{alert} = 1;
$sane = 0;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::sequence::alert" => $an->data->{cgi}{sequence}{alert} }});
}
if (not $an->Validate->is_positive_integer({number => $an->data->{cgi}{ifn_count}{value}}))
{
$an->data->{cgi}{ifn_count}{alert} = 1;
$sane = 0;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::ifn_count::alert" => $an->data->{cgi}{ifn_count}{alert} }});
}
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { sane => $sane }});
return($sane);
}
# This is step 1 in asking the user how to configure Striker.
sub config_step1
{
my ($an) = @_;
# TODO: Later, this will be a check to see if we've configured this Striker before and, if so, offer
# an option to restore.
my $reload_old_config = "";
if (1)
{
### TODO: ...
# Old config exists. Load the detail and present the option to reload.
}
my $organization_class = $an->data->{cgi}{organization}{alert} ? "input_alert" : "input_clear";
my $say_organization = $an->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "organization",
id => "organization",
field => "#!string!striker_0003!#",
description => "#!string!striker_0004!#",
value => defined $an->data->{cgi}{organization}{value} ? $an->data->{cgi}{organization}{value} : "",
class => $organization_class,
extra => "",
}});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_organization => $say_organization }});
my $prefix_class = $an->data->{cgi}{prefix}{alert} ? "input_alert" : "input_clear";
my $say_prefix = $an->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "prefix",
id => "prefix",
field => "#!string!striker_0005!#",
description => "#!string!striker_0006!#",
value => defined $an->data->{cgi}{prefix}{value} ? $an->data->{cgi}{prefix}{value} : "",
class => $prefix_class,
extra => "maxlength=\"5\"",
}});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_prefix => $say_prefix }});
my $domain_class = $an->data->{cgi}{domain}{alert} ? "input_alert" : "input_clear";
my $say_domain = $an->Template->get({file => "main.html", name => "input_text_form", variables => {
name => "domain",
id => "domain",
field => "#!string!striker_0007!#",
description => "#!string!striker_0008!#",
value => defined $an->data->{cgi}{domain}{value} ? $an->data->{cgi}{domain}{value} : "",
class => $domain_class,
extra => "maxlength=\"255\"",
}});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_domain => $say_domain }});
my $sequence_class = $an->data->{cgi}{sequence}{alert} ? "input_alert" : "input_clear";
my $say_sequence = $an->Template->get({file => "main.html", name => "input_number_form", variables => {
name => "sequence",
id => "sequence",
field => "#!string!striker_0009!#",
description => "#!string!striker_0010!#",
value => defined $an->data->{cgi}{sequence}{value} ? $an->data->{cgi}{sequence}{value} : "",
class => $sequence_class,
extra => "maxlength=\"2\"",
}});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_domain => $say_domain }});
my $ifn_count_class = $an->data->{cgi}{ifn_count}{alert} ? "input_alert" : "input_clear";
my $say_ifn_count = $an->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 $an->data->{cgi}{ifn_count}{value} ? $an->data->{cgi}{ifn_count}{value} : "",
class => $ifn_count_class,
extra => "maxlength=\"2\"",
}});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_ifn_count => $say_ifn_count }});
my $step1_body = $an->Template->get({file => "main.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,
cgi_list => "organization,prefix,domain,sequence,ifn_count",
}});
$an->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 $an->data->{network}{{...}.
sub get_network_details
{
my ($an) = @_;
### TODO: Daemonize this or solve selinux issues
### Refresh the network.xml
#$an->System->call({shell_call => $an->data->{path}{exe}{'scancore-update-states'}});
# Now read the network.xml
my $file = $an->data->{path}{directories}{html}."/status/network.xml";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $file }});
# Parse...
my $xml = XML::Simple->new();
my $data = "";
my $network = "";
eval { $data = $xml->XMLin($file, KeyAttr => { interface => 'name', key => 'name' }, ForceArray => [ 'interface', 'key' ]) };
if ($@)
{
chomp $@;
my $error = "[ Error ] - The was a problem reading: [$file]. The error was:\n";
$error .= "===========================================================\n";
$error .= $@."\n";
$error .= "===========================================================\n";
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", raw => $error});
}
else
{
foreach my $interface (sort {$a cmp $b} keys %{$data->{interface}})
{
$an->data->{interfaces}{$interface} = {
mac => $data->{interface}{$interface}{mac},
speed => $data->{interface}{$interface}{speed},
'link' => $data->{interface}{$interface}{'link'}
};
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"interfaces::${interface}::mac" => $an->data->{interfaces}{$interface}{mac},
"interfaces::${interface}::speed" => $an->data->{interfaces}{$interface}{speed},
"interfaces::${interface}::link" => $an->data->{interfaces}{$interface}{'link'},
}});
}
}
return(0);
}
sub get_network_details_form
{
my ($an) = @_;
my $file = $an->data->{path}{directories}{html}."/status/network.xml";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $file }});
my $xml = XML::Simple->new();
my $data = "";
my $network = "";
eval { $data = $xml->XMLin($file, KeyAttr => { interface => 'name', key => 'name' }, ForceArray => [ 'interface', 'key' ]) };
if ($@)
{
chomp $@;
my $error = "[ Error ] - The was a problem reading: [$file]. The error was:\n";
$error .= "===========================================================\n";
$error .= $@."\n";
$error .= "===========================================================\n";
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", raw => $error});
}
else
{
my $interface_list = "";
$network = $an->Template->get({file => "main.html", name => "network_header"});
foreach my $interface (sort {$a cmp $b} keys %{$data->{interface}})
{
$interface_list .= "$interface,";
$network .= $an->Template->get({file => "main.html", name => "network_entry", variables => {
#mac => $data->{interface}{$interface}{mac},
mac => "",
mac_id => $interface."_mac",
name => $interface,
name_id => $interface."_name",
#speed => $data->{interface}{$interface}{speed},
speed => "",
speed_id => $interface."_speed",
#'link' => $data->{interface}{$interface}{'link'},
'link' => "",
link_id => $interface."_link",
}});
}
$interface_list =~ s/,$//;
$network .= $an->Template->get({file => "main.html", name => "network_footer", variables => { interface_list => $interface_list }});
}
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network => $network }});
return($network);
}