#!/usr/bin/perl # # Exit codes; # 0 == OK # 1 == Host UUID not available yet. # 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. Setting 3 slows he program down a LOT. $an->Log->level({set => 2}); # Read in our words file. $an->Words->read({file => $an->data->{path}{directories}{'cgi-bin'}."/words.xml"}); # Read the config and then connect to the database. $an->Storage->read_config({file => "/etc/striker/striker.conf"}); # Make sure I can read the host UUID. if (not $an->Get->host_uuid) { # Too early, exit. print $an->Words->string({key => "striker_error_0002"}); $an->nice_exit({exit_code => 1}); } my $connections = $an->Database->connect({ sql_file => $an->data->{sys}{database}{schema}, test_table => "network_interfaces", }); $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0132", variables => { connections => $connections }}); if (not $connections) { # No databases, exit. print $an->Words->string({key => "striker_error_0003"}); $an->nice_exit({exit_code => 2}); } # Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. $| = 1; ### Setup some variables. $an->data->{form}{error_massage} = " "; ## Network stuff... The second octet auto-increments to handle N-number of netowrks. As such, we need to use ## a wider spread between the BCNs, SNs and IFNs than we had in v2. # BCN starts at 10.(0+n)/16 $an->data->{'default'}{bcn}{subnet} = "10.0.0.0"; $an->data->{'default'}{bcn}{netmask} = "255.255.0.0"; $an->data->{'default'}{bcn}{pdu_octet3} = "1"; $an->data->{'default'}{bcn}{ups_octet3} = "2"; $an->data->{'default'}{bcn}{switch_octet3} = "3"; $an->data->{'default'}{bcn}{striker_octet3} = "4"; # SN starts at 10.(40+n)/16 $an->data->{'default'}{sn}{subnet} = "10.40.0.0"; $an->data->{'default'}{sn}{netmask} = "255.255.0.0"; # IFN starts at 10.(80+)/16 $an->data->{'default'}{ifn}{subnet} = "10.80.0.0"; $an->data->{'default'}{ifn}{netmask} = "255.255.0.0"; # 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); } } elsif ($an->data->{cgi}{step}{value} eq "step2") { # Sanity check step1. my $sane = sanity_check_step2($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_step3($an); } else { # No good $body = config_step2($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 => $an->data->{form}{error_massage}, right_top_bar => $buttons, center_body => $body, left_bottom_bar => " ", center_bottom_bar => " ", right_bottom_bar => " ", footer => $footer, }}); print $template; $an->nice_exit({exit_code => 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 $interface_options = []; foreach my $interface (sort {$a cmp $b} keys %{$an->data->{interfaces}}) { my $this_mac = $an->data->{interfaces}{$interface}{mac}; push @{$interface_options}, $this_mac."#!#".$this_mac." (".$interface.")"; } 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 = $an->data->{cgi}{bcn_count}{value} ? $an->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_key = "bcn".$bcn."_subnet"; my $this_iface1_key = "bcn".$bcn."_iface1_mac"; my $this_iface2_key = "bcn".$bcn."_iface2_mac"; $cgi .= $this_ip_key.",".$this_subnet_key.",".$this_iface1_key.",".$this_iface2_key.","; my $this_ip = generate_ip($an, "bcn", $bcn, $an->data->{cgi}{sequence}{value}); my $this_ip_class = $an->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear"; my $this_subnet_class = $an->data->{cgi}{$this_subnet_key}{alert} ? "input_alert" : "input_clear"; my $this_iface1_class = $an->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear"; my $this_iface2_class = $an->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear"; # Build the interface select boxes... my $this_iface1_form = $an->Template->select_form({ name => $this_iface1_key, options => $interface_options, blank => 1, selected => defined $an->data->{cgi}{$this_iface1_key}{value} ? $an->data->{cgi}{$this_iface1_key}{value} : "", class => $an->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear", }); my $this_iface2_form = $an->Template->select_form({ name => $this_iface2_key, options => $interface_options, blank => 1, selected => defined $an->data->{cgi}{$this_iface2_key}{value} ? $an->data->{cgi}{$this_iface2_key}{value} : "", class => $an->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear", }); # Assemble the form $interface_form .= $an->Template->get({file => "main.html", name => "bonded_interface_form", variables => { field => $an->Words->string({key => "striker_0018", variables => { number => $bcn }}), description => "#!string!striker_0019!#", ip_key => $this_ip_key, ip_value => defined $an->data->{cgi}{$this_ip_key}{value} ? $an->data->{cgi}{$this_ip_key}{value} : $this_ip, ip_class => $this_ip_class, subnet_key => $this_subnet_key, subnet_value => defined $an->data->{cgi}{$this_subnet_key}{value} ? $an->data->{cgi}{$this_subnet_key}{value} : $an->data->{'default'}{bcn}{netmask}, subnet_class => $this_subnet_class, iface1_select => $this_iface1_form, iface2_select => $this_iface2_form, }}); } # IFN my $ifn_count = $an->data->{cgi}{ifn_count}{value} ? $an->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_key = "ifn".$ifn."_subnet"; my $this_iface1_key = "ifn".$ifn."_iface1_mac"; my $this_iface2_key = "ifn".$ifn."_iface2_mac"; $cgi .= $this_ip_key.",".$this_subnet_key.",".$this_iface1_key.",".$this_iface2_key.","; my $this_ip = generate_ip($an, "ifn", $ifn, $an->data->{cgi}{sequence}{value}); my $this_ip_class = $an->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear"; my $this_subnet_class = $an->data->{cgi}{$this_subnet_key}{alert} ? "input_alert" : "input_clear"; my $this_iface1_class = $an->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear"; my $this_iface2_class = $an->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear"; # Build the interface select boxes... my $this_iface1_form = $an->Template->select_form({ name => $this_iface1_key, options => $interface_options, blank => 1, selected => defined $an->data->{cgi}{$this_iface1_key}{value} ? $an->data->{cgi}{$this_iface1_key}{value} : "", class => $an->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear", }); my $this_iface2_form = $an->Template->select_form({ name => $this_iface2_key, options => $interface_options, blank => 1, selected => defined $an->data->{cgi}{$this_iface2_key}{value} ? $an->data->{cgi}{$this_iface2_key}{value} : "", class => $an->data->{cgi}{$this_iface2_key}{alert} ? "input_alert" : "input_clear", }); # Assemble the form $interface_form .= $an->Template->get({file => "main.html", name => "bonded_interface_form", variables => { field => $an->Words->string({key => "striker_0022", variables => { number => $ifn }}), description => "#!string!striker_0023!#", ip_key => $this_ip_key, ip_value => defined $an->data->{cgi}{$this_ip_key}{value} ? $an->data->{cgi}{$this_ip_key}{value} : $this_ip, ip_class => $this_ip_class, subnet_key => $this_subnet_key, subnet_value => defined $an->data->{cgi}{$this_subnet_key}{value} ? $an->data->{cgi}{$this_subnet_key}{value} : $an->data->{'default'}{ifn}{netmask}, subnet_class => $this_subnet_class, iface1_select => $this_iface1_form, iface2_select => $this_iface2_form, }}); } } else { ### Show the single iface per network form. # BCN my $bcn_count = $an->data->{cgi}{bcn_count}{value} ? $an->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_key = "bcn".$bcn."_subnet"; my $this_iface1_key = "bcn".$bcn."_iface1_mac"; $cgi .= $this_ip_key.",".$this_subnet_key.",".$this_iface1_key.","; my $this_ip = generate_ip($an, "bcn", $bcn, $an->data->{cgi}{sequence}{value}); my $this_ip_class = $an->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear"; my $this_subnet_class = $an->data->{cgi}{$this_subnet_key}{alert} ? "input_alert" : "input_clear"; my $this_iface1_class = $an->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear"; # Build the interface select boxes... my $this_iface1_form = $an->Template->select_form({ name => $this_iface1_key, options => $interface_options, blank => 1, selected => defined $an->data->{cgi}{$this_iface1_key}{value} ? $an->data->{cgi}{$this_iface1_key}{value} : "", class => $an->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear", }); # Assemble the form $interface_form .= $an->Template->get({file => "main.html", name => "single_interface_form", variables => { field => $an->Words->string({key => "striker_0018", variables => { number => $bcn }}), description => "#!string!striker_0019!#", ip_key => $this_ip_key, ip_value => defined $an->data->{cgi}{$this_ip_key}{value} ? $an->data->{cgi}{$this_ip_key}{value} : $this_ip, ip_class => $this_ip_class, subnet_key => $this_subnet_key, subnet_value => defined $an->data->{cgi}{$this_subnet_key}{value} ? $an->data->{cgi}{$this_subnet_key}{value} : $an->data->{'default'}{bcn}{netmask}, subnet_class => $this_subnet_class, iface1_select => $this_iface1_form, }}); } # IFN my $ifn_count = $an->data->{cgi}{ifn_count}{value} ? $an->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_key = "ifn".$ifn."_subnet"; my $this_iface1_key = "ifn".$ifn."_iface1_mac"; $cgi .= $this_ip_key.",".$this_subnet_key.",".$this_iface1_key.","; my $this_ip = generate_ip($an, "ifn", $ifn, $an->data->{cgi}{sequence}{value}); my $this_ip_class = $an->data->{cgi}{$this_ip_key}{alert} ? "input_alert" : "input_clear"; my $this_subnet_class = $an->data->{cgi}{$this_subnet_key}{alert} ? "input_alert" : "input_clear"; my $this_iface1_class = $an->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear"; # Build the interface select boxes... my $this_iface1_form = $an->Template->select_form({ name => $this_iface1_key, options => $interface_options, blank => 1, selected => defined $an->data->{cgi}{$this_iface1_key}{value} ? $an->data->{cgi}{$this_iface1_key}{value} : "", class => $an->data->{cgi}{$this_iface1_key}{alert} ? "input_alert" : "input_clear", }); # Assemble the form $interface_form .= $an->Template->get({file => "main.html", name => "single_interface_form", variables => { field => $an->Words->string({key => "striker_0022", variables => { number => $ifn }}), description => "#!string!striker_0023!#", ip_key => $this_ip_key, ip_value => defined $an->data->{cgi}{$this_ip_key}{value} ? $an->data->{cgi}{$this_ip_key}{value} : $this_ip, ip_class => $this_ip_class, subnet_key => $this_subnet_key, subnet_value => defined $an->data->{cgi}{$this_subnet_key}{value} ? $an->data->{cgi}{$this_subnet_key}{value} : $an->data->{'default'}{ifn}{netmask}, subnet_class => $this_subnet_class, iface1_select => $this_iface1_form, }}); } } ### TODO: Add a form for Gateway, DNS and which interface to use # Gateway my $say_default_gateway = ""; my $gateway_class = $an->data->{cgi}{gateway}{alert} ? "input_alert" : "input_clear"; my $say_gateway = $an->Template->get({file => "main.html", name => "input_text_form", variables => { name => "gateway", id => "gateway", field => "#!string!striker_0035!#", description => "#!string!striker_0036!#", value => defined $an->data->{cgi}{gateway}{value} ? $an->data->{cgi}{gateway}{value} : $say_default_gateway, class => $gateway_class, extra => "", }}); # DNS my $dns_class = $an->data->{cgi}{dns}{alert} ? "input_alert" : "input_clear"; my $say_dns = $an->Template->get({file => "main.html", name => "input_text_form", variables => { name => "dns", id => "dns", field => "#!string!striker_0037!#", description => "#!string!striker_0038!#", value => defined $an->data->{cgi}{dns}{value} ? $an->data->{cgi}{dns}{value} : "8.8.8.8, 8.8.4.4", class => $dns_class, extra => "", }}); # Which interface gets the route? my $default_dg_iface = defined $an->data->{cgi}{dg_iface}{value} ? $an->data->{cgi}{dg_iface}{value} : "ifn_link1"; my $dg_iface_select = $an->Template->select_form({ name => "dg_iface", options => $links, blank => 0, selected => $default_dg_iface, class => $an->data->{cgi}{dg_iface}{alert} ? "input_alert" : "input_clear", }); my $dg_iface_class = $an->data->{cgi}{dg_iface}{alert} ? "input_alert" : "input_clear"; my $say_dg_iface = $an->Template->get({file => "main.html", name => "input_select_form", variables => { field => "#!string!striker_0039!#", description => "#!string!striker_0040!#", 'select' => "", }}); # Hostname 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 => "", }}); # Admin user my $say_default_striker_user = "striker"; my $striker_user_class = $an->data->{cgi}{striker_user}{alert} ? "input_alert" : "input_clear"; my $say_striker_user = $an->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 $an->data->{cgi}{striker_user}{value} ? $an->data->{cgi}{striker_user}{value} : $say_default_striker_user, class => $striker_user_class, extra => "", }}); # Password my $say_default_striker_password = ""; my $striker_password_class = $an->data->{cgi}{striker_password}{alert} ? "input_alert" : "input_clear"; my $say_striker_password = $an->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 $an->data->{cgi}{striker_password}{value} ? $an->data->{cgi}{striker_password}{value} : $say_default_striker_password, class => $striker_password_class, extra => "", }}); # Get the table that shows the current interface states. my $interface_states = get_network_details_form($an); # Store the previous CGI variables and display the new fields. 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}, bcn_count => $an->data->{cgi}{bcn_count}{value}, ifn_count => $an->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, hostname_form => $say_hostname, cgi_list => $cgi."organization,prefix,domain,sequence,bcn_count,ifn_count,gateway,hostname,dns,striker_user,striker_password", }}); $an->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 ($an) = @_; # This will flip if we run into a problem. my $sane = 1; # Do we have a host name, striker user and password? if (not $an->Validate->form_field({name => "hostname", type => "domain_name"})) { $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }}); } # The user name if ((not defined $an->data->{cgi}{striker_user}{value}) or (not $an->data->{cgi}{striker_user}{value})) { $an->data->{cgi}{striker_user}{alert} = 1; $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::striker_user::alert" => $an->data->{cgi}{striker_user}{alert} }}); } # The password if ((not defined $an->data->{cgi}{striker_password}{value}) or (not $an->data->{cgi}{striker_password}{value}) or (length($an->data->{cgi}{striker_password}{value}) < 6)) { $an->data->{cgi}{striker_password}{alert} = 1; $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::striker_password::alert" => $an->data->{cgi}{striker_password}{alert} }}); } # The gateway if (not $an->Validate->form_field({name => "gateway", type => "ipv4"})) { $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }}); } # DNS can be multiple entries, comma-separated. if ((not defined $an->data->{cgi}{dns}{value}) or (not $an->data->{cgi}{dns}{value})) { $an->data->{cgi}{dns}{alert} = 1; $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::dns::alert" => $an->data->{cgi}{dns}{alert} }}); } else { foreach my $ip (split/,/, $an->data->{cgi}{dns}{value}) { $ip =~ s/^\s+//; $ip =~ s/\s+$//; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip => $ip }}); if (not $an->Validate->is_ipv4({ip => $ip})) { $an->data->{cgi}{dns}{alert} = 1; $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::dns::alert" => $an->data->{cgi}{dns}{alert} }}); } } } # Look for interfaces and sanity check them. my $links = []; foreach my $network ("bcn", "ifn") { my $count_key = $network."_count"; my $network_count = $an->data->{cgi}{$count_key}{value} ? $an->data->{cgi}{$count_key}{value} : 1; $an->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) { push @{$links}, $network."_link".$count; my $this_ip_key = $network.$count."_ip"; my $this_subnet_key = $network.$count."_subnet"; my $this_iface1_key = $network.$count."_iface1_mac"; my $this_iface2_key = $network.$count."_iface2_mac"; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { count => $count, this_ip_key => $this_ip_key, this_subnet_key => $this_subnet_key, this_iface1_key => $this_iface1_key, this_iface2_key => $this_iface2_key, "cgi::${this_ip_key}::value" => $an->data->{cgi}{$this_ip_key}{value}, "cgi::${this_subnet_key}::value" => $an->data->{cgi}{$this_subnet_key}{value}, "cgi::${this_iface1_key}::value" => $an->data->{cgi}{$this_iface1_key}{value}, "cgi::${this_iface2_key}::value" => $an->data->{cgi}{$this_iface2_key}{value}, }}); # Is the IP sane? if (not $an->Validate->form_field({name => $this_ip_key, type => "ipv4"})) { # Nope $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }}); } # What about the subnet? if (not $an->Validate->form_field({name => $this_subnet_key, type => "subnet"})) { $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }}); } # Interface 1 must be set if (not $an->Validate->form_field({name => $this_iface1_key, type => "mac"})) { $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }}); } else { # Valid MAC. Has it been assigned elsewhere? my $mac = $an->data->{cgi}{$this_iface1_key}{value}; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { mac => $mac }}); if ((not exists $an->data->{network}{$mac}{set_as}) or (not $an->data->{network}{$mac}{set_as})) { $an->data->{network}{$mac}{set_as} = $this_iface1_key; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "network::${mac}::set_as" => $an->data->{network}{$mac}{set_as} }}); } else { # Conflict! Set the alert for this interface and the conflicting one. my $conflict_key = $an->data->{network}{$mac}{set_as}; $an->data->{cgi}{$conflict_key}{alert} = 1; $an->data->{cgi}{$this_iface1_key}{alert} = 1; $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::${conflict_key}::alert" => $an->data->{cgi}{$conflict_key}{alert}, "cgi::${this_iface1_key}::alert" => $an->data->{cgi}{$this_iface1_key}{alert}, }}); } } # Interface 2 doesn't have to be set. if ((defined $an->data->{cgi}{$this_iface2_key}{value}) && ($an->data->{cgi}{$this_iface2_key}{value})) { if (not $an->Validate->form_field({name => $this_iface2_key, type => "mac"})) { $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane }}); } else { # Valid MAC. Has it been assigned elsewhere? my $mac = $an->data->{cgi}{$this_iface2_key}{value}; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { mac => $mac }}); if ((not exists $an->data->{network}{$mac}{set_as}) or (not $an->data->{network}{$mac}{set_as})) { $an->data->{network}{$mac}{set_as} = $this_iface2_key; } else { # Conflict! Set the alert for this interface and the conflicting one. my $conflict_key = $an->data->{network}{$mac}{set_as}; $an->data->{cgi}{$conflict_key}{alert} = 1; $an->data->{cgi}{$this_iface2_key}{alert} = 1; $sane = 0; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { sane => $sane, "cgi::${conflict_key}::alert" => $an->data->{cgi}{$conflict_key}{alert}, "cgi::${this_iface2_key}::alert" => $an->data->{cgi}{$this_iface2_key}{alert}, }}); } } } } } $an->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 ($an) = @_; $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0131", variables => { function => "sanity_check_step1()" }}); # 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} }}); } else { # Record the answer. $an->Database->insert_or_update_variables({ variable_name => "form::config_step1::organization::value", variable_value => $an->data->{cgi}{organization}{value}, variable_default => "", variable_description => "striker_0004", variable_section => "config_step1", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", update_value_only => 1, }); } # 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} }}); } else { # Record the answer. $an->Database->insert_or_update_variables({ variable_name => "form::config_step1::prefix::value", variable_value => $an->data->{cgi}{prefix}{value}, variable_default => "", variable_description => "striker_0006", variable_section => "config_step1", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", update_value_only => 1, }); } # 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} }}); } else { # Record the answer. $an->Database->insert_or_update_variables({ variable_name => "form::config_step1::domain::value", variable_value => $an->data->{cgi}{domain}{value}, variable_default => "", variable_description => "striker_0008", variable_section => "config_step1", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", update_value_only => 1, }); } # 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} }}); } else { # Record the answer. $an->Database->insert_or_update_variables({ variable_name => "form::config_step1::sequence::value", variable_value => $an->data->{cgi}{sequence}{value}, variable_default => "", variable_description => "striker_0010", variable_section => "config_step1", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", update_value_only => 1, }); } 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} }}); } # Make sure we have enough interfaces. get_network_details($an); my $required_interfaces_for_single = 1 + $an->data->{cgi}{ifn_count}{value}; my $interface_count = keys %{$an->data->{interfaces}}; $an->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 = $an->Words->string({key => "striker_error_0001", variables => { interface_count => $interface_count, required_interfaces_for_single => $required_interfaces_for_single, }}); # Not enough interfaces found. $an->data->{form}{error_massage} = $an->Template->get({file => "main.html", name => "error_message", variables => { error_message => $say_message }}); # We're not sane $an->data->{cgi}{ifn_count}{alert} = 1; $sane = 0; } else { # Sane, Record the answers. $an->Database->insert_or_update_variables({ variable_name => "form::config_step1::ifn_count::value", variable_value => $an->data->{cgi}{ifn_count}{value}, variable_default => "", variable_description => "striker_0012", variable_section => "config_step1", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", update_value_only => 1, }); } $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) = @_; if (not $an->data->{cgi}{'next'}{value}) { # First load. See if we can read old data. my ($organization) = $an->Database->read_variable({ variable_name => "form::config_step1::organization::value", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", }); my ($prefix) = $an->Database->read_variable({ variable_name => "form::config_step1::prefix::value", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", }); my ($domain) = $an->Database->read_variable({ variable_name => "form::config_step1::domain::value", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", }); my ($sequence) = $an->Database->read_variable({ variable_name => "form::config_step1::sequence::value", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", }); my ($ifn_count) = $an->Database->read_variable({ variable_name => "form::config_step1::ifn_count::value", variable_source_uuid => $an->Get->host_uuid, variable_source_table => "hosts", }); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { organization => $organization, prefix => $prefix, domain => $domain, sequence => $sequence, ifn_count => $ifn_count, }}); $an->data->{cgi}{organization}{value} = $organization ne "" ? $organization : ""; $an->data->{cgi}{prefix}{value} = $prefix ne "" ? $prefix : ""; $an->data->{cgi}{domain}{value} = $domain ne "" ? $domain : ""; $an->data->{cgi}{sequence}{value} = $sequence ne "" ? $sequence : 1; $an->data->{cgi}{ifn_count}{value} = $ifn_count ne "" ? $ifn_count : 1; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'cgi::organization::value' => $an->data->{cgi}{organization}{value}, 'cgi::prefix::value' => $an->data->{cgi}{prefix}{value}, 'cgi::domain::value' => $an->data->{cgi}{domain}{value}, 'cgi::sequence::value' => $an->data->{cgi}{sequence}{value}, 'cgi::ifn_count::value' => $an->data->{cgi}{ifn_count}{value}, }}); } 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 => "min=\"1\" max=\"24\"", }}); $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 => "min=\"1\" max=\"24\"", }}); $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} = { 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'}, }; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "interfaces::${interface}::bond" => $an->data->{interfaces}{$interface}{bond}, "interfaces::${interface}::bridge" => $an->data->{interfaces}{$interface}{bridge}, "interfaces::${interface}::duplex" => $an->data->{interfaces}{$interface}{duplex}, "interfaces::${interface}::link" => $an->data->{interfaces}{$interface}{'link'}, "interfaces::${interface}::mac" => $an->data->{interfaces}{$interface}{mac}, "interfaces::${interface}::media" => $an->data->{interfaces}{$interface}{media}, "interfaces::${interface}::mtu" => $an->data->{interfaces}{$interface}{mtu}, "interfaces::${interface}::order" => $an->data->{interfaces}{$interface}{order}, "interfaces::${interface}::speed" => $an->data->{interfaces}{$interface}{speed}, "interfaces::${interface}::state" => $an->data->{interfaces}{$interface}{'state'}, }}); } } 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 => "", 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 .= $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); } # This is a rudimentary function for generating default Striker IPs. sub generate_ip { my ($an, $network, $network_sequence, $device_sequence) = @_; $an->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's second octet will be '+X' where 'X' is the sequence. my $default_ip = $an->data->{'default'}{$network}{subnet}; my $default_netmark = $an->data->{'default'}{$network}{netmask}; $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { default_ip => $default_ip, default_netmark => $default_netmark, }}); if (($an->Validate->is_ipv4({ip => $default_ip})) && ($an->Validate->is_ipv4({ip => $default_netmark}))) { # Valid values. my ($ip_octet1, $ip_octet2, $ip_octet3, $ip_octet4) = (split/\./, $default_ip); $an->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_netmark eq "255.255.0.0") { # We can work with this. $ip_octet2 += $network_sequence; $ip_octet3 = $an->data->{'default'}{bcn}{striker_octet3}; $ip_octet4 = $device_sequence; $ip = $ip_octet1.".".$ip_octet2.".".$ip_octet3.".".$ip_octet4; $an->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!#"; } $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip => $ip }}); return($ip); }