41cd1e0319
* DRBD is now configured to a ping-timeout of 3 seconds. * Created Log->switches() that returnes the command line switches used by Anvil! tool command line calls based on the active log levels / secure logging. Appended this to all invocations of our tools. * Updated Database->resync_databases() to now only skip 'jobs' and 'variables' tables with less than 10 record differences. All other differences will trigger a resync. * Created System->_check_anvil_conf() that, as you might guess, checks in anvil.conf exists and created it (using defaults), if not. It also checks to see if the 'admin' group and user exists and creates them, if not. * Updated anvil-daemon to check anvil.conf on start up and in each loop. Created the function check_journald() that checks (and sets, if needed) that journald logging is persistent. * Made striker-manage-peers to check_if_configured on the Database->connect() when updating anvil.conf and the target UUID is the local machine. Also created a loop to make the reconnection a lot more robust. Signed-off-by: Digimer <digimer@alteeve.ca>
1229 lines
52 KiB
Perl
Executable File
1229 lines
52 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
#
|
|
# This is called when striker, a node or a DR host needs to configure the local network and user accounts.
|
|
#
|
|
# Exit codes;
|
|
# 0 = Normal exit.
|
|
# 1 = The program is not running as root.
|
|
# 2 = Failed to connect to database(s).
|
|
# 3 = Job was already picked up by another running instance.
|
|
# 4 = The host name did not update properly.
|
|
# 5 = Failed to write the temp file with the new password needed to call anvil-change-password.
|
|
# 6 = The job-uuid was not found.
|
|
# 7 = The host is an active cluster member.
|
|
#
|
|
# TODO:
|
|
# - Add MTU support
|
|
# - Check to see if this is a cluster node and/or running VMs, and if so, refuse to run.
|
|
#
|
|
|
|
use strict;
|
|
use warnings;
|
|
use Data::Dumper;
|
|
use Anvil::Tools;
|
|
|
|
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
|
|
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
|
|
if (($running_directory =~ /^\./) && ($ENV{PWD}))
|
|
{
|
|
$running_directory =~ s/^\./$ENV{PWD}/;
|
|
}
|
|
|
|
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
|
|
$| = 1;
|
|
|
|
my $anvil = Anvil::Tools->new();
|
|
|
|
# Read switches
|
|
$anvil->Get->switches;
|
|
### TODO: Remove this before final release
|
|
$anvil->Log->level({set => 2});
|
|
$anvil->Log->secure({set => 1});
|
|
##########################################
|
|
|
|
# Make sure we're running as 'root'
|
|
# $< == real UID, $> == effective UID
|
|
if (($< != 0) && ($> != 0))
|
|
{
|
|
# Not root
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0005"});
|
|
$anvil->nice_exit({exit_code => 1});
|
|
}
|
|
|
|
# Connect
|
|
$anvil->Database->connect();
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "message_0031"});
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, secure => 0, key => "log_0132"});
|
|
if (not $anvil->data->{sys}{database}{connections})
|
|
{
|
|
# No databases, exit.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0003"});
|
|
$anvil->nice_exit({exit_code => 2});
|
|
}
|
|
|
|
pickup_job_details($anvil);
|
|
|
|
# Set maintenance mode
|
|
$anvil->System->maintenance_mode({set => 1});
|
|
|
|
reconfigure_network($anvil);
|
|
|
|
# Record that we've configured this machine.
|
|
$anvil->Database->insert_or_update_variables({
|
|
variable_name => "system::configured",
|
|
variable_value => 1,
|
|
variable_default => "",
|
|
variable_description => "striker_0048",
|
|
variable_section => "system",
|
|
variable_source_uuid => $anvil->data->{sys}{host_uuid},
|
|
variable_source_table => "hosts",
|
|
});
|
|
|
|
update_passwords($anvil);
|
|
$anvil->Job->update_progress({
|
|
debug => 3,
|
|
progress => 100,
|
|
message => "",
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
|
|
# Clear maintenance mode.
|
|
$anvil->System->maintenance_mode({set => 0});
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, secure => 0, key => "log_0467"});
|
|
|
|
### TODO: As of now, the network doesn't come up reliably, so reboot.
|
|
my $shell_call = $anvil->data->{path}{exe}{systemctl}." reboot";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
|
|
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
|
|
|
|
# Unlikely we're still alive, but 'poweroff' and 'reboot' do return once enqueued, so...
|
|
$anvil->nice_exit({exit_code => 0});
|
|
|
|
|
|
#############################################################################################################
|
|
# Functions #
|
|
#############################################################################################################
|
|
|
|
# This updates the passwords on the root user, admin user, database and apache user.
|
|
sub update_passwords
|
|
{
|
|
my ($anvil) = @_;
|
|
|
|
# Have we been asked to set a password?
|
|
$anvil->data->{variables}{form}{config_step2}{striker_password}{value} = "" if not defined $anvil->data->{variables}{form}{config_step2}{striker_password}{value};
|
|
if ($anvil->data->{variables}{form}{config_step2}{striker_password}{value})
|
|
{
|
|
# Set the passwords
|
|
my $password = $anvil->data->{variables}{form}{config_step2}{striker_password}{value};
|
|
my $temp_file = "/tmp/anvil-".$anvil->Get->uuid;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { password => $password }});
|
|
|
|
# Write the password into a temporary file.
|
|
my $error = $anvil->Storage->write_file({
|
|
body => $password,
|
|
file => $temp_file,
|
|
group => "root",
|
|
mode => "0600",
|
|
overwrite => 1,
|
|
secure => 1,
|
|
user => "root",
|
|
});
|
|
|
|
# Call anvil-change-password
|
|
if ($error)
|
|
{
|
|
# Couldn't write the temp file.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "message_0030", variables => { file => $temp_file }});
|
|
$anvil->nice_exit({exit_code => 5});
|
|
}
|
|
else
|
|
{
|
|
my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'anvil-change-password'}." -y --password-file ".$temp_file.$anvil->Log->switches });
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { output => $output, return_code => $return_code }});
|
|
foreach my $line (split/\n/, $output)
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { line => $line }});
|
|
}
|
|
|
|
# Unlink the temp file.
|
|
unlink $temp_file;
|
|
|
|
if ($return_code)
|
|
{
|
|
# Something went wrong
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0011", variables => { return_code => $return_code }});
|
|
}
|
|
}
|
|
}
|
|
|
|
$anvil->Job->update_progress({
|
|
progress => 95,
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
|
|
return(0);
|
|
}
|
|
|
|
# This does the work of reconfiguring the network
|
|
sub reconfigure_network
|
|
{
|
|
my ($anvil) = @_;
|
|
|
|
my $local_host = $anvil->Get->short_host_name();
|
|
my $reboot_needed = 0;
|
|
my $prefix = exists $anvil->data->{variables}{form}{config_step1}{prefix}{value} ? $anvil->data->{variables}{form}{config_step1}{prefix}{value} : "";
|
|
my $sequence = exists $anvil->data->{variables}{form}{config_step1}{sequence}{value} ? $anvil->data->{variables}{form}{config_step1}{sequence}{value} : "";
|
|
my $domain = exists $anvil->data->{variables}{form}{config_step1}{domain}{value} ? $anvil->data->{variables}{form}{config_step1}{domain}{value} : "";
|
|
my $organization = exists $anvil->data->{variables}{form}{config_step1}{organization}{value} ? $anvil->data->{variables}{form}{config_step1}{organization}{value} : "";
|
|
my $bcn_count = exists $anvil->data->{variables}{form}{config_step1}{bcn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{bcn_count}{value} : 1;
|
|
my $sn_count = exists $anvil->data->{variables}{form}{config_step1}{sn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{sn_count}{value} : 0;
|
|
my $ifn_count = exists $anvil->data->{variables}{form}{config_step1}{ifn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{ifn_count}{value} : 1;
|
|
my $new_host_name = exists $anvil->data->{variables}{form}{config_step2}{host_name}{value} ? $anvil->data->{variables}{form}{config_step2}{host_name}{value} : "";
|
|
my $type = $anvil->Get->host_type();
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
prefix => $prefix,
|
|
sequence => $sequence,
|
|
domain => $domain,
|
|
organization => $organization,
|
|
bcn_count => $bcn_count,
|
|
sn_count => $sn_count,
|
|
ifn_count => $ifn_count,
|
|
new_host_name => $new_host_name,
|
|
type => $type,
|
|
}});
|
|
|
|
# If we're configuring a dashboard and no host name was given, generate it.
|
|
if (($type eq "striker") && (not $new_host_name))
|
|
{
|
|
$new_host_name = $prefix."-striker".sprintf("%02d", $sequence).".".$domain;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { new_host_name => $new_host_name }});
|
|
}
|
|
|
|
if ($new_host_name)
|
|
{
|
|
my $type_name = "";
|
|
if ($type eq "striker")
|
|
{
|
|
$type_name = $anvil->Words->string({key => "brand_0003"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, list => { type_name => $type_name }});
|
|
}
|
|
elsif ($type eq "node")
|
|
{
|
|
$type_name = $anvil->Words->string({key => "brand_0007"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, list => { type_name => $type_name }});
|
|
}
|
|
elsif ($type eq "dr")
|
|
{
|
|
$type_name = $anvil->Words->string({key => "brand_0008"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, list => { type_name => $type_name }});
|
|
}
|
|
my $pretty_host_name = $new_host_name;
|
|
if (($organization) && ($sequence))
|
|
{
|
|
$pretty_host_name = $organization." - ".$type_name." ".sprintf("%02d", $sequence);
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, list => { pretty_host_name => $pretty_host_name }});
|
|
}
|
|
|
|
# Set the host_name
|
|
my ($host_name, $descriptive_host_name) = $anvil->System->host_name({set => $new_host_name, pretty => $pretty_host_name, debug => 3});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
|
|
host_name => $host_name,
|
|
descriptive_host_name => $descriptive_host_name,
|
|
}});
|
|
if ($host_name eq $new_host_name)
|
|
{
|
|
# Success
|
|
$anvil->Job->update_progress({
|
|
progress => 10,
|
|
message => "message_0016,!!host_name!$new_host_name!!",
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "message_0016", variables => { host_name => $new_host_name }});
|
|
}
|
|
else
|
|
{
|
|
# Failed
|
|
$anvil->Job->update_progress({
|
|
progress => 0,
|
|
message => "message_0017,!!host_name!$new_host_name!!,!!bad_host_name!$host_name!!",
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "message_0017", variables => {
|
|
host_name => $new_host_name,
|
|
bad_host_name => $host_name,
|
|
}});
|
|
$anvil->nice_exit({exit_code => 4});
|
|
}
|
|
}
|
|
|
|
# Read the local network manager data.
|
|
$anvil->Network->read_nmcli({debug => 3});
|
|
|
|
# Get the current list of IPs and MAC addresses.
|
|
$anvil->Network->get_ips({debug => 3});
|
|
|
|
# Now configure the network.
|
|
my $dns = defined $anvil->data->{variables}{form}{config_step2}{dns}{value} ? [split/,/, $anvil->data->{variables}{form}{config_step2}{dns}{value}] : [];
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { dns => $dns }});
|
|
for (my $i = 0; $i < @{$dns}; $i++)
|
|
{
|
|
$dns->[$i] = $anvil->Words->clean_spaces({ string => $dns->[$i] });
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "dns->[$i]" => $dns->[$i] }});
|
|
}
|
|
|
|
my $gateway = defined $anvil->data->{variables}{form}{config_step2}{gateway}{value} ? $anvil->data->{variables}{form}{config_step2}{gateway}{value} : "";
|
|
my $gateway_interface = defined $anvil->data->{variables}{form}{config_step2}{gateway_interface}{value} ? $anvil->data->{variables}{form}{config_step2}{gateway_interface}{value} : "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
|
|
gateway => $gateway,
|
|
gateway_interface => $gateway_interface,
|
|
}});
|
|
|
|
# If there is no default gateway device, and one of the interfaces are set to DHCP, use it.
|
|
if (not $gateway_interface)
|
|
{
|
|
# IFN first, BCN second, SN last
|
|
foreach my $network_type ("ifn", "bcn", "sn")
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }});
|
|
|
|
my $count = 0;
|
|
if ($network_type eq "bcn") { $count = $bcn_count; }
|
|
elsif ($network_type eq "sn") { $count = $sn_count; }
|
|
elsif ($network_type eq "ifn") { $count = $ifn_count; }
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
|
|
|
|
next if not $count;
|
|
foreach my $network_count (1..$count)
|
|
{
|
|
my $ip_key = $network_type.$network_count."_ip";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ip_key => $ip_key }});
|
|
if ((exists $anvil->data->{variables}{form}{config_step2}{$ip_key}{value}) && ($anvil->data->{variables}{form}{config_step2}{$ip_key}{value} eq "dhcp"))
|
|
{
|
|
$gateway_interface = $network_type.$network_count;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { gateway_interface => $gateway_interface }});
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Disconnect from the database, as we're about to tear down our connection.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, secure => 0, key => "log_0466"});
|
|
$anvil->Database->disconnect();
|
|
|
|
# Close all open SSH connections
|
|
foreach my $ssh_fh_key (sort {$a cmp $b} keys %{$anvil->data->{cache}{ssh_fh}})
|
|
{
|
|
my $ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ssh_fh => $ssh_fh }});
|
|
|
|
next if $ssh_fh !~ /^Net::OpenSSH/;
|
|
$ssh_fh->disconnect();
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "message_0009", variables => { target => $ssh_fh_key }});
|
|
|
|
# For good measure, blank both variables.
|
|
$anvil->data->{cache}{ssh_fh}{$ssh_fh_key} = "";
|
|
$ssh_fh = "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cache::ssh_fh::${ssh_fh_key}" => $anvil->data->{cache}{ssh_fh}{$ssh_fh_key} }});
|
|
}
|
|
|
|
my $new_interfaces = [];
|
|
foreach my $network_type ("bcn", "sn", "ifn")
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_type => $network_type }});
|
|
|
|
my $count = 0;
|
|
if ($network_type eq "bcn") { $count = $bcn_count; }
|
|
elsif ($network_type eq "sn") { $count = $sn_count; }
|
|
elsif ($network_type eq "ifn") { $count = $ifn_count; }
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { count => $count }});
|
|
|
|
next if not $count;
|
|
foreach my $network_count (1..$count)
|
|
{
|
|
my $this_network = $network_type.$network_count;
|
|
my $link1_key = $this_network."_link1_mac_to_set";
|
|
my $link2_key = $this_network."_link2_mac_to_set";
|
|
my $subnet_mask_key = $this_network."_subnet_mask";
|
|
my $ip_key = $this_network."_ip";
|
|
my $bridge_key = $this_network."_create_bridge";
|
|
my $link1_mac = $anvil->data->{variables}{form}{config_step2}{$link1_key}{value};
|
|
my $is_gateway = $this_network eq $gateway_interface ? 1 : 0;
|
|
my $link2_mac = defined $anvil->data->{variables}{form}{config_step2}{$link2_key}{value} ? $anvil->data->{variables}{form}{config_step2}{$link2_key}{value} : "";
|
|
my $old_link1_iface = $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface} ? $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface} : "";
|
|
my $old_link2_iface = defined $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface} ? $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface} : "";
|
|
my $bridge = defined $anvil->data->{variables}{form}{config_step2}{$bridge_key}{value} ? $anvil->data->{variables}{form}{config_step2}{$bridge_key}{value} : 0;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
ip_key => $ip_key,
|
|
is_gateway => $is_gateway,
|
|
link1_key => $link1_key,
|
|
link1_mac => $link1_mac,
|
|
link2_key => $link2_key,
|
|
link2_mac => $link2_mac,
|
|
bridge_key => $bridge_key,
|
|
old_link1_iface => $old_link1_iface,
|
|
old_link2_iface => $old_link2_iface,
|
|
subnet_mask_key => $subnet_mask_key,
|
|
this_network => $this_network,
|
|
bridge => $bridge,
|
|
}});
|
|
|
|
# Dig out the name that network manager knows the old interface(s) as. The
|
|
# 'old_link1_iface' is the name reported by 'ip', the 'DEVICE=xxx' value in the ifcfg-xxx file.
|
|
my $old_link1_nm_name = $old_link1_iface;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_nm_name => $old_link1_nm_name }});
|
|
if ((exists $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link1_iface}) && ($anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link1_iface}))
|
|
{
|
|
$old_link1_nm_name = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link1_iface};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_nm_name => $old_link1_nm_name }});
|
|
}
|
|
|
|
# Is there a link 2?
|
|
my $old_link2_nm_name = "";
|
|
if ($old_link2_iface)
|
|
{
|
|
$old_link2_nm_name = $old_link2_iface;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_nm_name => $old_link2_nm_name }});
|
|
if ((exists $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link2_iface}) && ($anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link2_iface}))
|
|
{
|
|
$old_link2_nm_name = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link2_iface};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_nm_name => $old_link2_nm_name }});
|
|
}
|
|
}
|
|
|
|
# Skip if this doesn't exist or isn't a valid IPv4 address.
|
|
if (not exists $anvil->data->{variables}{form}{config_step2}{$ip_key}{value})
|
|
{
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0176", variables => { ip_key => $ip_key }});
|
|
next;
|
|
}
|
|
else
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "variables::form::config_step2::${ip_key}::value" => $anvil->data->{variables}{form}{config_step2}{$ip_key}{value} }});
|
|
}
|
|
if (($anvil->data->{variables}{form}{config_step2}{$ip_key}{value}) &&
|
|
($anvil->data->{variables}{form}{config_step2}{$ip_key}{value} ne "dhcp") &&
|
|
(not $anvil->Validate->ipv4({ip => $anvil->data->{variables}{form}{config_step2}{$ip_key}{value}})))
|
|
{
|
|
# Something was set, but it isn't valid.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "log_0148", variables => {
|
|
network => $this_network,
|
|
ip => $anvil->data->{variables}{form}{config_step2}{$ip_key}{value},
|
|
}});
|
|
next;
|
|
}
|
|
|
|
# The IP could be 'dhcp', we'll handle that in a bit.
|
|
my $ip_address = $anvil->data->{variables}{form}{config_step2}{$ip_key}{value};
|
|
my $subnet_mask = defined $anvil->data->{variables}{form}{config_step2}{$subnet_mask_key}{value} ? $anvil->data->{variables}{form}{config_step2}{$subnet_mask_key}{value} : "";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
ip_address => $ip_address,
|
|
subnet_mask => $subnet_mask,
|
|
}});
|
|
|
|
# Are we building bonded interfaces?
|
|
if ($anvil->Validate->mac({mac => $link2_mac}))
|
|
{
|
|
# Yup!
|
|
my $say_network = "";
|
|
my $say_interface = "";
|
|
my $interface_prefix = "";
|
|
my $say_defroute = $is_gateway ? "yes" : "no";
|
|
if ($network_type eq "bcn")
|
|
{
|
|
$say_network = "Back-Channel Network ".$network_count;
|
|
$say_interface = "bcn".$network_count;
|
|
$interface_prefix = "BCN";
|
|
}
|
|
elsif ($network_type eq "sn")
|
|
{
|
|
$say_network = "Storage Network ".$network_count;
|
|
$say_interface = "sn".$network_count;
|
|
$interface_prefix = "SN";
|
|
}
|
|
elsif ($network_type eq "ifn")
|
|
{
|
|
$say_network = "Internet-Facing Network ".$network_count;
|
|
$say_interface = "ifn".$network_count;
|
|
$interface_prefix = "IFN";
|
|
}
|
|
|
|
# Gather variables
|
|
my $cidr = $ip_address eq "dhcp" ? "" : $anvil->Convert->cidr({subnet_mask => $subnet_mask});
|
|
my $bridge_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Bridge_1";
|
|
my $bond_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Bond_1";
|
|
my $new_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_1";
|
|
my $new_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_2";
|
|
my $old_link1_file = $new_link1_file;
|
|
my $old_link2_file = $new_link2_file;
|
|
my $new_bridge_iface = $say_interface."_bridge1";
|
|
my $new_bond_iface = $say_interface."_bond1";
|
|
my $new_link1_iface = $say_interface."_link1";
|
|
my $new_link2_iface = $say_interface."_link2";
|
|
my $boot_proto = $ip_address eq "dhcp" ? "dhcp" : "none";
|
|
my $link1_uuid = get_uuid_from_interface_file($anvil, $old_link1_file);
|
|
my $link2_uuid = get_uuid_from_interface_file($anvil, $old_link2_file);
|
|
if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) && ($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}))
|
|
{
|
|
$old_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface};
|
|
}
|
|
if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}) && ($anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}))
|
|
{
|
|
$old_link2_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface};
|
|
}
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
bond_file => $bond_file,
|
|
boot_proto => $boot_proto,
|
|
bridge_file => $bridge_file,
|
|
cidr => $cidr,
|
|
link1_uuid => $link1_uuid,
|
|
link2_uuid => $link2_uuid,
|
|
new_bond_iface => $new_bond_iface,
|
|
new_bridge_iface => $new_bridge_iface,
|
|
new_link1_file => $new_link1_file,
|
|
new_link1_iface => $new_link1_iface,
|
|
new_link2_file => $new_link2_file,
|
|
new_link2_iface => $new_link2_iface,
|
|
old_link1_file => $old_link1_file,
|
|
old_link2_file => $old_link2_file,
|
|
say_defroute => $say_defroute,
|
|
}});
|
|
|
|
### NOTE: Bridges and bonds take a UUID, but it can be temperamental. It
|
|
### works more reliably without defining it, so we don't.
|
|
# Are we building a bridge interface?
|
|
my $bridge_config = "";
|
|
if ($bridge)
|
|
{
|
|
my $new_bridge1_nm_name = $interface_prefix." ".$network_count." - Bridge 1";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_bridge1_nm_name => $new_bridge1_nm_name }});
|
|
|
|
# Record that we need to start this.
|
|
push @{$new_interfaces}, $new_bridge1_nm_name;
|
|
|
|
# Yup!
|
|
$bridge_config = "# $say_network - Bridge 1\n";
|
|
$bridge_config .= "DEVICE=\"".$new_bridge_iface."\"\n";
|
|
$bridge_config .= "NAME=\"".$new_bridge1_nm_name."\"\n";
|
|
$bridge_config .= "TYPE=\"Bridge\"\n";
|
|
$bridge_config .= "STP=\"yes\"\n";
|
|
$bridge_config .= "BRIDGING_OPTS=\"priority=32768\"\n";
|
|
$bridge_config .= "PROXY_METHOD=\"none\"\n";
|
|
$bridge_config .= "BROWSER_ONLY=\"no\"\n";
|
|
$bridge_config .= "IPV4_FAILURE_FATAL=\"no\"\n";
|
|
$bridge_config .= "IPV6INIT=\"no\"\n";
|
|
$bridge_config .= "BOOTPROTO=\"".$boot_proto."\"\n";
|
|
|
|
# If the IP is NOT 'dhcp', set it.
|
|
if ($ip_address ne "dhcp")
|
|
{
|
|
$bridge_config .= "IPADDR=\"".$ip_address."\"\n";
|
|
$bridge_config .= $cidr ? "PREFIX=\"".$cidr."\"\n" : "NETMASK=\"".$subnet_mask."\"\n";
|
|
|
|
# If this is the default gateway, add that info.
|
|
if ($is_gateway)
|
|
{
|
|
$bridge_config .= "GATEWAY=\"".$gateway."\"\n";
|
|
for (my $i = 0; $i < @{$dns}; $i++)
|
|
{
|
|
$bridge_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n";
|
|
}
|
|
}
|
|
}
|
|
$bridge_config .= "DEFROUTE=\"".$say_defroute."\"\n";
|
|
$bridge_config .= "ONBOOT=\"yes\"\n";
|
|
$bridge_config .= "ZONE=\"".uc($say_interface)."\"\n";
|
|
}
|
|
|
|
# If this is DHCP, but there is a bridge, the bond's boot proto in 'none'.
|
|
$boot_proto = "none" if $bridge;
|
|
|
|
# Make the rest of the network names.
|
|
my $new_bond1_nm_name = $interface_prefix." ".$network_count." - Bond 1";
|
|
my $new_link1_nm_name = $interface_prefix." ".$network_count." - Link 1";
|
|
my $new_link2_nm_name = $interface_prefix." ".$network_count." - Link 2";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
new_bond1_nm_name => $new_bond1_nm_name,
|
|
new_link1_nm_name => $new_link1_nm_name,
|
|
new_link2_nm_name => $new_link2_nm_name,
|
|
}});
|
|
|
|
# Record that we need to start this.
|
|
push @{$new_interfaces}, $new_bond1_nm_name;
|
|
push @{$new_interfaces}, $new_link1_nm_name;
|
|
push @{$new_interfaces}, $new_link2_nm_name;
|
|
|
|
# Build the Bond config.
|
|
my $bond_config = "# $say_network - Bond 1\n";
|
|
$bond_config .= "DEVICE=\"".$new_bond_iface."\"\n";
|
|
$bond_config .= "NAME=\"".$new_bond1_nm_name."\"\n";
|
|
$bond_config .= "TYPE=\"Bond\"\n";
|
|
$bond_config .= "BONDING_OPTS=\"downdelay=0 miimon=100 mode=active-backup primary=".$say_interface."_link1 updelay=120000\"\n";
|
|
$bond_config .= "BONDING_MASTER=\"yes\"\n";
|
|
$bond_config .= "ONBOOT=\"yes\"\n";
|
|
|
|
# Is this connected to a bridge?
|
|
if ($bridge)
|
|
{
|
|
$bond_config .= "BRIDGE=\"".$new_bridge_iface."\"\n";
|
|
}
|
|
else
|
|
{
|
|
# Does this bond have an IP?
|
|
# If the IP is NOT 'dhcp', set it.
|
|
$bond_config .= "BOOTPROTO=\"".$boot_proto."\"\n";
|
|
if ($ip_address ne "dhcp")
|
|
{
|
|
$bond_config .= "IPADDR=\"".$ip_address."\"\n";
|
|
$bond_config .= $cidr ? "PREFIX=\"".$cidr."\"\n" : "NETMASK=\"".$subnet_mask."\"\n";
|
|
|
|
# If this is the default gateway, add that info.
|
|
if ($is_gateway)
|
|
{
|
|
$bond_config .= "GATEWAY=\"".$gateway."\"\n";
|
|
for (my $i = 0; $i < @{$dns}; $i++)
|
|
{
|
|
$bond_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n";
|
|
}
|
|
}
|
|
}
|
|
$bond_config .= "DEFROUTE=\"".$say_defroute."\"\n";
|
|
}
|
|
# Rest of the config
|
|
$bond_config .= "ZONE=\"".uc($say_interface)."\"\n";
|
|
|
|
# Now build the links
|
|
my $link1_config = "# $say_network - Link 1\n";
|
|
$link1_config .= "HWADDR=\"".uc($link1_mac)."\"\n";
|
|
$link1_config .= "UUID=\"".$link1_uuid."\"\n";
|
|
$link1_config .= "NAME=\"".$new_link1_nm_name."\"\n";
|
|
$link1_config .= "DEVICE=\"".$new_link1_iface."\"\n";
|
|
$link1_config .= "TYPE=\"Ethernet\"\n";
|
|
$link1_config .= "BOOTPROTO=\"none\"\n";
|
|
$link1_config .= "IPV6INIT=\"no\"\n";
|
|
$link1_config .= "ONBOOT=\"yes\"\n";
|
|
$link1_config .= "USERCTL=\"no\"\n";
|
|
$link1_config .= "MTU=\"1500\"\n"; # TODO: Make the MTU user-adjustable
|
|
$link1_config .= "NM_CONTROLLED=\"yes\"\n";
|
|
$link1_config .= "SLAVE=\"yes\"\n";
|
|
$link1_config .= "MASTER=\"".$say_interface."_bond1\"\n";
|
|
$link1_config .= "ZONE=\"".uc($say_interface)."\"\n";
|
|
|
|
my $link2_config = "# $say_network - Link 2\n";
|
|
$link2_config .= "HWADDR=\"".uc($link2_mac)."\"\n";
|
|
$link2_config .= "UUID=\"".$link2_uuid."\"\n";
|
|
$link2_config .= "NAME=\"".$new_link2_nm_name."\"\n";
|
|
$link2_config .= "DEVICE=\"".$new_link2_iface."\"\n";
|
|
$link2_config .= "TYPE=\"Ethernet\"\n";
|
|
$link2_config .= "BOOTPROTO=\"none\"\n";
|
|
$link2_config .= "IPV6INIT=\"no\"\n";
|
|
$link2_config .= "ONBOOT=\"yes\"\n";
|
|
$link2_config .= "USERCTL=\"no\"\n";
|
|
$link2_config .= "MTU=\"1500\"\n"; # TODO: Make the MTU user-adjustable
|
|
$link2_config .= "NM_CONTROLLED=\"yes\"\n";
|
|
$link2_config .= "SLAVE=\"yes\"\n";
|
|
$link2_config .= "MASTER=\"".$say_interface."_bond1\"\n";
|
|
$link2_config .= "ZONE=\"".uc($say_interface)."\"\n";
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
bridge_config => $bridge_config,
|
|
bond_config => $bond_config,
|
|
link1_config => $link1_config,
|
|
link2_config => $link2_config,
|
|
}});
|
|
|
|
# Make backups of existing files
|
|
if (-e $bridge_file)
|
|
{
|
|
$anvil->Storage->backup({debug => 2, file => $bridge_file});
|
|
}
|
|
if (-e $bond_file)
|
|
{
|
|
$anvil->Storage->backup({debug => 2, file => $bond_file});
|
|
}
|
|
if (-e $old_link1_file)
|
|
{
|
|
$anvil->Storage->backup({debug => 2, file => $old_link1_file});
|
|
}
|
|
if (-e $old_link2_file)
|
|
{
|
|
$anvil->Storage->backup({debug => 2, file => $old_link2_file});
|
|
}
|
|
if (($old_link1_file ne $new_link1_file) && (-e $new_link1_file))
|
|
{
|
|
$anvil->Storage->backup({debug => 2, file => $new_link1_file});
|
|
}
|
|
if (($old_link2_file ne $new_link2_file) && (-e $new_link2_file))
|
|
{
|
|
$anvil->Storage->backup({debug => 2, file => $new_link2_file});
|
|
}
|
|
|
|
# Remove the old link if it was different, of down and up it if the same.
|
|
if ($old_link1_iface ne $new_link1_iface)
|
|
{
|
|
# Delete the old interface
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0461", variables => { interface => $old_link1_nm_name }});
|
|
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link1_nm_name});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
output => $output,
|
|
return_code => $return_code,
|
|
}});
|
|
|
|
if (-e $old_link1_file)
|
|
{
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0589", variables => { file => $old_link1_file }});
|
|
unlink $old_link1_file;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# Down the interface
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0462", variables => { interface => $old_link1_nm_name }});
|
|
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link1_nm_name});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
output => $output,
|
|
return_code => $return_code,
|
|
}});
|
|
}
|
|
|
|
# Shut down (and rename) Link 2
|
|
if ($old_link2_iface ne $new_link2_iface)
|
|
{
|
|
# Delete the old interface
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0461", variables => { interface => $old_link2_nm_name }});
|
|
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link2_nm_name});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
output => $output,
|
|
return_code => $return_code,
|
|
}});
|
|
|
|
sleep 1;
|
|
if (-e $old_link2_file)
|
|
{
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0589", variables => { file => $old_link2_file }});
|
|
unlink $old_link2_file;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# Down the interface
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0462", variables => { interface => $old_link2_nm_name }});
|
|
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link2_nm_name});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
output => $output,
|
|
return_code => $return_code,
|
|
}});
|
|
}
|
|
|
|
### Write out the new configs
|
|
# Are we writing a bridge config?
|
|
if ($bridge)
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, list => {
|
|
output => $bridge_file,
|
|
return_code => $bridge_config,
|
|
}});
|
|
$anvil->Storage->write_file({
|
|
debug => 3,
|
|
file => $bridge_file,
|
|
body => $bridge_config,
|
|
user => "root",
|
|
group => "root",
|
|
mode => "0644",
|
|
overwrite => 1
|
|
});
|
|
}
|
|
|
|
# Bond, Link 1 and Link 2
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, list => {
|
|
output => $bond_file,
|
|
return_code => $bond_config,
|
|
}});
|
|
$anvil->Storage->write_file({
|
|
debug => 3,
|
|
file => $bond_file,
|
|
body => $bond_config,
|
|
user => "root",
|
|
group => "root",
|
|
mode => "0644",
|
|
overwrite => 1,
|
|
});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, list => {
|
|
output => $new_link1_file,
|
|
return_code => $link1_config,
|
|
}});
|
|
$anvil->Storage->write_file({
|
|
debug => 3,
|
|
file => $new_link1_file,
|
|
body => $link1_config,
|
|
user => "root",
|
|
group => "root",
|
|
mode => "0644",
|
|
overwrite => 1,
|
|
});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, list => {
|
|
output => $new_link2_file,
|
|
return_code => $link2_config,
|
|
}});
|
|
$anvil->Storage->write_file({
|
|
debug => 3,
|
|
file => $new_link2_file,
|
|
body => $link2_config,
|
|
user => "root",
|
|
group => "root",
|
|
mode => "0644",
|
|
overwrite => 1,
|
|
});
|
|
|
|
# If the NICs names have changed, rename them now.
|
|
if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) &&
|
|
($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) &&
|
|
($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface} ne $new_link1_iface))
|
|
{
|
|
rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}, $new_link1_iface);
|
|
}
|
|
if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}) &&
|
|
($anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}) &&
|
|
($anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface} ne $new_link2_iface))
|
|
{
|
|
rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}, $new_link2_iface);
|
|
}
|
|
}
|
|
elsif ((exists $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}) && ($anvil->Validate->mac({mac => $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}})))
|
|
{
|
|
### NOTE: This only applies when configuring Striker dashboards. They can't
|
|
### be 'dhcp', either, so no checks are made for those cases. Likewise,
|
|
### bridges are not used.
|
|
# Single interface, set it up
|
|
my $link1_mac = $anvil->data->{variables}{form}{config_step2}{$link1_key}{value};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link1_mac => $link1_mac }});
|
|
|
|
my $say_network = "";
|
|
my $say_interface = "";
|
|
my $interface_prefix = "";
|
|
if ($network_type eq "bcn")
|
|
{
|
|
$say_network = "Back-Channel Network ".$network_count;
|
|
$say_interface = "bcn".$network_count;
|
|
$interface_prefix = "BCN";
|
|
}
|
|
elsif ($network_type eq "sn")
|
|
{
|
|
$say_network = "Storage Network ".$network_count;
|
|
$say_interface = "sn".$network_count;
|
|
$interface_prefix = "SN";
|
|
}
|
|
elsif ($network_type eq "ifn")
|
|
{
|
|
$say_network = "Internet-Facing Network ".$network_count;
|
|
$say_interface = "ifn".$network_count;
|
|
$interface_prefix = "IFN";
|
|
}
|
|
my $say_defroute = $is_gateway ? "yes" : "no";
|
|
my $cidr = $anvil->Convert->cidr({subnet_mask => $subnet_mask});
|
|
my $new_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$interface_prefix."_".$network_count."_-_Link_1";
|
|
my $old_link1_file = $new_link1_file;
|
|
my $new_link1_iface = $say_interface."_link1";
|
|
if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) && ($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}))
|
|
{
|
|
$old_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface};
|
|
}
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
cidr => $cidr,
|
|
new_link1_file => $new_link1_file,
|
|
new_link1_iface => $new_link1_iface,
|
|
old_link1_file => $old_link1_file,
|
|
say_defroute => $say_defroute,
|
|
}});
|
|
|
|
my $new_link1_nm_name = $interface_prefix." ".$network_count." - Link 1";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_link1_nm_name => $new_link1_nm_name }});
|
|
push @{$new_interfaces}, $new_link1_nm_name;
|
|
|
|
# Gather (or create) UUIDs
|
|
my $link1_uuid = get_uuid_from_interface_file($anvil, $old_link1_file);
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link1_uuid => $link1_uuid }});
|
|
|
|
my $link1_config = "# $say_network - Link 1\n";
|
|
$link1_config .= "HWADDR=\"".uc($link1_mac)."\"\n";
|
|
$link1_config .= "UUID=\"".$link1_uuid."\"\n";
|
|
$link1_config .= "NAME=\"".$new_link1_nm_name."\"\n";
|
|
$link1_config .= "DEVICE=\"".$new_link1_iface."\"\n";
|
|
$link1_config .= "TYPE=\"Ethernet\"\n";
|
|
$link1_config .= "BOOTPROTO=\"none\"\n";
|
|
$link1_config .= "IPV6INIT=\"no\"\n";
|
|
$link1_config .= "ONBOOT=\"yes\"\n";
|
|
$link1_config .= "IPADDR=\"".$ip_address."\"\n";
|
|
$link1_config .= $cidr ? "PREFIX=\"".$cidr."\"\n" : "NETMASK=\"".$subnet_mask."\"\n";
|
|
if ($is_gateway)
|
|
{
|
|
$link1_config .= "GATEWAY=\"".$gateway."\"\n";
|
|
for (my $i = 0; $i < @{$dns}; $i++)
|
|
{
|
|
$link1_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n";
|
|
}
|
|
}
|
|
$link1_config .= "DEFROUTE=\"".$say_defroute."\"\n";
|
|
$link1_config .= "USERCTL=\"no\"\n";
|
|
$link1_config .= "MTU=\"1500\"\n"; # TODO: Make the MTU user-adjustable
|
|
$link1_config .= "NM_CONTROLLED=\"yes\"\n";
|
|
$link1_config .= "ZONE=\"".uc($say_interface)."\"";
|
|
|
|
# Backup the existing link1 file, if it exists.
|
|
if (-e $old_link1_file)
|
|
{
|
|
$anvil->Storage->backup({debug => 2, file => $old_link1_file});
|
|
}
|
|
|
|
# Write out the link1 config file.
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, list => {
|
|
output => $new_link1_file,
|
|
return_code => $link1_config,
|
|
}});
|
|
$anvil->Storage->write_file({
|
|
debug => 3,
|
|
file => $new_link1_file,
|
|
body => $link1_config,
|
|
user => "root",
|
|
group => "root",
|
|
mode => "0644",
|
|
overwrite => 1,
|
|
});
|
|
|
|
# If the name differs from old, delete the old interface.
|
|
if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) &&
|
|
($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}) &&
|
|
($anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface} ne $new_link1_iface))
|
|
{
|
|
# Delete the old interface
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "log_0461", variables => { interface => $old_link1_nm_name }});
|
|
$anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link1_nm_name});
|
|
|
|
rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}, $new_link1_iface);
|
|
}
|
|
else
|
|
{
|
|
# Down the interface
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0462", variables => { interface => $old_link1_nm_name }});
|
|
$anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link1_nm_name});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# Doesn't exist, skip.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "log_0149", variables => { network => $this_network }});
|
|
next;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Re-read the config
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0463"});
|
|
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{nmcli}." connection reload"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
output => $output,
|
|
return_code => $return_code,
|
|
}});
|
|
|
|
# Wait for a DB connection. We'll wait up to 130 seconds (updelay is 120 seconds, plus a small buffer).
|
|
my $wait_until = time + 130;
|
|
until ($anvil->data->{sys}{database}{connections})
|
|
{
|
|
$anvil->refresh();
|
|
$anvil->Database->connect();
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, secure => 0, key => "log_0132"});
|
|
if (not $anvil->data->{sys}{database}{connections})
|
|
{
|
|
if (time > $wait_until)
|
|
{
|
|
# Failed to reconnect, exit.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0107"});
|
|
$anvil->nice_exit({exit_code => 2});
|
|
}
|
|
|
|
# No databases, sleep and then try again.
|
|
sleep 2;
|
|
}
|
|
}
|
|
|
|
# We're half-way there.
|
|
$anvil->Job->update_progress({
|
|
progress => 50,
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
|
|
# If any virtio bridges exist, remove it/them.
|
|
my $start = 0;
|
|
(my $bridges, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{virsh}." net-list"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridges => $bridges, return_code => $return_code }});
|
|
if ($return_code)
|
|
{
|
|
### NOTE: We're doing a bunch of deletes, so to be safe we statically define the directory
|
|
### here.
|
|
# Libvirtd isn't running, check the directory directly.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0478"});
|
|
my $directory = "/etc/libvirt/qemu/networks/autostart";
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }});
|
|
|
|
if (-d $directory)
|
|
{
|
|
# Delete all files.
|
|
local(*DIRECTORY);
|
|
opendir(DIRECTORY, $directory);
|
|
while(my $file = readdir(DIRECTORY))
|
|
{
|
|
next if $file eq ".";
|
|
next if $file eq "..";
|
|
my $full_path = $directory."/".$file;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
|
|
file => $file,
|
|
full_path => $full_path,
|
|
}});
|
|
if (-l $full_path)
|
|
{
|
|
# It's a symlink, remove it.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0479", variables => { 'symlink' => $full_path }});
|
|
unlink $full_path;
|
|
if (-l $full_path)
|
|
{
|
|
# It didn't work...
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 0, priority => "err", key => "error_0132", variables => { 'symlink' => $full_path }});;
|
|
}
|
|
}
|
|
}
|
|
closedir(DIRECTORY);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach my $line (split/\n/, $bridges)
|
|
{
|
|
$line = $anvil->Words->clean_spaces({string => $line});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
|
|
if ($line =~ /^----------/)
|
|
{
|
|
$start = 1;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { start => $start }});
|
|
next;
|
|
}
|
|
next if not $start;
|
|
my $bridge = ($line =~ /(.*?)\s/)[0];
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge => $bridge }});
|
|
|
|
$anvil->data->{virsh}{bridge}{$bridge} = 1;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "virsh::bridge::$bridge" => $anvil->data->{virsh}{bridge}{$bridge} }});
|
|
}
|
|
|
|
foreach my $bridge (sort {$a cmp $b} keys %{$anvil->data->{virsh}{bridge}})
|
|
{
|
|
# Destroy (stop) it.
|
|
my ($destroy, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{virsh}." net-destroy ".$bridge});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { destroy => $destroy, return_code => $return_code }});
|
|
|
|
# Disable it from auto-start.
|
|
(my $disable, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{virsh}." net-autostart ".$bridge." --disable"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { disable => $disable, return_code => $return_code }});
|
|
|
|
# Undefine (delete)
|
|
(my $undefine, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{virsh}." net-undefine ".$bridge});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { undefine => $undefine, return_code => $return_code }});
|
|
}
|
|
}
|
|
|
|
$anvil->Job->update_progress({
|
|
progress => 75,
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
|
|
return(0);
|
|
}
|
|
|
|
# This renames a network interface
|
|
sub rename_interface
|
|
{
|
|
my ($anvil, $old_link_name, $new_link_name) = @_;
|
|
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0465", variables => {
|
|
old_interface => $old_link_name,
|
|
new_interface => $new_link_name,
|
|
}});
|
|
|
|
# Take the old name down.
|
|
my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_link_name." down"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
output => $output,
|
|
return_code => $return_code,
|
|
}});
|
|
|
|
# Rename
|
|
($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{ip}." link set ".$old_link_name." name ".$new_link_name});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
output => $output,
|
|
return_code => $return_code,
|
|
}});
|
|
|
|
# Bring up the new interface
|
|
($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{ip}." link set ".$new_link_name." up"});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => {
|
|
output => $output,
|
|
return_code => $return_code,
|
|
}});
|
|
|
|
return(0);
|
|
}
|
|
|
|
# This will read a network interface file and return the UUID="x" value. If the file doesn't exist or the
|
|
# UUID was not found, a new UUID is generated and returned.
|
|
sub get_uuid_from_interface_file
|
|
{
|
|
my ($anvil, $file) = @_;
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 'print' => 1, key => "log_0131", variables => { function => "get_uuid_from_interface_file" }});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $file }});
|
|
|
|
my $uuid = "";
|
|
if (-e $file)
|
|
{
|
|
my $body = $anvil->Storage->read_file({file => $file});
|
|
foreach my $line (split/\n/, $body)
|
|
{
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
|
|
$line =~ s/#.*//;
|
|
if ($line =~ /UUID=\"(.*?)\"/)
|
|
{
|
|
my $test_uuid = $1;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { test_uuid => $test_uuid }});
|
|
if ($anvil->Validate->uuid({uuid => $test_uuid}))
|
|
{
|
|
$uuid = $test_uuid;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uuid => $uuid }});
|
|
}
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
if (not $uuid)
|
|
{
|
|
$uuid = $anvil->Get->uuid();
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uuid => $uuid }});
|
|
}
|
|
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uuid => $uuid }});
|
|
return($uuid);
|
|
}
|
|
|
|
# This will pick up the job, or exit.
|
|
sub pickup_job_details
|
|
{
|
|
my ($anvil) = @_;
|
|
|
|
# If this returns '1', the job-uuid was bad. If it returns '2', another process is running.
|
|
my $return = $anvil->Job->get_job_details({
|
|
check => 1,
|
|
job_uuid => $anvil->data->{switches}{'job-uuid'},
|
|
});
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }});
|
|
if ($return == 1)
|
|
{
|
|
# It's not a valid UUID.
|
|
$anvil->nice_exit({exit_code => 6});
|
|
}
|
|
if ($return == 2)
|
|
{
|
|
# This job is being handled by another process that is still alive.
|
|
$anvil->nice_exit({exit_code => 3});
|
|
}
|
|
|
|
# Still alive? Good.
|
|
my $job_picked_up_by = $anvil->data->{jobs}{job_picked_up_by};
|
|
my $job_progress = $anvil->data->{jobs}{job_progress};
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
|
|
job_picked_up_by => $job_picked_up_by,
|
|
job_progress => $job_progress,
|
|
}});
|
|
|
|
# See if the job was picked up by another running instance.
|
|
if ($job_picked_up_by)
|
|
{
|
|
# The previous job is gone if we're still alive, we'll take this over.
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, 'print' => 1, key => "log_0147", variables => {
|
|
pid => $job_picked_up_by,
|
|
percent => $job_progress,
|
|
}});
|
|
}
|
|
|
|
# This will store the variables from the database
|
|
$anvil->data->{variables} = {};
|
|
|
|
# If we're still alive, pick up the details.
|
|
my $query = "
|
|
SELECT
|
|
variable_name,
|
|
variable_value
|
|
FROM
|
|
variables
|
|
WHERE
|
|
variable_name
|
|
LIKE
|
|
'form::config_step%'
|
|
AND
|
|
variable_source_table = 'hosts'
|
|
AND
|
|
variable_source_uuid = ".$anvil->Database->quote($anvil->data->{sys}{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,
|
|
}});
|
|
foreach my $row (@{$results})
|
|
{
|
|
my $this_variable = $row->[0];
|
|
my $this_value = $row->[1];
|
|
my $secure = $this_variable =~ /passw/ ? 1 : 0;
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
|
|
's1:this_variable' => $this_variable,
|
|
's2:this_value' => $anvil->Log->is_secure($this_value),
|
|
}});
|
|
|
|
$anvil->_make_hash_reference($anvil->data->{variables}, $this_variable, $this_value);
|
|
}
|
|
|
|
# Clear previous data
|
|
$anvil->Job->update_progress({
|
|
progress => 0,
|
|
message => "clear",
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
|
|
# Record that we've picked up this job.
|
|
$anvil->Job->update_progress({
|
|
progress => 1,
|
|
message => "message_0015",
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
|
|
# If we're in a cluster, abort.
|
|
if (-e $anvil->data->{path}{exe}{pcs})
|
|
{
|
|
my ($problem) = $anvil->Cluster->parse_cib();
|
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
|
|
if ((not $problem) && ($anvil->data->{cib}{parsed}{'local'}{ready}))
|
|
{
|
|
# We're in a cluster, abort.
|
|
$anvil->Job->update_progress({
|
|
progress => 100,
|
|
message => "error_0250",
|
|
job_uuid => $anvil->data->{job}{uuid},
|
|
});
|
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0250"});
|
|
$anvil->nice_exit({exit_code => 7});
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|