#!/usr/bin/perl # # This is called when striker, a node or a DR host needs to configure the local network and user accounts. # # Exit codes; # 0 = Normal exit. # 1 = The program is not running as root. # 2 = Failed to connect to database(s). # 3 = Job was already picked up by another running instance. # 4 = The host name did not update properly. # 5 = Failed to write the temp file with the new password needed to call anvil-change-password. # 6 = The job-uuid was not found. # 7 = The host is an active cluster member. # 8 = Duplicate NICs assigned to the same MAC address # # TODO: # - Add MTU support # - Check to see if this is a cluster node and/or running VMs, and if so, refuse to run. # use strict; use warnings; use Anvil::Tools; use Data::Dumper; use Text::Diff; 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 => [ "job-uuid", "debug", ], man => $THIS_FILE}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}}); if (($anvil->data->{switches}{debug}) && (not -e $anvil->data->{path}{configs}{'anvil.debug'})) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, key => "log_0843", variables => { file => $anvil->data->{path}{configs}{'anvil.debug'}, host => $anvil->Get->short_host_name(), }}); my $problem = $anvil->Storage->write_file({ file => $anvil->data->{path}{configs}{'anvil.debug'}, body => "", overwrite => 1, user => "root", group => "root", mode => "0666", }); } # Make sure we're running as 'root' # $< == real UID, $> == effective UID if (($< != 0) && ($> != 0)) { # Not root $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0005"}); $anvil->nice_exit({exit_code => 1}); } # Make sure that we set the network->wait_on_network() timeout to 60 seconds. $anvil->Storage->update_config({ append => 1, variable => "network::wait_on_network::timeout", value => 60, }); # Because we're working with the network config, we can't reliable use cached connections. $anvil->data->{sys}{net}{always_reconnect} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 1, list => { "sys::net::always_reconnect" => $anvil->data->{sys}{net}{always_reconnect}, }}); # Connect $anvil->Database->connect({check_for_resync => 1}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "message_0031"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0132"}); if (not $anvil->data->{sys}{database}{connections}) { # No databases, exit. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0003"}); $anvil->nice_exit({exit_code => 2}); } pickup_job_details($anvil); overwrite_variables_with_switches($anvil); # Set maintenance mode #$anvil->System->maintenance_mode({set => 1}); # Reconfigure the network. reconfigure_network($anvil); # Record that we've configured this machine. $anvil->Database->insert_or_update_variables({ variable_name => "system::configured", variable_value => 1, variable_default => "", variable_description => "striker_0048", variable_section => "system", variable_source_uuid => $anvil->data->{sys}{host_uuid}, variable_source_table => "hosts", }); update_passwords($anvil); $anvil->Job->update_progress({ progress => 100, message => "", job_uuid => $anvil->data->{job}{uuid}, }); # Make sure that we set the network->wait_on_network() timeout back to 180. $anvil->Storage->update_config({ append => 1, variable => "network::wait_on_network::timeout", value => 180, }); # Clear maintenance mode. $anvil->System->maintenance_mode({set => 0}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0467"}); $anvil->nice_exit({exit_code => 0}); ############################################################################################################# # Functions # ############################################################################################################# # This does a reboot. sub do_reboot { my ($anvil) = @_; # Tell the user why we're rebooting $anvil->Job->update_progress({ 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({steps => 1}), 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; $time_left -= 10; } # Last, log that we're going down now. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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 }}); my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }}); return(0); } # This updates the passwords on the root user, admin user, database and striker-ui-api user. sub update_passwords { my ($anvil) = @_; # Have we been asked to set a password? $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->{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 }}); # Write the password into a temporary file. my $error = $anvil->Storage->write_file({ body => $password, file => $temp_file, group => "root", mode => "0600", overwrite => 1, secure => 1, user => "root", }); # Call anvil-change-password if ($error) { # Couldn't write the temp file. $anvil->Job->update_progress({ progress => 100, message => "message_0030", log_level => 1, '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}); } else { my $wait_until = time + 120; my $waiting = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting, wait_until => $wait_until, }}); while ($waiting) { my $shell_call = $anvil->data->{path}{exe}{'anvil-change-password'}." -y --password-file ".$temp_file.$anvil->Log->switches; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }}); my ($output, $return_code) = $anvil->System->call({ debug => 2, timeout => 30, shell_call => $shell_call }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); if ($return_code) { # Something went wrong if (time > $wait_until) { # Give up. $waiting = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); } else { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0011", variables => { return_code => $return_code }}); } } else { # Success $waiting = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); } } # Unlink the temp file. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0263", variables => { file => $temp_file }}); unlink $temp_file; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0283"}); } } $anvil->Job->update_progress({ progress => 95, job_uuid => $anvil->data->{job}{uuid}, }); return(0); } # This does the work of reconfiguring the network sub reconfigure_network { my ($anvil) = @_; my $local_host = $anvil->Get->short_host_name(); my $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, domain => $domain, organization => $organization, bcn_count => $bcn_count, sn_count => $sn_count, mn_count => $mn_count, ifn_count => $ifn_count, new_host_name => $new_host_name, type => $type, }}); # If we're configuring a dashboard and no host name was given, generate it. if (($type eq "striker") && (not $new_host_name)) { $new_host_name = $prefix."-striker".sprintf("%02d", $sequence).".".$domain; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_host_name => $new_host_name }}); } if ($new_host_name) { my $type_name = ""; if ($type eq "striker") { $type_name = $anvil->Words->string({key => "brand_0003"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type_name => $type_name }}); } elsif ($type eq "node") { $type_name = $anvil->Words->string({key => "brand_0007"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type_name => $type_name }}); } elsif ($type eq "dr") { $type_name = $anvil->Words->string({key => "brand_0008"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type_name => $type_name }}); } my $pretty_host_name = $new_host_name; if (($organization) && ($sequence)) { $pretty_host_name = $organization." - ".$type_name." ".sprintf("%02d", $sequence); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { pretty_host_name => $pretty_host_name }}); } # Set the host_name my ($host_name, $descriptive_host_name) = $anvil->System->host_name({set => $new_host_name, pretty => $pretty_host_name}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { host_name => $host_name, descriptive_host_name => $descriptive_host_name, }}); if ($host_name eq $new_host_name) { # Success $anvil->Job->update_progress({ progress => $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 }, }); } else { # Failed $anvil->Job->update_progress({ progress => 100, message => "message_0017", 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, bad_host_name => $host_name, }, }); $anvil->nice_exit({exit_code => 4}); } } # 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 }}); for (my $i = 0; $i < @{$dns}; $i++) { $dns->[$i] = $anvil->Words->clean_spaces({ string => $dns->[$i] }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "dns->[$i]" => $dns->[$i] }}); } my $gateway = $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, }}); # If there is no default gateway device, and one of the interfaces are set to DHCP, use it. if (not $gateway_interface) { # IFN first, BCN second, SN last foreach my $network_type ("ifn", "bcn", "sn", "mn") { $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) { 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->{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 }}); last; } } } } # Before we continue, see if there's two interfaces pointing at the same NIC. If so, the node would # endlessly reboot. my $macs = {}; my $query = " SELECT variable_uuid, variable_name, variable_value FROM variables WHERE variable_name LIKE '\%_mac_to_set::value' AND variable_source_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ORDER BY variable_name ASC;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $variable_uuid = $row->[0]; my $variable_name = $row->[1]; my $variable_value = $row->[2]; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:variable_uuid' => $variable_uuid, 's2:variable_name' => $variable_name, 's3:variable_value' => $variable_value, }}); # An undefined interface will have the MAC address value set to '1', ignore those. next if $variable_value eq "1"; if ($variable_name =~ /form::config_step2::(.*?)_mac_to_set::value/) { my $device = lc($1); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device}}); if (not exists $macs->{$variable_value}) { $macs->{$variable_value} = $device; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "macs->${variable_value}" => $macs->{$variable_value}, }}); } else { # Fail out! $anvil->Job->update_progress({ progress => 100, message => "error_0376", job_status => "failed", 'print' => 1, log_level => 1, file => $THIS_FILE, line => __LINE__, variables => { mac_address => $variable_value, iface1 => $macs->{$variable_value}, iface2 => $device, }, }); $anvil->nice_exit({exit_code => 8}); } } } # 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, start => 1}); # 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 }}); # 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. $anvil->data->{sys}{restart_nm} = 0; reconfigure_bonds($anvil); reconfigure_bridges($anvil); reconfigure_ip_addresses($anvil); # Sleep a few seconds, and then restart NetworkManager.service. my $nm_running = $anvil->System->check_daemon({debug => 2, daemon => "NetworkManager.service"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_running => $nm_running, 'sys::restart_nm' => $anvil->data->{sys}{restart_nm}, }}); if (($anvil->data->{sys}{restart_nm}) or (not $nm_running)) { $anvil->System->stop_daemon({debug => 2, daemon => "NetworkManager.service"}); $anvil->System->start_daemon({debug => 2, daemon => "NetworkManager.service"}); sleep 2; } # Reconnect! if ($host_type ne "striker") { my $time_now = time; my $restart_nm_time = $time_now + 30; my $wait_until = $time_now + 60; my $nm_restarted = 0; my $waiting = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:time_now' => $time_now, 's2:restart_nm_time' => $restart_nm_time, 's3:wait_until' => $wait_until, }}); while ($waiting) { $anvil->refresh(); $anvil->Database->connect(); $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) { if (($now_time > $restart_nm_time) && (not $nm_restarted)) { # Kick the network $nm_restarted = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_restarted => $nm_restarted }}); # Restart the daemon $anvil->System->stop_daemon({debug => 2, daemon => "NetworkManager.service"}); $anvil->System->start_daemon({debug => 2, daemon => "NetworkManager.service"}); } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0829", variables => { time_left => $time_left }}); sleep 2; } else { # Give up and reboot. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "warning_0169"}); # Don't use 'do_reboot()' as we've got no DB connection. my $shell_call = $anvil->data->{path}{exe}{systemctl}." reboot"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { shell_call => $shell_call }}); # We should be dead by now... my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call, source => $THIS_FILE, line => __LINE__}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }}); } } } $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. my $start = 0; my $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 => { shell_call => $shell_call }}); my ($bridges, $return_code) = $anvil->System->call({shell_call => $shell_call}); $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 => $anvil->Job->bump_progress({steps => 1}), job_uuid => $anvil->data->{job}{uuid}, }); return(0); } sub reconfigure_bridges { my ($anvil) = @_; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0853"}); 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 => 1}), 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 => 1}), message => "message_0401", log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, file => $THIS_FILE, line => __LINE__, variables => {}, }); } else { # If there are ifcfg files for this bridge, move it. 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") { 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({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 }}); 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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. $anvil->data->{sys}{restart_nm} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::restart_nm' => $anvil->data->{sys}{restart_nm} }}); 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 => 1}), 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({uuid => $bridge_uuid, variable => "ipv4.method", value => "disabled"}); ($output, $return_code) = $anvil->Network->modify_connection({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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. $anvil->data->{sys}{restart_nm} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::restart_nm' => $anvil->data->{sys}{restart_nm} }}); } # Rescan. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, file => $THIS_FILE, line => __LINE__, variables => { }, }); $anvil->Network->collect_data(); } # Checking that the device is connected to this bridge $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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 => 1}), 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 => 1}), 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 => 1}), 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 => 1}), 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({uuid => $on_device_uuid, variable => "ipv4.method", value => "disabled"}); ($output, $return_code) = $anvil->Network->modify_connection({uuid => $on_device_uuid, variable => "ipv6.method", value => "disabled"}); # Connect it now. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. $anvil->data->{sys}{restart_nm} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::restart_nm' => $anvil->data->{sys}{restart_nm} }}); 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 => 1}), 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({uuid => $on_device_uuid}); # Rescan. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, file => $THIS_FILE, line => __LINE__, variables => { }, }); $anvil->Network->collect_data(); } } return(0); } sub reconfigure_bonds { my ($anvil) = @_; 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. $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. 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 => { 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 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({ progress => $anvil->Job->bump_progress({steps => 1}), 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({steps => 1}), 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} }, }); } else { # It doesn't, create it. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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, link1_mac => $link1_mac, link1_nm_uuid => $link1_nm_uuid, link2_name => $link2_name, link2_mac => $link2_mac, link2_nm_uuid => $link2_nm_uuid, }, }); # If there are ifcfg files for this bond, move it. 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") { 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({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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); 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 }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. $anvil->data->{sys}{restart_nm} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::restart_nm' => $anvil->data->{sys}{restart_nm} }}); sleep 2; if ($bond_uuid) { # Disabling DHCP on the new bond device $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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({uuid => $bond_uuid, variable => "ipv4.method", value => "disabled"}); ($output, $return_code) = $anvil->Network->modify_connection({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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. $anvil->data->{sys}{restart_nm} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::restart_nm' => $anvil->data->{sys}{restart_nm} }}); sleep 2; } # Done! Rescanning the network config $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0394", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, file => $THIS_FILE, line => __LINE__, }); $anvil->Network->collect_data(); } # 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}; 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, }}); 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 => 1}), message => "message_0395", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, file => $THIS_FILE, line => __LINE__, variables => { link_name => $link_device ? $link_device : $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 => 1}), message => "message_0396", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, file => $THIS_FILE, line => __LINE__, variables => { link_name => $link_device ? $link_device : $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 => 1}), message => "message_0397", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, file => $THIS_FILE, line => __LINE__, variables => { link_name => $link_device ? $link_device : $link_name, nm_uuid => $nm_uuid, }, }); } # Disabling DHCP on the interface $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0408", log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, file => $THIS_FILE, line => __LINE__, variables => { device => $link_device ? $link_device : $link_name, device_uuid => $nm_uuid, }, }); my ($output, $return_code) = $anvil->Network->modify_connection({uuid => $nm_uuid, variable => "ipv4.method", value => "disabled"}); ($output, $return_code) = $anvil->Network->modify_connection({uuid => $nm_uuid, variable => "ipv6.method", value => "disabled"}); # Connecting the interface to the bond $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0399", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, file => $THIS_FILE, line => __LINE__, variables => { link_name => $link_device ? $link_device : $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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. $anvil->data->{sys}{restart_nm} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::restart_nm' => $anvil->data->{sys}{restart_nm} }}); sleep 2; 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_device ? $link_device : $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 => 1}), message => "message_0403", log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, file => $THIS_FILE, line => __LINE__, variables => { device => $link_device ? $link_device : $link_name, device_uuid => $nm_uuid, }, }); ($output, $return_code) = $anvil->Network->reset_connection({uuid => $nm_uuid}); # Rescan. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { nm_uuid => $nm_uuid }}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { i => $i }}); } $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_type => $network_type }}); } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0852"}); return(0); } sub wait_for_nm { my ($anvil, $bond_name) = @_; my $found = 0; my $waiting = 1; my $wait_until = time + 30; while ($waiting) { my $shell_call = $anvil->data->{path}{exe}{nmcli}." connection show | ".$anvil->data->{path}{exe}{'grep'}." -c ".$bond_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 ($output eq "0") { if (time > $wait_until) { # Give up. $waiting = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }}); } # Not found yet. sleep 2; } else { # Found it. $found = 0; $waiting = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found, waiting => $waiting, }}); } } return($found); } 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 => 1}), 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 => 1}), 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 => 1}), 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 => 1}), 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 => 1}), 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 => 1}), 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 => 1}), 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 => 1}), 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 => 1}), 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({uuid => $old_uuid, variable => "ipv4.method", value => "disabled"}); ($output, $return_code) = $anvil->Network->modify_connection({uuid => $old_uuid, variable => "ipv6.method", value => "disabled"}); $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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({uuid => $old_uuid}); # NM seems to have a race issue, so we sleep a second after nmcli calls. $anvil->data->{sys}{restart_nm} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::restart_nm' => $anvil->data->{sys}{restart_nm} }}); sleep 2; } # 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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. $anvil->data->{sys}{restart_nm} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'sys::restart_nm' => $anvil->data->{sys}{restart_nm} }}); sleep 2; # Restart the interface $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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({uuid => $on_device_uuid}); # Rescan. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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_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: 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 $connection_autoconnect = $anvil->data->{nmcli}{uuid}{$uuid}{'connection.autoconnect'} // ""; 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:connection_autoconnect' => $connection_autoconnect, 's7:active' => $active, }}); ### NOTE: I don't think this is needed, but here's the code in case we change our mind. if (0) { # Try activating it. if ((not $general_ip_iface) && (not $active)) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, 'print' => 1, key => "log_0842", variables => { id => $connection_id, uuid => $uuid, }}); my $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 }}); 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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. sleep 2; # Rescan. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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}; 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 $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 => { i => $i, link1_mac_key => $link1_mac_key, 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}; 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"; 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 => { wanted_link1_name => $wanted_link1_name, wanted_link1_mac => $wanted_link1_mac, wanted_link2_name => $wanted_link2_name, wanted_link2_mac => $wanted_link2_mac, }}); # 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 }}); # Are the link(s) already configured? my $configure_link1 = 0; my $configure_link2 = 0; # Get the Network Manager UUIDs. 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 }}); # In case the GENERAL.IP-IFACE or GENERAL.NAME name didn't update, # map this interface name to 'nmcli::interface::::uuid'. if (not exists $anvil->data->{nmcli}{interface}{$interface}) { $anvil->data->{nmcli}{interface}{$interface}{uuid} = $link1_nm_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "nmcli::interface::${interface}::uuid" => $anvil->data->{nmcli}{interface}{$interface}{uuid}, }}); } if ($interface eq $wanted_link1_name) { $found = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); } } if (not $found) { $configure_link1 = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { configure_link1 => $configure_link1 }}); } # Make sure that the autoconnect is enabled. if ($anvil->data->{nmcli}{uuid}{$link1_nm_uuid}{'connection.autoconnect'} ne "yes") { my ($output, $return_code) = $anvil->Network->modify_connection({uuid => $link1_nm_uuid, variable => "connection.autoconnect", value => "yes"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); } } else { # We're dead. $anvil->Job->update_progress({ progress => 100, message => "error_0480", log_level => 1, 'print' => 1, job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", variables => { mac_address => $wanted_link1_mac, interface_name => $wanted_link1_name, }, }); $anvil->nice_exit({exit_code => 1}); } $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 ($link2_nm_uuid) { my $found = 0; my $match_interface_name = $anvil->data->{nmcli}{uuid}{$link2_nm_uuid}{'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 }}); } # Make sure that the autoconnect is enabled. if ($anvil->data->{nmcli}{uuid}{$link2_nm_uuid}{'connection.autoconnect'} ne "yes") { my ($output, $return_code) = $anvil->Network->modify_connection({uuid => $link2_nm_uuid, variable => "connection.autoconnect", value => "yes"}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); } } else { $anvil->Job->update_progress({ progress => 100, message => "error_0480", 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, interface_name => $wanted_link2_name, }, }); $anvil->nice_exit({exit_code => 1}); } $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. $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}, }}); } } } # 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}) { do_reboot($anvil); } 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, }}); # Tell the user what we're about to rename $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0383", log_level => 1, 'print' => 1, file => $THIS_FILE, line => __LINE__, 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, }, }); # If there are ifcfg files for this device, move them. 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") { 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({file => $file}); unlink $file; } } } # 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({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) { # Updating the udev file $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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'} }, }); 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) { # Failed to write the udev file $anvil->Job->update_progress({ progress => 100, 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'} }, }); $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) { # Removing the old 'connection.interface-name' $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0385", log_level => 1, 'print' => 1, file => $THIS_FILE, line => __LINE__, 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}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. sleep 2; $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) { # Failed to delete the 'connection.interface-name', This should have been blank $anvil->Job->update_progress({ progress => 100, 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 }, }); $anvil->nice_exit({exit_code => 1}); } } # 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 }}); $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0386", 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, }, }); if ($old_device eq $wanted_link_name) { # 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."\""; $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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. sleep 2; # 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 $anvil->Job->update_progress({ progress => 100, message => "error_0482", log_level => 1, '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, 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 => 1}), message => "message_0387", log_level => 1, 'print' => 1, file => $THIS_FILE, line => __LINE__, 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, }}); # NM seems to have a race issue, so we sleep a second after nmcli calls. sleep 2; # 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->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), 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. $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); } # This will pick up the job, or exit. sub pickup_job_details { my ($anvil) = @_; # If this returns '1', the job-uuid was bad. If it returns '2', another process is running. my $return = $anvil->Job->get_job_details({ check => 1, job_uuid => $anvil->data->{switches}{'job-uuid'}, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'return' => $return }}); if ($return == 1) { # It's not a valid UUID. $anvil->nice_exit({exit_code => 6}); } if ($return == 2) { # This job is being handled by another process that is still alive. $anvil->nice_exit({exit_code => 3}); } # Still alive? Good. my $job_picked_up_by = $anvil->data->{jobs}{job_picked_up_by}; my $job_progress = $anvil->data->{jobs}{job_progress}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_picked_up_by => $job_picked_up_by, job_progress => $job_progress, }}); # See if the job was picked up by another running instance. if ($job_picked_up_by) { # The previous job is gone if we're still alive, we'll take this over. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 'print' => 1, key => "log_0147", variables => { pid => $job_picked_up_by, percent => $job_progress, }}); } ### 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 variable_name, variable_value FROM variables WHERE variable_name LIKE 'form::config_step%' AND variable_source_table = 'hosts' AND variable_source_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ;"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); my $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { results => $results, count => $count, }}); foreach my $row (@{$results}) { my $this_variable = $row->[0]; my $this_value = $row->[1]; my $secure = $this_variable =~ /passw/ ? 1 : 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:this_variable' => $this_variable, 's2:this_value' => $anvil->Log->is_secure($this_value), }}); $anvil->_make_hash_reference($anvil->data->{variables}, $this_variable, $this_value); } ### 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}) { if ($line =~ /^(form::config_step[^\s]+)=(.*?)$/) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'job_data::variable_name' => $1, 'job_data::variable_value' => $anvil->Log->is_secure($2), }}); $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 $anvil->Job->update_progress({ progress => 0, message => "clear", job_uuid => $anvil->data->{job}{uuid}, }); # Record that we've picked up this job. $anvil->Job->update_progress({ progress => $anvil->Job->bump_progress({steps => 1}), message => "message_0015", job_uuid => $anvil->data->{job}{uuid}, 'print' => 1, log_level => 1, file => $THIS_FILE, line => __LINE__, }); # If we're in a cluster, abort. if (-e $anvil->data->{path}{exe}{pcs}) { # To make logs more sensible, we'll call 'problem' as 'out_of_cluster'. $anvil->data->{cib}{parsed}{'local'}{ready} = "" if not defined $anvil->data->{cib}{parsed}{'local'}{ready}; my ($out_of_cluster) = $anvil->Cluster->parse_cib(); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { out_of_cluster => $out_of_cluster, "cib::parsed::local::ready" => defined $anvil->data->{cib}{parsed}{'local'}{ready} ? $anvil->data->{cib}{parsed}{'local'}{ready} : "", }}); if ((not $out_of_cluster) && ($anvil->data->{cib}{parsed}{'local'}{ready})) { # We're in a cluster, abort. $anvil->Job->update_progress({ progress => 100, message => "error_0250", job_uuid => $anvil->data->{job}{uuid}, job_status => "failed", 'print' => 1, log_level => 1, file => $THIS_FILE, line => __LINE__, }); $anvil->nice_exit({exit_code => 7}); } } return(0); } sub overwrite_variables_with_switches { my ($anvil) = @_; if (not defined $anvil->data->{variables}) { $anvil->data->{variables} = {}; } foreach my $switch_name (keys %{$anvil->data->{switches}}) { my $switch_value = $anvil->data->{switches}{$switch_name}; if ($switch_name =~ /^form::config_step[^\s]+$/) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'switches::variable_name' => $switch_name, 'switches::variable_value' => $anvil->Log->is_secure($switch_value), }}); $anvil->_make_hash_reference($anvil->data->{variables}, $switch_name, $switch_value); } } return(0); }