From 52e7875252089bd1280387fe32b27e3358fabd52 Mon Sep 17 00:00:00 2001 From: digimer Date: Tue, 23 Jan 2024 01:18:21 -0500 Subject: [PATCH 01/43] Bumoed logging to find '!!error!!' related parsing errors. Signed-off-by: digimer --- Anvil/Tools/Email.pm | 2 +- Anvil/Tools/Job.pm | 4 ++-- scancore-agents/scan-server/scan-server | 1 + tools/anvil-daemon | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Anvil/Tools/Email.pm b/Anvil/Tools/Email.pm index e0d9add2..55b49c82 100644 --- a/Anvil/Tools/Email.pm +++ b/Anvil/Tools/Email.pm @@ -487,9 +487,9 @@ sub send_alerts if ($alert_title) { my $title = "[ ".$alert_set_by." ] ".$anvil->Words->parse_banged_string({ + debug => $debug, language => $recipient_language, key_string => $alert_title, - }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { title => $title }}); diff --git a/Anvil/Tools/Job.pm b/Anvil/Tools/Job.pm index 460ca803..37df8cac 100644 --- a/Anvil/Tools/Job.pm +++ b/Anvil/Tools/Job.pm @@ -501,8 +501,8 @@ sub html_list } # Convert the double-banged strings into a proper message. - my $say_title = $job_title ? $anvil->Words->parse_banged_string({key_string => $job_title}) : ""; - my $say_description = $job_description ? $anvil->Words->parse_banged_string({key_string => $job_description}) : ""; + my $say_title = $job_title ? $anvil->Words->parse_banged_string({debug => $debug, key_string => $job_title}) : ""; + my $say_description = $job_description ? $anvil->Words->parse_banged_string({debug => $debug, key_string => $job_description}) : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { job_title => $job_title, say_description => $say_description, diff --git a/scancore-agents/scan-server/scan-server b/scancore-agents/scan-server/scan-server index b3233196..3e8d0cfe 100755 --- a/scancore-agents/scan-server/scan-server +++ b/scancore-agents/scan-server/scan-server @@ -856,6 +856,7 @@ sub collect_data new_anvil_name => $anvil->Get->anvil_name_from_uuid({anvil_uuid => $server_anvil_uuid}), new_anvil_uuid => $server_anvil_uuid, }; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0009", variables => $variables}); $anvil->Alert->register({alert_level => "notice", message => "scan_server_alert_0009", variables => $variables, set_by => $THIS_FILE}); $update = 1; diff --git a/tools/anvil-daemon b/tools/anvil-daemon index eeea2e2e..d9211655 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -1793,9 +1793,9 @@ sub run_jobs } # Convert the double-banged strings into a proper message. - my $say_title = $job_title ? $anvil->Words->parse_banged_string({key_string => $job_title}) : ""; - my $say_description = $job_description ? $anvil->Words->parse_banged_string({key_string => $job_description}) : ""; - my $say_status = $job_status ? $anvil->Words->parse_banged_string({key_string => $job_status}) : ""; + my $say_title = $job_title ? $anvil->Words->parse_banged_string({debug => 2, key_string => $job_title}) : ""; + my $say_description = $job_description ? $anvil->Words->parse_banged_string({debug => 2, key_string => $job_description}) : ""; + my $say_status = $job_status ? $anvil->Words->parse_banged_string({debug => 2, key_string => $job_status}) : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { job_title => $job_title, say_description => $say_description, From fb363b5b6cc6fcb57e31c33bd8631c4fc0bc6d67 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 29 Nov 2023 18:04:13 -0500 Subject: [PATCH 02/43] Increased logging for debugging issue #339 Signed-off-by: digimer --- tools/anvil-watch-servers | 2 +- tools/fence_pacemaker | 16 ++++++++-------- tools/unfence_pacemaker | 16 ++++++++-------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tools/anvil-watch-servers b/tools/anvil-watch-servers index dbcf4acb..28a5183e 100755 --- a/tools/anvil-watch-servers +++ b/tools/anvil-watch-servers @@ -132,7 +132,7 @@ sub show_status if ($anvil->data->{switches}{watch}) { my $date = $anvil->Get->date_and_time(); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "message_0382", variables => { date => $date }}); + print $anvil->Words->string({key => "message_0382", variables => { date => $date }})."\n"; } print $anvil->data->{display}{status}; diff --git a/tools/fence_pacemaker b/tools/fence_pacemaker index 352656bf..325b4276 100755 --- a/tools/fence_pacemaker +++ b/tools/fence_pacemaker @@ -192,19 +192,19 @@ sub create_constraint my $rule_found = 0; my $rule_name = "drbd-fenced_".$target_server; my $shell_call = $conf->{path}{exe}{pcs}." constraint location config show ".$target_server; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); if ($line =~ /Expression: $rule_name /) { $rule_found = 1; - to_log($conf, {message => "rule_found: [".$rule_found."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "rule_found: [".$rule_found."]", 'line' => __LINE__, level => 1}); last; } } @@ -220,14 +220,14 @@ sub create_constraint # Set the node attribute my $rule_set = 0; $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --update 1"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); } close $file_handle; @@ -235,19 +235,19 @@ sub create_constraint $rule_set = 0; my $rule_output = ""; $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --query"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); if (($line =~ /name=$rule_name/) && ($line =~ /value=1/)) { $rule_set = 1; - to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 1}); last; } else diff --git a/tools/unfence_pacemaker b/tools/unfence_pacemaker index 1d26103c..75cae101 100755 --- a/tools/unfence_pacemaker +++ b/tools/unfence_pacemaker @@ -158,19 +158,19 @@ sub remove_constraint my $rule_found = 0; my $rule_output = ""; my $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --query"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); if (($line =~ /name=$rule_name/) && ($line =~ /value=0/)) { $rule_set = 0; - to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 1}); last; } else @@ -189,33 +189,33 @@ sub remove_constraint # Clear the node attribute $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --update 0"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 3}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); } close $file_handle; # Check that the rule was set. $rule_output = ""; $shell_call = $conf->{path}{exe}{crm_attribute}." --type nodes --node ".$target_node." --name ".$rule_name." --query"; - to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 1}); open ($file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n"; while(<$file_handle>) { # This should not generate output. chomp; my $line = $_; - to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "Output: [".$line."]", 'line' => __LINE__, level => 1}); if (($line =~ /name=$rule_name/) && ($line =~ /value=0/)) { $rule_set = 0; - to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 2}); + to_log($conf, {message => "rule_set: [".$rule_set."]", 'line' => __LINE__, level => 1}); last; } else From f575507c1e16514e5186070a4be73099d2cc53f0 Mon Sep 17 00:00:00 2001 From: digimer Date: Tue, 5 Dec 2023 16:42:34 -0500 Subject: [PATCH 03/43] This begins adding support for EL9. * Added the 'hostname' and 'hostnamectl --transient' to Get->host_name(). * Updated Database->insert_or_update_hosts() to log when no host_name, host_type or host_uuid is not passed. Signed-off-by: digimer --- Anvil/Tools.pm | 1 + Anvil/Tools/Database.pm | 37 ++++++++++++++++++++++++++++--------- Anvil/Tools/Get.pm | 19 +++++++++++++++++++ tools/anvil-check-memory | 6 +++--- tools/anvil-version-changes | 6 +++--- 5 files changed, 54 insertions(+), 15 deletions(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 5862c090..ee8de4be 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1210,6 +1210,7 @@ sub _set_paths 'grep' => "/usr/bin/grep", groupadd => "/usr/sbin/groupadd", head => "/usr/bin/head", + hostname => "/usr/bin/hostname", hostnamectl => "/usr/bin/hostnamectl", hpacucli => "/usr/sbin/hpacucli", htpasswd => "/usr/bin/htpasswd", diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index a7002d58..3e0903b2 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -9606,9 +9606,9 @@ sub insert_or_update_hosts my $line = defined $parameter->{line} ? $parameter->{line} : ""; my $host_ipmi = defined $parameter->{host_ipmi} ? $parameter->{host_ipmi} : ""; my $host_key = defined $parameter->{host_key} ? $parameter->{host_key} : ""; - my $host_name = defined $parameter->{host_name} ? $parameter->{host_name} : $anvil->Get->host_name; - my $host_type = defined $parameter->{host_type} ? $parameter->{host_type} : $anvil->Get->host_type; - my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid; + my $host_name = defined $parameter->{host_name} ? $parameter->{host_name} : ""; + my $host_type = defined $parameter->{host_type} ? $parameter->{host_type} : ""; + my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : ""; my $host_status = defined $parameter->{host_status} ? $parameter->{host_status} : "no_change"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid, @@ -9624,15 +9624,34 @@ sub insert_or_update_hosts if (not $host_name) { - # Throw an error and exit. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_hosts()", parameter => "host_name" }}); - return(""); + # Can we get it? + $host_name = $anvil->Get->host_name({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }}); + + if (not $host_name) + { + # Throw an error and exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_hosts()", parameter => "host_name" }}); + return(""); + } + } + if (not $host_type) + { + $host_type = $anvil->Get->host_type({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }}); } if (not $host_uuid) { - # Throw an error and exit. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_hosts()", parameter => "host_uuid" }}); - return(""); + # Can we get it? + $host_uuid = $anvil->Get->host_uuid({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }}); + + if (not $host_uuid) + { + # Throw an error and exit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_hosts()", parameter => "host_uuid" }}); + return(""); + } } # If we're looking at ourselves and we don't have the host_key, read it in. diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 29e8204a..39c4ccfa 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -1513,10 +1513,29 @@ sub host_name { # Failed to read the file, too. What the hell? Exit out. print "Failed to query the hostname using 'hostnamectl --static' and failed to read the content of: [".$anvil->data->{path}{configs}{hostname}."]. Something is very wrong, exiting.\n"; + $anvil->nice_exit({exit_code => 1}); } } else { + # Did we get a real answer? If it's "unet", the string will be emtpy. + if (not $host_name) + { + # Try seeing if there is a transient hostname. + ($host_name, my $return_code) = $anvil->System->call({debug => 9999, shell_call => $anvil->data->{path}{exe}{hostnamectl}." --transient"}); + if (not $host_name) + { + # OK, can we get it from the 'hostname' command? + ($host_name, my $return_code) = $anvil->System->call({debug => 9999, shell_call => $anvil->data->{path}{exe}{hostname}}); + if (not $host_name) + { + # Failed to find the hostname at all. + print "Failed to query the hostname using 'hostnamectl --static', 'hostnamectl --transient' or 'hostname'. Something is very wrong, exiting.\n"; + $anvil->nice_exit({exit_code => 1}); + } + } + } + # Cache the answer $anvil->data->{sys}{host_name} = $host_name; } diff --git a/tools/anvil-check-memory b/tools/anvil-check-memory index 971ade0a..acf0bb72 100755 --- a/tools/anvil-check-memory +++ b/tools/anvil-check-memory @@ -84,7 +84,7 @@ foreach my $pid (sort {$a cmp $b} @{$anvil->data->{sys}{pids}}) { my $size = $1; my $type = $2; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type => $type, size => $size, }}); @@ -94,10 +94,10 @@ foreach my $pid (sort {$a cmp $b} @{$anvil->data->{sys}{pids}}) # This uses 'kB' for 'KiB' >_> $type = lc($type); $type =~ s/b$/ib/ if $type !~ /ib$/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type => $type }}); my $size_in_bytes = $anvil->Convert->human_readable_to_bytes({size => $size, type => $type, base2 => 1}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { size_in_bytes => $anvil->Convert->add_commas({number => $size_in_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size_in_bytes}).")", }}); diff --git a/tools/anvil-version-changes b/tools/anvil-version-changes index c49176e9..d1932520 100755 --- a/tools/anvil-version-changes +++ b/tools/anvil-version-changes @@ -63,12 +63,12 @@ sub striker_checks { my ($anvil) = @_; + # This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists. + update_file_location_ready($anvil); + # This checks to make sure that the new dr_links table exists, and that existing anvil_dr1_host_uuid # entries are copied. update_dr_links($anvil); - - # This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists. - update_file_location_ready($anvil); # This replaces anvil_uuid with host_uuid to support more granular location info to support the new # multi-target DR system From 9cbb5c1f52c28c3b8816c37fb3c6e3e9104def09 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 6 Dec 2023 00:13:48 -0500 Subject: [PATCH 04/43] Got the data collection done for the new anvil-monitor-network tool. Signed-off-by: digimer --- tools/anvil-monitor-network | 201 ++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100755 tools/anvil-monitor-network diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network new file mode 100755 index 00000000..07f70b74 --- /dev/null +++ b/tools/anvil-monitor-network @@ -0,0 +1,201 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Data::Dumper; +use Sys::Virt; +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({list => [], man => $THIS_FILE}); +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); + +# We'll try to connect in case we're adding additional peers. +$anvil->Database->connect({debug => 3}); +$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); + +print "DBs: [".$anvil->data->{sys}{database}{connections}."]\n"; + +scan($anvil); + + + +############################################################################################################# +# Functions # +############################################################################################################# + +sub scan +{ + my ($anvil) = @_; + + # Get a list of interfaces. + get_interfaces($anvil); + + + return(0); +} + +sub get_interfaces +{ + my ($anvil) = @_; + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type connection show"; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^(.*?):(.*?)$/) + { + my $uuid = $1; + my $type = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + uuid => $uuid, + type => $type, + }}); + next if $type eq "loopback"; + + $anvil->data->{interface}{uuid}{$uuid}{type} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + uuid => $uuid, + type => $type, + }}); + } + } + + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{interface}{uuid}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); + + # Collect all the rest of the data now. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection show ".$uuid; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); + if ($line =~ /^(.*?):\s+(.*)$/) + { + my $variable = $1; + my $value = $2; + $anvil->data->{interface}{uuid}{$uuid}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${variable}" => $anvil->data->{interface}{uuid}{$uuid}{$variable}, + }}); + } + } + } + + # Now loop through and look for the name that maps to what's shown in 'ip addr list'. This can be a bit tricky. + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{interface}{uuid}}) + { + my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} // ""; + my $general_devices = $anvil->data->{interface}{uuid}{$uuid}{'GENERAL.DEVICES'} // ""; + my $device = $connection_interface_name ne "--" ? $connection_interface_name : $general_devices; + my $name = + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:uuid' => $uuid, + 's2:connection_interface_name' => $connection_interface_name, + 's3:general_devices' => $general_devices, + 's4:device' => $device, + }}); + + if ($device) + { + $anvil->data->{interface}{device}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::device::${device}::uuid" => $anvil->data->{interface}{device}{$device}{uuid}, + }}); + + ### Get some data from sysfs. + $anvil->data->{interface}{uuid}{$uuid}{mac_address} = ""; + $anvil->data->{interface}{uuid}{$uuid}{type} = ""; + $anvil->data->{interface}{uuid}{$uuid}{mtu} = 0; + + # MAC address + my $mac_address_file = "/sys/class/net/".$device."/address"; + my $type_file = "/sys/class/net/".$device."/type"; + my $mtu_file = "/sys/class/net/".$device."/mtu"; + if (-e $mac_address_file) + { + my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); + $mac_address =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + + if (($mac_address) && ($mac_address ne "!!error!!")) + { + $anvil->data->{interface}{uuid}{$uuid}{mac_address} = $mac_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::mac_address" => $anvil->data->{interface}{uuid}{$uuid}{mac_address}, + }}); + } + } + if (-e $type_file) + { + my $type = $anvil->Storage->read_file({file => $type_file}); + $type =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + + if (($type) && ($type ne "!!error!!")) + { + $anvil->data->{interface}{uuid}{$uuid}{type} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::type" => $anvil->data->{interface}{uuid}{$uuid}{type}, + }}); + } + } + if (-e $mtu_file) + { + my $mtu = $anvil->Storage->read_file({file => $mtu_file}); + $mtu =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mtu => $mtu }}); + + if (($mtu) && ($mtu ne "!!error!!")) + { + $anvil->data->{interface}{uuid}{$uuid}{mtu} = $mtu; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::mtu" => $anvil->data->{interface}{uuid}{$uuid}{mtu}, + }}); + } + } + } + } + + # Now lets confirm we got all the interfaces, including the down'ed ones. + foreach my $device (sort {$a cmp $b} keys %{$anvil->data->{interface}{device}}) + { + my $uuid = $anvil->data->{interface}{device}{$device}{uuid}; + my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; + my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; + my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; + my $mtu_type = $anvil->data->{interface}{uuid}{$uuid}{'802-3-ethernet.mtu'}; + my $mtu = $anvil->data->{interface}{uuid}{$uuid}{mtu}; + + print "- Device: [".$device."], UUID: [".$uuid."], name: [".$name."]\n"; + print " - MAC: [".$mac_address."], Type: [".$type."], MTU: [".$mtu."] MTU type: [".$mtu_type."]\n"; + } + + return(0); +} From 1f88abda0486d2628a987b10ac5050e9200b4be8 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 13 Dec 2023 19:04:30 -0500 Subject: [PATCH 05/43] * Further work done on anvil-monitor-network Signed-off-by: digimer --- share/anvil.sql | 84 +++++++++- tools/anvil-monitor-network | 296 +++++++++++++++++++++++++++++++++--- 2 files changed, 359 insertions(+), 21 deletions(-) diff --git a/share/anvil.sql b/share/anvil.sql index ea6de393..a6156bf1 100644 --- a/share/anvil.sql +++ b/share/anvil.sql @@ -1096,7 +1096,7 @@ CREATE TRIGGER trigger_network_interfaces CREATE TABLE ip_addresses ( ip_address_uuid uuid not null primary key, ip_address_host_uuid uuid not null, - ip_address_on_type text not null, -- Either 'interface', 'bond' or 'bridge' + ip_address_on_type text not null, -- Either 'interface', 'bond', 'bridge' or 'network_manager' ip_address_on_uuid uuid not null, -- This is the UUID of the interface, bond or bridge that has this IP ip_address_address text not null, -- The actual IP address ip_address_subnet_mask text not null, -- The subnet mask (in dotted decimal format) @@ -1167,6 +1167,88 @@ CREATE TRIGGER trigger_ip_addresses FOR EACH ROW EXECUTE PROCEDURE history_ip_addresses(); +-- This stores information about network interfaces on hosts. It is mainly used to match a MAC address to a +-- host. Given that it is possible that network devices can move, the linkage to the host_uuid can change. +CREATE TABLE network_manager ( + network_manager_uuid uuid not null primary key, -- Unlike most other tables, this UUID comes from nmcli itself, and so this matches what's displayed nmcli + network_manager_host_uuid uuid not null, -- The host_uuid for this interface + network_manager_device text not null, -- This is the nmcli "device" name + network_manager_name text not null, -- This is the nmcli "name" name + network_manager_mac text not null, -- This is the MAC address of the interface + network_manager_type text not null, -- This is the nmcli "type" string + network_manager_active text not null, -- This is the nmcli "active" field + network_manager_state text not null, -- This is the nmcli "state" field + network_manager_connected numeric not null, -- This is '0' if the connection is down, or a unix timestamp if it's up. + network_manager_mtu numeric not null, -- This is the MTU of the interface + modified_date timestamp with time zone not null, + + FOREIGN KEY(network_manager_host_uuid) REFERENCES hosts(host_uuid) + ); +ALTER TABLE network_manager OWNER TO admin; + +CREATE TABLE history.network_manager ( + history_id bigserial, + network_manager_uuid uuid not null, + network_manager_host_uuid uuid, + network_manager_mac_address text, + network_manager_name text, + network_manager_speed bigint, + network_manager_mtu bigint, + network_manager_link_state text, + network_manager_operational text, + network_manager_duplex text, + network_manager_medium text, + network_manager_bond_uuid uuid, + network_manager_bridge_uuid uuid, + modified_date timestamp with time zone not null +); +ALTER TABLE history.network_manager OWNER TO admin; + +CREATE FUNCTION history_network_manager() RETURNS trigger +AS $$ +DECLARE + history_network_manager RECORD; +BEGIN + SELECT INTO history_network_manager * FROM network_manager WHERE network_manager_uuid = new.network_manager_uuid; + INSERT INTO history.network_manager + (network_manager_uuid, + network_manager_host_uuid, + network_manager_mac_address, + network_manager_name, + network_manager_speed, + network_manager_mtu, + network_manager_link_state, + network_manager_operational, + network_manager_duplex, + network_manager_medium, + network_manager_bond_uuid, + network_manager_bridge_uuid, + modified_date) + VALUES + (history_network_manager.network_manager_uuid, + history_network_manager.network_manager_host_uuid, + history_network_manager.network_manager_mac_address, + history_network_manager.network_manager_name, + history_network_manager.network_manager_speed, + history_network_manager.network_manager_mtu, + history_network_manager.network_manager_link_state, + history_network_manager.network_manager_operational, + history_network_manager.network_manager_duplex, + history_network_manager.network_manager_medium, + history_network_manager.network_manager_bond_uuid, + history_network_manager.network_manager_bridge_uuid, + history_network_manager.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_network_manager() OWNER TO admin; + +CREATE TRIGGER trigger_network_manager + AFTER INSERT OR UPDATE ON network_manager + FOR EACH ROW EXECUTE PROCEDURE history_network_manager(); + + -- This stores files made available to Anvil! systems and DR hosts. CREATE TABLE files ( file_uuid uuid not null primary key, diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network index 07f70b74..f27f544b 100755 --- a/tools/anvil-monitor-network +++ b/tools/anvil-monitor-network @@ -27,7 +27,28 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure = $anvil->Database->connect({debug => 3}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); -print "DBs: [".$anvil->data->{sys}{database}{connections}."]\n"; +#print "DBs: [".$anvil->data->{sys}{database}{connections}."]\n"; + +$anvil->data->{network_manager}{want}{ifn1_link1}{mac_address} = "52:54:00:d3:19:cc"; +$anvil->data->{network_manager}{want}{ifn1_link1}{device} = "enp1s0"; +$anvil->data->{network_manager}{want}{ifn1_link1}{found} = 0; +$anvil->data->{network_manager}{want}{ifn1_link2}{mac_address} = "52:54:00:fc:82:b0"; +$anvil->data->{network_manager}{want}{ifn1_link2}{device} = "enp7s0"; +$anvil->data->{network_manager}{want}{ifn1_link2}{found} = 0; + +$anvil->data->{network_manager}{want}{bcn1_link1}{mac_address} = "52:54:00:86:f5:1d"; +$anvil->data->{network_manager}{want}{bcn1_link1}{device} = "enp8s0"; +$anvil->data->{network_manager}{want}{bcn1_link1}{found} = 0; +$anvil->data->{network_manager}{want}{bcn1_link2}{mac_address} = "52:54:00:16:c5:33"; +$anvil->data->{network_manager}{want}{bcn1_link2}{device} = "enp9s0"; +$anvil->data->{network_manager}{want}{bcn1_link2}{found} = 0; + +$anvil->data->{network_manager}{want}{sn1_link1}{mac_address} = "52:54:00:37:6f:22"; +$anvil->data->{network_manager}{want}{sn1_link1}{device} = "enp10s0"; +$anvil->data->{network_manager}{want}{sn1_link1}{found} = 0; +$anvil->data->{network_manager}{want}{sn1_link2}{mac_address} = "52:54:00:2f:02:1b"; +$anvil->data->{network_manager}{want}{sn1_link2}{device} = "enp11s0"; +$anvil->data->{network_manager}{want}{sn1_link2}{found} = 0; scan($anvil); @@ -52,7 +73,7 @@ sub get_interfaces { my ($anvil) = @_; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type connection show"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type,active,state connection show"; $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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { @@ -63,20 +84,27 @@ sub get_interfaces foreach my $line (split/\n/, $output) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /^(.*?):(.*?)$/) + if ($line =~ /^(.*?):(.*?):(.*?):(.*?)$/) { - my $uuid = $1; - my $type = $2; + my $uuid = $1; + my $type = $2; + my $active = $3; + my $state = $4; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - uuid => $uuid, - type => $type, + uuid => $uuid, + type => $type, + active => $active, + 'state' => $state, }}); next if $type eq "loopback"; - $anvil->data->{interface}{uuid}{$uuid}{type} = $type; + $anvil->data->{interface}{uuid}{$uuid}{type} = $type; + $anvil->data->{interface}{uuid}{$uuid}{active} = lc($active) eq "yes" ? 1 : 0; + $anvil->data->{interface}{uuid}{$uuid}{'state'} = lc($state); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - uuid => $uuid, - type => $type, + "interface::uuid::${uuid}::type" => $anvil->data->{interface}{uuid}{$uuid}{type}, + "interface::uuid::${uuid}::active" => $anvil->data->{interface}{uuid}{$uuid}{active}, + "interface::uuid::${uuid}::state" => $anvil->data->{interface}{uuid}{$uuid}{'state'}, }}); } } @@ -104,6 +132,117 @@ sub get_interfaces $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface::uuid::${uuid}::${variable}" => $anvil->data->{interface}{uuid}{$uuid}{$variable}, }}); + + if ($variable =~ /IP(\d).ADDRESS\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, + }}); + + if (($ip_type == 4) && ($value =~ /^(.*?)\/(.*)$/)) + { + my $ip_address = $1; + my $subnet_mask = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_address => $ip_address, + subnet_mask => $subnet_mask, + }}); + + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $1; + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, + "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, + }}); + } + else + { + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $value; + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, + "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, + }}); + } + + # Make sure the DNS key exists. + if (not exists $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns}) + { + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{interface}{uuid}{$uuid}{$sequence}{dns}, + }}); + } + if (not exists $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway}) + { + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{interface}{uuid}{$uuid}{$sequence}{gateway}, + }}); + } + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway} = $value; + } + if ($variable =~ /IP(\d).ROUTE\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, + }}); + + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{route}{$sequence} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${hash_key}::route::${sequence}" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{route}{$sequence}, + }}); + } + if ($variable =~ /IP(\d).DNS\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, + }}); + + if ((exists $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns}) and ($anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} ne "")) + { + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} .= ",".$value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{interface}{uuid}{$uuid}{$sequence}{dns}, + }}); + } + else + { + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns}, + }}); + } + } + if ($variable =~ /IP(\d).GATEWAY/) + { + my $ip_type = $1; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + hash_key => $hash_key, + }}); + + $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway}, + }}); + } } } } @@ -134,6 +273,13 @@ sub get_interfaces $anvil->data->{interface}{uuid}{$uuid}{type} = ""; $anvil->data->{interface}{uuid}{$uuid}{mtu} = 0; + # The 'connection.timestamp' seems to be where the 'connected' (as in, have an IP) + # comes from. + $anvil->data->{interface}{uuid}{$uuid}{connected} = $anvil->data->{interface}{uuid}{$uuid}{'connection.timestamp'} ? $anvil->data->{interface}{uuid}{$uuid}{'connection.timestamp'} : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::connected" => $anvil->data->{interface}{uuid}{$uuid}{connected}, + }}); + # MAC address my $mac_address_file = "/sys/class/net/".$device."/address"; my $type_file = "/sys/class/net/".$device."/type"; @@ -146,9 +292,11 @@ sub get_interfaces if (($mac_address) && ($mac_address ne "!!error!!")) { - $anvil->data->{interface}{uuid}{$uuid}{mac_address} = $mac_address; + $anvil->data->{interface}{uuid}{$uuid}{mac_address} = $mac_address; + $anvil->data->{interface}{mac_address}{$mac_address}{uuid} = $uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::mac_address" => $anvil->data->{interface}{uuid}{$uuid}{mac_address}, + "interface::uuid::${uuid}::mac_address" => $anvil->data->{interface}{uuid}{$uuid}{mac_address}, + "interface::mac_address::${mac_address}::uuid" => $anvil->data->{interface}{mac_address}{$mac_address}{uuid}, }}); } } @@ -186,15 +334,123 @@ sub get_interfaces # Now lets confirm we got all the interfaces, including the down'ed ones. foreach my $device (sort {$a cmp $b} keys %{$anvil->data->{interface}{device}}) { - my $uuid = $anvil->data->{interface}{device}{$device}{uuid}; - my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; - my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; - my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; - my $mtu_type = $anvil->data->{interface}{uuid}{$uuid}{'802-3-ethernet.mtu'}; - my $mtu = $anvil->data->{interface}{uuid}{$uuid}{mtu}; + my $uuid = $anvil->data->{interface}{device}{$device}{uuid}; + my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; + my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; + my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; + my $mtu_type = $anvil->data->{interface}{uuid}{$uuid}{'802-3-ethernet.mtu'}; + my $mtu = $anvil->data->{interface}{uuid}{$uuid}{mtu}; + my $active = $anvil->data->{interface}{uuid}{$uuid}{active}; + my $state = $anvil->data->{interface}{uuid}{$uuid}{'state'}; + my $connected = $anvil->data->{interface}{uuid}{$uuid}{connected}; + my $ipv4_dns = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{dns} // "--"; + my $ipv4_gateway = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{gateway} // "--"; + my $ip_count = keys %{$anvil->data->{interface}{uuid}{$uuid}{ipv4}{ip}}; + my $route_count = keys %{$anvil->data->{interface}{uuid}{$uuid}{ipv4}{route}}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s01:device" => $device, + "s02:uuid" => $uuid, + "s03:name" => $name, + "s04:mac_address" => $mac_address, + "s05:type" => $type, + "s06:mtu_type" => $mtu_type, + "s07:active" => $active, + "s08:state" => $state, + "s09:connected" => $connected, + "s10:ipv4_dns" => $ipv4_dns, + "s11:ipv4_gateway" => $ipv4_gateway, + "s12:ip_count" => $ip_count, + "s13:route_count" => $route_count, + }}); + + print "- Device: [".$device."], Name: [".$name."], MAC: [".$mac_address."], UUID: [".$uuid."]\n"; +# $anvil->data->{network_manager}{want}{ifn1_link1}{mac_address} = "52:54:00:d3:19:cc"; +# $anvil->data->{network_manager}{want}{ifn1_link1}{device} = "enp1s0"; +# $anvil->data->{network_manager}{want}{ifn1_link1}{found} = 0; + if (exists $anvil->data->{network_manager}{want}{$device}) + { + # We know this device. Does it match the expected MAC address? + my $wanted_mac_address = $anvil->data->{network_manager}{want}{ifn1_link1}{mac_address}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wanted_mac_address => $wanted_mac_address }}); + if (lc($wanted_mac_address) eq lc($mac_address)) + { + print " - Interface is configured as desired.\n"; + } + else + { + print " - The MAC address doesn't match the desired MAC address!\n"; + } + } + else + { + print " - This interface isn't one of the matched ones. Check if this should be reconfigured.\n"; + my $reconfigure_to = ""; + foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}}) + { + my $wanted_device = $anvil->data->{network_manager}{want}{$wanted_interface}{device}; + my $wanted_mac_address = $anvil->data->{network_manager}{want}{$wanted_interface}{mac_address}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + wanted_interface => $wanted_interface, + wanted_device => $wanted_device, + wanted_mac_address => $wanted_mac_address, + }}); + + # If this device already exists, skip it. + if (exists $anvil->data->{interface}{device}{$wanted_interface}) + { + next; + } + + if ($mac_address eq $wanted_mac_address) + { + # MAC address always takes priority. + $reconfigure_to = $wanted_interface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reconfigure_to => $reconfigure_to }}); + next; + } + elsif ((not $reconfigure_to) && ($wanted_device eq $name)) + { + $reconfigure_to = $wanted_interface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reconfigure_to => $reconfigure_to }}); + next; + } + } + if ($reconfigure_to) + { + # Reconfigure! + print " - This should be: [".$reconfigure_to."]\n"; + } + } - print "- Device: [".$device."], UUID: [".$uuid."], name: [".$name."]\n"; - print " - MAC: [".$mac_address."], Type: [".$type."], MTU: [".$mtu."] MTU type: [".$mtu_type."]\n"; + #print "- Device: [".$device."], UUID: [".$uuid."], name: [".$name."], state: [".$active."], active?: [".$active."], state: [".$state."], connected: [".$connected."]\n"; + #print " - MAC: [".$mac_address."], Type: [".$type."], MTU: [".$mtu."] MTU type: [".$mtu_type."], IPv4 DNS: [".$ipv4_dns."], Gateway: [".$ipv4_gateway."], IPs: [".$ip_count."], routes: [".$route_count."]\n"; + if ($ip_count) + { + foreach my $sequence (sort {$a <=> $b} keys %{$anvil->data->{interface}{uuid}{$uuid}{ipv4}{ip}}) + { + my $ip_address = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{ip}{$sequence}{ip_address}; + my $subnet_mask = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{ip}{$sequence}{subnet_mask}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:sequence" => $sequence, + "s2:ip_address" => $ip_address, + "s3:subnet_mask" => $subnet_mask, + }}); + print " - ".$sequence.": IPv4 IP: [".$ip_address."], subnet mask: [".$subnet_mask."]\n"; + } + } + if ($route_count) + { + foreach my $sequence (sort {$a <=> $b} keys %{$anvil->data->{interface}{uuid}{$uuid}{ipv4}{route}}) + { + my $route = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{route}{$sequence}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:sequence" => $sequence, + "s2:route" => $route, + }}); + #print " - ".$sequence.": Route: [".$route."]\n"; + } + } + #print "--------\n"; } return(0); From a038a1c55383e5be9f978a0f15ee24d54245938c Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 14 Dec 2023 22:01:55 -0500 Subject: [PATCH 06/43] Got anvil-monitor-network successfully renaming interfaces. Signed-off-by: digimer --- Anvil/Tools.pm | 2 + tools/anvil-monitor-network | 208 ++++++++++++++++++++++++++++++++++-- 2 files changed, 202 insertions(+), 8 deletions(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index ee8de4be..27096462 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1069,6 +1069,7 @@ sub _set_paths 'journald.conf' => "/etc/systemd/journald.conf", 'logind.conf' => "/etc/systemd/logind.conf", 'lvm.conf' => "/etc/lvm/lvm.conf", + 'persistent-net' => "/etc/udev/rules.d/70-persistent-net.rules", 'pg_hba.conf' => "/var/lib/pgsql/data/pg_hba.conf", 'postgresql.conf' => "/var/lib/pgsql/data/postgresql.conf", pxe_default => "/var/lib/tftpboot/pxelinux.cfg/default", @@ -1195,6 +1196,7 @@ sub _set_paths df => "/usr/bin/df", dmidecode => "/usr/sbin/dmidecode", dnf => "/usr/bin/dnf", + dracut => "/usr/bin/dracut", drbdadm => "/usr/sbin/drbdadm", drbdsetup => "/usr/sbin/drbdsetup", dropdb => "/usr/bin/dropdb", diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network index f27f544b..924f8318 100755 --- a/tools/anvil-monitor-network +++ b/tools/anvil-monitor-network @@ -3,7 +3,7 @@ use strict; use warnings; use Data::Dumper; -use Sys::Virt; +use Text::Diff; use Anvil::Tools; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; @@ -50,14 +50,201 @@ $anvil->data->{network_manager}{want}{sn1_link2}{mac_address} = "52:54:00:2f:02 $anvil->data->{network_manager}{want}{sn1_link2}{device} = "enp11s0"; $anvil->data->{network_manager}{want}{sn1_link2}{found} = 0; +$anvil->data->{sys}{reboot_needed} = 0; + scan($anvil); +reconfigure($anvil); + +$anvil->nice_exit({exit_code => 0}); ############################################################################################################# # Functions # ############################################################################################################# +sub reconfigure +{ + my ($anvil) = @_; + + my $reconfigure_count = keys %{$anvil->data->{network_manager}{reconfigure}}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reconfigure_count => $reconfigure_count }}); + if (not $reconfigure_count) + { + return(0); + } + + foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{reconfigure}}) + { + my $uuid = $anvil->data->{network_manager}{reconfigure}{$wanted_interface}{from_uuid}; + my $old_device = $anvil->data->{interface}{uuid}{$uuid}{device}; + my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; + my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; + my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; + print "Renaming old device/name: [".$old_device."/".$name."] with MAC: [".$mac_address."] to: [".$wanted_interface."] using UUID: [".$uuid."]\n"; + + # Read persistent-net and see if it needs to be updated. + my $new_persistent_net = ""; + my $old_persistent_net = ""; + if (-e $anvil->data->{path}{configs}{'persistent-net'}) + { + $old_persistent_net = $anvil->Storage->read_file({debug => 2, file => $anvil->data->{path}{configs}{'persistent-net'}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_persistent_net => $old_persistent_net }}); + } + foreach my $line (split/\n/, $old_persistent_net) + { + # If this MAC or device name exists already, delete the line. + if (($line =~ /"$mac_address"/) or ($line =~ /"$wanted_interface"/)) + { + next; + } + $new_persistent_net .= $line."\n"; + } + $new_persistent_net .= "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"".$mac_address."\",ATTR{type}==\"".$type."\",NAME=\"".$wanted_interface."\"\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_persistent_net => $new_persistent_net }}); + + my $difference = diff \$old_persistent_net, \$new_persistent_net, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + + # Write the new file. + if ($difference) + { + print "- Updating the udev file: [".$anvil->data->{path}{configs}{'persistent-net'}."]\n"; + my $problem = $anvil->Storage->write_file({ + file => $anvil->data->{path}{configs}{'persistent-net'}, + body => $new_persistent_net, + overwrite => 1, + user => "admin", + group => "admin", + mode => "0644", + + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + if ($problem) + { + print "[ Error ] - Failed to write the new: [".$anvil->data->{path}{configs}{'persistent-net'}."] file, aborting!\n"; + $anvil->nice_exit({exit_code => 1}); + } + } + + # Update the connection.interface-name + my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); + if ($connection_interface_name) + { + print "- Removing the old 'connection.interface-name': [".$connection_interface_name."]\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.interface-name \"\""; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.interface-name connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if ($output) + { + # This should have been blank + print "[ Error ] - Failed to delete the 'connection.interface-name', got: [".$output."] and it should bhave been blank, aborting!\n"; + $anvil->nice_exit({exit_code => 1}); + } + } + + # We'll log what it was, and change it anyway + my $match_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); + if (1) + { + print "- Matching the new interface name: [".$wanted_interface."] to the bios device name: [".$old_device."]\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." match.interface-name \"".$wanted_interface." ".$old_device."\""; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if (($output ne $wanted_interface.",".$old_device) && ($output ne $old_device.",".$wanted_interface)) + { + # This should have been blank + print "[ Error ] - Failed to create the 'match.interface-name' value. Expected: [".$wanted_interface.",".$old_device."], got: [".$output."], aborting!\n"; + $anvil->nice_exit({exit_code => 1}); + } + + # Set the connection.id to the old name. + print "- Setting the connection.id to the bios device name: [".$old_device."]\n"; + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.id \"".$old_device."\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + + # Set the reboot flag. + $anvil->data->{sys}{reboot_needed} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); + } + + if ($anvil->data->{sys}{reboot_needed}) + { + print "Reboot needed.\n"; + print "- Regenerating dracute initrd image, this can take a moment...\n"; + my $shell_call = $anvil->data->{path}{exe}{dracut}." --force"; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + print "- New initrd image created, rebooting in 60 seconds (press 'ctrl + c' to abort).\n"; + my $timeout = 60; + while($timeout) + { + if ($timeout % 10) + { + print "." + } + else + { + print $timeout; + } + sleep 1; + $timeout--; + } + print "0\n"; + + } + + return(0); +} + sub scan { my ($anvil) = @_; @@ -65,7 +252,6 @@ sub scan # Get a list of interfaces. get_interfaces($anvil); - return(0); } @@ -116,6 +302,7 @@ sub get_interfaces # Collect all the rest of the data now. my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection show ".$uuid; $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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, @@ -269,6 +456,7 @@ sub get_interfaces }}); ### Get some data from sysfs. + $anvil->data->{interface}{uuid}{$uuid}{device} = $device; $anvil->data->{interface}{uuid}{$uuid}{mac_address} = ""; $anvil->data->{interface}{uuid}{$uuid}{type} = ""; $anvil->data->{interface}{uuid}{$uuid}{mtu} = 0; @@ -363,7 +551,7 @@ sub get_interfaces "s13:route_count" => $route_count, }}); - print "- Device: [".$device."], Name: [".$name."], MAC: [".$mac_address."], UUID: [".$uuid."]\n"; + #print "- Device: [".$device."], Name: [".$name."], MAC: [".$mac_address."], UUID: [".$uuid."]\n"; # $anvil->data->{network_manager}{want}{ifn1_link1}{mac_address} = "52:54:00:d3:19:cc"; # $anvil->data->{network_manager}{want}{ifn1_link1}{device} = "enp1s0"; # $anvil->data->{network_manager}{want}{ifn1_link1}{found} = 0; @@ -374,16 +562,16 @@ sub get_interfaces $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wanted_mac_address => $wanted_mac_address }}); if (lc($wanted_mac_address) eq lc($mac_address)) { - print " - Interface is configured as desired.\n"; + #print " - Interface is configured as desired.\n"; } else { - print " - The MAC address doesn't match the desired MAC address!\n"; + #print " - The MAC address doesn't match the desired MAC address!\n"; } } else { - print " - This interface isn't one of the matched ones. Check if this should be reconfigured.\n"; + #print " - This interface isn't one of the matched ones. Check if this should be reconfigured.\n"; my $reconfigure_to = ""; foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}}) { @@ -418,7 +606,11 @@ sub get_interfaces if ($reconfigure_to) { # Reconfigure! - print " - This should be: [".$reconfigure_to."]\n"; + #print " - This should be: [".$reconfigure_to."]\n"; + $anvil->data->{network_manager}{reconfigure}{$reconfigure_to}{from_uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "network_manager::reconfigure::${reconfigure_to}::from_uuid" => $anvil->data->{network_manager}{reconfigure}{$reconfigure_to}{from_uuid}, + }}); } } @@ -435,7 +627,7 @@ sub get_interfaces "s2:ip_address" => $ip_address, "s3:subnet_mask" => $subnet_mask, }}); - print " - ".$sequence.": IPv4 IP: [".$ip_address."], subnet mask: [".$subnet_mask."]\n"; + #print " - ".$sequence.": IPv4 IP: [".$ip_address."], subnet mask: [".$subnet_mask."]\n"; } } if ($route_count) From ac2f9999ae07a37dc258330d96d2272766f7e576 Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 21 Dec 2023 00:33:58 -0500 Subject: [PATCH 07/43] Got anvil-monitor-network assembling bonds properly (I think) Signed-off-by: digimer --- tools/anvil-monitor-network | 663 +++++++++++++++++++++++++----------- 1 file changed, 455 insertions(+), 208 deletions(-) diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network index 924f8318..8fa88804 100755 --- a/tools/anvil-monitor-network +++ b/tools/anvil-monitor-network @@ -29,36 +29,56 @@ $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure = #print "DBs: [".$anvil->data->{sys}{database}{connections}."]\n"; -$anvil->data->{network_manager}{want}{ifn1_link1}{mac_address} = "52:54:00:d3:19:cc"; -$anvil->data->{network_manager}{want}{ifn1_link1}{device} = "enp1s0"; -$anvil->data->{network_manager}{want}{ifn1_link1}{found} = 0; -$anvil->data->{network_manager}{want}{ifn1_link2}{mac_address} = "52:54:00:fc:82:b0"; -$anvil->data->{network_manager}{want}{ifn1_link2}{device} = "enp7s0"; -$anvil->data->{network_manager}{want}{ifn1_link2}{found} = 0; +$anvil->data->{network_manager}{want}{interface}{ifn1_link1}{mac_address} = "52:54:00:d3:19:cc"; +$anvil->data->{network_manager}{want}{interface}{ifn1_link1}{device} = "enp1s0"; +$anvil->data->{network_manager}{want}{interface}{ifn1_link2}{mac_address} = "52:54:00:fc:82:b0"; +$anvil->data->{network_manager}{want}{interface}{ifn1_link2}{device} = "enp7s0"; -$anvil->data->{network_manager}{want}{bcn1_link1}{mac_address} = "52:54:00:86:f5:1d"; -$anvil->data->{network_manager}{want}{bcn1_link1}{device} = "enp8s0"; -$anvil->data->{network_manager}{want}{bcn1_link1}{found} = 0; -$anvil->data->{network_manager}{want}{bcn1_link2}{mac_address} = "52:54:00:16:c5:33"; -$anvil->data->{network_manager}{want}{bcn1_link2}{device} = "enp9s0"; -$anvil->data->{network_manager}{want}{bcn1_link2}{found} = 0; +$anvil->data->{network_manager}{want}{interface}{bcn1_link1}{mac_address} = "52:54:00:86:f5:1d"; +$anvil->data->{network_manager}{want}{interface}{bcn1_link1}{device} = "enp8s0"; +$anvil->data->{network_manager}{want}{interface}{bcn1_link2}{mac_address} = "52:54:00:16:c5:33"; +$anvil->data->{network_manager}{want}{interface}{bcn1_link2}{device} = "enp9s0"; -$anvil->data->{network_manager}{want}{sn1_link1}{mac_address} = "52:54:00:37:6f:22"; -$anvil->data->{network_manager}{want}{sn1_link1}{device} = "enp10s0"; -$anvil->data->{network_manager}{want}{sn1_link1}{found} = 0; -$anvil->data->{network_manager}{want}{sn1_link2}{mac_address} = "52:54:00:2f:02:1b"; -$anvil->data->{network_manager}{want}{sn1_link2}{device} = "enp11s0"; -$anvil->data->{network_manager}{want}{sn1_link2}{found} = 0; +$anvil->data->{network_manager}{want}{interface}{sn1_link1}{mac_address} = "52:54:00:37:6f:22"; +$anvil->data->{network_manager}{want}{interface}{sn1_link1}{device} = "enp10s0"; +$anvil->data->{network_manager}{want}{interface}{sn1_link2}{mac_address} = "52:54:00:2f:02:1b"; +$anvil->data->{network_manager}{want}{interface}{sn1_link2}{device} = "enp11s0"; + +# Bonds +#$anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{interfaces} = ["ifn1_link1", "ifn1_link2"]; # First interface is primary +$anvil->data->{network_manager}{want}{bond}{bcn1_bond1}{interfaces} = ["bcn1_link1", "bcn1_link2"]; +$anvil->data->{network_manager}{want}{bond}{sn1_bond1}{interfaces} = ["sn1_link1", "sn1_link2"]; + +# Bridges +#$anvil->data->{network_manager}{want}{bridge}{ifn1_bridge1}{on} = "ifn1_bond1"; +$anvil->data->{network_manager}{want}{bridge}{bcn1_bridge1}{on} = "bcn1_bond1"; + +# IP addresses. +#$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{ip_address} = "192.168.6.42"; +#$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{subnet_mask} = "255.255.0.0"; +#$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{gateway} = "192.168.255.254"; +#$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{dns} = "8.8.8.8,8.8.4.4"; + +$anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{ip_address} = "10.101.4.42"; +$anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{subnet_mask} = "255.255.0.0"; +$anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{gateway} = ""; +$anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{dns} = ""; + +$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{ip_address} = "10.201.4.42"; +$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{subnet_mask} = "255.255.0.0"; +$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{gateway} = ""; +$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{dns} = ""; $anvil->data->{sys}{reboot_needed} = 0; +$anvil->data->{sys}{make_changes} = 1; -scan($anvil); +collect_data($anvil); reconfigure($anvil); - $anvil->nice_exit({exit_code => 0}); + ############################################################################################################# # Functions # ############################################################################################################# @@ -67,195 +87,163 @@ sub reconfigure { my ($anvil) = @_; - my $reconfigure_count = keys %{$anvil->data->{network_manager}{reconfigure}}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reconfigure_count => $reconfigure_count }}); - if (not $reconfigure_count) - { - return(0); - } + reconfigure_interfaces($anvil); + reconfigure_bonds($anvil); + reconfigure_bridges($anvil); + reconfigure_ip_addresses($anvil); - foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{reconfigure}}) + return(0); +} + +sub reconfigure_bonds +{ + my ($anvil) = @_; + + # $anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{interfaces} = ["ifn1_link1", "ifn1_link2"]; # First interface is primary + # $anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{ipv4_method} = "disabled"; + foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{bond}}) { - my $uuid = $anvil->data->{network_manager}{reconfigure}{$wanted_interface}{from_uuid}; - my $old_device = $anvil->data->{interface}{uuid}{$uuid}{device}; - my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; - my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; - my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; - print "Renaming old device/name: [".$old_device."/".$name."] with MAC: [".$mac_address."] to: [".$wanted_interface."] using UUID: [".$uuid."]\n"; - - # Read persistent-net and see if it needs to be updated. - my $new_persistent_net = ""; - my $old_persistent_net = ""; - if (-e $anvil->data->{path}{configs}{'persistent-net'}) + print "Checking if the bond: [".$bond_name."] exists or not.\n"; + if (exists $anvil->data->{interface}{bond}{$bond_name}) { - $old_persistent_net = $anvil->Storage->read_file({debug => 2, file => $anvil->data->{path}{configs}{'persistent-net'}}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_persistent_net => $old_persistent_net }}); - } - foreach my $line (split/\n/, $old_persistent_net) - { - # If this MAC or device name exists already, delete the line. - if (($line =~ /"$mac_address"/) or ($line =~ /"$wanted_interface"/)) - { - next; - } - $new_persistent_net .= $line."\n"; + print "- It does, its UUID is: [".$anvil->data->{interface}{bond}{$bond_name}{uuid}."]\n"; } - $new_persistent_net .= "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"".$mac_address."\",ATTR{type}==\"".$type."\",NAME=\"".$wanted_interface."\"\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_persistent_net => $new_persistent_net }}); - - my $difference = diff \$old_persistent_net, \$new_persistent_net, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - - # Write the new file. - if ($difference) + else { - print "- Updating the udev file: [".$anvil->data->{path}{configs}{'persistent-net'}."]\n"; - my $problem = $anvil->Storage->write_file({ - file => $anvil->data->{path}{configs}{'persistent-net'}, - body => $new_persistent_net, - overwrite => 1, - user => "admin", - group => "admin", - mode => "0644", - - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); - if ($problem) + my $primary_interface = $anvil->data->{network_manager}{want}{bond}{$bond_name}{interfaces}->[0]; + if (not $primary_interface) { - print "[ Error ] - Failed to write the new: [".$anvil->data->{path}{configs}{'persistent-net'}."] file, aborting!\n"; + print "[ Error ] - There appears to be no primary interface specified for this bond!\n"; $anvil->nice_exit({exit_code => 1}); } - } - - # Update the connection.interface-name - my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); - if ($connection_interface_name) - { - print "- Removing the old 'connection.interface-name': [".$connection_interface_name."]\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.interface-name \"\""; + print "- It does not, creating it with the primary interface: [".$primary_interface."] now.\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bond con-name ".$bond_name." ifname ".$bond_name." bond.options \"mode=active-backup,miimon=100,downdelay=0,updelay=120000,primary=".$primary_interface."\""; $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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, + output => $output, return_code => $return_code, }}); - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.interface-name connection show ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - if ($output) + if ($return_code) { - # This should have been blank - print "[ Error ] - Failed to delete the 'connection.interface-name', got: [".$output."] and it should bhave been blank, aborting!\n"; + print "[ Error ] - The attempt to add the bond failed! The return code was: [".$return_code."]. The output, if any, was:\n"; + print "========\n"; + print $output."\n"; + print "========\n"; $anvil->nice_exit({exit_code => 1}); } + + my $bond_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); + + if ($bond_uuid) + { + print " - Disabling DHCP on the new bond device: [".$bond_uuid."].\n"; + my ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv4.method", "disabled"); + ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv6.method", "disabled"); + } + + # Rescan. + print " - Done! Rescanning the network config.\n"; + collect_data($anvil); } - # We'll log what it was, and change it anyway - my $match_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); - if (1) + # Now add the interfaces, disabling their ipv4.method first. + foreach my $interface_name (@{$anvil->data->{network_manager}{want}{bond}{$bond_name}{interfaces}}) { - print "- Matching the new interface name: [".$wanted_interface."] to the bios device name: [".$old_device."]\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." match.interface-name \"".$wanted_interface." ".$old_device."\""; - $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}); + # What is the interface UUID? + my $interface_uuid = $anvil->data->{interface}{device}{$interface_name}{uuid}; + my $parent_bond_name = $anvil->data->{interface}{uuid}{$interface_uuid}{'connection.master'}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, + interface_name => $interface_name, + interface_uuid => $interface_uuid, + parent_bond_name => $parent_bond_name, }}); + if ($parent_bond_name eq "--") + { + $parent_bond_name = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { parent_bond_name => $parent_bond_name }}); + } - # Read it back - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$uuid; + if ($parent_bond_name) + { + if ($parent_bond_name eq $bond_name) + { + print "- The interface: [".$interface_name."] (".$interface_uuid.") is already a member of the bond.\n"; + next; + } + else + { + print "- The interface: [".$interface_name."] (".$interface_uuid.") is a member of the bond: [".$parent_bond_name."], switching it to this bond.\n"; + } + } + else + { + print "- The interface: [".$interface_name."] (".$interface_uuid.") needs to be connected to the bond.\n"; + } + + print " - Disabling DHCP on the interface\n"; + my ($output, $return_code) = modify_connection($anvil, $interface_uuid, "ipv4.method", "disabled"); + ($output, $return_code) = modify_connection($anvil, $interface_uuid, "ipv6.method", "disabled"); + + print " - Connecting the interface to the bond.\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$interface_uuid." connection.master ".$bond_name." connection.slave-type bond"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, + output => $output, return_code => $return_code, }}); - if (($output ne $wanted_interface.",".$old_device) && ($output ne $old_device.",".$wanted_interface)) + if ($return_code) { - # This should have been blank - print "[ Error ] - Failed to create the 'match.interface-name' value. Expected: [".$wanted_interface.",".$old_device."], got: [".$output."], aborting!\n"; + print "[ Error ] - The attempt to add the bond failed! The return code was: [".$return_code."]. The output, if any, was:\n"; + print "========\n"; + print $output."\n"; + print "========\n"; $anvil->nice_exit({exit_code => 1}); } - # Set the connection.id to the old name. - print "- Setting the connection.id to the bios device name: [".$old_device."]\n"; - $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.id \"".$old_device."\""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + # Rescan. + print " - Done! Rescanning the network config.\n"; + ($output, $return_code) = reset_connection($anvil, $interface_uuid); - # Read it back - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + # Rescan. + collect_data($anvil); } - - # Set the reboot flag. - $anvil->data->{sys}{reboot_needed} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); } - if ($anvil->data->{sys}{reboot_needed}) + return(0); +} + +sub reconfigure_bridges +{ + my ($anvil) = @_; + + foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{bridge}}) { - print "Reboot needed.\n"; - print "- Regenerating dracute initrd image, this can take a moment...\n"; - my $shell_call = $anvil->data->{path}{exe}{dracut}." --force"; - $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}); + my $on_device = $anvil->data->{network_manager}{want}{bridge}{$bridge_name}{on}; + print "Checking if the bridge: [".$bridge_name."] exists and that it is on: [".$on_device."]\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, + bridge_name => $bridge_name, + on_device => $on_device, }}); - print "- New initrd image created, rebooting in 60 seconds (press 'ctrl + c' to abort).\n"; - my $timeout = 60; - while($timeout) - { - if ($timeout % 10) - { - print "." - } - else - { - print $timeout; - } - sleep 1; - $timeout--; - } - print "0\n"; - } return(0); } -sub scan +sub reconfigure_ip_addresses { my ($anvil) = @_; - # Get a list of interfaces. - get_interfaces($anvil); + return(0); } -sub get_interfaces +sub collect_data { my ($anvil) = @_; @@ -310,11 +298,16 @@ sub get_interfaces }}); foreach my $line (split/\n/, $output) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); if ($line =~ /^(.*?):\s+(.*)$/) { my $variable = $1; my $value = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:variable' => $variable, + 's2:value' => $value, + }}); + $anvil->data->{interface}{uuid}{$uuid}{$variable} = $value; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface::uuid::${uuid}::${variable}" => $anvil->data->{interface}{uuid}{$uuid}{$variable}, @@ -439,13 +432,14 @@ sub get_interfaces { my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} // ""; my $general_devices = $anvil->data->{interface}{uuid}{$uuid}{'GENERAL.DEVICES'} // ""; + my $device_type = $anvil->data->{interface}{uuid}{$uuid}{'connection.type'} // ""; my $device = $connection_interface_name ne "--" ? $connection_interface_name : $general_devices; - my $name = $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:uuid' => $uuid, 's2:connection_interface_name' => $connection_interface_name, 's3:general_devices' => $general_devices, - 's4:device' => $device, + 's4:device_type' => $device_type, + 's5:device' => $device, }}); if ($device) @@ -468,52 +462,67 @@ sub get_interfaces "interface::uuid::${uuid}::connected" => $anvil->data->{interface}{uuid}{$uuid}{connected}, }}); - # MAC address - my $mac_address_file = "/sys/class/net/".$device."/address"; - my $type_file = "/sys/class/net/".$device."/type"; - my $mtu_file = "/sys/class/net/".$device."/mtu"; - if (-e $mac_address_file) + if ($device_type eq "bond") { - my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); - $mac_address =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - - if (($mac_address) && ($mac_address ne "!!error!!")) - { - $anvil->data->{interface}{uuid}{$uuid}{mac_address} = $mac_address; - $anvil->data->{interface}{mac_address}{$mac_address}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::mac_address" => $anvil->data->{interface}{uuid}{$uuid}{mac_address}, - "interface::mac_address::${mac_address}::uuid" => $anvil->data->{interface}{mac_address}{$mac_address}{uuid}, - }}); - } + $anvil->data->{interface}{bond}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::bond::${device}::uuid" => $anvil->data->{interface}{bond}{$device}{uuid}, + }}); } - if (-e $type_file) + elsif ($device_type eq "802-3-ethernet") { - my $type = $anvil->Storage->read_file({file => $type_file}); - $type =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + $anvil->data->{interface}{phy}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::phy::${device}::uuid" => $anvil->data->{interface}{phy}{$device}{uuid}, + }}); - if (($type) && ($type ne "!!error!!")) + # MAC address + my $mac_address_file = "/sys/class/net/".$device."/address"; + my $type_file = "/sys/class/net/".$device."/type"; + my $mtu_file = "/sys/class/net/".$device."/mtu"; + if (-e $mac_address_file) { - $anvil->data->{interface}{uuid}{$uuid}{type} = $type; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::type" => $anvil->data->{interface}{uuid}{$uuid}{type}, - }}); + my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); + $mac_address =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + + if (($mac_address) && ($mac_address ne "!!error!!")) + { + $anvil->data->{interface}{uuid}{$uuid}{mac_address} = $mac_address; + $anvil->data->{interface}{mac_address}{$mac_address}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::mac_address" => $anvil->data->{interface}{uuid}{$uuid}{mac_address}, + "interface::mac_address::${mac_address}::uuid" => $anvil->data->{interface}{mac_address}{$mac_address}{uuid}, + }}); + } } - } - if (-e $mtu_file) - { - my $mtu = $anvil->Storage->read_file({file => $mtu_file}); - $mtu =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mtu => $mtu }}); - - if (($mtu) && ($mtu ne "!!error!!")) + if (-e $type_file) { - $anvil->data->{interface}{uuid}{$uuid}{mtu} = $mtu; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::mtu" => $anvil->data->{interface}{uuid}{$uuid}{mtu}, - }}); + my $type = $anvil->Storage->read_file({file => $type_file}); + $type =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + + if (($type) && ($type ne "!!error!!")) + { + $anvil->data->{interface}{uuid}{$uuid}{type} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::type" => $anvil->data->{interface}{uuid}{$uuid}{type}, + }}); + } + } + if (-e $mtu_file) + { + my $mtu = $anvil->Storage->read_file({file => $mtu_file}); + $mtu =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mtu => $mtu }}); + + if (($mtu) && ($mtu ne "!!error!!")) + { + $anvil->data->{interface}{uuid}{$uuid}{mtu} = $mtu; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::uuid::${uuid}::mtu" => $anvil->data->{interface}{uuid}{$uuid}{mtu}, + }}); + } } } } @@ -551,14 +560,10 @@ sub get_interfaces "s13:route_count" => $route_count, }}); - #print "- Device: [".$device."], Name: [".$name."], MAC: [".$mac_address."], UUID: [".$uuid."]\n"; -# $anvil->data->{network_manager}{want}{ifn1_link1}{mac_address} = "52:54:00:d3:19:cc"; -# $anvil->data->{network_manager}{want}{ifn1_link1}{device} = "enp1s0"; -# $anvil->data->{network_manager}{want}{ifn1_link1}{found} = 0; - if (exists $anvil->data->{network_manager}{want}{$device}) + if (exists $anvil->data->{network_manager}{want}{interface}{$device}) { # We know this device. Does it match the expected MAC address? - my $wanted_mac_address = $anvil->data->{network_manager}{want}{ifn1_link1}{mac_address}; + my $wanted_mac_address = $anvil->data->{network_manager}{want}{interface}{ifn1_link1}{mac_address}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wanted_mac_address => $wanted_mac_address }}); if (lc($wanted_mac_address) eq lc($mac_address)) { @@ -573,10 +578,10 @@ sub get_interfaces { #print " - This interface isn't one of the matched ones. Check if this should be reconfigured.\n"; my $reconfigure_to = ""; - foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}}) + foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{interface}}) { - my $wanted_device = $anvil->data->{network_manager}{want}{$wanted_interface}{device}; - my $wanted_mac_address = $anvil->data->{network_manager}{want}{$wanted_interface}{mac_address}; + my $wanted_device = $anvil->data->{network_manager}{want}{interface}{$wanted_interface}{device}; + my $wanted_mac_address = $anvil->data->{network_manager}{want}{interface}{$wanted_interface}{mac_address}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wanted_interface => $wanted_interface, wanted_device => $wanted_device, @@ -647,3 +652,245 @@ sub get_interfaces return(0); } + +sub reconfigure_interfaces +{ + my ($anvil) = @_; + + my $reconfigure_count = keys %{$anvil->data->{network_manager}{reconfigure}}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reconfigure_count => $reconfigure_count }}); + if (not $reconfigure_count) + { + return(0); + } + + foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{reconfigure}}) + { + my $uuid = $anvil->data->{network_manager}{reconfigure}{$wanted_interface}{from_uuid}; + my $old_device = $anvil->data->{interface}{uuid}{$uuid}{device}; + my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; + my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; + my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:wanted_interface' => $wanted_interface, + 's2:uuid' => $uuid, + 's3:old_device' => $old_device, + 's4:name' => $name, + 's5:mac_address' => $mac_address, + 's6:type' => $type, + }}); + + print "Renaming old device/name: [".$old_device."/".$name."] with MAC: [".$mac_address."] to: [".$wanted_interface."] using UUID: [".$uuid."]\n"; + + # Read persistent-net and see if it needs to be updated. + my $new_persistent_net = ""; + my $old_persistent_net = ""; + if (-e $anvil->data->{path}{configs}{'persistent-net'}) + { + $old_persistent_net = $anvil->Storage->read_file({debug => 2, file => $anvil->data->{path}{configs}{'persistent-net'}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_persistent_net => $old_persistent_net }}); + } + foreach my $line (split/\n/, $old_persistent_net) + { + # If this MAC or device name exists already, delete the line. + if (($line =~ /"$mac_address"/) or ($line =~ /"$wanted_interface"/)) + { + next; + } + $new_persistent_net .= $line."\n"; + } + $new_persistent_net .= "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"".$mac_address."\",ATTR{type}==\"".$type."\",NAME=\"".$wanted_interface."\"\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_persistent_net => $new_persistent_net }}); + + my $difference = diff \$old_persistent_net, \$new_persistent_net, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + + # Write the new file. + if ($difference) + { + print "- Updating the udev file: [".$anvil->data->{path}{configs}{'persistent-net'}."]\n"; + my $problem = $anvil->Storage->write_file({ + file => $anvil->data->{path}{configs}{'persistent-net'}, + body => $new_persistent_net, + overwrite => 1, + user => "admin", + group => "admin", + mode => "0644", + + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + if ($problem) + { + print "[ Error ] - Failed to write the new: [".$anvil->data->{path}{configs}{'persistent-net'}."] file, aborting!\n"; + $anvil->nice_exit({exit_code => 1}); + } + } + + # Update the connection.interface-name + my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); + if ($connection_interface_name) + { + print "- Removing the old 'connection.interface-name': [".$connection_interface_name."]\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.interface-name \"\""; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.interface-name connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if ($output) + { + # This should have been blank + print "[ Error ] - Failed to delete the 'connection.interface-name', got: [".$output."] and it should bhave been blank, aborting!\n"; + $anvil->nice_exit({exit_code => 1}); + } + } + + # We'll log what it was, and change it anyway + my $match_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); + if (1) + { + print "- Matching the new interface name: [".$wanted_interface."] to the bios device name: [".$old_device."]\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." match.interface-name \"".$wanted_interface." ".$old_device."\""; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if (($output ne $wanted_interface.",".$old_device) && ($output ne $old_device.",".$wanted_interface)) + { + # This should have been blank + print "[ Error ] - Failed to create the 'match.interface-name' value. Expected: [".$wanted_interface.",".$old_device."], got: [".$output."], aborting!\n"; + $anvil->nice_exit({exit_code => 1}); + } + + # Set the connection.id to the old name. + print "- Setting the connection.id to the bios device name: [".$old_device."]\n"; + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.id \"".$old_device."\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + + # Set the reboot flag. + $anvil->data->{sys}{reboot_needed} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); + } + + if ($anvil->data->{sys}{reboot_needed}) + { + print "Reboot needed.\n"; + print "- Regenerating dracute initrd image, this can take a moment...\n"; + my $shell_call = $anvil->data->{path}{exe}{dracut}." --force"; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + print "- New initrd image created.\n"; + print "[ Note ] - Reboot needed. Re-run this after the reboot to complete setup.\n"; + print "- Rebooting in 60 seconds (press 'ctrl + c' to abort).\n"; + my $timeout = 60; + while($timeout) + { + if ($timeout % 10) + { + print "." + } + else + { + print $timeout; + } + sleep 1; + $timeout--; + } + print "0\n"; + print "Rebooting NOW!\n"; + + $shell_call = $anvil->data->{path}{exe}{systemctl}." reboot"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($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 }}); + } + + return(0); +} + +sub modify_connection +{ + my ($anvil, $uuid, $variable, $value) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + uuid => $uuid, + variable => $variable, + value => $value, + }}); + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." ".$variable." ".$value; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + return($output, $return_code); +} + +sub reset_connection +{ + my ($anvil, $uuid) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$uuid; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + return($output, $return_code); +} From 9c57035b54e52424a7dce8ff216dde8ebfe08884 Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 21 Dec 2023 18:01:42 -0500 Subject: [PATCH 08/43] Got bridge support added to anvil-monitor-network. Signed-off-by: digimer --- tools/anvil-monitor-network | 176 ++++++++++++++++++++++++++++++------ 1 file changed, 149 insertions(+), 27 deletions(-) diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network index 8fa88804..5b47d522 100755 --- a/tools/anvil-monitor-network +++ b/tools/anvil-monitor-network @@ -95,6 +95,139 @@ sub reconfigure return(0); } +sub reconfigure_ip_addresses +{ + my ($anvil) = @_; + + + + return(0); +} + +sub reconfigure_bridges +{ + my ($anvil) = @_; + + foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{bridge}}) + { + my $on_device = $anvil->data->{network_manager}{want}{bridge}{$bridge_name}{on}; + print "Checking if the bridge: [".$bridge_name."] exists and that it is on: [".$on_device."]\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bridge_name => $bridge_name, + on_device => $on_device, + }}); + + if (exists $anvil->data->{interface}{bridge}{$bridge_name}) + { + # The bridge exists. + print "- The bridge exists!\n"; + } + else + { + # Create the bridge. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bridge con-name ".$bridge_name." ifname ".$bridge_name; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if ($return_code) + { + print "[ Error ] - The attempt to add the bridge failed! The return code was: [".$return_code."]. The output, if any, was:\n"; + print "========\n"; + print $output."\n"; + print "========\n"; + $anvil->nice_exit({exit_code => 1}); + } + + my $bridge_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); + + if ($bridge_uuid) + { + print " - Disabling DHCP on the new bridge device: [".$bridge_uuid."].\n"; + my ($output, $return_code) = modify_connection($anvil, $bridge_uuid, "ipv4.method", "disabled"); + ($output, $return_code) = modify_connection($anvil, $bridge_uuid, "ipv6.method", "disabled"); + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + + # Rescan. + print " - Done! Rescanning the network config.\n"; + collect_data($anvil); + } + + print "- Checking that the device: [".$on_device."] is connected to this bridge.\n"; + my $bridge_uuid = $anvil->data->{interface}{bridge}{$bridge_name}{uuid}; + my $on_device_uuid = $anvil->data->{interface}{device}{$on_device}{uuid} // ""; + my $on_device_parent = $anvil->data->{interface}{uuid}{$on_device_uuid}{'connection.master'} // ""; + my $on_device_child_type = $anvil->data->{interface}{uuid}{$on_device_uuid}{'connection.slave-type'} // ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bridge_uuid => $bridge_uuid, + on_device_uuid => $on_device_uuid, + on_device_parent => $on_device_parent, + on_device_child_type => $on_device_child_type, + }}); + + die if not $on_device_uuid; + + if ($on_device_parent) + { + if ($on_device_parent eq $bridge_name) + { + print "- The device is connected to the bridge already.\n"; + next; + } + else + { + print "- The device is on the bridge: [".$on_device_parent."], moving it.\n"; + } + } + else + { + print "- The device is not on this bridge, connecting it.\n"; + } + + print " - Disabling DHCP on the device: [".$on_device."] (".$on_device_uuid.") before connecting it.\n"; + my ($output, $return_code) = modify_connection($anvil, $on_device_uuid, "ipv4.method", "disabled"); + ($output, $return_code) = modify_connection($anvil, $on_device_uuid, "ipv6.method", "disabled"); + + print " - Connecting it now.\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$on_device_uuid." master ".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if ($return_code) + { + print "[ Error ] - The attempt to add the bridge failed! The return code was: [".$return_code."]. The output, if any, was:\n"; + print "========\n"; + print $output."\n"; + print "========\n"; + $anvil->nice_exit({exit_code => 1}); + } + + print " - Done! Rescanning the network config.\n"; + ($output, $return_code) = reset_connection($anvil, $on_device_uuid); + + # Rescan. + collect_data($anvil); + } + + return(0); +} + sub reconfigure_bonds { my ($anvil) = @_; @@ -142,6 +275,14 @@ sub reconfigure_bonds print " - Disabling DHCP on the new bond device: [".$bond_uuid."].\n"; my ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv4.method", "disabled"); ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv6.method", "disabled"); + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bond_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); } # Rescan. @@ -217,32 +358,6 @@ sub reconfigure_bonds return(0); } -sub reconfigure_bridges -{ - my ($anvil) = @_; - - foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{bridge}}) - { - my $on_device = $anvil->data->{network_manager}{want}{bridge}{$bridge_name}{on}; - print "Checking if the bridge: [".$bridge_name."] exists and that it is on: [".$on_device."]\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - bridge_name => $bridge_name, - on_device => $on_device, - }}); - } - - return(0); -} - -sub reconfigure_ip_addresses -{ - my ($anvil) = @_; - - - - return(0); -} - sub collect_data { my ($anvil) = @_; @@ -469,6 +584,13 @@ sub collect_data "interface::bond::${device}::uuid" => $anvil->data->{interface}{bond}{$device}{uuid}, }}); } + elsif ($device_type eq "bridge") + { + $anvil->data->{interface}{bridge}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::bridge::${device}::uuid" => $anvil->data->{interface}{bridge}{$device}{uuid}, + }}); + } elsif ($device_type eq "802-3-ethernet") { $anvil->data->{interface}{phy}{$device}{uuid} = $uuid; @@ -535,7 +657,7 @@ sub collect_data my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; - my $mtu_type = $anvil->data->{interface}{uuid}{$uuid}{'802-3-ethernet.mtu'}; + my $mtu_type = $anvil->data->{interface}{uuid}{$uuid}{'802-3-ethernet.mtu'} // ""; my $mtu = $anvil->data->{interface}{uuid}{$uuid}{mtu}; my $active = $anvil->data->{interface}{uuid}{$uuid}{active}; my $state = $anvil->data->{interface}{uuid}{$uuid}{'state'}; From 72325b9ed745ff807e989b12f6a8d10ee4858f09 Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 21 Dec 2023 22:49:52 -0500 Subject: [PATCH 09/43] Finished IP assignment. Signed-off-by: digimer --- tools/anvil-monitor-network | 144 +++++++++++++++++++++++++++++++++--- 1 file changed, 133 insertions(+), 11 deletions(-) diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network index 5b47d522..2b632a2f 100755 --- a/tools/anvil-monitor-network +++ b/tools/anvil-monitor-network @@ -45,19 +45,19 @@ $anvil->data->{network_manager}{want}{interface}{sn1_link2}{mac_address} = "52: $anvil->data->{network_manager}{want}{interface}{sn1_link2}{device} = "enp11s0"; # Bonds -#$anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{interfaces} = ["ifn1_link1", "ifn1_link2"]; # First interface is primary +$anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{interfaces} = ["ifn1_link1", "ifn1_link2"]; # First interface is primary $anvil->data->{network_manager}{want}{bond}{bcn1_bond1}{interfaces} = ["bcn1_link1", "bcn1_link2"]; $anvil->data->{network_manager}{want}{bond}{sn1_bond1}{interfaces} = ["sn1_link1", "sn1_link2"]; # Bridges -#$anvil->data->{network_manager}{want}{bridge}{ifn1_bridge1}{on} = "ifn1_bond1"; +$anvil->data->{network_manager}{want}{bridge}{ifn1_bridge1}{on} = "ifn1_bond1"; $anvil->data->{network_manager}{want}{bridge}{bcn1_bridge1}{on} = "bcn1_bond1"; # IP addresses. -#$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{ip_address} = "192.168.6.42"; -#$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{subnet_mask} = "255.255.0.0"; -#$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{gateway} = "192.168.255.254"; -#$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{dns} = "8.8.8.8,8.8.4.4"; +$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{ip_address} = "192.168.6.42"; +$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{subnet_mask} = "255.255.0.0"; +$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{gateway} = "192.168.255.254"; +$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{dns} = "8.8.8.8,8.8.4.4"; $anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{ip_address} = "10.101.4.42"; $anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{subnet_mask} = "255.255.0.0"; @@ -99,7 +99,122 @@ sub reconfigure_ip_addresses { my ($anvil) = @_; - + foreach my $on_device (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{ip_on}}) + { + my $on_device_uuid = $anvil->data->{interface}{device}{$on_device}{uuid}; + my $ip_address = $anvil->data->{network_manager}{want}{ip_on}{$on_device}{ip_address}; + my $subnet_mask = $anvil->data->{network_manager}{want}{ip_on}{$on_device}{subnet_mask}; + my $gateway = $anvil->data->{network_manager}{want}{ip_on}{$on_device}{gateway}; + my $dns = $anvil->data->{network_manager}{want}{ip_on}{$on_device}{dns}; + my $clear_ip_from = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:on_device' => $on_device, + 's2:on_device_uuid' => $on_device_uuid, + 's3:ip_address' => $ip_address, + 's4:subnet_mask' => $subnet_mask, + 's5:gateway' => $gateway, + 's6:dns' => $dns, + }}); + if (($subnet_mask !~ /^\d+$/) or ($subnet_mask < 1) or ($subnet_mask > 32)) + { + # Convert to CIDR + my $cidr = $anvil->Convert->cidr({subnet_mask => $subnet_mask}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cidr => $cidr }}); + if (not $cidr) + { + print "[ ERROR ] - The subnet_mask: [".$subnet_mask."] is not valid. It must be either a CIDR notation, or a dotted-decimal mask that can be translated to CIDR notation.\n"; + $anvil->nice_exit({exit_code => 1}); + } + + $subnet_mask = $cidr; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subnet_mask => $subnet_mask }}); + } + + print "Checking to see if the IP address: [".$ip_address."/".$subnet_mask."] is assigned to: [".$on_device."] yet.\n"; + if (exists $anvil->data->{interface}{ipv4}{$ip_address}) + { + my $ip_uuid = $anvil->data->{interface}{ipv4}{$ip_address}{on_uuid}; + my $current_device = $anvil->data->{interface}{uuid}{$ip_uuid}{device}; + my $ip_sequence = $anvil->data->{interface}{ipv4}{$ip_address}{sequence}; + my $current_subnet_mask = $anvil->data->{interface}{uuid}{$ip_uuid}{ipv4}{ip}{$ip_sequence}{subnet_mask}; + my $current_gateway = $anvil->data->{interface}{uuid}{$ip_uuid}{ipv4}{gateway}; + my $current_dns = $anvil->data->{interface}{uuid}{$ip_uuid}{ipv4}{dns}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:ip_uuid' => $ip_uuid, + 's2:current_device' => $current_device, + 's3:ip_sequence' => $ip_sequence, + 's4:current_subnet_mask' => $current_subnet_mask, + 's5:current_gateway' => $current_gateway, + 's6:current_dns' => $current_dns, + }}); + die if not $ip_uuid; + + print "- The IP exists, checking if it needs to be updated.\n"; + if ($on_device ne $current_device) + { + print "- The IP address is on: [".$current_device."], will move the IP.\n"; + $clear_ip_from = $current_device; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_ip_from => $clear_ip_from }}); + } + elsif ($subnet_mask ne $current_subnet_mask) + { + print "- The current subnet mask is: [".$current_subnet_mask."], will update.\n"; + } + elsif ($gateway ne $current_gateway) + { + print "- The current gateway is: [".$current_gateway."], will update.\n"; + } + elsif ($dns ne $current_dns) + { + print "- The current DNS is: [".$current_dns."], will update.\n"; + } + else + { + print "- No update is needed.\n"; + next; + } + } + else + { + print "- The IP address needs to be assigned.\n"; + } + + if ($clear_ip_from) + { + my $old_uuid = $anvil->data->{interface}{device}{$clear_ip_from}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_uuid => $old_uuid }}); + print " - Clearing the IP from: [".$old_uuid."] (".$clear_ip_from.")\n"; + + my ($output, $return_code) = modify_connection($anvil, $old_uuid, "ipv4.method", "disabled"); + ($output, $return_code) = modify_connection($anvil, $old_uuid, "ipv6.method", "disabled"); + ($output, $return_code) = reset_connection($anvil, $old_uuid); + } + + # Now assign the IP. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$on_device_uuid." ipv4.method manual ipv4.addresses ".$ip_address."/".$subnet_mask; + if ($gateway) + { + $shell_call .= " ipv4.gateway ".$gateway; + } + if ($dns) + { + $shell_call .= " ipv4.dns ".$dns; + } + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Restart the interface + print " - Restarting the interface.\n"; + ($output, $return_code) = reset_connection($anvil, $on_device_uuid); + + # Rescan. + collect_data($anvil); + } return(0); } @@ -177,8 +292,6 @@ sub reconfigure_bridges on_device_child_type => $on_device_child_type, }}); - die if not $on_device_uuid; - if ($on_device_parent) { if ($on_device_parent eq $bridge_name) @@ -450,19 +563,28 @@ sub collect_data $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $1; $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = $2; + $anvil->data->{interface}{ipv4}{$ip_address}{on_uuid} = $uuid; + $anvil->data->{interface}{ipv4}{$ip_address}{sequence} = $sequence; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, + "interface::ipv4::${ip_address}::on_uuid" => $anvil->data->{interface}{ipv4}{$ip_address}{on_uuid}, + "interface::ipv4::${ip_address}::sequence" => $anvil->data->{interface}{ipv4}{$ip_address}{sequence}, }}); } else { $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $value; $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = ""; + $anvil->data->{interface}{ipv4}{$value}{on_uuid} = $value; + $anvil->data->{interface}{ipv4}{$value}{sequence} = $sequence; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, + "interface::ipv4::${value}::on_uuid" => $anvil->data->{interface}{ipv4}{$value}{on_uuid}, + "interface::ipv4::${value}::sequence" => $anvil->data->{interface}{ipv4}{$value}{sequence}, }}); + } # Make sure the DNS key exists. @@ -470,14 +592,14 @@ sub collect_data { $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{interface}{uuid}{$uuid}{$sequence}{dns}, + "interface::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns}, }}); } if (not exists $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway}) { $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway} = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{interface}{uuid}{$uuid}{$sequence}{gateway}, + "interface::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway}, }}); } $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway} = $value; From ec11335197f59ab1ec643e3a3b6ec39ce1f78ac1 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 3 Jan 2024 17:42:53 -0500 Subject: [PATCH 10/43] Fixed DB initialization bugs. * More work done on the new network stack also. Signed-off-by: digimer --- Anvil/Tools/Database.pm | 135 ++++-- Anvil/Tools/Get.pm | 5 + Anvil/Tools/Network.pm | 511 +++++++++++++++++++++- Anvil/Tools/System.pm | 46 ++ scancore-agents/scan-network/scan-network | 454 ++++++++++++++++--- share/anvil.sql | 15 +- tools/anvil-configure-host | 3 + tools/anvil-daemon | 12 +- tools/anvil-monitor-network | 19 +- tools/anvil-version-changes | 149 ++++++- 10 files changed, 1233 insertions(+), 116 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 3e0903b2..cb21ab1b 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -971,7 +971,7 @@ sub configure_pgsql { # Did we initialize? $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { initialized => $initialized }}); - if ($initialized) + if (($initialized) or (not $running)) { # Start the daemon. my $return_code = $anvil->System->start_daemon({daemon => $anvil->data->{sys}{daemon}{postgresql}}); @@ -4470,7 +4470,8 @@ AND $query = " SELECT network_interface_uuid, - network_interface_name + network_interface_name, + network_interface_device FROM network_interfaces WHERE @@ -4488,14 +4489,18 @@ AND }}); foreach my $row (@{$results}) { - my $network_interface_uuid = $row->[0]; - my $network_interface_name = $row->[1]; + my $network_interface_uuid = $row->[0]; + my $network_interface_name = $row->[1]; + my $network_interface_device = $row->[2]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - network_interface_uuid => $network_interface_uuid, - network_interface_name => $network_interface_name, + network_interface_uuid => $network_interface_uuid, + network_interface_name => $network_interface_name, + network_interface_device => $network_interface_device, }}); - $anvil->data->{hosts}{host_uuid}{$host_uuid}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_name; + # The interface_device is the name used by 'ip addr list', and the name is the 'enX' + # biosdevname device. So we only use the name now if there is no device. + $anvil->data->{hosts}{host_uuid}{$host_uuid}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_device ? $network_interface_device : $network_interface_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hosts::host_uuid::${host_uuid}::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_name" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}, }}); @@ -6948,6 +6953,7 @@ sub initialize $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { sql => $sql }}); # In the off chance that the database user isn't 'admin', update the SQL file. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user => $user }}); if ($user ne "admin") { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0253", variables => { database_user => $user }}); @@ -6968,11 +6974,12 @@ sub initialize # Now that I am ready, disable autocommit, write and commit. $anvil->Database->write({ - debug => $debug, - uuid => $uuid, - query => $sql, - source => $THIS_FILE, - line => __LINE__, + debug => $debug, + uuid => $uuid, + query => $sql, + initializing => 1, + source => $THIS_FILE, + line => __LINE__, }); $anvil->data->{sys}{db_initialized}{$uuid} = 1; @@ -11383,6 +11390,10 @@ If this interface is part of a bond, this UUID will be the C<< bonds >> -> C<< b If this interface is connected to a bridge, this is the C<< bridges >> -> C<< bridge_uuid >> of that bridge. +=head3 network_interface_device (optional) + +This is the device name (nmcli's GENERAL.IP-IFACE) of the device. This is the name shown in 'ip addr list'. When the interface is down, this will be blank. Use the MAC address ideally, or the 'connection.id' if needed, to find this interface. + =head3 network_interface_duplex (optional) This can be set to C<< full >>, C<< half >> or C<< unknown >>, with the later being the default. @@ -11409,7 +11420,11 @@ This is the maximum transmit unit (MTU) that this interface supports, in bytes p =head3 network_interface_name (required) -This is the current device name for this interface. +This is the nmcli 'connection.id' name (bios device name) for the current device of this interface. If the previously recorded MAC address is no longer found, but a new/unknown interface with this name is found, it is sane to configure the device with this name as the replacement 'network_interface_device'. + +=head3 network_interface_nmcli_uuid (optional) + +This is the network manager's UUID for this interface. =head3 network_interface_operational (optional) @@ -11439,6 +11454,7 @@ sub insert_or_update_network_interfaces my $link_only = defined $parameter->{link_only} ? $parameter->{link_only} : 0; my $network_interface_bond_uuid = $parameter->{network_interface_bond_uuid} ? $parameter->{network_interface_bond_uuid} : 'NULL'; my $network_interface_bridge_uuid = $parameter->{network_interface_bridge_uuid} ? $parameter->{network_interface_bridge_uuid} : 'NULL'; + my $network_interface_device = defined $parameter->{network_interface_device} ? $parameter->{network_interface_device} : ""; my $network_interface_duplex = defined $parameter->{network_interface_duplex} ? $parameter->{network_interface_duplex} : "unknown"; my $network_interface_host_uuid = defined $parameter->{network_interface_host_uuid} ? $parameter->{network_interface_host_uuid} : $anvil->Get->host_uuid; my $network_interface_link_state = defined $parameter->{network_interface_link_state} ? $parameter->{network_interface_link_state} : "unknown"; @@ -11447,6 +11463,7 @@ sub insert_or_update_network_interfaces my $network_interface_medium = defined $parameter->{network_interface_medium} ? $parameter->{network_interface_medium} : ""; my $network_interface_mtu = defined $parameter->{network_interface_mtu} ? $parameter->{network_interface_mtu} : 0; my $network_interface_name = defined $parameter->{network_interface_name} ? $parameter->{network_interface_name} : ""; + my $network_interface_nmcli_uuid = defined $parameter->{network_interface_nmcli_uuid} ? $parameter->{network_interface_nmcli_uuid} : ""; my $network_interface_speed = defined $parameter->{network_interface_speed} ? $parameter->{network_interface_speed} : 0; my $network_interface_uuid = defined $parameter->{network_interface_uuid} ? $parameter->{network_interface_uuid} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -11457,6 +11474,7 @@ sub insert_or_update_network_interfaces link_only => $link_only, network_interface_bond_uuid => $network_interface_bond_uuid, network_interface_bridge_uuid => $network_interface_bridge_uuid, + network_interface_device => $network_interface_device, network_interface_duplex => $network_interface_duplex, network_interface_host_uuid => $network_interface_host_uuid, network_interface_link_state => $network_interface_link_state, @@ -11465,6 +11483,7 @@ sub insert_or_update_network_interfaces network_interface_medium => $network_interface_medium, network_interface_mtu => $network_interface_mtu, network_interface_name => $network_interface_name, + network_interface_nmcli_uuid => $network_interface_nmcli_uuid, network_interface_speed => $network_interface_speed, network_interface_uuid => $network_interface_uuid, }}); @@ -11523,6 +11542,7 @@ WHERE "; network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address)." AND "; } + ### TODO: We may need to switch this to 'device' if the name or MAC address isn't found $query .= " network_interface_name = ".$anvil->Database->quote($network_interface_name)." AND @@ -11604,8 +11624,10 @@ WHERE my $query = " SELECT network_interface_host_uuid, + network_interface_nmcli_uuid, network_interface_mac_address, network_interface_name, + network_interface_device, network_interface_speed, network_interface_mtu, network_interface_link_state, @@ -11636,20 +11658,24 @@ WHERE foreach my $row (@{$results}) { my $old_network_interface_host_uuid = $row->[0]; + my $old_network_interface_nmcli_uuid = defined $row->[1] ? $row->[1] : 'NULL'; my $old_network_interface_mac_address = $row->[1]; my $old_network_interface_name = $row->[2]; - my $old_network_interface_speed = $row->[3]; - my $old_network_interface_mtu = $row->[4]; - my $old_network_interface_link_state = $row->[5]; - my $old_network_interface_operational = $row->[6]; - my $old_network_interface_duplex = $row->[7]; - my $old_network_interface_medium = $row->[8]; - my $old_network_interface_bond_uuid = defined $row->[9] ? $row->[9] : 'NULL'; - my $old_network_interface_bridge_uuid = defined $row->[10] ? $row->[10] : 'NULL'; + my $old_network_interface_device = $row->[3]; + my $old_network_interface_speed = $row->[4]; + my $old_network_interface_mtu = $row->[5]; + my $old_network_interface_link_state = $row->[6]; + my $old_network_interface_operational = $row->[7]; + my $old_network_interface_duplex = $row->[8]; + my $old_network_interface_medium = $row->[9]; + my $old_network_interface_bond_uuid = defined $row->[10] ? $row->[10] : 'NULL'; + my $old_network_interface_bridge_uuid = defined $row->[11] ? $row->[11] : 'NULL'; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_network_interface_host_uuid => $old_network_interface_host_uuid, + old_network_interface_nmcli_uuid => $old_network_interface_nmcli_uuid, old_network_interface_mac_address => $old_network_interface_mac_address, old_network_interface_name => $old_network_interface_name, + old_network_interface_device => $old_network_interface_device, old_network_interface_speed => $old_network_interface_speed, old_network_interface_mtu => $old_network_interface_mtu, old_network_interface_link_state => $old_network_interface_link_state, @@ -11663,7 +11689,9 @@ WHERE # If 'link_only' is set, we're only checking/updating a subset of values. if ($link_only) { - if (($network_interface_name ne $old_network_interface_name) or + if (($network_interface_nmcli_uuid ne $old_network_interface_nmcli_uuid) or + ($network_interface_name ne $old_network_interface_name) or + ($network_interface_device ne $old_network_interface_device) or ($network_interface_link_state ne $old_network_interface_link_state) or ($network_interface_operational ne $old_network_interface_operational) or ($network_interface_mac_address ne $old_network_interface_mac_address) or @@ -11675,7 +11703,9 @@ UPDATE network_interfaces SET network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid).", + network_interface_nmcli_uuid = ".$anvil->Database->quote($network_interface_nmcli_uuid).", network_interface_name = ".$anvil->Database->quote($network_interface_name).", + network_interface_device = ".$anvil->Database->quote($network_interface_device).", network_interface_link_state = ".$anvil->Database->quote($network_interface_link_state).", network_interface_operational = ".$anvil->Database->quote($network_interface_operational).", network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address).", @@ -11695,7 +11725,9 @@ WHERE # not passed in, we want to not compare it. if (($network_interface_bond_uuid ne $old_network_interface_bond_uuid) or ($network_interface_bridge_uuid ne $old_network_interface_bridge_uuid) or + ($network_interface_nmcli_uuid ne $old_network_interface_nmcli_uuid) or ($network_interface_name ne $old_network_interface_name) or + ($network_interface_device ne $old_network_interface_device) or ($network_interface_duplex ne $old_network_interface_duplex) or ($network_interface_link_state ne $old_network_interface_link_state) or ($network_interface_operational ne $old_network_interface_operational) or @@ -11711,9 +11743,11 @@ UPDATE network_interfaces SET network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid).", + network_interface_nmcli_uuid = ".$anvil->Database->quote($network_interface_nmcli_uuid).", network_interface_bond_uuid = ".$anvil->Database->quote($network_interface_bond_uuid).", network_interface_bridge_uuid = ".$anvil->Database->quote($network_interface_bridge_uuid).", network_interface_name = ".$anvil->Database->quote($network_interface_name).", + network_interface_device = ".$anvil->Database->quote($network_interface_device).", network_interface_duplex = ".$anvil->Database->quote($network_interface_duplex).", network_interface_link_state = ".$anvil->Database->quote($network_interface_link_state).", network_interface_operational = ".$anvil->Database->quote($network_interface_operational).", @@ -11742,9 +11776,11 @@ INSERT INTO network_interfaces ( network_interface_uuid, + network_interface_nmcli_uuid, network_interface_bond_uuid, network_interface_bridge_uuid, network_interface_name, + network_interface_device, network_interface_duplex, network_interface_host_uuid, network_interface_link_state, @@ -11756,9 +11792,11 @@ INSERT INTO modified_date ) VALUES ( ".$anvil->Database->quote($network_interface_uuid).", + ".$anvil->Database->quote($network_interface_nmcli_uuid).", ".$anvil->Database->quote($network_interface_bond_uuid).", ".$anvil->Database->quote($network_interface_bridge_uuid).", ".$anvil->Database->quote($network_interface_name).", + ".$anvil->Database->quote($network_interface_device).", ".$anvil->Database->quote($network_interface_duplex).", ".$anvil->Database->quote($network_interface_host_uuid).", ".$anvil->Database->quote($network_interface_link_state).", @@ -17844,7 +17882,7 @@ sub resync_databases $query .= " ORDER BY utc_modified_date DESC;"; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0074", variables => { - uuid => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid}), + uuid => $anvil->Database->get_host_from_uuid({debug => $debug, short => 1, host_uuid => $uuid}), query => $query, }}); @@ -18090,7 +18128,7 @@ sub resync_databases # Already in, redirect to the history schema. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0029", variables => { table => $table, - host_name => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid}), + host_name => $anvil->Database->get_host_from_uuid({debug => $debug, short => 1, host_uuid => $uuid}), host_uuid => $uuid, column => $uuid_column, uuid => $row_uuid, @@ -18698,6 +18736,10 @@ This records data to one or all of the databases. If a UUID is passed, the query Parameters; +=head3 initializing (optional, default 0) + +When set to C<< 1 >>, this tells the method that the database is being initialized, so some checks and lookups are disabled. + =head3 line (optional) If you want errors to be traced back to the query called, this can be set (usually to C<< __LINE__ >>) along with the C<< source >> parameter. In such a case, if there is an error in this method, the caller's file and line are displayed in the logs. @@ -18737,20 +18779,23 @@ sub write my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->write()" }}); - my $line = $parameter->{line} ? $parameter->{line} : __LINE__; - my $query = $parameter->{query} ? $parameter->{query} : ""; - my $reenter = $parameter->{reenter} ? $parameter->{reenter} : ""; - my $secure = $parameter->{secure} ? $parameter->{secure} : 0; - my $source = $parameter->{source} ? $parameter->{source} : $THIS_FILE; - my $transaction = $parameter->{transaction} ? $parameter->{transaction} : 0; - my $uuid = $parameter->{uuid} ? $parameter->{uuid} : ""; + my $initializing = $parameter->{initializing} ? $parameter->{initializing} : 0; + my $line = $parameter->{line} ? $parameter->{line} : __LINE__; + my $query = $parameter->{query} ? $parameter->{query} : ""; + my $reenter = $parameter->{reenter} ? $parameter->{reenter} : ""; + my $secure = $parameter->{secure} ? $parameter->{secure} : 0; + my $source = $parameter->{source} ? $parameter->{source} : $THIS_FILE; + my $transaction = $parameter->{transaction} ? $parameter->{transaction} : 0; + my $uuid = $parameter->{uuid} ? $parameter->{uuid} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - uuid => $uuid, - line => $line, - query => (not $secure) ? $query : $anvil->Log->is_secure($query), - secure => $secure, - source => $source, - reenter => $reenter, + initializing => $initializing, + line => $line, + query => (not $secure) ? $query : $anvil->Log->is_secure($query), + reenter => $reenter, + secure => $secure, + source => $source, + transaction => $transaction, + uuid => $uuid, }}); if ($uuid) @@ -18784,7 +18829,7 @@ sub write } # If I am still alive check if any locks need to be renewed. - $anvil->Database->check_lock_age({debug => $debug}); + $anvil->Database->check_lock_age({debug => $debug}) if not $initializing; # This array will hold either just the passed DB ID or all of them, if no ID was specified. my @db_uuids; @@ -18841,6 +18886,10 @@ sub write { push @{$query_set}, $this_query; $i++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + this_query => $this_query, + i => $i, + }}); if ($i > $next) { @@ -18871,6 +18920,7 @@ sub write foreach my $this_query (@{$query}) { push @{$query_set}, $this_query; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_query => $this_query }}); } } } @@ -18886,8 +18936,11 @@ sub write foreach my $uuid (@db_uuids) { # Test access to the DB before we do the actual query - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); - $anvil->Database->_test_access({debug => $debug, uuid => $uuid}); + if (not $initializing) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); + $anvil->Database->_test_access({debug => $debug, uuid => $uuid}); + } # Do the actual query(ies) $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -18905,7 +18958,7 @@ sub write if (($anvil->data->{sys}{database}{log_transactions}) or ($debug <= $anvil->Log->level)) { $anvil->Log->entry({source => $source, line => $line, secure => $secure, level => 0, key => "log_0083", variables => { - uuid => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid}), + uuid => $initializing ? $uuid : $anvil->Database->get_host_from_uuid({debug => 1, short => 1, host_uuid => $uuid}), query => $query, }}); } diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 39c4ccfa..93d5773b 100644 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -2165,6 +2165,11 @@ sub os_type $os_type = "centos-stream".$1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }}); } + elsif ($release =~ /AlmaLinux .*? (\d+)/) + { + $os_type = "alma".$1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }}); + } elsif ($release =~ /CentOS .*? (\d+)\./) { # CentOS, with the major version number appended diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 0434afcb..a3bb0416 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -17,6 +17,7 @@ my $THIS_FILE = "Network.pm"; # check_firewall # check_network # check_internet +# collect_data # download # find_access # find_matches @@ -382,6 +383,7 @@ sub check_firewall } +### TODO: Phase this out when EL8 / ifcfg-X file support is ended. =head2 check_network B<< NOTE >>: This method is not yet implemented. @@ -472,7 +474,7 @@ sub check_network my $is_bond = ""; # Read in the file. - my $file_body = $anvil->Storage->read_file({debug => ($debug+1), file => $full_path}); + my $file_body = $anvil->Storage->read_file({debug => $debug, file => $full_path}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); foreach my $line (split/\n/, $file_body) @@ -572,7 +574,7 @@ sub check_network if (-e $carrier_file) { - my $carrier = $anvil->Storage->read_file({debug => ($debug+1), file => $carrier_file}); + my $carrier = $anvil->Storage->read_file({debug => $debug, file => $carrier_file}); chomp $carrier; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier => $carrier }}); @@ -587,7 +589,7 @@ sub check_network if (-e $operstate_file) { - my $operstate = $anvil->Storage->read_file({debug => ($debug+1), file => $operstate_file}); + my $operstate = $anvil->Storage->read_file({debug => $debug, file => $operstate_file}); chomp $operstate; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate => $operstate }}); @@ -904,6 +906,503 @@ sub check_internet return($access); } + +### NOTE: This is the new way of collecting data from nmcli, it is the method to use going forward. +=head2 collect_data + +This method uses Network Manager, sysfs and procfs to collect data about the current state of the network. + +Stored data: + +* nmcli::uuid::::device = 'connection.interface-name', or 'GENERAL.DEVICES'. See note below +* nmcli::uuid::::type = interface, bond, bridge, etc +* nmcli::uuid::::active = 1,0 +* nmcli::uuid::::state = activated,activating,etc +* nmcli::uuid:::: = all 'variable: value' pairs returned by 'nmcli connection show ' +* nmcli::uuid::::mac_address = MAC address (in lower case) +* nmcli::uuid::::connected = 0 is down, unix timestamp (seconds since epoch) of when it connected if up. +* nmcli::uuid::::mtu = This is the MTU (maximum transimssion unit in bytes) of the interface. + +To make it easier to map a device by name or MAC address to a UUID, this lookup hash is provided. Note that 'device' is 'connection.interface-name' when available, falling back to 'GENERAL.DEVICES' otherwise. + +B<< NOTE >>: An inactive interface will not report the 'connection.interface-name', and the bios device name will be returned (which is what is stored in 'GENERAL.DEVICES'. If you're trying to find a device, and the expected name doesn't exist, look up the device by MAC address. If that's not found, then the old GENERAL.DEVICES name can help you identify a replaced interface. + +* nmcli::device::::uuid = interface name (or device name) +* nmcli::mac_address::::uuid = MAC address (lower case) + +Given that a single interface can have multiple IP addresses and routes, the IPs on a given interface are stored using a sequence number <1, 2, 3 ... n>. To make it easier to find what device has an IP, the IPs are stored with a quick access hash. + +* nmcli::ipv4::::on_uuid = interface UUID +* nmcli::ipv4::::sequence = sequence number +* nmcli::uuid::::ipv{4,6}::ip::::ip_address = IP address +* nmcli::uuid::::ipv{4,6}::ip::::subnet_mask = subnet mask (CIDR notation) +* nmcli::uuid::::ipv{4,6}::dns = comma-separated list of DNS IP addresses +* nmcli::uuid::::ipv{4,6}::gateway = comma-separated list of DNS IP addresses +* nmcli::uuid::::ipv{4,6}::route:: = Route info (ie: 'dst = 0.0.0.0/0, nh = 192.168.255.254, mt = 428', or 'dst = 192.168.0.0/16, nh = 0.0.0.0, mt = 428'.) + +Bond data is stored in these hashes; + +* nmcli::bond::::uuid = The UUID on the bond +* nmcli::bond::::carrier = 1,0 - indicates if the bond has a connection or not. +* nmcli::bond::::operstate = 1,0 - indicates if the bond is operational or not. +* nmcli::bond::::up = 1,0 - indicates if the bond up up or not. +* nmcli::bond::::interface::::up = 1,0 - indicates if the child interface is up or not. + +Bridge data is simple, but also made easy to find. The only real data is the hash references for the interfaces connected to the bridge. + +* nmcli::bridge::::uuid = The UUID of the bridge +* nmcli::bridge::::interface::::status = This is the link data for the connected interface (ie: 'BROADCAST,MULTICAST,MASTER,UP,LOWER_UP'). + +To make it easier to find interfaces, the following look up hash is available. + +* nmcli::interface::::uuid = The UUID of the interface +* nmcli::mac_address::::uuid = $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, + +This method takes no parameters + +=cut +sub collect_data +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->check_internet()" }}); + + # Use nmcli to collect the data. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type,active,state connection show"; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^(.*?):(.*?):(.*?):(.*?)$/) + { + my $uuid = $1; + my $type = $2; + my $active = $3; + my $state = $4; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + uuid => $uuid, + type => $type, + active => $active, + 'state' => $state, + }}); + next if $type eq "loopback"; + + if ($type eq "802-3-ethernet") + { + $type = "interface"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + } + + $anvil->data->{nmcli}{uuid}{$uuid}{type} = $type; + $anvil->data->{nmcli}{uuid}{$uuid}{active} = lc($active) eq "yes" ? 1 : 0; + $anvil->data->{nmcli}{uuid}{$uuid}{'state'} = lc($state); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::type" => $anvil->data->{nmcli}{uuid}{$uuid}{type}, + "nmcli::uuid::${uuid}::active" => $anvil->data->{nmcli}{uuid}{$uuid}{active}, + "nmcli::uuid::${uuid}::state" => $anvil->data->{nmcli}{uuid}{$uuid}{'state'}, + }}); + } + } + + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); + + # Collect all the rest of the data now. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection show ".$uuid; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^(.*?):\s+(.*)$/) + { + my $variable = $1; + my $value = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:variable' => $variable, + 's2:value' => $value, + }}); + + $anvil->data->{nmcli}{uuid}{$uuid}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${variable}" => $anvil->data->{nmcli}{uuid}{$uuid}{$variable}, + }}); + + if ($variable =~ /IP(\d).ADDRESS\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, + }}); + + if (($ip_type == 4) && ($value =~ /^(.*?)\/(.*)$/)) + { + my $ip_address = $1; + my $subnet_mask = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_address => $ip_address, + subnet_mask => $subnet_mask, + }}); + + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $1; + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = $2; + $anvil->data->{nmcli}{ipv4}{$ip_address}{on_uuid} = $uuid; + $anvil->data->{nmcli}{ipv4}{$ip_address}{sequence} = $sequence; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, + "nmcli::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, + "nmcli::ipv4::${ip_address}::on_uuid" => $anvil->data->{nmcli}{ipv4}{$ip_address}{on_uuid}, + "nmcli::ipv4::${ip_address}::sequence" => $anvil->data->{nmcli}{ipv4}{$ip_address}{sequence}, + }}); + } + else + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $value; + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = ""; + $anvil->data->{nmcli}{ipv4}{$value}{on_uuid} = $value; + $anvil->data->{nmcli}{ipv4}{$value}{sequence} = $sequence; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, + "nmcli::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, + "nmcli::ipv4::${value}::on_uuid" => $anvil->data->{nmcli}{ipv4}{$value}{on_uuid}, + "nmcli::ipv4::${value}::sequence" => $anvil->data->{nmcli}{ipv4}{$value}{sequence}, + }}); + + } + + # Make sure the DNS key exists. + if (not exists $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}) + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}, + }}); + } + if (not exists $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway}) + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway}, + }}); + } + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway}, + }}); + } + if ($variable =~ /IP(\d).ROUTE\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, + }}); + + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{route}{$sequence} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::route::${sequence}" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{route}{$sequence}, + }}); + } + if ($variable =~ /IP(\d).DNS\[(\d+)\]/) + { + my $ip_type = $1; + my $sequence = $2; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + sequence => $sequence, + hash_key => $hash_key, + }}); + + if ((exists $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}) and ($anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} ne "")) + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} .= ",".$value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{nmcli}{uuid}{$uuid}{$sequence}{dns}, + }}); + } + else + { + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}, + }}); + } + } + if ($variable =~ /IP(\d).GATEWAY/) + { + my $ip_type = $1; + my $hash_key = "ipv".$ip_type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_type => $ip_type, + hash_key => $hash_key, + }}); + + $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{gateway}, + }}); + } + } + } + } + + # Now loop through and look for the name that maps to what's shown in 'ip addr list'. This can be a bit tricky. + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) + { + my $connection_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'} // ""; + my $general_devices = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.DEVICES'} // ""; + my $device_type = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.type'} // ""; + my $device = $connection_interface_name ne "--" ? $connection_interface_name : $general_devices; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:uuid' => $uuid, + 's2:connection_interface_name' => $connection_interface_name, + 's3:general_devices' => $general_devices, + 's4:device_type' => $device_type, + 's5:device' => $device, + }}); + + if ($device) + { + $anvil->data->{nmcli}{device}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::device::${device}::uuid" => $anvil->data->{nmcli}{device}{$device}{uuid}, + }}); + + ### Get some data from sysfs. + $anvil->data->{nmcli}{uuid}{$uuid}{device} = $device; + $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = ""; + $anvil->data->{nmcli}{uuid}{$uuid}{type} = ""; + $anvil->data->{nmcli}{uuid}{$uuid}{mtu} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::device" => $anvil->data->{nmcli}{uuid}{$uuid}{device}, + }}); + + # The 'connection.timestamp' seems to be where the 'connected' (as in, have an IP) + # comes from. + $anvil->data->{nmcli}{uuid}{$uuid}{connected} = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.timestamp'} ? $anvil->data->{nmcli}{uuid}{$uuid}{'connection.timestamp'} : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::connected" => $anvil->data->{nmcli}{uuid}{$uuid}{connected}, + }}); + + if ($device_type eq "bond") + { + $anvil->data->{nmcli}{bond}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::bond::${device}::uuid" => $anvil->data->{nmcli}{bond}{$device}{uuid}, + }}); + + # Read the interface's carrier + my $carrier_file = "/sys/class/net/".$device."/carrier"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier_file => $carrier_file }}); + + if (-e $carrier_file) + { + my $carrier = $anvil->Storage->read_file({debug => $debug, file => $carrier_file}); + chomp $carrier; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier => $carrier }}); + + $anvil->data->{nmcli}{bond}{$device}{carrier} = $carrier; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${device}::carrier" => $anvil->data->{nmcli}{bond}{$device}{carrier}, + }}); + } + + my $operstate_file = "/sys/class/net/".$device."/operstate"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate_file => $operstate_file }}); + + if (-e $operstate_file) + { + my $operstate = $anvil->Storage->read_file({debug => $debug, file => $operstate_file}); + chomp $operstate; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate => $operstate }}); + + $anvil->data->{nmcli}{bond}{$device}{up} = $operstate eq "up" ? 1 : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${device}::operstate" => $anvil->data->{nmcli}{bond}{$device}{operstate}, + }}); + } + + # Read in the /proc file. + my $proc_file = "/proc/net/bonding/".$device; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { proc_file => $proc_file }}); + + my $in_link = ""; + my $file_body = $anvil->Storage->read_file({debug => $debug, file => $proc_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); + foreach my $line (split/\n/, $file_body) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); + + if ($line =~ /Slave Interface: (.*)$/) + { + $in_link = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_link => $in_link }}); + next; + } + if (not $line) + { + $in_link = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_link => $in_link }}); + next; + } + if ($in_link) + { + if ($line =~ /MII Status: (.*)$/) + { + my $status = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }}); + if ($status eq "up") + { + $anvil->data->{nmcli}{bond}{$device}{interface}{$in_link}{up} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${device}::interface::${in_link}::up" => $anvil->data->{nmcli}{bond}{$device}{interface}{$in_link}{up}, + }}); + } + else + { + $anvil->data->{nmcli}{bond}{$device}{interface}{$in_link}{up} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${device}::interface::${in_link}::up" => $anvil->data->{nmcli}{bond}{$device}{interface}{$in_link}{up}, + }}); + } + next; + } + } + else + { + if ($line =~ /MII Status: (.*)$/) + { + my $status = $1; + $anvil->data->{nmcli}{bond}{$device}{up} = $status eq "up" ? 1 : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + status => $status, + "nmcli::bond::${device}::up" => $anvil->data->{nmcli}{bond}{$device}{up}, + }}); + next; + } + } + } + } + elsif ($device_type eq "bridge") + { + $anvil->data->{nmcli}{bridge}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::bridge::${device}::uuid" => $anvil->data->{nmcli}{bridge}{$device}{uuid}, + }}); + + # See what interfaces are connected to the bridge. + my $shell_call = $anvil->data->{path}{exe}{ip}." link show master ".$device; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^\d+: (.*?): <(.*?)>/) + { + my $interface = $1; + my $status = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + status => $status, + }}); + + $anvil->data->{nmcli}{bridge}{$device}{interface}{$interface}{status} = $status; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::bridge::${device}::interface::${interface}::status" => $anvil->data->{nmcli}{bridge}{$device}{interface}{$interface}{status}, + }}); + } + } + } + elsif (($device_type eq "802-3-ethernet") or ($device_type eq "interface")) + { + $anvil->data->{nmcli}{interface}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::interface::${device}::uuid" => $anvil->data->{nmcli}{interface}{$device}{uuid}, + }}); + + # MAC address + my $mac_address_file = "/sys/class/net/".$device."/address"; + my $type_file = "/sys/class/net/".$device."/type"; + my $mtu_file = "/sys/class/net/".$device."/mtu"; + if (-e $mac_address_file) + { + my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); + $mac_address =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + + if (($mac_address) && ($mac_address ne "!!error!!")) + { + $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = $mac_address; + $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::mac_address" => $anvil->data->{nmcli}{uuid}{$uuid}{mac_address}, + "nmcli::mac_address::${mac_address}::uuid" => $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, + }}); + } + } + if (-e $type_file) + { + my $type = $anvil->Storage->read_file({file => $type_file}); + $type =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + + if (($type) && ($type ne "!!error!!")) + { + $anvil->data->{nmcli}{uuid}{$uuid}{type} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::type" => $anvil->data->{nmcli}{uuid}{$uuid}{type}, + }}); + } + } + if (-e $mtu_file) + { + my $mtu = $anvil->Storage->read_file({file => $mtu_file}); + $mtu =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mtu => $mtu }}); + + if (($mtu) && ($mtu ne "!!error!!")) + { + $anvil->data->{nmcli}{uuid}{$uuid}{mtu} = $mtu; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::mtu" => $anvil->data->{nmcli}{uuid}{$uuid}{mtu}, + }}); + } + } + } + } + } + + return(0); +} + + + =head2 download This downloads a file from a network target and saves it to a local file. This must be called on a local system so that the download progress can be reported. @@ -3922,6 +4421,8 @@ sub ping return($pinged, $average_ping_time); } + +### TODO: Phase this out when EL8 / ifcfg-X file support is ended. =head2 read_nmcli This method reads and parses the C<< nmcli >> data. The data is stored as; @@ -4060,7 +4561,7 @@ sub read_nmcli # Read the file, see if we can find it there. if (-e $filename) { - my $file_body = $anvil->Storage->read_file({debug => ($debug+1), file => $filename}); + my $file_body = $anvil->Storage->read_file({debug => $debug, file => $filename}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); foreach my $line (split/\n/, $file_body) @@ -4326,7 +4827,7 @@ sub _get_drbd_ports $full_path =~ s/\/\//\//g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { full_path => $full_path }}); - my $file_body = $anvil->Storage->read_file({debug => ($debug+1), file => $full_path}); + my $file_body = $anvil->Storage->read_file({debug => $debug, file => $full_path}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); foreach my $line (split/\n/, $file_body) diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index e8e07bb1..f6e4d971 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -26,6 +26,7 @@ my $THIS_FILE = "System.pm"; # check_if_configured # check_ssh_keys # check_memory +# check_network_type # check_storage # collect_ipmi_data # configure_ipmi @@ -1279,6 +1280,51 @@ sub check_ssh_keys } +=head2 check_network_type + +This method checks to see if this host is using network manager to configure the network, versus the older C<< ifcfg-X >> based config. It does this by looking for any C<< ifcfg-X >> files in C<< /etc/sysconfig/network-scripts >>. + +If any 'ifcfg-X' files are found, C<< ifcfg >> is returned. Otherwise, C<< nm >> is returned. + +This method takes no parameters. + +=cut +sub check_network_type +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->check_storage()" }}); + + # Open the 'ifcfg' directory, if it exists, and see if there are any 'ifcfg-X' files. + my $type = "nm"; + my $directory = $anvil->data->{path}{directories}{ifcfg}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { directory => $directory }}); + + if (-e $directory) + { + local(*DIRECTORY); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0018", variables => { directory => $directory }}); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file => $file }}); + if ($file =~ /^ifcfg-(.*)$/) + { + $type = "ifcfg"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }}); + last; + } + } + closedir(DIRECTORY); + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }}); + return($type); +} + + =head2 check_storage Thic gathers LVM data from the local system. diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 7c6292f5..4d5f70de 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -460,19 +460,9 @@ sub collect_data { my ($anvil) = @_; - $anvil->Network->get_ips({debug => 2}); - - # Read the data from the ifcfg files, if available. We'll use this to check for bond interfaces that - # didn't start. - $anvil->Network->check_network(); - my $uptime = $anvil->Get->uptime(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uptime => $uptime }}); - if ($uptime < 600) - { - $anvil->Network->read_nmcli({debug => 2}) - } # The 'local_host' is needed to pull data recorded by Network->get_ips(); + $anvil->Network->get_ips({debug => 2}); my $local_host = $anvil->Get->short_host_name(); my $directory = "/sys/class/net"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { @@ -480,6 +470,7 @@ sub collect_data directory => $directory, }}); + ### TODO: Convert this to use Sys::Virt # Make sure there are no virsh bridges, removing any found. my $host_type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); @@ -516,60 +507,407 @@ sub collect_data set_by => $THIS_FILE, }); } -=cut - my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-list --all --name"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - - # This often hangs. - my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - if (not $return_code) + } + + ### TODO: Remove this check when ifcfg-X support is dropped. + my $network_type = $anvil->System->check_network_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + if ($network_type eq "ifcfg") + { + # Using the old 'ifcfg-X' style. + collect_data_ifcfg($anvil); + return(0); + } + + # Collect data from nmcli + $anvil->Network->collect_data({debug => 2}); + + # Walk through the sysfs files. + local(*DIRECTORY); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }}); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) + { + next if $file eq "."; + next if $file eq ".."; + next if $file eq "lo"; + my $full_path = $directory."/".$file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); + if (-d $full_path) { - # Virsh is up. - foreach my $line (split/\n/, $output) + # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. + my $interface = $file; + my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; + my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; + my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? + my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down + my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; + my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link + my $media = "unknown"; + my $type = "interface"; + my $driver = ""; + my $tx_bytes = 0; # How many bytes transmitted + my $rx_bytes = 0; # How many bytes received + + # Clean up some newlines. + $link_state =~ s/\n$//; + $mtu =~ s/\n$//; + $duplex =~ s/\n$//; + $operational =~ s/\n$//; + $speed =~ s/\n$//; + $modalias =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + link_state => $link_state, + mtu => $mtu, + duplex => $duplex, + operational => $operational, + speed => $speed, + modalias => $modalias, + }}); + + ### NOTE: This only parses virtio so far. + # Pick out our driver. + if ($modalias =~ /^virtio:/) { - $line =~ s/^\s+//; - $line =~ s/\s+$//; - next if not $line; - next if $line =~ /^error/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "striker_0287", variables => { bridge => $line }}); - - my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy ".$line; - $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}); + $driver = "virtio"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver => $driver }}); + } + + # The MAC address can faked by a number of ways, so we make an explicit call to 'ethtool' to get the permanent mac address. + my $mac_address = ""; + my $shell_call = $anvil->data->{path}{exe}{ethtool}." -P ".$interface; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + if ($output =~ /(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/) + { + $mac_address = lc($1); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + else + { + # Get it by reading the address file. + if (-e $full_path."/bonding_slave/perm_hwaddr") + { + $mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + elsif (-e $full_path."/address") + { + $mac_address = $anvil->Storage->read_file({file => $full_path."/address"}); + $mac_address =~ s/\n//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + } + + # These are variables that will be needed if this is a bond interface. + my $ip_address = ""; + my $subnet_mask = ""; + my $bond_mode = ""; + my $primary_interface = ""; + my $primary_reselect = ""; + my $active_interface = ""; + my $mii_polling_interval = ""; + my $up_delay = ""; + my $down_delay = ""; + my $bond_master = ""; + + # These are variables that will be needed if this is a bridge interface + my $bridge_id = ""; + my $bridge_stp_enabled = ""; + + # Explicitly check for the existing of the hash so that we don't auto-vivivate the interface. + if (exists $anvil->data->{network}{$local_host}{interface}{$interface}) + { + $ip_address = defined $anvil->data->{network}{$local_host}{interface}{$interface}{ip} ? $anvil->data->{network}{$local_host}{interface}{$interface}{ip} : ""; + $subnet_mask = defined $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} ? $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} : ""; + $type = defined $anvil->data->{network}{$local_host}{interface}{$interface}{type} ? $anvil->data->{network}{$local_host}{interface}{$interface}{type} : "interface"; + $tx_bytes = defined $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes} ? $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes} : 0; + $rx_bytes = defined $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes} ? $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes} : 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, + ip_address => $ip_address, + subnet_mask => $subnet_mask, + type => $type, + rx_bytes => $rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", + tx_bytes => $tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", }}); - - $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine ".$line; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + } + + # If this interface is already a bond slave, the real mac address will be in a + # sub-directory. + my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr"; + if (-e $mac_bond_file) + { + # It's a slave. + $mac_address = $anvil->Storage->read_file({file => $mac_bond_file}); + $mac_address =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + + # If this is a virtual interface, set some fake values that don't actually exist on + # the system for the sake of a cleaner display. + if (($mac_address =~ /^52:54:00/) or ($driver eq "virtio")) + { + ### Set some fake values. + # Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary. + if ((not $speed) or ($speed eq "-1")) + { + $speed = 10000; + } + if ((not $duplex) or ($duplex eq "unknown")) + { + $duplex = "full"; + } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, + speed => $speed, + duplex => $duplex, }}); + } + # If the state is 'down', set the speed to '0'. + if (not $link_state) + { + $speed = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); + } + + # Is this a bond interface? + if (-e "/proc/net/bonding/".$interface) + { + # Yup, we'll neet to dig into the bond proc files to get the proper slaved + # interface MAC addresses. + $type = "bond"; - # Register an alert - my $variables = { - bridge => $line, - }; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0001", variables => $variables}); - $anvil->Alert->register({ - alert_level => "notice", - message => "scan_network_alert_0001", - variables => $variables, - set_by => $THIS_FILE, - }); + # Read the bond mode. + $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); + $primary_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"}); + $primary_reselect = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"}); + $active_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"}); + $mii_polling_interval = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"}); + $up_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"}); + $down_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"}); + $bond_mode =~ s/\s.*//; + $bond_mode =~ s/\n$//; + $primary_interface =~ s/\n$//; + $primary_reselect =~ s/\s.*//; + $primary_reselect =~ s/\n$//; + $active_interface =~ s/\n$//; + $mii_polling_interval =~ s/\n$//; + $up_delay =~ s/\n$//; + $down_delay =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + active_interface => $active_interface, + bond_mode => $bond_mode, + mii_polling_interval => $mii_polling_interval, + primary_reselect => $primary_reselect, + primary_interface => $primary_interface, + type => $type, + }}); + } + elsif ((-e $full_path."/master") && ($interface !~ /^vnet/)) + { + # We're in a bond. + my $target = readlink($full_path."/master"); + $bond_master = ($target =~ /^.*\/(.*)$/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + target => $target, + bond_master => $bond_master, + }}); + } + elsif (-d $full_path."/bridge") + { + # It's a bridge + $type = "bridge"; + $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); + $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); + $bridge_id =~ s/\n$//; + $bridge_stp_enabled =~ s/\n$//; + $speed = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bridge_id => $bridge_id, + bridge_stp_enabled => $bridge_stp_enabled, + type => $type, + }}); + if ($bridge_stp_enabled eq "0") + { + $bridge_stp_enabled = "disabled"; + } + elsif ($bridge_stp_enabled eq "1") + { + $bridge_stp_enabled = "enabled_kernel"; + } + elsif ($bridge_stp_enabled eq "2") + { + $bridge_stp_enabled = "enabled_userland"; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_stp_enabled => $bridge_stp_enabled }}); + } + + # If this is a 'vnet' device, set 'operational' to up + if ($interface =~ /^vnet/) + { + $operational = "up"; + $media = "virtual"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + operational => $operational, + media => $media, + }}); + } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + active_interface => $active_interface, + bond_master => $bond_master, + bond_mode => $bond_mode, + bridge_id => $bridge_id, + bridge_stp_enabled => $bridge_stp_enabled, + down_delay => $down_delay, + duplex => $duplex, + interface => $interface, + mac_address => $mac_address, + mii_polling_interval => $mii_polling_interval, + mtu => $mtu, + operational => $operational, + primary_reselect => $primary_reselect, + primary_interface => $primary_interface, + speed => $speed, + subnet_mask => $subnet_mask, + type => $type, + up_delay => $up_delay, + }}); + + # If the MAC address starts with '52:54:00', we've got a virtio NIC. + if ((not defined $speed) or ($speed eq "")) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0001", variables => { file => $full_path."/speed" }}); + next; + } + if ($speed =~ /\D/) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0002", variables => { + file => $full_path."/speed", + speed => $speed, + }}); + next; + } + if ($speed > 100000) + { + # NOTE: This is probably 0 now... Though someday >100 Gbps will be reasonable + # and we'll need to change this. + $speed = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); + } + + # Find the media, if possible. + (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"}); + foreach my $line (split/\n/, $ethtool) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /Supported ports: \[ (.*?) \]/i) + { + $media = lc($1); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); + + # This can be 'tp mii', which breaks json. + if ($media =~ /\t/) + { + $media =~ s/\t/,/g; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); + } + last; + } + } + + # Store new information we found. + $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface} = $active_interface; + $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode} = $bond_mode; + $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master} = $bond_master; + $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id} = $bridge_id; + $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled} = $bridge_stp_enabled; + $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay} = $down_delay; + $anvil->data->{network}{$local_host}{interface}{$interface}{duplex} = $duplex; + $anvil->data->{network}{$local_host}{interface}{$interface}{ip} = $ip_address; + $anvil->data->{network}{$local_host}{interface}{$interface}{link_state} = $link_state; + $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address} = $mac_address; + $anvil->data->{network}{$local_host}{interface}{$interface}{media} = $media; + $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval} = $mii_polling_interval; + $anvil->data->{network}{$local_host}{interface}{$interface}{mtu} = $mtu; + $anvil->data->{network}{$local_host}{interface}{$interface}{operational} = $operational; + $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect} = $primary_reselect; + $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface} = $primary_interface; + $anvil->data->{network}{$local_host}{interface}{$interface}{speed} = $speed; + $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} = $subnet_mask; + $anvil->data->{network}{$local_host}{interface}{$interface}{type} = $type; + $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay} = $up_delay; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "network::${local_host}::interface::${interface}::active_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}, + "network::${local_host}::interface::${interface}::bond_mode" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}, + "network::${local_host}::interface::${interface}::bond_master" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}, + "network::${local_host}::interface::${interface}::bridge_id" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}, + "network::${local_host}::interface::${interface}::bridge_stp_enabled" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}, + "network::${local_host}::interface::${interface}::down_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}, + "network::${local_host}::interface::${interface}::duplex" => $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}, + "network::${local_host}::interface::${interface}::ip" => $anvil->data->{network}{$local_host}{interface}{$interface}{ip}, + "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, + "network::${local_host}::interface::${interface}::mac_address" => $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}, + "network::${local_host}::interface::${interface}::media" => $anvil->data->{network}{$local_host}{interface}{$interface}{media}, + "network::${local_host}::interface::${interface}::mii_polling_interval" => $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}, + "network::${local_host}::interface::${interface}::mtu" => $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}, + "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, + "network::${local_host}::interface::${interface}::primary_reselect" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}, + "network::${local_host}::interface::${interface}::primary_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}, + "network::${local_host}::interface::${interface}::speed" => $anvil->data->{network}{$local_host}{interface}{$interface}{speed}, + "network::${local_host}::interface::${interface}::subnet_mask" => $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}, + "network::${local_host}::interface::${interface}::type" => $anvil->data->{network}{$local_host}{interface}{$interface}{type}, + "network::${local_host}::interface::${interface}::up_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}, + }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, + "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, + }}); + + # If this is a link and there's no database connections, cache the data. + if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) + { + $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cache::new_file" => $anvil->data->{cache}{new_file}, + }}); } } -=cut } + closedir(DIRECTORY); + + die; + + return(0); +} + +### TODO: Remove this when ifcfg support is dropped. +sub collect_data_ifcfg +{ + my ($anvil) = @_; + + # Read the data from the ifcfg files, if available. We'll use this to check for bond interfaces that + # didn't start. + $anvil->Network->check_network(); + my $uptime = $anvil->Get->uptime(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uptime => $uptime }}); + if ($uptime < 600) + { + $anvil->Network->read_nmcli({debug => 2}) + } + + # The 'local_host' is needed to pull data recorded by Network->get_ips(); + my $local_host = $anvil->Get->short_host_name(); + my $directory = "/sys/class/net"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + directory => $directory, + }}); # Walk through the sysfs files. local(*DIRECTORY); @@ -2413,6 +2751,8 @@ sub check_interfaces new_rx_bytes => $new_rx_bytes, }}); + my $new_nmcli_uuid = ""; + # Find the bridge, if any, and the bond UUID, if there's a bond name. if ($new_bond_name) { @@ -2815,9 +3155,11 @@ sub check_interfaces { my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, + network_interface_nmcli_uuid => $new_nmcli_uuid, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, network_interface_name => $network_interface_name, + network_interface_device => $network_interface_device, network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, @@ -2948,9 +3290,11 @@ sub check_interfaces # Record the interface my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, + network_interface_nmcli_uuid => $new_nmcli_uuid, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, network_interface_name => $network_interface_name, + network_interface_device => $network_interface_device, network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, diff --git a/share/anvil.sql b/share/anvil.sql index a6156bf1..91b39b15 100644 --- a/share/anvil.sql +++ b/share/anvil.sql @@ -1011,8 +1011,10 @@ CREATE TRIGGER trigger_bonds CREATE TABLE network_interfaces ( network_interface_uuid uuid not null primary key, network_interface_host_uuid uuid not null, - network_interface_mac_address text not null, - network_interface_name text not null, -- This is the current name of the interface. + network_interface_nmcli_uuid uuid, -- This is the nmcli UUID used to track the device. It can change, so we can't used this as the main UUID + network_interface_mac_address text not null, -- This is the interface MAC address, and it can change if a failed controller it replaced. + network_interface_name text not null, -- This is the current name (network manager's connection.id) of the interface. + network_interface_device text not null, -- This is the current device name (network manager's ) of the interface. network_interface_speed bigint not null, -- This is the speed, in bits-per-second, of the interface. network_interface_mtu bigint not null, -- This is the MTU (Maximum Transmitable Size), in bytes, for this interface. network_interface_link_state text not null, -- 0 or 1 @@ -1033,8 +1035,10 @@ CREATE TABLE history.network_interfaces ( history_id bigserial, network_interface_uuid uuid not null, network_interface_host_uuid uuid, + network_interface_nmcli_uuid uuid, network_interface_mac_address text, network_interface_name text, + network_interface_device text, network_interface_speed bigint, network_interface_mtu bigint, network_interface_link_state text, @@ -1056,8 +1060,10 @@ BEGIN INSERT INTO history.network_interfaces (network_interface_uuid, network_interface_host_uuid, + network_interface_nmcli_uuid, network_interface_mac_address, network_interface_name, + network_interface_device, network_interface_speed, network_interface_mtu, network_interface_link_state, @@ -1070,8 +1076,10 @@ BEGIN VALUES (history_network_interfaces.network_interface_uuid, history_network_interfaces.network_interface_host_uuid, + history_network_interfaces.network_interface_nmcli_uuid, history_network_interfaces.network_interface_mac_address, history_network_interfaces.network_interface_name, + history_network_interfaces.network_interface_device, history_network_interfaces.network_interface_speed, history_network_interfaces.network_interface_mtu, history_network_interfaces.network_interface_link_state, @@ -1167,6 +1175,8 @@ CREATE TRIGGER trigger_ip_addresses FOR EACH ROW EXECUTE PROCEDURE history_ip_addresses(); +/* + TODO - This will be added only if we need to use it if the existing network tables aren't sufficient -- This stores information about network interfaces on hosts. It is mainly used to match a MAC address to a -- host. Given that it is possible that network devices can move, the linkage to the host_uuid can change. CREATE TABLE network_manager ( @@ -1247,6 +1257,7 @@ ALTER FUNCTION history_network_manager() OWNER TO admin; CREATE TRIGGER trigger_network_manager AFTER INSERT OR UPDATE ON network_manager FOR EACH ROW EXECUTE PROCEDURE history_network_manager(); +*/ -- This stores files made available to Anvil! systems and DR hosts. diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 231341ac..955e9a8d 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -494,6 +494,7 @@ ORDER BY { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); +=cut my $count = 0; if ($network_type eq "bcn") { $count = $bcn_count; } elsif ($network_type eq "sn") { $count = $sn_count; } @@ -1355,7 +1356,9 @@ ORDER BY next; } } +=cut } +die; # If we should reset, do so now. if ($anvil->data->{sys}{reboot}) diff --git a/tools/anvil-daemon b/tools/anvil-daemon index d9211655..510a1b3f 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -75,6 +75,7 @@ $anvil->System->wait_on_dnf(); $anvil->Database->connect({ check_if_configured => 1, check_for_resync => 2, + debug => 2, }); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0132"}); @@ -425,6 +426,9 @@ sub set_delay return($delay); } +### NOTE: This used to call 'Network->check_network', which is now 'scan_network' and no longer tries to +### bring up downed connections. Likely this entire method can be removed, now that we're not using +### ifcfg-X files. # This checks to see if it's time to see if the network is ok and, if the system has been up long enough, # checks and tries to repair network issues. sub check_network @@ -450,19 +454,11 @@ sub check_network $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }}); } - #$anvil->Network->check_network({heal => "all"}); - $anvil->data->{sys}{network}{initial_checks} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::network::initial_checks" => $anvil->data->{sys}{network}{initial_checks}, }}); } - else - { - ### NOTE: This is constantly trying to "fix" healthy bonds, without a know way to - ### trigger to debug. As such, disabling for now. - #$anvil->Network->check_network({heal => "down_only"}); - } check_firewall($anvil); } diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network index 2b632a2f..89557f8b 100755 --- a/tools/anvil-monitor-network +++ b/tools/anvil-monitor-network @@ -44,10 +44,16 @@ $anvil->data->{network_manager}{want}{interface}{sn1_link1}{device} = "enp $anvil->data->{network_manager}{want}{interface}{sn1_link2}{mac_address} = "52:54:00:2f:02:1b"; $anvil->data->{network_manager}{want}{interface}{sn1_link2}{device} = "enp11s0"; +$anvil->data->{network_manager}{want}{interface}{mn1_link1}{mac_address} = ""; +$anvil->data->{network_manager}{want}{interface}{mn1_link1}{device} = ""; +$anvil->data->{network_manager}{want}{interface}{mn1_link2}{mac_address} = ""; +$anvil->data->{network_manager}{want}{interface}{mn1_link2}{device} = ""; + # Bonds $anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{interfaces} = ["ifn1_link1", "ifn1_link2"]; # First interface is primary $anvil->data->{network_manager}{want}{bond}{bcn1_bond1}{interfaces} = ["bcn1_link1", "bcn1_link2"]; $anvil->data->{network_manager}{want}{bond}{sn1_bond1}{interfaces} = ["sn1_link1", "sn1_link2"]; +$anvil->data->{network_manager}{want}{bond}{mn1_bond1}{interfaces} = ["mn1_link1", "mn1_link2"]; # Bridges $anvil->data->{network_manager}{want}{bridge}{ifn1_bridge1}{on} = "ifn1_bond1"; @@ -59,15 +65,20 @@ $anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{subnet_mask} = "255.2 $anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{gateway} = "192.168.255.254"; $anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{dns} = "8.8.8.8,8.8.4.4"; +$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{ip_address} = "10.201.4.42"; +$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{subnet_mask} = "255.255.0.0"; +$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{gateway} = ""; +$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{dns} = ""; + $anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{ip_address} = "10.101.4.42"; $anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{subnet_mask} = "255.255.0.0"; $anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{gateway} = ""; $anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{dns} = ""; -$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{ip_address} = "10.201.4.42"; -$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{subnet_mask} = "255.255.0.0"; -$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{gateway} = ""; -$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{dns} = ""; +$anvil->data->{network_manager}{want}{ip_on}{mn1_bond1}{ip_address} = "10.199.4.42"; +$anvil->data->{network_manager}{want}{ip_on}{mn1_bond1}{subnet_mask} = "255.255.0.0"; +$anvil->data->{network_manager}{want}{ip_on}{mn1_bond1}{gateway} = ""; +$anvil->data->{network_manager}{want}{ip_on}{mn1_bond1}{dns} = ""; $anvil->data->{sys}{reboot_needed} = 0; $anvil->data->{sys}{make_changes} = 1; diff --git a/tools/anvil-version-changes b/tools/anvil-version-changes index d1932520..dea4b1ff 100755 --- a/tools/anvil-version-changes +++ b/tools/anvil-version-changes @@ -63,6 +63,9 @@ sub striker_checks { my ($anvil) = @_; + # This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists. + update_network_interfaces($anvil); + # This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists. update_file_location_ready($anvil); @@ -243,12 +246,156 @@ CREATE TRIGGER trigger_dr_links return(0); } +sub update_network_interfaces +{ + my ($anvil) = @_; + + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) + { + my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'network_interfaces' AND column_name = 'network_interface_device';"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + if (not $count) + { + my $queries = []; + push @{$queries}, "ALTER TABLE public.network_interfaces ADD COLUMN network_interface_device text not null DEFAULT '';"; + push @{$queries}, "ALTER TABLE history.network_interfaces ADD COLUMN network_interface_device text;"; + push @{$queries}, "DROP FUNCTION history_network_interfaces() CASCADE;"; + push @{$queries}, q|CREATE FUNCTION history_network_interfaces() RETURNS trigger +AS $$ +DECLARE + history_network_interfaces RECORD; +BEGIN + SELECT INTO history_network_interfaces * FROM network_interfaces WHERE network_interface_uuid = new.network_interface_uuid; + INSERT INTO history.network_interfaces + (network_interface_uuid, + network_interface_host_uuid, + network_interface_nmcli_uuid, + network_interface_mac_address, + network_interface_name, + network_interface_device, + network_interface_speed, + network_interface_mtu, + network_interface_link_state, + network_interface_operational, + network_interface_duplex, + network_interface_medium, + network_interface_bond_uuid, + network_interface_bridge_uuid, + modified_date) + VALUES + (history_network_interfaces.network_interface_uuid, + history_network_interfaces.network_interface_host_uuid, + history_network_interfaces.network_interface_nmcli_uuid, + history_network_interfaces.network_interface_mac_address, + history_network_interfaces.network_interface_name, + history_network_interfaces.network_interface_device, + history_network_interfaces.network_interface_speed, + history_network_interfaces.network_interface_mtu, + history_network_interfaces.network_interface_link_state, + history_network_interfaces.network_interface_operational, + history_network_interfaces.network_interface_duplex, + history_network_interfaces.network_interface_medium, + history_network_interfaces.network_interface_bond_uuid, + history_network_interfaces.network_interface_bridge_uuid, + history_network_interfaces.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_network_interfaces() OWNER TO admin; + +CREATE TRIGGER trigger_network_interfaces + AFTER INSERT OR UPDATE ON network_interfaces + FOR EACH ROW EXECUTE PROCEDURE history_network_interfaces(); +|; + foreach my $query (@{$queries}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + } + $anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__}); + } + + $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'network_interfaces' AND column_name = 'network_interface_nmcli_uuid';"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + if (not $count) + { + my $queries = []; + push @{$queries}, "ALTER TABLE public.network_interfaces ADD COLUMN network_interface_nmcli_uuid uuid;"; + push @{$queries}, "ALTER TABLE history.network_interfaces ADD COLUMN network_interface_nmcli_uuid uuid;"; + push @{$queries}, "DROP FUNCTION history_network_interfaces() CASCADE;"; + push @{$queries}, q|CREATE FUNCTION history_network_interfaces() RETURNS trigger +AS $$ +DECLARE + history_network_interfaces RECORD; +BEGIN + SELECT INTO history_network_interfaces * FROM network_interfaces WHERE network_interface_uuid = new.network_interface_uuid; + INSERT INTO history.network_interfaces + (network_interface_uuid, + network_interface_host_uuid, + network_interface_nmcli_uuid, + network_interface_mac_address, + network_interface_name, + network_interface_device, + network_interface_speed, + network_interface_mtu, + network_interface_link_state, + network_interface_operational, + network_interface_duplex, + network_interface_medium, + network_interface_bond_uuid, + network_interface_bridge_uuid, + modified_date) + VALUES + (history_network_interfaces.network_interface_uuid, + history_network_interfaces.network_interface_host_uuid, + history_network_interfaces.network_interface_nmcli_uuid, + history_network_interfaces.network_interface_mac_address, + history_network_interfaces.network_interface_name, + history_network_interfaces.network_interface_device, + history_network_interfaces.network_interface_speed, + history_network_interfaces.network_interface_mtu, + history_network_interfaces.network_interface_link_state, + history_network_interfaces.network_interface_operational, + history_network_interfaces.network_interface_duplex, + history_network_interfaces.network_interface_medium, + history_network_interfaces.network_interface_bond_uuid, + history_network_interfaces.network_interface_bridge_uuid, + history_network_interfaces.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_network_interfaces() OWNER TO admin; + +CREATE TRIGGER trigger_network_interfaces + AFTER INSERT OR UPDATE ON network_interfaces + FOR EACH ROW EXECUTE PROCEDURE history_network_interfaces(); +|; + foreach my $query (@{$queries}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + } + $anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__}); + } + } + + + return(0); +} + # This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists. sub update_file_location_ready { my ($anvil) = @_; - foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) { my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'file_locations' AND column_name = 'file_location_ready';"; From 9c67b97fdd6172805d3ef283bdd63d2ab582c81f Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 4 Jan 2024 00:04:51 -0500 Subject: [PATCH 11/43] Fixed a bug in initializing DROP'ed DBs. * Got more work done on adding network_interfaces to the database in scan-server. Signed-off-by: digimer --- Anvil/Tools/Database.pm | 43 +++-- Anvil/Tools/Network.pm | 23 ++- scancore-agents/scan-network/scan-network | 198 ++++++++++++++++++++-- share/anvil.sql | 26 ++- tools/anvil-version-changes | 162 +++++++++++++++++- 5 files changed, 400 insertions(+), 52 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index cb21ab1b..d80ea507 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -786,7 +786,11 @@ If the system is already configured, this method will do nothing, so it is safe If the method completes, C<< 0 >> is returned. If this method is called without C<< root >> access, it returns C<< 1 >> without doing anything. If there is a problem, C<< !!error!! >> is returned. -This method takes no parameters. +Parameters; + +=head3 check_db_exists (optional, default 0) + +If set, the database will be checked to see if the schema exists. This is normally not needed, but can be triggered if the database was DROP'ed by a user. =cut ### TODO: Much of this logic is in striker-prep-database, consolidate! @@ -797,6 +801,11 @@ sub configure_pgsql my $anvil = $self->parent; my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->configure_pgsql()" }}); + + my $check_db_exists = defined $parameter->{check_db_exists} ? $parameter->{check_db_exists} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + check_db_exists => $check_db_exists, + }}); # The local host_uuid is the ID of the local database, so get that. my $uuid = $anvil->Get->host_uuid(); @@ -1012,7 +1021,7 @@ sub configure_pgsql 's2:update_postgresql_file' => $update_postgresql_file, 's3:update_pg_hba_file' => $update_pg_hba_file, }}); - if (($initialized) or ($update_postgresql_file) or ($update_pg_hba_file)) + if (($initialized) or ($update_postgresql_file) or ($update_pg_hba_file) or ($check_db_exists)) { # Create the .pgpass file, if needed. my $created_pgpass = 0; @@ -1366,7 +1375,11 @@ sub connect # This method just returns if nothing is needed. if (($local_host_type eq "striker") && ($check_if_configured) && ($< == 0) && ($> == 0)) { - $anvil->Database->configure_pgsql({debug => 2, uuid => $local_host_uuid}); + $anvil->Database->configure_pgsql({ + debug => 2, + uuid => $local_host_uuid, + check_db_exists => $check_if_configured, + }); } # Now setup or however-many connections @@ -11422,7 +11435,7 @@ This is the maximum transmit unit (MTU) that this interface supports, in bytes p This is the nmcli 'connection.id' name (bios device name) for the current device of this interface. If the previously recorded MAC address is no longer found, but a new/unknown interface with this name is found, it is sane to configure the device with this name as the replacement 'network_interface_device'. -=head3 network_interface_nmcli_uuid (optional) +=head3 network_interface_nm_uuid (optional) This is the network manager's UUID for this interface. @@ -11463,7 +11476,7 @@ sub insert_or_update_network_interfaces my $network_interface_medium = defined $parameter->{network_interface_medium} ? $parameter->{network_interface_medium} : ""; my $network_interface_mtu = defined $parameter->{network_interface_mtu} ? $parameter->{network_interface_mtu} : 0; my $network_interface_name = defined $parameter->{network_interface_name} ? $parameter->{network_interface_name} : ""; - my $network_interface_nmcli_uuid = defined $parameter->{network_interface_nmcli_uuid} ? $parameter->{network_interface_nmcli_uuid} : ""; + my $network_interface_nm_uuid = defined $parameter->{network_interface_nm_uuid} ? $parameter->{network_interface_nm_uuid} : ""; my $network_interface_speed = defined $parameter->{network_interface_speed} ? $parameter->{network_interface_speed} : 0; my $network_interface_uuid = defined $parameter->{network_interface_uuid} ? $parameter->{network_interface_uuid} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { @@ -11483,7 +11496,7 @@ sub insert_or_update_network_interfaces network_interface_medium => $network_interface_medium, network_interface_mtu => $network_interface_mtu, network_interface_name => $network_interface_name, - network_interface_nmcli_uuid => $network_interface_nmcli_uuid, + network_interface_nm_uuid => $network_interface_nm_uuid, network_interface_speed => $network_interface_speed, network_interface_uuid => $network_interface_uuid, }}); @@ -11624,7 +11637,7 @@ WHERE my $query = " SELECT network_interface_host_uuid, - network_interface_nmcli_uuid, + network_interface_nm_uuid, network_interface_mac_address, network_interface_name, network_interface_device, @@ -11658,7 +11671,7 @@ WHERE foreach my $row (@{$results}) { my $old_network_interface_host_uuid = $row->[0]; - my $old_network_interface_nmcli_uuid = defined $row->[1] ? $row->[1] : 'NULL'; + my $old_network_interface_nm_uuid = defined $row->[1] ? $row->[1] : 'NULL'; my $old_network_interface_mac_address = $row->[1]; my $old_network_interface_name = $row->[2]; my $old_network_interface_device = $row->[3]; @@ -11672,7 +11685,7 @@ WHERE my $old_network_interface_bridge_uuid = defined $row->[11] ? $row->[11] : 'NULL'; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_network_interface_host_uuid => $old_network_interface_host_uuid, - old_network_interface_nmcli_uuid => $old_network_interface_nmcli_uuid, + old_network_interface_nm_uuid => $old_network_interface_nm_uuid, old_network_interface_mac_address => $old_network_interface_mac_address, old_network_interface_name => $old_network_interface_name, old_network_interface_device => $old_network_interface_device, @@ -11689,7 +11702,7 @@ WHERE # If 'link_only' is set, we're only checking/updating a subset of values. if ($link_only) { - if (($network_interface_nmcli_uuid ne $old_network_interface_nmcli_uuid) or + if (($network_interface_nm_uuid ne $old_network_interface_nm_uuid) or ($network_interface_name ne $old_network_interface_name) or ($network_interface_device ne $old_network_interface_device) or ($network_interface_link_state ne $old_network_interface_link_state) or @@ -11703,7 +11716,7 @@ UPDATE network_interfaces SET network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid).", - network_interface_nmcli_uuid = ".$anvil->Database->quote($network_interface_nmcli_uuid).", + network_interface_nm_uuid = ".$anvil->Database->quote($network_interface_nm_uuid).", network_interface_name = ".$anvil->Database->quote($network_interface_name).", network_interface_device = ".$anvil->Database->quote($network_interface_device).", network_interface_link_state = ".$anvil->Database->quote($network_interface_link_state).", @@ -11725,7 +11738,7 @@ WHERE # not passed in, we want to not compare it. if (($network_interface_bond_uuid ne $old_network_interface_bond_uuid) or ($network_interface_bridge_uuid ne $old_network_interface_bridge_uuid) or - ($network_interface_nmcli_uuid ne $old_network_interface_nmcli_uuid) or + ($network_interface_nm_uuid ne $old_network_interface_nm_uuid) or ($network_interface_name ne $old_network_interface_name) or ($network_interface_device ne $old_network_interface_device) or ($network_interface_duplex ne $old_network_interface_duplex) or @@ -11743,7 +11756,7 @@ UPDATE network_interfaces SET network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid).", - network_interface_nmcli_uuid = ".$anvil->Database->quote($network_interface_nmcli_uuid).", + network_interface_nm_uuid = ".$anvil->Database->quote($network_interface_nm_uuid).", network_interface_bond_uuid = ".$anvil->Database->quote($network_interface_bond_uuid).", network_interface_bridge_uuid = ".$anvil->Database->quote($network_interface_bridge_uuid).", network_interface_name = ".$anvil->Database->quote($network_interface_name).", @@ -11776,7 +11789,7 @@ INSERT INTO network_interfaces ( network_interface_uuid, - network_interface_nmcli_uuid, + network_interface_nm_uuid, network_interface_bond_uuid, network_interface_bridge_uuid, network_interface_name, @@ -11792,7 +11805,7 @@ INSERT INTO modified_date ) VALUES ( ".$anvil->Database->quote($network_interface_uuid).", - ".$anvil->Database->quote($network_interface_nmcli_uuid).", + ".$anvil->Database->quote($network_interface_nm_uuid).", ".$anvil->Database->quote($network_interface_bond_uuid).", ".$anvil->Database->quote($network_interface_bridge_uuid).", ".$anvil->Database->quote($network_interface_name).", diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index a3bb0416..10fa570e 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -1172,16 +1172,33 @@ sub collect_data { my $connection_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'} // ""; my $general_devices = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.DEVICES'} // ""; + my $general_ip_iface = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.IP-IFACE'} // ""; my $device_type = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.type'} // ""; - my $device = $connection_interface_name ne "--" ? $connection_interface_name : $general_devices; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:uuid' => $uuid, 's2:connection_interface_name' => $connection_interface_name, 's3:general_devices' => $general_devices, - 's4:device_type' => $device_type, - 's5:device' => $device, + 's4:general_ip_iface' => $general_ip_iface, + 's5:device_type' => $device_type, }}); + my $device = ""; + if (($general_ip_iface) && ($general_ip_iface ne "--")) + { + $device = $general_ip_iface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }}); + } + elsif (($connection_interface_name) && ($connection_interface_name ne "--")) + { + $device = $connection_interface_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }}); + } + elsif (($general_devices) && ($general_devices ne "--")) + { + $device = $connection_interface_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }}); + } + if ($device) { $anvil->data->{nmcli}{device}{$device}{uuid} = $uuid; diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 4d5f70de..f00f74e2 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -537,27 +537,28 @@ sub collect_data { # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. my $interface = $file; + my $nm_uuid = $anvil->data->{nmcli}{interface}{$interface}{uuid} ? $anvil->data->{nmcli}{interface}{$interface}{uuid} : ""; + my $nm_device = ""; my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; + $link_state =~ s/\n$//; my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; + $mtu =~ s/\n$//; my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? + $duplex =~ s/\n$//; my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down + $operational =~ s/\n$//; my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; + $modalias =~ s/\n$//; my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link + $speed =~ s/\n$//; my $media = "unknown"; my $type = "interface"; my $driver = ""; my $tx_bytes = 0; # How many bytes transmitted my $rx_bytes = 0; # How many bytes received - - # Clean up some newlines. - $link_state =~ s/\n$//; - $mtu =~ s/\n$//; - $duplex =~ s/\n$//; - $operational =~ s/\n$//; - $speed =~ s/\n$//; - $modalias =~ s/\n$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface, + nm_uuid => $nm_uuid, link_state => $link_state, mtu => $mtu, duplex => $duplex, @@ -680,7 +681,12 @@ sub collect_data { # Yup, we'll neet to dig into the bond proc files to get the proper slaved # interface MAC addresses. - $type = "bond"; + $type = "bond"; + $nm_uuid = $anvil->data->{nmcli}{bond}{$interface}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + type => $type, + nm_uuid => $nm_uuid, + }}); # Read the bond mode. $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); @@ -722,15 +728,17 @@ sub collect_data { # It's a bridge $type = "bridge"; + $nm_uuid = $anvil->data->{nmcli}{bridge}{$interface}{uuid}; $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); $bridge_id =~ s/\n$//; $bridge_stp_enabled =~ s/\n$//; $speed = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + type => $type, + nm_uuid => $nm_uuid, bridge_id => $bridge_id, bridge_stp_enabled => $bridge_stp_enabled, - type => $type, }}); if ($bridge_stp_enabled eq "0") { @@ -747,6 +755,12 @@ sub collect_data $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_stp_enabled => $bridge_stp_enabled }}); } + if ($nm_uuid) + { + $nm_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_device => $nm_device }}); + } + # If this is a 'vnet' device, set 'operational' to up if ($interface =~ /^vnet/) { @@ -822,6 +836,8 @@ sub collect_data } # Store new information we found. + $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid} = $nm_uuid; + $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device} = $nm_device; $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface} = $active_interface; $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode} = $bond_mode; $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master} = $bond_master; @@ -843,6 +859,8 @@ sub collect_data $anvil->data->{network}{$local_host}{interface}{$interface}{type} = $type; $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay} = $up_delay; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "network::${local_host}::interface::${interface}::nm_uuid" => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}, + "network::${local_host}::interface::${interface}::nm_device" => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}, "network::${local_host}::interface::${interface}::active_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}, "network::${local_host}::interface::${interface}::bond_mode" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}, "network::${local_host}::interface::${interface}::bond_master" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}, @@ -881,7 +899,139 @@ sub collect_data } closedir(DIRECTORY); - die; + # Find what interfaces are connected to which bridges + $anvil->Network->bridge_info({debug => 2}); + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) + { + my $ip_address = $anvil->data->{network}{$local_host}{interface}{$interface}{ip}; + my $type = $anvil->data->{network}{$local_host}{interface}{$interface}{type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + ip_address => $ip_address, + type => $type, + }}); + + $anvil->data->{interface}{name_to_type}{$interface} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "interface::name_to_type::${interface}" => $anvil->data->{interface}{name_to_type}{$interface}, + }}); + + if ($type eq "bridge") + { + # Store the bridge + $anvil->data->{new}{bridge}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; + $anvil->data->{new}{bridge}{$interface}{id} = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}; + $anvil->data->{new}{bridge}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; + $anvil->data->{new}{bridge}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; + $anvil->data->{new}{bridge}{$interface}{stp_enabled} = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}; + $anvil->data->{new}{bridge}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; + $anvil->data->{new}{bridge}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::bridge::${interface}::nm_uuid" => $anvil->data->{new}{bridge}{$interface}{nm_uuid}, + "new::bridge::${interface}::id" => $anvil->data->{new}{bridge}{$interface}{id}, + "new::bridge::${interface}::mac_address" => $anvil->data->{new}{bridge}{$interface}{mac_address}, + "new::bridge::${interface}::mtu" => $anvil->data->{new}{bridge}{$interface}{mtu}, + "new::bridge::${interface}::stp_enabled" => $anvil->data->{new}{bridge}{$interface}{stp_enabled}, + "new::bridge::${interface}::tx_bytes" => $anvil->data->{new}{bridge}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bridge}{$interface}{tx_bytes}}).")", + "new::bridge::${interface}::rx_bytes" => $anvil->data->{new}{bridge}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bridge}{$interface}{rx_bytes}}).")", + }}); + } + elsif ($type eq "bond") + { + # Store the bond + $anvil->data->{new}{bond}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; + $anvil->data->{new}{bond}{$interface}{mode} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}; + $anvil->data->{new}{bond}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; + $anvil->data->{new}{bond}{$interface}{master} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; + $anvil->data->{new}{bond}{$interface}{link_state} = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; + $anvil->data->{new}{bond}{$interface}{operational} = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; + $anvil->data->{new}{bond}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; + $anvil->data->{new}{bond}{$interface}{primary_interface} = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}; + $anvil->data->{new}{bond}{$interface}{primary_reselect} = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}; + $anvil->data->{new}{bond}{$interface}{active_interface} = $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}; + $anvil->data->{new}{bond}{$interface}{mii_polling_interval} = $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}; + $anvil->data->{new}{bond}{$interface}{up_delay} = $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}; + $anvil->data->{new}{bond}{$interface}{down_delay} = $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}; + $anvil->data->{new}{bond}{$interface}{bridge_uuid} = ""; # We'll dig his out later as the bridge might not be in the database yet. + $anvil->data->{new}{bond}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; + $anvil->data->{new}{bond}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::bond::${interface}::nm_uuid" => $anvil->data->{new}{bond}{$interface}{nm_uuid}, + "new::bond::${interface}::mode" => $anvil->data->{new}{bond}{$interface}{mode}, + "new::bond::${interface}::mtu" => $anvil->data->{new}{bond}{$interface}{mtu}, + "new::bond::${interface}::master" => $anvil->data->{new}{bond}{$interface}{master}, + "new::bond::${interface}::link_state" => $anvil->data->{new}{bond}{$interface}{link_state}, + "new::bond::${interface}::operational" => $anvil->data->{new}{bond}{$interface}{operational}, + "new::bond::${interface}::mac_address" => $anvil->data->{new}{bond}{$interface}{mac_address}, + "new::bond::${interface}::primary_interface" => $anvil->data->{new}{bond}{$interface}{primary_interface}, + "new::bond::${interface}::primary_reselect" => $anvil->data->{new}{bond}{$interface}{primary_reselect}, + "new::bond::${interface}::active_interface" => $anvil->data->{new}{bond}{$interface}{active_interface}, + "new::bond::${interface}::mii_polling_interval" => $anvil->data->{new}{bond}{$interface}{mii_polling_interval}, + "new::bond::${interface}::up_delay" => $anvil->data->{new}{bond}{$interface}{up_delay}, + "new::bond::${interface}::down_delay" => $anvil->data->{new}{bond}{$interface}{down_delay}, + "new::bond::${interface}::bridge_uuid" => $anvil->data->{new}{bond}{$interface}{bridge_uuid}, + "new::bond::${interface}::tx_bytes" => $anvil->data->{new}{bond}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bond}{$interface}{tx_bytes}}).")", + "new::bond::${interface}::rx_bytes" => $anvil->data->{new}{bond}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bond}{$interface}{rx_bytes}}).")", + }}); + } + elsif ($type eq "interface") + { + # Store the interface + $anvil->data->{new}{interface}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; + $anvil->data->{new}{interface}{$interface}{nm_device} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}; + $anvil->data->{new}{interface}{$interface}{bond_uuid} = ""; + $anvil->data->{new}{interface}{$interface}{bond_name} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; + $anvil->data->{new}{interface}{$interface}{bridge_uuid} = ""; + $anvil->data->{new}{interface}{$interface}{bridge_name} = ""; + $anvil->data->{new}{interface}{$interface}{duplex} = $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}; + $anvil->data->{new}{interface}{$interface}{link_state} = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; + $anvil->data->{new}{interface}{$interface}{operational} = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; + $anvil->data->{new}{interface}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; + $anvil->data->{new}{interface}{$interface}{medium} = $anvil->data->{network}{$local_host}{interface}{$interface}{media}; + $anvil->data->{new}{interface}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; + $anvil->data->{new}{interface}{$interface}{speed} = $anvil->data->{network}{$local_host}{interface}{$interface}{speed}; + $anvil->data->{new}{interface}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; + $anvil->data->{new}{interface}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::interface::${interface}::nm_uuid" => $anvil->data->{new}{interface}{$interface}{nm_uuid}, + "new::interface::${interface}::nm_device" => $anvil->data->{new}{interface}{$interface}{nm_device}, + "new::interface::${interface}::bond_uuid" => $anvil->data->{new}{interface}{$interface}{bond_uuid}, + "new::interface::${interface}::bond_name" => $anvil->data->{new}{interface}{$interface}{bond_name}, + "new::interface::${interface}::bridge_uuid" => $anvil->data->{new}{interface}{$interface}{bridge_uuid}, + "new::interface::${interface}::bridge_name" => $anvil->data->{new}{interface}{$interface}{bridge_name}, + "new::interface::${interface}::duplex" => $anvil->data->{new}{interface}{$interface}{duplex}, + "new::interface::${interface}::link_state" => $anvil->data->{new}{interface}{$interface}{link_state}, + "new::interface::${interface}::operational" => $anvil->data->{new}{interface}{$interface}{operational}, + "new::interface::${interface}::mac_address" => $anvil->data->{new}{interface}{$interface}{mac_address}, + "new::interface::${interface}::medium" => $anvil->data->{new}{interface}{$interface}{medium}, + "new::interface::${interface}::mtu" => $anvil->data->{new}{interface}{$interface}{mtu}, + "new::interface::${interface}::speed" => $anvil->data->{new}{interface}{$interface}{speed}, + "new::interface::${interface}::tx_bytes" => $anvil->data->{new}{interface}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{tx_bytes}}).")", + "new::interface::${interface}::rx_bytes" => $anvil->data->{new}{interface}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{rx_bytes}}).")", + }}); + } + + # Record the IP address info. + if ($ip_address) + { + $anvil->data->{new}{ip_address}{$ip_address}{on_interface} = $interface; + $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask} = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}; + $anvil->data->{new}{ip_address}{$ip_address}{gateway} = $anvil->data->{network}{$local_host}{interface}{$interface}{gateway}; + $anvil->data->{new}{ip_address}{$ip_address}{default_gateway} = $anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway}; + $anvil->data->{new}{ip_address}{$ip_address}{dns} = $anvil->data->{network}{$local_host}{interface}{$interface}{dns}; + $anvil->data->{new}{ip_address}{$ip_address}{on_uuid} = ""; + $anvil->data->{new}{ip_address}{$ip_address}{note} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::ip_address::${ip_address}::on_interface" => $anvil->data->{new}{ip_address}{$ip_address}{on_interface}, + "new::ip_address::${ip_address}::subnet_mask" => $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask}, + "new::ip_address::${ip_address}::gateway" => $anvil->data->{new}{ip_address}{$ip_address}{gateway}, + "new::ip_address::${ip_address}::default_gateway" => $anvil->data->{new}{ip_address}{$ip_address}{default_gateway}, + "new::ip_address::${ip_address}::dns" => $anvil->data->{new}{ip_address}{$ip_address}{dns}, + "new::ip_address::${ip_address}::on_uuid" => $anvil->data->{new}{ip_address}{$ip_address}{on_uuid}, + "new::ip_address::${ip_address}::note" => $anvil->data->{new}{ip_address}{$ip_address}{note}, + }}); + } + } return(0); } @@ -1288,6 +1438,7 @@ sub collect_data_ifcfg if ($type eq "bridge") { # Store the bridge + $anvil->data->{new}{bridge}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; $anvil->data->{new}{bridge}{$interface}{id} = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}; $anvil->data->{new}{bridge}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; $anvil->data->{new}{bridge}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; @@ -1295,6 +1446,7 @@ sub collect_data_ifcfg $anvil->data->{new}{bridge}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{bridge}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::bridge::${interface}::nm_uuid" => $anvil->data->{new}{bridge}{$interface}{nm_uuid}, "new::bridge::${interface}::id" => $anvil->data->{new}{bridge}{$interface}{id}, "new::bridge::${interface}::mac_address" => $anvil->data->{new}{bridge}{$interface}{mac_address}, "new::bridge::${interface}::mtu" => $anvil->data->{new}{bridge}{$interface}{mtu}, @@ -1306,6 +1458,7 @@ sub collect_data_ifcfg elsif ($type eq "bond") { # Store the bond + $anvil->data->{new}{bond}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; $anvil->data->{new}{bond}{$interface}{mode} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}; $anvil->data->{new}{bond}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; $anvil->data->{new}{bond}{$interface}{master} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; @@ -1322,6 +1475,7 @@ sub collect_data_ifcfg $anvil->data->{new}{bond}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{bond}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::bond::${interface}::nm_uuid" => $anvil->data->{new}{bond}{$interface}{nm_uuid}, "new::bond::${interface}::mode" => $anvil->data->{new}{bond}{$interface}{mode}, "new::bond::${interface}::mtu" => $anvil->data->{new}{bond}{$interface}{mtu}, "new::bond::${interface}::master" => $anvil->data->{new}{bond}{$interface}{master}, @@ -1342,6 +1496,8 @@ sub collect_data_ifcfg elsif ($type eq "interface") { # Store the interface + $anvil->data->{new}{interface}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; + $anvil->data->{new}{interface}{$interface}{nm_device} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}; $anvil->data->{new}{interface}{$interface}{bond_uuid} = ""; $anvil->data->{new}{interface}{$interface}{bond_name} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; $anvil->data->{new}{interface}{$interface}{bridge_uuid} = ""; @@ -1356,6 +1512,8 @@ sub collect_data_ifcfg $anvil->data->{new}{interface}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; $anvil->data->{new}{interface}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new::interface::${interface}::nm_uuid" => $anvil->data->{new}{interface}{$interface}{nm_uuid}, + "new::interface::${interface}::nm_device" => $anvil->data->{new}{interface}{$interface}{nm_device}, "new::interface::${interface}::bond_uuid" => $anvil->data->{new}{interface}{$interface}{bond_uuid}, "new::interface::${interface}::bond_name" => $anvil->data->{new}{interface}{$interface}{bond_name}, "new::interface::${interface}::bridge_uuid" => $anvil->data->{new}{interface}{$interface}{bridge_uuid}, @@ -2719,8 +2877,12 @@ sub check_interfaces { my ($anvil) = @_; + my $interfaces = keys %{$anvil->data->{new}{interface}}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interfaces => $interfaces }}); foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{new}{interface}}) { + my $new_nm_uuid = $anvil->data->{new}{interface}{$network_interface_name}{nm_uuid}; + my $new_nm_device = $anvil->data->{new}{interface}{$network_interface_name}{nm_device}; my $new_bond_uuid = $anvil->data->{new}{interface}{$network_interface_name}{bond_uuid}; my $new_bond_name = $anvil->data->{new}{interface}{$network_interface_name}{bond_name}; my $new_bridge_uuid = $anvil->data->{new}{interface}{$network_interface_name}{bridge_uuid}; @@ -2736,6 +2898,8 @@ sub check_interfaces my $new_rx_bytes = $anvil->data->{new}{interface}{$network_interface_name}{rx_bytes}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_name => $network_interface_name, + new_nm_uuid => $new_nm_uuid, + new_nm_device => $new_nm_device, new_bond_uuid => $new_bond_uuid, new_bond_name => $new_bond_name, new_bridge_uuid => $new_bridge_uuid, @@ -2751,8 +2915,6 @@ sub check_interfaces new_rx_bytes => $new_rx_bytes, }}); - my $new_nmcli_uuid = ""; - # Find the bridge, if any, and the bond UUID, if there's a bond name. if ($new_bond_name) { @@ -3155,11 +3317,11 @@ sub check_interfaces { my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, - network_interface_nmcli_uuid => $new_nmcli_uuid, + network_interface_nm_uuid => $new_nm_uuid, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, network_interface_name => $network_interface_name, - network_interface_device => $network_interface_device, + network_interface_device => $new_nm_device, network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, @@ -3290,11 +3452,11 @@ sub check_interfaces # Record the interface my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, - network_interface_nmcli_uuid => $new_nmcli_uuid, + network_interface_nm_uuid => $new_nm_uuid, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, network_interface_name => $network_interface_name, - network_interface_device => $network_interface_device, + network_interface_device => $new_nm_device, network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, @@ -3423,6 +3585,7 @@ sub check_bonds foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{new}{bond}}) { # Store the bond + my $new_nm_uuid = $anvil->data->{new}{bond}{$bond_name}{nm_uuid}; my $new_mode = $anvil->data->{new}{bond}{$bond_name}{mode}; my $new_mtu = $anvil->data->{new}{bond}{$bond_name}{mtu}; my $new_operational = $anvil->data->{new}{bond}{$bond_name}{operational}; @@ -3793,6 +3956,7 @@ sub check_bonds { my $bond_uuid = $anvil->Database->insert_or_update_bonds({ debug => 2, + bond_nm_uuid => $new_nm_uuid, bond_name => $bond_name, bond_mode => $new_mode, bond_mtu => $new_mtu, diff --git a/share/anvil.sql b/share/anvil.sql index 91b39b15..3c4106e3 100644 --- a/share/anvil.sql +++ b/share/anvil.sql @@ -855,6 +855,7 @@ CREATE TRIGGER trigger_jobs CREATE TABLE bridges ( bridge_uuid uuid not null primary key, bridge_host_uuid uuid not null, + bridge_nm_uuid uuid not null, -- This is the network manager UUID for this bridge interface bridge_name text not null, bridge_id text not null, bridge_mac_address text not null, @@ -870,6 +871,7 @@ CREATE TABLE history.bridges ( history_id bigserial, bridge_uuid uuid, bridge_host_uuid uuid, + bridge_nm_uuid uuid, bridge_name text, bridge_id text, bridge_mac_address text, @@ -888,6 +890,7 @@ BEGIN INSERT INTO history.bridges (bridge_uuid, bridge_host_uuid, + bridge_nm_uuid, bridge_name, bridge_id, bridge_mac_address, @@ -897,6 +900,7 @@ BEGIN VALUES (history_bridges.bridge_uuid, history_bridges.bridge_host_uuid, + history_bridges.bridge_nm_uuid, history_bridges.bridge_name, history_bridges.bridge_id, history_bridges.bridge_mac_address, @@ -918,6 +922,7 @@ CREATE TRIGGER trigger_bridges CREATE TABLE bonds ( bond_uuid uuid not null primary key, bond_host_uuid uuid not null, + bond_nm_uuid uuid not null, -- The is the network manager UUID for this bond. bond_name text not null, bond_mode text not null, -- This is the numerical bond type (will translate to the user's language in the Anvil!) bond_mtu bigint not null, @@ -941,6 +946,7 @@ CREATE TABLE history.bonds ( history_id bigserial, bond_uuid uuid, bond_host_uuid uuid, + bond_nm_uuid uuid, bond_name text, bond_mode text, bond_mtu bigint, @@ -964,8 +970,9 @@ DECLARE BEGIN SELECT INTO history_bonds * FROM bonds WHERE bond_uuid = new.bond_uuid; INSERT INTO history.bonds - (bond_uuid, - bond_host_uuid, + (bond_uuid, + bond_host_uuid, + bond_nm_uuid, bond_name, bond_mode, bond_mtu, @@ -980,8 +987,9 @@ BEGIN bond_bridge_uuid, modified_date) VALUES - (history_bonds.bond_uuid, - history_bonds.bond_host_uuid, + (history_bonds.bond_uuid, + history_bonds.bond_host_uuid, + history_bonds.bond_nm_uuid, history_bonds.bond_name, history_bonds.bond_mode, history_bonds.bond_mtu, @@ -1011,10 +1019,10 @@ CREATE TRIGGER trigger_bonds CREATE TABLE network_interfaces ( network_interface_uuid uuid not null primary key, network_interface_host_uuid uuid not null, - network_interface_nmcli_uuid uuid, -- This is the nmcli UUID used to track the device. It can change, so we can't used this as the main UUID + network_interface_nm_uuid uuid, -- This is the network manager UUID used to track the device. It can change, so we can't used this as the main UUID network_interface_mac_address text not null, -- This is the interface MAC address, and it can change if a failed controller it replaced. network_interface_name text not null, -- This is the current name (network manager's connection.id) of the interface. - network_interface_device text not null, -- This is the current device name (network manager's ) of the interface. + network_interface_device text not null, -- This is the current device name (network manager's GENERAL.IP-IFACE) of the interface. network_interface_speed bigint not null, -- This is the speed, in bits-per-second, of the interface. network_interface_mtu bigint not null, -- This is the MTU (Maximum Transmitable Size), in bytes, for this interface. network_interface_link_state text not null, -- 0 or 1 @@ -1035,7 +1043,7 @@ CREATE TABLE history.network_interfaces ( history_id bigserial, network_interface_uuid uuid not null, network_interface_host_uuid uuid, - network_interface_nmcli_uuid uuid, + network_interface_nm_uuid uuid, network_interface_mac_address text, network_interface_name text, network_interface_device text, @@ -1060,7 +1068,7 @@ BEGIN INSERT INTO history.network_interfaces (network_interface_uuid, network_interface_host_uuid, - network_interface_nmcli_uuid, + network_interface_nm_uuid, network_interface_mac_address, network_interface_name, network_interface_device, @@ -1076,7 +1084,7 @@ BEGIN VALUES (history_network_interfaces.network_interface_uuid, history_network_interfaces.network_interface_host_uuid, - history_network_interfaces.network_interface_nmcli_uuid, + history_network_interfaces.network_interface_nm_uuid, history_network_interfaces.network_interface_mac_address, history_network_interfaces.network_interface_name, history_network_interfaces.network_interface_device, diff --git a/tools/anvil-version-changes b/tools/anvil-version-changes index dea4b1ff..602b3dc3 100755 --- a/tools/anvil-version-changes +++ b/tools/anvil-version-changes @@ -63,8 +63,10 @@ sub striker_checks { my ($anvil) = @_; - # This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists. + # This checks to make sure that the new network manager columns are in place update_network_interfaces($anvil); + update_bonds($anvil); + update_bridges($anvil); # This checks to make sure that the new 'file_locations' -> 'file_location_ready' column exists. update_file_location_ready($anvil); @@ -246,6 +248,150 @@ CREATE TRIGGER trigger_dr_links return(0); } +sub update_bridges +{ + my ($anvil) = @_; + + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) + { + my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'bridges' AND column_name = 'bridge_nm_uuid';"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + if (not $count) + { + my $queries = []; + push @{$queries}, "ALTER TABLE public.bridges ADD COLUMN bridge_nm_uuid uuid;"; + push @{$queries}, "ALTER TABLE history.bridges ADD COLUMN bridge_nm_uuid uuid;"; + push @{$queries}, "DROP FUNCTION history_bridges() CASCADE;"; + push @{$queries}, q|CREATE FUNCTION history_bridges() RETURNS trigger +AS $$ +DECLARE + history_bridges RECORD; +BEGIN + SELECT INTO history_bridges * FROM bridges WHERE bridge_uuid = new.bridge_uuid; + INSERT INTO history.bridges + (bridge_uuid, + bridge_host_uuid, + bridge_nm_uuid, + bridge_name, + bridge_id, + bridge_mac_address, + bridge_mtu, + bridge_stp_enabled, + modified_date) + VALUES + (history_bridges.bridge_uuid, + history_bridges.bridge_host_uuid, + history_bridges.bridge_nm_uuid, + history_bridges.bridge_name, + history_bridges.bridge_id, + history_bridges.bridge_mac_address, + history_bridges.bridge_mtu, + history_bridges.bridge_stp_enabled, + history_bridges.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_bridges() OWNER TO admin; + +CREATE TRIGGER trigger_bridges + AFTER INSERT OR UPDATE ON bridges + FOR EACH ROW EXECUTE PROCEDURE history_bridges(); +|; + foreach my $query (@{$queries}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + } + $anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__}); + } + } + + return(0); +} + +sub update_bonds +{ + my ($anvil) = @_; + + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) + { + my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'bonds' AND column_name = 'bond_nm_uuid';"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + if (not $count) + { + my $queries = []; + push @{$queries}, "ALTER TABLE public.bonds ADD COLUMN bond_nm_uuid uuid;"; + push @{$queries}, "ALTER TABLE history.bonds ADD COLUMN bond_nm_uuid uuid;"; + push @{$queries}, "DROP FUNCTION history_bonds() CASCADE;"; + push @{$queries}, q|CREATE FUNCTION history_bonds() RETURNS trigger +AS $$ +DECLARE + history_bonds RECORD; +BEGIN + SELECT INTO history_bonds * FROM bonds WHERE bond_uuid = new.bond_uuid; + INSERT INTO history.bonds + (bond_uuid, + bond_host_uuid, + bond_nm_uuid, + bond_name, + bond_mode, + bond_mtu, + bond_primary_interface, + bond_primary_reselect, + bond_active_interface, + bond_mii_polling_interval, + bond_up_delay, + bond_down_delay, + bond_mac_address, + bond_operational, + bond_bridge_uuid, + modified_date) + VALUES + (history_bonds.bond_uuid, + history_bonds.bond_host_uuid, + history_bonds.bond_nm_uuid, + history_bonds.bond_name, + history_bonds.bond_mode, + history_bonds.bond_mtu, + history_bonds.bond_primary_interface, + history_bonds.bond_primary_reselect, + history_bonds.bond_active_interface, + history_bonds.bond_mii_polling_interval, + history_bonds.bond_up_delay, + history_bonds.bond_down_delay, + history_bonds.bond_mac_address, + history_bonds.bond_operational, + history_bonds.bond_bridge_uuid, + history_bonds.modified_date); + RETURN NULL; +END; +$$ +LANGUAGE plpgsql; +ALTER FUNCTION history_bonds() OWNER TO admin; + +CREATE TRIGGER trigger_bonds + AFTER INSERT OR UPDATE ON bonds + FOR EACH ROW EXECUTE PROCEDURE history_bonds(); +|; + foreach my $query (@{$queries}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); + } + $anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__}); + } + } + + return(0); +} + sub update_network_interfaces { my ($anvil) = @_; @@ -273,7 +419,7 @@ BEGIN INSERT INTO history.network_interfaces (network_interface_uuid, network_interface_host_uuid, - network_interface_nmcli_uuid, + network_interface_nm_uuid, network_interface_mac_address, network_interface_name, network_interface_device, @@ -289,7 +435,7 @@ BEGIN VALUES (history_network_interfaces.network_interface_uuid, history_network_interfaces.network_interface_host_uuid, - history_network_interfaces.network_interface_nmcli_uuid, + history_network_interfaces.network_interface_nm_uuid, history_network_interfaces.network_interface_mac_address, history_network_interfaces.network_interface_name, history_network_interfaces.network_interface_device, @@ -319,7 +465,7 @@ CREATE TRIGGER trigger_network_interfaces $anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__}); } - $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'network_interfaces' AND column_name = 'network_interface_nmcli_uuid';"; + $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'network_interfaces' AND column_name = 'network_interface_nm_uuid';"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0]; @@ -328,8 +474,8 @@ CREATE TRIGGER trigger_network_interfaces if (not $count) { my $queries = []; - push @{$queries}, "ALTER TABLE public.network_interfaces ADD COLUMN network_interface_nmcli_uuid uuid;"; - push @{$queries}, "ALTER TABLE history.network_interfaces ADD COLUMN network_interface_nmcli_uuid uuid;"; + push @{$queries}, "ALTER TABLE public.network_interfaces ADD COLUMN network_interface_nm_uuid uuid;"; + push @{$queries}, "ALTER TABLE history.network_interfaces ADD COLUMN network_interface_nm_uuid uuid;"; push @{$queries}, "DROP FUNCTION history_network_interfaces() CASCADE;"; push @{$queries}, q|CREATE FUNCTION history_network_interfaces() RETURNS trigger AS $$ @@ -340,7 +486,7 @@ BEGIN INSERT INTO history.network_interfaces (network_interface_uuid, network_interface_host_uuid, - network_interface_nmcli_uuid, + network_interface_nm_uuid, network_interface_mac_address, network_interface_name, network_interface_device, @@ -356,7 +502,7 @@ BEGIN VALUES (history_network_interfaces.network_interface_uuid, history_network_interfaces.network_interface_host_uuid, - history_network_interfaces.network_interface_nmcli_uuid, + history_network_interfaces.network_interface_nm_uuid, history_network_interfaces.network_interface_mac_address, history_network_interfaces.network_interface_name, history_network_interfaces.network_interface_device, From a27773a69dcd74dbcbf080be2cf0b7b008d64922 Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 4 Jan 2024 00:32:51 -0500 Subject: [PATCH 12/43] scan-network now records interfaces, bonds and bridges! * Much testing still needed, but this is a significant milestone. Signed-off-by: digimer --- Anvil/Tools/Database.pm | 70 ++++++++++++++++------- scancore-agents/scan-network/scan-network | 2 +- share/anvil.sql | 4 +- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index d80ea507..c0f4129b 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -3984,7 +3984,7 @@ AND }}); $anvil->data->{host_from_uuid}{$host_uuid}{full} = $host_name; - $anvil->data->{host_from_uuid}{$host_uuid}{short} = $short_host_name; + $anvil->data->{host_from_uuid}{$host_uuid}{short} = $short_host_name ? $short_host_name : $host_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "host_from_uuid::${host_uuid}::full" => $anvil->data->{host_from_uuid}{$host_uuid}{full}, "host_from_uuid::${host_uuid}::short" => $anvil->data->{host_from_uuid}{$host_uuid}{short}, @@ -7542,7 +7542,6 @@ WHERE return($anvil_uuid); } - =head2 insert_or_update_bridges This updates (or inserts) a record in the 'bridges' table. The C<< bridge_uuid >> referencing the database row will be returned. @@ -7575,6 +7574,10 @@ This is the host that the IP address is on. If not passed, the local C<< sys::ho This is the bridge's device name. +=head3 bridge_nm_uuid (optional) + +This is the network manager UUID for the bridge. + =head3 bridge_id (optional) This is the unique identifier for the bridge. @@ -7611,6 +7614,7 @@ sub insert_or_update_bridges my $bridge_uuid = defined $parameter->{bridge_uuid} ? $parameter->{bridge_uuid} : ""; my $bridge_host_uuid = defined $parameter->{bridge_host_uuid} ? $parameter->{bridge_host_uuid} : $anvil->data->{sys}{host_uuid}; my $bridge_name = defined $parameter->{bridge_name} ? $parameter->{bridge_name} : ""; + my $bridge_nm_uuid = $parameter->{bridge_nm_uuid} ? $parameter->{bridge_nm_uuid} : 'NULL'; my $bridge_id = defined $parameter->{bridge_id} ? $parameter->{bridge_id} : ""; my $bridge_mac_address = defined $parameter->{bridge_mac_address} ? $parameter->{bridge_mac_address} : ""; my $bridge_mtu = defined $parameter->{bridge_mtu} ? $parameter->{bridge_mtu} : ""; @@ -7623,6 +7627,7 @@ sub insert_or_update_bridges bridge_uuid => $bridge_uuid, bridge_host_uuid => $bridge_host_uuid, bridge_name => $bridge_name, + bridge_nm_uuid => $bridge_nm_uuid, bridge_id => $bridge_id, bridge_mac_address => $bridge_mac_address, bridge_mtu => $bridge_mtu, @@ -7755,6 +7760,7 @@ INSERT INTO ( bridge_uuid, bridge_host_uuid, + bridge_nm_uuid, bridge_name, bridge_id, bridge_mac_address, @@ -7764,6 +7770,7 @@ INSERT INTO ) VALUES ( ".$anvil->Database->quote($bridge_uuid).", ".$anvil->Database->quote($bridge_host_uuid).", + ".$anvil->Database->quote($bridge_nm_uuid).", ".$anvil->Database->quote($bridge_name).", ".$anvil->Database->quote($bridge_id).", ".$anvil->Database->quote($bridge_mac_address).", @@ -7772,6 +7779,7 @@ INSERT INTO ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." ); "; + $query =~ s/'NULL'/NULL/g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); } @@ -7781,6 +7789,7 @@ INSERT INTO my $query = " SELECT bridge_host_uuid, + bridge_nm_uuid, bridge_name, bridge_id, bridge_mac_address, @@ -7807,14 +7816,16 @@ WHERE } foreach my $row (@{$results}) { - my $old_bridge_host_uuid = $row->[0]; - my $old_bridge_name = $row->[1]; - my $old_bridge_id = $row->[2]; - my $old_bridge_mac_address = $row->[3]; - my $old_bridge_mtu = $row->[4]; - my $old_bridge_stp_enabled = $row->[5]; + my $old_bridge_host_uuid = $row->[0]; + my $old_bridge_nm_uuid = defined $row->[1] ? $row->[1] : 'NULL'; + my $old_bridge_name = $row->[2]; + my $old_bridge_id = $row->[3]; + my $old_bridge_mac_address = $row->[4]; + my $old_bridge_mtu = $row->[5]; + my $old_bridge_stp_enabled = $row->[6]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_bridge_host_uuid => $old_bridge_host_uuid, + old_bridge_nm_uuid => $old_bridge_nm_uuid, old_bridge_name => $old_bridge_name, old_bridge_id => $old_bridge_id, old_bridge_mac_address => $old_bridge_mac_address, @@ -7824,6 +7835,7 @@ WHERE # Anything change? if (($old_bridge_host_uuid ne $bridge_host_uuid) or + ($old_bridge_nm_uuid ne $bridge_nm_uuid) or ($old_bridge_name ne $bridge_name) or ($old_bridge_id ne $bridge_id) or ($old_bridge_mac_address ne $bridge_mac_address) or @@ -7836,6 +7848,7 @@ UPDATE bridges SET bridge_host_uuid = ".$anvil->Database->quote($bridge_host_uuid).", + bridge_nm_uuid = ".$anvil->Database->quote($bridge_nm_uuid).", bridge_name = ".$anvil->Database->quote($bridge_name).", bridge_id = ".$anvil->Database->quote($bridge_id).", bridge_mac_address = ".$anvil->Database->quote($bridge_mac_address).", @@ -7845,6 +7858,7 @@ SET WHERE bridge_uuid = ".$anvil->Database->quote($bridge_uuid)." "; + $query =~ s/'NULL'/NULL/g; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); $anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); } @@ -7891,6 +7905,10 @@ This is the host that the IP address is on. If not passed, the local C<< sys::ho This is the bond's device name. +=head3 bond_nm_uuid (optional) + +This is the network manager UUID for this bond. + =head3 bond_mode (required) This is the bonding mode used for this bond. @@ -7951,6 +7969,7 @@ sub insert_or_update_bonds my $bond_uuid = defined $parameter->{bond_uuid} ? $parameter->{bond_uuid} : ""; my $bond_host_uuid = defined $parameter->{bond_host_uuid} ? $parameter->{bond_host_uuid} : $anvil->data->{sys}{host_uuid}; my $bond_name = defined $parameter->{bond_name} ? $parameter->{bond_name} : ""; + my $bond_nm_uuid = $parameter->{bond_nm_uuid} ? $parameter->{bond_nm_uuid} : 'NULL'; my $bond_mode = defined $parameter->{bond_mode} ? $parameter->{bond_mode} : ""; my $bond_mtu = defined $parameter->{bond_mtu} ? $parameter->{bond_mtu} : ""; my $bond_primary_interface = defined $parameter->{bond_primary_interface} ? $parameter->{bond_primary_interface} : ""; @@ -7961,7 +7980,7 @@ sub insert_or_update_bonds my $bond_down_delay = defined $parameter->{bond_down_delay} ? $parameter->{bond_down_delay} : ""; my $bond_mac_address = defined $parameter->{bond_mac_address} ? $parameter->{bond_mac_address} : ""; my $bond_operational = defined $parameter->{bond_operational} ? $parameter->{bond_operational} : ""; - my $bond_bridge_uuid = defined $parameter->{bond_bridge_uuid} ? $parameter->{bond_bridge_uuid} : 'NULL'; + my $bond_bridge_uuid = $parameter->{bond_bridge_uuid} ? $parameter->{bond_bridge_uuid} : 'NULL'; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid, file => $file, @@ -7970,6 +7989,7 @@ sub insert_or_update_bonds bond_uuid => $bond_uuid, bond_host_uuid => $bond_host_uuid, bond_name => $bond_name, + bond_nm_uuid => $bond_nm_uuid, bond_mode => $bond_mode, bond_mtu => $bond_mtu, bond_primary_interface => $bond_primary_interface, @@ -8121,6 +8141,7 @@ INSERT INTO ( bond_uuid, bond_host_uuid, + bond_nm_uuid, bond_name, bond_mode, bond_mtu, @@ -8137,6 +8158,7 @@ INSERT INTO ) VALUES ( ".$anvil->Database->quote($bond_uuid).", ".$anvil->Database->quote($bond_host_uuid).", + ".$anvil->Database->quote($bond_nm_uuid).", ".$anvil->Database->quote($bond_name).", ".$anvil->Database->quote($bond_mode).", ".$anvil->Database->quote($bond_mtu).", @@ -8162,6 +8184,7 @@ INSERT INTO my $query = " SELECT bond_host_uuid, + bond_nm_uuid, bond_name, bond_mode, bond_mtu, @@ -8196,20 +8219,22 @@ WHERE foreach my $row (@{$results}) { my $old_bond_host_uuid = $row->[0]; - my $old_bond_name = $row->[1]; - my $old_bond_mode = $row->[2]; - my $old_bond_mtu = $row->[3]; - my $old_bond_primary_interface = $row->[4]; - my $old_bond_primary_reselect = $row->[5]; - my $old_bond_active_interface = $row->[6]; - my $old_bond_mii_polling_interval = $row->[7]; - my $old_bond_up_delay = $row->[8]; - my $old_bond_down_delay = $row->[9]; - my $old_bond_mac_address = $row->[10]; - my $old_bond_operational = $row->[11]; - my $old_bond_bridge_uuid = defined $row->[12] ? $row->[12] : 'NULL'; + my $old_bond_nm_uuid = defined $row->[1] ? $row->[1] : 'NULL'; + my $old_bond_name = $row->[2]; + my $old_bond_mode = $row->[3]; + my $old_bond_mtu = $row->[4]; + my $old_bond_primary_interface = $row->[5]; + my $old_bond_primary_reselect = $row->[6]; + my $old_bond_active_interface = $row->[7]; + my $old_bond_mii_polling_interval = $row->[8]; + my $old_bond_up_delay = $row->[9]; + my $old_bond_down_delay = $row->[10]; + my $old_bond_mac_address = $row->[11]; + my $old_bond_operational = $row->[12]; + my $old_bond_bridge_uuid = defined $row->[13] ? $row->[12] : 'NULL'; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_bond_host_uuid => $old_bond_host_uuid, + old_bond_nm_uuid => $old_bond_nm_uuid, old_bond_name => $old_bond_name, old_bond_mode => $old_bond_mode, old_bond_mtu => $old_bond_mtu, @@ -8226,6 +8251,7 @@ WHERE # Anything change? if (($old_bond_host_uuid ne $bond_host_uuid) or + ($old_bond_nm_uuid ne $bond_nm_uuid) or ($old_bond_name ne $bond_name) or ($old_bond_mode ne $bond_mode) or ($old_bond_mtu ne $bond_mtu) or @@ -8245,6 +8271,7 @@ UPDATE bonds SET bond_host_uuid = ".$anvil->Database->quote($bond_host_uuid).", + bond_nm_uuid = ".$anvil->Database->quote($bond_nm_uuid).", bond_name = ".$anvil->Database->quote($bond_name).", bond_mode = ".$anvil->Database->quote($bond_mode).", bond_mtu = ".$anvil->Database->quote($bond_mtu).", @@ -18990,6 +19017,7 @@ sub write 's1:test' => $test, 's2:$@' => $@, }}); + if (not $test) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0090", variables => { diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index f00f74e2..ddf0e9d8 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -124,7 +124,7 @@ sub clear_old_interfaces foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - uuid => $anvil->Database->get_host_from_uuid({short => 1, host_uuid => $uuid})." (".$uuid.")", + uuid => $anvil->Database->get_host_from_uuid({debug => 2, short => 1, host_uuid => $uuid})." (".$uuid.")", }}); my $query = " SELECT diff --git a/share/anvil.sql b/share/anvil.sql index 3c4106e3..11cdf49f 100644 --- a/share/anvil.sql +++ b/share/anvil.sql @@ -855,7 +855,7 @@ CREATE TRIGGER trigger_jobs CREATE TABLE bridges ( bridge_uuid uuid not null primary key, bridge_host_uuid uuid not null, - bridge_nm_uuid uuid not null, -- This is the network manager UUID for this bridge interface + bridge_nm_uuid uuid, -- This is the network manager UUID for this bridge interface bridge_name text not null, bridge_id text not null, bridge_mac_address text not null, @@ -922,7 +922,7 @@ CREATE TRIGGER trigger_bridges CREATE TABLE bonds ( bond_uuid uuid not null primary key, bond_host_uuid uuid not null, - bond_nm_uuid uuid not null, -- The is the network manager UUID for this bond. + bond_nm_uuid uuid, -- The is the network manager UUID for this bond. bond_name text not null, bond_mode text not null, -- This is the numerical bond type (will translate to the user's language in the Anvil!) bond_mtu bigint not null, From cad524db9d96e767f8bf282584bda7d8837634cd Mon Sep 17 00:00:00 2001 From: digimer Date: Fri, 5 Jan 2024 18:15:11 -0500 Subject: [PATCH 13/43] Removed anvil-update-states * Created new anvil-monitor-network daemon to trigger scan-server via anvil-monitor-network on network events. * Moved functionality into scan-network Signed-off-by: digimer --- Anvil/Tools.pm | 1 - Anvil/Tools/Database.pm | 1 - anvil.spec.in | 6 +- man/anvil-manage-host.8 | 9 - scancore-agents/scan-network/scan-network | 81 +- tools/Makefile.am | 1 - tools/anvil-configure-host | 2034 ++++++++++++--------- tools/anvil-daemon | 131 +- tools/anvil-manage-host | 119 -- tools/anvil-monitor-network | 1418 ++++---------- tools/anvil-update-states | 1161 ------------ units/Makefile.am | 1 + units/anvil-monitor-network.service | 12 + 13 files changed, 1633 insertions(+), 3342 deletions(-) delete mode 100755 tools/anvil-update-states create mode 100644 units/anvil-monitor-network.service diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 27096462..b73a489c 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1170,7 +1170,6 @@ sub _set_paths 'anvil-special-operations' => "/usr/sbin/anvil-special-operations", 'anvil-sync-shared' => "/usr/sbin/anvil-sync-shared", 'anvil-update-files' => "/usr/sbin/anvil-update-files", - 'anvil-update-states' => "/usr/sbin/anvil-update-states", 'anvil-update-system' => "/usr/sbin/anvil-update-system", 'anvil-version-changes' => "/usr/sbin/anvil-version-changes", augtool => "/usr/bin/augtool", diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index c0f4129b..ac8069c0 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -18591,7 +18591,6 @@ sub track_files }}); next if $file_type eq "DELETED"; - ### TODO - Left off here, not adding DR links. my $anvil_needs_file = 0; foreach my $host_uuid ($anvil_node1_host_uuid, $anvil_node2_host_uuid) { diff --git a/anvil.spec.in b/anvil.spec.in index 458221a1..073ec54f 100644 --- a/anvil.spec.in +++ b/anvil.spec.in @@ -247,6 +247,7 @@ setenforce 0 ### TODO: check it if was disabled (if it existed before) and, if so, leave it disabled. systemctl enable --now chronyd.service systemctl enable --now anvil-daemon.service +systemctl enable --now anvil-monitor-network.service systemctl enable --now scancore.service %pre striker @@ -285,11 +286,6 @@ then systemctl enable gdm.service fi -### This is handled by anvil-daemon now -#echo "Preparing the database" -#striker-prep-database -#anvil-update-states - # Touch the system type file. echo "Touching the system type file" if [ -e '/etc/anvil/type.node' ] diff --git a/man/anvil-manage-host.8 b/man/anvil-manage-host.8 index 9a587139..366a5319 100644 --- a/man/anvil-manage-host.8 +++ b/man/anvil-manage-host.8 @@ -35,9 +35,6 @@ Check to see if the host is marked as configured or yet. \fB\-\-check\-database\fR This checks to see if the database is enabled or not. .TP -\fB\-\-check\-network\-mapping\fR -This reports if the host is currently in network mapping (this disables several features and watches the network states much more frequently) -.TP \fB\-\-confirm\fR This confirms actions that would normally prompt the user to confirm before proceeding. .TP @@ -47,12 +44,6 @@ This enables the database on the local Striker dashboard. \fB\-\-database\-inactive\fR This disables the database on the local Striker dashboard. .TP -\fB\-\-disable\-network\-mapping\fR -This disables the network mapping mode. -.TP -\fB\-\-enable\-network\-mapping\fR -This enables the network mapping mode. -.TP \fB\-\-mark\-configured\fR This marks the host as having been configured. .TP diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index ddf0e9d8..872fd5c3 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -69,6 +69,9 @@ if ($anvil->data->{switches}{purge}) $anvil->nice_exit({exit_code => 0}); } +# If there's no DB (or cached data isn't recorded to the database yet), this will store those records. +$anvil->data->{cache}{new_file} = "# interface,timestamp,mac_address,speed,link_state,operational,nm_uuid,nm_device\n"; +process_interface_cache($anvil); # Read the data. collect_data($anvil); @@ -88,6 +91,18 @@ clear_old_variables($anvil); # This removes network interfaces that have been marked as DELETED for a while now. clear_old_interfaces($anvil); +# Write out the interface cache +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + "cache::new_file" => $anvil->data->{cache}{new_file}, + "path::data::network_cache" => $anvil->data->{path}{data}{network_cache}, +}}); +$anvil->Storage->write_file({ + body => $anvil->data->{cache}{new_file}, + file => $anvil->data->{path}{data}{network_cache}, + overwrite => 1, + backup => 0, +}); + # Shut down. $anvil->ScanCore->agent_shutdown({agent => $THIS_FILE}); @@ -96,6 +111,67 @@ $anvil->ScanCore->agent_shutdown({agent => $THIS_FILE}); # Functions # ############################################################################################################# +# This reads in the interface cache file and looks for records that haven't been stored in the database yet. +sub process_interface_cache +{ + my ($anvil) = @_; + + # Does the file exist? If so, read it in. + if (-e $anvil->data->{path}{data}{network_cache}) + { + my $body = $anvil->Storage->read_file({debug => 2, cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}}); + foreach my $line (split/\n/, $body) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + next if $line =~ /^#/; + my ($interface, $timestamp, $mac_address, $speed, $link_state, $operational, $nm_uuid, $nm_device) = (split/,/, $line); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + timestamp => $timestamp, + speed => $speed, + mac_address => $mac_address, + link_state => $link_state, + operational => $operational, + nm_uuid => $nm_uuid, + nm_device => $nm_device, + }}); + + if ($anvil->data->{sys}{database}{connections}) + { + my ($network_interface_uuid) = $anvil->Database->insert_or_update_network_interfaces({ + debug => 2, + link_only => 1, + timestamp => $timestamp, + network_interface_name => $interface, + network_interface_link_state => $link_state, + network_interface_mac_address => $mac_address, + network_interface_operational => $operational, + network_interface_speed => $speed, + network_interface_nm_uuid => $nm_uuid, + network_interface_device => $nm_device, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }}); + if (not $network_interface_uuid) + { + # Failed to update, could be that we cached data for an interface not yet + # seen. If so, the coming scan will add it and this cache should flush out + # next time. + $anvil->data->{cache}{new_file} .= $line."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }}); + } + } + else + { + # No database, re-cache + $anvil->data->{cache}{new_file} .= $line."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }}); + } + } + } + + return(0); +} + # This removes network interfaces that have been marked as DELETED for a while now. sub clear_old_interfaces { @@ -460,7 +536,6 @@ sub collect_data { my ($anvil) = @_; - # The 'local_host' is needed to pull data recorded by Network->get_ips(); $anvil->Network->get_ips({debug => 2}); my $local_host = $anvil->Get->short_host_name(); @@ -890,7 +965,7 @@ sub collect_data # If this is a link and there's no database connections, cache the data. if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) { - $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational."\n"; + $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational.",".$nm_uuid.",".$nm_device."\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cache::new_file" => $anvil->data->{cache}{new_file}, }}); @@ -1409,7 +1484,7 @@ sub collect_data_ifcfg # If this is a link and there's no database connections, cache the data. if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) { - $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational."\n"; + $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational.",NULL,NULL\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cache::new_file" => $anvil->data->{cache}{new_file}, }}); diff --git a/tools/Makefile.am b/tools/Makefile.am index 88e9ec61..bdd4fddd 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -42,7 +42,6 @@ dist_sbin_SCRIPTS = \ anvil-test-alerts \ anvil-update-definition \ anvil-update-issue \ - anvil-update-states \ anvil-update-system \ anvil-version-changes \ anvil-virsh-wrapper \ diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 955e9a8d..8f623b3e 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -149,11 +149,13 @@ 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}) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { + "config::striker_password" => $anvil->data->{config}{striker_password}, + }}); + if ($anvil->data->{config}{striker_password}) { # Set the passwords - my $password = $anvil->data->{variables}{form}{config_step2}{striker_password}{value}; + my $password = $anvil->data->{config}{striker_password}; my $temp_file = "/tmp/anvil-".$anvil->Get->uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { password => $password }}); @@ -235,17 +237,17 @@ 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 $mn_count = exists $anvil->data->{variables}{form}{config_step1}{mn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{mn_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 $local_host = $anvil->Get->short_host_name(); + my $prefix = $anvil->data->{config}{prefix}; + my $sequence = $anvil->data->{config}{sequence}; + my $domain = $anvil->data->{config}{domain}; + my $new_host_name = $anvil->data->{config}{host_name}; + my $organization = $anvil->data->{config}{organization}; + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; my $type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { prefix => $prefix, @@ -259,18 +261,6 @@ sub reconfigure_network new_host_name => $new_host_name, type => $type, }}); - - # Clear the network mapping flag. - $anvil->Database->insert_or_update_variables({ - debug => 2, - variable_name => "config::map_network", - variable_value => 0, - variable_default => "", - variable_description => "striker_0202", - variable_section => "config", - variable_source_uuid => $anvil->Get->host_uuid, - variable_source_table => "hosts", - }); # If we're configuring a dashboard and no host name was given, generate it. if (($type eq "striker") && (not $new_host_name)) @@ -349,7 +339,7 @@ sub reconfigure_network } # Now configure the network. - my $dns = defined $anvil->data->{variables}{form}{config_step2}{dns}{value} ? [split/,/, $anvil->data->{variables}{form}{config_step2}{dns}{value}] : []; + my $dns = $anvil->data->{config}{dns} ? [split/,/, $anvil->data->{config}{dns}] : []; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { dns => $dns }}); for (my $i = 0; $i < @{$dns}; $i++) { @@ -357,8 +347,8 @@ sub reconfigure_network $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} : ""; + my $gateway = $anvil->data->{config}{gateway}; + my $gateway_interface = $anvil->data->{config}{gateway_interface}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { gateway => $gateway, gateway_interface => $gateway_interface, @@ -384,7 +374,8 @@ sub reconfigure_network { 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")) + + if ((exists $anvil->data->{config}{$ip_key}) && ($anvil->data->{config}{$ip_key} eq "dhcp")) { $gateway_interface = $network_type.$network_count; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { gateway_interface => $gateway_interface }}); @@ -490,586 +481,966 @@ ORDER BY # This will be set to '1' if we make a change. my $changes = 0; my $new_interfaces = []; + + my $network_type = $anvil->System->check_network_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + if ($network_type eq "ifcfg") + { + foreach my $network_type ("bcn", "sn", "mn", "ifn") + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + + # This is the old type of network config + configure_ifcfg_network($anvil, $network_type); + } + } + else + { + # Configure the network using Network Manager + reconfigure_bridges($anvil); + reconfigure_bonds($anvil); + reconfigure_interfaces($anvil); + reconfigure_ip_addresses($anvil); + } + + # If we should reset, do so now. + if ($anvil->data->{sys}{reboot}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0687", variables => { reason => "#!string!log_0631!#" }}); + do_reboot($anvil); + } + + if ($changes) + { + # In an attempt to make network changes more reliable, we'll just reboot. This shouldn't + # actually be hit anymore as any change should have triggered the reboot above. + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0687", variables => { reason => "#!string!log_0631!#" }}); + do_reboot($anvil); + + # Re-read the config + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0463"}); + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection reload"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Give a couple seconds for the reload + sleep 2; + + # Now check the bonds + my $repaired = $anvil->Network->check_network({heal => "all"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { repaired => $repaired }}); + if ($repaired) + { + # It can take a bit for the bonds to allow traffic, so sleep for a bit. + sleep 30; + } + } + + # Wait for a DB connection. We'll wait up to 130 seconds, as sometimes it takes a while for the network + # to start routing traffic. + 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, key => "log_0132"}); + if (not $anvil->data->{sys}{database}{connections}) + { + if (time > $wait_until) + { + # Failed to reconnect, reboot. Hopefully the network comes up cleanly + # next time.. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0107"}); + do_reboot($anvil); + } + + # No databases, sleep and then try again. + sleep 10; + } + } + + # 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}{setsid}." --wait ".$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}{setsid}." --wait ".$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}{setsid}." --wait ".$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}{setsid}." --wait ".$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); +} + +sub reconfigure_interfaces +{ + my ($anvil) = @_; + foreach my $network_type ("bcn", "sn", "mn", "ifn") { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + + # This is the old type of network config + configure_ifcfg_network($anvil, $network_type); + } + + + + + + foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{reconfigure}}) + { + my $uuid = $anvil->data->{network_manager}{reconfigure}{$wanted_interface}{from_uuid}; + my $old_device = $anvil->data->{interface}{uuid}{$uuid}{device}; + my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; + my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; + my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:wanted_interface' => $wanted_interface, + 's2:uuid' => $uuid, + 's3:old_device' => $old_device, + 's4:name' => $name, + 's5:mac_address' => $mac_address, + 's6:type' => $type, + }}); + + print "Renaming old device/name: [".$old_device."/".$name."] with MAC: [".$mac_address."] to: [".$wanted_interface."] using UUID: [".$uuid."]\n"; + + # Read persistent-net and see if it needs to be updated. + my $new_persistent_net = ""; + my $old_persistent_net = ""; + if (-e $anvil->data->{path}{configs}{'persistent-net'}) + { + $old_persistent_net = $anvil->Storage->read_file({debug => 2, file => $anvil->data->{path}{configs}{'persistent-net'}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_persistent_net => $old_persistent_net }}); + } + foreach my $line (split/\n/, $old_persistent_net) + { + # If this MAC or device name exists already, delete the line. + if (($line =~ /"$mac_address"/) or ($line =~ /"$wanted_interface"/)) + { + next; + } + $new_persistent_net .= $line."\n"; + } + $new_persistent_net .= "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"".$mac_address."\",ATTR{type}==\"".$type."\",NAME=\"".$wanted_interface."\"\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_persistent_net => $new_persistent_net }}); + + my $difference = diff \$old_persistent_net, \$new_persistent_net, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); -=cut - 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; } - elsif ($network_type eq "mn") { $count = $mn_count; } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + # Write the new file. + if ($difference) + { + print "- Updating the udev file: [".$anvil->data->{path}{configs}{'persistent-net'}."]\n"; + my $problem = $anvil->Storage->write_file({ + file => $anvil->data->{path}{configs}{'persistent-net'}, + body => $new_persistent_net, + overwrite => 1, + user => "admin", + group => "admin", + mode => "0644", + + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + if ($problem) + { + print "[ Error ] - Failed to write the new: [".$anvil->data->{path}{configs}{'persistent-net'}."] file, aborting!\n"; + $anvil->nice_exit({exit_code => 1}); + } + } - next if not $count; - foreach my $network_count (1..$count) + # Update the connection.interface-name + my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); + if ($connection_interface_name) { - # If the user had the option to create a network but didn't, there will be no link1 - # mac to set. - my $this_network = $network_type.$network_count; - my $link1_key = $this_network."_link1_mac_to_set"; + print "- Removing the old 'connection.interface-name': [".$connection_interface_name."]\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.interface-name \"\""; + $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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - this_network => $this_network, - link1_key => $link1_key, + output => $output, + return_code => $return_code, }}); - next if not exists $anvil->data->{variables}{form}{config_step2}{$link1_key}; - next if not $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}; - 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; + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.interface-name connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_key => $ip_key, - is_gateway => $is_gateway, - 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, - bridge => $bridge, + output => $output, + return_code => $return_code, }}); - # 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; - my $link1_nm_uuid = $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, - link1_nm_uuid => $link1_nm_uuid, - }}); - if ((exists $anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}) && ($anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}{name})) + if ($output) { - $old_link1_nm_name = $anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_nm_name => $old_link1_nm_name }}); + # This should have been blank + print "[ Error ] - Failed to delete the 'connection.interface-name', got: [".$output."] and it should bhave been blank, aborting!\n"; + $anvil->nice_exit({exit_code => 1}); } + } + + # We'll log what it was, and change it anyway + my $match_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); + if (1) + { + print "- Matching the new interface name: [".$wanted_interface."] to the bios device name: [".$old_device."]\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." match.interface-name \"".$wanted_interface." ".$old_device."\""; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); - # Is there a link 2? - my $old_link2_nm_name = ""; - if ($old_link2_iface) + if (($output ne $wanted_interface.",".$old_device) && ($output ne $old_device.",".$wanted_interface)) { - $old_link2_nm_name = $old_link2_iface; - my $link2_nm_uuid = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link2_nm_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - old_link2_nm_name => $old_link2_nm_name, - link2_nm_uuid => $link2_nm_uuid, - }}); - if ((exists $anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}) && ($anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}{name})) - { - $old_link2_nm_name = $anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_nm_name => $old_link2_nm_name }}); - } + # This should have been blank + print "[ Error ] - Failed to create the 'match.interface-name' value. Expected: [".$wanted_interface.",".$old_device."], got: [".$output."], aborting!\n"; + $anvil->nice_exit({exit_code => 1}); } - # 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}) + # Set the connection.id to the old name. + print "- Setting the connection.id to the bios device name: [".$old_device."]\n"; + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.id \"".$old_device."\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + + # Set the reboot flag. + $anvil->data->{sys}{reboot_needed} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); + } + + if ($anvil->data->{sys}{reboot_needed}) + { + print "Reboot needed.\n"; + print "- Regenerating dracute initrd image, this can take a moment...\n"; + my $shell_call = $anvil->data->{path}{exe}{dracut}." --force"; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + print "- New initrd image created.\n"; + print "[ Note ] - Reboot needed. Re-run this after the reboot to complete setup.\n"; + print "- Rebooting in 60 seconds (press 'ctrl + c' to abort).\n"; + my $timeout = 60; + while($timeout) + { + if ($timeout % 10) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0176", variables => { ip_key => $ip_key }}); - next; + print "." } 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} }}); + print $timeout; } - 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}}))) + sleep 1; + $timeout--; + } + print "0\n"; + print "Rebooting NOW!\n"; + + $shell_call = $anvil->data->{path}{exe}{systemctl}." reboot"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($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 }}); + } + + return(0); +} + +sub configure_ifcfg_network +{ + my ($anvil, $network_type) = @_; + $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; } + elsif ($network_type eq "mn") { $count = $mn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + next if not $count; + foreach my $network_count (1..$count) + { + # If the user had the option to create a network but didn't, there will be no link1 + # mac to set. + my $this_network = $network_type.$network_count; + my $link1_key = $this_network."_link1_mac_to_set"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + this_network => $this_network, + link1_key => $link1_key, + }}); + + + next if not exists $anvil->data->{config}{$link1_key}; + next if not $anvil->data->{config}{$link1_key}; + 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->{config}{$link1_key}; + my $is_gateway = $this_network eq $gateway_interface ? 1 : 0; + my $link2_mac = defined $anvil->data->{config}{$link2_key} ? $anvil->data->{config}{$link2_key} : ""; + 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->{config}{$bridge_key} ? $anvil->data->{config}{$bridge_key} : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_key => $ip_key, + is_gateway => $is_gateway, + 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, + 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; + my $link1_nm_uuid = $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, + link1_nm_uuid => $link1_nm_uuid, + }}); + if ((exists $anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}) && ($anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}{name})) + { + $old_link1_nm_name = $anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}{name}; + $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; + my $link2_nm_uuid = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link2_nm_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_link2_nm_name => $old_link2_nm_name, + link2_nm_uuid => $link2_nm_uuid, + }}); + if ((exists $anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}) && ($anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}{name})) { - # 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; + $old_link2_nm_name = $anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}{name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_nm_name => $old_link2_nm_name }}); } - - # 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, + } + + # Skip if this doesn't exist or isn't a valid IPv4 address. + if (not exists $anvil->data->{config}{$ip_key}) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0176", variables => { ip_key => $ip_key }}); + next; + } + else + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "config::${ip_key}" => $anvil->data->{config}{$ip_key} }}); + } + if (($anvil->data->{config}{$ip_key}) && + ($anvil->data->{config}{$ip_key} ne "dhcp") && + (not $anvil->Validate->ipv4({ip => $anvil->data->{config}{$ip_key}}))) + { + # 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->{config}{$ip_key}, }}); + next; + } + + # The IP could be 'dhcp', we'll handle that in a bit. + my $ip_address = $anvil->data->{config}{$ip_key}; + my $subnet_mask = defined $anvil->data->{config}{$subnet_mask_key} ? $anvil->data->{config}{$subnet_mask_key} : ""; + $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 "mn") + { + $say_network = "Migration Network ".$network_count; + $say_interface = "mn".$network_count; + $interface_prefix = "MN"; + } + elsif ($network_type eq "ifn") + { + $say_network = "Internet-Facing Network ".$network_count; + $say_interface = "ifn".$network_count; + $interface_prefix = "IFN"; + } - # Are we building bonded interfaces? - if ($anvil->Validate->mac({mac => $link2_mac})) + # 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})) { - # Yup! - my $say_network = ""; - my $say_interface = ""; - my $interface_prefix = ""; - my $say_defroute = $is_gateway ? "yes" : "no"; - if ($network_type eq "bcn") + # This is the device name (ie: bcn1_link1, ens0, etc). If it doesn't + # exist, see if the new name exists already. + $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 => { old_link1_file => $old_link1_file }}); + if (not -f $old_link1_file) { - $say_network = "Back-Channel Network ".$network_count; - $say_interface = "bcn".$network_count; - $interface_prefix = "BCN"; + # Does the new file already exist? + if (-f $new_link1_file) + { + # Set the old file to the new one. + $old_link1_file = $new_link1_file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); + } } - elsif ($network_type eq "sn") - { - $say_network = "Storage Network ".$network_count; - $say_interface = "sn".$network_count; - $interface_prefix = "SN"; - } - elsif ($network_type eq "mn") - { - $say_network = "Migration Network ".$network_count; - $say_interface = "mn".$network_count; - $interface_prefix = "MN"; - } - 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})) + } + 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 => { old_link2_file => $old_link2_file }}); + if (not -f $old_link2_file) { - # This is the device name (ie: bcn1_link1, ens0, etc). If it doesn't - # exist, see if the new name exists already. - $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 => { old_link1_file => $old_link1_file }}); - if (not -f $old_link1_file) + # Does the new file already exist? + if (-f $new_link2_file) { - # Does the new file already exist? - if (-f $new_link1_file) - { - # Set the old file to the new one. - $old_link1_file = $new_link1_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); - } + # Set the old file to the new one. + $old_link2_file = $new_link2_file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_file => $old_link2_file }}); } } - if ((exists $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}) && ($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") { - $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 => { old_link2_file => $old_link2_file }}); - if (not -f $old_link2_file) + $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) { - # Does the new file already exist? - if (-f $new_link2_file) + $bridge_config .= "GATEWAY=\"".$gateway."\"\n"; + for (my $i = 0; $i < @{$dns}; $i++) { - # Set the old file to the new one. - $old_link2_file = $new_link2_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_file => $old_link2_file }}); + $bridge_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n"; } } } - $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) + $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") { - 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; + $bond_config .= "IPADDR=\"".$ip_address."\"\n"; + $bond_config .= $cidr ? "PREFIX=\"".$cidr."\"\n" : "NETMASK=\"".$subnet_mask."\"\n"; - # 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") + # If this is the default gateway, add that info. + if ($is_gateway) { - $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) + $bond_config .= "GATEWAY=\"".$gateway."\"\n"; + for (my $i = 0; $i < @{$dns}; $i++) { - $bridge_config .= "GATEWAY=\"".$gateway."\"\n"; - for (my $i = 0; $i < @{$dns}; $i++) - { - $bridge_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n"; - } + $bond_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"; } + $bond_config .= "DEFROUTE=\"".$say_defroute."\"\n"; + } + # Rest of the config + $bond_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; + # 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"; - # 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 => { + bridge_config => $bridge_config, + bond_config => $bond_config, + link1_config => $link1_config, + link2_config => $link2_config, + }}); + + # Decide if we need to reboot. + if (($old_link1_file ne $new_link1_file) && (-e $new_link1_file)) + { + $changes = 1; + $anvil->data->{sys}{reboot} = 1; $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, + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, }}); - - # 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"; - + } + if (($old_link2_file ne $new_link2_file) && (-e $new_link2_file)) + { + $changes = 1; + $anvil->data->{sys}{reboot} = 1; $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, + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, }}); - - # Decide if we need to reboot. - if (($old_link1_file ne $new_link1_file) && (-e $new_link1_file)) - { - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - if (($old_link2_file ne $new_link2_file) && (-e $new_link2_file)) - { - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - - ### Write out the new configs, if needed - # Are we writing a bridge config? - if ($bridge) - { - # If the file already exists, see if it changed. - my $update = 1; - if (-e $bridge_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $bridge_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$bridge_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $bridge_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); - } - } - - if ($update) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - bridge_file => $bridge_file, - bridge_config => $bridge_config, - }}); - $anvil->Storage->write_file({ - file => $bridge_file, - body => $bridge_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } - } - - # Bond, Link 1 and Link 2 - my $update_bond = 1; - if (-f $bond_file) + } + + ### Write out the new configs, if needed + # Are we writing a bridge config? + if ($bridge) + { + # If the file already exists, see if it changed. + my $update = 1; + if (-e $bridge_file) { # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $bond_file}); + my $old_body = $anvil->Storage->read_file({file => $bridge_file}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - my $difference = diff \$old_body, \$bond_config, { STYLE => 'Unified' }; + my $difference = diff \$old_body, \$bridge_config, { STYLE => 'Unified' }; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); if ($difference) { # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $bond_file}); + $anvil->Storage->backup({debug => 2, file => $bridge_file}); $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); } else { # No need to update - $update_bond = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_bond => $update_bond }}); + $update = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); } } - if ($update_bond) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - bond_file => $bond_file, - bond_config => $bond_config, - }}); - $anvil->Storage->write_file({ - file => $bond_file, - body => $bond_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } - # Link 1 - my $update_link1 = 1; - if (-f $new_link1_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link1_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$link1_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link1_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update_link1 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link1 => $update_link1 }}); - } - } - if ($update_link1) + if ($update) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link1_file => $new_link1_file, - link1_config => $link1_config, + bridge_file => $bridge_file, + bridge_config => $bridge_config, }}); $anvil->Storage->write_file({ - file => $new_link1_file, - body => $link1_config, + file => $bridge_file, + body => $bridge_config, user => "root", group => "root", mode => "0644", overwrite => 1 }); } + } + + # Bond, Link 1 and Link 2 + my $update_bond = 1; + if (-f $bond_file) + { + # Read it in to see if there is a difference. + my $old_body = $anvil->Storage->read_file({file => $bond_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - # Link 2 - my $update_link2 = 1; - if (-f $new_link2_file) + my $difference = diff \$old_body, \$bond_config, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + if ($difference) { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link2_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$link2_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link2_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update_link2 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link2 => $update_link2 }}); - } + # Backup the old file. + $anvil->Storage->backup({debug => 2, file => $bond_file}); + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); } - if ($update_link2) + else { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link2_file => $new_link2_file, - link2_config => $link2_config, - }}); - $anvil->Storage->write_file({ - file => $new_link2_file, - body => $link2_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); + # No need to update + $update_bond = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_bond => $update_bond }}); } + } + if ($update_bond) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + bond_file => $bond_file, + bond_config => $bond_config, + }}); + $anvil->Storage->write_file({ + file => $bond_file, + body => $bond_config, + user => "root", + group => "root", + mode => "0644", + overwrite => 1 + }); + } + + # Link 1 + my $update_link1 = 1; + if (-f $new_link1_file) + { + # Read it in to see if there is a difference. + my $old_body = $anvil->Storage->read_file({file => $new_link1_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - # Backup the old config files, if needed. - if (-e $old_link1_file) + my $difference = diff \$old_body, \$link1_config, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + if ($difference) { - $anvil->Storage->backup({file => $old_link1_file}); + # Backup the old file. + $anvil->Storage->backup({debug => 2, file => $new_link1_file}); + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); } - if (-e $old_link2_file) + else { - $anvil->Storage->backup({file => $old_link2_file}); + # No need to update + $update_link1 = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link1 => $update_link1 }}); } + } + if ($update_link1) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + link1_file => $new_link1_file, + link1_config => $link1_config, + }}); + $anvil->Storage->write_file({ + file => $new_link1_file, + body => $link1_config, + user => "root", + group => "root", + mode => "0644", + overwrite => 1 + }); + } + + # Link 2 + my $update_link2 = 1; + if (-f $new_link2_file) + { + # Read it in to see if there is a difference. + my $old_body = $anvil->Storage->read_file({file => $new_link2_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - # 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)) + my $difference = diff \$old_body, \$link2_config, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + if ($difference) { - rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}, $new_link1_iface); - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); + # Backup the old file. + $anvil->Storage->backup({debug => 2, file => $new_link2_file}); + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); } - 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)) + else { - rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link2_mac}{interface}, $new_link2_iface); - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); + # No need to update + $update_link2 = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link2 => $update_link2 }}); } + } + if ($update_link2) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + link2_file => $new_link2_file, + link2_config => $link2_config, + }}); + $anvil->Storage->write_file({ + file => $new_link2_file, + body => $link2_config, + user => "root", + group => "root", + mode => "0644", + overwrite => 1 + }); + } + + # Backup the old config files, if needed. + if (-e $old_link1_file) + { + $anvil->Storage->backup({file => $old_link1_file}); + } + if (-e $old_link2_file) + { + $anvil->Storage->backup({file => $old_link2_file}); + } + + # 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); + $changes = 1; + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, + }}); + } + 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); + $changes = 1; + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, + }}); + } + + # 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 }}); - # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link1_nm_name; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); # my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); @@ -1077,25 +1448,25 @@ ORDER BY # 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; - } - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - elsif ($update_link1) + + if (-e $old_link1_file) { - # 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->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0589", variables => { file => $old_link1_file }}); + unlink $old_link1_file; + } + + $changes = 1; + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, + }}); + } + elsif ($update_link1) + { + # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link1_nm_name; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); # my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); @@ -1106,21 +1477,21 @@ ORDER BY # # $changes = 1; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - # 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 }}); - + $changes = 1; + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, + }}); + } + + # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link2_nm_name; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); # my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); @@ -1128,25 +1499,25 @@ ORDER BY # output => $output, # return_code => $return_code, # }}); - - 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; - } - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - elsif ($update_link1) + + if (-e $old_link2_file) { - # Down the interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0462", variables => { interface => $old_link2_nm_name }}); - + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0589", variables => { file => $old_link2_file }}); + unlink $old_link2_file; + } + + $changes = 1; + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, + }}); + } + elsif ($update_link1) + { + # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link2_nm_name; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); # my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); @@ -1157,360 +1528,206 @@ ORDER BY # # $changes = 1; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } + + $changes = 1; + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, + }}); } - elsif ((exists $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}) && ($anvil->Validate->mac({mac => $anvil->data->{variables}{form}{config_step2}{$link1_key}{value}}))) + } + elsif ((exists $anvil->data->{config}{$link1_key}) && ($anvil->Validate->mac({mac => $anvil->data->{config}{$link1_key}}))) + { + ### 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->{config}{$link1_key}; + $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") { - ### 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"; - } - elsif ($network_type eq "mn") - { - $say_network = "Migration Network ".$network_count; - $say_interface = "mn".$network_count; - $interface_prefix = "MN"; - } - 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})) + $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"; + } + elsif ($network_type eq "mn") + { + $say_network = "Migration Network ".$network_count; + $say_interface = "mn".$network_count; + $interface_prefix = "MN"; + } + 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}; + if (not -f $old_link1_file) { - $old_link1_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}; - if (not -f $old_link1_file) + # Does the new file already exist? + if (-f $new_link1_file) { - # Does the new file already exist? - if (-f $new_link1_file) - { - # Set the old file to the new one. - $old_link1_file = $new_link1_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); - } + # Set the old file to the new one. + $old_link1_file = $new_link1_file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); } } - $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) + } + $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 .= "GATEWAY=\"".$gateway."\"\n"; - for (my $i = 0; $i < @{$dns}; $i++) - { - $link1_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n"; - } + $link1_config .= "DNS".($i+1)."=\"".$dns->[$i]."\"\n"; } - $link1_config .= "DEFROUTE=\"".$say_defroute."\"\n"; - $link1_config .= "USERCTL=\"no\"\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)."\""; + $link1_config .= "NM_CONTROLLED=\"yes\"\n"; + $link1_config .= "ZONE=\"".uc($say_interface)."\""; + + # Link 1 + my $update_link1 = 1; + if (-f $new_link1_file) + { + # Read it in to see if there is a difference. + my $old_body = $anvil->Storage->read_file({file => $new_link1_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - # Link 1 - my $update_link1 = 1; - if (-f $new_link1_file) + my $difference = diff \$old_body, \$link1_config, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + if ($difference) { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link1_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$link1_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link1_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update_link1 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link1 => $update_link1 }}); - } + # Backup the old file. + $anvil->Storage->backup({debug => 2, file => $new_link1_file}); + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); } - if ($update_link1) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link1_file => $new_link1_file, - link1_config => $link1_config, - }}); - $anvil->Storage->write_file({ - file => $new_link1_file, - body => $link1_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } - - # Backup the existing link1 file, if it exists and is different. - if (-e $old_link1_file) + else { - $anvil->Storage->backup({file => $old_link1_file}); + # No need to update + $update_link1 = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link1 => $update_link1 }}); } + } + if ($update_link1) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + link1_file => $new_link1_file, + link1_config => $link1_config, + }}); + $anvil->Storage->write_file({ + file => $new_link1_file, + body => $link1_config, + user => "root", + group => "root", + mode => "0644", + overwrite => 1 + }); + } + + # Backup the existing link1 file, if it exists and is different. + if (-e $old_link1_file) + { + $anvil->Storage->backup({file => $old_link1_file}); + } + + # 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 }}); - # 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 }}); - # my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link1_nm_name; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); # $anvil->System->call({debug => 2, shell_call => $shell_call}); # # rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}, $new_link1_iface); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - elsif ($update_link1) - { - # Down the interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0462", variables => { interface => $old_link1_nm_name }}); - + + $changes = 1; + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, + }}); + } + elsif ($update_link1) + { + # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link1_nm_name; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); # $anvil->System->call({debug => 2, shell_call => $shell_call}); # # $changes = 1; # $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - } - 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; - } - } -=cut - } -die; - - # If we should reset, do so now. - if ($anvil->data->{sys}{reboot}) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0687", variables => { reason => "#!string!log_0631!#" }}); - do_reboot($anvil); - } - - if ($changes) - { - # In an attempt to make network changes more reliable, we'll just reboot. This shouldn't - # actually be hit anymore as any change should have triggered the reboot above. - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0687", variables => { reason => "#!string!log_0631!#" }}); - do_reboot($anvil); - -# # Re-read the config -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0463"}); -# -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection reload"; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# # Give a couple seconds for the reload -# sleep 2; -# -# # Now check the bonds -# my $repaired = $anvil->Network->check_network({heal => "all"}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { repaired => $repaired }}); -# if ($repaired) -# { -# # It can take a bit for the bonds to allow traffic, so sleep for a bit. -# sleep 30; -# } - } - - # Wait for a DB connection. We'll wait up to 130 seconds, as sometimes it takes a while for the network - # to start routing traffic. -# 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, key => "log_0132"}); -# if (not $anvil->data->{sys}{database}{connections}) -# { -# if (time > $wait_until) -# { -# # Failed to reconnect, reboot. Hopefully the network comes up cleanly -# # next time.. -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0107"}); -# do_reboot($anvil); -# } -# -# # No databases, sleep and then try again. -# sleep 10; -# } -# } - - # 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}{setsid}." --wait ".$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, + + $changes = 1; + $anvil->data->{sys}{reboot} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + changes => $changes, + "sys::reboot" => $anvil->data->{sys}{reboot}, }}); - 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) + else { - $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}{setsid}." --wait ".$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}{setsid}." --wait ".$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}{setsid}." --wait ".$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 }}); + # Doesn't exist, skip. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "log_0149", variables => { network => $this_network }}); + next; } } - $anvil->Job->update_progress({ - progress => 75, - job_uuid => $anvil->data->{job}{uuid}, - }); - return(0); } @@ -1633,9 +1850,26 @@ sub pickup_job_details }}); } + ### These are the new variables + $anvil->data->{config}{striker_password} = ""; + $anvil->data->{config}{prefix} = ""; + $anvil->data->{config}{sequence} = ""; + $anvil->data->{config}{domain} = ""; + $anvil->data->{config}{host_name} = ""; + $anvil->data->{config}{organization} = ""; + $anvil->data->{config}{bcn_count} = 1; + $anvil->data->{config}{ifn_count} = 1; + $anvil->data->{config}{sn_count} = 0; + $anvil->data->{config}{mn_count} = 0; + $anvil->data->{config}{dns} = ""; + $anvil->data->{config}{gateway} = ""; + $anvil->data->{config}{gateway_interface} = ""; + + ### TODO: Remove this later # This will store the variables from the database $anvil->data->{variables} = {}; + ### TODO: Remove this, it shouldn't be needed once we confirm everything is in the job_data. # If we're still alive, pick up the details. my $query = " SELECT @@ -1673,6 +1907,7 @@ AND $anvil->_make_hash_reference($anvil->data->{variables}, $this_variable, $this_value); } + ### TODO: This is the only way we should do it, but the variable names need to change to be more sensible. # Overwrite variables with job data. foreach my $line (split/\n/, $anvil->data->{jobs}{job_data}) { @@ -1684,6 +1919,37 @@ AND }}); $anvil->_make_hash_reference($anvil->data->{variables}, $1, $2); } + elsif ($line =~ /^(.*?)=(.*)$/) + { + my $variable = $1; + my $value = $2; + my $secure = $variable =~ /passw/ ? 1 : 0; + $anvil->data->{config}{$variable} = $value; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:variable' => $variable, + 's2:value' => $anvil->Log->is_secure($value), + "s3:config::${variable}" => $anvil->Log->is_secure($anvil->data->{config}{$variable}), + }}); + } + } + + ### TODO: Remove this when no longer needed. + # Convert old variables to new ones. + foreach my $config_step (sort {$a cmp $b} keys %{$anvil->data->{variables}{form}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { config_step => $config_step }}); + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{variables}{form}{$config_step}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable => $variable }}); + + if (exists $anvil->data->{variables}{form}{$config_step}{$variable}{value}) + { + $anvil->data->{config}{$variable} = $anvil->data->{variables}{form}{$config_step}{$variable}{value}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${variable}" => $anvil->data->{config}{$variable}, + }}); + } + } } # Clear previous data diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 510a1b3f..794827c1 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -201,7 +201,7 @@ while(1) # Reload defaults, re-read the config and then connect to the database(s) $anvil->refresh(); - # If, so some reason, anvil.conf is lost, create it. + # If, for some reason, anvil.conf is lost, create it. $anvil->System->_check_anvil_conf(); $anvil->Database->connect({check_if_configured => $check_if_database_is_configured, check_for_resync => 2}); @@ -210,25 +210,13 @@ while(1) # Mark that we don't want to check the database now. $check_if_database_is_configured = 0; - # If this host is mapping the network, we'll skip a lot of stuff. If set for over an hour, we'll - # clear it. - $anvil->data->{sys}{mapping_network} = check_if_mapping($anvil); - if ($anvil->data->{sys}{database}{connections}) { # Run the normal tasks keep_running($anvil); # Handle periodic tasks - handle_periodic_tasks($anvil) if not $anvil->data->{sys}{mapping_network}; - } - else - { - # No databases available, we'll update the state file in case this host is having it's - # network mapped and the interface used to talk to the databases went down. That's all we - # can do though. - update_state_file($anvil); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "log_0202"}); + handle_periodic_tasks($anvil); } # Exit if 'run-once' selected. @@ -313,85 +301,6 @@ sub check_ram return(0); } -# Check to see if we're mapping the network on this host. -sub check_if_mapping -{ - my ($anvil) = @_; - - $anvil->data->{sys}{mapping_network} = 0; - if ($anvil->data->{sys}{database}{connections}) - { - my ($map_network_value, $map_network_uuid, $map_network_mtime, $map_network_modified_date) = $anvil->Database->read_variable({ - debug => 3, - variable_name => "config::map_network", - variable_source_table => "hosts", - variable_source_uuid => $anvil->data->{sys}{host_uuid}, - }); - # We'll run for a day (should be cancelled by the program when the user's done, so this - # shouldn't fire in practice). - my $expire_age = 86400; - my $map_network_age = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:map_network_value' => $map_network_value, - 's2:map_network_mtime' => $map_network_mtime, - 's3:map_network_modified_date' => $map_network_modified_date, - 's4:map_network_uuid' => $map_network_uuid, - }}); - if ($map_network_uuid) - { - $map_network_age = time - $map_network_mtime; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { map_network_age => $map_network_age }}); - } - if ($map_network_value) - { - # How long ago was it set? - $anvil->data->{switches}{'clear-mapping'} = "" if not defined $anvil->data->{switches}{'clear-mapping'}; - if (($map_network_age >= $expire_age) or ($anvil->data->{switches}{'clear-mapping'})) - { - # Clear it. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0470"}); - $anvil->Database->insert_or_update_variables({ - debug => 3, - variable_value => 0, - variable_uuid => $map_network_uuid, - update_value_only => 1, - }); - } - else - { - # Mark it so we only track the network. - my $say_age = $anvil->Convert->add_commas({number => $expire_age}); - my $timeout = $anvil->Convert->add_commas({number => ($expire_age - $map_network_age)}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0471", variables => { - age => $say_age, - timeout => $timeout, - }}); - - $anvil->data->{sys}{mapping_network} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::mapping_network" => $anvil->data->{sys}{mapping_network} }}); - - # Close any open ssh connections. - foreach my $ssh_fh_key (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 => 3, list => { - ssh_fh_key => $ssh_fh_key, - ssh_fh => $ssh_fh, - }}); - if ($ssh_fh =~ /^Net::OpenSSH/) - { - $ssh_fh->disconnect(); - } - delete $anvil->data->{cache}{ssh_fh}{$ssh_fh_key}; - } - } - } - } - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "sys::mapping_network" => $anvil->data->{sys}{mapping_network} }}); - return($anvil->data->{sys}{mapping_network}); -} - # This decides if the local system will delay daily runs on start-up. sub set_delay { @@ -556,9 +465,6 @@ sub handle_periodic_tasks return_code => $return_code, }}); - # Scan the local network. - update_state_file($anvil); - # Check shared files. check_files($anvil); @@ -1537,7 +1443,7 @@ sub keep_running my ($anvil) = @_; # Check for jobs that were running and now exited. - if ((not $anvil->data->{sys}{mapping_network}) && (exists $anvil->data->{processes})) + if (exists $anvil->data->{processes}) { foreach my $job_uuid (%{$anvil->data->{jobs}{handles}}) { @@ -1568,18 +1474,13 @@ sub keep_running # If we're configured, write out the status JSON file. If we're not configured, Update hardware state files. my $configured = $anvil->System->check_if_configured; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { configured => $configured }}); - if ((not $anvil->data->{sys}{mapping_network}) && ($configured)) + if ($configured) { # Write out state information for all known Anvil! systems and the information from # unconfigured nods and DR hosts, using just database data (hence, fast enough to run # constantly). $anvil->System->generate_state_json({debug => 2}); } - else - { - # Run this to monitor the network in real time. - update_state_file($anvil); - } # Run any pending jobs by calling 'anvil-jobs' with the 'job_uuid' as a background process. run_jobs($anvil, 0); @@ -1672,11 +1573,10 @@ sub run_jobs 's12:job_status' => $job_status, 's13:started_seconds_ago' => $started_seconds_ago, 's14:updated_seconds_ago' => $updated_seconds_ago, - 's15:sys::mapping_network' => $anvil->data->{sys}{mapping_network}, }}); # If we're mapping, we'll only run 'anvil-configure-host' jobs on this host. - next if (($anvil->data->{sys}{mapping_network}) && ($job_command !~ /anvil-configure-host/)); + next if $job_command !~ /anvil-configure-host/; # To minimize the chance of race conditions, any given command will be called only # once at a time. If two jobs of the same command exist, only one will be called. @@ -2028,24 +1928,3 @@ sub check_files return(0); } - -# This calls 'anvil-update-states' which will scan the local machine's state (hardware and software) and -# record write it out to an HTML file -sub update_state_file -{ - my ($anvil) = @_; - - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0480"}); - - #my $shell_call = $anvil->data->{path}{exe}{'anvil-update-states'}.$anvil->Log->switches; - my $shell_call = $anvil->data->{path}{exe}{'anvil-update-states'}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }}); - - my ($states_output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - states_output => $states_output, - return_code => $return_code, - }}); - - return(0); -} diff --git a/tools/anvil-manage-host b/tools/anvil-manage-host index 97f7894d..9b3ce96c 100755 --- a/tools/anvil-manage-host +++ b/tools/anvil-manage-host @@ -29,12 +29,9 @@ $anvil->Get->switches({list => [ "auto-grow-pv", "check-configured", "check-database", - "check-network-mapping", "confirm", "database-active", "database-inactive", - "disable-network-mapping", - "enable-network-mapping", "mark-configured", "mark-unconfigured", "resync-database"], man => $THIS_FILE}); @@ -58,10 +55,6 @@ elsif (($anvil->data->{switches}{'database-active'}) or ($anvil->data->{switches { update_database($anvil); } -elsif (($anvil->data->{switches}{'enable-network-mapping'}) or ($anvil->data->{switches}{'disable-network-mapping'}) or ($anvil->data->{switches}{'check-network-mapping'})) -{ - update_network_mapping($anvil); -} elsif ($anvil->data->{switches}{'age-out-database'}) { age_out_data($anvil); @@ -279,118 +272,6 @@ sub update_database return(0); } -sub update_network_mapping -{ - my ($anvil) = @_; - - my $variable_name = "config::map_network"; - my ($map_network_value, $map_network_uuid, $map_network_mtime, $map_network_modified_date) = $anvil->Database->read_variable({ - variable_name => $variable_name, - variable_source_table => "hosts", - variable_source_uuid => $anvil->data->{sys}{host_uuid}, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:variable_name' => $variable_name, - 's2:map_network_value' => $map_network_value, - 's3:map_network_mtime' => $map_network_mtime, - 's4:map_network_modified_date' => $map_network_modified_date, - 's5:map_network_uuid' => $map_network_uuid, - }}); - if ($anvil->data->{switches}{'check-network-mapping'}) - { - # We'll run for a day (should be cancelled by the program when the user's done, so this - # shouldn't fire in practice). - my $expire_age = 86400; - my $map_network_age = 0; - if ($map_network_uuid) - { - $map_network_age = time - $map_network_mtime; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { map_network_age => $map_network_age }}); - } - if ($map_network_value) - { - # How long ago was it set? - $anvil->data->{switches}{'clear-mapping'} = "" if not defined $anvil->data->{switches}{'clear-mapping'}; - if (($map_network_age >= $expire_age) or ($anvil->data->{switches}{'clear-mapping'})) - { - # Clear it. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0470"}); - $anvil->Database->insert_or_update_variables({ - debug => 3, - variable_value => 0, - variable_uuid => $map_network_uuid, - update_value_only => 1, - }); - } - else - { - # Mark it so we only track the network. - my $say_age = $anvil->Convert->add_commas({number => $expire_age}); - my $timeout = $anvil->Convert->add_commas({number => ($expire_age - $map_network_age)}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0471", variables => { - age => $say_age, - timeout => $timeout, - }}); - } - } - else - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0820"}); - } - return(0); - } - - if ($anvil->data->{switches}{'enable-network-mapping'}) - { - if ($map_network_value) - { - # Nothing to do. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0353"}); - } - else - { - # Enable network configuring. - my $variable_uuid = $anvil->Database->insert_or_update_variables({ - variable_name => $variable_name, - variable_value => 1, - variable_default => "", - variable_description => "striker_0202", - variable_section => "config", - variable_source_uuid => $anvil->Get->host_uuid, - variable_source_table => "hosts", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0354"}); - } - } - - if ($anvil->data->{switches}{'disable-network-mapping'}) - { - if ($map_network_value) - { - # Disable network configuring. - my $variable_uuid = $anvil->Database->insert_or_update_variables({ - variable_name => $variable_name, - variable_value => 0, - variable_default => "", - variable_description => "striker_0202", - variable_section => "config", - variable_source_uuid => $anvil->Get->host_uuid, - variable_source_table => "hosts", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { variable_uuid => $variable_uuid }}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0356"}); - } - else - { - # Nothing to do. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0355"}); - } - } - - return(0); -} - sub update_config { my ($anvil) = @_; diff --git a/tools/anvil-monitor-network b/tools/anvil-monitor-network index 89557f8b..dab33a0e 100755 --- a/tools/anvil-monitor-network +++ b/tools/anvil-monitor-network @@ -1,4 +1,12 @@ #!/usr/bin/perl +# +# This daemon watches for network interface link change (unplugged or plugged in network cables). +# +# At this point, the only thing this does is call 'scan-network' when a change is detected. +# +# NOTE: This is designed to be minimal overhead, so there is no attempt to connect to the database. As such, +# be mindful of what this daemon is used for. +# use strict; use warnings; @@ -23,1129 +31,475 @@ $anvil->Get->switches({list => [], man => $THIS_FILE}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); -# We'll try to connect in case we're adding additional peers. -$anvil->Database->connect({debug => 3}); -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"}); +# Calculate my sum so that we can exit if it changes later. +$anvil->Storage->record_md5sums; +my $next_md5sum_check = time + 30; -#print "DBs: [".$anvil->data->{sys}{database}{connections}."]\n"; +my $directory = "/sys/class/net"; +$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }}); -$anvil->data->{network_manager}{want}{interface}{ifn1_link1}{mac_address} = "52:54:00:d3:19:cc"; -$anvil->data->{network_manager}{want}{interface}{ifn1_link1}{device} = "enp1s0"; -$anvil->data->{network_manager}{want}{interface}{ifn1_link2}{mac_address} = "52:54:00:fc:82:b0"; -$anvil->data->{network_manager}{want}{interface}{ifn1_link2}{device} = "enp7s0"; - -$anvil->data->{network_manager}{want}{interface}{bcn1_link1}{mac_address} = "52:54:00:86:f5:1d"; -$anvil->data->{network_manager}{want}{interface}{bcn1_link1}{device} = "enp8s0"; -$anvil->data->{network_manager}{want}{interface}{bcn1_link2}{mac_address} = "52:54:00:16:c5:33"; -$anvil->data->{network_manager}{want}{interface}{bcn1_link2}{device} = "enp9s0"; - -$anvil->data->{network_manager}{want}{interface}{sn1_link1}{mac_address} = "52:54:00:37:6f:22"; -$anvil->data->{network_manager}{want}{interface}{sn1_link1}{device} = "enp10s0"; -$anvil->data->{network_manager}{want}{interface}{sn1_link2}{mac_address} = "52:54:00:2f:02:1b"; -$anvil->data->{network_manager}{want}{interface}{sn1_link2}{device} = "enp11s0"; - -$anvil->data->{network_manager}{want}{interface}{mn1_link1}{mac_address} = ""; -$anvil->data->{network_manager}{want}{interface}{mn1_link1}{device} = ""; -$anvil->data->{network_manager}{want}{interface}{mn1_link2}{mac_address} = ""; -$anvil->data->{network_manager}{want}{interface}{mn1_link2}{device} = ""; - -# Bonds -$anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{interfaces} = ["ifn1_link1", "ifn1_link2"]; # First interface is primary -$anvil->data->{network_manager}{want}{bond}{bcn1_bond1}{interfaces} = ["bcn1_link1", "bcn1_link2"]; -$anvil->data->{network_manager}{want}{bond}{sn1_bond1}{interfaces} = ["sn1_link1", "sn1_link2"]; -$anvil->data->{network_manager}{want}{bond}{mn1_bond1}{interfaces} = ["mn1_link1", "mn1_link2"]; - -# Bridges -$anvil->data->{network_manager}{want}{bridge}{ifn1_bridge1}{on} = "ifn1_bond1"; -$anvil->data->{network_manager}{want}{bridge}{bcn1_bridge1}{on} = "bcn1_bond1"; - -# IP addresses. -$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{ip_address} = "192.168.6.42"; -$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{subnet_mask} = "255.255.0.0"; -$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{gateway} = "192.168.255.254"; -$anvil->data->{network_manager}{want}{ip_on}{ifn1_bridge1}{dns} = "8.8.8.8,8.8.4.4"; - -$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{ip_address} = "10.201.4.42"; -$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{subnet_mask} = "255.255.0.0"; -$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{gateway} = ""; -$anvil->data->{network_manager}{want}{ip_on}{bcn1_bridge1}{dns} = ""; - -$anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{ip_address} = "10.101.4.42"; -$anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{subnet_mask} = "255.255.0.0"; -$anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{gateway} = ""; -$anvil->data->{network_manager}{want}{ip_on}{sn1_bond1}{dns} = ""; - -$anvil->data->{network_manager}{want}{ip_on}{mn1_bond1}{ip_address} = "10.199.4.42"; -$anvil->data->{network_manager}{want}{ip_on}{mn1_bond1}{subnet_mask} = "255.255.0.0"; -$anvil->data->{network_manager}{want}{ip_on}{mn1_bond1}{gateway} = ""; -$anvil->data->{network_manager}{want}{ip_on}{mn1_bond1}{dns} = ""; - -$anvil->data->{sys}{reboot_needed} = 0; -$anvil->data->{sys}{make_changes} = 1; - -collect_data($anvil); - -reconfigure($anvil); - -$anvil->nice_exit({exit_code => 0}); - - -############################################################################################################# -# Functions # -############################################################################################################# - -sub reconfigure -{ - my ($anvil) = @_; - - reconfigure_interfaces($anvil); - reconfigure_bonds($anvil); - reconfigure_bridges($anvil); - reconfigure_ip_addresses($anvil); - - return(0); -} - -sub reconfigure_ip_addresses +# Now go into the main loop +while(1) { - my ($anvil) = @_; + ### NOTE: A lot of this logic comes from scan-network + my $scan_time = time; + my $trigger = 0; - foreach my $on_device (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{ip_on}}) + # Look for interfaces. + local(*DIRECTORY); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }}); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) { - my $on_device_uuid = $anvil->data->{interface}{device}{$on_device}{uuid}; - my $ip_address = $anvil->data->{network_manager}{want}{ip_on}{$on_device}{ip_address}; - my $subnet_mask = $anvil->data->{network_manager}{want}{ip_on}{$on_device}{subnet_mask}; - my $gateway = $anvil->data->{network_manager}{want}{ip_on}{$on_device}{gateway}; - my $dns = $anvil->data->{network_manager}{want}{ip_on}{$on_device}{dns}; - my $clear_ip_from = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:on_device' => $on_device, - 's2:on_device_uuid' => $on_device_uuid, - 's3:ip_address' => $ip_address, - 's4:subnet_mask' => $subnet_mask, - 's5:gateway' => $gateway, - 's6:dns' => $dns, - }}); - if (($subnet_mask !~ /^\d+$/) or ($subnet_mask < 1) or ($subnet_mask > 32)) - { - # Convert to CIDR - my $cidr = $anvil->Convert->cidr({subnet_mask => $subnet_mask}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cidr => $cidr }}); - if (not $cidr) - { - print "[ ERROR ] - The subnet_mask: [".$subnet_mask."] is not valid. It must be either a CIDR notation, or a dotted-decimal mask that can be translated to CIDR notation.\n"; - $anvil->nice_exit({exit_code => 1}); - } - - $subnet_mask = $cidr; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subnet_mask => $subnet_mask }}); - } - - print "Checking to see if the IP address: [".$ip_address."/".$subnet_mask."] is assigned to: [".$on_device."] yet.\n"; - if (exists $anvil->data->{interface}{ipv4}{$ip_address}) + next if $file eq "."; + next if $file eq ".."; + next if $file eq "lo"; + my $full_path = $directory."/".$file; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); + if (-d $full_path) { - my $ip_uuid = $anvil->data->{interface}{ipv4}{$ip_address}{on_uuid}; - my $current_device = $anvil->data->{interface}{uuid}{$ip_uuid}{device}; - my $ip_sequence = $anvil->data->{interface}{ipv4}{$ip_address}{sequence}; - my $current_subnet_mask = $anvil->data->{interface}{uuid}{$ip_uuid}{ipv4}{ip}{$ip_sequence}{subnet_mask}; - my $current_gateway = $anvil->data->{interface}{uuid}{$ip_uuid}{ipv4}{gateway}; - my $current_dns = $anvil->data->{interface}{uuid}{$ip_uuid}{ipv4}{dns}; + # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. + my $interface = $file; + my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; + $link_state =~ s/\n$//; + my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; + $mtu =~ s/\n$//; + my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? + $duplex =~ s/\n$//; + my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down + $operational =~ s/\n$//; + my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; + $modalias =~ s/\n$//; + my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link + $speed =~ s/\n$//; + my $media = "unknown"; + my $type = "interface"; + my $driver = ""; + my $tx_bytes = 0; # How many bytes transmitted + my $rx_bytes = 0; # How many bytes received $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:ip_uuid' => $ip_uuid, - 's2:current_device' => $current_device, - 's3:ip_sequence' => $ip_sequence, - 's4:current_subnet_mask' => $current_subnet_mask, - 's5:current_gateway' => $current_gateway, - 's6:current_dns' => $current_dns, + interface => $interface, + link_state => $link_state, + mtu => $mtu, + duplex => $duplex, + operational => $operational, + speed => $speed, + modalias => $modalias, }}); - die if not $ip_uuid; - print "- The IP exists, checking if it needs to be updated.\n"; - if ($on_device ne $current_device) - { - print "- The IP address is on: [".$current_device."], will move the IP.\n"; - $clear_ip_from = $current_device; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_ip_from => $clear_ip_from }}); - } - elsif ($subnet_mask ne $current_subnet_mask) - { - print "- The current subnet mask is: [".$current_subnet_mask."], will update.\n"; - } - elsif ($gateway ne $current_gateway) - { - print "- The current gateway is: [".$current_gateway."], will update.\n"; - } - elsif ($dns ne $current_dns) - { - print "- The current DNS is: [".$current_dns."], will update.\n"; - } - else - { - print "- No update is needed.\n"; - next; - } - } - else - { - print "- The IP address needs to be assigned.\n"; - } - - if ($clear_ip_from) - { - my $old_uuid = $anvil->data->{interface}{device}{$clear_ip_from}{uuid}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_uuid => $old_uuid }}); - print " - Clearing the IP from: [".$old_uuid."] (".$clear_ip_from.")\n"; - - my ($output, $return_code) = modify_connection($anvil, $old_uuid, "ipv4.method", "disabled"); - ($output, $return_code) = modify_connection($anvil, $old_uuid, "ipv6.method", "disabled"); - ($output, $return_code) = reset_connection($anvil, $old_uuid); - } - - # Now assign the IP. - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$on_device_uuid." ipv4.method manual ipv4.addresses ".$ip_address."/".$subnet_mask; - if ($gateway) - { - $shell_call .= " ipv4.gateway ".$gateway; - } - if ($dns) - { - $shell_call .= " ipv4.dns ".$dns; - } - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Restart the interface - print " - Restarting the interface.\n"; - ($output, $return_code) = reset_connection($anvil, $on_device_uuid); - - # Rescan. - collect_data($anvil); - } - - return(0); -} - -sub reconfigure_bridges -{ - my ($anvil) = @_; - - foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{bridge}}) - { - my $on_device = $anvil->data->{network_manager}{want}{bridge}{$bridge_name}{on}; - print "Checking if the bridge: [".$bridge_name."] exists and that it is on: [".$on_device."]\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - bridge_name => $bridge_name, - on_device => $on_device, - }}); - - if (exists $anvil->data->{interface}{bridge}{$bridge_name}) - { - # The bridge exists. - print "- The bridge exists!\n"; - } - else - { - # Create the bridge. - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bridge con-name ".$bridge_name." ifname ".$bridge_name; + # Get the MAC address + my $mac_address = ""; + my $shell_call = $anvil->data->{path}{exe}{ethtool}." -P ".$interface; $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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); - - if ($return_code) + if ($output =~ /(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/) { - print "[ Error ] - The attempt to add the bridge failed! The return code was: [".$return_code."]. The output, if any, was:\n"; - print "========\n"; - print $output."\n"; - print "========\n"; - $anvil->nice_exit({exit_code => 1}); - } - - my $bridge_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); - - if ($bridge_uuid) - { - print " - Disabling DHCP on the new bridge device: [".$bridge_uuid."].\n"; - my ($output, $return_code) = modify_connection($anvil, $bridge_uuid, "ipv4.method", "disabled"); - ($output, $return_code) = modify_connection($anvil, $bridge_uuid, "ipv6.method", "disabled"); - - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bridge_name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - } - - # Rescan. - print " - Done! Rescanning the network config.\n"; - collect_data($anvil); - } - - print "- Checking that the device: [".$on_device."] is connected to this bridge.\n"; - my $bridge_uuid = $anvil->data->{interface}{bridge}{$bridge_name}{uuid}; - my $on_device_uuid = $anvil->data->{interface}{device}{$on_device}{uuid} // ""; - my $on_device_parent = $anvil->data->{interface}{uuid}{$on_device_uuid}{'connection.master'} // ""; - my $on_device_child_type = $anvil->data->{interface}{uuid}{$on_device_uuid}{'connection.slave-type'} // ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - bridge_uuid => $bridge_uuid, - on_device_uuid => $on_device_uuid, - on_device_parent => $on_device_parent, - on_device_child_type => $on_device_child_type, - }}); - - if ($on_device_parent) - { - if ($on_device_parent eq $bridge_name) - { - print "- The device is connected to the bridge already.\n"; - next; + $mac_address = lc($1); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); } else { - print "- The device is on the bridge: [".$on_device_parent."], moving it.\n"; - } - } - else - { - print "- The device is not on this bridge, connecting it.\n"; - } - - print " - Disabling DHCP on the device: [".$on_device."] (".$on_device_uuid.") before connecting it.\n"; - my ($output, $return_code) = modify_connection($anvil, $on_device_uuid, "ipv4.method", "disabled"); - ($output, $return_code) = modify_connection($anvil, $on_device_uuid, "ipv6.method", "disabled"); - - print " - Connecting it now.\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$on_device_uuid." master ".$bridge_name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - if ($return_code) - { - print "[ Error ] - The attempt to add the bridge failed! The return code was: [".$return_code."]. The output, if any, was:\n"; - print "========\n"; - print $output."\n"; - print "========\n"; - $anvil->nice_exit({exit_code => 1}); - } - - print " - Done! Rescanning the network config.\n"; - ($output, $return_code) = reset_connection($anvil, $on_device_uuid); - - # Rescan. - collect_data($anvil); - } - - return(0); -} - -sub reconfigure_bonds -{ - my ($anvil) = @_; - - # $anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{interfaces} = ["ifn1_link1", "ifn1_link2"]; # First interface is primary - # $anvil->data->{network_manager}{want}{bond}{ifn1_bond1}{ipv4_method} = "disabled"; - foreach my $bond_name (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{bond}}) - { - print "Checking if the bond: [".$bond_name."] exists or not.\n"; - if (exists $anvil->data->{interface}{bond}{$bond_name}) - { - print "- It does, its UUID is: [".$anvil->data->{interface}{bond}{$bond_name}{uuid}."]\n"; - } - else - { - my $primary_interface = $anvil->data->{network_manager}{want}{bond}{$bond_name}{interfaces}->[0]; - if (not $primary_interface) - { - print "[ Error ] - There appears to be no primary interface specified for this bond!\n"; - $anvil->nice_exit({exit_code => 1}); + # Get it by reading the address file. + if (-e $full_path."/bonding_slave/perm_hwaddr") + { + $mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } + elsif (-e $full_path."/address") + { + $mac_address = $anvil->Storage->read_file({file => $full_path."/address"}); + $mac_address =~ s/\n//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + } } - print "- It does not, creating it with the primary interface: [".$primary_interface."] now.\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bond con-name ".$bond_name." ifname ".$bond_name." bond.options \"mode=active-backup,miimon=100,downdelay=0,updelay=120000,primary=".$primary_interface."\""; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - if ($return_code) - { - print "[ Error ] - The attempt to add the bond failed! The return code was: [".$return_code."]. The output, if any, was:\n"; - print "========\n"; - print $output."\n"; - print "========\n"; - $anvil->nice_exit({exit_code => 1}); - } + # These are variables that will be needed if this is a bond interface. + my $ip_address = ""; + my $subnet_mask = ""; + my $bond_mode = ""; + my $primary_interface = ""; + my $primary_reselect = ""; + my $active_interface = ""; + my $mii_polling_interval = ""; + my $up_delay = ""; + my $down_delay = ""; + my $bond_parent = ""; - my $bond_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); + # These are variables that will be needed if this is a bridge interface + my $bridge_id = ""; + my $bridge_stp_enabled = ""; - if ($bond_uuid) + # If this interface is already a bond slave, the real mac address will be in a + # sub-directory. + my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr"; + if (-e $mac_bond_file) { - print " - Disabling DHCP on the new bond device: [".$bond_uuid."].\n"; - my ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv4.method", "disabled"); - ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv6.method", "disabled"); - - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bond_name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + # It's a slave. + $mac_address = $anvil->Storage->read_file({file => $mac_bond_file}); + $mac_address =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); } - # Rescan. - print " - Done! Rescanning the network config.\n"; - collect_data($anvil); - } - - # Now add the interfaces, disabling their ipv4.method first. - foreach my $interface_name (@{$anvil->data->{network_manager}{want}{bond}{$bond_name}{interfaces}}) - { - # What is the interface UUID? - my $interface_uuid = $anvil->data->{interface}{device}{$interface_name}{uuid}; - my $parent_bond_name = $anvil->data->{interface}{uuid}{$interface_uuid}{'connection.master'}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface_name => $interface_name, - interface_uuid => $interface_uuid, - parent_bond_name => $parent_bond_name, - }}); - if ($parent_bond_name eq "--") + # Pick out our driver. + if ($modalias =~ /^virtio:/) { - $parent_bond_name = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { parent_bond_name => $parent_bond_name }}); + $driver = "virtio"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver => $driver }}); } - if ($parent_bond_name) + # If this is a virtual interface, set some fake values that don't actually exist on + # the system for the sake of a cleaner display. + if (($mac_address =~ /^52:54:00/) or ($driver eq "virtio")) { - if ($parent_bond_name eq $bond_name) + ### Set some fake values. + # Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary. + if ((not $speed) or ($speed eq "-1")) { - print "- The interface: [".$interface_name."] (".$interface_uuid.") is already a member of the bond.\n"; - next; + $speed = 10000; } - else + if ((not $duplex) or ($duplex eq "unknown")) { - print "- The interface: [".$interface_name."] (".$interface_uuid.") is a member of the bond: [".$parent_bond_name."], switching it to this bond.\n"; + $duplex = "full"; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + speed => $speed, + duplex => $duplex, + }}); } - else + # If the state is 'down', set the speed to '0'. + if (not $link_state) { - print "- The interface: [".$interface_name."] (".$interface_uuid.") needs to be connected to the bond.\n"; + $speed = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); } - print " - Disabling DHCP on the interface\n"; - my ($output, $return_code) = modify_connection($anvil, $interface_uuid, "ipv4.method", "disabled"); - ($output, $return_code) = modify_connection($anvil, $interface_uuid, "ipv6.method", "disabled"); - - print " - Connecting the interface to the bond.\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$interface_uuid." connection.master ".$bond_name." connection.slave-type bond"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - if ($return_code) + # Is this a bond interface? + if (-e "/proc/net/bonding/".$interface) { - print "[ Error ] - The attempt to add the bond failed! The return code was: [".$return_code."]. The output, if any, was:\n"; - print "========\n"; - print $output."\n"; - print "========\n"; - $anvil->nice_exit({exit_code => 1}); + # Yup, we'll neet to dig into the bond proc files to get the proper slaved + # interface MAC addresses. + $type = "bond"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); + + # Read the bond mode. + $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); + $bond_mode =~ s/\s.*//; + $bond_mode =~ s/\n$//; + $primary_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"}); + $primary_interface =~ s/\n$//; + $primary_reselect = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"}); + $primary_reselect =~ s/\s.*//; + $primary_reselect =~ s/\n$//; + $active_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"}); + $active_interface =~ s/\n$//; + $mii_polling_interval = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"}); + $mii_polling_interval =~ s/\n$//; + $up_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"}); + $up_delay =~ s/\n$//; + $down_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"}); + $down_delay =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + active_interface => $active_interface, + bond_mode => $bond_mode, + mii_polling_interval => $mii_polling_interval, + primary_reselect => $primary_reselect, + primary_interface => $primary_interface, + type => $type, + }}); } - - # Rescan. - print " - Done! Rescanning the network config.\n"; - ($output, $return_code) = reset_connection($anvil, $interface_uuid); - - # Rescan. - collect_data($anvil); - } - } - - return(0); -} - -sub collect_data -{ - my ($anvil) = @_; - - my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type,active,state connection show"; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - foreach my $line (split/\n/, $output) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /^(.*?):(.*?):(.*?):(.*?)$/) - { - my $uuid = $1; - my $type = $2; - my $active = $3; - my $state = $4; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - uuid => $uuid, - type => $type, - active => $active, - 'state' => $state, - }}); - next if $type eq "loopback"; - - $anvil->data->{interface}{uuid}{$uuid}{type} = $type; - $anvil->data->{interface}{uuid}{$uuid}{active} = lc($active) eq "yes" ? 1 : 0; - $anvil->data->{interface}{uuid}{$uuid}{'state'} = lc($state); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::type" => $anvil->data->{interface}{uuid}{$uuid}{type}, - "interface::uuid::${uuid}::active" => $anvil->data->{interface}{uuid}{$uuid}{active}, - "interface::uuid::${uuid}::state" => $anvil->data->{interface}{uuid}{$uuid}{'state'}, - }}); - } - } - - foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{interface}{uuid}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); - - # Collect all the rest of the data now. - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection show ".$uuid; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - output => $output, - return_code => $return_code, - }}); - foreach my $line (split/\n/, $output) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /^(.*?):\s+(.*)$/) + elsif ((-e $full_path."/master") && ($interface !~ /^vnet/)) { - my $variable = $1; - my $value = $2; + # We're in a bond. + my $target = readlink($full_path."/master"); + $bond_parent = ($target =~ /^.*\/(.*)$/)[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:variable' => $variable, - 's2:value' => $value, + target => $target, + bond_parent => $bond_parent, }}); - - $anvil->data->{interface}{uuid}{$uuid}{$variable} = $value; + } + elsif (-d $full_path."/bridge") + { + # It's a bridge + $type = "bridge"; + $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); + $bridge_id =~ s/\n$//; + $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); + $bridge_stp_enabled =~ s/\n$//; + $speed = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${variable}" => $anvil->data->{interface}{uuid}{$uuid}{$variable}, + type => $type, + bridge_id => $bridge_id, + bridge_stp_enabled => $bridge_stp_enabled, }}); - - if ($variable =~ /IP(\d).ADDRESS\[(\d+)\]/) + if ($bridge_stp_enabled eq "0") { - my $ip_type = $1; - my $sequence = $2; - my $hash_key = "ipv".$ip_type; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_type => $ip_type, - sequence => $sequence, - hash_key => $hash_key, - }}); - - if (($ip_type == 4) && ($value =~ /^(.*?)\/(.*)$/)) - { - my $ip_address = $1; - my $subnet_mask = $2; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_address => $ip_address, - subnet_mask => $subnet_mask, - }}); - - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $1; - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = $2; - $anvil->data->{interface}{ipv4}{$ip_address}{on_uuid} = $uuid; - $anvil->data->{interface}{ipv4}{$ip_address}{sequence} = $sequence; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, - "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, - "interface::ipv4::${ip_address}::on_uuid" => $anvil->data->{interface}{ipv4}{$ip_address}{on_uuid}, - "interface::ipv4::${ip_address}::sequence" => $anvil->data->{interface}{ipv4}{$ip_address}{sequence}, - }}); - } - else - { - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address} = $value; - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask} = ""; - $anvil->data->{interface}{ipv4}{$value}{on_uuid} = $value; - $anvil->data->{interface}{ipv4}{$value}{sequence} = $sequence; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::ip_address" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{ip_address}, - "interface::uuid::${uuid}::${hash_key}::ip::${sequence}::subnet_mask" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{ip}{$sequence}{subnet_mask}, - "interface::ipv4::${value}::on_uuid" => $anvil->data->{interface}{ipv4}{$value}{on_uuid}, - "interface::ipv4::${value}::sequence" => $anvil->data->{interface}{ipv4}{$value}{sequence}, - }}); - - } - - # Make sure the DNS key exists. - if (not exists $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns}) - { - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns}, - }}); - } - if (not exists $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway}) - { - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway} = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway}, - }}); - } - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway} = $value; - } - if ($variable =~ /IP(\d).ROUTE\[(\d+)\]/) - { - my $ip_type = $1; - my $sequence = $2; - my $hash_key = "ipv".$ip_type; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_type => $ip_type, - sequence => $sequence, - hash_key => $hash_key, - }}); - - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{route}{$sequence} = $value; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::route::${sequence}" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{route}{$sequence}, - }}); + $bridge_stp_enabled = "disabled"; } - if ($variable =~ /IP(\d).DNS\[(\d+)\]/) + elsif ($bridge_stp_enabled eq "1") { - my $ip_type = $1; - my $sequence = $2; - my $hash_key = "ipv".$ip_type; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_type => $ip_type, - sequence => $sequence, - hash_key => $hash_key, - }}); - - if ((exists $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns}) and ($anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} ne "")) - { - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} .= ",".$value; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{interface}{uuid}{$uuid}{$sequence}{dns}, - }}); - } - else - { - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns} = $value; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{dns}, - }}); - } + $bridge_stp_enabled = "enabled_kernel"; } - if ($variable =~ /IP(\d).GATEWAY/) + elsif ($bridge_stp_enabled eq "2") { - my $ip_type = $1; - my $hash_key = "ipv".$ip_type; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_type => $ip_type, - hash_key => $hash_key, - }}); - - $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway} = $value; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::${hash_key}::gateway" => $anvil->data->{interface}{uuid}{$uuid}{$hash_key}{gateway}, - }}); + $bridge_stp_enabled = "enabled_userland"; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_stp_enabled => $bridge_stp_enabled }}); } - } - } - - # Now loop through and look for the name that maps to what's shown in 'ip addr list'. This can be a bit tricky. - foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{interface}{uuid}}) - { - my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} // ""; - my $general_devices = $anvil->data->{interface}{uuid}{$uuid}{'GENERAL.DEVICES'} // ""; - my $device_type = $anvil->data->{interface}{uuid}{$uuid}{'connection.type'} // ""; - my $device = $connection_interface_name ne "--" ? $connection_interface_name : $general_devices; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:uuid' => $uuid, - 's2:connection_interface_name' => $connection_interface_name, - 's3:general_devices' => $general_devices, - 's4:device_type' => $device_type, - 's5:device' => $device, - }}); - - if ($device) - { - $anvil->data->{interface}{device}{$device}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::device::${device}::uuid" => $anvil->data->{interface}{device}{$device}{uuid}, - }}); - - ### Get some data from sysfs. - $anvil->data->{interface}{uuid}{$uuid}{device} = $device; - $anvil->data->{interface}{uuid}{$uuid}{mac_address} = ""; - $anvil->data->{interface}{uuid}{$uuid}{type} = ""; - $anvil->data->{interface}{uuid}{$uuid}{mtu} = 0; - - # The 'connection.timestamp' seems to be where the 'connected' (as in, have an IP) - # comes from. - $anvil->data->{interface}{uuid}{$uuid}{connected} = $anvil->data->{interface}{uuid}{$uuid}{'connection.timestamp'} ? $anvil->data->{interface}{uuid}{$uuid}{'connection.timestamp'} : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::connected" => $anvil->data->{interface}{uuid}{$uuid}{connected}, - }}); - if ($device_type eq "bond") - { - $anvil->data->{interface}{bond}{$device}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::bond::${device}::uuid" => $anvil->data->{interface}{bond}{$device}{uuid}, - }}); - } - elsif ($device_type eq "bridge") + # If this is a 'vnet' device, set 'operational' to up + if ($interface =~ /^vnet/) { - $anvil->data->{interface}{bridge}{$device}{uuid} = $uuid; + ### TODO: We can't assume this, we need to detect virsh net up/down + $operational = "up"; + $media = "virtual"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::bridge::${device}::uuid" => $anvil->data->{interface}{bridge}{$device}{uuid}, + operational => $operational, + media => $media, }}); } - elsif ($device_type eq "802-3-ethernet") + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + active_interface => $active_interface, + bond_parent => $bond_parent, + bond_mode => $bond_mode, + bridge_id => $bridge_id, + bridge_stp_enabled => $bridge_stp_enabled, + down_delay => $down_delay, + duplex => $duplex, + interface => $interface, + mac_address => $mac_address, + mii_polling_interval => $mii_polling_interval, + mtu => $mtu, + operational => $operational, + primary_reselect => $primary_reselect, + primary_interface => $primary_interface, + speed => $speed, + subnet_mask => $subnet_mask, + type => $type, + up_delay => $up_delay, + }}); + + # Find the media, if possible. + (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." ".$interface}); + foreach my $line (split/\n/, $ethtool) { - $anvil->data->{interface}{phy}{$device}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::phy::${device}::uuid" => $anvil->data->{interface}{phy}{$device}{uuid}, - }}); - - # MAC address - my $mac_address_file = "/sys/class/net/".$device."/address"; - my $type_file = "/sys/class/net/".$device."/type"; - my $mtu_file = "/sys/class/net/".$device."/mtu"; - if (-e $mac_address_file) + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /Supported ports: \[ (.*?) \]/i) { - my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); - $mac_address =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); + $media = lc($1); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); - if (($mac_address) && ($mac_address ne "!!error!!")) + # This can be 'tp mii', which breaks json. + if ($media =~ /\t/) { - $anvil->data->{interface}{uuid}{$uuid}{mac_address} = $mac_address; - $anvil->data->{interface}{mac_address}{$mac_address}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::mac_address" => $anvil->data->{interface}{uuid}{$uuid}{mac_address}, - "interface::mac_address::${mac_address}::uuid" => $anvil->data->{interface}{mac_address}{$mac_address}{uuid}, - }}); - } - } - if (-e $type_file) - { - my $type = $anvil->Storage->read_file({file => $type_file}); - $type =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); - - if (($type) && ($type ne "!!error!!")) - { - $anvil->data->{interface}{uuid}{$uuid}{type} = $type; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::type" => $anvil->data->{interface}{uuid}{$uuid}{type}, - }}); - } - } - if (-e $mtu_file) - { - my $mtu = $anvil->Storage->read_file({file => $mtu_file}); - $mtu =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mtu => $mtu }}); - - if (($mtu) && ($mtu ne "!!error!!")) - { - $anvil->data->{interface}{uuid}{$uuid}{mtu} = $mtu; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::uuid::${uuid}::mtu" => $anvil->data->{interface}{uuid}{$uuid}{mtu}, - }}); + $media =~ s/\t/,/g; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); } + last; } } - } - } - - # Now lets confirm we got all the interfaces, including the down'ed ones. - foreach my $device (sort {$a cmp $b} keys %{$anvil->data->{interface}{device}}) - { - my $uuid = $anvil->data->{interface}{device}{$device}{uuid}; - my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; - my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; - my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; - my $mtu_type = $anvil->data->{interface}{uuid}{$uuid}{'802-3-ethernet.mtu'} // ""; - my $mtu = $anvil->data->{interface}{uuid}{$uuid}{mtu}; - my $active = $anvil->data->{interface}{uuid}{$uuid}{active}; - my $state = $anvil->data->{interface}{uuid}{$uuid}{'state'}; - my $connected = $anvil->data->{interface}{uuid}{$uuid}{connected}; - my $ipv4_dns = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{dns} // "--"; - my $ipv4_gateway = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{gateway} // "--"; - my $ip_count = keys %{$anvil->data->{interface}{uuid}{$uuid}{ipv4}{ip}}; - my $route_count = keys %{$anvil->data->{interface}{uuid}{$uuid}{ipv4}{route}}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "s01:device" => $device, - "s02:uuid" => $uuid, - "s03:name" => $name, - "s04:mac_address" => $mac_address, - "s05:type" => $type, - "s06:mtu_type" => $mtu_type, - "s07:active" => $active, - "s08:state" => $state, - "s09:connected" => $connected, - "s10:ipv4_dns" => $ipv4_dns, - "s11:ipv4_gateway" => $ipv4_gateway, - "s12:ip_count" => $ip_count, - "s13:route_count" => $route_count, - }}); - - if (exists $anvil->data->{network_manager}{want}{interface}{$device}) - { - # We know this device. Does it match the expected MAC address? - my $wanted_mac_address = $anvil->data->{network_manager}{want}{interface}{ifn1_link1}{mac_address}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { wanted_mac_address => $wanted_mac_address }}); - if (lc($wanted_mac_address) eq lc($mac_address)) + + # Trigger? + if (not exists $anvil->data->{last_scan}{$interface}) { - #print " - Interface is configured as desired.\n"; + print "The interface: [".$interface."] has been found. We will now monitor it for changes.\n"; + $trigger = 1; } else { - #print " - The MAC address doesn't match the desired MAC address!\n"; - } - } - else - { - #print " - This interface isn't one of the matched ones. Check if this should be reconfigured.\n"; - my $reconfigure_to = ""; - foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{want}{interface}}) - { - my $wanted_device = $anvil->data->{network_manager}{want}{interface}{$wanted_interface}{device}; - my $wanted_mac_address = $anvil->data->{network_manager}{want}{interface}{$wanted_interface}{mac_address}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - wanted_interface => $wanted_interface, - wanted_device => $wanted_device, - wanted_mac_address => $wanted_mac_address, - }}); - - # If this device already exists, skip it. - if (exists $anvil->data->{interface}{device}{$wanted_interface}) + # Now look for differences. + if ($anvil->data->{last_scan}{$interface}{active_interface} ne $active_interface) { - next; + print "The ".$type.": [".$interface."] has a different active interface: [".$anvil->data->{last_scan}{$interface}{active_interface}."] -> [".$active_interface."].\n"; + $trigger = 1; } - - if ($mac_address eq $wanted_mac_address) + if ($anvil->data->{last_scan}{$interface}{bond_mode} ne $bond_mode) { - # MAC address always takes priority. - $reconfigure_to = $wanted_interface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reconfigure_to => $reconfigure_to }}); - next; + print "The ".$type.": [".$interface."] mode has changed from: [".$anvil->data->{last_scan}{$interface}{bond_mode}."] -> [".$bond_mode."].\n"; + $trigger = 1; } - elsif ((not $reconfigure_to) && ($wanted_device eq $name)) + if ($anvil->data->{last_scan}{$interface}{bond_parent} ne $bond_parent) { - $reconfigure_to = $wanted_interface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reconfigure_to => $reconfigure_to }}); - next; + print "The ".$type.": [".$interface."] bond parent has changed from: [".$anvil->data->{last_scan}{$interface}{bond_parent}."] -> [".$bond_parent."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{bridge_id} ne $bridge_id) + { + print "The ".$type.": [".$interface."] bridge ID has changed from: [".$anvil->data->{last_scan}{$interface}{bridge_id}."] -> [".$bridge_id."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{bridge_stp_enabled} ne $bridge_stp_enabled) + { + print "The ".$type.": [".$interface."] spanning tree protocol (STP) setting has changed from: [".$anvil->data->{last_scan}{$interface}{bridge_stp_enabled}."] -> [".$bridge_stp_enabled."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{down_delay} ne $down_delay) + { + print "The ".$type.": [".$interface."] down delay has changed from: [".$anvil->data->{last_scan}{$interface}{bridge_stp_enabled}."ms] -> [".$bridge_stp_enabled."ms].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{up_delay} ne $up_delay) + { + print "The ".$type.": [".$interface."] up delay has changed from: [".$anvil->data->{last_scan}{$interface}{up_delay}."ms] -> [".$up_delay."ms].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{duplex} ne $duplex) + { + print "The ".$type.": [".$interface."] duplex has changed from: [".$anvil->data->{last_scan}{$interface}{duplex}."] -> [".$duplex."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{ip_address} ne $ip_address) + { + print "The ".$type.": [".$interface."] ip address has changed from: [".$anvil->data->{last_scan}{$interface}{ip_address}."] -> [".$ip_address."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{subnet_mask} ne $subnet_mask) + { + print "The ".$type.": [".$interface."] subnet_mask has changed from: [".$anvil->data->{last_scan}{$interface}{subnet_mask}."] -> [".$subnet_mask."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{link_state} ne $link_state) + { + print "The ".$type.": [".$interface."] link status has changed from: [".$anvil->data->{last_scan}{$interface}{link_state}."] -> [".$link_state."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{mac_address} ne $mac_address) + { + print "The ".$type.": [".$interface."] MAC address has changed from: [".$anvil->data->{last_scan}{$interface}{mac_address}."] -> [".$mac_address."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{media} ne $media) + { + print "The ".$type.": [".$interface."] media has changed from: [".$anvil->data->{last_scan}{$interface}{media}."] -> [".$media."]. (Excuse me, how?!)\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{mii_polling_interval} ne $mii_polling_interval) + { + print "The ".$type.": [".$interface."] media independent interface (mii) polling interval has changed from: [".$anvil->data->{last_scan}{$interface}{mii_polling_interval}."ms] -> [".$mii_polling_interval."ms].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{mtu} ne $mtu) + { + print "The ".$type.": [".$interface."] maximum transmission unit (mtu) has changed from: [".$anvil->data->{last_scan}{$interface}{mtu}." bytes] -> [".$mtu." bytes].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{operational} ne $operational) + { + print "The ".$type.": [".$interface."] operational status has changed from: [".$anvil->data->{last_scan}{$interface}{operational}."] -> [".$operational."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{primary_reselect} ne $primary_reselect) + { + print "The ".$type.": [".$interface."] primary reselect policy has changed from: [".$anvil->data->{last_scan}{$interface}{primary_reselect}."] -> [".$primary_reselect."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{primary_interface} ne $primary_interface) + { + print "The ".$type.": [".$interface."] primary interface has changed from: [".$anvil->data->{last_scan}{$interface}{primary_interface}."] -> [".$primary_interface."].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{speed} ne $speed) + { + print "The ".$type.": [".$interface."] speed has changed from: [".$anvil->data->{last_scan}{$interface}{speed}." Mbps] -> [".$speed." Mbps].\n"; + $trigger = 1; + } + if ($anvil->data->{last_scan}{$interface}{type} ne $type) + { + print "The device: [".$interface."] type has changed from: [".$anvil->data->{last_scan}{$interface}{type}."] -> [".$type."].\n"; + $trigger = 1; } - } - if ($reconfigure_to) - { - # Reconfigure! - #print " - This should be: [".$reconfigure_to."]\n"; - $anvil->data->{network_manager}{reconfigure}{$reconfigure_to}{from_uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "network_manager::reconfigure::${reconfigure_to}::from_uuid" => $anvil->data->{network_manager}{reconfigure}{$reconfigure_to}{from_uuid}, - }}); - } - } - - #print "- Device: [".$device."], UUID: [".$uuid."], name: [".$name."], state: [".$active."], active?: [".$active."], state: [".$state."], connected: [".$connected."]\n"; - #print " - MAC: [".$mac_address."], Type: [".$type."], MTU: [".$mtu."] MTU type: [".$mtu_type."], IPv4 DNS: [".$ipv4_dns."], Gateway: [".$ipv4_gateway."], IPs: [".$ip_count."], routes: [".$route_count."]\n"; - if ($ip_count) - { - foreach my $sequence (sort {$a <=> $b} keys %{$anvil->data->{interface}{uuid}{$uuid}{ipv4}{ip}}) - { - my $ip_address = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{ip}{$sequence}{ip_address}; - my $subnet_mask = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{ip}{$sequence}{subnet_mask}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "s1:sequence" => $sequence, - "s2:ip_address" => $ip_address, - "s3:subnet_mask" => $subnet_mask, - }}); - #print " - ".$sequence.": IPv4 IP: [".$ip_address."], subnet mask: [".$subnet_mask."]\n"; - } - } - if ($route_count) - { - foreach my $sequence (sort {$a <=> $b} keys %{$anvil->data->{interface}{uuid}{$uuid}{ipv4}{route}}) - { - my $route = $anvil->data->{interface}{uuid}{$uuid}{ipv4}{route}{$sequence}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "s1:sequence" => $sequence, - "s2:route" => $route, - }}); - #print " - ".$sequence.": Route: [".$route."]\n"; - } - } - #print "--------\n"; - } - - return(0); -} - -sub reconfigure_interfaces -{ - my ($anvil) = @_; - - my $reconfigure_count = keys %{$anvil->data->{network_manager}{reconfigure}}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { reconfigure_count => $reconfigure_count }}); - if (not $reconfigure_count) - { - return(0); - } - - foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{reconfigure}}) - { - my $uuid = $anvil->data->{network_manager}{reconfigure}{$wanted_interface}{from_uuid}; - my $old_device = $anvil->data->{interface}{uuid}{$uuid}{device}; - my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; - my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; - my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:wanted_interface' => $wanted_interface, - 's2:uuid' => $uuid, - 's3:old_device' => $old_device, - 's4:name' => $name, - 's5:mac_address' => $mac_address, - 's6:type' => $type, - }}); - - print "Renaming old device/name: [".$old_device."/".$name."] with MAC: [".$mac_address."] to: [".$wanted_interface."] using UUID: [".$uuid."]\n"; - - # Read persistent-net and see if it needs to be updated. - my $new_persistent_net = ""; - my $old_persistent_net = ""; - if (-e $anvil->data->{path}{configs}{'persistent-net'}) - { - $old_persistent_net = $anvil->Storage->read_file({debug => 2, file => $anvil->data->{path}{configs}{'persistent-net'}}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_persistent_net => $old_persistent_net }}); - } - foreach my $line (split/\n/, $old_persistent_net) - { - # If this MAC or device name exists already, delete the line. - if (($line =~ /"$mac_address"/) or ($line =~ /"$wanted_interface"/)) - { - next; - } - $new_persistent_net .= $line."\n"; - } - $new_persistent_net .= "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"".$mac_address."\",ATTR{type}==\"".$type."\",NAME=\"".$wanted_interface."\"\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_persistent_net => $new_persistent_net }}); - - my $difference = diff \$old_persistent_net, \$new_persistent_net, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - - # Write the new file. - if ($difference) - { - print "- Updating the udev file: [".$anvil->data->{path}{configs}{'persistent-net'}."]\n"; - my $problem = $anvil->Storage->write_file({ - file => $anvil->data->{path}{configs}{'persistent-net'}, - body => $new_persistent_net, - overwrite => 1, - user => "admin", - group => "admin", - mode => "0644", - - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); - if ($problem) - { - print "[ Error ] - Failed to write the new: [".$anvil->data->{path}{configs}{'persistent-net'}."] file, aborting!\n"; - $anvil->nice_exit({exit_code => 1}); - } - } - - # Update the connection.interface-name - my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); - if ($connection_interface_name) - { - print "- Removing the old 'connection.interface-name': [".$connection_interface_name."]\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.interface-name \"\""; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.interface-name connection show ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - if ($output) - { - # This should have been blank - print "[ Error ] - Failed to delete the 'connection.interface-name', got: [".$output."] and it should bhave been blank, aborting!\n"; - $anvil->nice_exit({exit_code => 1}); - } - } - - # We'll log what it was, and change it anyway - my $match_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); - if (1) - { - print "- Matching the new interface name: [".$wanted_interface."] to the bios device name: [".$old_device."]\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." match.interface-name \"".$wanted_interface." ".$old_device."\""; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Read it back - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - if (($output ne $wanted_interface.",".$old_device) && ($output ne $old_device.",".$wanted_interface)) - { - # This should have been blank - print "[ Error ] - Failed to create the 'match.interface-name' value. Expected: [".$wanted_interface.",".$old_device."], got: [".$output."], aborting!\n"; - $anvil->nice_exit({exit_code => 1}); } - # Set the connection.id to the old name. - print "- Setting the connection.id to the bios device name: [".$old_device."]\n"; - $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.id \"".$old_device."\""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + # We'll use this to determine when an interface has disappeared. + $anvil->data->{last_scan}{$interface}{seen} = $scan_time; - # Read it back - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + # Store new information we found. + $anvil->data->{last_scan}{$interface}{active_interface} = $active_interface; + $anvil->data->{last_scan}{$interface}{bond_mode} = $bond_mode; + $anvil->data->{last_scan}{$interface}{bond_parent} = $bond_parent; + $anvil->data->{last_scan}{$interface}{bridge_id} = $bridge_id; + $anvil->data->{last_scan}{$interface}{bridge_stp_enabled} = $bridge_stp_enabled; + $anvil->data->{last_scan}{$interface}{down_delay} = $down_delay; + $anvil->data->{last_scan}{$interface}{duplex} = $duplex; + $anvil->data->{last_scan}{$interface}{ip_address} = $ip_address; + $anvil->data->{last_scan}{$interface}{link_state} = $link_state; + $anvil->data->{last_scan}{$interface}{mac_address} = $mac_address; + $anvil->data->{last_scan}{$interface}{media} = $media; + $anvil->data->{last_scan}{$interface}{mii_polling_interval} = $mii_polling_interval; + $anvil->data->{last_scan}{$interface}{mtu} = $mtu; + $anvil->data->{last_scan}{$interface}{operational} = $operational; + $anvil->data->{last_scan}{$interface}{primary_reselect} = $primary_reselect; + $anvil->data->{last_scan}{$interface}{primary_interface} = $primary_interface; + $anvil->data->{last_scan}{$interface}{speed} = $speed; + $anvil->data->{last_scan}{$interface}{subnet_mask} = $subnet_mask; + $anvil->data->{last_scan}{$interface}{type} = $type; + $anvil->data->{last_scan}{$interface}{up_delay} = $up_delay; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, + "last_scan::${interface}::seen" => $anvil->data->{last_scan}{$interface}{seen}, + "last_scan::${interface}::active_interface" => $anvil->data->{last_scan}{$interface}{active_interface}, + "last_scan::${interface}::bond_mode" => $anvil->data->{last_scan}{$interface}{bond_mode}, + "last_scan::${interface}::bond_parent" => $anvil->data->{last_scan}{$interface}{bond_parent}, + "last_scan::${interface}::bridge_id" => $anvil->data->{last_scan}{$interface}{bridge_id}, + "last_scan::${interface}::bridge_stp_enabled" => $anvil->data->{last_scan}{$interface}{bridge_stp_enabled}, + "last_scan::${interface}::down_delay" => $anvil->data->{last_scan}{$interface}{down_delay}, + "last_scan::${interface}::duplex" => $anvil->data->{last_scan}{$interface}{duplex}, + "last_scan::${interface}::ip_address" => $anvil->data->{last_scan}{$interface}{ip_address}, + "last_scan::${interface}::link_state" => $anvil->data->{last_scan}{$interface}{link_state}, + "last_scan::${interface}::mac_address" => $anvil->data->{last_scan}{$interface}{mac_address}, + "last_scan::${interface}::media" => $anvil->data->{last_scan}{$interface}{media}, + "last_scan::${interface}::mii_polling_interval" => $anvil->data->{last_scan}{$interface}{mii_polling_interval}, + "last_scan::${interface}::mtu" => $anvil->data->{last_scan}{$interface}{mtu}, + "last_scan::${interface}::operational" => $anvil->data->{last_scan}{$interface}{operational}, + "last_scan::${interface}::primary_reselect" => $anvil->data->{last_scan}{$interface}{primary_reselect}, + "last_scan::${interface}::primary_interface" => $anvil->data->{last_scan}{$interface}{primary_interface}, + "last_scan::${interface}::speed" => $anvil->data->{last_scan}{$interface}{speed}, + "last_scan::${interface}::subnet_mask" => $anvil->data->{last_scan}{$interface}{subnet_mask}, + "last_scan::${interface}::type" => $anvil->data->{last_scan}{$interface}{type}, + "last_scan::${interface}::up_delay" => $anvil->data->{last_scan}{$interface}{up_delay}, }}); } + } + closedir(DIRECTORY); + + # Now look for interfaces that disappeared. + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{last_scan}}) + { + next if $anvil->data->{last_scan}{$interface}{seen} == $scan_time; + print "The device: [".$interface."] appears to have disappeared!\n"; + delete $anvil->data->{last_scan}{$interface}; - # Set the reboot flag. - $anvil->data->{sys}{reboot_needed} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); + $trigger = 1; } - if ($anvil->data->{sys}{reboot_needed}) + # Trigger? + if ($trigger) { - print "Reboot needed.\n"; - print "- Regenerating dracute initrd image, this can take a moment...\n"; - my $shell_call = $anvil->data->{path}{exe}{dracut}." --force"; + my $shell_call = $anvil->data->{path}{directories}{scan_agents}."/scan-network/scan-network".$anvil->Log->switches; + print "Triggering the call to run: [".$shell_call."]\n"; $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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, + output => $output, return_code => $return_code, }}); - print "- New initrd image created.\n"; - print "[ Note ] - Reboot needed. Re-run this after the reboot to complete setup.\n"; - print "- Rebooting in 60 seconds (press 'ctrl + c' to abort).\n"; - my $timeout = 60; - while($timeout) + } + + if (time > $next_md5sum_check) + { + $next_md5sum_check = time + 30; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { next_md5sum_check => $next_md5sum_check }}); + if ($anvil->Storage->check_md5sums) { - if ($timeout % 10) - { - print "." - } - else - { - print $timeout; - } - sleep 1; - $timeout--; + # NOTE: We exit with '0' to prevent systemctl from showing a scary red message. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "message_0014"}); + $anvil->nice_exit({exit_code => 0}); } - print "0\n"; - print "Rebooting NOW!\n"; - - $shell_call = $anvil->data->{path}{exe}{systemctl}." reboot"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($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 }}); } - return(0); -} - -sub modify_connection -{ - my ($anvil, $uuid, $variable, $value) = @_; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - uuid => $uuid, - variable => $variable, - value => $value, - }}); - - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." ".$variable." ".$value; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - return($output, $return_code); -} - -sub reset_connection -{ - my ($anvil, $uuid) = @_; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); - - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$uuid; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - return($output, $return_code); + sleep 2; } diff --git a/tools/anvil-update-states b/tools/anvil-update-states deleted file mode 100755 index e9df6781..00000000 --- a/tools/anvil-update-states +++ /dev/null @@ -1,1161 +0,0 @@ -#!/usr/bin/perl -# -# This updates things like the current network configuration, shared file data and writes it out to a json file. -# -# TODO: -# - Retire this once scan-network is finished. -# -use strict; -use warnings; -use Anvil::Tools; -use Data::Dumper; - -# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. -$| = 1; - -my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; -my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; -if (($running_directory =~ /^\./) && ($ENV{PWD})) -{ - $running_directory =~ s/^\./$ENV{PWD}/; -} - -my $anvil = Anvil::Tools->new(); - -$anvil->Get->switches; -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); - -# If there's no DB (or cached data isn't recorded to the database yet), this will store those records. -$anvil->data->{cache}{new_file} = "# interface,timestamp,mac_address,speed,link_state,operational\n"; - -$anvil->Database->connect(); -$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"}); -if (not $anvil->data->{sys}{database}{connections}) -{ - # No database, but we need to keep going. If the user unplugged the only cable connecting us to the - # network, we'll lose all DBs, but we still need to record the order the NICs went up and down. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0016"}); -} - -process_interface_cache($anvil); - -update_network($anvil); - -# Write out the interface cache -$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "cache::new_file" => $anvil->data->{cache}{new_file}, - "path::data::network_cache" => $anvil->data->{path}{data}{network_cache}, -}}); -$anvil->Storage->write_file({ - debug => 3, - body => $anvil->data->{cache}{new_file}, - file => $anvil->data->{path}{data}{network_cache}, - overwrite => 1, - backup => 0, -}); - -$anvil->nice_exit({exit_code => 0}); - - -############################################################################################################# -# Functions # -############################################################################################################# - -# This reads in the interface cache file and looks for records that haven't been stored in the database yet. -sub process_interface_cache -{ - my ($anvil) = @_; - - # Does the file exist? If so, read it in. - if (-e $anvil->data->{path}{data}{network_cache}) - { - my $body = $anvil->Storage->read_file({debug => 2, cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}}); - foreach my $line (split/\n/, $body) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - next if $line =~ /^#/; - my ($interface, $timestamp, $mac_address, $speed, $link_state, $operational) = (split/,/, $line); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface => $interface, - timestamp => $timestamp, - speed => $speed, - mac_address => $mac_address, - link_state => $link_state, - operational => $operational, - }}); - - if ($anvil->data->{sys}{database}{connections}) - { - my ($network_interface_uuid) = $anvil->Database->insert_or_update_network_interfaces({ - debug => 2, - link_only => 1, - timestamp => $timestamp, - network_interface_name => $interface, - network_interface_link_state => $link_state, - network_interface_mac_address => $mac_address, - network_interface_operational => $operational, - network_interface_speed => $speed, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }}); - if (not $network_interface_uuid) - { - # Failed to update, could be that we cached data for an interface not yet - # seen. If so, the coming scan will add it and this cache should flush out - # next time. - $anvil->data->{cache}{new_file} .= $line."\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }}); - } - } - else - { - # No database, re-cache - $anvil->data->{cache}{new_file} .= $line."\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "cache::new_file" => $anvil->data->{cache}{new_file} }}); - } - } - } - - return(0); -} - -# This reports the current network interface states, tracked by the MAC address. -sub update_network -{ - my ($anvil) = @_; - - # Run 'ip addr' to see what IPs are in use. - $anvil->Network->get_ips(); - - # We'll read through '/sys/class/net' looking for network interfaces. - # * 'network::${local_host}::interface::::ip' - If an IP address is set - # * 'network::${local_host}::interface::::subnet_mask' - If an IP is set - my $local_host = $anvil->Get->short_host_name(); - my $directory = "/sys/class/net"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { directory => $directory }}); - - # We'll need to know what interfaces to remove, if any. This will store the interfaces we've seen and - # any others will be removed. - $anvil->data->{seen} = { - interface => {}, - bond => {}, - bridge => {}, - ip => {}, - }; - - # Make sure there are no virsh bridges, removing any found. - my $host_type = $anvil->Get->host_type(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); - if (($host_type eq "node") or ($host_type eq "dr")) - { - my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-list --all --name"; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - if (not $return_code) - { - # Virsh is up. - foreach my $line (split/\n/, $output) - { - $line =~ s/^\s+//; - $line =~ s/\s+$//; - next if not $line; - next if $line =~ /^error/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "striker_0287", variables => { bridge => $line }}); - - my $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-destroy ".$line; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - $shell_call = $anvil->data->{path}{exe}{setsid}." --wait ".$anvil->data->{path}{exe}{virsh}." net-undefine ".$line; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - } - } - } - - # Walk through the sysfs files. - local(*DIRECTORY); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0018", variables => { directory => $directory }}); - opendir(DIRECTORY, $directory); - while(my $file = readdir(DIRECTORY)) - { - next if $file eq "."; - next if $file eq ".."; - next if $file eq "lo"; - my $full_path = $directory."/".$file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { full_path => $full_path }}); - if (-d $full_path) - { - # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. - my $interface = $file; - my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; - my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; - my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? - my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down - my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; - my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link - my $media = "unknown"; - my $type = "interface"; - my $driver = ""; - - # Clean up some newlines. - $link_state =~ s/\n$//; - $mtu =~ s/\n$//; - $duplex =~ s/\n$//; - $operational =~ s/\n$//; - $speed =~ s/\n$//; - $modalias =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface => $interface, - link_state => $link_state, - mtu => $mtu, - duplex => $duplex, - operational => $operational, - speed => $speed, - modalias => $modalias, - }}); - - ### NOTE: This only parses virtio so far. - # Pick out our driver. - if ($modalias =~ /^virtio:/) - { - $driver = "virtio"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver => $driver }}); - } - - # The MAC address can faked by a number of ways, so we make an explicit call to 'ethtool' to get the permanent mac address. - my $mac_address = ""; - my $shell_call = $anvil->data->{path}{exe}{ethtool}." -P ".$interface; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - if ($output =~ /(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/) - { - $mac_address = lc($1); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - else - { - # Get it by reading the address file. - if (-e $full_path."/bonding_slave/perm_hwaddr") - { - $mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - elsif (-e $full_path."/address") - { - $mac_address = $anvil->Storage->read_file({file => $full_path."/address"}); - $mac_address =~ s/\n//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - } - - # These are variables that will be needed if this is a bond interface. - my $ip_address = ""; - my $subnet_mask = ""; - my $bond_mode = ""; - my $primary_interface = ""; - my $primary_reselect = ""; - my $active_interface = ""; - my $mii_polling_interval = ""; - my $up_delay = ""; - my $down_delay = ""; - my $bond_master = ""; - - # These are variables that will be needed if this is a bridge interface - my $bridge_id = ""; - my $bridge_stp_enabled = ""; - - # Explicitly check for the existing of the hash so that we don't auto-vivivate the interface. - if (exists $anvil->data->{network}{$local_host}{interface}{$interface}) - { - $ip_address = defined $anvil->data->{network}{$local_host}{interface}{$interface}{ip} ? $anvil->data->{network}{$local_host}{interface}{$interface}{ip} : ""; - $subnet_mask = defined $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} ? $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} : ""; - $type = defined $anvil->data->{network}{$local_host}{interface}{$interface}{type} ? $anvil->data->{network}{$local_host}{interface}{$interface}{type} : "interface"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_address => $ip_address, - subnet_mask => $subnet_mask, - type => $type, - }}); - } - - # If this interface is already a bond slave, the real mac address will be in a - # sub-directory. - my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr"; - if (-e $mac_bond_file) - { - # It's a slave. - $mac_address = $anvil->Storage->read_file({file => $mac_bond_file}); - $mac_address =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { mac_address => $mac_address }}); - } - - # If this is a virtual interface, set some fake values that don't actually exist on - # the system for the sake of a cleaner display. - if (($mac_address =~ /^52:54:00/) or ($driver eq "virtio")) - { - ### Set some fake values. - # Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary. - if ((not $speed) or ($speed eq "-1")) - { - $speed = 10000; - } - if ((not $duplex) or ($duplex eq "unknown")) - { - $duplex = "full"; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - speed => $speed, - duplex => $duplex, - }}); - } - # If the state is 'down', set the speed to '0'. - if (not $link_state) - { - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); - } - - # Is this a bond interface? - if (-e "/proc/net/bonding/".$interface) - { - # Yup, we'll neet to dig into the bond proc files to get the proper slaved - # interface MAC addresses. - $type = "bond"; - - # Read the bond mode. - $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); - $primary_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"}); - $primary_reselect = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"}); - $active_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"}); - $mii_polling_interval = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"}); - $up_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"}); - $down_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"}); - $bond_mode =~ s/\s.*//; - $bond_mode =~ s/\n$//; - $primary_interface =~ s/\n$//; - $primary_reselect =~ s/\s.*//; - $primary_reselect =~ s/\n$//; - $active_interface =~ s/\n$//; - $mii_polling_interval =~ s/\n$//; - $up_delay =~ s/\n$//; - $down_delay =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - active_interface => $active_interface, - bond_mode => $bond_mode, - mii_polling_interval => $mii_polling_interval, - primary_reselect => $primary_reselect, - primary_interface => $primary_interface, - type => $type, - }}); - } - elsif (-e $full_path."/master") - { - # No, but it's slaved to one. - my $target = readlink($full_path."/master"); - $bond_master = ($target =~ /^.*\/(.*)$/)[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - target => $target, - bond_master => $bond_master, - }}); - } - elsif (-d $full_path."/bridge") - { - # It's a bridge - $type = "bridge"; - $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); - $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); - $bridge_id =~ s/\n$//; - $bridge_stp_enabled =~ s/\n$//; - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - bridge_id => $bridge_id, - bridge_stp_enabled => $bridge_stp_enabled, - type => $type, - }}); - if ($bridge_stp_enabled eq "0") - { - $bridge_stp_enabled = "disabled"; - } - elsif ($bridge_stp_enabled eq "1") - { - $bridge_stp_enabled = "enabled_kernel"; - } - elsif ($bridge_stp_enabled eq "2") - { - $bridge_stp_enabled = "enabled_userland"; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bridge_stp_enabled => $bridge_stp_enabled }}); - } - - # If this a vnet device, set 'operational' to 'up'. - if ($interface =~ /^vnet/) - { - $operational = "up"; - $media = "virtual"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - operational => $operational, - media => $media, - }}); - } - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - active_interface => $active_interface, - bond_master => $bond_master, - bond_mode => $bond_mode, - bridge_id => $bridge_id, - bridge_stp_enabled => $bridge_stp_enabled, - down_delay => $down_delay, - duplex => $duplex, - interface => $interface, - mac_address => $mac_address, - mii_polling_interval => $mii_polling_interval, - mtu => $mtu, - operational => $operational, - primary_reselect => $primary_reselect, - primary_interface => $primary_interface, - speed => $speed, - subnet_mask => $subnet_mask, - type => $type, - up_delay => $up_delay, - }}); - - # If the MAC address starts with '52:54:00', we've got a virtio NIC. - if ((not defined $speed) or ($speed eq "")) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0001", variables => { file => $full_path."/speed" }}); - next; - } - if ($speed =~ /\D/) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0002", variables => { - file => $full_path."/speed", - speed => $speed, - }}); - next; - } - if ($speed > 100000) - { - # NOTE: This is probably 0 now... Though someday >100 Gbps will be reasonable - # and we'll need to change this. - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { speed => $speed }}); - } - - # Find the media, if possible. - (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"}); - foreach my $line (split/\n/, $ethtool) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); - if ($line =~ /Supported ports: \[ (.*?) \]/i) - { - $media = lc($1); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); - - # This can be 'tp mii', which breaks json. - if ($media =~ /\t/) - { - $media =~ s/\t/,/g; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); - } - last; - } - } - - # Record this interface - $anvil->data->{seen}{$type}{$interface} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "seen::${type}::${interface}" => $anvil->data->{seen}{$type}{$interface} }}); - - # Record the IP, if set. - if ($ip_address) - { - $anvil->data->{seen}{ip}{$ip_address} = $interface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "seen::ip::${ip_address}" => $anvil->data->{seen}{ip}{$ip_address} }}); - } - - # Store new information we found. - $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface} = $active_interface; - $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode} = $bond_mode; - $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master} = $bond_master; - $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id} = $bridge_id; - $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled} = $bridge_stp_enabled; - $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay} = $down_delay; - $anvil->data->{network}{$local_host}{interface}{$interface}{duplex} = $duplex; - $anvil->data->{network}{$local_host}{interface}{$interface}{ip} = $ip_address; - $anvil->data->{network}{$local_host}{interface}{$interface}{link_state} = $link_state; - $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address} = $mac_address; - $anvil->data->{network}{$local_host}{interface}{$interface}{media} = $media; - $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval} = $mii_polling_interval; - $anvil->data->{network}{$local_host}{interface}{$interface}{mtu} = $mtu; - $anvil->data->{network}{$local_host}{interface}{$interface}{operational} = $operational; - $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect} = $primary_reselect; - $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface} = $primary_interface; - $anvil->data->{network}{$local_host}{interface}{$interface}{speed} = $speed; - $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} = $subnet_mask; - $anvil->data->{network}{$local_host}{interface}{$interface}{type} = $type; - $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay} = $up_delay; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "network::${local_host}::interface::${interface}::active_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}, - "network::${local_host}::interface::${interface}::bond_mode" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}, - "network::${local_host}::interface::${interface}::bond_master" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}, - "network::${local_host}::interface::${interface}::bridge_id" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}, - "network::${local_host}::interface::${interface}::bridge_stp_enabled" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}, - "network::${local_host}::interface::${interface}::down_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}, - "network::${local_host}::interface::${interface}::duplex" => $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}, - "network::${local_host}::interface::${interface}::ip" => $anvil->data->{network}{$local_host}{interface}{$interface}{ip}, - "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, - "network::${local_host}::interface::${interface}::mac_address" => $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}, - "network::${local_host}::interface::${interface}::media" => $anvil->data->{network}{$local_host}{interface}{$interface}{media}, - "network::${local_host}::interface::${interface}::mii_polling_interval" => $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}, - "network::${local_host}::interface::${interface}::mtu" => $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}, - "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, - "network::${local_host}::interface::${interface}::primary_reselect" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}, - "network::${local_host}::interface::${interface}::primary_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}, - "network::${local_host}::interface::${interface}::speed" => $anvil->data->{network}{$local_host}{interface}{$interface}{speed}, - "network::${local_host}::interface::${interface}::subnet_mask" => $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}, - "network::${local_host}::interface::${interface}::type" => $anvil->data->{network}{$local_host}{interface}{$interface}{type}, - "network::${local_host}::interface::${interface}::up_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}, - }}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, - "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, - }}); - - # If this is a link and there's no database connections, cache the data. - if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) - { - $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational."\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "cache::new_file" => $anvil->data->{cache}{new_file}, - }}); - } - } - } - closedir(DIRECTORY); - - # Find what interfaces are connected to which bridges - $anvil->Network->bridge_info({debug => 2}); - - # We need to record bridges first so we know their UUIDs when looking at bonds and interfaces that - # might be connected to them. Then we need to look at bonds so that their UUIDs are available when - # recording interfaces. - foreach my $processing ("bridge", "bond", "interface") - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { processing => $processing }}); - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) - { - # Skip if this isn't the device type we're working on. - next if not defined $anvil->data->{network}{$local_host}{interface}{$interface}{type}; - my $type = $anvil->data->{network}{$local_host}{interface}{$interface}{type}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:interface' => $interface, - 's2:type' => $type, - 's3:processing' => $processing, - }}); - next if $processing ne $anvil->data->{network}{$local_host}{interface}{$interface}{type}; - - my $active_interface = $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}; - my $bond_mode = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}; - my $bond_master = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; - my $bridge_id = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}; - my $bridge_stp_enabled = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}; - my $down_delay = $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}; - my $duplex = $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}; - my $ip_address = $anvil->data->{network}{$local_host}{interface}{$interface}{ip}; - my $link_state = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; - my $mac_address = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; - my $media = $anvil->data->{network}{$local_host}{interface}{$interface}{media}; - my $mii_polling_interval = $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}; - my $mtu = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; - my $operational = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; - my $primary_reselect = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}; - my $primary_interface = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}; - my $speed = $anvil->data->{network}{$local_host}{interface}{$interface}{speed}; - my $subnet_mask = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}; - my $up_delay = $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}; - my $default_gateway = $anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway}; - my $gateway = $anvil->data->{network}{$local_host}{interface}{$interface}{gateway}; - my $dns = $anvil->data->{network}{$local_host}{interface}{$interface}{dns}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - active_interface => $active_interface, - bond_mode => $bond_mode, - bond_master => $bond_master, - default_gateway => $default_gateway, - down_delay => $down_delay, - dns => $dns, - duplex => $duplex, - gateway => $gateway, - interface => $interface, - ip_address => $ip_address, - link_state => $link_state, - mac_address => $mac_address, - media => $media, - mii_polling_interval => $mii_polling_interval, - mtu => $mtu, - operational => $operational, - primary_reselect => $primary_reselect, - primary_interface => $primary_interface, - speed => $speed, - subnet_mask => $subnet_mask, - up_delay => $up_delay, - }}); - - if (($type eq $processing) && ($type eq "bridge")) - { - if ($anvil->data->{sys}{database}{connections}) - { - my $bridge_uuid = $anvil->Database->insert_or_update_bridges({ - debug => 3, - file => $THIS_FILE, - line => __LINE__, - bridge_name => $interface, - bridge_id => $bridge_id, - bridge_mac_address => $mac_address, - bridge_mtu => $mtu, - bridge_stp_enabled => $bridge_stp_enabled, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); - - $anvil->data->{bridge_by_name}{$interface} = $bridge_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bridge_by_name::${interface}" => $anvil->data->{bridge_by_name}{$interface} }}); - if (($bridge_uuid) && ($ip_address)) - { - my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - ip_address_on_type => $type, - ip_address_on_uuid => $bridge_uuid, - ip_address_address => $ip_address, - ip_address_subnet_mask => $subnet_mask, - ip_address_gateway => $gateway, - ip_address_default_gateway => $default_gateway, - ip_address_dns => $dns, - ip_address_note => "", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address_uuid => $ip_address_uuid }}); - } - } - } - - if (($type eq $processing) && ($type eq "bond")) - { - # Is this bond connected to a bridge? - my $bond_bridge_uuid = ""; - my $bond_on_bridge = exists $anvil->data->{interface_to_bridge}{$interface} ? $anvil->data->{interface_to_bridge}{$interface} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_on_bridge => $bond_on_bridge }}); - if ($bond_on_bridge) - { - $bond_bridge_uuid = $anvil->data->{bridge_by_name}{$bond_on_bridge}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_bridge_uuid => $bond_bridge_uuid }}); - } - - if ($anvil->data->{sys}{database}{connections}) - { - my $bond_uuid = $anvil->Database->insert_or_update_bonds({ - debug => 3, - file => $THIS_FILE, - line => __LINE__, - bond_name => $interface, - bond_mode => $bond_mode, - bond_mtu => $mtu, - bond_link_state => $link_state, - bond_operational => $operational, - bond_mac_address => $mac_address, - bond_primary_interface => $primary_interface, - bond_primary_reselect => $primary_reselect, - bond_active_interface => $active_interface, - bond_mii_polling_interval => $mii_polling_interval, - bond_up_delay => $up_delay, - bond_down_delay => $down_delay, - bond_bridge_uuid => $bond_bridge_uuid, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_uuid => $bond_uuid }}); - - $anvil->data->{bond_by_name}{$interface} = $bond_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "bond_by_name::${interface}" => $anvil->data->{bond_by_name}{$interface} }}); - - if (($bond_uuid) && ($ip_address)) - { - my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - ip_address_on_type => $type, - ip_address_on_uuid => $bond_uuid, - ip_address_address => $ip_address, - ip_address_subnet_mask => $subnet_mask, - ip_address_gateway => $gateway, - ip_address_default_gateway => $default_gateway, - ip_address_dns => $dns, - ip_address_note => "", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip_address_uuid => $ip_address_uuid }}); - } - } - } - - if (($type eq $processing) && ($type eq "interface")) - { - # Is this interface connected to a bridge? - my $network_interface_bridge_uuid = ""; - my $network_interface_on_bridge = exists $anvil->data->{interface_to_bridge}{$interface} ? $anvil->data->{interface_to_bridge}{$interface} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_on_bridge => $network_interface_on_bridge }}); - if ($network_interface_on_bridge) - { - $network_interface_bridge_uuid = $anvil->data->{bridge_by_name}{$network_interface_on_bridge}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_bridge_uuid => $network_interface_bridge_uuid }}); - } - - my $say_bond_uuid = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_master => $bond_master }}); - if (($bond_master) && ($anvil->data->{bond_by_name}{$bond_master})) - { - $say_bond_uuid = $anvil->data->{bond_by_name}{$bond_master}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "bond_by_name::${bond_master}" => $anvil->data->{bond_by_name}{$bond_master}, - say_bond_uuid => $say_bond_uuid, - }}); - } - if ($anvil->data->{sys}{database}{connections}) - { - my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - network_interface_bond_uuid => $say_bond_uuid, - network_interface_bridge_uuid => $network_interface_bridge_uuid, - network_interface_name => $interface, - network_interface_duplex => $duplex, - network_interface_link_state => $link_state, - network_interface_operational => $operational, - network_interface_mac_address => $mac_address, - network_interface_medium => $media, - network_interface_mtu => $mtu, - network_interface_speed => $speed, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); - - $anvil->data->{interface_by_name}{$interface} = $network_interface_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface_by_name::${interface}" => $anvil->data->{interface_by_name}{$interface} }}); - if (($network_interface_uuid) && ($ip_address)) - { - my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - ip_address_on_type => $type, - ip_address_on_uuid => $network_interface_uuid, - ip_address_address => $ip_address, - ip_address_subnet_mask => $subnet_mask, - ip_address_gateway => $gateway, - ip_address_default_gateway => $default_gateway, - ip_address_dns => $dns, - ip_address_note => "", - }); - } - } - } - } - } - - if (not $anvil->data->{sys}{database}{connections}) - { - return(0); - } - - # I need to read back in the interface and bridge data and splice it together before I write out the - # XML and JSON files. - my $query = " -SELECT - bond_uuid, - bond_name, - bond_mode, - bond_mtu, - bond_primary_interface, - bond_primary_reselect, - bond_active_interface, - bond_mii_polling_interval, - bond_up_delay, - bond_down_delay, - bond_mac_address, - bond_operational -FROM - bonds -WHERE - bond_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -AND - bond_mode != 'DELETED' -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); - my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - my $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, - }}); - foreach my $row (@{$results}) - { - my $bond_uuid = $row->[0]; - my $bond_name = $row->[1]; - $anvil->data->{bonds}{$bond_uuid} = { - bond_name => $bond_name, - bond_mode => $row->[2], - bond_mtu => $row->[3], - bond_primary_interface => $row->[4], - bond_primary_reselect => $row->[5], - bond_active_interface => $row->[6], - bond_mii_polling_interval => $row->[7], - bond_up_delay => $row->[8], - bond_down_delay => $row->[9], - bond_mac_address => $row->[10], - bond_operational => $row->[11], - }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "bonds::${bond_uuid}::bond_name" => $anvil->data->{bonds}{$bond_uuid}{bond_name}, - "bonds::${bond_uuid}::bond_mode" => $anvil->data->{bonds}{$bond_uuid}{bond_mode}, - "bonds::${bond_uuid}::bond_mtu" => $anvil->data->{bonds}{$bond_uuid}{bond_mtu}, - "bonds::${bond_uuid}::bond_primary_interface" => $anvil->data->{bonds}{$bond_uuid}{bond_primary_interface}, - "bonds::${bond_uuid}::bond_primary_reselect" => $anvil->data->{bonds}{$bond_uuid}{bond_primary_reselect}, - "bonds::${bond_uuid}::bond_active_interface" => $anvil->data->{bonds}{$bond_uuid}{bond_active_interface}, - "bonds::${bond_uuid}::bond_mii_polling_interval" => $anvil->data->{bonds}{$bond_uuid}{bond_mii_polling_interval}, - "bonds::${bond_uuid}::bond_up_delay" => $anvil->data->{bonds}{$bond_uuid}{bond_up_delay}, - "bonds::${bond_uuid}::bond_down_delay" => $anvil->data->{bonds}{$bond_uuid}{bond_down_delay}, - "bonds::${bond_uuid}::bond_mac_address" => $anvil->data->{bonds}{$bond_uuid}{bond_mac_address}, - "bonds::${bond_uuid}::bond_operational" => $anvil->data->{bonds}{$bond_uuid}{bond_operational}, - }}); - - # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. - if ((not exists $anvil->data->{seen}{bond}{$bond_name}) or (not $anvil->data->{seen}{bond}{$bond_name})) - { - # Mark it as deleted. - my $query = " -UPDATE - bonds -SET - bond_mode = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." -WHERE - bond_uuid = ".$anvil->Database->quote($bond_uuid)." -;"; - $anvil->Database->write({debug => 3, query => $query, source => $THIS_FILE, line => __LINE__}); - - # Remove it from the hash so we don't add it to the .json and .xml files. - delete $anvil->data->{bonds}{$bond_uuid}; - } - } - - $query = " -SELECT - bridge_uuid, - bridge_name, - bridge_id, - bridge_mac_address, - bridge_mtu, - bridge_stp_enabled -FROM - bridges -WHERE - bridge_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -AND - bridge_id != 'DELETED' -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); - $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, - }}); - foreach my $row (@{$results}) - { - my $bridge_uuid = $row->[0]; - my $bridge_name = $row->[1]; - my $bridge_id = $row->[2]; - my $bridge_mac_address = $row->[3]; - my $bridge_mtu = $row->[4]; - my $bridge_stp_enabled = $row->[5]; - $anvil->data->{bridges}{$bridge_uuid} = { - bridge_name => $bridge_name, - bridge_id => $bridge_id, - bridge_mac_address => $bridge_mac_address, - bridge_mtu => $bridge_mtu, - bridge_stp_enabled => $bridge_stp_enabled, - }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - "bridges::${bridge_uuid}::bridge_name" => $anvil->data->{bridges}{$bridge_uuid}{bridge_name}, - "bridges::${bridge_uuid}::bridge_id" => $anvil->data->{bridges}{$bridge_uuid}{bridge_id}, - "bridges::${bridge_uuid}::bridge_mac_address" => $anvil->data->{bridges}{$bridge_uuid}{bridge_mac_address}, - "bridges::${bridge_uuid}::bridge_mtu" => $anvil->data->{bridges}{$bridge_uuid}{bridge_mtu}, - "bridges::${bridge_uuid}::bridge_stp_enabled" => $anvil->data->{bridges}{$bridge_uuid}{bridge_stp_enabled}, - }}); - - # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. - if ((not exists $anvil->data->{seen}{bridge}{$bridge_name}) or (not $anvil->data->{seen}{bridge}{$bridge_name})) - { - # Mark it as deleted. - my $query = " -UPDATE - bridges -SET - bridge_id = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." -WHERE - bridge_uuid = ".$anvil->Database->quote($bridge_uuid).";"; - $anvil->Database->write({debug => 3, query => $query, source => $THIS_FILE, line => __LINE__}); - - # Remove it from the hash so we don't add it to the .json and .xml files. - delete $anvil->data->{bridges}{$bridge_uuid}; - } - } - - # Process interfaces - $query = " -SELECT - network_interface_uuid, - network_interface_mac_address, - network_interface_name, - network_interface_speed, - network_interface_mtu, - network_interface_link_state, - network_interface_operational, - network_interface_duplex, - network_interface_medium, - network_interface_bond_uuid, - network_interface_bridge_uuid -FROM - network_interfaces -WHERE - network_interface_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -ORDER BY - modified_date DESC -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); - $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, - }}); - - # The order will track the order the interfaces were last modified, which is a way to determine when - # they came up. - my $network_xml = "\n"; - $network_xml .= "\n"; - my $network_json = "{\"networks\":[\n"; - my $order = 1; - foreach my $row (@{$results}) - { - my $network_interface_uuid = $row->[0]; - my $network_interface_name = $row->[2]; - $anvil->data->{network_interfaces}{$network_interface_uuid} = { - network_interface_mac_address => $row->[1], - network_interface_name => $network_interface_name, - network_interface_speed => $row->[3], - network_interface_mtu => $row->[4], - network_interface_link_state => $row->[5], - network_interface_operational => $row->[6], - network_interface_duplex => $row->[7], - network_interface_medium => $row->[8], - network_interface_bond_uuid => defined $row->[9] ? $row->[9] : 'NULL', - network_interface_bridge_uuid => defined $row->[10] ? $row->[10] : 'NULL', - }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "network_interfaces::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}, - "network_interfaces::${network_interface_uuid}::network_interface_name" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name}, - "network_interfaces::${network_interface_uuid}::network_interface_speed" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}, - "network_interfaces::${network_interface_uuid}::network_interface_mtu" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu}, - "network_interfaces::${network_interface_uuid}::network_interface_link_state" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state}, - "network_interfaces::${network_interface_uuid}::network_interface_operational" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational}, - "network_interfaces::${network_interface_uuid}::network_interface_duplex" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex}, - "network_interfaces::${network_interface_uuid}::network_interface_medium" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium}, - "network_interfaces::${network_interface_uuid}::network_interface_bond_uuid" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bond_uuid}, - "network_interfaces::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bridge_uuid}, - order => $order, - }}); - - # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. - if (not exists $anvil->data->{network}{$local_host}{interface}{$network_interface_name}) - { - if ($anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational} ne "DELETED") - { - # Mark it as deleted. - my $query = " -UPDATE - network_interfaces -SET - network_interface_operational = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." -WHERE - network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid)." -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0124", variables => { query => $query }}); - $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); - } - - # Remove it from the hash so we don't add it to the .json and .xml files. - delete $anvil->data->{interface}{$network_interface_uuid}; - - # Loop so we don't try to process any further. - next; - } - - my $say_bond = ""; - my $network_interface_bond_uuid = $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bond_uuid}; - my $network_interface_bridge_uuid = $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bridge_uuid}; - if (($network_interface_bond_uuid) && ($network_interface_bond_uuid ne 'NULL')) - { - $say_bond = $anvil->data->{bonds}{$network_interface_bond_uuid}{bond_name}; - } - my $say_bridge = ""; - if (($network_interface_bridge_uuid) && ($network_interface_bridge_uuid ne 'NULL')) - { - $say_bridge = $anvil->data->{bridges}{$network_interface_bridge_uuid}{bridge_name}; - } - - $network_json .= " { \"name\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name}."\", \"mac\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}."\", \"link\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state}."\", \"speed\":\"".$anvil->Convert->add_commas({number => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}})."\", \"mtu\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu}."\", \"duplex\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex}."\", \"state\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational}."\", \"media\":\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium}."\", \"bond\":\"".$say_bond."\", \"bridge\":\"".$say_bridge."\", \"order\":\"".$order."\" },\n"; - $network_xml .= " data->{network_interfaces}{$network_interface_uuid}{network_interface_name}."\" mac=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}."\" link=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_link_state}."\" speed=\"".$anvil->Convert->add_commas({number => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}})."\" mtu=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mtu}."\" duplex=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_duplex}."\" state=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_operational}."\" media=\"".$anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_medium}."\" bond=\"".$say_bond."\" bridge=\"".$say_bridge."\" order=\"".$order."\" />\n"; - $order++; - } - - $network_json =~ s/,$//s; - $network_json .= "],\n"; - $network_json .= "\"ips\":[\n"; - - # Now record the IPs. - $query = " -SELECT - ip_address_uuid, - ip_address_on_type, - ip_address_on_uuid, - ip_address_address, - ip_address_subnet_mask, - ip_address_gateway, - ip_address_default_gateway, - ip_address_dns, - ip_address_note -FROM - ip_addresses -WHERE - ip_address_host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid})." -;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); - $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); - $count = @{$results}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - results => $results, - count => $count, - }}); - foreach my $row (@{$results}) - { - my $ip_address_uuid = $row->[0]; - my $ip_address_on_type = $row->[1]; - my $ip_address_on_uuid = $row->[2]; - my $ip_address_address = $row->[3]; - my $ip_address_subnet_mask = $row->[4]; - my $ip_address_gateway = $row->[5]; - my $ip_address_default_gateway = $row->[6]; - my $ip_address_dns = $row->[7]; - my $ip_address_note = $row->[8]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_address_on_type => $ip_address_on_type, - ip_address_on_uuid => $ip_address_on_uuid, - ip_address_address => $ip_address_address, - ip_address_subnet_mask => $ip_address_subnet_mask, - ip_address_gateway => $ip_address_gateway, - ip_address_default_gateway => $ip_address_default_gateway, - ip_address_dns => $ip_address_dns, - ip_address_note => $ip_address_note, - }}); - - if ((not exists $anvil->data->{seen}{ip}{$ip_address_address}) or (not $anvil->data->{seen}{ip}{$ip_address_address})) - { - # This IP address no longer exists on this host, removing it. - my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ - debug => 2, - file => $THIS_FILE, - line => __LINE__, - 'delete' => 1, - ip_address_uuid => $ip_address_uuid, - }); - next; - } - - my $say_on = ""; - if ($ip_address_on_type eq "interface") - { - $say_on = $anvil->data->{network_interfaces}{$ip_address_on_uuid}{network_interface_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }}); - } - elsif ($ip_address_on_type eq "bond") - { - $say_on = $anvil->data->{bonds}{$ip_address_on_uuid}{bond_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }}); - } - elsif ($ip_address_on_type eq "bridge") - { - $say_on = $anvil->data->{bridges}{$ip_address_on_uuid}{bridge_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { say_on => $say_on }}); - } - - $network_json .= " { \"address\":\"$ip_address_address\", \"on\":\"$say_on\", \"subnet_mask\":\"$ip_address_subnet_mask\", \"gateway\":\"$ip_address_gateway\", \"default_gateway\":\"$ip_address_default_gateway\", \"dns\":\"$ip_address_dns\" },\n"; - $network_xml .= " \n"; - } - - $network_json =~ s/,$//s; - $network_json .= "]}\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_json => $network_json }}); - - $network_xml .= "\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_xml => $network_xml }}); - - # Write the JSON file, if we're a dashboard. Nodes and DR hosts don't have a WebUI, so they're not - # needed. - if ($anvil->Get->host_type eq "striker") - { - my $output_json = $anvil->data->{path}{directories}{html}."/status/network.json"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_json }}); - $anvil->Storage->write_file({ - backup => 0, - file => $output_json, - body => $network_json, - overwrite => 1, - mode => "0644", - user => "apache", - group => "apache" - }); - - # Write the XML file. - my $output_xml = $anvil->data->{path}{directories}{html}."/status/network.xml"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_xml }}); - $anvil->Storage->write_file({ - backup => 0, - file => $output_xml, - body => $network_xml, - overwrite => 1, - mode => "0644", - user => "apache", - group => "apache" - }); - } - - return(0); -} diff --git a/units/Makefile.am b/units/Makefile.am index 6c518615..d25cbf05 100644 --- a/units/Makefile.am +++ b/units/Makefile.am @@ -3,6 +3,7 @@ MAINTAINERCLEANFILES = Makefile.in servicedir = $(SYSTEMD_UNIT_DIR) dist_service_DATA = \ anvil-daemon.service \ + anvil-monitor-network.service \ anvil-safe-start.service \ scancore.service \ striker-ui-api.service diff --git a/units/anvil-monitor-network.service b/units/anvil-monitor-network.service new file mode 100644 index 00000000..9e33cd1d --- /dev/null +++ b/units/anvil-monitor-network.service @@ -0,0 +1,12 @@ +[Unit] +Description=Anvil! Intelligent Availability Platform - Network Monitor Daemon +Wants=network.target + +[Service] +Type=simple +ExecStart=/usr/sbin/anvil-monitor-network +ExecStop=/bin/kill -WINCH ${MAINPID} +Restart=always + +[Install] +WantedBy=multi-user.target From ef89a79162724d53e2ed085091118677606d2b00 Mon Sep 17 00:00:00 2001 From: digimer Date: Sat, 6 Jan 2024 01:09:05 -0500 Subject: [PATCH 14/43] More progress on anvil-configure-host * Now working on the reconfiguring of interfaces. Signed-off-by: digimer --- share/words.xml | 1 + tools/anvil-configure-host | 633 +++++++++++++++++++++++-------------- 2 files changed, 397 insertions(+), 237 deletions(-) diff --git a/share/words.xml b/share/words.xml index fef25809..f730b77a 100644 --- a/share/words.xml +++ b/share/words.xml @@ -752,6 +752,7 @@ The XML that failed sanity check was: [ Error ] - The requested number of cores: [#!variable!requested_cores!#] (sockets: [#!variable!new_sockets!], cores per socket: [#!variable!new_cores!#], threads per core: [#!variable!new_threads!#]). [ Error ] - This program must be run on a subnode. [ Error ] - This subnode is not in the cluster (failed to parse the CIB). Exiting. + [ Error ] - The wanted interface: [#!variable!interface_name!#] which should have the MAC address: [#!variable!mac_address!#] was not found in Network Manager. Unable to proceed. diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 8f623b3e..b210d7d3 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -64,7 +64,7 @@ pickup_job_details($anvil); overwrite_variables_with_switches($anvil); # Set maintenance mode -$anvil->System->maintenance_mode({set => 1}); +#$anvil->System->maintenance_mode({set => 1}); # Reconfigure the network. reconfigure_network($anvil); @@ -327,10 +327,10 @@ sub reconfigure_network } # Read the local network manager data. - $anvil->Network->read_nmcli({debug => 2}); + #$anvil->Network->read_nmcli({debug => 2}); # Get the current list of IPs and MAC addresses. - $anvil->Network->get_ips({debug => 2}); + #$anvil->Network->get_ips({debug => 2}); # If we're a striker, check apache's config. if ($type eq "striker") @@ -478,6 +478,9 @@ ORDER BY # We'll set this to '1' if we reconfigure the network $anvil->data->{sys}{reboot} = 0; + # Read the existing network data + $anvil->Network->collect_data({debug => 2}); + # This will be set to '1' if we make a change. my $changes = 0; my $new_interfaces = []; @@ -491,7 +494,7 @@ ORDER BY $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); # This is the old type of network config - configure_ifcfg_network($anvil, $network_type); + #configure_ifcfg_network($anvil, $network_type); } } else @@ -502,6 +505,7 @@ ORDER BY reconfigure_interfaces($anvil); reconfigure_ip_addresses($anvil); } + die; # If we should reset, do so now. if ($anvil->data->{sys}{reboot}) @@ -657,206 +661,357 @@ ORDER BY return(0); } -sub reconfigure_interfaces +sub reconfigure_bridges { my ($anvil) = @_; - foreach my $network_type ("bcn", "sn", "mn", "ifn") - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); - # This is the old type of network config - configure_ifcfg_network($anvil, $network_type); - } - + return(0); +} +sub reconfigure_bonds +{ + my ($anvil) = @_; + + + return(0); +} +sub reconfigure_ip_addresses +{ + my ($anvil) = @_; + + + return(0); +} - foreach my $wanted_interface (sort {$a cmp $b} keys %{$anvil->data->{network_manager}{reconfigure}}) +sub reconfigure_interfaces +{ + my ($anvil) = @_; + + my $reboot_needed = 0; + my $local_host = $anvil->Get->short_host_name(); + my $prefix = $anvil->data->{config}{prefix}; + my $sequence = $anvil->data->{config}{sequence}; + my $domain = $anvil->data->{config}{domain}; + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + prefix => $prefix, + sequence => $sequence, + domain => $domain, + type => $type, + }}); + foreach my $network_type ("bcn", "sn", "mn", "ifn") { - my $uuid = $anvil->data->{network_manager}{reconfigure}{$wanted_interface}{from_uuid}; - my $old_device = $anvil->data->{interface}{uuid}{$uuid}{device}; - my $name = $anvil->data->{interface}{uuid}{$uuid}{'connection.id'}; - my $mac_address = $anvil->data->{interface}{uuid}{$uuid}{mac_address}; - my $type = $anvil->data->{interface}{uuid}{$uuid}{type}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:wanted_interface' => $wanted_interface, - 's2:uuid' => $uuid, - 's3:old_device' => $old_device, - 's4:name' => $name, - 's5:mac_address' => $mac_address, - 's6:type' => $type, - }}); - - print "Renaming old device/name: [".$old_device."/".$name."] with MAC: [".$mac_address."] to: [".$wanted_interface."] using UUID: [".$uuid."]\n"; - - # Read persistent-net and see if it needs to be updated. - my $new_persistent_net = ""; - my $old_persistent_net = ""; - if (-e $anvil->data->{path}{configs}{'persistent-net'}) - { - $old_persistent_net = $anvil->Storage->read_file({debug => 2, file => $anvil->data->{path}{configs}{'persistent-net'}}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_persistent_net => $old_persistent_net }}); - } - foreach my $line (split/\n/, $old_persistent_net) - { - # If this MAC or device name exists already, delete the line. - if (($line =~ /"$mac_address"/) or ($line =~ /"$wanted_interface"/)) - { - next; - } - $new_persistent_net .= $line."\n"; - } - $new_persistent_net .= "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"".$mac_address."\",ATTR{type}==\"".$type."\",NAME=\"".$wanted_interface."\"\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_persistent_net => $new_persistent_net }}); - - my $difference = diff \$old_persistent_net, \$new_persistent_net, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - - # Write the new file. - if ($difference) - { - print "- Updating the udev file: [".$anvil->data->{path}{configs}{'persistent-net'}."]\n"; - my $problem = $anvil->Storage->write_file({ - file => $anvil->data->{path}{configs}{'persistent-net'}, - body => $new_persistent_net, - overwrite => 1, - user => "admin", - group => "admin", - mode => "0644", - - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); - if ($problem) - { - print "[ Error ] - Failed to write the new: [".$anvil->data->{path}{configs}{'persistent-net'}."] file, aborting!\n"; - $anvil->nice_exit({exit_code => 1}); - } - } + $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; } + elsif ($network_type eq "mn") { $count = $mn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); - # Update the connection.interface-name - my $connection_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'connection.interface-name'} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); - if ($connection_interface_name) + # This is the old type of network config + foreach my $i (1..$count) { - print "- Removing the old 'connection.interface-name': [".$connection_interface_name."]\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.interface-name \"\""; - $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}); + my $link1_mac_key = $network_type.$i."_link1_mac_to_set"; + my $link2_mac_key = $network_type.$i."_link2_mac_to_set"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, + i => $i, + link1_mac_key => $link1_mac_key, + link2_mac_key => $link2_mac_key, }}); - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.interface-name connection show ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + my $wanted_link1_name = $network_type.$i."_link1"; + my $wanted_link1_mac = $anvil->data->{config}{$link1_mac_key}; + my $wanted_link2_name = $network_type.$i."_link2"; + my $wanted_link2_mac = exists $anvil->data->{config}{$link2_mac_key} ? $anvil->data->{config}{$link2_mac_key} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, + wanted_link1_name => $wanted_link1_name, + wanted_link1_mac => $wanted_link1_mac, + wanted_link2_name => $wanted_link2_name, + wanted_link2_mac => $wanted_link2_mac, }}); - if ($output) + # Loop through our interfaces to see if we can find this interface. + my $link1_nm_uuid = $anvil->data->{nmcli}{mac_address}{$wanted_link1_mac}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link1_nm_uuid => $link1_nm_uuid }}); + + # Get the Network Manager UUIDs. + if (not $link1_nm_uuid) { - # This should have been blank - print "[ Error ] - Failed to delete the 'connection.interface-name', got: [".$output."] and it should bhave been blank, aborting!\n"; + $anvil->Job->update_progress({ + progress => 100, + message => "error_0480", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + variables => { + mac_address => $wanted_link1_mac, + interface_name => $wanted_link1_name, + }, + }); $anvil->nice_exit({exit_code => 1}); } - } - - # We'll log what it was, and change it anyway - my $match_interface_name = $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} ? $anvil->data->{interface}{uuid}{$uuid}{'match.interface-name'} : ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); - if (1) - { - print "- Matching the new interface name: [".$wanted_interface."] to the bios device name: [".$old_device."]\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." match.interface-name \"".$wanted_interface." ".$old_device."\""; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Read it back - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + rename_interface($anvil, $wanted_link1_name, $link1_nm_uuid); - if (($output ne $wanted_interface.",".$old_device) && ($output ne $old_device.",".$wanted_interface)) + my $link2_nm_uuid = ""; + if ($link2_nm_uuid) { - # This should have been blank - print "[ Error ] - Failed to create the 'match.interface-name' value. Expected: [".$wanted_interface.",".$old_device."], got: [".$output."], aborting!\n"; - $anvil->nice_exit({exit_code => 1}); + $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$wanted_link1_mac}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link2_nm_uuid => $link2_nm_uuid }}); + if (not $link2_nm_uuid) + { + $anvil->Job->update_progress({ + progress => 100, + message => "error_0480", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + variables => { + mac_address => $wanted_link2_mac, + interface_name => $wanted_link2_name, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + rename_interface($anvil, $wanted_link1_name, $link1_nm_uuid); } + } + } + +=cut + +* nmcli::uuid::::device = 'connection.interface-name', or 'GENERAL.DEVICES'. See note below +* nmcli::uuid::::type = interface, bond, bridge, etc +* nmcli::uuid::::active = 1,0 +* nmcli::uuid::::state = activated,activating,etc +* nmcli::uuid:::: = all 'variable: value' pairs returned by 'nmcli connection show ' +* nmcli::uuid::::mac_address = MAC address (in lower case) +* nmcli::uuid::::connected = 0 is down, unix timestamp (seconds since epoch) of when it connected if up. +* nmcli::uuid::::mtu = This is the MTU (maximum transimssion unit in bytes) of the interface. + +To make it easier to map a device by name or MAC address to a UUID, this lookup hash is provided. Note that 'device' is 'connection.interface-name' when available, falling back to 'GENERAL.DEVICES' otherwise. + +B<< NOTE >>: An inactive interface will not report the 'connection.interface-name', and the bios device name will be returned (which is what is stored in 'GENERAL.DEVICES'. If you're trying to find a device, and the expected name doesn't exist, look up the device by MAC address. If that's not found, then the old GENERAL.DEVICES name can help you identify a replaced interface. + +* nmcli::device::::uuid = interface name (or device name) +* nmcli::mac_address::::uuid = MAC address (lower case) + +Given that a single interface can have multiple IP addresses and routes, the IPs on a given interface are stored using a sequence number <1, 2, 3 ... n>. To make it easier to find what device has an IP, the IPs are stored with a quick access hash. + +* nmcli::ipv4::::on_uuid = interface UUID +* nmcli::ipv4::::sequence = sequence number +* nmcli::uuid::::ipv{4,6}::ip::::ip_address = IP address +* nmcli::uuid::::ipv{4,6}::ip::::subnet_mask = subnet mask (CIDR notation) +* nmcli::uuid::::ipv{4,6}::dns = comma-separated list of DNS IP addresses +* nmcli::uuid::::ipv{4,6}::gateway = comma-separated list of DNS IP addresses +* nmcli::uuid::::ipv{4,6}::route:: = Route info (ie: 'dst = 0.0.0.0/0, nh = 192.168.255.254, mt = 428', or 'dst = 192.168.0.0/16, nh = 0.0.0.0, mt = 428'.) + +Bond data is stored in these hashes; + +* nmcli::bond::::uuid = The UUID on the bond +* nmcli::bond::::carrier = 1,0 - indicates if the bond has a connection or not. +* nmcli::bond::::operstate = 1,0 - indicates if the bond is operational or not. +* nmcli::bond::::up = 1,0 - indicates if the bond up up or not. +* nmcli::bond::::interface::::up = 1,0 - indicates if the child interface is up or not. + +Bridge data is simple, but also made easy to find. The only real data is the hash references for the interfaces connected to the bridge. + +* nmcli::bridge::::uuid = The UUID of the bridge +* nmcli::bridge::::interface::::status = This is the link data for the connected interface (ie: 'BROADCAST,MULTICAST,MASTER,UP,LOWER_UP'). + +To make it easier to find interfaces, the following look up hash is available. + +* nmcli::interface::::uuid = The UUID of the interface +* nmcli::mac_address::::uuid = $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, + + +bcn1_ip: [10.201.4.1] +bcn1_link1_mac_to_set: [52:54:00:84:b3:2c] +bcn1_subnet_mask: [255.255.0.0] +bcn_count: [1] +dns: [8.8.8.8,8.8.4.4] +domain: [alteeve.com] +gateway: [192.168.255.254] +gateway_interface: [ifn1] +host_name: [an9-striker01.alteeve.com] +mn_count: [0] +organization: [Alteeve] +prefix: [an9] +sequence: [1] +sn_count: [0] +striker_password: [Initial1] +striker_user: [admin] +=cut + + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{config}}) + { + print $variable.": [".$anvil->data->{config}{$variable}."]\n"; + } + + return(0); +} + +sub rename_interface +{ + my ($anvil, $wanted_link_name, $nm_uuid) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + wanted_link_name => $wanted_link_name, + nm_uuid => $nm_uuid, + }}); + + my $old_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device}; + my $name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'connection.id'}; + my $mac_address = $anvil->data->{nmcli}{uuid}{$nm_uuid}{mac_address}; + my $type = $anvil->data->{nmcli}{uuid}{$nm_uuid}{type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:wanted_link_name' => $wanted_link_name, + 's2:nm_uuid' => $nm_uuid, + 's3:old_device' => $old_device, + 's4:name' => $name, + 's5:mac_address' => $mac_address, + 's6:type' => $type, + }}); + + print "Renaming old device/name: [".$old_device."/".$name."] with MAC: [".$mac_address."] to: [".$wanted_link_name."] using UUID: [".$nm_uuid."]\n"; + die; + + # Read persistent-net and see if it needs to be updated. + my $new_persistent_net = ""; + my $old_persistent_net = ""; + if (-e $anvil->data->{path}{configs}{'persistent-net'}) + { + $old_persistent_net = $anvil->Storage->read_file({debug => 2, file => $anvil->data->{path}{configs}{'persistent-net'}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_persistent_net => $old_persistent_net }}); + } + foreach my $line (split/\n/, $old_persistent_net) + { + # If this MAC or device name exists already, delete the line. + if (($line =~ /"$mac_address"/) or ($line =~ /"$wanted_link_name"/)) + { + next; + } + $new_persistent_net .= $line."\n"; + } + $new_persistent_net .= "SUBSYSTEM==\"net\",ACTION==\"add\",ATTR{address}==\"".$mac_address."\",ATTR{type}==\"".$type."\",NAME=\"".$wanted_link_name."\"\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_persistent_net => $new_persistent_net }}); + + my $difference = diff \$old_persistent_net, \$new_persistent_net, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + + # Write the new file. + if ($difference) + { + print "- Updating the udev file: [".$anvil->data->{path}{configs}{'persistent-net'}."]\n"; + my $problem = $anvil->Storage->write_file({ + file => $anvil->data->{path}{configs}{'persistent-net'}, + body => $new_persistent_net, + overwrite => 1, + user => "admin", + group => "admin", + mode => "0644", - # Set the connection.id to the old name. - print "- Setting the connection.id to the bios device name: [".$old_device."]\n"; - $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." connection.id \"".$old_device."\""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Read it back - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + if ($problem) + { + print "[ Error ] - Failed to write the new: [".$anvil->data->{path}{configs}{'persistent-net'}."] file, aborting!\n"; + $anvil->nice_exit({exit_code => 1}); } + } + + # Update the connection.interface-name + my $connection_interface_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'connection.interface-name'} ? $anvil->data->{nmcli}{uuid}{$nm_uuid}{'connection.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); + if ($connection_interface_name) + { + print "- Removing the old 'connection.interface-name': [".$connection_interface_name."]\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.interface-name \"\""; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); - # Set the reboot flag. - $anvil->data->{sys}{reboot_needed} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.interface-name connection show ".$nm_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if ($output) + { + # This should have been blank + print "[ Error ] - Failed to delete the 'connection.interface-name', got: [".$output."] and it should bhave been blank, aborting!\n"; + $anvil->nice_exit({exit_code => 1}); + } } - if ($anvil->data->{sys}{reboot_needed}) + # We'll log what it was, and change it anyway + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'match.interface-name'} ? $anvil->data->{nmcli}{uuid}{$nm_uuid}{'match.interface-name'} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); + if (1) { - print "Reboot needed.\n"; - print "- Regenerating dracute initrd image, this can take a moment...\n"; - my $shell_call = $anvil->data->{path}{exe}{dracut}." --force"; + print "- Matching the new interface name: [".$wanted_link_name."] to the bios device name: [".$old_device."]\n"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." match.interface-name \"".$wanted_link_name." ".$old_device."\""; $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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); - print "- New initrd image created.\n"; - print "[ Note ] - Reboot needed. Re-run this after the reboot to complete setup.\n"; - print "- Rebooting in 60 seconds (press 'ctrl + c' to abort).\n"; - my $timeout = 60; - while($timeout) + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$nm_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if (($output ne $wanted_link_name.",".$old_device) && ($output ne $old_device.",".$wanted_link_name)) { - if ($timeout % 10) - { - print "." - } - else - { - print $timeout; - } - sleep 1; - $timeout--; + # This should have been blank + print "[ Error ] - Failed to create the 'match.interface-name' value. Expected: [".$wanted_link_name.",".$old_device."], got: [".$output."], aborting!\n"; + $anvil->nice_exit({exit_code => 1}); } - print "0\n"; - print "Rebooting NOW!\n"; - $shell_call = $anvil->data->{path}{exe}{systemctl}." reboot"; + # Set the connection.id to the old name. + print "- Setting the connection.id to the bios device name: [".$old_device."]\n"; + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.id \"".$old_device."\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$nm_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($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 }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); } + # Set the reboot flag. + $anvil->data->{sys}{reboot_needed} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); + + return(0); } @@ -865,13 +1020,16 @@ sub configure_ifcfg_network my ($anvil, $network_type) = @_; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); +=cut 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; } elsif ($network_type eq "mn") { $count = $mn_count; } + my $localhost = $anvil->Get->short_host_name(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + next if not $count; foreach my $network_count (1..$count) { @@ -1727,88 +1885,89 @@ sub configure_ifcfg_network next; } } +=cut 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 $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$old_link_name." down"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Rename - $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, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Bring up the new interface - $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$new_link_name." up"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - return(0); -} +# 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 $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$old_link_name." down"; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); +# my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { +# output => $output, +# return_code => $return_code, +# }}); +# +# # Rename +# $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, list => { shell_call => $shell_call }}); +# ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { +# output => $output, +# return_code => $return_code, +# }}); +# +# # Bring up the new interface +# $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$new_link_name." up"; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); +# ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, 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); -} +# 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 From 71735947dc8859e8e044f0d525a361df3697b2fd Mon Sep 17 00:00:00 2001 From: digimer Date: Mon, 8 Jan 2024 02:18:27 -0500 Subject: [PATCH 15/43] Created Job->bump_progress() to make advancing job progress easier * Updated Network->collect_data() to find the GENERAL.DEVICES and GENERAL.IP-IFACE from match.interface-name when the link is down. * More work done on anvil-configure-host. Signed-off-by: digimer --- Anvil/Tools/Job.pm | 79 ++++ Anvil/Tools/Network.pm | 31 +- share/words.xml | 12 + tools/anvil-configure-host | 728 ++++++++++++++++++++++++++----------- 4 files changed, 641 insertions(+), 209 deletions(-) diff --git a/Anvil/Tools/Job.pm b/Anvil/Tools/Job.pm index 37df8cac..09ba32a4 100644 --- a/Anvil/Tools/Job.pm +++ b/Anvil/Tools/Job.pm @@ -12,6 +12,7 @@ our $VERSION = "3.0.0"; my $THIS_FILE = "Job.pm"; ### Methods; +# bump_progress # clear # get_job_details # get_job_uuid @@ -80,6 +81,84 @@ sub parent # Public methods # ############################################################################################################# +=head2 bump_progress + +This method is meant to make it easier to bump the progress of a jump by some number of steps when a job doesn't run in a linear fashion. + +It does this by storing the progress in the C<< sys::job_progress >> hash and incrementing it by the C<< steps >> parameter value (setting it to C<< 0 >> if it doesn't exist or exists with a non-digit value). If the progress goes over C<< 99 >>, it will return C<< 99 >>. + +If you want to set the progress to C<< 0 >> or C<< 100 >>, use the C<< set >> parameter. + +Parameters; + +=head3 set (optional) + +If you want to set the progress to a specific value, use this parameter. + +B<< NOTE >>: If the set value is less than the current value, the current progress + 1 will be returns. This is meant to prevent progress bars from backing up. + +=head3 steps (default '1') + +This takes an integer and it will increase the job progress by that value. If this is not specified, or if it is set to a non-integer value, C<< 1 >> will be used. + +=cut +sub bump_progress +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Job->bump_progress()" }}); + + my $set = defined $parameter->{set} ? $parameter->{set} : ""; + my $steps = defined $parameter->{steps} ? $parameter->{steps} : 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + set => $set, + steps => $steps, + }}); + + if ((not exists $anvil->data->{sys}{job_progress}) or ($anvil->data->{sys}{job_progress} !~ /^\d+$/)) + { + $anvil->data->{sys}{job_progress} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + } + + if ($set =~ /^\d+$/) + { + if ($set > 100) + { + $anvil->data->{sys}{job_progress} = 100; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + } + elsif ($set > $anvil->data->{sys}{job_progress}) + { + $anvil->data->{sys}{job_progress}++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + } + } + + $anvil->data->{sys}{job_progress} += $steps; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + if ($anvil->data->{sys}{job_progress} > 99) + { + $anvil->data->{sys}{job_progress} = 99; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::job_progress" => $anvil->data->{sys}{job_progress}, + }}); + } + + return($anvil->data->{sys}{job_progress}); +} + + =head2 clear This clears the C<< job_picked_up_by >> value for the given job. diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 10fa570e..612aa053 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -1170,18 +1170,41 @@ sub collect_data # Now loop through and look for the name that maps to what's shown in 'ip addr list'. This can be a bit tricky. foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) { + my $connection_id = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.id'} // ""; my $connection_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'} // ""; my $general_devices = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.DEVICES'} // ""; my $general_ip_iface = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.IP-IFACE'} // ""; my $device_type = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.type'} // ""; + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'match.interface-name'} // ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:uuid' => $uuid, - 's2:connection_interface_name' => $connection_interface_name, - 's3:general_devices' => $general_devices, - 's4:general_ip_iface' => $general_ip_iface, - 's5:device_type' => $device_type, + 's2:connection_id' => $connection_id, + 's3:connection_interface_name' => $connection_interface_name, + 's4:general_devices' => $general_devices, + 's5:general_ip_iface' => $general_ip_iface, + 's6:device_type' => $device_type, + 's7:match_interface_name' => $match_interface_name, }}); + # If there isn't a GENERAL.DEVICES or GENERAL.IP-IFACE, the link is down. Use the match.interface-name. + if (((not $general_devices) or (not $general_ip_iface)) && ($match_interface_name)) + { + foreach my $interface (split/,/, $match_interface_name) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface }}); + next if $connection_id eq $interface; + if ($interface) + { + $general_devices = $interface if not $general_devices; + $general_ip_iface = $interface if not $general_ip_iface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + general_devices => $general_devices, + general_ip_iface => $general_ip_iface, + }}); + } + } + } + my $device = ""; if (($general_ip_iface) && ($general_ip_iface ne "--")) { diff --git a/share/words.xml b/share/words.xml index f730b77a..b31899e8 100644 --- a/share/words.xml +++ b/share/words.xml @@ -753,6 +753,8 @@ The XML that failed sanity check was: [ Error ] - This program must be run on a subnode. [ Error ] - This subnode is not in the cluster (failed to parse the CIB). Exiting. [ Error ] - The wanted interface: [#!variable!interface_name!#] which should have the MAC address: [#!variable!mac_address!#] was not found in Network Manager. Unable to proceed. + [ Error ] - Failed to delete the 'connection.interface-name', got: [#!variable!output!#] and it should bhave been blank, aborting! + [ Error ] - Failed to create the 'match.interface-name' value. Expected: [#!variable!new_name!#,#!variable!old_device!#], got: [#!variable!output!#], aborting! @@ -3285,6 +3287,16 @@ proceeding. - Threads per Core: [#!variable!old_threads!#] -> [#!variable!new_threads!#] - Total Cores: .... [#!variable!old_total_cores!#] -> [#!variable!new_total_cores!#]]]> + ' to exit]]> + Renaming old device/name: [#!variable!old_device!#/#!variable!old_name!#] with MAC: [#!variable!mac_address!#] to: [#!variable!new_name!#] using UUID: [#!variable!nm_uuid!#]. + - Updating the udev file: [#!variable!file!#]. + - Removing the old 'connection.interface-name': [#!variable!name!#]. + - Matching the new interface name: [#!variable!new_name!#] to the bios device name: [#!variable!old_device!#]. + - Setting the connection.id to the bios device name: [#!variable!old_device!#] + The new interface names need a reboot to take effect. + Rebooting NOW! The job will restart on reboot. + Checking if the bond: [#!variable!bond_name!#] exists or not. + - It does, its UUID is: [#!variable!nm_uuid!#]. + - The bond: [#!variable!bond_name!#] doesn't exist. Will create it using the primary interface: [#!variable!link1_name!#] (MAC: [#!variable!link1_mac!#], NM UUID: [#!variable!link1_nm_uuid!#) and the backup interface: : [#!variable!link2_name!#] (MAC: [#!variable!link2_mac!#], NM UUID: [#!variable!link2_nm_uuid!#). Normal Password diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index b210d7d3..18fc0479 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -83,10 +83,9 @@ $anvil->Database->insert_or_update_variables({ update_passwords($anvil); $anvil->Job->update_progress({ - debug => 3, - progress => 100, - message => "", - job_uuid => $anvil->data->{job}{uuid}, + progress => 100, + message => "", + job_uuid => $anvil->data->{job}{uuid}, }); # Clear maintenance mode. @@ -113,28 +112,38 @@ sub do_reboot { my ($anvil) = @_; -### TODO: Nothing should be killing us, anything that could should be updated to hold while we run. -# # Mark that a reboot is needed, in case something kills us before we actually reboot. -# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0687", variables => { reason => "#!string!log_0693!#" }}); -# my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ -# file => $THIS_FILE, -# line => __LINE__, -# job_command => $anvil->data->{path}{exe}{'anvil-manage-power'}." --reboot -y".$anvil->Log->switches, -# job_data => "", -# job_name => "reboot::system", -# job_title => "job_0009", -# job_description => "job_0006", -# job_progress => 0, -# }); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); - + # Tell the user why we're rebooting + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 10}), + message => "message_0388", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + }); my $time_left = 60; while ($time_left) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0626", variables => { seconds => $time_left }}); + # Give them the countdown. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 10}), + message => "log_0626", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + variables => { seconds => $time_left }, + }); sleep 10; $time_left -= 10; } + + # Last, log that we're going down now. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 10}), + message => "message_0389", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + }); 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__}); @@ -174,7 +183,15 @@ sub update_passwords 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->Job->update_progress({ + progress => 100, + message => "message_0030", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { file => $temp_file }, + }); $anvil->nice_exit({exit_code => 5}); } else @@ -237,18 +254,17 @@ sub reconfigure_network { my ($anvil) = @_; - my $reboot_needed = 0; - my $local_host = $anvil->Get->short_host_name(); - my $prefix = $anvil->data->{config}{prefix}; - my $sequence = $anvil->data->{config}{sequence}; - my $domain = $anvil->data->{config}{domain}; - my $new_host_name = $anvil->data->{config}{host_name}; - my $organization = $anvil->data->{config}{organization}; - my $bcn_count = $anvil->data->{config}{bcn_count}; - my $ifn_count = $anvil->data->{config}{ifn_count}; - my $sn_count = $anvil->data->{config}{sn_count}; - my $mn_count = $anvil->data->{config}{mn_count}; - my $type = $anvil->Get->host_type(); + my $local_host = $anvil->Get->short_host_name(); + my $prefix = $anvil->data->{config}{prefix}; + my $sequence = $anvil->data->{config}{sequence}; + my $domain = $anvil->data->{config}{domain}; + my $new_host_name = $anvil->data->{config}{host_name}; + my $organization = $anvil->data->{config}{organization}; + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { prefix => $prefix, sequence => $sequence, @@ -304,24 +320,29 @@ sub reconfigure_network { # Success $anvil->Job->update_progress({ - progress => 10, - message => "message_0016,!!host_name!$new_host_name!!", - job_uuid => $anvil->data->{job}{uuid}, + progress => $anvil->Job->bump_progress({set => 10}), + message => "message_0016", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + variables => { host_name => $new_host_name }, }); - $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}, + progress => 100, + message => "message_0017", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + job_status => "failed", + variables => { + host_name => $new_host_name, + bad_host_name => $host_name, + }, }); - $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}); } } @@ -458,17 +479,17 @@ ORDER BY else { # Fail out! - my $variables = { - mac_address => $variable_value, - iface1 => $macs->{$variable_value}, - iface2 => $device, - }; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "error_0376", variables => $variables}); $anvil->Job->update_progress({ progress => 100, message => "error_0376", - variables => $variables, job_status => "failed", + 'print' => 1, + log_level => 1, + variables => { + mac_address => $variable_value, + iface1 => $macs->{$variable_value}, + iface2 => $device, + }, }); $anvil->nice_exit({exit_code => 8}); } @@ -500,9 +521,9 @@ ORDER BY else { # Configure the network using Network Manager - reconfigure_bridges($anvil); - reconfigure_bonds($anvil); reconfigure_interfaces($anvil); + reconfigure_bonds($anvil); + reconfigure_bridges($anvil); reconfigure_ip_addresses($anvil); } die; @@ -571,7 +592,7 @@ ORDER BY # We're half-way there. $anvil->Job->update_progress({ - progress => 50, + progress => $anvil->Job->bump_progress({set => 50}), job_uuid => $anvil->data->{job}{uuid}, }); @@ -654,7 +675,7 @@ ORDER BY } $anvil->Job->update_progress({ - progress => 75, + progress => $anvil->Job->bump_progress({set => 75}), job_uuid => $anvil->data->{job}{uuid}, }); @@ -671,8 +692,278 @@ sub reconfigure_bridges sub reconfigure_bonds { - my ($anvil) = @_; + my ($anvil, $wanted_link_name, $nm_uuid) = @_; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + wanted_link_name => $wanted_link_name, + nm_uuid => $nm_uuid, + }}); + + my $local_host = $anvil->Get->short_host_name(); + my $prefix = $anvil->data->{config}{prefix}; + my $sequence = $anvil->data->{config}{sequence}; + my $domain = $anvil->data->{config}{domain}; + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + prefix => $prefix, + sequence => $sequence, + domain => $domain, + type => $type, + }}); + foreach my $network_type ("bcn", "sn", "mn", "ifn") + { + $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; } + elsif ($network_type eq "mn") { $count = $mn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + # This is the old type of network config + foreach my $i (1..$count) + { + my $bond_name = $network_type.$i."_bond1"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_name => $bond_name }}); + + # Skip if this isn't marked to become a bond. + next if not exists $anvil->data->{config}{$bond_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + }}); + + # Check if the bond exists or not. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 10}), + message => "message_0390", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + variables => { bond_name => $bond_name }, + }); + if (exists $anvil->data->{nmcli}{bond}{$bond_name}) + { + # It does. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 10}), + message => "message_0391", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + variables => { nm_uuid => $anvil->data->{nmcli}{bond}{$bond_name}{uuid} }, + }); + } + else + { + # It doesn't, create it. + my $link1_name = $network_type.$i."_link1"; + my $link1_mac_key = $network_type.$i."_link1_mac_to_set"; + my $link1_mac = $anvil->data->{config}{$link1_mac_key}; + my $link1_nm_uuid = $anvil->data->{nmcli}{mac_address}{$link1_mac}{uuid}; + + my $link2_name = $network_type.$i."_link2"; + my $link2_mac_key = $network_type.$i."_link2_mac_to_set"; + my $link2_mac = $anvil->data->{config}{$link2_mac_key}; + my $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$link2_mac}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + link1_name => $link1_name, + link1_mac_key => $link1_mac_key, + link1_mac => $link1_mac, + link1_nm_uuid => $link1_nm_uuid, + link2_name => $link2_name, + link2_mac_key => $link2_mac_key, + link2_mac => $link2_mac, + link2_nm_uuid => $link2_nm_uuid, + }}); + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 10}), + message => "message_0392", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + variables => { + bond_name => $bond_name, + link1_name => $link1_name, + link1_mac => $link1_mac, + link1_nm_uuid => $link1_nm_uuid, + link2_name => $link2_name, + link2_mac => $link2_mac, + link2_nm_uuid => $link2_nm_uuid, + }, + }); + die; + + +# my $primary_interface = $anvil->data->{network_manager}{want}{bond}{$bond_name}{interfaces}->[0]; +# if (not $primary_interface) +# { +# print "[ Error ] - There appears to be no primary interface specified for this bond!\n"; +# $anvil->nice_exit({exit_code => 1}); +# } +# print "- It does not, creating it with the primary interface: [".$primary_interface."] now.\n"; +# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bond con-name ".$bond_name." ifname ".$bond_name." bond.options \"mode=active-backup,miimon=100,downdelay=0,updelay=120000,primary=".$primary_interface."\""; +# $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}); +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { +# output => $output, +# return_code => $return_code, +# }}); +# +# if ($return_code) +# { +# print "[ Error ] - The attempt to add the bond failed! The return code was: [".$return_code."]. The output, if any, was:\n"; +# print "========\n"; +# print $output."\n"; +# print "========\n"; +# $anvil->nice_exit({exit_code => 1}); +# } +# +# my $bond_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); +# +# if ($bond_uuid) +# { +# print " - Disabling DHCP on the new bond device: [".$bond_uuid."].\n"; +# my ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv4.method", "disabled"); +# ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv6.method", "disabled"); +# +# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bond_name; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); +# ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { +# output => $output, +# return_code => $return_code, +# }}); +# } +# +# # Rescan. +# print " - Done! Rescanning the network config.\n"; +# collect_data($anvil); + } + + # Now add the interfaces, disabling their ipv4.method first. +# foreach my $interface_name (@{$anvil->data->{network_manager}{want}{bond}{$bond_name}{interfaces}}) +# { +# # What is the interface UUID? +# my $interface_uuid = $anvil->data->{interface}{device}{$interface_name}{uuid}; +# my $parent_bond_name = $anvil->data->{interface}{uuid}{$interface_uuid}{'connection.master'}; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { +# interface_name => $interface_name, +# interface_uuid => $interface_uuid, +# parent_bond_name => $parent_bond_name, +# }}); +# if ($parent_bond_name eq "--") +# { +# $parent_bond_name = ""; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { parent_bond_name => $parent_bond_name }}); +# } +# +# if ($parent_bond_name) +# { +# if ($parent_bond_name eq $bond_name) +# { +# print "- The interface: [".$interface_name."] (".$interface_uuid.") is already a member of the bond.\n"; +# next; +# } +# else +# { +# print "- The interface: [".$interface_name."] (".$interface_uuid.") is a member of the bond: [".$parent_bond_name."], switching it to this bond.\n"; +# } +# } +# else +# { +# print "- The interface: [".$interface_name."] (".$interface_uuid.") needs to be connected to the bond.\n"; +# } +# +# print " - Disabling DHCP on the interface\n"; +# my ($output, $return_code) = modify_connection($anvil, $interface_uuid, "ipv4.method", "disabled"); +# ($output, $return_code) = modify_connection($anvil, $interface_uuid, "ipv6.method", "disabled"); +# +# print " - Connecting the interface to the bond.\n"; +# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$interface_uuid." connection.master ".$bond_name." connection.slave-type bond"; +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); +# ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); +# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { +# output => $output, +# return_code => $return_code, +# }}); +# +# if ($return_code) +# { +# print "[ Error ] - The attempt to add the bond failed! The return code was: [".$return_code."]. The output, if any, was:\n"; +# print "========\n"; +# print $output."\n"; +# print "========\n"; +# $anvil->nice_exit({exit_code => 1}); +# } +# +# # Rescan. +# print " - Done! Rescanning the network config.\n"; +# ($output, $return_code) = reset_connection($anvil, $interface_uuid); +# +# # Rescan. +# collect_data($anvil); +# } + } + } +=cut + +* nmcli::uuid::::device = 'connection.interface-name', or 'GENERAL.DEVICES'. See note below +* nmcli::uuid::::type = interface, bond, bridge, etc +* nmcli::uuid::::active = 1,0 +* nmcli::uuid::::state = activated,activating,etc +* nmcli::uuid:::: = all 'variable: value' pairs returned by 'nmcli connection show ' +* nmcli::uuid::::mac_address = MAC address (in lower case) +* nmcli::uuid::::connected = 0 is down, unix timestamp (seconds since epoch) of when it connected if up. +* nmcli::uuid::::mtu = This is the MTU (maximum transimssion unit in bytes) of the interface. + +To make it easier to map a device by name or MAC address to a UUID, this lookup hash is provided. Note that 'device' is 'connection.interface-name' when available, falling back to 'GENERAL.DEVICES' otherwise. + +B<< NOTE >>: An inactive interface will not report the 'connection.interface-name', and the bios device name will be returned (which is what is stored in 'GENERAL.DEVICES'. If you're trying to find a device, and the expected name doesn't exist, look up the device by MAC address. If that's not found, then the old GENERAL.DEVICES name can help you identify a replaced interface. + +* nmcli::device::::uuid = interface name (or device name) +* nmcli::mac_address::::uuid = MAC address (lower case) + +Given that a single interface can have multiple IP addresses and routes, the IPs on a given interface are stored using a sequence number <1, 2, 3 ... n>. To make it easier to find what device has an IP, the IPs are stored with a quick access hash. + +* nmcli::ipv4::::on_uuid = interface UUID +* nmcli::ipv4::::sequence = sequence number +* nmcli::uuid::::ipv{4,6}::ip::::ip_address = IP address +* nmcli::uuid::::ipv{4,6}::ip::::subnet_mask = subnet mask (CIDR notation) +* nmcli::uuid::::ipv{4,6}::dns = comma-separated list of DNS IP addresses +* nmcli::uuid::::ipv{4,6}::gateway = comma-separated list of DNS IP addresses +* nmcli::uuid::::ipv{4,6}::route:: = Route info (ie: 'dst = 0.0.0.0/0, nh = 192.168.255.254, mt = 428', or 'dst = 192.168.0.0/16, nh = 0.0.0.0, mt = 428'.) + +Bond data is stored in these hashes; + +* nmcli::bond::::uuid = The UUID on the bond +* nmcli::bond::::carrier = 1,0 - indicates if the bond has a connection or not. +* nmcli::bond::::operstate = 1,0 - indicates if the bond is operational or not. +* nmcli::bond::::up = 1,0 - indicates if the bond up up or not. +* nmcli::bond::::interface::::up = 1,0 - indicates if the child interface is up or not. + +Bridge data is simple, but also made easy to find. The only real data is the hash references for the interfaces connected to the bridge. + +* nmcli::bridge::::uuid = The UUID of the bridge +* nmcli::bridge::::interface::::status = This is the link data for the connected interface (ie: 'BROADCAST,MULTICAST,MASTER,UP,LOWER_UP'). + +To make it easier to find interfaces, the following look up hash is available. + +* nmcli::interface::::uuid = The UUID of the interface +* nmcli::mac_address::::uuid = $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, + + +=cut + + foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{config}}) + { + print $variable.": [".$anvil->data->{config}{$variable}."]\n"; + } return(0); } @@ -690,16 +981,15 @@ sub reconfigure_interfaces { my ($anvil) = @_; - my $reboot_needed = 0; - my $local_host = $anvil->Get->short_host_name(); - my $prefix = $anvil->data->{config}{prefix}; - my $sequence = $anvil->data->{config}{sequence}; - my $domain = $anvil->data->{config}{domain}; - my $bcn_count = $anvil->data->{config}{bcn_count}; - my $ifn_count = $anvil->data->{config}{ifn_count}; - my $sn_count = $anvil->data->{config}{sn_count}; - my $mn_count = $anvil->data->{config}{mn_count}; - my $type = $anvil->Get->host_type(); + my $local_host = $anvil->Get->short_host_name(); + my $prefix = $anvil->data->{config}{prefix}; + my $sequence = $anvil->data->{config}{sequence}; + my $domain = $anvil->data->{config}{domain}; + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $type = $anvil->Get->host_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { local_host => $local_host, prefix => $prefix, @@ -728,6 +1018,11 @@ sub reconfigure_interfaces link2_mac_key => $link2_mac_key, }}); + # If the user had the option to create a network but didn't, there will be no link1 + # mac to set. + next if not exists $anvil->data->{config}{$link1_mac_key}; + next if not $anvil->data->{config}{$link1_mac_key}; + my $wanted_link1_name = $network_type.$i."_link1"; my $wanted_link1_mac = $anvil->data->{config}{$link1_mac_key}; my $wanted_link2_name = $network_type.$i."_link2"; @@ -747,12 +1042,13 @@ sub reconfigure_interfaces if (not $link1_nm_uuid) { $anvil->Job->update_progress({ - progress => 100, - message => "error_0480", - log_leve => 1, - 'print' => 1, - job_uuid => $anvil->data->{job}{uuid}, - variables => { + progress => 100, + message => "error_0480", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { mac_address => $wanted_link1_mac, interface_name => $wanted_link1_name, }, @@ -769,91 +1065,35 @@ sub reconfigure_interfaces if (not $link2_nm_uuid) { $anvil->Job->update_progress({ - progress => 100, - message => "error_0480", - log_leve => 1, - 'print' => 1, - job_uuid => $anvil->data->{job}{uuid}, - variables => { + progress => 100, + message => "error_0480", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { mac_address => $wanted_link2_mac, interface_name => $wanted_link2_name, }, }); $anvil->nice_exit({exit_code => 1}); } - rename_interface($anvil, $wanted_link1_name, $link1_nm_uuid); + rename_interface($anvil, $wanted_link2_name, $link2_nm_uuid); + + # There's a second interface, so create a bond. + my $bond_name = $network_type.$i."_bond1"; + $anvil->data->{config}{$bond_name} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + }}); } } } -=cut - -* nmcli::uuid::::device = 'connection.interface-name', or 'GENERAL.DEVICES'. See note below -* nmcli::uuid::::type = interface, bond, bridge, etc -* nmcli::uuid::::active = 1,0 -* nmcli::uuid::::state = activated,activating,etc -* nmcli::uuid:::: = all 'variable: value' pairs returned by 'nmcli connection show ' -* nmcli::uuid::::mac_address = MAC address (in lower case) -* nmcli::uuid::::connected = 0 is down, unix timestamp (seconds since epoch) of when it connected if up. -* nmcli::uuid::::mtu = This is the MTU (maximum transimssion unit in bytes) of the interface. - -To make it easier to map a device by name or MAC address to a UUID, this lookup hash is provided. Note that 'device' is 'connection.interface-name' when available, falling back to 'GENERAL.DEVICES' otherwise. - -B<< NOTE >>: An inactive interface will not report the 'connection.interface-name', and the bios device name will be returned (which is what is stored in 'GENERAL.DEVICES'. If you're trying to find a device, and the expected name doesn't exist, look up the device by MAC address. If that's not found, then the old GENERAL.DEVICES name can help you identify a replaced interface. - -* nmcli::device::::uuid = interface name (or device name) -* nmcli::mac_address::::uuid = MAC address (lower case) - -Given that a single interface can have multiple IP addresses and routes, the IPs on a given interface are stored using a sequence number <1, 2, 3 ... n>. To make it easier to find what device has an IP, the IPs are stored with a quick access hash. - -* nmcli::ipv4::::on_uuid = interface UUID -* nmcli::ipv4::::sequence = sequence number -* nmcli::uuid::::ipv{4,6}::ip::::ip_address = IP address -* nmcli::uuid::::ipv{4,6}::ip::::subnet_mask = subnet mask (CIDR notation) -* nmcli::uuid::::ipv{4,6}::dns = comma-separated list of DNS IP addresses -* nmcli::uuid::::ipv{4,6}::gateway = comma-separated list of DNS IP addresses -* nmcli::uuid::::ipv{4,6}::route:: = Route info (ie: 'dst = 0.0.0.0/0, nh = 192.168.255.254, mt = 428', or 'dst = 192.168.0.0/16, nh = 0.0.0.0, mt = 428'.) - -Bond data is stored in these hashes; - -* nmcli::bond::::uuid = The UUID on the bond -* nmcli::bond::::carrier = 1,0 - indicates if the bond has a connection or not. -* nmcli::bond::::operstate = 1,0 - indicates if the bond is operational or not. -* nmcli::bond::::up = 1,0 - indicates if the bond up up or not. -* nmcli::bond::::interface::::up = 1,0 - indicates if the child interface is up or not. - -Bridge data is simple, but also made easy to find. The only real data is the hash references for the interfaces connected to the bridge. - -* nmcli::bridge::::uuid = The UUID of the bridge -* nmcli::bridge::::interface::::status = This is the link data for the connected interface (ie: 'BROADCAST,MULTICAST,MASTER,UP,LOWER_UP'). - -To make it easier to find interfaces, the following look up hash is available. - -* nmcli::interface::::uuid = The UUID of the interface -* nmcli::mac_address::::uuid = $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, - - -bcn1_ip: [10.201.4.1] -bcn1_link1_mac_to_set: [52:54:00:84:b3:2c] -bcn1_subnet_mask: [255.255.0.0] -bcn_count: [1] -dns: [8.8.8.8,8.8.4.4] -domain: [alteeve.com] -gateway: [192.168.255.254] -gateway_interface: [ifn1] -host_name: [an9-striker01.alteeve.com] -mn_count: [0] -organization: [Alteeve] -prefix: [an9] -sequence: [1] -sn_count: [0] -striker_password: [Initial1] -striker_user: [admin] -=cut - - foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{config}}) + # There is no way (that we've found) to get the network interface ames to be updated without a reboot. + if ($anvil->data->{sys}{reboot_needed}) { - print $variable.": [".$anvil->data->{config}{$variable}."]\n"; + do_reboot($anvil); } return(0); @@ -880,8 +1120,21 @@ sub rename_interface 's6:type' => $type, }}); - print "Renaming old device/name: [".$old_device."/".$name."] with MAC: [".$mac_address."] to: [".$wanted_link_name."] using UUID: [".$nm_uuid."]\n"; - die; + # Tell the user what we're about to rename + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0383", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + variables => { + mac_address => $mac_address, + old_device => $old_device, + old_name => $name, + new_name => $wanted_link_name, + nm_uuid => $nm_uuid, + }, + }); # Read persistent-net and see if it needs to be updated. my $new_persistent_net = ""; @@ -909,7 +1162,15 @@ sub rename_interface # Write the new file. if ($difference) { - print "- Updating the udev file: [".$anvil->data->{path}{configs}{'persistent-net'}."]\n"; + # Updating the udev file + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0384", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + variables => { file => $anvil->data->{path}{configs}{'persistent-net'} }, + }); my $problem = $anvil->Storage->write_file({ file => $anvil->data->{path}{configs}{'persistent-net'}, body => $new_persistent_net, @@ -922,7 +1183,16 @@ sub rename_interface $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); if ($problem) { - print "[ Error ] - Failed to write the new: [".$anvil->data->{path}{configs}{'persistent-net'}."] file, aborting!\n"; + # Failed to write the udev file + $anvil->Job->update_progress({ + progress => 100, + message => "error_0043", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { file => $anvil->data->{path}{configs}{'persistent-net'} }, + }); $anvil->nice_exit({exit_code => 1}); } } @@ -932,7 +1202,15 @@ sub rename_interface $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_interface_name => $connection_interface_name }}); if ($connection_interface_name) { - print "- Removing the old 'connection.interface-name': [".$connection_interface_name."]\n"; + # Removing the old 'connection.interface-name' + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0385", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + variables => { name => $connection_interface_name }, + }); my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.interface-name \"\""; $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}); @@ -951,8 +1229,16 @@ sub rename_interface if ($output) { - # This should have been blank - print "[ Error ] - Failed to delete the 'connection.interface-name', got: [".$output."] and it should bhave been blank, aborting!\n"; + # Failed to delete the 'connection.interface-name', This should have been blank + $anvil->Job->update_progress({ + progress => 100, + message => "error_0481", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { output => $output }, + }); $anvil->nice_exit({exit_code => 1}); } } @@ -960,58 +1246,86 @@ sub rename_interface # We'll log what it was, and change it anyway my $match_interface_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'match.interface-name'} ? $anvil->data->{nmcli}{uuid}{$nm_uuid}{'match.interface-name'} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); - if (1) + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0386", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + variables => { + new_name => $wanted_link_name, + old_device => $old_device, + }, + }); + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." match.interface-name \"".$wanted_link_name." ".$old_device."\""; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$nm_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if (($output ne $wanted_link_name.",".$old_device) && ($output ne $old_device.",".$wanted_link_name)) { - print "- Matching the new interface name: [".$wanted_link_name."] to the bios device name: [".$old_device."]\n"; - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." match.interface-name \"".$wanted_link_name." ".$old_device."\""; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Read it back - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values match.interface-name connection show ".$nm_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - if (($output ne $wanted_link_name.",".$old_device) && ($output ne $old_device.",".$wanted_link_name)) - { - # This should have been blank - print "[ Error ] - Failed to create the 'match.interface-name' value. Expected: [".$wanted_link_name.",".$old_device."], got: [".$output."], aborting!\n"; - $anvil->nice_exit({exit_code => 1}); - } - - # Set the connection.id to the old name. - print "- Setting the connection.id to the bios device name: [".$old_device."]\n"; - $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.id \"".$old_device."\""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Read it back - $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$nm_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + # This should have been blank + $anvil->Job->update_progress({ + progress => 100, + message => "error_0482", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + new_name => $wanted_link_name, + old_device => $old_device, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); } + # Set the connection.id to the old name. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0387", + log_leve => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + variables => { old_device => $old_device }, + }); + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.id \"".$old_device."\""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Read it back + $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values connection.id connection show ".$nm_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Re-read the updated data + $anvil->Network->collect_data({debug => 2}); + # Set the reboot flag. $anvil->data->{sys}{reboot_needed} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::reboot_needed" => $anvil->data->{sys}{reboot_needed} }}); - return(0); } @@ -2120,9 +2434,11 @@ AND # Record that we've picked up this job. $anvil->Job->update_progress({ - progress => 1, - message => "message_0015", - job_uuid => $anvil->data->{job}{uuid}, + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0015", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, }); # If we're in a cluster, abort. @@ -2139,11 +2455,13 @@ AND { # We're in a cluster, abort. $anvil->Job->update_progress({ - progress => 100, - message => "error_0250", - job_uuid => $anvil->data->{job}{uuid}, + progress => 100, + message => "error_0250", + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + 'print' => 1, + log_level => 1, }); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0250"}); $anvil->nice_exit({exit_code => 7}); } } From 92ddf279792a4145752fb48caa80b2a7d954bc5b Mon Sep 17 00:00:00 2001 From: digimer Date: Mon, 8 Jan 2024 23:22:06 -0500 Subject: [PATCH 16/43] Fixed bugs, got X_link2 interfaces configuring properly now Signed-off-by: digimer --- tools/anvil-configure-host | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 18fc0479..f869673d 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -186,7 +186,7 @@ sub update_passwords $anvil->Job->update_progress({ progress => 100, message => "message_0030", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", @@ -1044,7 +1044,7 @@ sub reconfigure_interfaces $anvil->Job->update_progress({ progress => 100, message => "error_0480", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", @@ -1058,16 +1058,16 @@ sub reconfigure_interfaces rename_interface($anvil, $wanted_link1_name, $link1_nm_uuid); my $link2_nm_uuid = ""; - if ($link2_nm_uuid) + if ($wanted_link2_mac) { - $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$wanted_link1_mac}{uuid}; + $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$wanted_link2_mac}{uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link2_nm_uuid => $link2_nm_uuid }}); if (not $link2_nm_uuid) { $anvil->Job->update_progress({ progress => 100, message => "error_0480", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", @@ -1090,6 +1090,8 @@ sub reconfigure_interfaces } } + die; + # There is no way (that we've found) to get the network interface ames to be updated without a reboot. if ($anvil->data->{sys}{reboot_needed}) { @@ -1124,7 +1126,7 @@ sub rename_interface $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0383", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, variables => { @@ -1166,7 +1168,7 @@ sub rename_interface $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0384", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, variables => { file => $anvil->data->{path}{configs}{'persistent-net'} }, @@ -1187,7 +1189,7 @@ sub rename_interface $anvil->Job->update_progress({ progress => 100, message => "error_0043", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", @@ -1206,7 +1208,7 @@ sub rename_interface $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0385", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, variables => { name => $connection_interface_name }, @@ -1233,7 +1235,7 @@ sub rename_interface $anvil->Job->update_progress({ progress => 100, message => "error_0481", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", @@ -1249,7 +1251,7 @@ sub rename_interface $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0386", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, variables => { @@ -1257,6 +1259,13 @@ sub rename_interface old_device => $old_device, }, }); + + if ($old_device eq $wanted_link_name) + { + print "Both the netbios name: [".$wanted_link_name."], IP device name: [".$old_device."] are the same, match would break!\n"; + die; + } + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." match.interface-name \"".$wanted_link_name." ".$old_device."\""; $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}); @@ -1280,7 +1289,7 @@ sub rename_interface $anvil->Job->update_progress({ progress => 100, message => "error_0482", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", @@ -1297,7 +1306,7 @@ sub rename_interface $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0387", - log_leve => 1, + log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, variables => { old_device => $old_device }, From 83057d0b454b0e467fff2ab8f35a8c544f119861 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 10 Jan 2024 21:17:05 -0500 Subject: [PATCH 17/43] Fixed several bugs around renaming interfaces * Also fixed problems with scan-network related to the new network naming / NM system. * Updated Database->insert_or_update_network_interfaces() to better search for a network_interface_uuid when not specified. * Updated Network->collect_data() to take the new 'start' parameter which, when set, brings up unconfigured connections/devices. Signed-off-by: digimer --- Anvil/Tools/Database.pm | 62 +++ Anvil/Tools/Network.pm | 518 +++++++++++------- scancore-agents/scan-network/scan-network | 233 ++++++-- scancore-agents/scan-network/scan-network.xml | 2 + tools/anvil-configure-host | 101 +++- 5 files changed, 644 insertions(+), 272 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index ac8069c0..1f32f81e 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -11601,6 +11601,68 @@ AND $network_interface_uuid = $results->[0]->[0]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }}); } + elsif ($network_interface_device) + { + # Try again using the device name. + my $query = " +SELECT + network_interface_uuid +FROM + network_interfaces +WHERE "; + if ($network_interface_name !~ /^vnet/) + { + $query .= " + network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address)." +AND "; + } + ### TODO: We may need to switch this to 'device' if the name or MAC address isn't found + $query .= " + network_interface_device = ".$anvil->Database->quote($network_interface_device)." +AND + network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); + + my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + results => $results, + count => $count, + }}); + if ($count) + { + $network_interface_uuid = $results->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }}); + } + } + elsif ($network_interface_name !~ /^vnet/) + { + # Try finding it by MAC + my $query = " +SELECT + network_interface_uuid +FROM + network_interfaces +WHERE + network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address)." +AND + network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid)." +;"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); + + my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__}); + my $count = @{$results}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + results => $results, + count => $count, + }}); + if ($count) + { + $network_interface_uuid = $results->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }}); + } + } if (($link_only) && (not $network_interface_uuid)) { diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 612aa053..5c28fb01 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -956,9 +956,13 @@ Bridge data is simple, but also made easy to find. The only real data is the has To make it easier to find interfaces, the following look up hash is available. * nmcli::interface::::uuid = The UUID of the interface -* nmcli::mac_address::::uuid = $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, +* nmcli::mac_address::::uuid = MAC address -This method takes no parameters +Parameters; + +=head3 start (optional, default '0') + +If this is set to C<< 1 >>, any connetions found to be down and not referencing any devices will be assigned the unroutable IP C<< 169.0.0.x >>, where C<< x >> is a sequential number. This should bring up unconfigured devices. =cut sub collect_data @@ -969,8 +973,13 @@ sub collect_data my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->check_internet()" }}); + my $start = defined $parameter->{start} ? $parameter->{start} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + start => $start, + }}); + # Use nmcli to collect the data. - my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type,active,state connection show"; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type,active,state,name connection show"; $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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { @@ -980,17 +989,19 @@ sub collect_data foreach my $line (split/\n/, $output) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /^(.*?):(.*?):(.*?):(.*?)$/) + if ($line =~ /^(.*?):(.*?):(.*?):(.*?):(.*?)$/) { - my $uuid = $1; - my $type = $2; - my $active = $3; - my $state = $4; + my $uuid = $1; + my $type = $2; + my $active = $3; + my $state = $4; + my $nm_name = $4; # biosdevname $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid, type => $type, active => $active, 'state' => $state, + nm_name => $nm_name, }}); next if $type eq "loopback"; @@ -1003,10 +1014,12 @@ sub collect_data $anvil->data->{nmcli}{uuid}{$uuid}{type} = $type; $anvil->data->{nmcli}{uuid}{$uuid}{active} = lc($active) eq "yes" ? 1 : 0; $anvil->data->{nmcli}{uuid}{$uuid}{'state'} = lc($state); + $anvil->data->{nmcli}{uuid}{$uuid}{nm_name} = $nm_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::uuid::${uuid}::type" => $anvil->data->{nmcli}{uuid}{$uuid}{type}, - "nmcli::uuid::${uuid}::active" => $anvil->data->{nmcli}{uuid}{$uuid}{active}, - "nmcli::uuid::${uuid}::state" => $anvil->data->{nmcli}{uuid}{$uuid}{'state'}, + "nmcli::uuid::${uuid}::type" => $anvil->data->{nmcli}{uuid}{$uuid}{type}, + "nmcli::uuid::${uuid}::active" => $anvil->data->{nmcli}{uuid}{$uuid}{active}, + "nmcli::uuid::${uuid}::state" => $anvil->data->{nmcli}{uuid}{$uuid}{'state'}, + "nmcli::uuid::${uuid}::nm_name" => $anvil->data->{nmcli}{uuid}{$uuid}{nm_name}, }}); } } @@ -1036,6 +1049,12 @@ sub collect_data 's2:value' => $value, }}); + if ($value eq "--") + { + $value = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { value => $value }}); + } + $anvil->data->{nmcli}{uuid}{$uuid}{$variable} = $value; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "nmcli::uuid::${uuid}::${variable}" => $anvil->data->{nmcli}{uuid}{$uuid}{$variable}, @@ -1138,7 +1157,7 @@ sub collect_data { $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns} .= ",".$value; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{nmcli}{uuid}{$uuid}{$sequence}{dns}, + "nmcli::uuid::${uuid}::${hash_key}::dns" => $anvil->data->{nmcli}{uuid}{$uuid}{$hash_key}{dns}, }}); } else @@ -1167,27 +1186,38 @@ sub collect_data } } - # Now loop through and look for the name that maps to what's shown in 'ip addr list'. This can be a bit tricky. + # Now loop through and look for the name that maps to what's shown in 'ip addr list'. This can be a + # bit tricky. foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) { + ### NOTE: The 'connection_id' is the 'network_interface_name' (biosdevname) and it is always + ### available, 'GENERAL.IP-IFACE' is the 'network_interface_device' and is only + ### available when the interface is up. my $connection_id = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.id'} // ""; - my $connection_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'} // ""; - my $general_devices = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.DEVICES'} // ""; my $general_ip_iface = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.IP-IFACE'} // ""; + $general_ip_iface = "" if $general_ip_iface eq "--"; my $device_type = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.type'} // ""; + my $connection_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'} // ""; my $match_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'match.interface-name'} // ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:uuid' => $uuid, 's2:connection_id' => $connection_id, - 's3:connection_interface_name' => $connection_interface_name, - 's4:general_devices' => $general_devices, - 's5:general_ip_iface' => $general_ip_iface, - 's6:device_type' => $device_type, - 's7:match_interface_name' => $match_interface_name, + 's3:general_ip_iface' => $general_ip_iface, + 's4:device_type' => $device_type, + 's5:connection_interface_name' => $connection_interface_name, + 's6:match_interface_name' => $match_interface_name, }}); + # An unrenamed interface will have a default 'Wired connection X' name, not he biosdevname + # name. So if there's not 'match.interface_name', use the 'connection.interface-name'. + if ((not $match_interface_name) && ($connection_interface_name)) + { + $connection_id = $connection_interface_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { connection_id => $connection_id }}); + } + # If there isn't a GENERAL.DEVICES or GENERAL.IP-IFACE, the link is down. Use the match.interface-name. - if (((not $general_devices) or (not $general_ip_iface)) && ($match_interface_name)) + if ((not $general_ip_iface) && ($match_interface_name)) { foreach my $interface (split/,/, $match_interface_name) { @@ -1195,247 +1225,313 @@ sub collect_data next if $connection_id eq $interface; if ($interface) { - $general_devices = $interface if not $general_devices; - $general_ip_iface = $interface if not $general_ip_iface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - general_devices => $general_devices, - general_ip_iface => $general_ip_iface, - }}); + $general_ip_iface = $interface; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { general_ip_iface => $general_ip_iface }}); } + last if $general_ip_iface; } } - my $device = ""; - if (($general_ip_iface) && ($general_ip_iface ne "--")) - { - $device = $general_ip_iface; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }}); - } - elsif (($connection_interface_name) && ($connection_interface_name ne "--")) - { - $device = $connection_interface_name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }}); - } - elsif (($general_devices) && ($general_devices ne "--")) + # Make it easier to lookup this device by name. + $anvil->data->{nmcli}{name}{$connection_id}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::name::${connection_id}::uuid" => $anvil->data->{nmcli}{name}{$connection_id}{uuid}, + }}); + + if ((not $general_ip_iface) && (not $connection_interface_name)) { - $device = $connection_interface_name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }}); + # This connection is down, so it's not linked to a device. + next; } - if ($device) - { - $anvil->data->{nmcli}{device}{$device}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::device::${device}::uuid" => $anvil->data->{nmcli}{device}{$device}{uuid}, - }}); + my $device = $general_ip_iface ? $general_ip_iface : $connection_interface_name; + $anvil->data->{nmcli}{device}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::device::${device}::uuid" => $anvil->data->{nmcli}{device}{$device}{uuid}, + }}); + + ### Get some data from sysfs. + $anvil->data->{nmcli}{uuid}{$uuid}{name} = $connection_id; + $anvil->data->{nmcli}{uuid}{$uuid}{device} = $device; + $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = ""; + $anvil->data->{nmcli}{uuid}{$uuid}{type} = ""; + $anvil->data->{nmcli}{uuid}{$uuid}{mtu} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::device" => $anvil->data->{nmcli}{uuid}{$uuid}{device}, + }}); + + # The 'connection.timestamp' seems to be where the 'connected' (as in, have an IP) + # comes from. + $anvil->data->{nmcli}{uuid}{$uuid}{connected} = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.timestamp'} ? $anvil->data->{nmcli}{uuid}{$uuid}{'connection.timestamp'} : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::connected" => $anvil->data->{nmcli}{uuid}{$uuid}{connected}, + }}); - ### Get some data from sysfs. - $anvil->data->{nmcli}{uuid}{$uuid}{device} = $device; - $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = ""; - $anvil->data->{nmcli}{uuid}{$uuid}{type} = ""; - $anvil->data->{nmcli}{uuid}{$uuid}{mtu} = 0; + if ($device_type eq "bond") + { + # Bonds always have the name we chose as the connection.id as they don't have + # biosdevnames. + $anvil->data->{nmcli}{bond}{$connection_id}{uuid} = $uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::uuid::${uuid}::device" => $anvil->data->{nmcli}{uuid}{$uuid}{device}, + "nmcli::bond::${connection_id}::uuid" => $anvil->data->{nmcli}{bond}{$connection_id}{uuid}, }}); - # The 'connection.timestamp' seems to be where the 'connected' (as in, have an IP) - # comes from. - $anvil->data->{nmcli}{uuid}{$uuid}{connected} = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.timestamp'} ? $anvil->data->{nmcli}{uuid}{$uuid}{'connection.timestamp'} : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::uuid::${uuid}::connected" => $anvil->data->{nmcli}{uuid}{$uuid}{connected}, - }}); + # Read the interface's carrier + my $carrier_file = "/sys/class/net/".$connection_id."/carrier"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier_file => $carrier_file }}); - if ($device_type eq "bond") + if (-e $carrier_file) { - $anvil->data->{nmcli}{bond}{$device}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::bond::${device}::uuid" => $anvil->data->{nmcli}{bond}{$device}{uuid}, + my $carrier = $anvil->Storage->read_file({debug => $debug, file => $carrier_file}); + chomp $carrier; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier => $carrier }}); + + $anvil->data->{nmcli}{bond}{$connection_id}{carrier} = $carrier; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${connection_id}::carrier" => $anvil->data->{nmcli}{bond}{$connection_id}{carrier}, }}); + } + + my $operstate_file = "/sys/class/net/".$connection_id."/operstate"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate_file => $operstate_file }}); + + if (-e $operstate_file) + { + my $operstate = $anvil->Storage->read_file({debug => $debug, file => $operstate_file}); + chomp $operstate; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate => $operstate }}); - # Read the interface's carrier - my $carrier_file = "/sys/class/net/".$device."/carrier"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier_file => $carrier_file }}); + $anvil->data->{nmcli}{bond}{$connection_id}{up} = $operstate eq "up" ? 1 : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${connection_id}::operstate" => $anvil->data->{nmcli}{bond}{$connection_id}{operstate}, + }}); + } + + # Read in the /proc file. + my $proc_file = "/proc/net/bonding/".$connection_id; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { proc_file => $proc_file }}); + + my $in_link = ""; + my $file_body = $anvil->Storage->read_file({debug => $debug, file => $proc_file}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); + foreach my $line (split/\n/, $file_body) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - if (-e $carrier_file) + if ($line =~ /Slave Interface: (.*)$/) { - my $carrier = $anvil->Storage->read_file({debug => $debug, file => $carrier_file}); - chomp $carrier; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier => $carrier }}); - - $anvil->data->{nmcli}{bond}{$device}{carrier} = $carrier; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "nmcli::bond::${device}::carrier" => $anvil->data->{nmcli}{bond}{$device}{carrier}, - }}); + $in_link = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_link => $in_link }}); + next; } - - my $operstate_file = "/sys/class/net/".$device."/operstate"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate_file => $operstate_file }}); - - if (-e $operstate_file) + if (not $line) { - my $operstate = $anvil->Storage->read_file({debug => $debug, file => $operstate_file}); - chomp $operstate; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate => $operstate }}); - - $anvil->data->{nmcli}{bond}{$device}{up} = $operstate eq "up" ? 1 : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "nmcli::bond::${device}::operstate" => $anvil->data->{nmcli}{bond}{$device}{operstate}, - }}); + $in_link = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_link => $in_link }}); + next; } - - # Read in the /proc file. - my $proc_file = "/proc/net/bonding/".$device; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { proc_file => $proc_file }}); - - my $in_link = ""; - my $file_body = $anvil->Storage->read_file({debug => $debug, file => $proc_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); - foreach my $line (split/\n/, $file_body) + if ($in_link) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - - if ($line =~ /Slave Interface: (.*)$/) - { - $in_link = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_link => $in_link }}); - next; - } - if (not $line) - { - $in_link = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_link => $in_link }}); - next; - } - if ($in_link) + if ($line =~ /MII Status: (.*)$/) { - if ($line =~ /MII Status: (.*)$/) + my $status = $1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }}); + if ($status eq "up") { - my $status = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }}); - if ($status eq "up") - { - $anvil->data->{nmcli}{bond}{$device}{interface}{$in_link}{up} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "nmcli::bond::${device}::interface::${in_link}::up" => $anvil->data->{nmcli}{bond}{$device}{interface}{$in_link}{up}, - }}); - } - else - { - $anvil->data->{nmcli}{bond}{$device}{interface}{$in_link}{up} = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "nmcli::bond::${device}::interface::${in_link}::up" => $anvil->data->{nmcli}{bond}{$device}{interface}{$in_link}{up}, - }}); - } - next; + $anvil->data->{nmcli}{bond}{$connection_id}{interface}{$in_link}{up} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "nmcli::bond::${connection_id}::interface::${in_link}::up" => $anvil->data->{nmcli}{bond}{$connection_id}{interface}{$in_link}{up}, + }}); } - } - else - { - if ($line =~ /MII Status: (.*)$/) + else { - my $status = $1; - $anvil->data->{nmcli}{bond}{$device}{up} = $status eq "up" ? 1 : 0; + $anvil->data->{nmcli}{bond}{$connection_id}{interface}{$in_link}{up} = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - status => $status, - "nmcli::bond::${device}::up" => $anvil->data->{nmcli}{bond}{$device}{up}, + "nmcli::bond::${connection_id}::interface::${in_link}::up" => $anvil->data->{nmcli}{bond}{$connection_id}{interface}{$in_link}{up}, }}); - next; } + next; + } + } + else + { + if ($line =~ /MII Status: (.*)$/) + { + my $status = $1; + $anvil->data->{nmcli}{bond}{$connection_id}{up} = $status eq "up" ? 1 : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + status => $status, + "nmcli::bond::${connection_id}::up" => $anvil->data->{nmcli}{bond}{$connection_id}{up}, + }}); + next; } } } - elsif ($device_type eq "bridge") + } + elsif ($device_type eq "bridge") + { + # Bonds always have the name we chose as the connection.id as they don't have + # biosdevnames. + $anvil->data->{nmcli}{bridge}{$connection_id}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::bridge::${connection_id}::uuid" => $anvil->data->{nmcli}{bridge}{$connection_id}{uuid}, + }}); + + # See what interfaces are connected to the bridge. + my $shell_call = $anvil->data->{path}{exe}{ip}." link show master ".$connection_id; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + foreach my $line (split/\n/, $output) { - $anvil->data->{nmcli}{bridge}{$device}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::bridge::${device}::uuid" => $anvil->data->{nmcli}{bridge}{$device}{uuid}, - }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + if ($line =~ /^\d+: (.*?): <(.*?)>/) + { + my $interface = $1; + my $status = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + status => $status, + }}); + + $anvil->data->{nmcli}{bridge}{$connection_id}{interface}{$interface}{status} = $status; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::bridge::${connection_id}::interface::${interface}::status" => $anvil->data->{nmcli}{bridge}{$connection_id}{interface}{$interface}{status}, + }}); + } + } + } + elsif (($device_type eq "802-3-ethernet") or ($device_type eq "interface")) + { + # If we've got the if-name, use it. Otherwise, it's likely down and not renamed by + # us, so use the connection id. + my $device = $connection_id; + if (($general_ip_iface) && ($general_ip_iface ne "--")) + { + $device = $general_ip_iface; + } + $anvil->data->{nmcli}{interface}{$device}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::interface::${device}::uuid" => $anvil->data->{nmcli}{interface}{$device}{uuid}, + }}); + + # MAC address + my $mac_address_file = "/sys/class/net/".$device."/address"; + my $type_file = "/sys/class/net/".$device."/type"; + my $mtu_file = "/sys/class/net/".$device."/mtu"; + if (-e $mac_address_file) + { + my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); + $mac_address =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - # See what interfaces are connected to the bridge. - my $shell_call = $anvil->data->{path}{exe}{ip}." link show master ".$device; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + if (($mac_address) && ($mac_address ne "!!error!!")) + { + $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = $mac_address; + $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::mac_address" => $anvil->data->{nmcli}{uuid}{$uuid}{mac_address}, + "nmcli::mac_address::${mac_address}::uuid" => $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, + }}); + } + } + if (-e $type_file) + { + my $type = $anvil->Storage->read_file({file => $type_file}); + $type =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); - my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - foreach my $line (split/\n/, $output) + if (($type) && ($type ne "!!error!!")) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /^\d+: (.*?): <(.*?)>/) - { - my $interface = $1; - my $status = $2; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface => $interface, - status => $status, - }}); - - $anvil->data->{nmcli}{bridge}{$device}{interface}{$interface}{status} = $status; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::bridge::${device}::interface::${interface}::status" => $anvil->data->{nmcli}{bridge}{$device}{interface}{$interface}{status}, - }}); - } + $anvil->data->{nmcli}{uuid}{$uuid}{type} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::type" => $anvil->data->{nmcli}{uuid}{$uuid}{type}, + }}); } } - elsif (($device_type eq "802-3-ethernet") or ($device_type eq "interface")) + if (-e $mtu_file) { - $anvil->data->{nmcli}{interface}{$device}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::interface::${device}::uuid" => $anvil->data->{nmcli}{interface}{$device}{uuid}, - }}); + my $mtu = $anvil->Storage->read_file({file => $mtu_file}); + $mtu =~ s/\n$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mtu => $mtu }}); - # MAC address - my $mac_address_file = "/sys/class/net/".$device."/address"; - my $type_file = "/sys/class/net/".$device."/type"; - my $mtu_file = "/sys/class/net/".$device."/mtu"; - if (-e $mac_address_file) + if (($mtu) && ($mtu ne "!!error!!")) { - my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); - $mac_address =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - - if (($mac_address) && ($mac_address ne "!!error!!")) - { - $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = $mac_address; - $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::uuid::${uuid}::mac_address" => $anvil->data->{nmcli}{uuid}{$uuid}{mac_address}, - "nmcli::mac_address::${mac_address}::uuid" => $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, - }}); - } + $anvil->data->{nmcli}{uuid}{$uuid}{mtu} = $mtu; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::mtu" => $anvil->data->{nmcli}{uuid}{$uuid}{mtu}, + }}); } - if (-e $type_file) + } + } + } + + # Should we start interfaces? + if ($start) + { + # Yup, but are there any to start? We'll set this to '1' if so and that will trigger a + # rescan. + my $rescan = 0; + + # Sorted for log consistency on repeat runs + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::uuid::${uuid}::active" => $anvil->data->{nmcli}{uuid}{$uuid}{active}, + "nmcli::uuid::${uuid}::active" => $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'}, + }}); + if ((not $anvil->data->{nmcli}{uuid}{$uuid}{active}) && (not $anvil->data->{nmcli}{uuid}{$uuid}{'connection.interface-name'})) + { + # Find an IP + my $sequence = 1; + my $found = 0; + my $use_ip = ""; + until ($found) { - my $type = $anvil->Storage->read_file({file => $type_file}); - $type =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }}); - - if (($type) && ($type ne "!!error!!")) + my $test_ip = "169.0.0.".$sequence; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_ip => $test_ip }}); + if (not exists $anvil->data->{nmcli}{ipv4}{$test_ip}) { - $anvil->data->{nmcli}{uuid}{$uuid}{type} = $type; + $found = 1; + $use_ip = $test_ip; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::uuid::${uuid}::type" => $anvil->data->{nmcli}{uuid}{$uuid}{type}, + found => $found, + use_ip => $use_ip, }}); } - } - if (-e $mtu_file) - { - my $mtu = $anvil->Storage->read_file({file => $mtu_file}); - $mtu =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mtu => $mtu }}); - - if (($mtu) && ($mtu ne "!!error!!")) + else { - $anvil->data->{nmcli}{uuid}{$uuid}{mtu} = $mtu; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::uuid::${uuid}::mtu" => $anvil->data->{nmcli}{uuid}{$uuid}{mtu}, - }}); + $sequence++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sequence => $sequence }}); } + die "Failed to find an unused IP in 169.0.0.0/24\n" if $sequence > 255; } + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." ipv4.method manual ipv4.addresses ".$use_ip."/8"; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $rescan = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rescan => $rescan }}); } } + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { rescan => $rescan }}); + if ($rescan) + { + # Give things a few seconds to settle + sleep 3; + + # Rescan + $anvil->Network->collect_data({debug => $debug}); + } } return(0); diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 872fd5c3..492e11fd 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -70,7 +70,7 @@ if ($anvil->data->{switches}{purge}) } # If there's no DB (or cached data isn't recorded to the database yet), this will store those records. -$anvil->data->{cache}{new_file} = "# interface,timestamp,mac_address,speed,link_state,operational,nm_uuid,nm_device\n"; +$anvil->data->{cache}{new_file} = "# interface (nm_device),timestamp,mac_address,speed,link_state,operational,nm_uuid,nm_name\n"; process_interface_cache($anvil); # Read the data. @@ -124,9 +124,8 @@ sub process_interface_cache { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); next if $line =~ /^#/; - my ($interface, $timestamp, $mac_address, $speed, $link_state, $operational, $nm_uuid, $nm_device) = (split/,/, $line); + my ($nm_device, $timestamp, $mac_address, $speed, $link_state, $operational, $nm_uuid, $nm_name) = (split/,/, $line); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface => $interface, timestamp => $timestamp, speed => $speed, mac_address => $mac_address, @@ -142,7 +141,7 @@ sub process_interface_cache debug => 2, link_only => 1, timestamp => $timestamp, - network_interface_name => $interface, + network_interface_name => $nm_device, network_interface_link_state => $link_state, network_interface_mac_address => $mac_address, network_interface_operational => $operational, @@ -610,10 +609,10 @@ sub collect_data $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); if (-d $full_path) { + ### NOTE: The 'interface' maps to the network manager 'GENERAL.IP-IFACE', which is + ### 'network_interface_device'. The 'network_interface_name' is the biosdevname. # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. my $interface = $file; - my $nm_uuid = $anvil->data->{nmcli}{interface}{$interface}{uuid} ? $anvil->data->{nmcli}{interface}{$interface}{uuid} : ""; - my $nm_device = ""; my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; $link_state =~ s/\n$//; my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; @@ -626,14 +625,13 @@ sub collect_data $modalias =~ s/\n$//; my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link $speed =~ s/\n$//; - my $media = "unknown"; - my $type = "interface"; - my $driver = ""; - my $tx_bytes = 0; # How many bytes transmitted - my $rx_bytes = 0; # How many bytes received + my $media = "unknown"; + my $type = "interface"; + my $driver = ""; + my $tx_bytes = 0; # How many bytes transmitted + my $rx_bytes = 0; # How many bytes received $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface, - nm_uuid => $nm_uuid, link_state => $link_state, mtu => $mtu, duplex => $duplex, @@ -642,6 +640,31 @@ sub collect_data modalias => $modalias, }}); + # Try to find the nm_uuid + my $nm_uuid = ""; + if ((exists $anvil->data->{nmcli}{name}{$interface}) && ($anvil->data->{nmcli}{name}{$interface}{uuid})) + { + $nm_uuid = $anvil->data->{nmcli}{name}{$interface}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_uuid => $nm_uuid }}); + } + elsif ((exists $anvil->data->{nmcli}{device}{$interface}) && ($anvil->data->{nmcli}{device}{$interface}{uuid})) + { + $nm_uuid = $anvil->data->{nmcli}{device}{$interface}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_uuid => $nm_uuid }}); + } + + my $nm_device = ""; # biosdevname + my $nm_name = ""; # ip name + if ($nm_uuid) + { + $nm_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device}; + $nm_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{name}; + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + nm_device => $nm_device, + nm_name => $nm_name, + }}); + ### NOTE: This only parses virtio so far. # Pick out our driver. if ($modalias =~ /^virtio:/) @@ -803,7 +826,6 @@ sub collect_data { # It's a bridge $type = "bridge"; - $nm_uuid = $anvil->data->{nmcli}{bridge}{$interface}{uuid}; $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); $bridge_id =~ s/\n$//; @@ -811,7 +833,6 @@ sub collect_data $speed = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type, - nm_uuid => $nm_uuid, bridge_id => $bridge_id, bridge_stp_enabled => $bridge_stp_enabled, }}); @@ -830,12 +851,6 @@ sub collect_data $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_stp_enabled => $bridge_stp_enabled }}); } - if ($nm_uuid) - { - $nm_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_device => $nm_device }}); - } - # If this is a 'vnet' device, set 'operational' to up if ($interface =~ /^vnet/) { @@ -891,7 +906,7 @@ sub collect_data } # Find the media, if possible. - (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"}); + (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." ".$interface}); foreach my $line (split/\n/, $ethtool) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); @@ -913,6 +928,7 @@ sub collect_data # Store new information we found. $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid} = $nm_uuid; $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device} = $nm_device; + $anvil->data->{network}{$local_host}{interface}{$interface}{nm_name} = $nm_name; $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface} = $active_interface; $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode} = $bond_mode; $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master} = $bond_master; @@ -936,6 +952,7 @@ sub collect_data $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network::${local_host}::interface::${interface}::nm_uuid" => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}, "network::${local_host}::interface::${interface}::nm_device" => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}, + "network::${local_host}::interface::${interface}::nm_name" => $anvil->data->{network}{$local_host}{interface}{$interface}{nm_name}, "network::${local_host}::interface::${interface}::active_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}, "network::${local_host}::interface::${interface}::bond_mode" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}, "network::${local_host}::interface::${interface}::bond_master" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}, @@ -965,7 +982,12 @@ sub collect_data # If this is a link and there's no database connections, cache the data. if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) { - $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational.",".$nm_uuid.",".$nm_device."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + nm_name => $nm_name, + nm_device => $nm_device, + }}); + # nm_device,timestamp,mac_address,speed,link_state,operational,nm_uuid,nm_name + $anvil->data->{cache}{new_file} .= $nm_device.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational.",".$nm_uuid.",".$nm_name."\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cache::new_file" => $anvil->data->{cache}{new_file}, }}); @@ -1054,6 +1076,7 @@ sub collect_data # Store the interface $anvil->data->{new}{interface}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; $anvil->data->{new}{interface}{$interface}{nm_device} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}; + $anvil->data->{new}{interface}{$interface}{nm_name} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_name}; $anvil->data->{new}{interface}{$interface}{bond_uuid} = ""; $anvil->data->{new}{interface}{$interface}{bond_name} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; $anvil->data->{new}{interface}{$interface}{bridge_uuid} = ""; @@ -1070,6 +1093,7 @@ sub collect_data $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "new::interface::${interface}::nm_uuid" => $anvil->data->{new}{interface}{$interface}{nm_uuid}, "new::interface::${interface}::nm_device" => $anvil->data->{new}{interface}{$interface}{nm_device}, + "new::interface::${interface}::nm_name" => $anvil->data->{new}{interface}{$interface}{nm_name}, "new::interface::${interface}::bond_uuid" => $anvil->data->{new}{interface}{$interface}{bond_uuid}, "new::interface::${interface}::bond_name" => $anvil->data->{new}{interface}{$interface}{bond_name}, "new::interface::${interface}::bridge_uuid" => $anvil->data->{new}{interface}{$interface}{bridge_uuid}, @@ -1114,6 +1138,7 @@ sub collect_data ### TODO: Remove this when ifcfg support is dropped. sub collect_data_ifcfg { +=cut my ($anvil) = @_; # Read the data from the ifcfg files, if available. We'll use this to check for bond interfaces that @@ -1670,6 +1695,7 @@ sub collect_data_ifcfg } return(0); +=cut } # This reads in the states from the last can @@ -2349,9 +2375,11 @@ sub load_interface_data # Process interfaces my $query = " SELECT - network_interface_uuid, + network_interface_uuid, + network_interface_nm_uuid, network_interface_mac_address, network_interface_name, + network_interface_device, network_interface_speed, network_interface_mtu, network_interface_link_state, @@ -2376,12 +2404,14 @@ WHERE foreach my $row (@{$results}) { my $network_interface_uuid = $row->[0]; - my $network_interface_mac_address = $row->[1]; - my $network_interface_name = $row->[2]; + my $network_interface_mac_address = $row->[2]; + my $network_interface_name = $row->[3]; + my $network_interface_device = $row->[4]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid, network_interface_mac_address => $network_interface_mac_address, network_interface_name => $network_interface_name, + network_interface_device => $network_interface_device, }}); # Read in the RX/TX values, set to '0' if not found. @@ -2404,23 +2434,27 @@ WHERE tx_variable_uuid => $tx_variable_uuid, }}); + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_nm_uuid} = $row->[1]; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address} = $network_interface_mac_address; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name} = $network_interface_name; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed} = $row->[3]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu} = $row->[4]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state} = $row->[5]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $row->[6]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex} = $row->[7]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium} = $row->[8]; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid} = defined $row->[9] ? $row->[9] : ''; - $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = defined $row->[10] ? $row->[10] : ''; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device} = $network_interface_device; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed} = $row->[5]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu} = $row->[6]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state} = $row->[7]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational} = $row->[8]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex} = $row->[9]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium} = $row->[10]; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid} = defined $row->[11] ? $row->[11] : ''; + $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid} = defined $row->[12] ? $row->[12] : ''; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes} = $rx_bytes =~ /^\d+$/ ? $rx_bytes : 0; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid} = $rx_variable_uuid; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes} = $tx_bytes =~ /^\d+$/ ? $tx_bytes : 0; $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid} = $tx_variable_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_nm_uuid" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_nm_uuid}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_name" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}, + "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_device" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_speed" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_mtu" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}, "old::network_interfaces::network_interface_uuid::${network_interface_uuid}::network_interface_link_state" => $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}, @@ -2436,11 +2470,13 @@ WHERE }}); $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; + $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_device} = $network_interface_uuid; $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid} = $network_interface_name; $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address} = $network_interface_uuid; $anvil->data->{interface}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::name_to_uuid::${network_interface_name}" => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}, + "network_interfaces::device_to_uuid::${network_interface_device}" => $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_device}, "network_interfaces::uuid_to_name::${network_interface_name}" => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}, "network_interfaces::mac_to_uuid::${network_interface_mac_address}" => $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address}, "interface::name_to_uuid::${network_interface_name}" => $anvil->data->{interface}{name_to_uuid}{$network_interface_name}, @@ -2676,7 +2712,6 @@ sub check_ip_addresses { my $on_interface = $anvil->data->{new}{ip_address}{$ip_address}{on_interface}; my $new_on_type = $anvil->data->{interface}{name_to_type}{$on_interface}; - my $new_on_uuid = $anvil->data->{interface}{name_to_uuid}{$on_interface}; my $new_subnet_mask = $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask}; my $new_gateway = $anvil->data->{new}{ip_address}{$ip_address}{gateway}; my $new_default_gateway = $anvil->data->{new}{ip_address}{$ip_address}{default_gateway}; @@ -2685,12 +2720,22 @@ sub check_ip_addresses ip_address => $ip_address, on_interface => $on_interface, new_on_type => $new_on_type, - new_on_uuid => $new_on_uuid, new_subnet_mask => $new_subnet_mask, new_gateway => $new_gateway, new_default_gateway => $new_default_gateway, new_dns => $new_dns, }}); + my $new_on_uuid = ""; + if ($anvil->data->{interface}{name_to_uuid}{$on_interface}) + { + $new_on_uuid = $anvil->data->{interface}{name_to_uuid}{$on_interface}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_on_uuid => $new_on_uuid }}); + } + elsif ($anvil->data->{interface}{device_to_uuid}{$on_interface}) + { + $new_on_uuid = $anvil->data->{interface}{device_to_uuid}{$on_interface}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_on_uuid => $new_on_uuid }}); + } if (exists $anvil->data->{old}{ip_addresses}{ip_to_uuid}{$ip_address}) { @@ -2957,6 +3002,7 @@ sub check_interfaces foreach my $network_interface_name (sort {$a cmp $b} keys %{$anvil->data->{new}{interface}}) { my $new_nm_uuid = $anvil->data->{new}{interface}{$network_interface_name}{nm_uuid}; + my $new_nm_name = $anvil->data->{new}{interface}{$network_interface_name}{nm_name}; my $new_nm_device = $anvil->data->{new}{interface}{$network_interface_name}{nm_device}; my $new_bond_uuid = $anvil->data->{new}{interface}{$network_interface_name}{bond_uuid}; my $new_bond_name = $anvil->data->{new}{interface}{$network_interface_name}{bond_name}; @@ -2974,6 +3020,7 @@ sub check_interfaces $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_name => $network_interface_name, new_nm_uuid => $new_nm_uuid, + new_nm_name => $new_nm_name, new_nm_device => $new_nm_device, new_bond_uuid => $new_bond_uuid, new_bond_name => $new_bond_name, @@ -3008,26 +3055,45 @@ sub check_interfaces } # New or existing? + my $network_interface_uuid = ""; if (exists $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}) + { + $network_interface_uuid = $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); + } + elsif (exists $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_name}) + { + $network_interface_uuid = $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); + } + elsif (($new_mac_address) && (exists $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address})) + { + $network_interface_uuid = $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }}); + } + if ($network_interface_uuid) { # Existing. Changes? - my $network_interface_uuid = $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}; - my $old_bond_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}; - my $old_bond_name = ""; - my $old_bridge_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}; - my $old_bridge_name = ""; - my $old_duplex = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex}; - my $old_link_state = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}; - my $old_operational = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}; - my $old_mac_address = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}; - my $old_medium = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium}; - my $old_mtu = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}; - my $old_speed = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}; - my $old_rx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}; - my $rx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid}; - my $old_tx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}; - my $tx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid}; + my $old_nm_name = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_name}; + my $old_nm_device = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_device}; + my $old_bond_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bond_uuid}; + my $old_bond_name = ""; + my $old_bridge_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_bridge_uuid}; + my $old_bridge_name = ""; + my $old_duplex = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_duplex}; + my $old_link_state = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_link_state}; + my $old_operational = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_operational}; + my $old_mac_address = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mac_address}; + my $old_medium = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_medium}; + my $old_mtu = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_mtu}; + my $old_speed = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{network_interface_speed}; + my $old_rx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_bytes}; + my $rx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{rx_variable_uuid}; + my $old_tx_bytes = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_bytes}; + my $tx_variable_uuid = $anvil->data->{old}{network_interfaces}{network_interface_uuid}{$network_interface_uuid}{tx_variable_uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_nm_name => $old_nm_name, + old_nm_device => $old_nm_device, old_bond_uuid => $old_bond_uuid, old_bridge_uuid => $old_bridge_uuid, old_duplex => $old_duplex, @@ -3061,6 +3127,52 @@ sub check_interfaces # Look for changes. my $changes = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_nm_name => $new_nm_name, + old_nm_name => $old_nm_name, + }}); + if ($new_nm_name ne $old_nm_name) + { + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + + my $variables = { + name => $network_interface_name, + old => $old_nm_name, + new => $new_nm_name, + }; + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0062", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_network_alert_0062", + variables => $variables, + set_by => $THIS_FILE, + }); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_nm_device => $new_nm_device, + old_nm_device => $old_nm_device, + }}); + if ($new_nm_device ne $old_nm_device) + { + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + + my $variables = { + name => $network_interface_name, + old => $old_nm_device, + new => $new_nm_device, + }; + + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_alert_0063", variables => $variables}); + $anvil->Alert->register({ + alert_level => "notice", + message => "scan_network_alert_0063", + variables => $variables, + set_by => $THIS_FILE, + }); + } if ($new_bond_uuid ne $old_bond_uuid) { # We're making this a warning level alert as it should not be changing. @@ -3390,13 +3502,17 @@ sub check_interfaces if ($changes) { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_nm_name => $new_nm_name, + new_nm_device => $new_nm_device, + }}); my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, network_interface_nm_uuid => $new_nm_uuid, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, - network_interface_name => $network_interface_name, - network_interface_device => $new_nm_device, + network_interface_name => $new_nm_name, # biosdevname + network_interface_device => $new_nm_device, # ip name network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, @@ -3525,13 +3641,18 @@ sub check_interfaces else { # Record the interface + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_nm_name => $new_nm_name, + network_interface_name => $network_interface_name, + new_nm_device => $new_nm_device, + }}); my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ debug => 2, network_interface_nm_uuid => $new_nm_uuid, network_interface_bond_uuid => $new_bond_uuid, network_interface_bridge_uuid => $new_bridge_uuid, - network_interface_name => $network_interface_name, - network_interface_device => $new_nm_device, + network_interface_name => $new_nm_name, + network_interface_device => $network_interface_name, network_interface_duplex => $new_duplex, network_interface_link_state => $new_link_state, network_interface_operational => $new_operational, @@ -3547,11 +3668,13 @@ sub check_interfaces $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid} = $network_interface_name; $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address} = $network_interface_uuid; $anvil->data->{interface}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; + $anvil->data->{interface}{device_to_uuid}{$new_nm_device} = $network_interface_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::name_to_uuid::${network_interface_name}" => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}, "network_interfaces::uuid_to_name::${network_interface_uuid}" => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}, "network_interfaces::mac_to_uuid::${new_mac_address}" => $anvil->data->{network_interfaces}{mac_to_uuid}{$new_mac_address}, "interface::name_to_uuid::${network_interface_name}" => $anvil->data->{interface}{name_to_uuid}{$network_interface_name}, + "interface::device_to_uuid::${new_nm_device}" => $anvil->data->{interface}{device_to_uuid}{$new_nm_device}, }}); # Store the rx_bytes and tx_bytes diff --git a/scancore-agents/scan-network/scan-network.xml b/scancore-agents/scan-network/scan-network.xml index 04908108..3dcfaf6d 100644 --- a/scancore-agents/scan-network/scan-network.xml +++ b/scancore-agents/scan-network/scan-network.xml @@ -133,6 +133,8 @@ Note: If this is a Storage Network directly connected to the peer, and the peer The network interface: [#!variable!name!#] appears to have been removed. The last time we saw it, it had transmitted: [#!variable!tx!#] and received: [#!variable!rx!#]. The IP address: [#!variable!ip!#] appears to no longer be used on this machine. The network interface: [#!variable!name!#] MAC address has changed from: [#!variable!old!#] to: [#!variable!new!#]. This is normal when a server boots or migrates. + The network interface: [#!variable!name!#] network manager's 'connection.id' name (biosdevname) has changed from: [#!variable!old!#] to: [#!variable!new!#]. + The network interface: [#!variable!name!#] network manager's 'GENERAL.IP-IFACE' name (ip addr name) has changed from: [#!variable!old!#] to: [#!variable!new!#]. Failed to read the network interface speed from the file: [#!variable!file!#]. Ignoring interface. diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index f869673d..dfbcc756 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -981,6 +981,37 @@ sub reconfigure_interfaces { my ($anvil) = @_; + # Before we start, we need to make sure all interfaces are up. Otherwise, there's no way to match a + # network manager device to the ip addr name or the biosdevname. + foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{uuid}}) + { + ### TODO: Left off here... any devices that are down, set: + ### nmcli connection modify ipv4.method manual ipv4.addresses 169.0.0.x/8' (x == Wired connection x) + my $connection_id = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.id'} // ""; + my $general_ip_iface = $anvil->data->{nmcli}{uuid}{$uuid}{'GENERAL.IP-IFACE'} // ""; + $general_ip_iface = "" if $general_ip_iface eq "--"; + my $device_type = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.type'} // ""; + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$uuid}{'match.interface-name'} // ""; + my $active = $anvil->data->{nmcli}{uuid}{$uuid}{active}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:uuid' => $uuid, + 's2:connection_id' => $connection_id, + 's3:general_ip_iface' => $general_ip_iface, + 's4:device_type' => $device_type, + 's5:match_interface_name' => $match_interface_name, + 's6:active' => $active, + }}); + + # Try activating it. + if ((not $general_ip_iface) && (not $active)) + { + + # Rescan. + $anvil->Network->collect_data({debug => 2}); + } + } + + my $local_host = $anvil->Get->short_host_name(); my $prefix = $anvil->data->{config}{prefix}; my $sequence = $anvil->data->{config}{sequence}; @@ -1038,9 +1069,35 @@ sub reconfigure_interfaces my $link1_nm_uuid = $anvil->data->{nmcli}{mac_address}{$wanted_link1_mac}{uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link1_nm_uuid => $link1_nm_uuid }}); + # Are the link(s) already configured? + my $configure_link1 = 0; + my $configure_link2 = 0; + # Get the Network Manager UUIDs. - if (not $link1_nm_uuid) + if ($link1_nm_uuid) + { + my $found = 0; + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$link1_nm_uuid}{'match.interface-name'} // ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); + foreach my $interface (split/,/, $match_interface_name) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface }}); + if ($interface eq $wanted_link1_name) + { + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + last; + } + } + if (not $found) + { + $configure_link1 = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link1 => $configure_link1 }}); + } + } + else { + # We're dead. $anvil->Job->update_progress({ progress => 100, message => "error_0480", @@ -1055,14 +1112,40 @@ sub reconfigure_interfaces }); $anvil->nice_exit({exit_code => 1}); } - rename_interface($anvil, $wanted_link1_name, $link1_nm_uuid); + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link1 => $configure_link1 }}); + if ($configure_link1) + { + rename_interface($anvil, $wanted_link1_name, $link1_nm_uuid); + } my $link2_nm_uuid = ""; if ($wanted_link2_mac) { $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$wanted_link2_mac}{uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { link2_nm_uuid => $link2_nm_uuid }}); - if (not $link2_nm_uuid) + if ($link2_nm_uuid) + { + my $found = 0; + my $match_interface_name = $anvil->data->{nmcli}{uuid}{$link2_nm_uuid}{'match.interface-name'} // ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); + foreach my $interface (split/,/, $match_interface_name) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface }}); + if ($interface eq $wanted_link2_name) + { + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + last; + } + } + if (not $found) + { + $configure_link2 = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link1 => $configure_link1 }}); + } + } + else { $anvil->Job->update_progress({ progress => 100, @@ -1078,7 +1161,12 @@ sub reconfigure_interfaces }); $anvil->nice_exit({exit_code => 1}); } - rename_interface($anvil, $wanted_link2_name, $link2_nm_uuid); + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link2 => $configure_link2 }}); + if ($configure_link2) + { + rename_interface($anvil, $wanted_link2_name, $link2_nm_uuid); + } # There's a second interface, so create a bond. my $bond_name = $network_type.$i."_bond1"; @@ -1090,8 +1178,6 @@ sub reconfigure_interfaces } } - die; - # There is no way (that we've found) to get the network interface ames to be updated without a reboot. if ($anvil->data->{sys}{reboot_needed}) { @@ -1122,6 +1208,9 @@ sub rename_interface 's6:type' => $type, }}); + die if not $wanted_link_name; + die if not $old_device; + # Tell the user what we're about to rename $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 2}), From 518fddfa8286966098773b100e52f53aa7632b04 Mon Sep 17 00:00:00 2001 From: digimer Date: Sat, 13 Jan 2024 02:09:06 -0500 Subject: [PATCH 18/43] More progress on the new NM version of anvil-configure-host * It's technically done, but I know bugs remain. * Updated Jobs->update_progress() to take 'file' and 'line' to make it easier in the logs to see the origin of the message, when logging the update. * Created Network->modify_connection() to update network manager variables. Created ->reset_connection() to take an interface down and bring it back up again. * Fixed a bug in scan-network where the device_to_uuid hash wasn't being stored. Signed-off-by: digimer --- Anvil/Tools/Job.pm | 16 +- Anvil/Tools/Network.pm | 117 ++ scancore-agents/scan-network/scan-network | 6 + share/words.xml | 48 +- tools/anvil-configure-host | 1309 ++++++++++++++++----- 5 files changed, 1206 insertions(+), 290 deletions(-) diff --git a/Anvil/Tools/Job.pm b/Anvil/Tools/Job.pm index 09ba32a4..f1658204 100644 --- a/Anvil/Tools/Job.pm +++ b/Anvil/Tools/Job.pm @@ -616,10 +616,18 @@ B<< Note >>: Some special C<< job_status >> processing is done to support some s Parameters; +=head3 file (optional) + +When logging as well, this is the file causing the update. Use with C<< line >>. Ignored if C<< log_level >> is not set, or such that it wouldn't be logged anyway. + =head3 job_uuid (optional, default 'jobs::job_uuid') This is the UUID of the job to update. If it isn't set, but C<< jobs::job_uuid >> is set, it will be used. If that is also not set, +=head3 line (optional_ + +When logging as well, this is the line the update came from. Use with C<< file >>. Ignored if C<< log_level >> is not set, or such that it wouldn't be logged anyway. + =head3 log_level (optional) If set to a numeric level, the job's message will also be logged. This is designed to simplify code as most job progress messages will also want to be logged. @@ -663,7 +671,9 @@ sub update_progress my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Job->update_progress()" }}); + my $file = defined $parameter->{file} ? $parameter->{file} : $THIS_FILE; my $job_uuid = defined $parameter->{job_uuid} ? $parameter->{job_uuid} : ""; + my $line = defined $parameter->{line} ? $parameter->{line} : __LINE__; my $log_level = defined $parameter->{log_level} ? $parameter->{log_level} : ""; my $message = defined $parameter->{message} ? $parameter->{message} : ""; my $picked_up_by = defined $parameter->{picked_up_by} ? $parameter->{picked_up_by} : ""; @@ -673,11 +683,13 @@ sub update_progress my $secure = defined $parameter->{secure} ? $parameter->{secure} : ""; my $variables = defined $parameter->{variables} ? $parameter->{variables} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + file => $file, job_uuid => $job_uuid, + line => $line, + log_level => $log_level, picked_up_by => $picked_up_by, 'print' => $print, progress => $progress, - log_level => $log_level, message => $message, variables => $variables, secure => $secure, @@ -687,7 +699,7 @@ sub update_progress if (($message ne "clear") && ($log_level =~ /^\d+$/)) { # Log this message. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $log_level, 'print' => $print, secure => $secure, priority => $priority, key => $message, variables => $variables}); + $anvil->Log->entry({source => $file, line => $line, level => $log_level, 'print' => $print, secure => $secure, priority => $priority, key => $message, variables => $variables}); } if ($picked_up_by eq "") diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 5c28fb01..82ba92e3 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -32,8 +32,10 @@ my $THIS_FILE = "Network.pm"; # load_interfces # load_ips # manage_firewall +# modify_connection # ping # read_nmcli +# reset_connection # _check_firewalld_conf # _get_existing_zone_interfaces # _get_server_ports @@ -4320,6 +4322,68 @@ sub manage_firewall return(0); } +=head3 modify_connection + +This takes a network manager connection UUID, and changes the requested variable to be set to the given value. + +The command output and return code are returned. If there is a problem, C<< !!error!! >> is returned. + +Parameters + +=head3 uuid (required) + +This is the network manager UUID of the connection being worked on. + +=head3 variable (required) + +This is the name of the variable to set (as shown in C<< nmcli connection show >>). + +=head3 value (optional, defult "") + +This is the value to set. Note that and empty string (C<< "" >>) deletes the variable. + +=cut +sub modify_connection +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->modify_connection()" }}); + + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; + my $variable = defined $parameter->{variable} ? $parameter->{variable} : ""; + my $value = defined $parameter->{value} ? $parameter->{value} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + uuid => $uuid, + variable => $variable, + value => $value, + }}); + + if (not $uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->modify_connection()", parameter => "uuid" }}); + return("!!error!!"); + } + + if (not $variable) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->modify_connection()", parameter => "variable" }}); + return("!!error!!"); + } + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$uuid." ".$variable." ".$value; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + return($output, $return_code); +} + + =head2 ping @@ -4754,6 +4818,59 @@ sub read_nmcli return(0); } + +=head2 reset_connection + +This method takes a network manager connection UUID and resets the connection by calling it C<< down >> and then C<< up >>. + +If there is a problem, C<< !!error!! >> is returned. Otherwise, the output and return code from the C<< up >> call are returned. + +Parameters; + +=head3 uuid (required) + +This is the UUID of the connection to reset. + +=cut +sub reset_connection +{ + my $self = shift; + my $parameter = shift; + my $anvil = $self->parent; + my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->reset_connection()" }}); + + my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + uuid => $uuid, + }}); + + if (not $uuid) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->reset_connection()", parameter => "uuid" }}); + return("!!error!!"); + } + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$uuid; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + return($output, $return_code); +} + + ############################################################################################################# # Private functions # ############################################################################################################# diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 492e11fd..c40d67e3 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -535,6 +535,10 @@ sub collect_data { my ($anvil) = @_; + # Read in data from Network Manager + $anvil->Network->collect_data({debug => 2}); + + ### TODO: We can get the IPs from collect_data, we should phase this out. # The 'local_host' is needed to pull data recorded by Network->get_ips(); $anvil->Network->get_ips({debug => 2}); my $local_host = $anvil->Get->short_host_name(); @@ -2474,12 +2478,14 @@ WHERE $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid} = $network_interface_name; $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address} = $network_interface_uuid; $anvil->data->{interface}{name_to_uuid}{$network_interface_name} = $network_interface_uuid; + $anvil->data->{interface}{device_to_uuid}{$network_interface_device} = $network_interface_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::name_to_uuid::${network_interface_name}" => $anvil->data->{network_interfaces}{name_to_uuid}{$network_interface_name}, "network_interfaces::device_to_uuid::${network_interface_device}" => $anvil->data->{network_interfaces}{device_to_uuid}{$network_interface_device}, "network_interfaces::uuid_to_name::${network_interface_name}" => $anvil->data->{network_interfaces}{uuid_to_name}{$network_interface_uuid}, "network_interfaces::mac_to_uuid::${network_interface_mac_address}" => $anvil->data->{network_interfaces}{mac_to_uuid}{$network_interface_mac_address}, "interface::name_to_uuid::${network_interface_name}" => $anvil->data->{interface}{name_to_uuid}{$network_interface_name}, + "interface::device_to_uuid::${network_interface_device}" => $anvil->data->{interface}{device_to_uuid}{$network_interface_device}, }}); } diff --git a/share/words.xml b/share/words.xml index b31899e8..3031fcb7 100644 --- a/share/words.xml +++ b/share/words.xml @@ -755,6 +755,30 @@ The XML that failed sanity check was: [ Error ] - The wanted interface: [#!variable!interface_name!#] which should have the MAC address: [#!variable!mac_address!#] was not found in Network Manager. Unable to proceed. [ Error ] - Failed to delete the 'connection.interface-name', got: [#!variable!output!#] and it should bhave been blank, aborting! [ Error ] - Failed to create the 'match.interface-name' value. Expected: [#!variable!new_name!#,#!variable!old_device!#], got: [#!variable!output!#], aborting! + [ Error ] - The attempt to add the bond: [#!variable!bond_name!#] failed! The return code was: [#!variable!return_code!#]. The output, if any, was: +======== +#!variable!output!# +======== + + [ Error ] - The attempt to add the network link: [#!variable!link_name!#] to the bond: [#!variable!bond_name!#] failed! The return code was: [#!variable!return_code!#]. The output, if any, was: +======== +#!variable!output!# +======== + + [ Error ] - The attempt to add the bridge: [#!variable!bridge_name!# failed! The return code was: [#!variable!return_code!#]. The output, if any, was: +======== +#!variable!output!# +======== + + [ Error ] - The attempt to add the device: [#!variable!on_device!#] to the bridge: [#!variable!bridge_name!#] failed! The return code was: [#!variable!return_code!#]. The output, if any, was: +======== +#!variable!output!# +======== + + [ Error ] - The subnet_mask: [#!variable!subnet_mask!#] is not valid. It must be either a CIDR notation, or a dotted-decimal mask that can be translated to CIDR notation. + [ Error ] - Can't find a device to assign the: [#!variable!network!#] IP address: [#!variable!ip_address!#/#!variable!subnet_mask!#] to! + [ Error ] - Failed to map the IP address: [#!variable!ip_address!#] to a network manager connection UUID! + [ Error ] - Both the netbios name: [#!variable!wanted_link_name!#] and the old device name: [#!variable!old_device!#] are the same, 'match.interface-name' would break! @@ -3296,7 +3320,29 @@ proceeding. Rebooting NOW! The job will restart on reboot. Checking if the bond: [#!variable!bond_name!#] exists or not. - It does, its UUID is: [#!variable!nm_uuid!#]. - - The bond: [#!variable!bond_name!#] doesn't exist. Will create it using the primary interface: [#!variable!link1_name!#] (MAC: [#!variable!link1_mac!#], NM UUID: [#!variable!link1_nm_uuid!#) and the backup interface: : [#!variable!link2_name!#] (MAC: [#!variable!link2_mac!#], NM UUID: [#!variable!link2_nm_uuid!#). + - The bond: [#!variable!bond_name!#] doesn't exist. Will create it using the primary interface: [#!variable!link1_name!#] (MAC: [#!variable!link1_mac!#], NM UUID: [#!variable!link1_nm_uuid!#) and the backup interface: [#!variable!link2_name!#] (MAC: [#!variable!link2_mac!#], NM UUID: [#!variable!link2_nm_uuid!#). + Checking to see if the IP address: [#!variable!ip_address!#/#!variable!subnet_mask!#] is assigned to: [#!variable!device!#] yet. + - Done! Rescanning the network config. + - The interface: [#!variable!link_name!#] (#!variable!nm_uuid!#) is already a member of the bond. + - The interface: [#!variable!link_name!#] (#!variable!nm_uuid!#) is a member of the bond: [#!variable!old_bond!#], switching it to this bond. + - The interface: [#!variable!link_name!#] (#!variable!nm_uuid!#) needs to be connected to the bond. + - The IP exists, checking if it needs to be updated. + - Connecting the interface: [#!variable!link_name!#] to the bond: [#!variable!bond_name!#]. + Checking if the bridge: [#!variable!bridge_name!#] exists and that it is on: [#!variable!on_device!#] + - The bridge exists! + - The IP address is on: [#!variable!current_device!#], will move the IP. + - Resetting the device: [#!variable!device!#] (#!variable!device_uuid!#) to make sure the new config takes effect. + - Checking that the device: [#!variable!on_device!#] is connected to this bridge. + - The device is connected to the bridge already. + - The device is on the bridge: [#!variable!on_device_parent!#], moving it. + - The device is not on this bridge, connecting it. + - Disabling DHCP on the device: [#!variable!device!#] (#!variable!device_uuid!#). + - Connecting it now. + - The current subnet mask is: [#!variable!current_subnet_mask!#], will update. + - The current gateway is: [#!variable!current_gateway!#], will update. + - The current DNS is: [#!variable!current_dns!#], will update. + - No update is needed. + - The IP address needs to be assigned. Normal Password diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index dfbcc756..d402578e 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -92,14 +92,6 @@ $anvil->Job->update_progress({ $anvil->System->maintenance_mode({set => 0, debug => 2}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0467"}); -### TODO: As of now, the network doesn't come up reliably, so reboot. We add a 60 second delay to make it -### easier to log in and disable anvil-daemon in case of reboot loops caused by this program thinking -### it needs to reconfigure the system every run. -# if ($anvil->data->{sys}{reboot}) -# { -# do_reboot($anvil); -# } - $anvil->nice_exit({exit_code => 0}); @@ -114,22 +106,26 @@ sub do_reboot # Tell the user why we're rebooting $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 10}), + progress => $anvil->Job->bump_progress({steps => 5}), message => "message_0388", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, }); my $time_left = 60; while ($time_left) { # Give them the countdown. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 10}), + progress => $anvil->Job->bump_progress({steps => 2}), message => "log_0626", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, variables => { seconds => $time_left }, }); sleep 10; @@ -138,11 +134,13 @@ sub do_reboot # Last, log that we're going down now. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 10}), + progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0389", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, }); my $shell_call = $anvil->data->{path}{exe}{systemctl}." reboot"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); @@ -190,6 +188,8 @@ sub update_passwords 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", + file => $THIS_FILE, + line => __LINE__, variables => { file => $temp_file }, }); $anvil->nice_exit({exit_code => 5}); @@ -320,11 +320,13 @@ sub reconfigure_network { # Success $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 10}), + progress => $anvil->Job->bump_progress({steps => 5}), message => "message_0016", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, variables => { host_name => $new_host_name }, }); } @@ -337,6 +339,8 @@ sub reconfigure_network job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, job_status => "failed", variables => { host_name => $new_host_name, @@ -347,12 +351,6 @@ sub reconfigure_network } } - # Read the local network manager data. - #$anvil->Network->read_nmcli({debug => 2}); - - # Get the current list of IPs and MAC addresses. - #$anvil->Network->get_ips({debug => 2}); - # If we're a striker, check apache's config. if ($type eq "striker") { @@ -405,27 +403,6 @@ sub reconfigure_network } } } - - ### NOTE: Not disconnecting anymore, we'll reboot on changes. - # 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, 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} }}); -# } # Before we continue, see if there's two interfaces pointing at the same NIC. If so, the node would # endlessly reboot. @@ -485,6 +462,8 @@ ORDER BY job_status => "failed", 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, variables => { mac_address => $variable_value, iface1 => $macs->{$variable_value}, @@ -526,75 +505,6 @@ ORDER BY reconfigure_bridges($anvil); reconfigure_ip_addresses($anvil); } - die; - - # If we should reset, do so now. - if ($anvil->data->{sys}{reboot}) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0687", variables => { reason => "#!string!log_0631!#" }}); - do_reboot($anvil); - } - - if ($changes) - { - # In an attempt to make network changes more reliable, we'll just reboot. This shouldn't - # actually be hit anymore as any change should have triggered the reboot above. - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0687", variables => { reason => "#!string!log_0631!#" }}); - do_reboot($anvil); - - # Re-read the config - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0463"}); - - my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection reload"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); - my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - - # Give a couple seconds for the reload - sleep 2; - - # Now check the bonds - my $repaired = $anvil->Network->check_network({heal => "all"}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { repaired => $repaired }}); - if ($repaired) - { - # It can take a bit for the bonds to allow traffic, so sleep for a bit. - sleep 30; - } - } - - # Wait for a DB connection. We'll wait up to 130 seconds, as sometimes it takes a while for the network - # to start routing traffic. - 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, key => "log_0132"}); - if (not $anvil->data->{sys}{database}{connections}) - { - if (time > $wait_until) - { - # Failed to reconnect, reboot. Hopefully the network comes up cleanly - # next time.. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0107"}); - do_reboot($anvil); - } - - # No databases, sleep and then try again. - sleep 10; - } - } - - # We're half-way there. - $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 50}), - job_uuid => $anvil->data->{job}{uuid}, - }); # If any virtio bridges exist, remove it/them. my $start = 0; @@ -675,7 +585,7 @@ ORDER BY } $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 75}), + progress => $anvil->Job->bump_progress({steps => 2}), job_uuid => $anvil->data->{job}{uuid}, }); @@ -686,17 +596,309 @@ sub reconfigure_bridges { my ($anvil) = @_; + my $local_host = $anvil->Get->short_host_name(); + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + bcn_count => $bcn_count, + ifn_count => $ifn_count, + type => $type, + }}); + + if ($type eq "striker") + { + # No bridges on strikers. + return(0); + } + + foreach my $network_type ("bcn", "ifn") + { + $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 "ifn") { $count = $ifn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + # This is the old type of network config + foreach my $i (1..$count) + { + ### TODO: This is almost always going to be on the bond, but we need to handle + ### bridges on interfaces on DR hosts. + my $bridge_name = $network_type.$i."_bridge1"; + my $on_device = $network_type.$i."_bond1"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bridge_name => $bridge_name, + on_device => $on_device, + }}); + + # Checking if the bridge exists and that it is on the requested device + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0400", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + bridge_name => $bridge_name, + on_device => $on_device, + }, + }); + + if (exists $anvil->data->{nmcli}{bridge}{$bridge_name}) + { + # The bridge exists. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0401", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => {}, + }); + } + else + { + # Create the bridge. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bridge con-name ".$bridge_name." ifname ".$bridge_name; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if ($return_code) + { + # Failed to add the bridge + $anvil->Job->update_progress({ + progress => 100, + message => "error_0485", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + bridge_name => $bridge_name, + return_code => $return_code, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + my $bridge_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }}); + + if ($bridge_uuid) + { + # Disabling DHCP on the new bridge + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $bridge_name, + device_uuid => $bridge_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $bridge_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $bridge_uuid, variable => "ipv6.method", value => "disabled"}); + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + + # Checking that the device is connected to this bridge + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0404", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { on_device => $on_device }, + }); + my $bridge_uuid = $anvil->data->{nmcli}{bridge}{$bridge_name}{uuid}; + my $on_device_uuid = $anvil->data->{nmcli}{device}{$on_device}{uuid} // ""; + my $on_device_parent = $anvil->data->{nmcli}{uuid}{$on_device_uuid}{'connection.master'} // ""; + my $on_device_child_type = $anvil->data->{nmcli}{uuid}{$on_device_uuid}{'connection.slave-type'} // ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + bridge_uuid => $bridge_uuid, + on_device_uuid => $on_device_uuid, + on_device_parent => $on_device_parent, + on_device_child_type => $on_device_child_type, + }}); + + if ($on_device_parent) + { + if ($on_device_parent eq $bridge_name) + { + # The device is connected to the bridge already. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0405", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + next; + } + else + { + # The device is on another bridge, moving it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0406", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { on_device_parent => $on_device_parent }, + }); + } + } + else + { + # The device is not on this bridge, connecting it + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0407", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { on_device_parent => $on_device_parent }, + }); + } + + # Disabling DHCP on the device before connecting it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $on_device, + device_uuid => $on_device_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $on_device_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $on_device_uuid, variable => "ipv6.method", value => "disabled"}); + + # Connect it now. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0409", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$on_device_uuid." master ".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if ($return_code) + { + # Failed to connect the device to the bridge. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0486", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + on_device => $on_device, + bridge_name => $bridge_name, + return_code => $return_code, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + # Reset the device. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0403", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $on_device, + device_uuid => $on_device_uuid, + }, + }); + ($output, $return_code) = $anvil->Network->reset_connection({debug => 2, uuid => $on_device_uuid}); + + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + } return(0); } sub reconfigure_bonds { - my ($anvil, $wanted_link_name, $nm_uuid) = @_; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - wanted_link_name => $wanted_link_name, - nm_uuid => $nm_uuid, - }}); + my ($anvil) = @_; my $local_host = $anvil->Get->short_host_name(); my $prefix = $anvil->data->{config}{prefix}; @@ -731,29 +933,41 @@ sub reconfigure_bonds $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_name => $bond_name }}); # Skip if this isn't marked to become a bond. - next if not exists $anvil->data->{config}{$bond_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "config::${bond_name}" => $anvil->data->{config}{$bond_name}, }}); + if (not $anvil->data->{config}{$bond_name}) + { + # No bond on this network. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + }}); + } + + my $link_nm_uuids = []; # Check if the bond exists or not. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 10}), + progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0390", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, variables => { bond_name => $bond_name }, }); if (exists $anvil->data->{nmcli}{bond}{$bond_name}) { # It does. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 10}), + progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0391", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, variables => { nm_uuid => $anvil->data->{nmcli}{bond}{$bond_name}{uuid} }, }); } @@ -779,12 +993,18 @@ sub reconfigure_bonds link2_mac => $link2_mac, link2_nm_uuid => $link2_nm_uuid, }}); + + push @{$link_nm_uuids}, $link1_nm_uuid; + push @{$link_nm_uuids}, $link2_nm_uuid; + $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 10}), + progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0392", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, variables => { bond_name => $bond_name, link1_name => $link1_name, @@ -795,174 +1015,245 @@ sub reconfigure_bonds link2_nm_uuid => $link2_nm_uuid, }, }); - die; + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bond con-name ".$bond_name." ifname ".$bond_name." bond.options \"mode=active-backup,miimon=100,downdelay=0,updelay=120000,primary=".$link1_name."\""; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); -# my $primary_interface = $anvil->data->{network_manager}{want}{bond}{$bond_name}{interfaces}->[0]; -# if (not $primary_interface) -# { -# print "[ Error ] - There appears to be no primary interface specified for this bond!\n"; -# $anvil->nice_exit({exit_code => 1}); -# } -# print "- It does not, creating it with the primary interface: [".$primary_interface."] now.\n"; -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bond con-name ".$bond_name." ifname ".$bond_name." bond.options \"mode=active-backup,miimon=100,downdelay=0,updelay=120000,primary=".$primary_interface."\""; -# $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}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# if ($return_code) -# { -# print "[ Error ] - The attempt to add the bond failed! The return code was: [".$return_code."]. The output, if any, was:\n"; -# print "========\n"; -# print $output."\n"; -# print "========\n"; -# $anvil->nice_exit({exit_code => 1}); -# } -# -# my $bond_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); -# -# if ($bond_uuid) -# { -# print " - Disabling DHCP on the new bond device: [".$bond_uuid."].\n"; -# my ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv4.method", "disabled"); -# ($output, $return_code) = modify_connection($anvil, $bond_uuid, "ipv6.method", "disabled"); -# -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bond_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# } -# -# # Rescan. -# print " - Done! Rescanning the network config.\n"; -# collect_data($anvil); + if ($return_code) + { + # Adding the bond failed. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0483", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + bond_name => $bond_name, + return_code => $return_code, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + my $bond_uuid = ($output =~ /\((.*?)\) successfully added/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }}); + + if ($bond_uuid) + { + # Disabling DHCP on the new bond device + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $bond_name, + device_uuid => $bond_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $bond_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $bond_uuid, variable => "ipv6.method", value => "disabled"}); + + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection up ".$bond_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + + # Done! Rescanning the network config + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0394", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + }); + $anvil->Network->collect_data({debug => 2}); } # Now add the interfaces, disabling their ipv4.method first. -# foreach my $interface_name (@{$anvil->data->{network_manager}{want}{bond}{$bond_name}{interfaces}}) -# { -# # What is the interface UUID? -# my $interface_uuid = $anvil->data->{interface}{device}{$interface_name}{uuid}; -# my $parent_bond_name = $anvil->data->{interface}{uuid}{$interface_uuid}{'connection.master'}; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# interface_name => $interface_name, -# interface_uuid => $interface_uuid, -# parent_bond_name => $parent_bond_name, -# }}); -# if ($parent_bond_name eq "--") -# { -# $parent_bond_name = ""; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { parent_bond_name => $parent_bond_name }}); -# } -# -# if ($parent_bond_name) -# { -# if ($parent_bond_name eq $bond_name) -# { -# print "- The interface: [".$interface_name."] (".$interface_uuid.") is already a member of the bond.\n"; -# next; -# } -# else -# { -# print "- The interface: [".$interface_name."] (".$interface_uuid.") is a member of the bond: [".$parent_bond_name."], switching it to this bond.\n"; -# } -# } -# else -# { -# print "- The interface: [".$interface_name."] (".$interface_uuid.") needs to be connected to the bond.\n"; -# } -# -# print " - Disabling DHCP on the interface\n"; -# my ($output, $return_code) = modify_connection($anvil, $interface_uuid, "ipv4.method", "disabled"); -# ($output, $return_code) = modify_connection($anvil, $interface_uuid, "ipv6.method", "disabled"); -# -# print " - Connecting the interface to the bond.\n"; -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$interface_uuid." connection.master ".$bond_name." connection.slave-type bond"; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# if ($return_code) -# { -# print "[ Error ] - The attempt to add the bond failed! The return code was: [".$return_code."]. The output, if any, was:\n"; -# print "========\n"; -# print $output."\n"; -# print "========\n"; -# $anvil->nice_exit({exit_code => 1}); -# } -# -# # Rescan. -# print " - Done! Rescanning the network config.\n"; -# ($output, $return_code) = reset_connection($anvil, $interface_uuid); -# -# # Rescan. -# collect_data($anvil); -# } - } - } - -=cut - -* nmcli::uuid::::device = 'connection.interface-name', or 'GENERAL.DEVICES'. See note below -* nmcli::uuid::::type = interface, bond, bridge, etc -* nmcli::uuid::::active = 1,0 -* nmcli::uuid::::state = activated,activating,etc -* nmcli::uuid:::: = all 'variable: value' pairs returned by 'nmcli connection show ' -* nmcli::uuid::::mac_address = MAC address (in lower case) -* nmcli::uuid::::connected = 0 is down, unix timestamp (seconds since epoch) of when it connected if up. -* nmcli::uuid::::mtu = This is the MTU (maximum transimssion unit in bytes) of the interface. - -To make it easier to map a device by name or MAC address to a UUID, this lookup hash is provided. Note that 'device' is 'connection.interface-name' when available, falling back to 'GENERAL.DEVICES' otherwise. - -B<< NOTE >>: An inactive interface will not report the 'connection.interface-name', and the bios device name will be returned (which is what is stored in 'GENERAL.DEVICES'. If you're trying to find a device, and the expected name doesn't exist, look up the device by MAC address. If that's not found, then the old GENERAL.DEVICES name can help you identify a replaced interface. - -* nmcli::device::::uuid = interface name (or device name) -* nmcli::mac_address::::uuid = MAC address (lower case) + foreach my $nm_uuid (@{$link_nm_uuids}) + { + my $link_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{name}; + my $link_device = $anvil->data->{nmcli}{uuid}{$nm_uuid}{device}; + my $mac_address = $anvil->data->{nmcli}{uuid}{$nm_uuid}{mac_address}; + my $parent_bond_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'connection.master'}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:nm_uuid' => $nm_uuid, + 's2:link_name' => $link_name, + 's3:link_device' => $link_device, + 's4:mac_address' => $mac_address, + 's5:parent_bond_name' => $parent_bond_name, + }}); -Given that a single interface can have multiple IP addresses and routes, the IPs on a given interface are stored using a sequence number <1, 2, 3 ... n>. To make it easier to find what device has an IP, the IPs are stored with a quick access hash. - -* nmcli::ipv4::::on_uuid = interface UUID -* nmcli::ipv4::::sequence = sequence number -* nmcli::uuid::::ipv{4,6}::ip::::ip_address = IP address -* nmcli::uuid::::ipv{4,6}::ip::::subnet_mask = subnet mask (CIDR notation) -* nmcli::uuid::::ipv{4,6}::dns = comma-separated list of DNS IP addresses -* nmcli::uuid::::ipv{4,6}::gateway = comma-separated list of DNS IP addresses -* nmcli::uuid::::ipv{4,6}::route:: = Route info (ie: 'dst = 0.0.0.0/0, nh = 192.168.255.254, mt = 428', or 'dst = 192.168.0.0/16, nh = 0.0.0.0, mt = 428'.) - -Bond data is stored in these hashes; - -* nmcli::bond::::uuid = The UUID on the bond -* nmcli::bond::::carrier = 1,0 - indicates if the bond has a connection or not. -* nmcli::bond::::operstate = 1,0 - indicates if the bond is operational or not. -* nmcli::bond::::up = 1,0 - indicates if the bond up up or not. -* nmcli::bond::::interface::::up = 1,0 - indicates if the child interface is up or not. - -Bridge data is simple, but also made easy to find. The only real data is the hash references for the interfaces connected to the bridge. - -* nmcli::bridge::::uuid = The UUID of the bridge -* nmcli::bridge::::interface::::status = This is the link data for the connected interface (ie: 'BROADCAST,MULTICAST,MASTER,UP,LOWER_UP'). - -To make it easier to find interfaces, the following look up hash is available. - -* nmcli::interface::::uuid = The UUID of the interface -* nmcli::mac_address::::uuid = $anvil->data->{nmcli}{mac_address}{$mac_address}{uuid}, - - -=cut - - foreach my $variable (sort {$a cmp $b} keys %{$anvil->data->{config}}) - { - print $variable.": [".$anvil->data->{config}{$variable}."]\n"; + if ($parent_bond_name eq "--") + { + $parent_bond_name = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { parent_bond_name => $parent_bond_name }}); + } + + if ($parent_bond_name) + { + if ($parent_bond_name eq $bond_name) + { + # Already a member of the bond. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0395", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + link_name => $link_name, + nm_uuid => $nm_uuid, + }, + }); + next; + } + else + { + # The interface is a member of another bond, switching it to this bond.\n"; + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0396", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + link_name => $link_name, + nm_uuid => $nm_uuid, + old_bond => $parent_bond_name, + }, + }); + } + } + else + { + # The interface needs to be connected to the bond. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0397", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + link_name => $link_name, + nm_uuid => $nm_uuid, + }, + }); + } + + # Disabling DHCP on the interface + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $link_name, + device_uuid => $nm_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $nm_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $nm_uuid, variable => "ipv6.method", value => "disabled"}); + + # Connecting the interface to the bond + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0399", + job_uuid => $anvil->data->{job}{uuid}, + 'print' => 1, + log_level => 1, + file => $THIS_FILE, + line => __LINE__, + variables => { + link_name => $link_name, + bond_name => $bond_name, + }, + }); + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." connection.master ".$bond_name." connection.slave-type bond"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + ($output, $return_code) = $anvil->System->call({shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + if ($return_code) + { + # Adding the link failed. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0484", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + link_name => $link_name, + bond_name => $bond_name, + return_code => $return_code, + output => $output, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + # Reset the interface. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0403", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $link_name, + device_uuid => $nm_uuid, + }, + }); + ($output, $return_code) = $anvil->Network->reset_connection({debug => 2, uuid => $nm_uuid}); + + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + } } return(0); @@ -972,6 +1263,392 @@ sub reconfigure_ip_addresses { my ($anvil) = @_; + my $local_host = $anvil->Get->short_host_name(); + my $bcn_count = $anvil->data->{config}{bcn_count}; + my $ifn_count = $anvil->data->{config}{ifn_count}; + my $sn_count = $anvil->data->{config}{sn_count}; + my $mn_count = $anvil->data->{config}{mn_count}; + my $dns = $anvil->data->{config}{dns}; + my $gateway = $anvil->data->{config}{gateway}; + my $gw_interface = $anvil->data->{config}{gateway_interface}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + local_host => $local_host, + bcn_count => $bcn_count, + ifn_count => $ifn_count, + sn_count => $sn_count, + mn_count => $mn_count, + dns => $dns, + gateway => $gateway, + gw_interface => $gw_interface, + }}); + foreach my $network_type ("bcn", "sn", "mn", "ifn") + { + $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; } + elsif ($network_type eq "mn") { $count = $mn_count; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + + # This is the old type of network config + foreach my $i (1..$count) + { + my $ip_key = $network_type.$i."_ip"; + my $subnet_key = $network_type.$i."_subnet_mask"; + my $link1_name = $network_type.$i."_link1"; + my $link2_name = $network_type.$i."_link2"; + my $bond_name = $network_type.$i."_bond1"; + my $bridge_name = $network_type.$i."_bridge1"; + my $is_gateway = $gw_interface eq $network_type.$i ? 1 : 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_key => $ip_key, + subnet_key => $subnet_key, + link1_name => $link1_name, + link2_name => $link2_name, + bond_name => $bond_name, + bridge_name => $bridge_name, + is_gateway => $is_gateway, + }}); + + if ((not exists $anvil->data->{config}{$ip_key}) or (not $anvil->data->{config}{$ip_key})) + { + # No IP for this network + next; + } + + my $ip_address = $anvil->data->{config}{$ip_key}; + my $subnet_mask = $anvil->data->{config}{$subnet_key}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + ip_address => $ip_address, + subnet_mask => $subnet_mask, + }}); + + if (($subnet_mask !~ /^\d+$/) or ($subnet_mask < 1) or ($subnet_mask > 32)) + { + # Convert to CIDR + my $cidr = $anvil->Convert->cidr({subnet_mask => $subnet_mask}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { cidr => $cidr }}); + if (not $cidr) + { + # The subnet_mask is not valid. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0487", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + file => $THIS_FILE, + line => __LINE__, + variables => { subnet_mask => $subnet_mask }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + $subnet_mask = $cidr; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { subnet_mask => $subnet_mask }}); + } + + # What device are we assigning the IP address to? + my $on_device = ""; + my $on_device_uuid = ""; + if ((exists $anvil->data->{nmcli}{bridge}{$bridge_name}) && ($anvil->data->{nmcli}{bridge}{$bridge_name}{uuid})) + { + $on_device = $bridge_name; + $on_device_uuid = $anvil->data->{nmcli}{bridge}{$bridge_name}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + on_device => $on_device, + on_device_uuid => $on_device_uuid, + }}); + } + elsif ((exists $anvil->data->{nmcli}{bond}{$bond_name}) && ($anvil->data->{nmcli}{bond}{$bond_name}{uuid})) + { + $on_device = $bond_name; + $on_device_uuid = $anvil->data->{nmcli}{bond}{$bond_name}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + on_device => $on_device, + on_device_uuid => $on_device_uuid, + }}); + } + elsif ((exists $anvil->data->{nmcli}{interface}{$link1_name}) && ($anvil->data->{nmcli}{interface}{$link1_name}{uuid})) + { + $on_device = $link1_name; + $on_device_uuid = $anvil->data->{nmcli}{interface}{$link1_name}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + on_device => $on_device, + on_device_uuid => $on_device_uuid, + }}); + } + else + { + # Failed to find a device to assign this IP address to. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0488", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + file => $THIS_FILE, + line => __LINE__, + variables => { + network => $network_type.$i, + ip_address => $ip_address, + subnet_mask => $subnet_mask, + }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + # Check to see if the IP address is assigned yet. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0393", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + ip_address => $ip_address, + subnet_mask => $subnet_mask, + device => $on_device, + }, + }); + my $clear_ip_from = ""; + if (exists $anvil->data->{nmcli}{ipv4}{$ip_address}) + { + my $ip_uuid = $anvil->data->{nmcli}{ipv4}{$ip_address}{on_uuid}; + my $current_device = $anvil->data->{nmcli}{uuid}{$ip_uuid}{device}; + my $ip_sequence = $anvil->data->{nmcli}{ipv4}{$ip_address}{sequence}; + my $current_subnet_mask = $anvil->data->{nmcli}{uuid}{$ip_uuid}{ipv4}{ip}{$ip_sequence}{subnet_mask}; + my $current_gateway = $anvil->data->{nmcli}{uuid}{$ip_uuid}{ipv4}{gateway}; + my $current_dns = $anvil->data->{nmcli}{uuid}{$ip_uuid}{ipv4}{dns}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:ip_uuid' => $ip_uuid, + 's2:current_device' => $current_device, + 's3:ip_sequence' => $ip_sequence, + 's4:current_subnet_mask' => $current_subnet_mask, + 's5:current_gateway' => $current_gateway, + 's6:current_dns' => $current_dns, + }}); + if (not $ip_uuid) + { + # The IP exists, but wasn't translate to a network manager UUID. + $anvil->Job->update_progress({ + progress => 100, + message => "error_0489", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + file => $THIS_FILE, + line => __LINE__, + variables => { ip_address => $ip_address }, + }); + $anvil->nice_exit({exit_code => 1}); + } + + # The IP exists, checking if it needs to be updated. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0398", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => {}, + }); + if ($on_device ne $current_device) + { + # The IP address is on another device, we'll move it + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0402", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { device => $current_device }, + }); + $clear_ip_from = $current_device; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { clear_ip_from => $clear_ip_from }}); + } + elsif ($subnet_mask ne $current_subnet_mask) + { + # The current subnet mask is different, will update. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0410", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { current_subnet_mask => $current_subnet_mask }, + }); + } + elsif ($gateway ne $current_gateway) + { + # The current gateway is different, will update. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0411", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { current_gateway => $current_gateway }, + }); + } + elsif ($dns ne $current_dns) + { + # The current DNS is different, will update. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0412", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { current_dns => $current_dns }, + }); + } + else + { + # No update is needed. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0413", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + next; + } + } + else + { + # The IP address needs to be assigned. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0414", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + } + + if ($clear_ip_from) + { + # Clear the IP off the old device + my $old_uuid = $anvil->data->{nmcli}{device}{$clear_ip_from}{uuid}; + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0408", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $clear_ip_from, + device_uuid => $old_uuid, + }, + }); + my ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $old_uuid, variable => "ipv4.method", value => "disabled"}); + ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $old_uuid, variable => "ipv6.method", value => "disabled"}); + + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0403", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $clear_ip_from, + device_uuid => $old_uuid, + }, + }); + ($output, $return_code) = $anvil->Network->reset_connection({debug => 2, uuid => $old_uuid}); + } + + # Now assign the IP. + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$on_device_uuid." ipv4.method manual ipv4.addresses ".$ip_address."/".$subnet_mask; + if ($is_gateway) + { + if ($gateway) + { + $shell_call .= " ipv4.gateway ".$gateway; + } + if ($dns) + { + $shell_call .= " ipv4.dns ".$dns; + } + } + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + # Restart the interface + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0403", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { + device => $on_device, + device_uuid => $on_device_uuid, + }, + }); + ($output, $return_code) = $anvil->Network->reset_connection({debug => 2, uuid => $on_device_uuid}); + + # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); + $anvil->Network->collect_data({debug => 2}); + } + } + +=cut + form::config_step2::dns::value=8.8.8.8,8.8.4.4 + + form::config_step2::gateway::value=192.168.255.254 + + form::config_step2::gateway_interface::value=ifn1 + + + form::config_step2::bcn1_ip::value=10.201.4.1 + + form::config_step2::bcn1_subnet_mask::value=255.255.0.0 + + + form::config_step2::ifn1_ip::value=192.168.4.1 + + form::config_step2::ifn1_subnet_mask::value=255.255.0.0 + +=cut return(0); } @@ -1007,11 +1684,20 @@ sub reconfigure_interfaces { # Rescan. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); $anvil->Network->collect_data({debug => 2}); } } - my $local_host = $anvil->Get->short_host_name(); my $prefix = $anvil->data->{config}{prefix}; my $sequence = $anvil->data->{config}{sequence}; @@ -1049,6 +1735,13 @@ sub reconfigure_interfaces link2_mac_key => $link2_mac_key, }}); + # This will get set to '1' if there's a link2 + my $bond_name = $network_type.$i."_bond1"; + $anvil->data->{config}{$bond_name} = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + }}); + # If the user had the option to create a network but didn't, there will be no link1 # mac to set. next if not exists $anvil->data->{config}{$link1_mac_key}; @@ -1153,6 +1846,8 @@ sub reconfigure_interfaces log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, job_status => "failed", variables => { mac_address => $wanted_link2_mac, @@ -1169,7 +1864,6 @@ sub reconfigure_interfaces } # There's a second interface, so create a bond. - my $bond_name = $network_type.$i."_bond1"; $anvil->data->{config}{$bond_name} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "config::${bond_name}" => $anvil->data->{config}{$bond_name}, @@ -1208,15 +1902,14 @@ sub rename_interface 's6:type' => $type, }}); - die if not $wanted_link_name; - die if not $old_device; - # Tell the user what we're about to rename $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0383", log_level => 1, 'print' => 1, + file => $THIS_FILE, + line => __LINE__, job_uuid => $anvil->data->{job}{uuid}, variables => { mac_address => $mac_address, @@ -1259,6 +1952,8 @@ sub rename_interface message => "message_0384", log_level => 1, 'print' => 1, + file => $THIS_FILE, + line => __LINE__, job_uuid => $anvil->data->{job}{uuid}, variables => { file => $anvil->data->{path}{configs}{'persistent-net'} }, }); @@ -1280,6 +1975,8 @@ sub rename_interface message => "error_0043", log_level => 1, 'print' => 1, + file => $THIS_FILE, + line => __LINE__, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", variables => { file => $anvil->data->{path}{configs}{'persistent-net'} }, @@ -1299,6 +1996,8 @@ sub rename_interface message => "message_0385", log_level => 1, 'print' => 1, + file => $THIS_FILE, + line => __LINE__, job_uuid => $anvil->data->{job}{uuid}, variables => { name => $connection_interface_name }, }); @@ -1326,6 +2025,8 @@ sub rename_interface message => "error_0481", log_level => 1, 'print' => 1, + file => $THIS_FILE, + line => __LINE__, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", variables => { output => $output }, @@ -1343,6 +2044,8 @@ sub rename_interface log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, variables => { new_name => $wanted_link_name, old_device => $old_device, @@ -1351,8 +2054,22 @@ sub rename_interface if ($old_device eq $wanted_link_name) { - print "Both the netbios name: [".$wanted_link_name."], IP device name: [".$old_device."] are the same, match would break!\n"; - die; + # Both the netbios name and the old device name are the same, match would break! + $anvil->Job->update_progress({ + progress => 100, + message => "error_0490", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + job_status => "failed", + variables => { + wanted_link_name => $wanted_link_name, + old_device => $old_device, + }, + }); + $anvil->nice_exit({exit_code => 1}); } my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection modify ".$nm_uuid." match.interface-name \"".$wanted_link_name." ".$old_device."\""; @@ -1382,6 +2099,8 @@ sub rename_interface 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", + file => $THIS_FILE, + line => __LINE__, variables => { new_name => $wanted_link_name, old_device => $old_device, @@ -1397,6 +2116,8 @@ sub rename_interface message => "message_0387", log_level => 1, 'print' => 1, + file => $THIS_FILE, + line => __LINE__, job_uuid => $anvil->data->{job}{uuid}, variables => { old_device => $old_device }, }); @@ -1418,6 +2139,16 @@ sub rename_interface }}); # Re-read the updated data + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 2}), + message => "message_0394", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + variables => { }, + }); $anvil->Network->collect_data({debug => 2}); # Set the reboot flag. @@ -2537,6 +3268,8 @@ AND job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, }); # If we're in a cluster, abort. @@ -2559,6 +3292,8 @@ AND job_status => "failed", 'print' => 1, log_level => 1, + file => $THIS_FILE, + line => __LINE__, }); $anvil->nice_exit({exit_code => 7}); } From ff0e6c3575707fe19ad1c4a53dd0561b3c270c61 Mon Sep 17 00:00:00 2001 From: digimer Date: Sat, 13 Jan 2024 20:17:59 -0500 Subject: [PATCH 19/43] Updated anvil-daemon to call scan-network if no interfaces exist. Signed-off-by: digimer --- Anvil/Tools/Network.pm | 34 ++++++++++++++++++++++++++++++++++ tools/anvil-daemon | 21 +++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 82ba92e3..9ed4baf0 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -1354,6 +1354,15 @@ sub collect_data } next; } + if ($line =~ / (\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/i) + { + # This is the real MAC address of the link. + my $mac_address = $1; + $anvil->data->{nmcli}{perm_mac_address}{$in_link} = $mac_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "nmcli::perm_mac_address::${in_link}" => $anvil->data->{nmcli}{perm_mac_address}{$in_link}, + }}); + } } else { @@ -1427,6 +1436,8 @@ sub collect_data my $mtu_file = "/sys/class/net/".$device."/mtu"; if (-e $mac_address_file) { + ### NOTE: This will always be the active link's MAC in a bond, so tis gets + ### overwritten when the bond device is parsed. my $mac_address = $anvil->Storage->read_file({file => $mac_address_file}); $mac_address =~ s/\n$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); @@ -1472,6 +1483,29 @@ sub collect_data } } + # Loop through interfaces and see if the MAC address needs to be updated if it's the backup interface + # in a bond. + foreach my $device (sort {$a cmp $b} keys %{$anvil->data->{nmcli}{interface}}) + { + my $uuid = $anvil->data->{nmcli}{interface}{$device}{uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:device" => $device, + "s2:uuid" => $uuid, + }}); + + if ((exists $anvil->data->{nmcli}{perm_mac_address}{$device}) && ($anvil->data->{nmcli}{perm_mac_address}{$device})) + { + # There's a permanent MAC address, overwrite the one we read earlier. + my $perm_mac_address = $anvil->data->{nmcli}{perm_mac_address}{$device}; + $anvil->data->{nmcli}{uuid}{$uuid}{mac_address} = $perm_mac_address; + $anvil->data->{nmcli}{mac_address}{$perm_mac_address}{uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:nmcli::uuid::${uuid}::mac_address" => $anvil->data->{nmcli}{uuid}{$uuid}{mac_address}, + "s2:nmcli::mac_address::${perm_mac_address}::uuid" => $anvil->data->{nmcli}{mac_address}{$perm_mac_address}{uuid}, + }}); + } + } + # Should we start interfaces? if ($start) { diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 794827c1..9d0c002a 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -405,6 +405,27 @@ sub check_network } } + # Check that there's at least one entry in 'network_interfaces' and, if not, call scan-network. + if (1) + { + my $query = "SELECT COUNT(*) FROM network_interfaces WHERE network_interface_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); + + my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); + if (not $count) + { + # Run scan-network + my $shell_call = $anvil->data->{path}{directories}{scan_agents}."/scan-network/scan-network".$anvil->Log->switches; + $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}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } + } + return(0); } From 1373345f33cd9bf59f00aa17a89e3a29101bd934 Mon Sep 17 00:00:00 2001 From: digimer Date: Sun, 14 Jan 2024 00:55:36 -0500 Subject: [PATCH 20/43] Fixed a bug where inactive links weren't started * anvil-configure-host now requests a start on the first scan of network->collect_date(). * Fixed a minor bug where networks without bonds were being processed needlessly. Signed-off-by: digimer --- tools/anvil-configure-host | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index d402578e..6778f020 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -479,7 +479,7 @@ ORDER BY $anvil->data->{sys}{reboot} = 0; # Read the existing network data - $anvil->Network->collect_data({debug => 2}); + $anvil->Network->collect_data({debug => 2, start => 1}); # This will be set to '1' if we make a change. my $changes = 0; @@ -939,10 +939,11 @@ sub reconfigure_bonds if (not $anvil->data->{config}{$bond_name}) { # No bond on this network. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "config::${bond_name}" => $anvil->data->{config}{$bond_name}, - }}); + next; } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + }}); my $link_nm_uuids = []; @@ -1088,6 +1089,8 @@ sub reconfigure_bonds } # Now add the interfaces, disabling their ipv4.method first. + my $uuid_count = @{$link_nm_uuids}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid_count => $uuid_count }}); foreach my $nm_uuid (@{$link_nm_uuids}) { my $link_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{name}; From 76218dcd32ecc126a12e2d11aea07737926f51e3 Mon Sep 17 00:00:00 2001 From: digimer Date: Sun, 14 Jan 2024 23:09:13 -0500 Subject: [PATCH 21/43] Updated logging and debugging. Signed-off-by: digimer --- tools/anvil-configure-host | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 6778f020..30f15de0 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -40,6 +40,9 @@ my $anvil = Anvil::Tools->new(); $anvil->Get->switches({list => ["job-uuid"], man => $THIS_FILE}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); + # Make sure we're running as 'root' # $< == real UID, $> == effective UID if (($< != 0) && ($> != 0)) @@ -1125,7 +1128,7 @@ sub reconfigure_bonds file => $THIS_FILE, line => __LINE__, variables => { - link_name => $link_name, + link_name => $link_device ? $link_device : $link_name, nm_uuid => $nm_uuid, }, }); @@ -1143,7 +1146,7 @@ sub reconfigure_bonds file => $THIS_FILE, line => __LINE__, variables => { - link_name => $link_name, + link_name => $link_device ? $link_device : $link_name, nm_uuid => $nm_uuid, old_bond => $parent_bond_name, }, @@ -1162,7 +1165,7 @@ sub reconfigure_bonds file => $THIS_FILE, line => __LINE__, variables => { - link_name => $link_name, + link_name => $link_device ? $link_device : $link_name, nm_uuid => $nm_uuid, }, }); @@ -1178,7 +1181,7 @@ sub reconfigure_bonds file => $THIS_FILE, line => __LINE__, variables => { - device => $link_name, + device => $link_device ? $link_device : $link_name, device_uuid => $nm_uuid, }, }); @@ -1195,7 +1198,7 @@ sub reconfigure_bonds file => $THIS_FILE, line => __LINE__, variables => { - link_name => $link_name, + link_name => $link_device ? $link_device : $link_name, bond_name => $bond_name, }, }); @@ -1218,7 +1221,7 @@ sub reconfigure_bonds job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", variables => { - link_name => $link_name, + link_name => $link_device ? $link_device : $link_name, bond_name => $bond_name, return_code => $return_code, output => $output, @@ -1237,7 +1240,7 @@ sub reconfigure_bonds file => $THIS_FILE, line => __LINE__, variables => { - device => $link_name, + device => $link_device ? $link_device : $link_name, device_uuid => $nm_uuid, }, }); From ebd96c7eb30750b0d6c4bb175eeab9c4de3e0ab2 Mon Sep 17 00:00:00 2001 From: digimer Date: Mon, 15 Jan 2024 00:25:46 -0500 Subject: [PATCH 22/43] Disabled the collect_ifcfg_data() method entirely. Signed-off-by: digimer --- scancore-agents/scan-network/scan-network | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index c40d67e3..87cab0f3 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -590,12 +590,12 @@ sub collect_data ### TODO: Remove this check when ifcfg-X support is dropped. my $network_type = $anvil->System->check_network_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); - if ($network_type eq "ifcfg") - { - # Using the old 'ifcfg-X' style. - collect_data_ifcfg($anvil); - return(0); - } +# if ($network_type eq "ifcfg") +# { +# # Using the old 'ifcfg-X' style. +# collect_data_ifcfg($anvil); +# return(0); +# } # Collect data from nmcli $anvil->Network->collect_data({debug => 2}); From d7aa7966dcac73f171e84a90c2226898104746bb Mon Sep 17 00:00:00 2001 From: digimer Date: Tue, 16 Jan 2024 00:06:29 -0500 Subject: [PATCH 23/43] Fixed a couple bugs * Network->collect_data() wasn't deleting old data before rescans. * anvil-configure-host wasn't checking links that should be in a bond if the bond already existed. Signed-off-by: digimer --- Anvil/Tools/Network.pm | 5 ++++ share/words.xml | 2 +- tools/anvil-configure-host | 47 ++++++++++++++++++-------------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 9ed4baf0..75a8ba39 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -980,6 +980,11 @@ sub collect_data start => $start, }}); + if (exists $anvil->data->{nmcli}) + { + delete $anvil->data->{nmcli}; + } + # Use nmcli to collect the data. my $shell_call = $anvil->data->{path}{exe}{nmcli}." --get-values uuid,type,active,state,name connection show"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); diff --git a/share/words.xml b/share/words.xml index 3031fcb7..2fa2dd03 100644 --- a/share/words.xml +++ b/share/words.xml @@ -3330,7 +3330,7 @@ proceeding. - Connecting the interface: [#!variable!link_name!#] to the bond: [#!variable!bond_name!#]. Checking if the bridge: [#!variable!bridge_name!#] exists and that it is on: [#!variable!on_device!#] - The bridge exists! - - The IP address is on: [#!variable!current_device!#], will move the IP. + - The IP address is on: [#!variable!device!#], will move the IP. - Resetting the device: [#!variable!device!#] (#!variable!device_uuid!#) to make sure the new config takes effect. - Checking that the device: [#!variable!on_device!#] is connected to this bridge. - The device is connected to the bridge already. diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 30f15de0..9260c70b 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -944,11 +944,31 @@ sub reconfigure_bonds # No bond on this network. next; } + + my $link_nm_uuids = []; + my $link1_name = $network_type.$i."_link1"; + my $link1_mac_key = $network_type.$i."_link1_mac_to_set"; + my $link1_mac = $anvil->data->{config}{$link1_mac_key}; + my $link1_nm_uuid = $anvil->data->{nmcli}{mac_address}{$link1_mac}{uuid}; + + my $link2_name = $network_type.$i."_link2"; + my $link2_mac_key = $network_type.$i."_link2_mac_to_set"; + my $link2_mac = $anvil->data->{config}{$link2_mac_key}; + my $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$link2_mac}{uuid}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "config::${bond_name}" => $anvil->data->{config}{$bond_name}, + link1_name => $link1_name, + link1_mac_key => $link1_mac_key, + link1_mac => $link1_mac, + link1_nm_uuid => $link1_nm_uuid, + link2_name => $link2_name, + link2_mac_key => $link2_mac_key, + link2_mac => $link2_mac, + link2_nm_uuid => $link2_nm_uuid, }}); - my $link_nm_uuids = []; + # Push the two nm_uuids into the array for later checking/adding to the bond. + push @{$link_nm_uuids}, $link1_nm_uuid; + push @{$link_nm_uuids}, $link2_nm_uuid; # Check if the bond exists or not. $anvil->Job->update_progress({ @@ -978,29 +998,6 @@ sub reconfigure_bonds else { # It doesn't, create it. - my $link1_name = $network_type.$i."_link1"; - my $link1_mac_key = $network_type.$i."_link1_mac_to_set"; - my $link1_mac = $anvil->data->{config}{$link1_mac_key}; - my $link1_nm_uuid = $anvil->data->{nmcli}{mac_address}{$link1_mac}{uuid}; - - my $link2_name = $network_type.$i."_link2"; - my $link2_mac_key = $network_type.$i."_link2_mac_to_set"; - my $link2_mac = $anvil->data->{config}{$link2_mac_key}; - my $link2_nm_uuid = $anvil->data->{nmcli}{mac_address}{$link2_mac}{uuid}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - link1_name => $link1_name, - link1_mac_key => $link1_mac_key, - link1_mac => $link1_mac, - link1_nm_uuid => $link1_nm_uuid, - link2_name => $link2_name, - link2_mac_key => $link2_mac_key, - link2_mac => $link2_mac, - link2_nm_uuid => $link2_nm_uuid, - }}); - - push @{$link_nm_uuids}, $link1_nm_uuid; - push @{$link_nm_uuids}, $link2_nm_uuid; - $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 2}), message => "message_0392", From 92ed77e05b6629315cdca4a0c0127e1123f7973d Mon Sep 17 00:00:00 2001 From: digimer Date: Tue, 16 Jan 2024 11:52:19 -0500 Subject: [PATCH 24/43] Fixed a bug blocking most jobs from running. * Also updated a bunch of 'apache' ownership calls to now use 'striker-ui-api'. Signed-off-by: digimer --- Anvil/Tools/Log.pm | 4 ++-- Anvil/Tools/System.pm | 4 ++-- tools/anvil-configure-host | 5 +++-- tools/anvil-daemon | 26 ++++++++++++++------------ tools/anvil-download-file | 8 ++++---- tools/anvil-parse-fence-agents | 4 ++-- tools/anvil-sync-shared | 2 +- tools/striker-manage-install-target | 2 +- tools/striker-prep-database | 6 +++--- 9 files changed, 32 insertions(+), 29 deletions(-) diff --git a/Anvil/Tools/Log.pm b/Anvil/Tools/Log.pm index db627adb..7bcb0bf2 100644 --- a/Anvil/Tools/Log.pm +++ b/Anvil/Tools/Log.pm @@ -491,7 +491,7 @@ sub entry binmode($anvil->data->{HANDLE}{'log'}{main}, ':encoding(utf-8)'); print $THIS_FILE." ".__LINE__."; HANDLE::log::main: [".$anvil->data->{HANDLE}{'log'}{main}."]\n" if $test; - # Make sure it can be written to by apache. + # Make sure it can be written to by striker-ui-api. $anvil->Storage->change_mode({test => $test, debug => $debug, path => $log_file, mode => "0666"}); } @@ -531,7 +531,7 @@ sub entry $anvil->data->{HANDLE}{'log'}{alert} = $file_handle; print $THIS_FILE." ".__LINE__."; HANDLE::log::alert: [".$anvil->data->{HANDLE}{'log'}{alert}."]\n" if $test; - # Make sure it can be written to by apache. + # Make sure it can be written to by striker-ui-api. $anvil->Storage->change_mode({test => $test, debug => $debug, path => $log_file, mode => "0666"}); } diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index f6e4d971..e45ec6d4 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -3237,8 +3237,8 @@ sub generate_state_json backup => 0, file => $json_file, body => $json, - group => "apache", - user => "apache", + group => "striker-ui-api", + user => "striker-ui-api", mode => "0644", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error }}); diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index 9260c70b..a8f4c634 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -153,7 +153,7 @@ sub do_reboot return(0); } -# This updates the passwords on the root user, admin user, database and apache user. +# This updates the passwords on the root user, admin user, database and striker-ui-api user. sub update_passwords { my ($anvil) = @_; @@ -354,10 +354,11 @@ sub reconfigure_network } } + ### NOTE: No longer needed, we don't use apache anymore. # If we're a striker, check apache's config. if ($type eq "striker") { - $anvil->Striker->check_httpd_conf({debug => 2}); + #$anvil->Striker->check_httpd_conf({debug => 2}); } # Now configure the network. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 9d0c002a..d9f44848 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -1123,7 +1123,7 @@ sub check_journald return(0); } -# This creates, as needed, the setuid wrappers used by apache to make certain system calls. +# This creates, as needed, the setuid wrappers used by striker-ui-api to make certain system calls. sub check_setuid_wrappers { my ($anvil) = @_; @@ -1366,7 +1366,7 @@ AND # Check the firewall needs to be updated. check_firewall($anvil); - # If we're a striker, check apache + # If we're a striker, check striker-ui-api my $host_type = $anvil->Get->host_type; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); if ($host_type eq "striker") @@ -1538,10 +1538,6 @@ sub run_jobs # changed on disk. $anvil->data->{sys}{jobs_running} = 0; - # If we're not configured, we won't hold on starting jobs - my $configured = $anvil->System->check_if_configured; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configured => $configured }}); - # We'll also update the jobs.json file. my $jobs_file = "{\"jobs\":[\n"; @@ -1596,8 +1592,14 @@ sub run_jobs 's14:updated_seconds_ago' => $updated_seconds_ago, }}); - # If we're mapping, we'll only run 'anvil-configure-host' jobs on this host. - next if $job_command !~ /anvil-configure-host/; + # If we're not configured, we will only run the 'anvil-configure-host' job + my $configured = $anvil->System->check_if_configured; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configured => $configured }}); + + if ((not $configured) && ($job_command !~ /anvil-configure-host/)) + { + next; + } # To minimize the chance of race conditions, any given command will be called only # once at a time. If two jobs of the same command exist, only one will be called. @@ -1880,8 +1882,8 @@ sub run_jobs overwrite => 1, backup => 0, mode => "0644", - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", }); return(0); @@ -1921,8 +1923,8 @@ sub check_files { my $failed = $anvil->Storage->make_directory({ directory => $directory, - group => "apache", - user => "apache", + group => "striker-ui-api", + user => "striker-ui-api", mode => "0777", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { failed => $failed }}); diff --git a/tools/anvil-download-file b/tools/anvil-download-file index a28e49ce..a5937a73 100755 --- a/tools/anvil-download-file +++ b/tools/anvil-download-file @@ -222,8 +222,8 @@ sub download_file debug => 2, directory => $save_to, mode => "0777", - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); } @@ -233,8 +233,8 @@ sub download_file debug => 2, directory => $anvil->data->{path}{directories}{shared}{temp}, mode => "0777", - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); } diff --git a/tools/anvil-parse-fence-agents b/tools/anvil-parse-fence-agents index c4ee440b..d8ffb8b5 100755 --- a/tools/anvil-parse-fence-agents +++ b/tools/anvil-parse-fence-agents @@ -91,8 +91,8 @@ sub refresh_unified_metadata backup => 0, file => $anvil->data->{path}{data}{fences_unified_metadata}, body => $anvil->data->{fences}{unified_xml}, - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", mode => "0666", }); } diff --git a/tools/anvil-sync-shared b/tools/anvil-sync-shared index a0497555..a821c8ca 100755 --- a/tools/anvil-sync-shared +++ b/tools/anvil-sync-shared @@ -483,7 +483,7 @@ sub process_incoming_file $anvil->nice_exit({exit_code => 1}); } - # Change the owner as it'll be apache, which won't be a valid users on anvil members. + # Change the owner as it'll be striker-ui-api, which won't be a valid users on anvil members. $anvil->Storage->change_owner({ debug => 2, path => $target_file, diff --git a/tools/striker-manage-install-target b/tools/striker-manage-install-target index 73660356..10c5185a 100755 --- a/tools/striker-manage-install-target +++ b/tools/striker-manage-install-target @@ -709,7 +709,7 @@ sub setup_boot_environment { # Updated $anvil->Storage->change_mode({path => $kickstart_file, mode => "0664"}); - $anvil->Storage->change_owner({path => $kickstart_file, user => "apache", group => "apache" }); + $anvil->Storage->change_owner({path => $kickstart_file, user => "striker-ui-api", group => "striker-ui-api" }); print $anvil->Words->string({key => "message_0097", variables => { file => $kickstart_file }})."\n"; update_progress($anvil, $progress, "message_0097,!!file!".$kickstart_file."!!"); diff --git a/tools/striker-prep-database b/tools/striker-prep-database index 275a09ba..efe04be2 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -475,7 +475,7 @@ if ($local_uuid) ##################################################################################################### ### TODO: This will need to set the proper SELinux context. - # Apache run scripts can't call the system UUID, so we'll write it to a text file. + # striker-ui-api run scripts can't call the system UUID, so we'll write it to a text file. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "path::data::host_uuid" => $anvil->data->{path}{data}{host_uuid} }}); if (not -e $anvil->data->{path}{data}{host_uuid}) { @@ -483,8 +483,8 @@ if ($local_uuid) debug => 3, file => $anvil->data->{path}{data}{host_uuid}, body => $anvil->Get->host_uuid, - user => "apache", - group => "apache", + user => "striker-ui-api", + group => "striker-ui-api", mode => "0666", overwrite => 0, }); From 282fdbe7e004f0695fd65f2145e37f9a8dccb38e Mon Sep 17 00:00:00 2001 From: digimer Date: Tue, 16 Jan 2024 21:16:40 -0500 Subject: [PATCH 25/43] Fixed a bug where IPs were being marked repeatedly as DELETEd. * Database->get_ip_addresses() was marking IPs that weren't on a network we managed, the IP would be marked as DELETEd, which caused problems with initializing targets, and it generated a lot of repeat alerts. * Updated logging in Network.pm to help with debugging. Signed-off-by: digimer --- Anvil/Tools/Database.pm | 52 +++++++++++++---------------------- Anvil/Tools/Network.pm | 2 +- tools/anvil-daemon | 4 +-- tools/anvil-manage-dr | 4 +-- tools/striker-initialize-host | 5 ++-- 5 files changed, 27 insertions(+), 40 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 1f32f81e..287d627a 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -4579,51 +4579,37 @@ AND $on_interface = $anvil->data->{hosts}{host_uuid}{$host_uuid}{network_interfaces}{network_interface_uuid}{$ip_address_on_uuid}{network_interface_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { on_interface => $on_interface }}); } - my $on_network = ($on_interface =~ /^(.*?)_/)[0]; - if (not defined $on_network) - { - # This isn't a network we should know about (ie: it might be a stray 'virbrX' - # birdge), delete this IP. - my $query = " -UPDATE - ip_addresses -SET - ip_address_note = 'DELETED', - modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)." -WHERE - ip_address_uuid = ".$anvil->Database->quote($ip_address_uuid)." -;"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); - $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); - next; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { on_network => $on_network }}); - # Store it. - $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{ip_address} = $ip_address_address; - $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{subnet_mask} = $ip_address_subnet_mask; - $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{on_interface} = $on_interface; + # We want to be able to map IPs to hosts. + $anvil->data->{ip_addresses}{$ip_address_address}{host_uuid} = $ip_address_host_uuid; + $anvil->data->{ip_addresses}{$ip_address_address}{ip_address_uuid} = $ip_address_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "hosts::host_uuid::${host_uuid}::network::${on_network}::ip_address" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{ip_address}, - "hosts::host_uuid::${host_uuid}::network::${on_network}::subnet_mask" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{subnet_mask}, - "hosts::host_uuid::${host_uuid}::network::${on_network}::on_interface" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{on_interface}, + "ip_addresses::${ip_address_address}::host_uuid" => $anvil->data->{ip_addresses}{$ip_address_address}{host_uuid}, + "ip_addresses::${ip_address_address}::ip_address_uuid" => $anvil->data->{ip_addresses}{$ip_address_address}{ip_address_uuid}, }}); $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{subnet_mask} = $ip_address_subnet_mask; $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_interface} = $on_interface; - $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_network} = $on_network; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "hosts::host_uuid::${host_uuid}::ip_address::${ip_address_address}::subnet_mask" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{subnet_mask}, "hosts::host_uuid::${host_uuid}::ip_address::${ip_address_address}::on_interface" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_interface}, - "hosts::host_uuid::${host_uuid}::ip_address::${ip_address_address}::on_network" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_network}, }}); - # We also want to be able to map IPs to hosts. - $anvil->data->{ip_addresses}{$ip_address_address}{host_uuid} = $ip_address_host_uuid; - $anvil->data->{ip_addresses}{$ip_address_address}{ip_address_uuid} = $ip_address_uuid; + # If this is an interface that doesn't belong to us, we're done. + my $on_network = ($on_interface =~ /^(.*?)_/)[0]; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { on_network => $on_network }}); + next if not $on_network; + + # Store it by network. + $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{ip_address} = $ip_address_address; + $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{subnet_mask} = $ip_address_subnet_mask; + $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{on_interface} = $on_interface; + $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_network} = $on_network; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "ip_addresses::${ip_address_address}::host_uuid" => $anvil->data->{ip_addresses}{$ip_address_address}{host_uuid}, - "ip_addresses::${ip_address_address}::ip_address_uuid" => $anvil->data->{ip_addresses}{$ip_address_address}{ip_address_uuid}, + "hosts::host_uuid::${host_uuid}::network::${on_network}::ip_address" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{ip_address}, + "hosts::host_uuid::${host_uuid}::network::${on_network}::subnet_mask" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{subnet_mask}, + "hosts::host_uuid::${host_uuid}::network::${on_network}::on_interface" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{network}{$on_network}{on_interface}, + "hosts::host_uuid::${host_uuid}::ip_address::${ip_address_address}::on_network" => $anvil->data->{hosts}{host_uuid}{$host_uuid}{ip_address}{$ip_address_address}{on_network}, }}); } diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 75a8ba39..41c61f3a 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -2435,7 +2435,7 @@ sub get_ip_from_mac =head2 get_ips -This method checks the local system for interfaces and stores them in: +This method checks the target system for interfaces and stores them in: * C<< network::::interface::::ip >> - If an IP address is set * C<< network::::interface::::subnet_mask >> - If an IP is set diff --git a/tools/anvil-daemon b/tools/anvil-daemon index d9f44848..d0714920 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -456,7 +456,7 @@ sub handle_periodic_tasks # Check that the users we care about have ssh public keys and they're recorded in ssh_keys. $anvil->System->check_ssh_keys({debug => 2}); - $anvil->System->update_hosts({debug => 3}); + $anvil->System->update_hosts({debug => 2}); # Check if the files on disk have changed. Even if it is time to check, don't if a job is # running. @@ -1355,7 +1355,7 @@ AND } # Make sure /etc/hosts is updated. - $anvil->System->update_hosts(); + $anvil->System->update_hosts({debug => 2}); # This handles weird bits for things like bug work-arounds. handle_special_cases($anvil); diff --git a/tools/anvil-manage-dr b/tools/anvil-manage-dr index ad2286e0..b9e9cef8 100755 --- a/tools/anvil-manage-dr +++ b/tools/anvil-manage-dr @@ -1945,7 +1945,7 @@ sub process_remove ### If we're here, we can now update the resource config file to remove the DR host. # Refresh the IP info (usually scrubbed by this point) - $anvil->Database->get_ip_addresses(); + $anvil->Database->get_ip_addresses({debug => 2}); # First loop to build the node sections, then we'll loop to build the connections my $node1_volumes = ""; @@ -2901,7 +2901,7 @@ sub process_protect } # Refresh the IP info (usually scrubbed by this point) - $anvil->Database->get_ip_addresses(); + $anvil->Database->get_ip_addresses({debug => 2}); # The connections. Node 1 to 2 always uses the BCN, Either node to DR needs my $storage_network = "sn1"; diff --git a/tools/striker-initialize-host b/tools/striker-initialize-host index a55e7b87..3b4d0030 100755 --- a/tools/striker-initialize-host +++ b/tools/striker-initialize-host @@ -163,7 +163,7 @@ sub add_databases $anvil->Network->get_ips({debug => 3}); $anvil->Network->get_ips({ - debug => 3, + debug => 2, target => $target, remote_user => "root", password => $anvil->data->{data}{password}, @@ -171,7 +171,7 @@ sub add_databases }); my $local_host = $anvil->Get->short_host_name(); my ($match) = $anvil->Network->find_matches({ - debug => 3, + debug => 2, first => $local_host, second => $target, source => $THIS_FILE, @@ -283,6 +283,7 @@ sub add_databases # Find a match between the target and the peer. my ($match) = $anvil->Network->find_matches({ + debug => 2, first => $target, second => $uuid, source => $THIS_FILE, From 827cf1f331f34b5fc44c92c675bf044018fd25ca Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 17 Jan 2024 23:17:59 -0500 Subject: [PATCH 26/43] Fixed a bug that was crashing anvil-daemon * Network->find_matches() was trying to compare two IPs when the second IP wasn't actually defined. * Disabled scancore's blocking of running before the host is configured. Signed-off-by: digimer --- Anvil/Tools/Network.pm | 14 ++++++++------ Anvil/Tools/System.pm | 16 +++++++++------- tools/anvil-daemon | 1 - tools/scancore | 4 +++- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 41c61f3a..5b49a639 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -2079,7 +2079,7 @@ sub find_matches $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_matches()", parameter => "first" }}); return(""); } - elsif (ref($anvil->data->{network}{$first}) ne "HASH") + if (ref($anvil->data->{network}{$first}) ne "HASH") { $anvil->Network->load_ips({ debug => $debug, @@ -2096,12 +2096,13 @@ sub find_matches return(""); } } + if (not $second) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_matches()", parameter => "second" }}); return(""); } - elsif (ref($anvil->data->{network}{$second}) ne "HASH") + if (ref($anvil->data->{network}{$second}) ne "HASH") { $anvil->Network->load_ips({ debug => $debug, @@ -2145,13 +2146,14 @@ sub find_matches foreach my $second_interface (sort {$b cmp $a} keys %{$anvil->data->{network}{$second}{interface}}) { + next if not exists $anvil->data->{network}{$second}{interface}{$second_interface}{ip}; my $second_ip = $anvil->data->{network}{$second}{interface}{$second_interface}{ip}; my $second_subnet_mask = $anvil->data->{network}{$second}{interface}{$second_interface}{subnet_mask}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - second => $second, - second_interface => $second_interface, - second_ip => $second_ip, - second_subnet_mask => $second_subnet_mask, + 's1:second' => $second, + 's2:second_interface' => $second_interface, + 's3:second_ip' => $second_ip, + 's4:second_subnet_mask' => $second_subnet_mask, }}); if (($second_ip) && ($second_subnet_mask)) { diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index e45ec6d4..08baf5ff 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -2836,6 +2836,7 @@ sub disable_daemon return($return_code); } + =head2 generate_state_json This method generates the C<< all_status.json >> file. @@ -2925,13 +2926,14 @@ sub generate_state_json my $mac_address = $anvil->data->{network}{$host}{interface}{$interface}{mac_address}; my $iface_hash = {}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:interface" => $interface, - "s2:mac_address" => $mac_address, - "s3:type" => $type, - "s4:mtu" => $mtu, - "s5:configured" => $configured, - "s6:host_uuid" => $host_uuid, - "s7:host_key" => $host_key, + "s1:host" => $host, + "s2:interface" => $interface, + "s3:mac_address" => $mac_address, + "s4:type" => $type, + "s5:mtu" => $mtu, + "s6:configured" => $configured, + "s7:host_uuid" => $host_uuid, + "s8:host_key" => $host_key, }}); $iface_hash->{name} = $interface; $iface_hash->{type} = $type; diff --git a/tools/anvil-daemon b/tools/anvil-daemon index d0714920..c8d6796a 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -209,7 +209,6 @@ while(1) # Mark that we don't want to check the database now. $check_if_database_is_configured = 0; - if ($anvil->data->{sys}{database}{connections}) { # Run the normal tasks diff --git a/tools/scancore b/tools/scancore index 5c387936..e4e842d8 100755 --- a/tools/scancore +++ b/tools/scancore @@ -91,8 +91,10 @@ $anvil->Storage->record_md5sums(); # Connect to DBs. wait_for_database($anvil); +### NOTE: We need to collect data from the start. Once confirmed this isn't introducing old problems, remove +### this function # If we're not configured, sleep. -wait_until_configured($anvil); +#wait_until_configured($anvil); # Startup tasks. startup_tasks($anvil); From e03219d1d857bf7e44059f5bf3f911aadfd19398 Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 18 Jan 2024 23:29:27 -0500 Subject: [PATCH 27/43] Fixed a bug where non-strikers hung configuring their network. * Updated Job->update_progress() to log and return if there are not DB connections. * Bumped some logging in Database->connect(). * Deleted ifcfg code from anvil-configure-host. Signed-off-by: digimer --- Anvil/Tools/Database.pm | 7 +- Anvil/Tools/Job.pm | 6 + share/words.xml | 4 + tools/anvil-configure-host | 1046 +++--------------------------------- 4 files changed, 94 insertions(+), 969 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 287d627a..090fa04b 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -1688,7 +1688,6 @@ sub connect $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); my $count = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); if ($count < 1) { @@ -1778,6 +1777,9 @@ sub connect # Record this as successful $anvil->data->{sys}{database}{connections}++; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::database::connections" => $anvil->data->{sys}{database}{connections}, + }}); push @{$successful_connections}, $uuid; } @@ -1838,6 +1840,9 @@ sub connect $anvil->data->{sys}{database}{primary_db} = "" if $anvil->data->{sys}{database}{read_active} eq $uuid; $anvil->data->{sys}{database}{read_uuid} = "" if $anvil->data->{sys}{database}{read_uuid} eq $uuid; $anvil->data->{sys}{database}{connections}--; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "sys::database::connections" => $anvil->data->{sys}{database}{connections}, + }}); delete $anvil->data->{database}{$uuid}; next; } diff --git a/Anvil/Tools/Job.pm b/Anvil/Tools/Job.pm index f1658204..27146dea 100644 --- a/Anvil/Tools/Job.pm +++ b/Anvil/Tools/Job.pm @@ -745,6 +745,12 @@ sub update_progress $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::last_update" => $anvil->data->{sys}{last_update} }}); } + # If we don't have a database connection, we're done. + if (not $anvil->data->{sys}{database}{connections}) + { + return(0); + } + # Add variables to the message, if required if (ref($variables) eq "HASH") { diff --git a/share/words.xml b/share/words.xml index 2fa2dd03..6aba4a1a 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2708,6 +2708,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: The physical volume: [#!variable!pv_name!#] has been resized! The user answered: [#!variable!answer!#] + Failed to connect to any database, waiting before trying to connect again. We will reboot if we do not connect in: [#!variable!time_left!#] second. The host name: [#!variable!target!#] does not resolve to an IP address. @@ -3343,6 +3344,8 @@ proceeding. - The current DNS is: [#!variable!current_dns!#], will update. - No update is needed. - The IP address needs to be assigned. + [ Note ] - Reconfiguring the network will break connections. Disconnecting from the database before starting. It might take a bit before this system reconnects and progress can be seen. + [ Note ] - The network has reconnected to the database, configuring will complete shortly. Normal Password @@ -4153,6 +4156,7 @@ We will try to proceed anyway. ==== Please specify a storage group to use to add the new drive to. + [ Warning ] - After reconfiguring the network, we've failed to connect to any database for two minutes. Rebooting in case this fixes the connection. diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index a8f4c634..faec462b 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -505,9 +505,85 @@ ORDER BY { # Configure the network using Network Manager reconfigure_interfaces($anvil); + + ### NOTE: If we're not a striker, the update the job to say we're disconnecting to + ### reconfigure the network. + my $host_type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); + if ($host_type ne "striker") + { + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 50}), + message => "message_0415", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + }); + $anvil->Database->disconnect({debug => 2}); + } + + # These can brake the connection. reconfigure_bonds($anvil); reconfigure_bridges($anvil); reconfigure_ip_addresses($anvil); + + # Reconnect! + if ($host_type ne "striker") + { + my $time_now = time; + my $wait_until = $time_now + 120; + my $waiting = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + time_now => $time_now, + wait_until => $wait_until, + }}); + while ($waiting) + { + $anvil->refresh(); + $anvil->Database->connect({debug => 2}); + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::database::connections" => $anvil->data->{sys}{database}{connections} }}); + if ($anvil->data->{sys}{database}{connections}) + { + # We're back! + $waiting = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + } + else + { + # Sleep for a bit. + my $now_time = time; + my $time_left = $wait_until - $now_time; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + now_time => $now_time, + time_left => $time_left, + }}); + if ($time_left > 0) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0829", variables => { time_left => $time_left }}); + sleep 5; + } + else + { + # Give up and reboot. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0169"}); + do_reboot($anvil); + } + } + } + + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 75}), + message => "message_0416", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + }); + } } # If any virtio bridges exist, remove it/them. @@ -1641,18 +1717,6 @@ sub reconfigure_ip_addresses $anvil->Network->collect_data({debug => 2}); } } - -=cut - form::config_step2::dns::value=8.8.8.8,8.8.4.4 + - form::config_step2::gateway::value=192.168.255.254 + - form::config_step2::gateway_interface::value=ifn1 + - - form::config_step2::bcn1_ip::value=10.201.4.1 + - form::config_step2::bcn1_subnet_mask::value=255.255.0.0 + - - form::config_step2::ifn1_ip::value=192.168.4.1 + - form::config_step2::ifn1_subnet_mask::value=255.255.0.0 + -=cut return(0); } @@ -1740,8 +1804,8 @@ sub reconfigure_interfaces }}); # This will get set to '1' if there's a link2 - my $bond_name = $network_type.$i."_bond1"; - $anvil->data->{config}{$bond_name} = 0; + my $bond_name = $network_type.$i."_bond1"; + $anvil->data->{config}{$bond_name} = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "config::${bond_name}" => $anvil->data->{config}{$bond_name}, }}); @@ -2162,960 +2226,6 @@ sub rename_interface return(0); } -sub configure_ifcfg_network -{ - my ($anvil, $network_type) = @_; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); - -=cut - 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; } - elsif ($network_type eq "mn") { $count = $mn_count; } - my $localhost = $anvil->Get->short_host_name(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }}); - - - next if not $count; - foreach my $network_count (1..$count) - { - # If the user had the option to create a network but didn't, there will be no link1 - # mac to set. - my $this_network = $network_type.$network_count; - my $link1_key = $this_network."_link1_mac_to_set"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - this_network => $this_network, - link1_key => $link1_key, - }}); - - - next if not exists $anvil->data->{config}{$link1_key}; - next if not $anvil->data->{config}{$link1_key}; - 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->{config}{$link1_key}; - my $is_gateway = $this_network eq $gateway_interface ? 1 : 0; - my $link2_mac = defined $anvil->data->{config}{$link2_key} ? $anvil->data->{config}{$link2_key} : ""; - 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->{config}{$bridge_key} ? $anvil->data->{config}{$bridge_key} : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_key => $ip_key, - is_gateway => $is_gateway, - 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, - 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; - my $link1_nm_uuid = $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, - link1_nm_uuid => $link1_nm_uuid, - }}); - if ((exists $anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}) && ($anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}{name})) - { - $old_link1_nm_name = $anvil->data->{nmcli}{$local_host}{uuid}{$link1_nm_uuid}{name}; - $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; - my $link2_nm_uuid = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$old_link2_nm_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - old_link2_nm_name => $old_link2_nm_name, - link2_nm_uuid => $link2_nm_uuid, - }}); - if ((exists $anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}) && ($anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}{name})) - { - $old_link2_nm_name = $anvil->data->{nmcli}{$local_host}{uuid}{$link2_nm_uuid}{name}; - $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->{config}{$ip_key}) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0176", variables => { ip_key => $ip_key }}); - next; - } - else - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "config::${ip_key}" => $anvil->data->{config}{$ip_key} }}); - } - if (($anvil->data->{config}{$ip_key}) && - ($anvil->data->{config}{$ip_key} ne "dhcp") && - (not $anvil->Validate->ipv4({ip => $anvil->data->{config}{$ip_key}}))) - { - # 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->{config}{$ip_key}, - }}); - next; - } - - # The IP could be 'dhcp', we'll handle that in a bit. - my $ip_address = $anvil->data->{config}{$ip_key}; - my $subnet_mask = defined $anvil->data->{config}{$subnet_mask_key} ? $anvil->data->{config}{$subnet_mask_key} : ""; - $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 "mn") - { - $say_network = "Migration Network ".$network_count; - $say_interface = "mn".$network_count; - $interface_prefix = "MN"; - } - 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})) - { - # This is the device name (ie: bcn1_link1, ens0, etc). If it doesn't - # exist, see if the new name exists already. - $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 => { old_link1_file => $old_link1_file }}); - if (not -f $old_link1_file) - { - # Does the new file already exist? - if (-f $new_link1_file) - { - # Set the old file to the new one. - $old_link1_file = $new_link1_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); - } - } - } - 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 => { old_link2_file => $old_link2_file }}); - if (not -f $old_link2_file) - { - # Does the new file already exist? - if (-f $new_link2_file) - { - # Set the old file to the new one. - $old_link2_file = $new_link2_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link2_file => $old_link2_file }}); - } - } - } - $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, - }}); - - # Decide if we need to reboot. - if (($old_link1_file ne $new_link1_file) && (-e $new_link1_file)) - { - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - if (($old_link2_file ne $new_link2_file) && (-e $new_link2_file)) - { - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - - ### Write out the new configs, if needed - # Are we writing a bridge config? - if ($bridge) - { - # If the file already exists, see if it changed. - my $update = 1; - if (-e $bridge_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $bridge_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$bridge_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $bridge_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update => $update }}); - } - } - - if ($update) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - bridge_file => $bridge_file, - bridge_config => $bridge_config, - }}); - $anvil->Storage->write_file({ - file => $bridge_file, - body => $bridge_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } - } - - # Bond, Link 1 and Link 2 - my $update_bond = 1; - if (-f $bond_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $bond_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$bond_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $bond_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update_bond = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_bond => $update_bond }}); - } - } - if ($update_bond) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - bond_file => $bond_file, - bond_config => $bond_config, - }}); - $anvil->Storage->write_file({ - file => $bond_file, - body => $bond_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } - - # Link 1 - my $update_link1 = 1; - if (-f $new_link1_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link1_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$link1_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link1_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update_link1 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link1 => $update_link1 }}); - } - } - if ($update_link1) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link1_file => $new_link1_file, - link1_config => $link1_config, - }}); - $anvil->Storage->write_file({ - file => $new_link1_file, - body => $link1_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } - - # Link 2 - my $update_link2 = 1; - if (-f $new_link2_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link2_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$link2_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link2_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update_link2 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link2 => $update_link2 }}); - } - } - if ($update_link2) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link2_file => $new_link2_file, - link2_config => $link2_config, - }}); - $anvil->Storage->write_file({ - file => $new_link2_file, - body => $link2_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } - - # Backup the old config files, if needed. - if (-e $old_link1_file) - { - $anvil->Storage->backup({file => $old_link1_file}); - } - if (-e $old_link2_file) - { - $anvil->Storage->backup({file => $old_link2_file}); - } - - # 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); - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - 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); - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - - # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link1_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, 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; - } - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - elsif ($update_link1) - { - # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link1_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# $changes = 1; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - - # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link2_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); - - 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; - } - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - elsif ($update_link1) - { - # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link2_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# $changes = 1; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - } - elsif ((exists $anvil->data->{config}{$link1_key}) && ($anvil->Validate->mac({mac => $anvil->data->{config}{$link1_key}}))) - { - ### 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->{config}{$link1_key}; - $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"; - } - elsif ($network_type eq "mn") - { - $say_network = "Migration Network ".$network_count; - $say_interface = "mn".$network_count; - $interface_prefix = "MN"; - } - 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}; - if (not -f $old_link1_file) - { - # Does the new file already exist? - if (-f $new_link1_file) - { - # Set the old file to the new one. - $old_link1_file = $new_link1_file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_link1_file => $old_link1_file }}); - } - } - } - $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)."\""; - - # Link 1 - my $update_link1 = 1; - if (-f $new_link1_file) - { - # Read it in to see if there is a difference. - my $old_body = $anvil->Storage->read_file({file => $new_link1_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_body => $old_body }}); - - my $difference = diff \$old_body, \$link1_config, { STYLE => 'Unified' }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); - if ($difference) - { - # Backup the old file. - $anvil->Storage->backup({debug => 2, file => $new_link1_file}); - $changes = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - } - else - { - # No need to update - $update_link1 = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { update_link1 => $update_link1 }}); - } - } - if ($update_link1) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { - link1_file => $new_link1_file, - link1_config => $link1_config, - }}); - $anvil->Storage->write_file({ - file => $new_link1_file, - body => $link1_config, - user => "root", - group => "root", - mode => "0644", - overwrite => 1 - }); - } - - # Backup the existing link1 file, if it exists and is different. - if (-e $old_link1_file) - { - $anvil->Storage->backup({file => $old_link1_file}); - } - - # 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 }}); - -# my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection delete ".$old_link1_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# $anvil->System->call({debug => 2, shell_call => $shell_call}); -# -# rename_interface($anvil, $anvil->data->{network}{$local_host}{mac_address}{$link1_mac}{interface}, $new_link1_iface); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - elsif ($update_link1) - { - # 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 $shell_call = $anvil->data->{path}{exe}{nmcli}." connection down ".$old_link1_nm_name; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# $anvil->System->call({debug => 2, shell_call => $shell_call}); -# -# $changes = 1; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); - - $changes = 1; - $anvil->data->{sys}{reboot} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - changes => $changes, - "sys::reboot" => $anvil->data->{sys}{reboot}, - }}); - } - } - 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; - } - } -=cut - - 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 $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$old_link_name." down"; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# # Rename -# $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, list => { shell_call => $shell_call }}); -# ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { -# output => $output, -# return_code => $return_code, -# }}); -# -# # Bring up the new interface -# $shell_call = $anvil->data->{path}{exe}{ip}." link set ".$new_link_name." up"; -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); -# ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $shell_call}); -# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, 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 { From b0cede49e3402f8158efeb46d32f24be07003780 Mon Sep 17 00:00:00 2001 From: digimer Date: Fri, 19 Jan 2024 00:12:30 -0500 Subject: [PATCH 28/43] Removed calls to check apache config. Signed-off-by: digimer --- Anvil/Tools/Striker.pm | 2 +- tools/anvil-configure-host | 7 ------- tools/anvil-daemon | 8 -------- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/Anvil/Tools/Striker.pm b/Anvil/Tools/Striker.pm index 6451a810..9195add1 100644 --- a/Anvil/Tools/Striker.pm +++ b/Anvil/Tools/Striker.pm @@ -14,7 +14,7 @@ our $VERSION = "3.0.0"; my $THIS_FILE = "Striker.pm"; ### Methods; -# check_httpd_conf +# check_httpd_conf - Deprecated # generate_manifest # get_fence_data # get_local_repo diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index faec462b..f0eb955d 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -354,13 +354,6 @@ sub reconfigure_network } } - ### NOTE: No longer needed, we don't use apache anymore. - # If we're a striker, check apache's config. - if ($type eq "striker") - { - #$anvil->Striker->check_httpd_conf({debug => 2}); - } - # Now configure the network. my $dns = $anvil->data->{config}{dns} ? [split/,/, $anvil->data->{config}{dns}] : []; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { dns => $dns }}); diff --git a/tools/anvil-daemon b/tools/anvil-daemon index c8d6796a..71fb69d9 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -1365,14 +1365,6 @@ AND # Check the firewall needs to be updated. check_firewall($anvil); - # If we're a striker, check striker-ui-api - my $host_type = $anvil->Get->host_type; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); - if ($host_type eq "striker") - { - $anvil->Striker->check_httpd_conf({debug => 3}); - } - return(0); } From dd0175e05c8c662b91b0211d080a46e026faba82 Mon Sep 17 00:00:00 2001 From: digimer Date: Fri, 19 Jan 2024 02:08:16 -0500 Subject: [PATCH 29/43] Now check for/backup/remove ifcfg-X files on EL8 hosts. * Added caching to System->check_network_type() * Changed anvil-configure-host job progress steps to 1. Signed-off-by: digimer --- Anvil/Tools/System.pm | 15 +- share/words.xml | 1 + tools/anvil-configure-host | 326 ++++++++++++++++++++++--------------- 3 files changed, 212 insertions(+), 130 deletions(-) diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index 08baf5ff..1d837517 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -1286,6 +1286,8 @@ This method checks to see if this host is using network manager to configure the If any 'ifcfg-X' files are found, C<< ifcfg >> is returned. Otherwise, C<< nm >> is returned. +The results are cached in C<< sys::network_type >>. + This method takes no parameters. =cut @@ -1297,6 +1299,13 @@ sub check_network_type my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->check_storage()" }}); + if ((exists $anvil->data->{sys}{network_type}) && ($anvil->data->{sys}{network_type})) + { + # Cached. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::network_type" => $anvil->data->{sys}{network_type} }}); + return($anvil->data->{sys}{network_type}); + } + # Open the 'ifcfg' directory, if it exists, and see if there are any 'ifcfg-X' files. my $type = "nm"; my $directory = $anvil->data->{path}{directories}{ifcfg}; @@ -1320,8 +1329,10 @@ sub check_network_type closedir(DIRECTORY); } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }}); - return($type); + # Cache the results + $anvil->data->{sys}{network_type} = $type; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::network_type" => $anvil->data->{sys}{network_type} }}); + return($anvil->data->{sys}{network_type}); } diff --git a/share/words.xml b/share/words.xml index 6aba4a1a..bc95413f 100644 --- a/share/words.xml +++ b/share/words.xml @@ -3346,6 +3346,7 @@ proceeding. - The IP address needs to be assigned. [ Note ] - Reconfiguring the network will break connections. Disconnecting from the database before starting. It might take a bit before this system reconnects and progress can be seen. [ Note ] - The network has reconnected to the database, configuring will complete shortly. + [ Note ] - The old 'ifcfg' style config file: [#!variable!file!#] will be backed up and then removed! Normal Password diff --git a/tools/anvil-configure-host b/tools/anvil-configure-host index f0eb955d..10e4df6f 100755 --- a/tools/anvil-configure-host +++ b/tools/anvil-configure-host @@ -122,7 +122,7 @@ sub do_reboot { # Give them the countdown. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "log_0626", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -137,7 +137,7 @@ sub do_reboot # Last, log that we're going down now. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0389", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -484,99 +484,87 @@ ORDER BY my $network_type = $anvil->System->check_network_type(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); - if ($network_type eq "ifcfg") + + # Configure the network using Network Manager + reconfigure_interfaces($anvil); + + ### NOTE: If we're not a striker, the update the job to say we're disconnecting to + ### reconfigure the network. + my $host_type = $anvil->Get->host_type(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); + if ($host_type ne "striker") { - foreach my $network_type ("bcn", "sn", "mn", "ifn") - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); - - # This is the old type of network config - #configure_ifcfg_network($anvil, $network_type); - } + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 50}), + message => "message_0415", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + }); + $anvil->Database->disconnect({debug => 2}); } - else + + # These can brake the connection. + reconfigure_bonds($anvil); + reconfigure_bridges($anvil); + reconfigure_ip_addresses($anvil); + + # Reconnect! + if ($host_type ne "striker") { - # Configure the network using Network Manager - reconfigure_interfaces($anvil); - - ### NOTE: If we're not a striker, the update the job to say we're disconnecting to - ### reconfigure the network. - my $host_type = $anvil->Get->host_type(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }}); - if ($host_type ne "striker") - { - $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 50}), - message => "message_0415", - log_level => 1, - 'print' => 1, - job_uuid => $anvil->data->{job}{uuid}, - file => $THIS_FILE, - line => __LINE__, - }); - $anvil->Database->disconnect({debug => 2}); - } - - # These can brake the connection. - reconfigure_bonds($anvil); - reconfigure_bridges($anvil); - reconfigure_ip_addresses($anvil); - - # Reconnect! - if ($host_type ne "striker") + my $time_now = time; + my $wait_until = $time_now + 120; + my $waiting = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + time_now => $time_now, + wait_until => $wait_until, + }}); + while ($waiting) { - my $time_now = time; - my $wait_until = $time_now + 120; - my $waiting = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - time_now => $time_now, - wait_until => $wait_until, - }}); - while ($waiting) + $anvil->refresh(); + $anvil->Database->connect({debug => 2}); + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::database::connections" => $anvil->data->{sys}{database}{connections} }}); + if ($anvil->data->{sys}{database}{connections}) { - $anvil->refresh(); - $anvil->Database->connect({debug => 2}); - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::database::connections" => $anvil->data->{sys}{database}{connections} }}); - if ($anvil->data->{sys}{database}{connections}) + # We're back! + $waiting = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + } + else + { + # Sleep for a bit. + my $now_time = time; + my $time_left = $wait_until - $now_time; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + now_time => $now_time, + time_left => $time_left, + }}); + if ($time_left > 0) { - # We're back! - $waiting = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0829", variables => { time_left => $time_left }}); + sleep 5; } else { - # Sleep for a bit. - my $now_time = time; - my $time_left = $wait_until - $now_time; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - now_time => $now_time, - time_left => $time_left, - }}); - if ($time_left > 0) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0829", variables => { time_left => $time_left }}); - sleep 5; - } - else - { - # Give up and reboot. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0169"}); - do_reboot($anvil); - } + # Give up and reboot. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0169"}); + do_reboot($anvil); } } - - $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({set => 75}), - message => "message_0416", - log_level => 1, - 'print' => 1, - job_uuid => $anvil->data->{job}{uuid}, - file => $THIS_FILE, - line => __LINE__, - }); } + + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({set => 75}), + message => "message_0416", + log_level => 1, + 'print' => 1, + job_uuid => $anvil->data->{job}{uuid}, + file => $THIS_FILE, + line => __LINE__, + }); } # If any virtio bridges exist, remove it/them. @@ -658,7 +646,7 @@ ORDER BY } $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), job_uuid => $anvil->data->{job}{uuid}, }); @@ -708,7 +696,7 @@ sub reconfigure_bridges # Checking if the bridge exists and that it is on the requested device $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0400", log_level => 1, 'print' => 1, @@ -725,7 +713,7 @@ sub reconfigure_bridges { # The bridge exists. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0401", log_level => 1, 'print' => 1, @@ -737,6 +725,31 @@ sub reconfigure_bridges } else { + # If there are ifcfg files for this bridge, move it. + my $network_type = $anvil->System->check_network_type({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + if ($network_type eq "ifcfg") + { + my $ifcfg_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$bridge_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ifcfg_file => $ifcfg_file }}); + if (-f $ifcfg_file) + { + # It exists, move it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0417", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { file => $ifcfg_file }, + }); + $anvil->Storage->backup({debug => 2, file => $ifcfg_file}); + unlink $ifcfg_file; + } + } + # Create the bridge. my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bridge con-name ".$bridge_name." ifname ".$bridge_name; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); @@ -772,7 +785,7 @@ sub reconfigure_bridges { # Disabling DHCP on the new bridge $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0408", log_level => 1, 'print' => 1, @@ -798,7 +811,7 @@ sub reconfigure_bridges # Rescan. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", log_level => 1, 'print' => 1, @@ -812,7 +825,7 @@ sub reconfigure_bridges # Checking that the device is connected to this bridge $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0404", log_level => 1, 'print' => 1, @@ -838,7 +851,7 @@ sub reconfigure_bridges { # The device is connected to the bridge already. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0405", log_level => 1, 'print' => 1, @@ -853,7 +866,7 @@ sub reconfigure_bridges { # The device is on another bridge, moving it. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0406", log_level => 1, 'print' => 1, @@ -868,7 +881,7 @@ sub reconfigure_bridges { # The device is not on this bridge, connecting it $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0407", log_level => 1, 'print' => 1, @@ -881,7 +894,7 @@ sub reconfigure_bridges # Disabling DHCP on the device before connecting it. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0408", log_level => 1, 'print' => 1, @@ -898,7 +911,7 @@ sub reconfigure_bridges # Connect it now. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0409", log_level => 1, 'print' => 1, @@ -937,7 +950,7 @@ sub reconfigure_bridges # Reset the device. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0403", log_level => 1, 'print' => 1, @@ -953,7 +966,7 @@ sub reconfigure_bridges # Rescan. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", log_level => 1, 'print' => 1, @@ -1042,7 +1055,7 @@ sub reconfigure_bonds # Check if the bond exists or not. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0390", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -1055,7 +1068,7 @@ sub reconfigure_bonds { # It does. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0391", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -1069,7 +1082,7 @@ sub reconfigure_bonds { # It doesn't, create it. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0392", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -1087,6 +1100,31 @@ sub reconfigure_bonds }, }); + # If there are ifcfg files for this bond, move it. + my $network_type = $anvil->System->check_network_type({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + if ($network_type eq "ifcfg") + { + my $ifcfg_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$bond_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { ifcfg_file => $ifcfg_file }}); + if (-f $ifcfg_file) + { + # It exists, move it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0417", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { file => $ifcfg_file }, + }); + $anvil->Storage->backup({debug => 2, file => $ifcfg_file}); + unlink $ifcfg_file; + } + } + my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection add type bond con-name ".$bond_name." ifname ".$bond_name." bond.options \"mode=active-backup,miimon=100,downdelay=0,updelay=120000,primary=".$link1_name."\""; $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}); @@ -1121,7 +1159,7 @@ sub reconfigure_bonds { # Disabling DHCP on the new bond device $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0408", log_level => 1, 'print' => 1, @@ -1147,7 +1185,7 @@ sub reconfigure_bonds # Done! Rescanning the network config $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -1187,7 +1225,7 @@ sub reconfigure_bonds { # Already a member of the bond. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0395", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -1205,7 +1243,7 @@ sub reconfigure_bonds { # The interface is a member of another bond, switching it to this bond.\n"; $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0396", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -1224,7 +1262,7 @@ sub reconfigure_bonds { # The interface needs to be connected to the bond. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0397", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -1240,7 +1278,7 @@ sub reconfigure_bonds # Disabling DHCP on the interface $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0408", log_level => 1, 'print' => 1, @@ -1257,7 +1295,7 @@ sub reconfigure_bonds # Connecting the interface to the bond $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0399", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, @@ -1299,7 +1337,7 @@ sub reconfigure_bonds # Reset the interface. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0403", log_level => 1, 'print' => 1, @@ -1315,7 +1353,7 @@ sub reconfigure_bonds # Rescan. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", log_level => 1, 'print' => 1, @@ -1476,7 +1514,7 @@ sub reconfigure_ip_addresses # Check to see if the IP address is assigned yet. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0393", log_level => 1, 'print' => 1, @@ -1525,7 +1563,7 @@ sub reconfigure_ip_addresses # The IP exists, checking if it needs to be updated. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0398", log_level => 1, 'print' => 1, @@ -1538,7 +1576,7 @@ sub reconfigure_ip_addresses { # The IP address is on another device, we'll move it $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0402", log_level => 1, 'print' => 1, @@ -1554,7 +1592,7 @@ sub reconfigure_ip_addresses { # The current subnet mask is different, will update. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0410", log_level => 1, 'print' => 1, @@ -1568,7 +1606,7 @@ sub reconfigure_ip_addresses { # The current gateway is different, will update. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0411", log_level => 1, 'print' => 1, @@ -1582,7 +1620,7 @@ sub reconfigure_ip_addresses { # The current DNS is different, will update. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0412", log_level => 1, 'print' => 1, @@ -1596,7 +1634,7 @@ sub reconfigure_ip_addresses { # No update is needed. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0413", log_level => 1, 'print' => 1, @@ -1612,7 +1650,7 @@ sub reconfigure_ip_addresses { # The IP address needs to be assigned. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0414", log_level => 1, 'print' => 1, @@ -1628,7 +1666,7 @@ sub reconfigure_ip_addresses # Clear the IP off the old device my $old_uuid = $anvil->data->{nmcli}{device}{$clear_ip_from}{uuid}; $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0408", log_level => 1, 'print' => 1, @@ -1644,7 +1682,7 @@ sub reconfigure_ip_addresses ($output, $return_code) = $anvil->Network->modify_connection({debug => 2, uuid => $old_uuid, variable => "ipv6.method", value => "disabled"}); $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0403", log_level => 1, 'print' => 1, @@ -1682,7 +1720,7 @@ sub reconfigure_ip_addresses # Restart the interface $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0403", log_level => 1, 'print' => 1, @@ -1698,7 +1736,7 @@ sub reconfigure_ip_addresses # Rescan. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", log_level => 1, 'print' => 1, @@ -1714,7 +1752,6 @@ sub reconfigure_ip_addresses return(0); } - sub reconfigure_interfaces { my ($anvil) = @_; @@ -1746,7 +1783,7 @@ sub reconfigure_interfaces # Rescan. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", log_level => 1, 'print' => 1, @@ -1965,7 +2002,7 @@ sub rename_interface # Tell the user what we're about to rename $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0383", log_level => 1, 'print' => 1, @@ -1981,6 +2018,39 @@ sub rename_interface }, }); + # If there are ifcfg files for this device, move them. + my $network_type = $anvil->System->check_network_type({debug => 2}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); + if ($network_type eq "ifcfg") + { + my $old_ifcfg_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$old_device; + my $new_ifcfg_file = $anvil->data->{path}{directories}{ifcfg}."/ifcfg-".$wanted_link_name; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + old_ifcfg_file => $old_ifcfg_file, + new_ifcfg_file => $new_ifcfg_file, + }}); + foreach my $file ($old_ifcfg_file, $new_ifcfg_file) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }}); + if (-f $file) + { + # It exists, move it. + $anvil->Job->update_progress({ + progress => $anvil->Job->bump_progress({steps => 1}), + message => "message_0417", + log_level => 1, + 'print' => 1, + file => $THIS_FILE, + line => __LINE__, + job_uuid => $anvil->data->{job}{uuid}, + variables => { file => $file }, + }); + $anvil->Storage->backup({debug => 2, file => $file}); + unlink $file; + } + } + } + # Read persistent-net and see if it needs to be updated. my $new_persistent_net = ""; my $old_persistent_net = ""; @@ -2009,7 +2079,7 @@ sub rename_interface { # Updating the udev file $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0384", log_level => 1, 'print' => 1, @@ -2053,7 +2123,7 @@ sub rename_interface { # Removing the old 'connection.interface-name' $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0385", log_level => 1, 'print' => 1, @@ -2100,7 +2170,7 @@ sub rename_interface my $match_interface_name = $anvil->data->{nmcli}{uuid}{$nm_uuid}{'match.interface-name'} ? $anvil->data->{nmcli}{uuid}{$nm_uuid}{'match.interface-name'} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { match_interface_name => $match_interface_name }}); $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0386", log_level => 1, 'print' => 1, @@ -2173,7 +2243,7 @@ sub rename_interface # Set the connection.id to the old name. $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0387", log_level => 1, 'print' => 1, @@ -2201,7 +2271,7 @@ sub rename_interface # Re-read the updated data $anvil->Job->update_progress({ - progress => $anvil->Job->bump_progress({steps => 2}), + progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", log_level => 1, 'print' => 1, From 023bcf46a4ad9fd48a67963bd428dbd2b29dc079 Mon Sep 17 00:00:00 2001 From: digimer Date: Fri, 19 Jan 2024 23:08:05 -0500 Subject: [PATCH 30/43] Fixed a bug with hung cluster startup in some cases Signed-off-by: digimer --- tools/anvil-join-anvil | 54 +++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/tools/anvil-join-anvil b/tools/anvil-join-anvil index e4952005..81eb8be4 100755 --- a/tools/anvil-join-anvil +++ b/tools/anvil-join-anvil @@ -495,20 +495,52 @@ sub configure_pacemaker } if (time > $start_again) { - # Call cluster start again. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0272"}); - $start_again = time + 60; - my $shell_call = $anvil->data->{path}{exe}{pcs}." cluster start --all"; + ### NOTE: We can't just call 'start --all' again anymore. Now we need to + ### stop -> start. Before we do this, make sure there are no servers + ### running. + $start_again = time + 60; + my $restart = 1; + my $server_count = keys %{$anvil->data->{cib}{parsed}{data}{server}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - start_again => $start_again, - shell_call => $shell_call, + start_again => $start_again, + server_count => $server_count, }}); + foreach my $server (sort {$a cmp $b} keys %{$anvil->data->{cib}{parsed}{data}{server}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "cib::parsed::data::server::${server}::active" => $anvil->data->{cib}{parsed}{data}{server}{$server}{active}, + }}); + if ($anvil->data->{cib}{parsed}{data}{server}{$server}{active}) + { + $restart = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { restart => $restart }}); + } + } - my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { restart => $restart }}); + if ($restart) + { + # Call cluster start again. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0272"}); + my $shell_call = $anvil->data->{path}{exe}{pcs}." cluster stop --all"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + start_again => $start_again, + shell_call => $shell_call, + }}); + + my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + + $shell_call = $anvil->data->{path}{exe}{pcs}." cluster start --all"; + ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + output => $output, + return_code => $return_code, + }}); + } } sleep 5 if not $both_online; } From 476b28560710e3a1fad7a25c2d31d9f98d8a467e Mon Sep 17 00:00:00 2001 From: digimer Date: Fri, 19 Jan 2024 23:48:56 -0500 Subject: [PATCH 31/43] Added a wait_for_access() function to anvil-join-anvil Signed-off-by: digimer --- tools/anvil-join-anvil | 142 +++++++++++++++++++++++++++++++++++++++++ tools/anvil-safe-start | 2 +- 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/tools/anvil-join-anvil b/tools/anvil-join-anvil index 81eb8be4..606565b9 100755 --- a/tools/anvil-join-anvil +++ b/tools/anvil-join-anvil @@ -22,6 +22,7 @@ use Anvil::Tools; use Data::Dumper; use String::ShellQuote; use Text::Diff; +use NetAddr::IP; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; @@ -63,6 +64,9 @@ update_passwords($anvil); # Check if we need to change any IPs or our hostname. check_local_network($anvil); +# Wait until we can ping our peer on all networks. +wait_for_access($anvil); + # (wait for out peer and) Configure pacemaker configure_pacemaker($anvil); @@ -98,6 +102,144 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# +sub wait_for_access +{ + my ($anvil) = @_; + + # NOTE: This logic is a copy of anvil-safe-start. + $anvil->Database->get_hosts(); + $anvil->Database->get_anvils(); + my $host_uuid = $anvil->Get->host_uuid(); + my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name}; + my $peer_host_uuid = $anvil->data->{sys}{peer_host_uuid}; + my $peer_short_host_name = $anvil->data->{hosts}{host_uuid}{$peer_host_uuid}{short_host_name}; + my $peer_password = $anvil->data->{sys}{peer_password}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + host_uuid => $host_uuid, + short_host_name => $short_host_name, + peer_host_uuid => $peer_host_uuid, + peer_short_host_name => $peer_short_host_name, + peer_password => $anvil->Log->is_secure($peer_password), + }}); + + my $waiting = 1; + while ($waiting) + { + # This will get set back to '1' if + $waiting = 0; + + # Load IPs (again, to catch changes that might be delaying startup) + $anvil->Network->load_ips({ + clear => 1, + host => $short_host_name, + host_uuid => $host_uuid, + + }); + $anvil->Network->load_ips({ + clear => 1, + host => $peer_short_host_name, + host_uuid => $peer_host_uuid, + + }); + + # Loop through our interfaces and then loop our peers. Test access over them and set + # 'waiting' back to '1' if the connection fails. + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$short_host_name}{interface}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + waiting => $waiting, + }}); + + # Only care about our networks. + next if $waiting; + if (not $anvil->Network->is_our_interface({interface => $interface})) + { + # Not an interface we care about + next; + } + + my $this_network = ($interface =~ /^(.*?)_/)[0]; + my $ip_address = $anvil->data->{network}{$short_host_name}{interface}{$interface}{ip}; + my $subnet_mask = $anvil->data->{network}{$short_host_name}{interface}{$interface}{subnet_mask}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:this_network' => $this_network, + 's2:ip_address' => $ip_address, + 's3:subnet_mask' => $subnet_mask, + }}); + + ### NOTE: I know I could match interface names, but that's not certain enough. It's + ### possible (if unlikely) that the network name+numbre differs on our peer. So + ### this is safer. + # Loop through my peer's interfaces and see if we're sharing this one. + my $local_network = NetAddr::IP->new($ip_address."/".$subnet_mask); + my $peer_match_found = 0; + foreach my $peer_interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$peer_short_host_name}{interface}}) + { + last if $peer_match_found; + my $peer_ip_address = $anvil->data->{network}{$peer_short_host_name}{interface}{$peer_interface}{ip}; + my $peer_subnet_mask = $anvil->data->{network}{$peer_short_host_name}{interface}{$peer_interface}{subnet_mask}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + peer_interface => $peer_interface, + peer_ip_address => $peer_ip_address, + peer_subnet_mask => $peer_subnet_mask, + }}); + + # This the matching network? + next if $subnet_mask ne $peer_subnet_mask; + + my $peer_network = NetAddr::IP->new($peer_ip_address."/".$peer_subnet_mask); + if ($peer_network->within($local_network)) + { + # Match, test access. + $peer_match_found = 1; + my $access = $anvil->Remote->test_access({ + target => $peer_ip_address, + password => $peer_password, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }}); + if ($access) + { + # This network is good. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0604", variables => { + peer => $peer_short_host_name, + network => $this_network, + peer_ip => $peer_ip_address, + }}); + + $anvil->data->{sys}{peer_target_ip} = $peer_ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "sys::peer_target_ip" => $anvil->data->{sys}{peer_target_ip}, + }}); + } + else + { + # No access, wait and try it again. + $waiting = 1; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "log_0605", variables => { + peer => $peer_short_host_name, + network => $this_network, + peer_ip => $peer_ip_address, + }}); + } + } + + } + } + + if ($waiting) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "log_0606", variables => { peer => $peer_short_host_name }}); + sleep 5; + } + } + + # All networks are up. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, priority => "alert", key => "log_0607", variables => { peer => $peer_short_host_name }}); + + return(0); +} + # Configure DRBD sub configure_drbd { diff --git a/tools/anvil-safe-start b/tools/anvil-safe-start index c37cd869..34b32f4b 100755 --- a/tools/anvil-safe-start +++ b/tools/anvil-safe-start @@ -94,7 +94,7 @@ if (not $anvil->data->{sys}{database}{connections}) # Check to see if we should run. Also checks/sets enable/disable requests. prerun_checks($anvil); -# Wait until I can ping the peer on all three networks. This will not return until access is available on all +# Wait until I can ping the peer on all networks. This will not return until access is available on all # networks. There is no timeout. wait_for_access($anvil); From de4bb0d0010c89a6be333904d97cc6d5c8a3b1d4 Mon Sep 17 00:00:00 2001 From: digimer Date: Sat, 20 Jan 2024 23:36:53 -0500 Subject: [PATCH 32/43] Bumped logging for debugging. Signed-off-by: digimer --- tools/anvil-safe-start | 5 +++++ tools/scancore | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/anvil-safe-start b/tools/anvil-safe-start index 34b32f4b..86072904 100755 --- a/tools/anvil-safe-start +++ b/tools/anvil-safe-start @@ -44,6 +44,11 @@ $anvil->Get->switches({list => [], man => $THIS_FILE}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }}); +### TODO: Remove before PR! +# Force up the logging. +$anvil->Log->level({set => 2}); +$anvil->Log->secure({set => 1}); + # Make sure we're running as 'root' # $< == real UID, $> == effective UID if (($< != 0) && ($> != 0)) diff --git a/tools/scancore b/tools/scancore index e4e842d8..1743dce7 100755 --- a/tools/scancore +++ b/tools/scancore @@ -143,7 +143,7 @@ while(1) if ($anvil->data->{sys}{database}{connections}) { # Run the normal tasks - $anvil->ScanCore->call_scan_agents(); + $anvil->ScanCore->call_scan_agents({debug => 2}); # Do post-scan analysis. $anvil->ScanCore->post_scan_analysis({debug => 2}); From 760d9f53d8fbc704541510efd30b3774103019a3 Mon Sep 17 00:00:00 2001 From: digimer Date: Sun, 21 Jan 2024 17:28:15 -0500 Subject: [PATCH 33/43] Bumped logging. Signed-off-by: digimer --- tools/anvil-safe-start | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/anvil-safe-start b/tools/anvil-safe-start index 86072904..c890e7fe 100755 --- a/tools/anvil-safe-start +++ b/tools/anvil-safe-start @@ -348,7 +348,7 @@ sub start_pacemaker while ($waiting) { $waiting = 0; - my ($problem) = $anvil->Cluster->parse_cib({debug => 3}); + my ($problem) = $anvil->Cluster->parse_cib({debug => 2}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); if ($problem) { From d8ceb7fbf4b01b4a32b7bd5292397f75d03a7130 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 24 Jan 2024 00:23:28 -0500 Subject: [PATCH 34/43] Updated to add all subnode nets to /etc/hosts before forming cluster Signed-off-by: digimer --- share/words.xml | 6 + tools/anvil-join-anvil | 277 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 277 insertions(+), 6 deletions(-) diff --git a/share/words.xml b/share/words.xml index bc95413f..eee7754e 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2709,6 +2709,12 @@ The file: [#!variable!file!#] needs to be updated. The difference is: The physical volume: [#!variable!pv_name!#] has been resized! The user answered: [#!variable!answer!#] Failed to connect to any database, waiting before trying to connect again. We will reboot if we do not connect in: [#!variable!time_left!#] second. + The host: [#!variable!host_name!#] was found in the '/etc/hosts' file with the expected IP: [#!variable!ip_address!#]! + The host: [#!variable!host_name!#] was found in the '/etc/hosts' file, but the expected IP: [#!variable!ip_address!#] doesn't match the found IP: [#!variable!found_ip!#]! Ignoring this entry. + The host: [#!variable!host_name!#] was found not found in the '/etc/hosts' file! We'll wait a few seconds and check again. + All host names were found in '/etc/hosts', ready to proceed! + One or more hosts are not yet in the '/etc/hosts' file with expected IPs. We'll wait a short bit and check again. + There are entries we need to add to the '/etc/hosts' file before we can form the cluster, updating it now. The host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-join-anvil b/tools/anvil-join-anvil index 606565b9..81acd4e1 100755 --- a/tools/anvil-join-anvil +++ b/tools/anvil-join-anvil @@ -55,6 +55,9 @@ if (not $anvil->data->{sys}{database}{connections}) # Get the job details load_job($anvil); +# Make sure the hosts file has entries for all nets for both subnodes +wait_for_etc_hosts($anvil); + # Hold until both subnodes are marked as configured and not in maintenance mode. wait_for_subnodes($anvil); @@ -67,6 +70,7 @@ check_local_network($anvil); # Wait until we can ping our peer on all networks. wait_for_access($anvil); +### TODO: Change corosync.conf to use IPs, including MN if it exists. # (wait for out peer and) Configure pacemaker configure_pacemaker($anvil); @@ -102,6 +106,271 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# +# Make sure the hosts file has entries for all nets for both subnodes +sub wait_for_etc_hosts +{ + my ($anvil) = @_; + + my $anvil_uuid = $anvil->data->{sys}{anvil_uuid}; + my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; + my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; + my $manifest_uuid = $anvil->data->{sys}{manifest_uuid}; + my $i_am = $anvil->data->{sys}{machine}; + my $peer_is = $i_am eq "node1" ? "node2" : "node1"; + my $peer_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{"anvil_".$peer_is."_host_uuid"}; + my $peer_short_host_name = $anvil->data->{hosts}{host_uuid}{$peer_host_uuid}{short_host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:anvil_uuid' => $anvil_uuid, + 's2:manifest_uuid' => $manifest_uuid, + 's3:node1_host_uuid' => $node1_host_uuid, + 's4:node2_host_uuid' => $node2_host_uuid, + 's5:i_am' => $i_am, + 's6:peer_is' => $peer_is, + 's7:peer_host_uuid' => $peer_host_uuid, + 's8:peer_short_host_name' => $peer_short_host_name, + }}); + + my $problem = $anvil->Striker->load_manifest({debug => 2, manifest_uuid => $manifest_uuid}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + manifest_uuid => $anvil->data->{sys}{manifest_uuid}, + problem => $problem, + }}); + if ($problem) + { + # Something went wrong, fatally. Abort the job. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "job_0076", variables => { uuid => $anvil->data->{sys}{manifest_uuid} }}); + update_progress($anvil, 100, "job_0076,!!uuid!".$anvil->data->{sys}{manifest_uuid}."!!"); + $anvil->nice_exit({exit_code => 2}); + } + + # Create the list of host names we need to see in /etc/hosts and the hostnames to use in corosync. + foreach my $machine (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}}) + { + my $this_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{"anvil_".$machine."_host_uuid"}; + my $this_short_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine => $machine }}); + foreach my $network_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{network}}) + { + my $host_name = $this_short_host_name.".".$network_name; + my $ip_address = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{network}{$network_name}{ip}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:network_name' => $network_name, + 's2:host_name' => $host_name, + 's3:ip_address' => $ip_address, + }}); + + $anvil->data->{networks}{$host_name}{ip_address} = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:networks::${host_name}::ip_address" => $anvil->data->{networks}{$host_name}{ip_address}, + }}); + } + } + + my $waiting = 1; + update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0477"); + while($waiting) + { + # Update the /etc/hosts file. Note that this doesn't add hosts that are not yet trusted, so + # anything not found will be inserted here. + $anvil->System->update_hosts({debug => 2}); + + # Now lets see if all expected hosts names are in the /etc/hosts file yet. + my $ready = 1; + my $hosts_file = $anvil->Storage->read_file({ + file => $anvil->data->{path}{configs}{hosts}, + force_read => 1, + cache => 0, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { hosts_file => $hosts_file }}); + + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{networks}}) + { + my $found = 0; + my $ip_address = $anvil->data->{networks}{$host_name}{ip_address}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + 's1:host_name' => $host_name, + 's2:ip_address' => $ip_address, + }}); + + foreach my $line (split/\n/, $hosts_file) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); + + $line =~ s/#.*$//; + if ($line =~ /^(\d.*?)\s+(.*)$/) + { + my $this_ip = $1; + my $hosts = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + this_ip => $this_ip, + hosts => $hosts, + }}); + + if ($anvil->Validate->ip({ip => $this_ip})) + { + foreach my $this_host (split/\s+/, $hosts) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_host => $this_host }}); + + if ($host_name eq $this_host) + { + my $variables = { + host_name => $host_name, + ip_address => $ip_address, + found_ip => $this_ip, + }; + if ($ip_address eq $this_ip) + { + # Found it + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0830", variables => $variables }); + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + } + else + { + # Found the host, but the IP doesn't match. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0831", variables => $variables }); + } + } + last if $found; + } + } + } + last if $found; + } + + if (not $found) + { + $ready = 0; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0832", variables => { host_name => $host_name }}); + + # Add the IP to be added to /etc/hosts. + $anvil->data->{to_add}{$host_name} = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "to_add::${ip_address}" => $anvil->data->{to_add}{$host_name} }}); + } + } + + if ($ready) + { + # Ready! + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0833"}); + + $waiting = 0; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); + } + else + { + # Not ready, wait a bit. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0834"}); + + # Add the values to /etc/hosts. + my $new_hosts_body = ""; + foreach my $line (split/\n/, $hosts_file) + { + # See if this line needs to be modified. + if ($line =~ /^(\d.*?)\s+(.*)$/) + { + my $this_ip = $1; + my $hosts = $2; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + this_ip => $this_ip, + hosts => $hosts, + }}); + if ($anvil->Validate->ip({ip => $this_ip})) + { + my $changes = 0; + my $new_hosts = ""; + my $comment = ($hosts =~ /(#.*)$/)[0]; + $comment = "" if not defined $comment; + $hosts =~ s/#.*?//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + comment => $comment, + hosts => $hosts, + }}); + foreach my $host_name (split/\s+/, $hosts) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }}); + + if ((exists $anvil->data->{to_add}{$host_name}) && + ($anvil->data->{to_add}{$host_name}) && + ($this_ip ne $anvil->data->{to_add}{$host_name})) + { + # Remove this host. + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + + delete $anvil->data->{to_add}{$host_name}; + next; + } + $new_hosts .= $host_name." "; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_hosts => $new_hosts }}); + } + + # Do we have any names to add to this IP? + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{to_add}}) + { + if ($this_ip eq $anvil->data->{to_add}{$host_name}) + { + # Add it. + $new_hosts .= $host_name." "; + + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + + delete $anvil->data->{to_add}{$host_name}; + } + } + + if ($changes) + { + $new_hosts_body .= $this_ip."\t".$new_hosts.$comment."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { changes => $changes }}); + next; + } + } + } + + # If we're alive here, just add the old line. + $new_hosts_body .= $line."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_hosts_body => $new_hosts_body }}); + } + + # Add any hosts still not processed. + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{to_add}}) + { + $new_hosts_body .= $anvil->data->{to_add}{$host_name}."\t".$host_name."\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_hosts_body => $new_hosts_body }}); + + delete $anvil->data->{to_add}{$host_name}; + } + + # If there's a difference, write the new hosts file. + my $difference = diff \$new_hosts_body, \$hosts_file, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }}); + + if ($difference) + { + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0112"}); + update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0112"); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0835"}); + my $failed = $anvil->Storage->write_file({ + debug => 2, + overwrite => 1, + file => $anvil->data->{path}{configs}{hosts}, + body => $new_hosts_body, + user => "root", + group => "root", + mode => "0644", + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { failed => $failed }}); + } + sleep 1; + } + } + + return(0); +} + sub wait_for_access { my ($anvil) = @_; @@ -1329,7 +1598,7 @@ sub configure_pacemaker } } - # Update (if needed) corosync.conf to use the BCN1 and SN1 as knet networks. + # Update (if needed) corosync.conf to use the BCN1, MN1 and SN1 as knet networks. if ($machine eq "node1") { update_progress($anvil, ($anvil->data->{job}{progress} += 1), "job_0344"); @@ -1363,6 +1632,7 @@ sub check_corosync my $new_password = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}; while ($waiting) { + ### TODO: Add MN where appropriate my $problem = $anvil->Cluster->parse_cib({debug => 3}); my $peer_ready = $anvil->data->{cib}{parsed}{peer}{ready}; my $peer_name = $anvil->data->{cib}{parsed}{peer}{name}; @@ -2432,11 +2702,6 @@ sub check_local_network } } - # Update the hosts file. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0112"}); - update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0112"); - $anvil->System->update_hosts({debug => 3}); - # Configure SSH by adding ours and our peer's SSH keys to ~/.ssh/known_hosts $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "job_0113"}); update_progress($anvil, ($anvil->data->{job}{progress} += 2), "job_0113"); From 59a33306cc418deb3839a2dc3c50cb6c826fea42 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 24 Jan 2024 11:34:09 -0500 Subject: [PATCH 35/43] Removed ifcfg support from scan-network. Signed-off-by: digimer --- scancore-agents/scan-network/scan-network | 573 ---------------------- 1 file changed, 573 deletions(-) diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index 87cab0f3..663c59de 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -587,16 +587,6 @@ sub collect_data } } - ### TODO: Remove this check when ifcfg-X support is dropped. - my $network_type = $anvil->System->check_network_type(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); -# if ($network_type eq "ifcfg") -# { -# # Using the old 'ifcfg-X' style. -# collect_data_ifcfg($anvil); -# return(0); -# } - # Collect data from nmcli $anvil->Network->collect_data({debug => 2}); @@ -1139,569 +1129,6 @@ sub collect_data return(0); } -### TODO: Remove this when ifcfg support is dropped. -sub collect_data_ifcfg -{ -=cut - my ($anvil) = @_; - - # Read the data from the ifcfg files, if available. We'll use this to check for bond interfaces that - # didn't start. - $anvil->Network->check_network(); - my $uptime = $anvil->Get->uptime(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uptime => $uptime }}); - if ($uptime < 600) - { - $anvil->Network->read_nmcli({debug => 2}) - } - - # The 'local_host' is needed to pull data recorded by Network->get_ips(); - my $local_host = $anvil->Get->short_host_name(); - my $directory = "/sys/class/net"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - local_host => $local_host, - directory => $directory, - }}); - - # Walk through the sysfs files. - local(*DIRECTORY); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }}); - opendir(DIRECTORY, $directory); - while(my $file = readdir(DIRECTORY)) - { - next if $file eq "."; - next if $file eq ".."; - next if $file eq "lo"; - my $full_path = $directory."/".$file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { full_path => $full_path }}); - if (-d $full_path) - { - # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. - my $interface = $file; - my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; - my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; - my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? - my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down - my $modalias = -e $full_path."/device/modalias" ? $anvil->Storage->read_file({file => $full_path."/device/modalias"}) : "unknown"; - my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link - my $media = "unknown"; - my $type = "interface"; - my $driver = ""; - my $tx_bytes = 0; # How many bytes transmitted - my $rx_bytes = 0; # How many bytes received - - # Clean up some newlines. - $link_state =~ s/\n$//; - $mtu =~ s/\n$//; - $duplex =~ s/\n$//; - $operational =~ s/\n$//; - $speed =~ s/\n$//; - $modalias =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface => $interface, - link_state => $link_state, - mtu => $mtu, - duplex => $duplex, - operational => $operational, - speed => $speed, - modalias => $modalias, - }}); - - ### NOTE: This only parses virtio so far. - # Pick out our driver. - if ($modalias =~ /^virtio:/) - { - $driver = "virtio"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { driver => $driver }}); - } - - # The MAC address can faked by a number of ways, so we make an explicit call to 'ethtool' to get the permanent mac address. - my $mac_address = ""; - my $shell_call = $anvil->data->{path}{exe}{ethtool}." -P ".$interface; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - if ($output =~ /(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)$/) - { - $mac_address = lc($1); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - else - { - # Get it by reading the address file. - if (-e $full_path."/bonding_slave/perm_hwaddr") - { - $mac_address = $anvil->Storage->read_file({file => $full_path."/bonding_slave/perm_hwaddr"}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - elsif (-e $full_path."/address") - { - $mac_address = $anvil->Storage->read_file({file => $full_path."/address"}); - $mac_address =~ s/\n//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - } - - # These are variables that will be needed if this is a bond interface. - my $ip_address = ""; - my $subnet_mask = ""; - my $bond_mode = ""; - my $primary_interface = ""; - my $primary_reselect = ""; - my $active_interface = ""; - my $mii_polling_interval = ""; - my $up_delay = ""; - my $down_delay = ""; - my $bond_master = ""; - - # These are variables that will be needed if this is a bridge interface - my $bridge_id = ""; - my $bridge_stp_enabled = ""; - - # Explicitly check for the existing of the hash so that we don't auto-vivivate the interface. - if (exists $anvil->data->{network}{$local_host}{interface}{$interface}) - { - $ip_address = defined $anvil->data->{network}{$local_host}{interface}{$interface}{ip} ? $anvil->data->{network}{$local_host}{interface}{$interface}{ip} : ""; - $subnet_mask = defined $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} ? $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} : ""; - $type = defined $anvil->data->{network}{$local_host}{interface}{$interface}{type} ? $anvil->data->{network}{$local_host}{interface}{$interface}{type} : "interface"; - $tx_bytes = defined $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes} ? $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes} : 0; - $rx_bytes = defined $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes} ? $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes} : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - ip_address => $ip_address, - subnet_mask => $subnet_mask, - type => $type, - rx_bytes => $rx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $rx_bytes}).")", - tx_bytes => $tx_bytes." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $tx_bytes}).")", - }}); - } - - # If this interface is already a bond slave, the real mac address will be in a - # sub-directory. - my $mac_bond_file = $directory."/".$file."/bonding_slave/perm_hwaddr"; - if (-e $mac_bond_file) - { - # It's a slave. - $mac_address = $anvil->Storage->read_file({file => $mac_bond_file}); - $mac_address =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { mac_address => $mac_address }}); - } - - # If this is a virtual interface, set some fake values that don't actually exist on - # the system for the sake of a cleaner display. - if (($mac_address =~ /^52:54:00/) or ($driver eq "virtio")) - { - ### Set some fake values. - # Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary. - if ((not $speed) or ($speed eq "-1")) - { - $speed = 10000; - } - if ((not $duplex) or ($duplex eq "unknown")) - { - $duplex = "full"; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - speed => $speed, - duplex => $duplex, - }}); - } - # If the state is 'down', set the speed to '0'. - if (not $link_state) - { - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); - } - - # Is this a bond interface? - if (-e "/proc/net/bonding/".$interface) - { - # Yup, we'll neet to dig into the bond proc files to get the proper slaved - # interface MAC addresses. - $type = "bond"; - - # Read the bond mode. - $bond_mode = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/mode"}); - $primary_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary"}); - $primary_reselect = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/primary_reselect"}); - $active_interface = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/active_slave"}); - $mii_polling_interval = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/miimon"}); - $up_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/updelay"}); - $down_delay = $anvil->Storage->read_file({file => "/sys/devices/virtual/net/".$interface."/bonding/downdelay"}); - $bond_mode =~ s/\s.*//; - $bond_mode =~ s/\n$//; - $primary_interface =~ s/\n$//; - $primary_reselect =~ s/\s.*//; - $primary_reselect =~ s/\n$//; - $active_interface =~ s/\n$//; - $mii_polling_interval =~ s/\n$//; - $up_delay =~ s/\n$//; - $down_delay =~ s/\n$//; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - active_interface => $active_interface, - bond_mode => $bond_mode, - mii_polling_interval => $mii_polling_interval, - primary_reselect => $primary_reselect, - primary_interface => $primary_interface, - type => $type, - }}); - } - elsif ((-e $full_path."/master") && ($interface !~ /^vnet/)) - { - # We're in a bond. - my $target = readlink($full_path."/master"); - $bond_master = ($target =~ /^.*\/(.*)$/)[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - target => $target, - bond_master => $bond_master, - }}); - } - elsif (-d $full_path."/bridge") - { - # It's a bridge - $type = "bridge"; - $bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"}); - $bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"}); - $bridge_id =~ s/\n$//; - $bridge_stp_enabled =~ s/\n$//; - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - bridge_id => $bridge_id, - bridge_stp_enabled => $bridge_stp_enabled, - type => $type, - }}); - if ($bridge_stp_enabled eq "0") - { - $bridge_stp_enabled = "disabled"; - } - elsif ($bridge_stp_enabled eq "1") - { - $bridge_stp_enabled = "enabled_kernel"; - } - elsif ($bridge_stp_enabled eq "2") - { - $bridge_stp_enabled = "enabled_userland"; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_stp_enabled => $bridge_stp_enabled }}); - } - - # If this is a 'vnet' device, set 'operational' to up - if ($interface =~ /^vnet/) - { - $operational = "up"; - $media = "virtual"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - operational => $operational, - media => $media, - }}); - } - - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - active_interface => $active_interface, - bond_master => $bond_master, - bond_mode => $bond_mode, - bridge_id => $bridge_id, - bridge_stp_enabled => $bridge_stp_enabled, - down_delay => $down_delay, - duplex => $duplex, - interface => $interface, - mac_address => $mac_address, - mii_polling_interval => $mii_polling_interval, - mtu => $mtu, - operational => $operational, - primary_reselect => $primary_reselect, - primary_interface => $primary_interface, - speed => $speed, - subnet_mask => $subnet_mask, - type => $type, - up_delay => $up_delay, - }}); - - # If the MAC address starts with '52:54:00', we've got a virtio NIC. - if ((not defined $speed) or ($speed eq "")) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0001", variables => { file => $full_path."/speed" }}); - next; - } - if ($speed =~ /\D/) - { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_network_error_0002", variables => { - file => $full_path."/speed", - speed => $speed, - }}); - next; - } - if ($speed > 100000) - { - # NOTE: This is probably 0 now... Though someday >100 Gbps will be reasonable - # and we'll need to change this. - $speed = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { speed => $speed }}); - } - - # Find the media, if possible. - (my $ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"}); - foreach my $line (split/\n/, $ethtool) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /Supported ports: \[ (.*?) \]/i) - { - $media = lc($1); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); - - # This can be 'tp mii', which breaks json. - if ($media =~ /\t/) - { - $media =~ s/\t/,/g; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }}); - } - last; - } - } - - # Store new information we found. - $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface} = $active_interface; - $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode} = $bond_mode; - $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master} = $bond_master; - $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id} = $bridge_id; - $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled} = $bridge_stp_enabled; - $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay} = $down_delay; - $anvil->data->{network}{$local_host}{interface}{$interface}{duplex} = $duplex; - $anvil->data->{network}{$local_host}{interface}{$interface}{ip} = $ip_address; - $anvil->data->{network}{$local_host}{interface}{$interface}{link_state} = $link_state; - $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address} = $mac_address; - $anvil->data->{network}{$local_host}{interface}{$interface}{media} = $media; - $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval} = $mii_polling_interval; - $anvil->data->{network}{$local_host}{interface}{$interface}{mtu} = $mtu; - $anvil->data->{network}{$local_host}{interface}{$interface}{operational} = $operational; - $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect} = $primary_reselect; - $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface} = $primary_interface; - $anvil->data->{network}{$local_host}{interface}{$interface}{speed} = $speed; - $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask} = $subnet_mask; - $anvil->data->{network}{$local_host}{interface}{$interface}{type} = $type; - $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay} = $up_delay; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "network::${local_host}::interface::${interface}::active_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}, - "network::${local_host}::interface::${interface}::bond_mode" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}, - "network::${local_host}::interface::${interface}::bond_master" => $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}, - "network::${local_host}::interface::${interface}::bridge_id" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}, - "network::${local_host}::interface::${interface}::bridge_stp_enabled" => $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}, - "network::${local_host}::interface::${interface}::down_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}, - "network::${local_host}::interface::${interface}::duplex" => $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}, - "network::${local_host}::interface::${interface}::ip" => $anvil->data->{network}{$local_host}{interface}{$interface}{ip}, - "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, - "network::${local_host}::interface::${interface}::mac_address" => $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}, - "network::${local_host}::interface::${interface}::media" => $anvil->data->{network}{$local_host}{interface}{$interface}{media}, - "network::${local_host}::interface::${interface}::mii_polling_interval" => $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}, - "network::${local_host}::interface::${interface}::mtu" => $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}, - "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, - "network::${local_host}::interface::${interface}::primary_reselect" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}, - "network::${local_host}::interface::${interface}::primary_interface" => $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}, - "network::${local_host}::interface::${interface}::speed" => $anvil->data->{network}{$local_host}{interface}{$interface}{speed}, - "network::${local_host}::interface::${interface}::subnet_mask" => $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}, - "network::${local_host}::interface::${interface}::type" => $anvil->data->{network}{$local_host}{interface}{$interface}{type}, - "network::${local_host}::interface::${interface}::up_delay" => $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}, - }}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "network::${local_host}::interface::${interface}::link_state" => $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}, - "network::${local_host}::interface::${interface}::operational" => $anvil->data->{network}{$local_host}{interface}{$interface}{operational}, - }}); - - # If this is a link and there's no database connections, cache the data. - if (($type eq "interface") && (not $anvil->data->{sys}{database}{connections})) - { - $anvil->data->{cache}{new_file} .= $interface.",".$anvil->Database->refresh_timestamp.",".$mac_address.",".$speed.",".$link_state.",".$operational.",NULL,NULL\n"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "cache::new_file" => $anvil->data->{cache}{new_file}, - }}); - } - } - } - closedir(DIRECTORY); - - # Find what interfaces are connected to which bridges - $anvil->Network->bridge_info({debug => 2}); - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{$local_host}{interface}}) - { - my $ip_address = $anvil->data->{network}{$local_host}{interface}{$interface}{ip}; - my $type = $anvil->data->{network}{$local_host}{interface}{$interface}{type}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - interface => $interface, - ip_address => $ip_address, - type => $type, - }}); - - $anvil->data->{interface}{name_to_type}{$interface} = $type; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "interface::name_to_type::${interface}" => $anvil->data->{interface}{name_to_type}{$interface}, - }}); - - if ($type eq "bridge") - { - # Store the bridge - $anvil->data->{new}{bridge}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; - $anvil->data->{new}{bridge}{$interface}{id} = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_id}; - $anvil->data->{new}{bridge}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; - $anvil->data->{new}{bridge}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; - $anvil->data->{new}{bridge}{$interface}{stp_enabled} = $anvil->data->{network}{$local_host}{interface}{$interface}{bridge_stp_enabled}; - $anvil->data->{new}{bridge}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; - $anvil->data->{new}{bridge}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "new::bridge::${interface}::nm_uuid" => $anvil->data->{new}{bridge}{$interface}{nm_uuid}, - "new::bridge::${interface}::id" => $anvil->data->{new}{bridge}{$interface}{id}, - "new::bridge::${interface}::mac_address" => $anvil->data->{new}{bridge}{$interface}{mac_address}, - "new::bridge::${interface}::mtu" => $anvil->data->{new}{bridge}{$interface}{mtu}, - "new::bridge::${interface}::stp_enabled" => $anvil->data->{new}{bridge}{$interface}{stp_enabled}, - "new::bridge::${interface}::tx_bytes" => $anvil->data->{new}{bridge}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bridge}{$interface}{tx_bytes}}).")", - "new::bridge::${interface}::rx_bytes" => $anvil->data->{new}{bridge}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bridge}{$interface}{rx_bytes}}).")", - }}); - } - elsif ($type eq "bond") - { - # Store the bond - $anvil->data->{new}{bond}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; - $anvil->data->{new}{bond}{$interface}{mode} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_mode}; - $anvil->data->{new}{bond}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; - $anvil->data->{new}{bond}{$interface}{master} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; - $anvil->data->{new}{bond}{$interface}{link_state} = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; - $anvil->data->{new}{bond}{$interface}{operational} = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; - $anvil->data->{new}{bond}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; - $anvil->data->{new}{bond}{$interface}{primary_interface} = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_interface}; - $anvil->data->{new}{bond}{$interface}{primary_reselect} = $anvil->data->{network}{$local_host}{interface}{$interface}{primary_reselect}; - $anvil->data->{new}{bond}{$interface}{active_interface} = $anvil->data->{network}{$local_host}{interface}{$interface}{active_interface}; - $anvil->data->{new}{bond}{$interface}{mii_polling_interval} = $anvil->data->{network}{$local_host}{interface}{$interface}{mii_polling_interval}; - $anvil->data->{new}{bond}{$interface}{up_delay} = $anvil->data->{network}{$local_host}{interface}{$interface}{up_delay}; - $anvil->data->{new}{bond}{$interface}{down_delay} = $anvil->data->{network}{$local_host}{interface}{$interface}{down_delay}; - $anvil->data->{new}{bond}{$interface}{bridge_uuid} = ""; # We'll dig his out later as the bridge might not be in the database yet. - $anvil->data->{new}{bond}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; - $anvil->data->{new}{bond}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "new::bond::${interface}::nm_uuid" => $anvil->data->{new}{bond}{$interface}{nm_uuid}, - "new::bond::${interface}::mode" => $anvil->data->{new}{bond}{$interface}{mode}, - "new::bond::${interface}::mtu" => $anvil->data->{new}{bond}{$interface}{mtu}, - "new::bond::${interface}::master" => $anvil->data->{new}{bond}{$interface}{master}, - "new::bond::${interface}::link_state" => $anvil->data->{new}{bond}{$interface}{link_state}, - "new::bond::${interface}::operational" => $anvil->data->{new}{bond}{$interface}{operational}, - "new::bond::${interface}::mac_address" => $anvil->data->{new}{bond}{$interface}{mac_address}, - "new::bond::${interface}::primary_interface" => $anvil->data->{new}{bond}{$interface}{primary_interface}, - "new::bond::${interface}::primary_reselect" => $anvil->data->{new}{bond}{$interface}{primary_reselect}, - "new::bond::${interface}::active_interface" => $anvil->data->{new}{bond}{$interface}{active_interface}, - "new::bond::${interface}::mii_polling_interval" => $anvil->data->{new}{bond}{$interface}{mii_polling_interval}, - "new::bond::${interface}::up_delay" => $anvil->data->{new}{bond}{$interface}{up_delay}, - "new::bond::${interface}::down_delay" => $anvil->data->{new}{bond}{$interface}{down_delay}, - "new::bond::${interface}::bridge_uuid" => $anvil->data->{new}{bond}{$interface}{bridge_uuid}, - "new::bond::${interface}::tx_bytes" => $anvil->data->{new}{bond}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bond}{$interface}{tx_bytes}}).")", - "new::bond::${interface}::rx_bytes" => $anvil->data->{new}{bond}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{bond}{$interface}{rx_bytes}}).")", - }}); - } - elsif ($type eq "interface") - { - # Store the interface - $anvil->data->{new}{interface}{$interface}{nm_uuid} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_uuid}; - $anvil->data->{new}{interface}{$interface}{nm_device} = $anvil->data->{network}{$local_host}{interface}{$interface}{nm_device}; - $anvil->data->{new}{interface}{$interface}{bond_uuid} = ""; - $anvil->data->{new}{interface}{$interface}{bond_name} = $anvil->data->{network}{$local_host}{interface}{$interface}{bond_master}; - $anvil->data->{new}{interface}{$interface}{bridge_uuid} = ""; - $anvil->data->{new}{interface}{$interface}{bridge_name} = ""; - $anvil->data->{new}{interface}{$interface}{duplex} = $anvil->data->{network}{$local_host}{interface}{$interface}{duplex}; - $anvil->data->{new}{interface}{$interface}{link_state} = $anvil->data->{network}{$local_host}{interface}{$interface}{link_state}; - $anvil->data->{new}{interface}{$interface}{operational} = $anvil->data->{network}{$local_host}{interface}{$interface}{operational}; - $anvil->data->{new}{interface}{$interface}{mac_address} = $anvil->data->{network}{$local_host}{interface}{$interface}{mac_address}; - $anvil->data->{new}{interface}{$interface}{medium} = $anvil->data->{network}{$local_host}{interface}{$interface}{media}; - $anvil->data->{new}{interface}{$interface}{mtu} = $anvil->data->{network}{$local_host}{interface}{$interface}{mtu}; - $anvil->data->{new}{interface}{$interface}{speed} = $anvil->data->{network}{$local_host}{interface}{$interface}{speed}; - $anvil->data->{new}{interface}{$interface}{tx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{tx_bytes}; - $anvil->data->{new}{interface}{$interface}{rx_bytes} = $anvil->data->{network}{$local_host}{interface}{$interface}{rx_bytes}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "new::interface::${interface}::nm_uuid" => $anvil->data->{new}{interface}{$interface}{nm_uuid}, - "new::interface::${interface}::nm_device" => $anvil->data->{new}{interface}{$interface}{nm_device}, - "new::interface::${interface}::bond_uuid" => $anvil->data->{new}{interface}{$interface}{bond_uuid}, - "new::interface::${interface}::bond_name" => $anvil->data->{new}{interface}{$interface}{bond_name}, - "new::interface::${interface}::bridge_uuid" => $anvil->data->{new}{interface}{$interface}{bridge_uuid}, - "new::interface::${interface}::bridge_name" => $anvil->data->{new}{interface}{$interface}{bridge_name}, - "new::interface::${interface}::duplex" => $anvil->data->{new}{interface}{$interface}{duplex}, - "new::interface::${interface}::link_state" => $anvil->data->{new}{interface}{$interface}{link_state}, - "new::interface::${interface}::operational" => $anvil->data->{new}{interface}{$interface}{operational}, - "new::interface::${interface}::mac_address" => $anvil->data->{new}{interface}{$interface}{mac_address}, - "new::interface::${interface}::medium" => $anvil->data->{new}{interface}{$interface}{medium}, - "new::interface::${interface}::mtu" => $anvil->data->{new}{interface}{$interface}{mtu}, - "new::interface::${interface}::speed" => $anvil->data->{new}{interface}{$interface}{speed}, - "new::interface::${interface}::tx_bytes" => $anvil->data->{new}{interface}{$interface}{tx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{tx_bytes}}).")", - "new::interface::${interface}::rx_bytes" => $anvil->data->{new}{interface}{$interface}{rx_bytes}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new}{interface}{$interface}{rx_bytes}}).")", - }}); - - # On some occassions, an interface that is in a bond won't start. If the host uptime - # is less than ten minutes, and a bond's member interface is down, up it. - if ($uptime < 600) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "nmcli::${local_host}::device_to_uuid::${interface}" => $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$interface}, - }}); - my $uuid = $anvil->data->{nmcli}{$local_host}{device_to_uuid}{$interface}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uuid => $uuid }}); - - if ($uuid) - { - my $state = $anvil->data->{nmcli}{$local_host}{uuid}{$uuid}{'state'}; - my $filename = $anvil->data->{nmcli}{$local_host}{uuid}{$uuid}{filename}; - my $name = ($filename =~ /ifcfg-(.*?)$/)[0]; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - filename => $filename, - name => $name, - 'state' => $state, - }}); - - # This could be 'active' or 'activated' - if ($state !~ /activ/) - { - # Try brinding the interface up. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0147", variables => { - interface => $interface, - uptime => $uptime, - 'state' => $state, - }}); - - my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$name; - $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}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - output => $output, - return_code => $return_code, - }}); - } - } - } - } - - # Record the IP address info. - if ($ip_address) - { - $anvil->data->{new}{ip_address}{$ip_address}{on_interface} = $interface; - $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask} = $anvil->data->{network}{$local_host}{interface}{$interface}{subnet_mask}; - $anvil->data->{new}{ip_address}{$ip_address}{gateway} = $anvil->data->{network}{$local_host}{interface}{$interface}{gateway}; - $anvil->data->{new}{ip_address}{$ip_address}{default_gateway} = $anvil->data->{network}{$local_host}{interface}{$interface}{default_gateway}; - $anvil->data->{new}{ip_address}{$ip_address}{dns} = $anvil->data->{network}{$local_host}{interface}{$interface}{dns}; - $anvil->data->{new}{ip_address}{$ip_address}{on_uuid} = ""; - $anvil->data->{new}{ip_address}{$ip_address}{note} = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "new::ip_address::${ip_address}::on_interface" => $anvil->data->{new}{ip_address}{$ip_address}{on_interface}, - "new::ip_address::${ip_address}::subnet_mask" => $anvil->data->{new}{ip_address}{$ip_address}{subnet_mask}, - "new::ip_address::${ip_address}::gateway" => $anvil->data->{new}{ip_address}{$ip_address}{gateway}, - "new::ip_address::${ip_address}::default_gateway" => $anvil->data->{new}{ip_address}{$ip_address}{default_gateway}, - "new::ip_address::${ip_address}::dns" => $anvil->data->{new}{ip_address}{$ip_address}{dns}, - "new::ip_address::${ip_address}::on_uuid" => $anvil->data->{new}{ip_address}{$ip_address}{on_uuid}, - "new::ip_address::${ip_address}::note" => $anvil->data->{new}{ip_address}{$ip_address}{note}, - }}); - } - } - - return(0); -=cut -} - # This reads in the states from the last can sub read_last_scan { From 943bf2e8d357dcf101cb6d53f0e3067acd64cdce Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 24 Jan 2024 11:42:11 -0500 Subject: [PATCH 36/43] Removed the no-longer-needed Network->check_network() method Signed-off-by: digimer --- Anvil/Tools/Network.pm | 404 ----------------------------------------- tools/anvil-daemon | 4 +- 2 files changed, 1 insertion(+), 407 deletions(-) diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 5b49a639..00906da5 100644 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -15,7 +15,6 @@ my $THIS_FILE = "Network.pm"; ### Methods; # bridge_info # check_firewall -# check_network # check_internet # collect_data # download @@ -385,409 +384,6 @@ sub check_firewall } -### TODO: Phase this out when EL8 / ifcfg-X file support is ended. -=head2 check_network - -B<< NOTE >>: This method is not yet implemented. - -This method checks to see if bridges and the links in bonds are up. It can simply report the bridge, bond and link states, or it can try to bring up interfaces that are down. - -This method returns C<< 0 >> if nothing was done. It returns C<< 1 >> if any repairs were done. - -Data is stored in the hash; - -* bridge_health::::up = [0,1] -* bond_health::::up = [0,1] -* bond_health::::active_links = -* bond_health::::up_links = -* bond_health::::configured_links = -* bond_health::::interface::::in_bond = [0,1] -* bond_health::::interface::::up = [0,1] -* bond_health::::interface::::carrier = [0,1] -* bond_health::::interface::::name = - -Parameters; - -=head3 heal (optional, default 'down_only') - -When set to C<< down_only >>, a bond where both links are down will attempt to up the links. However, bonds with at least one link up will be left alone. This is the default behaviour as it's not uncommon for admins to remotely down a single interface that is failing to stop alerts until a physical repair can be made. - -When set to C<< all >>, any interfaces that are found to be down will attempt to brought up. - -Wen set to C<< none >>, no attempts will be made to bring up any interfaces. The states will simply be recorded. - -B<< Note >>: Interfaces that show no carrier will not be started in any case. - -=cut -sub check_network -{ - my $self = shift; - my $parameter = shift; - my $anvil = $self->parent; - my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->check_internet()" }}); - - # This is causing more problems than it solves. Disabled for the time being. - return(0); - - my $heal = defined $parameter->{heal} ? $parameter->{heal} : "down_only"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - heal => $heal, - }}); - - # Find out the bonds that are up. - my $host = $anvil->Get->short_host_name(); - $anvil->Network->bridge_info({debug => $debug}); - - if (exists $anvil->data->{bond_health}) - { - delete $anvil->data->{bond_health}; - } - - # Read in the network configuration files to track which interfaces are bound to which bonds. - my $repaired = 0; - my $interface = ""; - my $directory = $anvil->data->{path}{directories}{ifcfg}; - local(*DIRECTORY); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0018", variables => { directory => $directory }}); - opendir(DIRECTORY, $directory); - while(my $file = readdir(DIRECTORY)) - { - if ($file =~ /^ifcfg-(.*)$/) - { - $interface = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface => $interface }}); - - # We'll check these, so this just makes sure we don't get an undefined variable error. - $anvil->data->{raw_network}{interface}{$interface}{variable}{TYPE} = ""; - $anvil->data->{raw_network}{interface}{$interface}{variable}{DEVICE} = ""; - $anvil->data->{raw_network}{interface}{$interface}{variable}{MASTER} = ""; - } - else - { - next; - } - my $full_path = $directory."/".$file; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { full_path => $full_path }}); - - my $device = ""; - my $is_link = ""; - my $in_bond = ""; - my $is_bond = ""; - - # Read in the file. - my $file_body = $anvil->Storage->read_file({debug => $debug, file => $full_path}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); - - foreach my $line (split/\n/, $file_body) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - $line =~ s/#.*$//; - if ($line =~ /^(.*?)=(.*)$/) - { - my $variable = $1; - my $value = $2; - $value =~ s/^"(.*)"$/$1/; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - variable => $variable, - value => $value, - }}); - - $anvil->data->{raw_network}{interface}{$interface}{variable}{$variable} = $value; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "raw_network::interface::${interface}::variable::${variable}" => $anvil->data->{raw_network}{interface}{$interface}{variable}{$variable}, - }}); - } - } - $interface = ""; - } - closedir(DIRECTORY); - - # Process - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{raw_network}{interface}}) - { - my $type = $anvil->data->{raw_network}{interface}{$interface}{variable}{TYPE}; - my $device = $anvil->data->{raw_network}{interface}{$interface}{variable}{DEVICE}; - my $name = defined $anvil->data->{raw_network}{interface}{$interface}{variable}{NAME} ? $anvil->data->{raw_network}{interface}{$interface}{variable}{NAME} : $device; - $name =~ s/ /_/g; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - interface => $interface, - type => $type, - device => $device, - name => $name, - }}); - - # Is this a bridge? - if (lc($type) eq "bridge") - { - # Yup! - $anvil->data->{bridge_health}{$device}{up} = 0; - $anvil->data->{bridge_health}{$device}{name} = $name; - if ((exists $anvil->data->{bridge}{$host}{$device}) && ($anvil->data->{bridge}{$host}{$device}{found})) - { - $anvil->data->{bridge_health}{$device}{up} = 1; - } - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bridge_health::${device}::up" => $anvil->data->{bridge_health}{$device}{up}, - "bridge_health::${device}::name" => $anvil->data->{bridge_health}{$device}{name}, - }}); - } - - # Is this a bond? - if (lc($type) eq "bond") - { - # Yes! - $anvil->data->{bond_health}{$device}{configured_links} = 0; - $anvil->data->{bond_health}{$device}{active_links} = 0; - $anvil->data->{bond_health}{$device}{up_links} = 0; - $anvil->data->{bond_health}{$device}{name} = $name; - - # Find the links configured to be under this bond. - foreach my $this_interface (sort {$a cmp $b} keys %{$anvil->data->{raw_network}{interface}}) - { - # Is this a bond? - my $this_type = $anvil->data->{raw_network}{interface}{$this_interface}{variable}{TYPE}; - my $this_device = $anvil->data->{raw_network}{interface}{$this_interface}{variable}{DEVICE}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - this_interface => $this_interface, - this_type => $this_type, - this_device => $this_device, - }}); - next if lc($this_type) ne "ethernet"; - - my $master = $anvil->data->{raw_network}{interface}{$this_interface}{variable}{MASTER}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { master => $master }}); - if (($master) && ($master eq $device)) - { - # This interface belongs to this bond. - $anvil->data->{bond_health}{$device}{interface}{$this_device}{in_bond} = 0; - $anvil->data->{bond_health}{$device}{interface}{$this_device}{up} = "unknown"; - $anvil->data->{bond_health}{$device}{interface}{$this_device}{carrier} = "unknown"; - $anvil->data->{bond_health}{$device}{interface}{$this_device}{name} = $this_interface; - $anvil->data->{bond_health}{$device}{configured_links}++; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::interface::${this_device}::name" => $anvil->data->{bond_health}{$device}{interface}{$this_device}{name}, - "bond_health::${device}::configured_links" => $anvil->data->{bond_health}{$device}{configured_links}, - }}); - - # Read the interface's carrier - my $carrier_file = "/sys/class/net/".$this_device."/carrier"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier_file => $carrier_file }}); - - if (-e $carrier_file) - { - my $carrier = $anvil->Storage->read_file({debug => $debug, file => $carrier_file}); - chomp $carrier; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { carrier => $carrier }}); - - $anvil->data->{bond_health}{$device}{interface}{$this_device}{carrier} = $carrier; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::interface::${this_device}::carrier" => $anvil->data->{bond_health}{$device}{interface}{$this_device}{carrier}, - }}); - } - - my $operstate_file = "/sys/class/net/".$this_device."/operstate"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate_file => $operstate_file }}); - - if (-e $operstate_file) - { - my $operstate = $anvil->Storage->read_file({debug => $debug, file => $operstate_file}); - chomp $operstate; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { operstate => $operstate }}); - - $anvil->data->{bond_health}{$device}{interface}{$this_device}{up} = $operstate eq "up" ? 1 : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::interface::${this_device}::operstate" => $anvil->data->{bond_health}{$device}{interface}{$this_device}{operstate}, - }}); - } - } - } - - # Read in the /proc file. - my $proc_file = "/proc/net/bonding/".$device; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { proc_file => $proc_file }}); - - my $in_link = ""; - my $file_body = $anvil->Storage->read_file({debug => $debug, file => $proc_file}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_body => $file_body }}); - foreach my $line (split/\n/, $file_body) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); - - if ($line =~ /Slave Interface: (.*)$/) - { - $in_link = $1; - $anvil->data->{bond_health}{$device}{active_links}++; - $anvil->data->{bond_health}{$device}{interface}{$in_link}{in_bond} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::active_links" => $anvil->data->{bond_health}{$device}{active_links}, - "bond_health::${device}::interface::${in_link}::in_bond" => $anvil->data->{bond_health}{$device}{interface}{$in_link}{in_bond}, - }}); - next; - } - if (not $line) - { - $in_link = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_link => $in_link }}); - next; - } - if ($in_link) - { - if ($line =~ /MII Status: (.*)$/) - { - my $status = $1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { status => $status }}); - if ($status eq "up") - { - $anvil->data->{bond_health}{$device}{up_links}++; - $anvil->data->{bond_health}{$device}{interface}{$in_link}{up} = 1; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::up_links" => $anvil->data->{bond_health}{$device}{up_links}, - "bond_health::${device}::interface::${in_link}::up" => $anvil->data->{bond_health}{$device}{interface}{$in_link}{up}, - }}); - } - else - { - $anvil->data->{bond_health}{$device}{interface}{$in_link}{up} = 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "bond_health::${device}::interface::${in_link}::up" => $anvil->data->{bond_health}{$device}{interface}{$in_link}{up}, - }}); - } - next; - } - } - else - { - if ($line =~ /MII Status: (.*)$/) - { - my $status = $1; - $anvil->data->{bond_health}{$device}{up} = $status eq "up" ? 1 : 0; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - status => $status, - "bond_health::${device}::up" => $anvil->data->{bond_health}{$device}{up}, - }}); - next; - } - } - } - } - } - - # Before we check the bonds, check the bridges. Bonds won't come up if they're in a bridge that is - # down. - my $bridge_count = keys %{$anvil->data->{bridge_health}}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bridge_count => $bridge_count }}); - if (($bridge_count) && (not $heal eq "none")) - { - foreach my $bridge (sort {$a cmp $b} keys %{$anvil->data->{bridge_health}}) - { - my $up = $anvil->data->{bridge_health}{$bridge}{up}; - my $name = $anvil->data->{bridge_health}{$bridge}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - bridge => $bridge, - name => $name, - up => $up, - }}); - - if (not $up) - { - # Try to recover the interface - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0632", variables => { bridge => $bridge }}); - - my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$name; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); - - my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'output' => $output, - 'return_code' => $return_code, - }}); - } - } - } - - foreach my $bond (sort {$a cmp $b} keys %{$anvil->data->{bond_health}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:bond_health::${bond}::name" => $anvil->data->{bond_health}{$bond}{name}, - "s2:bond_health::${bond}::up" => $anvil->data->{bond_health}{$bond}{up}, - "s3:bond_health::${bond}::configured_links" => $anvil->data->{bond_health}{$bond}{configured_links}, - "s4:bond_health::${bond}::active_links" => $anvil->data->{bond_health}{$bond}{active_links}, - "s5:bond_health::${bond}::up_links" => $anvil->data->{bond_health}{$bond}{up_links}, - }}); - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{bond_health}{$bond}{interface}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s1:bond_health::${bond}::interface::${interface}::name" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{name}, - "s2:bond_health::${bond}::interface::${interface}::in_bond" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{in_bond}, - "s3:bond_health::${bond}::interface::${interface}::up" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{up}, - "s4:bond_health::${bond}::interface::${interface}::carrier" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{carrier}, - }}); - } - - if ($anvil->data->{bond_health}{$bond}{configured_links} != $anvil->data->{bond_health}{$bond}{up_links}) - { - next if $heal eq "none"; - next if (($anvil->data->{bond_health}{$bond}{up}) && ($heal eq "down_only")); - - # Log that we're going to try to heal this bond. - if ($heal eq "down_only") - { - # Log that we're healing fully down bonds. - $repaired = 1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0627", variables => { bond => $bond }}); - } - else - { - # Log that we're healing all bond links - $repaired = 1; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0628", variables => { bond => $bond }}); - } - - # For good measure, try to up the bond as well. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0630", variables => { bond => $bond }}); - - my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$anvil->data->{bond_health}{$bond}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); - - my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'output' => $output, - 'return_code' => $return_code, - }}); - - # If we're here, try to bring up down'ed interfaces. - foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{bond_health}{$bond}{interface}}) - { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "s2:bond_health::${bond}::interface::${interface}::in_bond" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{in_bond}, - "s4:bond_health::${bond}::interface::${interface}::carrier" => $anvil->data->{bond_health}{$bond}{interface}{$interface}{carrier}, - }}); - if ((not $anvil->data->{bond_health}{$bond}{interface}{$interface}{in_bond}) && ($anvil->data->{bond_health}{$bond}{interface}{$interface}{carrier})) - { - # Link shown, try to start the interface. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0629", variables => { - bond => $bond, - interface => $interface." (".$anvil->data->{bond_health}{$bond}{interface}{$interface}{name}.")", - }}); - - my $shell_call = $anvil->data->{path}{exe}{ifup}." ".$anvil->data->{bond_health}{$bond}{interface}{$interface}{name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }}); - - my ($output, $return_code) = $anvil->System->call({debug => 1, shell_call => $shell_call}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 'output' => $output, - 'return_code' => $return_code, - }}); - } - } - } - } - - return($repaired); -} - - =head2 check_internet This method tries to connect to the internet. If successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 71fb69d9..ec43f305 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -334,15 +334,13 @@ sub set_delay return($delay); } -### NOTE: This used to call 'Network->check_network', which is now 'scan_network' and no longer tries to -### bring up downed connections. Likely this entire method can be removed, now that we're not using -### ifcfg-X files. # This checks to see if it's time to see if the network is ok and, if the system has been up long enough, # checks and tries to repair network issues. sub check_network { my ($anvil) = @_; + ### TODO: Remove this when EL8 support is dropped. This was an issue with the old ifcfg configured bonds # The network sometimes doesn't come up, but we don't want to try recovering it too soon. As such, # we'll start watching the network after the uptime is 2 minutes. my $uptime = $anvil->Get->uptime; From bf693ed212bf1bdbbf321533efa9132d3de36b35 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 24 Jan 2024 22:14:53 -0500 Subject: [PATCH 37/43] Updated anvil-daemon to enable root SSH access during startup This is required as we need to be able to ssh into peer strikers and into nodes and DR hosts during initialization. Signed-off-by: digimer --- Anvil/Tools.pm | 1 + share/words.xml | 1 + tools/anvil-daemon | 40 +++++++++++++++++++++++++++++++ tools/striker-auto-initialize-all | 1 + 4 files changed, 43 insertions(+) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index b73a489c..1addce07 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1079,6 +1079,7 @@ sub _set_paths postfix_relay_password => "/etc/postfix/relay_password", 'qemu.conf' => "/etc/libvirt/qemu.conf", ssh_config => "/etc/ssh/ssh_config", + sshd_root_password => "/etc/ssh/sshd_config.d/01-permitrootlogin.conf", 'type.striker' => "/etc/anvil/type.striker", 'type.dr' => "/etc/anvil/type.dr", 'type.node' => "/etc/anvil/type.node", diff --git a/share/words.xml b/share/words.xml index eee7754e..0f3b4ec1 100644 --- a/share/words.xml +++ b/share/words.xml @@ -3353,6 +3353,7 @@ proceeding. [ Note ] - Reconfiguring the network will break connections. Disconnecting from the database before starting. It might take a bit before this system reconnects and progress can be seen. [ Note ] - The network has reconnected to the database, configuring will complete shortly. [ Note ] - The old 'ifcfg' style config file: [#!variable!file!#] will be backed up and then removed! + [ Note ] - Updated the ssh daemon config file: [#!variable!file!#] to enable ssh access for the root user. Normal Password diff --git a/tools/anvil-daemon b/tools/anvil-daemon index ec43f305..51ff9437 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -1020,6 +1020,9 @@ sub run_once # Check journald is configured for persistent storage. check_journald($anvil); + # Make sure root can ssh + chech_sshd($anvil); + if ($anvil->data->{switches}{'startup-only'}) { $anvil->nice_exit({exit_code => 0}); @@ -1028,6 +1031,43 @@ sub run_once return(0); } +sub chech_sshd +{ + my ($anvil) = @_; + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'path::configs::sshd_root_password' => $anvil->data->{path}{configs}{sshd_root_password} }}); + if (not -f $anvil->data->{path}{configs}{sshd_root_password}) + { + # Write it out + my $body = "# This file was added to enable root login by password, which is needed while +# forming the Anvil! cluster. Once the cluster is formed, passwordless SSH +# should be enabled and you can disable this feature. Please remove during a +# maintanence window or after testing in a lab environment. +PermitRootLogin yes +"; + # Update the config + $anvil->Storage->write_file({ + debug => 2, + secure => 0, + file => $anvil->data->{path}{configs}{sshd_root_password}, + body => $body, + mode => "0644", + }); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "message_0418", variables => { file => $anvil->data->{path}{configs}{sshd_root_password} }}); + + # Restart the journald service. + my $shell_call = $anvil->data->{path}{exe}{systemctl}." restart sshd.service"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); + my ($output, $return_code) = $anvil->System->call({debug => 3, 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, + }}); + } + + return(0); +} + sub check_journald { my ($anvil) = @_; diff --git a/tools/striker-auto-initialize-all b/tools/striker-auto-initialize-all index ce4fc90d..6687dcd0 100755 --- a/tools/striker-auto-initialize-all +++ b/tools/striker-auto-initialize-all @@ -1288,6 +1288,7 @@ fi; remote_user => "root", }}); my ($host_uuid, $error, $return_code) = $anvil->Remote->call({ + debug => 2, shell_call => $shell_call, target => $ip, password => $anvil->data->{base}{password}{desired}, From 14022896aac44af54677e4bfd99324f8685cf3b4 Mon Sep 17 00:00:00 2001 From: digimer Date: Wed, 24 Jan 2024 23:41:52 -0500 Subject: [PATCH 38/43] Added a call for non-striker machines to call check_sshd if no DBs. Also added a check for sshd_config.d so that it doesn't error on EL8 machines. Signed-off-by: digimer --- Anvil/Tools.pm | 1 + tools/anvil-daemon | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index 1addce07..87ed9f6e 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1131,6 +1131,7 @@ sub _set_paths provision => "/mnt/shared/provision", temp => "/mnt/shared/temp", }, + 'sshd_config.d' => "/etc/ssh/sshd_config.d", skins => "/var/www/html/skins", status => "/var/www/html/status", syslinux => "/usr/share/syslinux", diff --git a/tools/anvil-daemon b/tools/anvil-daemon index 51ff9437..05e6cdd0 100755 --- a/tools/anvil-daemon +++ b/tools/anvil-daemon @@ -101,6 +101,9 @@ if (not $anvil->data->{sys}{database}{connections}) } else { + # Striker can't initialize us unless it can ssh into us, so make sure root login is enabled. + chech_sshd($anvil); + # Wait until we have one. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0075"}); @@ -1035,6 +1038,13 @@ sub chech_sshd { my ($anvil) = @_; + # On EL8, the 'sshd_config.d' directory doesn't exist and root is enabled. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'path::directories::sshd_config.d' => $anvil->data->{path}{directories}{'sshd_config.d'} }}); + if (not -d $anvil->data->{path}{directories}{'sshd_config.d'}) + { + return(0); + } + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'path::configs::sshd_root_password' => $anvil->data->{path}{configs}{sshd_root_password} }}); if (not -f $anvil->data->{path}{configs}{sshd_root_password}) { From 423f6777163b6a4c6891267ca9d460d0f6bf1d91 Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 25 Jan 2024 14:38:43 -0500 Subject: [PATCH 39/43] Updated Storage->manage_lvm_conf() to only run on EL8. Signed-off-by: digimer --- Anvil/Tools/Storage.pm | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Anvil/Tools/Storage.pm b/Anvil/Tools/Storage.pm index 2a158d39..32159eca 100644 --- a/Anvil/Tools/Storage.pm +++ b/Anvil/Tools/Storage.pm @@ -3232,6 +3232,8 @@ fi;"; =head2 manage_lvm_conf +B<< Note >>: This only works on EL8. If used on another distro, this method will return without actually doing anything. + This method configures C<< lvm.conf >> to add the C<< filter = [ ... ] >> to ensure DRBD devices aren't scanned. If there was a problem, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. @@ -3274,6 +3276,18 @@ sub manage_lvm_conf target => $target, }}); + ### NOTE: Only add the filter on EL8 machines. + my ($os_type, $os_arch) = $anvil->Get->os_type({debug => $debug}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + os_type => $os_type, + os_arch => $os_arch, + }}); + if ($os_type !~ /\D8/) + { + # Not EL8, return + return(0); + } + my $body = $anvil->Storage->read_file({ debug => $debug, file => $anvil->data->{path}{configs}{'lvm.conf'}, From 7018703c247b378b9f6df000ab90506ea6de92d9 Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 25 Jan 2024 19:58:06 -0500 Subject: [PATCH 40/43] Fixed a bug where the peer subnode would add a server to pacemaker * Updated anvil-provision-server to only call add_server_to_cluster() if it's NOT the peer. * Added the new 'ok_if_exists' parameter to Cluster->add_server() to return 0 if the server already existed in pacemaker as a resource. Signed-off-by: digimer --- Anvil/Tools/Cluster.pm | 14 ++++++++++++-- tools/anvil-provision-server | 12 ++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Anvil/Tools/Cluster.pm b/Anvil/Tools/Cluster.pm index 13aabc84..eab943da 100644 --- a/Anvil/Tools/Cluster.pm +++ b/Anvil/Tools/Cluster.pm @@ -105,6 +105,10 @@ This takes a server name, finds where it is running and then adds it to pacemake Parameters; +=head3 ok_if_exists (optional, default '0') + +Normally, if the server is already in the cluster, C<< !!error!! >> is returned. If this is set to C<< 1 >> and the server is already in pacemaker, we'll return C<< 0 >> instead. + =head3 server_name (required) This is the name of the server being added. @@ -118,9 +122,11 @@ sub add_server my $debug = defined $parameter->{debug} ? $parameter->{debug} : 2; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Cluster->add_server()" }}); - my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : ""; + my $ok_if_exists = defined $parameter->{ok_if_exists} ? $parameter->{ok_if_exists} : ""; + my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - server_name => $server_name, + ok_if_exists => $ok_if_exists, + server_name => $server_name, }}); if (not $server_name) @@ -146,6 +152,10 @@ sub add_server $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "cib::parsed::cib::resources::primitive::${server_name}::type" => $anvil->data->{cib}{parsed}{cib}{resources}{primitive}{$server_name}{type}, }}); + if ($ok_if_exists) + { + return(0); + } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0213", variables => { server_name => $server_name }}); return("!!error!!"); } diff --git a/tools/anvil-provision-server b/tools/anvil-provision-server index e358456a..5a87605a 100755 --- a/tools/anvil-provision-server +++ b/tools/anvil-provision-server @@ -321,8 +321,11 @@ sub run_jobs # Make sure the VNC port is open. $anvil->Network->manage_firewall(); - # Add the server to the cluster. - add_server_to_cluster($anvil); + # If we're not the peer, add the server to the cluster. + if (not $anvil->data->{job}{peer_mode}) + { + add_server_to_cluster($anvil); + } # Update the database by calling select scan agents $anvil->Job->update_progress({ @@ -368,8 +371,9 @@ sub add_server_to_cluster # Is our peer in the cluster? For that matter, are we? my $problem = $anvil->Cluster->add_server({ - debug => 2, - server_name => $anvil->data->{job}{server_name}, + debug => 2, + server_name => $anvil->data->{job}{server_name}, + ok_if_exists => 1, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); if ($problem) From b85e38d20def4f39827f1db7e2a24d3b581c8725 Mon Sep 17 00:00:00 2001 From: digimer Date: Thu, 25 Jan 2024 21:28:21 -0500 Subject: [PATCH 41/43] Added the short and full host names to hosts * Updated anvil_join_anvil->wait_for_etc_hosts() to add the short host name and the FQDN to the /etc/hosts file using the first BCN network's IP address. Signed-off-by: digimer --- tools/anvil-join-anvil | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/anvil-join-anvil b/tools/anvil-join-anvil index 81acd4e1..5202beed 100755 --- a/tools/anvil-join-anvil +++ b/tools/anvil-join-anvil @@ -148,6 +148,7 @@ sub wait_for_etc_hosts { my $this_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{"anvil_".$machine."_host_uuid"}; my $this_short_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{short_host_name}; + my $bcn_name = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { machine => $machine }}); foreach my $network_name (sort {$a cmp $b} keys %{$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{network}}) { @@ -163,6 +164,22 @@ sub wait_for_etc_hosts $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "s1:networks::${host_name}::ip_address" => $anvil->data->{networks}{$host_name}{ip_address}, }}); + + # If this is the first BCN, record it's name (in case BCN1 isn't used here) and IP + # address, and add the short and full host names. + if (($network_name =~ /^bcn/) && (not $bcn_name)) + { + $bcn_name = $network_name; + my $this_host_name = $anvil->data->{hosts}{host_uuid}{$this_host_uuid}{host_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bcn_name => $bcn_name }}); + + $anvil->data->{networks}{$this_short_host_name}{ip_address} = $ip_address; + $anvil->data->{networks}{$this_host_name}{ip_address} = $ip_address; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:networks::${this_short_host_name}::ip_address" => $anvil->data->{networks}{$this_short_host_name}{ip_address}, + "s2:networks::${this_host_name}::ip_address" => $anvil->data->{networks}{$this_host_name}{ip_address}, + }}); + } } } From bb78d65c770cac434accd428d3184d5cd8534026 Mon Sep 17 00:00:00 2001 From: digimer Date: Sat, 27 Jan 2024 21:36:54 -0500 Subject: [PATCH 42/43] Bumped debug logging. Signed-off-by: digimer --- tools/striker-collect-debug | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/striker-collect-debug b/tools/striker-collect-debug index 888dd859..9d77a662 100755 --- a/tools/striker-collect-debug +++ b/tools/striker-collect-debug @@ -353,6 +353,7 @@ sub collect_remote_data # Copying the file print "Done! Copying to here... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/tmp/journalctl-previous-boot.log", destination => $target_directory."/", }); @@ -392,6 +393,7 @@ sub collect_remote_data # Copying the file print "Done! Copying to here... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/tmp/journalctl-current-boot.log", destination => $target_directory."/", }); @@ -431,6 +433,7 @@ sub collect_remote_data { print "- Grabbing cloud-init logs... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/var/log/cloud-init*", destination => $target_directory."/", }); @@ -499,6 +502,7 @@ sub collect_remote_data print "- Grabbing hosts file... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/etc/hosts", destination => $target_directory."/", }); @@ -522,6 +526,7 @@ sub collect_remote_data print "- Grabbing Anvil! log... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/var/log/anvil.log", destination => $target_directory."/", }); @@ -559,6 +564,7 @@ sub collect_remote_data # Copying the file print "Done! Copying to here... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/tmp/cib.xml", destination => $target_directory."/", }); @@ -586,6 +592,7 @@ sub collect_remote_data { print "- Collecting server definitions... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/mnt/shared/definitions", destination => $target_directory."/", }); @@ -593,6 +600,7 @@ sub collect_remote_data print "- Collecting replicated storage config... "; $anvil->Storage->rsync({ + debug => 2, source => "root\@".$anvil->data->{peer}{$short_host_name}{access}{ip}.":/etc/drbd.d", destination => $target_directory."/", }); From 050891d7519d1a1c2144ec43148e72ef985ff4c9 Mon Sep 17 00:00:00 2001 From: digimer Date: Sun, 28 Jan 2024 00:12:13 -0500 Subject: [PATCH 43/43] Fixed inverted file copy check logic. This should resolve issue #534 Signed-off-by: digimer --- tools/striker-collect-debug | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/striker-collect-debug b/tools/striker-collect-debug index 9d77a662..1f5a5b08 100755 --- a/tools/striker-collect-debug +++ b/tools/striker-collect-debug @@ -359,7 +359,7 @@ sub collect_remote_data }); my $test_file = $target_directory."/tmp/journalctl-previous-boot.log"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -399,7 +399,7 @@ sub collect_remote_data }); $test_file = $target_directory."/journalctl-current-boot.log"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -439,7 +439,7 @@ sub collect_remote_data }); $test_file = $target_directory."/cloud-init.log"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -508,7 +508,7 @@ sub collect_remote_data }); $test_file = $target_directory."/hosts"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -532,7 +532,7 @@ sub collect_remote_data }); $test_file = $target_directory."/anvil.log"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; } @@ -570,7 +570,7 @@ sub collect_remote_data }); my $test_file = $target_directory."/cib.xml"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { test_file => $test_file }}); - if (not -e $test_file) + if (-e $test_file) { print "Done.\n"; }