From d26a16e711232eaaab1993da58d26a5121851fcc Mon Sep 17 00:00:00 2001 From: Digimer Date: Tue, 10 May 2022 00:42:40 -0400 Subject: [PATCH] * Updated anvil-provision-server to handle human-readable sizes for disk and ram. * Updated Database->get_anvils() to make it possible to translate a file name to a file UUID. * Updated System->test_ipmi() to quote passwords properly. Also dropped the timeouts to 2 seconds. * Updated anvil-provision-server to support pure CLI switch server provisioning using the --ci-test (and optional --options {--machine}) to allow CI tests. * Continued work of anvil-manage-server. * Fixed a bug in striker-prep-database to fix a bug in writing the pg_hba.conf file. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 14 +- Anvil/Tools/System.pm | 5 +- scancore-agents/scan-server/scan-server | 4 + tools/anvil-manage-server | 937 ++++++++++++++++++++++-- tools/anvil-provision-server | 449 ++++++++++-- tools/anvil-test-alerts | 0 tools/striker-prep-database | 2 +- 7 files changed, 1276 insertions(+), 135 deletions(-) create mode 100755 tools/anvil-test-alerts diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index efbe20bf..3464e7c8 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -2711,11 +2711,15 @@ WHERE next if not $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active}; my $file_uuid = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_file_uuid}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_uuid => $file_uuid }}); + my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + file_uuid => $file_uuid, + file_name => $file_name, + }}); # If the file was deleted, this won't exist next if not exists $anvil->data->{files}{file_uuid}{$file_uuid}; - $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_name} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; + $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_name} = $file_name; $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_directory} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_directory}; $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_size}; $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_md5sum} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_md5sum}; @@ -2727,6 +2731,12 @@ WHERE "anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_md5sum" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_md5sum}, "anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_type" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type}, }}); + + # Make it so that we can list the files by name. + $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid} = $file_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "anvils::anvil_uuid::${anvil_uuid}::file_name::${file_name}::file_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid}, + }}); } } diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index fe8d6aec..f5270f50 100644 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -4955,7 +4955,7 @@ sub test_ipmi next if $test_password eq ""; # Build the shell call. - $shell_call = $anvil->data->{path}{directories}{fence_agents}."/fence_ipmilan ".$lanplus_switch." --ip ".$ipmi_target." --username ".$ipmi_user." --password ".$test_password." --action status"; + $shell_call = $anvil->data->{path}{directories}{fence_agents}."/fence_ipmilan ".$lanplus_switch." --ip ".$ipmi_target." --username ".$ipmi_user." --password \"".$test_password."\" --action status"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { shell_call => $shell_call }}); my $output = ""; @@ -4967,7 +4967,7 @@ sub test_ipmi ($output, my $error, $return_code) = $anvil->Remote->call({ debug => $debug, secure => 1, - timeout => 30, + timeout => 2, shell_call => $shell_call, target => $target, password => $password, @@ -4984,6 +4984,7 @@ sub test_ipmi ($output, $return_code) = $anvil->System->call({ debug => $debug, secure => 1, + timeout => 2, shell_call => $shell_call, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { diff --git a/scancore-agents/scan-server/scan-server b/scancore-agents/scan-server/scan-server index 3ed01f5c..76fc5702 100755 --- a/scancore-agents/scan-server/scan-server +++ b/scancore-agents/scan-server/scan-server @@ -11,6 +11,10 @@ # 1 = Startup failure (not running as root, no DB, bad file read, etc) # 2 = libvirtd is not running. # +# BUG: +# - Check that an update on disk is not overwritten by the old config still being in memory for a still- +# running VM (specifically, RAM updates) +# # TODO: # - Move location constraints to the host node if the server is not on the preferred host (this happens after # recovering from a node loss). diff --git a/tools/anvil-manage-server b/tools/anvil-manage-server index 975a8cdf..cbf57c0f 100755 --- a/tools/anvil-manage-server +++ b/tools/anvil-manage-server @@ -15,6 +15,7 @@ use warnings; use Anvil::Tools; require POSIX; use Term::Cap; +use Data::Dumper; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; @@ -97,6 +98,7 @@ else $anvil->data->{new_config}{cpu}{sockets} = ""; $anvil->data->{new_config}{cpu}{cores} = ""; $anvil->data->{new_config}{ram}{'bytes'} = ""; + $anvil->data->{old_config}{ram}{'bytes'} = ""; interactive_question($anvil); } @@ -511,10 +513,10 @@ sub interactive_question if ($anvil->data->{target_server}{disk}{$target}{boot_order}) { - my $boot_order = $anvil->data->{target_server}{disk}{$target}{boot_order}; - $anvil->data->{target_server}{boot}{$boot_order}{$target} = $anvil->data->{target_server}{disk}{$target}{path}; + my $boot_order = $anvil->data->{target_server}{disk}{$target}{boot_order}; + $anvil->data->{target_server}{boot_order}{$boot_order} = $target; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "target_server::boot::${boot_order}::${target}" => $anvil->data->{target_server}{boot}{$boot_order}{$target}, + "target_server::boot_order::${boot_order}::${target}" => $anvil->data->{target_server}{boot_order}{$boot_order}, }}); } } @@ -534,10 +536,10 @@ sub interactive_question if ($anvil->data->{target_server}{cdrom}{$target}{boot_order}) { - my $boot_order = $anvil->data->{target_server}{cdrom}{$target}{boot_order}; - $anvil->data->{target_server}{boot}{$boot_order}{$target} = $anvil->data->{target_server}{cdrom}{$target}{path}; + my $boot_order = $anvil->data->{target_server}{cdrom}{$target}{boot_order}; + $anvil->data->{target_server}{boot_order}{$boot_order} = $target; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "target_server::boot::${boot_order}::${target}" => $anvil->data->{target_server}{boot}{$boot_order}{$target}, + "target_server::boot_order::${boot_order}::${target}" => $anvil->data->{target_server}{boot_order}{$boot_order}, }}); } } @@ -634,9 +636,11 @@ sub interactive_configure_main anvil_name => $anvil->data->{target_server}{anvil_name}, server_name => $anvil->data->{target_server}{server_name}, }})."\n"; - my $changes = 0; - my $cpu_star = ""; - my $ram_star = ""; + + my $changes = 0; + my $cpu_star = ""; + my $ram_star = ""; + my $storage_star = ""; if (($anvil->data->{new_config}{cpu}{sockets}) or ($anvil->data->{new_config}{cpu}{cores})) { $cpu_star = "*"; @@ -655,10 +659,41 @@ sub interactive_configure_main changes => $changes, }}); } + if (exists $anvil->data->{new_config}{storage_group_data}) + { + foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{new_config}{storage_group_data}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::new_drive_size" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}, + }}); + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}) + { + $storage_star = "*"; + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + storage_star => $storage_star, + changes => $changes, + }}); + } + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target => $target }}); + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}) + { + $storage_star = "*"; + $changes = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + storage_star => $storage_star, + changes => $changes, + }}); + } + } + } + } print "[ 1 ] - CPU".$cpu_star."\n"; print "[ 2 ] - RAM".$ram_star."\n"; - print "[ 3 ] - Storage\n"; + print "[ 3 ] - Storage".$storage_star."\n"; print "[ 4 ] - Network\n"; print "[ 5 ] - Boot Order\n"; print "[ 6 ] - Cluster Management\n"; @@ -667,13 +702,64 @@ sub interactive_configure_main print "[ Q ] - Quit\n"; if ($changes) { + if (($anvil->data->{new_config}{cpu}{sockets}) or ($anvil->data->{new_config}{cpu}{cores})) + { + $changes++; + my $say_old_cpu = $anvil->data->{old_config}{cpu}{sockets}." socket(s), ".$anvil->data->{old_config}{cpu}{cores}." core(s)"; + my $say_new_cpu = $anvil->data->{new_config}{cpu}{sockets}." socket(s), ".$anvil->data->{new_config}{cpu}{cores}." core(s)"; + print " - Change CPU from: [".$say_old_cpu."] to: [".$say_new_cpu."]\n"; + } + if ($anvil->data->{new_config}{ram}{'bytes'}) + { + $changes++; + my $say_old_ram = $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old_config}{ram}{'bytes'}}); + my $say_new_ram = $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{new_config}{ram}{'bytes'}}); + print " - Change RAM from: [".$say_old_ram."] to: [".$say_new_ram."]\n"; + } + if (exists $anvil->data->{new_config}{storage_group_data}) + { + foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{new_config}{storage_group_data}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::new_drive_size" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}, + }}); + + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size} =~ /new:(\d+)$/) + { + my $say_new_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $1}); + $changes++; + print " - Create a new drive that is: [".$say_new_size."] large.\n"; + } + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::target::${target}::changes" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}, + }}); + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} =~ /grow:(\d+)$/) + { + my $say_new_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $1}); + my $say_old_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size}}); + $changes++; + print " - Grow: [".$storage_group_name."/".$target."] from: [".$say_old_size."] to: [".$say_new_size."]\n"; + } + elsif ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} eq "delete") + { + my $say_old_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size}}); + $changes++; + print " - Delete: [".$storage_group_name."/".$target."], freeing up: [".$say_old_size."].\n"; + } + } + } + } + print "[ S ] - Save and commit the changes.\n"; } print "\n"; - print $terminal->Tgoto('cm', 0, (9+$changes))."? "; + print $terminal->Tgoto('cm', 0, (10+$changes))."? "; my $answer = ; chomp $answer; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); if ($answer eq "1") { @@ -709,11 +795,6 @@ sub interactive_configure_main $anvil->data->{switches}{server} = ""; interactive_ask_server_name($anvil, $terminal); } - elsif (lc($answer) eq "q") - { - print "NO CARRIER, good bye.\n"; - $anvil->nice_exit({exit_code => 0}); - } elsif (lc($answer) eq "s") { # Confirm changes @@ -769,16 +850,13 @@ sub interactive_configure_storage { my ($anvil, $terminal) = @_; - # Get the - $anvil->Database->get_storage_group_data({debug => 2}); while(1) { # Here, we'll list each storage pool and for each indicate if it's used and, if so - my $index = 1; - my $lines = 2; - my $changes = 0; - my $storage_group_selection = []; - push @{$storage_group_selection}, "NULL"; + $anvil->Database->get_storage_group_data(); + my $index = 1; + my $lines = 2; + my $changes = ""; print $terminal->Tputs('cl'); print $anvil->Words->string({key => "job_0355", variables => { @@ -803,14 +881,36 @@ sub interactive_configure_storage 's6:available_on_dr' => $free_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $available_on_dr}).")", }}); - my $paths = {}; + # Store the SG options so we can pull up the details when a user selects one to work + # with + $anvil->data->{storage_group_data}{$index}{name} = $storage_group_name; + $anvil->data->{storage_group_data}{$index}{uuid} = $storage_group_uuid; + $anvil->data->{storage_group_data}{$index}{size} = $vg_size; + $anvil->data->{storage_group_data}{$index}{free} = $free_size; + $anvil->data->{storage_group_data}{$index}{used} = $vg_size - $free_size; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:storage_group_data::${index}::name" => $anvil->data->{storage_group_data}{$index}{name}, + "s2:storage_group_data::${index}::uuid" => $anvil->data->{storage_group_data}{$index}{uuid}, + "s3:storage_group_data::${index}::size" => $anvil->data->{storage_group_data}{$index}{size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{storage_group_data}{$index}{size}}).")", + "s4:storage_group_data::${index}::free" => $anvil->data->{storage_group_data}{$index}{free}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{storage_group_data}{$index}{free}}).")", + "s5:storage_group_data::${index}::used" => $anvil->data->{storage_group_data}{$index}{used}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{storage_group_data}{$index}{used}}).")", + }}); + + if (not exists $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}) + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::new_drive_size" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}, + }}); + } + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{target_server}{disk}}) { my $device_bus = $anvil->data->{target_server}{disk}{$target}{device_bus}; my $cache = $anvil->data->{target_server}{disk}{$target}{cache}; my $io = $anvil->data->{target_server}{disk}{$target}{io}; my $this_path = $anvil->data->{target_server}{disk}{$target}{path}; - my $boot_order = $anvil->data->{target_server}{disk}{$target}{boot_order} ? $anvil->data->{target_server}{disk}{$target}{boot_order} : "--"; + my $boot_order = $anvil->data->{target_server}{disk}{$target}{boot_order} ? $anvil->data->{target_server}{disk}{$target}{boot_order} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target => $target, device_bus => $device_bus, @@ -829,31 +929,34 @@ sub interactive_configure_storage if (($this_storage_group_uuid) && ($storage_group_uuid eq $this_storage_group_uuid)) { - $paths->{$target}{path} = $this_path; - $paths->{$target}{boot_order} = $boot_order; + $anvil->data->{storage_group_data}{$index}{target}{$target}{path} = $this_path; + $anvil->data->{storage_group_data}{$index}{target}{$target}{boot_order} = $boot_order; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - "s1:paths->{".$target."}{path}" => $paths->{$target}{path}, - "s2:paths->{".$target."}{boot_order}" => $paths->{$target}{boot_order}, + "s1:storage_group_data::${index}::target::${target}::path" => $anvil->data->{storage_group_data}{$index}{target}{$target}{path}, + "s2:storage_group_data::${index}::target::${target}::boot_order" => $anvil->data->{storage_group_data}{$index}{target}{$target}{boot_order}, }}); + + if (not exists $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}) + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} = ""; + } + $changes = $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} ? "*" : ""; } } $lines += 2; - print "[ ".$index." ] - Name: \"".$storage_group_name."\" - Size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $vg_size})."], Free: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $free_size})."]\n"; + print "[ ".$index." ] - Name: \"".$storage_group_name."\" - Size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $vg_size})."], Free: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $free_size})."]".$changes."\n"; - my $path_count = keys %{$paths}; + my $path_count = keys %{$anvil->data->{storage_group_data}{$index}{target}}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { path_count => $path_count }}); if ($path_count) { - foreach my $target (sort {$a cmp $b} keys %{$paths}) + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{storage_group_data}{$index}{target}}) { - my $path = $paths->{$target}{path}; - my $boot_order = $paths->{$target}{boot_order}; - my $size = $anvil->Storage->get_size_of_block_device({ - debug => 2, - path => $path, - }); - my $say_size = ""; + my $path = $anvil->data->{storage_group_data}{$index}{target}{$target}{path}; + my $boot_order = $anvil->data->{storage_group_data}{$index}{target}{$target}{boot_order}; + my $size = $anvil->Storage->get_size_of_block_device({path => $path}); + my $say_size = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { size => $size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $size}).")", }}); @@ -865,16 +968,399 @@ sub interactive_configure_storage { $say_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $size}) } + print " - Target: [".$target."], boot order: [".$boot_order."], backed by: [".$path."], Size: [".$say_size."]\n"; $lines++; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { lines => $lines }}); + + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}) + { + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} =~ /grow:(\d+)$/) + { + my $new_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $1}); + $lines++; + print " - Will grow to: [".$new_size."]\n"; + } + elsif ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} eq "delete") + { + $lines++; + print " - Marked for deletion!\n"; + } + } } } else { - print " - \n"; + print " - \n"; + } + + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size} =~ /new:(\d+)/) + { + print " - New drive will be created that is: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $1})."] large.\n"; + $lines++; + } + $index++; + } + + # Optical drives + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{target_server}{cdrom}}) + { + $anvil->data->{optical_drives}{$index}{target} = $target; + $anvil->data->{optical_drives}{$index}{device_bus} = $anvil->data->{target_server}{cdrom}{$target}{device_bus}; + $anvil->data->{optical_drives}{$index}{boot_order} = $anvil->data->{target_server}{cdrom}{$target}{boot_order}; + $anvil->data->{optical_drives}{$index}{iso} = $anvil->data->{target_server}{cdrom}{$target}{path}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "optical_drives::${index}::target" => $anvil->data->{optical_drives}{$index}{target}, + "optical_drives::${index}::device_bus" => $anvil->data->{optical_drives}{$index}{device_bus}, + "optical_drives::${index}::boot_order" => $anvil->data->{optical_drives}{$index}{boot_order}, + "optical_drives::${index}::iso" => $anvil->data->{optical_drives}{$index}{iso}, + }}); + + my $say_disc = $anvil->data->{optical_drives}{$index}{iso} ? $anvil->data->{optical_drives}{$index}{iso} : ""; + print "[ ".$index." ] - Optical drive: [".$anvil->data->{optical_drives}{$index}{device_bus}."/".$target."], boot order: [".$anvil->data->{optical_drives}{$index}{boot_order}."], ISO: [".$say_disc."]\n"; + $index++; + $lines++; + } + + foreach my $boot_order (sort {$a <=> $b} keys %{$anvil->data->{target_server}{boot_order}}) + { + my $target = $anvil->data->{target_server}{boot_order}{$boot_order}; + my $path = exists $anvil->data->{target_server}{disk}{$target} ? $anvil->data->{target_server}{disk}{$target}{boot_order} : $anvil->data->{target_server}{cdrom}{$target}{path}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:boot_order" => $boot_order, + "s2:target" => $target, + "s3:path" => $path, + }}); + } + + print "\n"; + print "[ B ] - Back\n"; + print "[ Q ] - Quit\n"; + if ($changes) + { + print "- Changes can be committed on the main page.\n"; + print $terminal->Tgoto('cm', 0, ($lines+3))."? "; + } + else + { + print $terminal->Tgoto('cm', 0, ($lines+2))."? "; + } + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); + if ($answer =~ /^\d+$/) + { + if (exists $anvil->data->{storage_group_data}{$answer}) + { + interactive_configure_storage_group($anvil, $terminal, $answer); + } + elsif (exists $anvil->data->{optical_drives}{$index}) + { + interactive_configure_optical_disk($anvil, $terminal, $answer); + } + } + elsif (lc($answer) eq "b") + { + interactive_configure_main($anvil, $terminal); + } + } + + return(0); +} + +sub interactive_configure_optical_disk +{ + my ($anvil, $terminal, $index) = @_; + + while(1) + { + # This refreshes files as well. + $anvil->Database->get_anvils(); + + my $lines = 3; + my $target = $anvil->data->{optical_drives}{$index}{target}; + my $device_bus = $anvil->data->{optical_drives}{$index}{device_bus}; + my $boot_order = $anvil->data->{optical_drives}{$index}{boot_order}; + my $iso = $anvil->data->{optical_drives}{$index}{iso}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:target" => $target, + "s2:device_bus" => $device_bus, + "s3:boot_order" => $boot_order, + "s4:iso" => $iso, + }}); + + if (not exists $anvil->data->{new_config}{optical}{$target}) + { + $anvil->data->{new_config}{optical}{$target}{changes} = ""; + $anvil->data->{old_config}{optical}{$target}{disc} = $iso; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:new_config::optical::${target}::changes" => $anvil->data->{new_config}{optical}{$target}{changes}, + "s1:old_config::optical::${target}::disc" => $anvil->data->{old_config}{optical}{$target}{disc}, + }}); + } + if ($anvil->data->{new_config}{optical}{$target}{changes}) + { + $changes = 1; + } + + print $terminal->Tputs('cl'); + print $anvil->Words->string({key => "job_0355", variables => { + anvil_name => $anvil->data->{target_server}{anvil_name}, + server_name => $anvil->data->{target_server}{server_name}, + }})."\n"; + print "* Managing: [".$device_bus."/".$target."]\n"; + if ($iso) + { + print "[ E ] - Eject: [".$iso."]\n"; + if ($anvil->data->{new_config}{optical}{$target}{changes} eq "eject") + { + print " - To be ejected.\n"; + $lines++; + } + print "[ C ] - Change disc.\n"; + $lines += 2; + } + else + { + print "[ I ] - Insert ISO\n"; + $lines++; + } + + print "\n"; + print "[ B ] - Back\n"; + print "[ Q ] - Quit\n"; + if ($changes) + { + print "- Changes can be committed on the main page.\n"; + print $terminal->Tgoto('cm', 0, ($lines+3))."? "; + } + else + { + print $terminal->Tgoto('cm', 0, ($lines+2))."? "; + } + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); + if ((lc($answer) eq "e") && ($iso)) + { + $anvil->data->{new_config}{optical}{$target}{changes} = "eject"; + $anvil->data->{old_config}{optical}{$target}{disc} = $iso; + print "The disc: [".$iso."] will be ejected.\n"; + hold_for_input($anvil); + } + elsif ((lc($answer) eq "c") && (lc($answer) eq "i")) + { + my $file_uuid = pick_file($anvil, $terminal, $index); + if ($file_uuid) + { + my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name}; + $anvil->data->{new_config}{optical}{$target}{changes} = "insert:".$file_uuid; + if ($iso) + { + print "- Will replace the disc with: [".$file_name."].\n" + } + else + { + print "- Will insert the disc: [".$file_name."].\n"; + } + hold_for_input($anvil); + } + } + elsif (lc($answer) eq "b") + { + interactive_configure_storage($anvil, $terminal); + } + } + + return(0); +} + +sub pick_file +{ + my ($anvil, $terminal, $drive_index) = @_; + + my $file_uuid = ""; + my $anvil_uuid = $anvil->data->{target_server}{anvil_uuid}; + my $target = $anvil->data->{optical_drives}{$drive_index}{target}; + my $device_bus = $anvil->data->{optical_drives}{$drive_index}{device_bus}; + my $boot_order = $anvil->data->{optical_drives}{$drive_index}{boot_order}; + my $iso = $anvil->data->{optical_drives}{$drive_index}{iso}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:drive_index" => $drive_index, + "s2:anvil_uuid" => $anvil_uuid, + "s3:target" => $target, + "s4:device_bus" => $device_bus, + "s5:boot_order" => $boot_order, + "s6:iso" => $iso, + }}); + + while(1) + { + $anvil->Database->get_anvils(); + + print $terminal->Tputs('cl'); + print $anvil->Words->string({key => "job_0355", variables => { + anvil_name => $anvil->data->{target_server}{anvil_name}, + server_name => $anvil->data->{target_server}{server_name}, + }})."\n"; + + my $index = 1; + my $lines = 3; + + print "* What file do you want to insert into: [".$device_bus."/".$target."]?\n"; + foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}}) + { + my $file_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid}; + my $file_directory = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_directory}; + my $file_size = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}; + my $file_md5sum = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_md5sum}; + my $file_type = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:file_name" => $file_name, + "s2:file_uuid" => $file_uuid, + "s3:file_directory" => $file_directory, + "s4:file_size" => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")", + "s5:file_md5sum" => $file_md5sum, + "s6:file_type" => $file_type, + }}); + + next if $file_type ne "iso"; + print "[ ".$index."] - ".$file_name.", size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size})."], md5_sum: [".$file_md5sum."]\n"; + + $anvil->data->{iso_files}{$index}{file_uuid} = $file_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:iso_files::${index}::file_uuid" => $anvil->data->{iso_files}{$index}{file_uuid}, + }}); + } + + print "\n"; + print "[ B ] - Back\n"; + print "[ Q ] - Quit\n"; + print $terminal->Tgoto('cm', 0, ($lines+2))."? "; + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); + if (($answer =~ /^\d+$/) && (exists $anvil->data->{iso_files}{$answer})) + { + return($anvil->data->{iso_files}{$answer}{file_uuid}); + } + elsif (lc($answer) eq "b") + { + return(""); + } + } + + return(0); +} + +sub interactive_configure_storage_group +{ + my ($anvil, $terminal, $selected_sg) = @_; + + while(1) + { + $anvil->Database->get_storage_group_data(); + my $storage_group_name = $anvil->data->{storage_group_data}{$selected_sg}{name}; + my $storage_group_uuid = $anvil->data->{storage_group_data}{$selected_sg}{uuid}; + my $storage_group_size = $anvil->data->{storage_group_data}{$selected_sg}{size}; + my $storage_group_free = $anvil->data->{storage_group_data}{$selected_sg}{free}; + my $storage_group_used = $anvil->data->{storage_group_data}{$selected_sg}{used}; + my $say_max_free = $anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:storage_group_name" => $storage_group_name, + "s2:storage_group_uuid" => $storage_group_uuid, + "s3:storage_group_size" => $storage_group_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_size}).")", + "s4:storage_group_free" => $storage_group_free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}).")", + "s5:storage_group_used" => $storage_group_used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_used}).")", + "s6:say_max_free" => $say_max_free, + }}); + + print $terminal->Tputs('cl'); + print $anvil->Words->string({key => "job_0355", variables => { + anvil_name => $anvil->data->{target_server}{anvil_name}, + server_name => $anvil->data->{target_server}{server_name}, + }})."\n"; + + foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{new_config}{storage_group_data}}) + { + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}}) + { + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} =~ /grow:(\d+)$/) + { + my $added = $1 - $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size}; + $storage_group_used += $added; + $storage_group_free -= $added; + $say_max_free = $anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:added" => $added." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $added}).")", + "s2:storage_group_used" => $storage_group_used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_used}).")", + "s3:storage_group_free" => $storage_group_free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}).")", + "s4:say_max_free" => $say_max_free, + }}); + } + elsif ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} eq "delete") + { + my $old_size = $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size}; + $storage_group_used -= $old_size; + $storage_group_free -= $old_size; + $say_max_free = $anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:old_size" => $old_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_size}).")", + "s2:storage_group_used" => $storage_group_used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_used}).")", + "s3:storage_group_free" => $storage_group_free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}).")", + "s4:say_max_free" => $say_max_free, + }}); + } } + } + + my $changes = ""; + my $index = 1; + my $lines = 2; + my $drive = {}; + + print "* Storage Group: [".$storage_group_name."] configuration.\n"; + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{storage_group_data}{$selected_sg}{target}}) + { + my $path = $anvil->data->{storage_group_data}{$selected_sg}{target}{$target}{path}; + my $boot_order = $anvil->data->{storage_group_data}{$selected_sg}{target}{$target}{boot_order}; + my $size = $anvil->Storage->get_size_of_block_device({path => $path}); + my $say_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $size}); + + $drive->{$index} = $target; + + $changes = $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} ? "*" : ""; + print "[ ".$index." ] - Manage: [".$target."], boot order: [".$boot_order."], backed by: [".$path."], Size: [".$say_size."]".$changes."\n"; $index++; + $lines++; + if ($changes) + { + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} =~ /grow:(\d+)$/) + { + my $new_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $1}); + $lines++; + print " - Will grow to: [".$new_size."]\n"; + } + elsif ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} eq "delete") + { + $lines++; + print " - Marked for deletion!\n"; + + } + } + } + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}) + { + my $say_requested = ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size} =~ /new:(\d+)$/)[0]; + $say_requested = $anvil->Convert->bytes_to_human_readable({'bytes' => $say_requested}); + print "[ C ] - Cancel creation of new: [".$say_requested."] sized drive.\n"; + } + else + { + print "[ N ] - New Drive\n"; } print "\n"; @@ -892,6 +1378,329 @@ sub interactive_configure_storage my $answer = ; chomp $answer; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); + if (($answer =~ /^\d+$/) && (exists $drive->{$answer})) + { + my $target = $drive->{$answer}; + interactive_configure_storage_group_manage_drive($anvil, $terminal, $selected_sg, $target); + } + elsif (lc($answer) eq "n") + { + print "- How big would you like the new drive to be? Maximum is: [".$say_max_free."]\n"; + my $answer = ; + chomp $answer; + $answer =~ s/^\s+//; + $answer =~ s/\s+$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); + + if ($answer) + { + # Convert to bytes + my $requested_bytes = $answer; + if ($requested_bytes =~ /\D/) + { + $requested_bytes = $anvil->Convert->human_readable_to_bytes({ + base2 => 1, + size => $requested_bytes, + }); + if ($requested_bytes eq "!!error!!") + { + # Problem. + $requested_bytes = ""; + print "[ Error ] - The answer: [".$answer."] could not be interpretted as a size.\n"; + hold_for_input($anvil); + } + } + + if (($requested_bytes =~ /^\d+$/) && ($requested_bytes > $storage_group_free)) + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::new_drive_size" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}, + }}); + print "[ Error ] - You asked for: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $requested_bytes})."] (".$anvil->Convert->add_commas({number => $requested_bytes})." bytes), but the max available is: [".$say_max_free."] (".$anvil->Convert->add_commas({number => $storage_group_free})." bytes).\n"; + hold_for_input($anvil); + } + elsif ($requested_bytes) + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size} = "new:".$requested_bytes; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::new_drive_size" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}, + }}); + } + } + } + elsif ((lc($answer) eq "c") && ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size})) + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::new_drive_size" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}, + }}); + print "- New volume will NOT be created.\n"; + hold_for_input($anvil); + } + elsif (lc($answer) eq "b") + { + interactive_configure_storage($anvil, $terminal); + } + } + + return(0); +} + +sub interactive_configure_storage_group_manage_drive +{ + my ($anvil, $terminal, $selected_sg, $target) = @_; + + while(1) + { + $anvil->Database->get_storage_group_data(); + my $storage_group_name = $anvil->data->{storage_group_data}{$selected_sg}{name}; + my $storage_group_uuid = $anvil->data->{storage_group_data}{$selected_sg}{uuid}; + my $storage_group_size = $anvil->data->{storage_group_data}{$selected_sg}{size}; + my $storage_group_free = $anvil->data->{storage_group_data}{$selected_sg}{free}; + my $storage_group_used = $anvil->data->{storage_group_data}{$selected_sg}{used}; + my $path = $anvil->data->{storage_group_data}{$selected_sg}{target}{$target}{path}; + my $boot_order = $anvil->data->{storage_group_data}{$selected_sg}{target}{$target}{boot_order}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:selected_sg" => $selected_sg, + "s2:target" => $target, + "s3:storage_group_name" => $storage_group_name, + "s4:storage_group_uuid" => $storage_group_uuid, + "s5:storage_group_size" => $storage_group_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_size}).")", + "s6:storage_group_free" => $storage_group_free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}).")", + "s6:storage_group_used" => $storage_group_used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_used}).")", + "s7:path" => $path, + "s8:boot_order" => $boot_order, + }}); + + my $size = $anvil->Storage->get_size_of_block_device({path => $path}); + my $say_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $size}); + my $max_assignable = ($size + $storage_group_free); + my $say_max_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $max_assignable}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:size" => $size, + "s2:max_assignable" => $say_size, + "s3:say_max_size" => $say_max_size, + }}); + + foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{new_config}{storage_group_data}}) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::new_drive_size" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size}, + }}); + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{new_drive_size} =~ /new:(\d+)$/) + { + my $to_create = $1; + $storage_group_used += $to_create; + $storage_group_free -= $to_create; + $max_assignable = $size + $storage_group_free; + $say_max_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $max_assignable}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:to_create" => $to_create." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $to_create}).")", + "s2:storage_group_used" => $storage_group_used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_used}).")", + "s3:storage_group_free" => $storage_group_free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}).")", + "s4:max_assignable" => $max_assignable, + "s5:say_max_size" => $say_max_size, + }}); + } + foreach my $target (sort {$a cmp $b} keys %{$anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}}) + { + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} =~ /grow:(\d+)$/) + { + my $added = $1 - $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size}; + $storage_group_used += $added; + $storage_group_free -= $added; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:added" => $added." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $added}).")", + "s2:storage_group_used" => $storage_group_used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_used}).")", + "s3:storage_group_free" => $storage_group_free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}).")", + }}); + } + elsif ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} eq "delete") + { + my $old_size = $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size}; + $storage_group_used -= $old_size; + $storage_group_free += $old_size; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:old_size" => $old_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_size}).")", + "s2:storage_group_used" => $storage_group_used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_used}).")", + "s3:storage_group_free" => $storage_group_free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free}).")", + }}); + } + } + } + + my $say_new_max_size = $say_max_size; + my $new_max_assignable = $max_assignable; + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} =~ /grow:(\d+)$/) + { + # Add the space assigned to the max size + my $added = $1; + $max_assignable = ($size + $storage_group_free + $added); + $say_max_size = $anvil->Convert->bytes_to_human_readable({'bytes' => $max_assignable}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "s1:added" => $added." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $added}).")", + "s2:max_assignable" => $say_size, + "s3:say_max_size" => $say_max_size, + }}); + } + + print $terminal->Tputs('cl'); + print $anvil->Words->string({key => "job_0355", variables => { + anvil_name => $anvil->data->{target_server}{anvil_name}, + server_name => $anvil->data->{target_server}{server_name}, + }})."\n"; + + my $say_requested = ""; + my $say_delete = ""; + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}) + { + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} =~ /grow:(\d+)$/) + { + $say_requested = $anvil->Convert->bytes_to_human_readable({'bytes' => $1}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_requested => $say_requested }}); + } + } + my $changes = $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} ? "*" : " "; + print "* Manage: [".$target."], boot order: [".$boot_order."], backed by: [".$path."], Size: [".$say_size."]\n"; + print " - In storage Group: [".$storage_group_name."], Size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_size})."], Free space: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $storage_group_free})."].\n"; + print "[ G ] - Grow (Current size: [".$say_size."], Requested: [".$say_requested."], Max: [".$say_max_size."]".$changes."\n"; + if ($boot_order == 1) + { + print "[ - ] - .\n"; + } + else + { + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} eq "delete") + { + print "[ D ] - Abort Deletion (Currently scheduled for deletion!)\n"; + } + else + { + print "[ D ] - Delete\n"; + } + } + + print "\n"; + print "[ B ] - Back\n"; + print "[ Q ] - Quit\n"; + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}) + { + print "- Changes can be committed on the main page.\n"; + print $terminal->Tgoto('cm', 0, 9)."? "; + } + else + { + print $terminal->Tgoto('cm', 0, 8)."? "; + } + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); + if (lc($answer) eq "g") + { + my $say_new_max_size = $say_max_size; + my $new_max_assignable = $max_assignable; + # Ask what size they want. + print "- How big do you want the drive to be? You can enter up to: [".$say_max_size."];\n"; + my $answer = ; + chomp $answer; + $answer =~ s/^\s+//; + $answer =~ s/\s+$//; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); + if (not $answer) + { + # Go back + interactive_configure_storage_group_manage_drive($anvil, $terminal, $selected_sg, $target); + } + else + { + # Convert to bytes + my $requested_bytes = $answer; + if ($requested_bytes =~ /\D/) + { + $requested_bytes = $anvil->Convert->human_readable_to_bytes({ + base2 => 1, + size => $requested_bytes, + }); + if ($requested_bytes eq "!!error!!") + { + # Problem. + $requested_bytes = ""; + print "[ Error ] - The answer: [".$answer."] could not be interpretted as a size.\n"; + hold_for_input($anvil); + } + } + + if (($requested_bytes =~ /^\d+$/) && ($requested_bytes > $max_assignable)) + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} = ""; + print "[ Error ] - You asked for: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $requested_bytes})."] (".$anvil->Convert->add_commas({number => $requested_bytes})." bytes), but the max available is: [".$say_max_size."] (".$anvil->Convert->add_commas({number => $max_assignable})." bytes).\n"; + hold_for_input($anvil); + interactive_configure_storage_group_manage_drive($anvil, $terminal, $selected_sg, $target); + } + elsif ($requested_bytes) + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} = "grow:".$requested_bytes; + $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size} = $size; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::target::${target}::changes" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}, + "old_config::storage_group_data::${storage_group_name}::target::${target}::size" => $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size}, + }}); + } + } + } + if (lc($answer) eq "d") + { + if ($anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} eq "delete") + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} = ""; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::target::${target}::changes" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}, + }}); + } + else + { + $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes} = "delete"; + $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size} = $size; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + "new_config::storage_group_data::${storage_group_name}::target::${target}::changes" => $anvil->data->{new_config}{storage_group_data}{$storage_group_name}{target}{$target}{changes}, + "old_config::storage_group_data::${storage_group_name}::target::${target}::size" => $anvil->data->{old_config}{storage_group_data}{$storage_group_name}{target}{$target}{size}, + }}); + } + } + elsif (lc($answer) eq "b") + { + interactive_configure_storage_group($anvil, $terminal, $selected_sg); + } + } + + return(0); +} + +sub hold_for_input +{ + my ($anvil) = @_; + + my $answer = ; + chomp $answer; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); + + return(0); +} + +sub check_answer +{ + my ($anvil, $answer) = @_; + + if (lc($answer) eq "q") + { + print "NO CARRIER, good bye.\n"; + $anvil->nice_exit({exit_code => 0}); } return(0); @@ -935,6 +1744,7 @@ sub interactive_configure_ram ram_star => $ram_star, changes => $changes, }}); + $anvil->data->{old_config}{ram}{'bytes'} = $anvil->data->{target_server}{configured_ram}; } print $terminal->Tputs('cl'); @@ -960,6 +1770,7 @@ sub interactive_configure_ram my $answer = ; chomp $answer; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); if ($answer eq "1") { @@ -970,6 +1781,7 @@ sub interactive_configure_ram $answer =~ s/^\s+//; $answer =~ s/\s+$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); if (not $answer) { # Go back @@ -989,9 +1801,7 @@ sub interactive_configure_ram { # Problem. print "[ Error ] - The answer: [".$answer."] could not be interpretted.\n"; - my $answer = ; - chomp $answer; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + hold_for_input($anvil); interactive_configure_ram($anvil, $terminal); } } @@ -1004,9 +1814,7 @@ sub interactive_configure_ram { $anvil->data->{new_config}{ram}{'bytes'} = 0; print "[ Error ] - You asked for: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $requested_bytes})."] (".$anvil->Convert->add_commas({number => $max_assignable})." bytes) RAM, but the max available is: [".$say_max_assignable."] (".$anvil->Convert->add_commas({number => $max_assignable})." bytes).\n"; - my $answer = ; - chomp $answer; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + hold_for_input($anvil); interactive_configure_ram($anvil, $terminal); } else @@ -1022,11 +1830,6 @@ sub interactive_configure_ram { interactive_configure_main($anvil, $terminal); } - elsif (lc($answer) eq "q") - { - print "NO CARRIER, good bye.\n"; - $anvil->nice_exit({exit_code => 0}); - } else { interactive_configure_ram($anvil, $terminal); @@ -1062,16 +1865,18 @@ sub interactive_configure_cpu star_cores => $star_cores, changes => $changes, }}); + $anvil->data->{old_config}{cpu}{cores} = $anvil->data->{target_server}{server_cpu_cores}; } my $star_sockets = " "; if (($anvil->data->{new_config}{cpu}{sockets}) && ($anvil->data->{new_config}{cpu}{sockets} ne $anvil->data->{target_server}{server_cpu_sockets})) { $star_sockets = "*"; - $changes = 1; + $changes = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { star_sockets => $star_sockets, changes => $changes, }}); + $anvil->data->{old_config}{cpu}{sockets} = $anvil->data->{target_server}{server_cpu_sockets}; } print $terminal->Tputs('cl'); @@ -1098,6 +1903,7 @@ sub interactive_configure_cpu my $answer = ; chomp $answer; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); if ($answer eq "1") { @@ -1114,7 +1920,7 @@ sub interactive_configure_cpu { print "[ Error ] - The answer: [".$answer."] is not valid. You need to specify a digit.\n"; print "Press any key to continue.\n"; - my $answer = ; + hold_for_input($anvil); interactive_configure_cpu($anvil, $terminal); } else @@ -1146,7 +1952,7 @@ sub interactive_configure_cpu print " You may wish to reduce the socket count first.\n"; } print __LINE__."; Press any key to continue.\n"; - my $answer = ; + hold_for_input($anvil); interactive_configure_cpu($anvil, $terminal); } else @@ -1173,7 +1979,7 @@ sub interactive_configure_cpu { print "[ Error ] - The answer: [".$answer."] is not valid. You need to specify a digit.\n"; print "Press any key to continue.\n"; - my $answer = ; + hold_for_input($anvil); interactive_configure_cpu($anvil, $terminal); } else @@ -1193,7 +1999,7 @@ sub interactive_configure_cpu print " You may wish to reduce the core count first.\n"; } print __LINE__."; Press any key to continue.\n"; - my $answer = ; + hold_for_input($anvil); interactive_configure_cpu($anvil, $terminal); } elsif ((not $anvil->data->{new_config}{cpu}{cores}) && (($answer * $anvil->data->{target_server}{server_cpu_cores}) > $maximum_cores)) @@ -1205,7 +2011,7 @@ sub interactive_configure_cpu print " You may wish to reduce the core count first.\n"; } print __LINE__."; Press any key to continue.\n"; - my $answer = ; + hold_for_input($anvil); interactive_configure_cpu($anvil, $terminal); } else @@ -1221,11 +2027,6 @@ sub interactive_configure_cpu { interactive_configure_main($anvil, $terminal); } - elsif (lc($answer) eq "q") - { - print "NO CARRIER, good bye.\n"; - $anvil->nice_exit({exit_code => 0}); - } else { interactive_configure_cpu($anvil, $terminal); @@ -1307,6 +2108,7 @@ sub interactive_ask_anvil_name my $answer = ; chomp $answer; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); if ((not $answer) && ($default)) { @@ -1340,11 +2142,6 @@ sub interactive_ask_anvil_name }}); last; } - elsif (lc($answer) eq "q") - { - print "NO CARRIER, good bye.\n"; - $anvil->nice_exit({exit_code => 0}); - } else { $retry = 1; @@ -1443,6 +2240,7 @@ sub interactive_ask_server_name my $answer = ; chomp $answer; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { answer => $answer }}); + check_answer($anvil, $answer); if ((not $answer) && ($default)) { @@ -1481,11 +2279,6 @@ sub interactive_ask_server_name print "Going back\n"; interactive_ask_anvil_name($anvil, $terminal); } - elsif (lc($answer) eq "q") - { - print "NO CARRIER, good bye.\n"; - $anvil->nice_exit({exit_code => 0}); - } else { # Inalid. diff --git a/tools/anvil-provision-server b/tools/anvil-provision-server index 275bc711..04e2cd76 100755 --- a/tools/anvil-provision-server +++ b/tools/anvil-provision-server @@ -18,6 +18,7 @@ use warnings; use Anvil::Tools; require POSIX; use Term::Cap; +use Data::Dumper; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; @@ -36,10 +37,16 @@ my $anvil = Anvil::Tools->new(); $anvil->data->{switches}{anvil} = ""; $anvil->data->{switches}{'anvil-name'} = ""; $anvil->data->{switches}{'anvil-uuid'} = ""; -$anvil->data->{switches}{os} = ""; +$anvil->data->{switches}{'ci-test'} = ""; # If set, all we do is read the switches and submit the job +$anvil->data->{switches}{'driver-disc'} = ""; $anvil->data->{switches}{cpu} = ""; +$anvil->data->{switches}{'install-media'} = ""; $anvil->data->{switches}{'job-uuid'} = ""; +$anvil->data->{switches}{machine} = ""; $anvil->data->{switches}{name} = ""; +$anvil->data->{switches}{options} = ""; +$anvil->data->{switches}{os} = ""; +$anvil->data->{switches}{'pre-test'} = ""; $anvil->data->{switches}{uuid} = ""; $anvil->data->{switches}{ram} = ""; $anvil->data->{switches}{'storage-group'} = ""; @@ -51,10 +58,16 @@ $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list 'switches::anvil' => $anvil->data->{switches}{anvil}, 'switches::anvil-name' => $anvil->data->{switches}{'anvil-name'}, 'switches::anvil-uuid' => $anvil->data->{switches}{'anvil-uuid'}, - 'switches::os' => $anvil->data->{switches}{os}, + 'switches::ci-test' => $anvil->data->{switches}{'ci-test'}, + 'switches::driver-disc' => $anvil->data->{switches}{'driver-disc'}, 'switches::cpu' => $anvil->data->{switches}{cpu}, + 'switches::install-media' => $anvil->data->{switches}{'install-media'}, 'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'}, + 'switches::machine' => $anvil->data->{switches}{machine}, 'switches::name' => $anvil->data->{switches}{name}, + 'switches::options' => $anvil->data->{switches}{options}, + 'switches::os' => $anvil->data->{switches}{os}, + 'switches::pre-test' => $anvil->data->{switches}{'pre-test'}, 'switches::uuid' => $anvil->data->{switches}{uuid}, 'switches::ram' => $anvil->data->{switches}{ram}, 'switches::storage-group' => $anvil->data->{switches}{'storage-group'}, @@ -96,6 +109,10 @@ if ($anvil->data->{switches}{'job-uuid'}) # Job data will be in $anvil->data->{jobs}{job_data} run_jobs($anvil); } +elsif ($anvil->data->{switches}{'ci-test'}) +{ + interactive_ask_server_confirm($anvil, ""); +} else { # Interactive! @@ -1248,6 +1265,13 @@ sub parse_job_data { $anvil->data->{job}{ram} = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'job::ram' => $anvil->data->{job}{ram} }}); + + # If needed, convert the RAM to bytes. + if ($anvil->data->{job}{ram} =~ /\D/) + { + $anvil->data->{job}{ram} = $anvil->Convert->human_readable_to_bytes({debug => 2, size => $anvil->data->{job}{ram}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'job::ram' => $anvil->data->{job}{ram} }}); + } } if ($line =~ /storage_group_uuid=(.*)$/) { @@ -1258,6 +1282,13 @@ sub parse_job_data { $anvil->data->{job}{storage_size} = $1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'job::storage_size' => $anvil->data->{job}{storage_size} }}); + + # If needed, convert the disk size to bytes. + if ($anvil->data->{job}{storage_size} =~ /\D/) + { + $anvil->data->{job}{storage_size} = $anvil->Convert->human_readable_to_bytes({debug => 2, size => $anvil->data->{job}{storage_size}}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'job::storage_size' => $anvil->data->{job}{storage_size} }}); + } } if ($line =~ /install_iso=(.*)$/) { @@ -1514,12 +1545,10 @@ sub parse_job_data return(0); } -# Go through a series of questions to ask the user how they want to build their server. -sub interactive_question +sub check_anvil { my ($anvil) = @_; - # If 'switches::anvil' is set, see if it's a UUID and then set either 'anvil-uuid' or 'anvil-name'. if (($anvil->data->{switches}{anvil}) && (not $anvil->data->{switches}{'anvil-uuid'}) && (not $anvil->data->{switches}{'anvil-name'})) { if ($anvil->Validate->uuid({uuid => $anvil->data->{switches}{anvil}})) @@ -1569,6 +1598,17 @@ sub interactive_question $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "new_server::anvil_name" => $anvil->data->{new_server}{anvil_name} }}); } + return(0); +} + +# Go through a series of questions to ask the user how they want to build their server. +sub interactive_question +{ + my ($anvil) = @_; + + # Process the anvil switch + check_anvil($anvil); + $anvil->data->{new_server}{name} = $anvil->data->{switches}{name} ? $anvil->data->{switches}{name} : ""; $anvil->data->{new_server}{uuid} = $anvil->data->{switches}{uuid} ? $anvil->data->{switches}{uuid} : ""; @@ -2249,7 +2289,7 @@ sub interactive_ask_server_install_media my $install_isos = [""]; my $iso_list = ""; my $position = 0; - foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{files}{file_name}}) + foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}}) { my $file_uuid = $anvil->data->{files}{file_name}{$file_name}{file_uuid}; my $file_directory = $anvil->data->{files}{file_name}{$file_name}{file_directory}; @@ -2527,12 +2567,304 @@ sub interactive_ask_server_confirm { my ($anvil, $terminal) = @_; + # terminal isn't set with --ci-test set. + check_anvil($anvil); + $anvil->Database->get_anvils(); $anvil->Database->get_files(); $anvil->Database->get_file_locations(); + + if ($anvil->data->{switches}{'ci-test'}) + { + # Show available options; + # anvil-provision-server --ci-test --options + # Minimal Example; + # anvil-provision-server --ci-test --name srv01-test \ + # All options + # anvil-provision-server --ci-test --name srv01-test --uuid \ + + check_anvil($anvil); + if (not $anvil->data->{new_server}{anvil_uuid}) + { + # Instantly fatal + print "Missing '--anvil '\n"; + $anvil->nice_exit({exit_code => 1}); + } + + my $anvil_uuid = $anvil->data->{new_server}{anvil_uuid}; + $anvil->Get->available_resources({anvil_uuid => $anvil_uuid, debug => 2}); + + my $problem = 0; + if (not $anvil->data->{switches}{name}) + { + print "Missing '--name '\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + if (not $anvil->data->{switches}{os}) + { + print "Missing '--os ', valid options match 'virt-install --os-variant' (run: 'osinfo-query os' and reference the 'Short ID' column).\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + else + { + # Make sure it's valid. + my $os_key = "os_list_".$anvil->data->{switches}{os}; + my $os_name = $anvil->Words->string({key => $os_key}); + if ($os_name =~ /#!not_found/) + { + print "The OS: [".$anvil->data->{switches}{os}."] was not found. If you're sure the OS is valid, please run 'striker-parse-os-list --xml --new' and add the output to 'words.xml'.\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + } + if (not $anvil->data->{switches}{cpu}) + { + print "Missing '--cpu <1 ~ ".$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}.">'\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + elsif (($anvil->data->{switches}{cpu} =~ /\D/) or ($anvil->data->{switches}{cpu} > $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}) or ($anvil->data->{switches}{cpu} < 1)) + { + print "The number of CPU cores: [".$anvil->data->{switches}{cpu}."] is invalid. Must be between 1 and ".$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}.".\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + + my $max_ram = $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{available}; + my $say_max_ram = $anvil->Convert->bytes_to_human_readable({"bytes" => $max_ram}); + my $requested_ram = $anvil->Convert->human_readable_to_bytes({ + base2 => 1, + size => $anvil->data->{switches}{ram}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + max_ram => $max_ram, + say_max_ram => $say_max_ram, + requested_ram => $requested_ram, + }}); + if (not $anvil->data->{switches}{ram}) + { + print "Missing '--ram '\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + elsif (($requested_ram eq "!!error!!") or + (not $requested_ram) or + ($requested_ram < (640*1024)) or + ($requested_ram > $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{available})) + { + # Invalid + print "The requested RAM: [".$anvil->data->{switches}{ram}."] is not valid. Must be between: [64KiB] and: [".$say_max_ram."]\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + + my $max_storage_group_size = 0; + my $storage_group_uuid = ""; + if (not $anvil->data->{switches}{'storage-group'}) + { + print "Missing '--storage-group . Valid options are:'\n" if not $anvil->data->{switches}{options}; + foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}}) + { + print "- Name: [".$storage_group_name."], UUID: [".$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid}."]\n" if not $anvil->data->{switches}{options}; + } + $problem = 1; + } + else + { + # Make sure it's valid. + my $storage_group = $anvil->data->{switches}{'storage-group'}; + if (exists $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}{$storage_group}) + { + $storage_group_uuid = $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}{$storage_group}{storage_group_uuid}; + $max_storage_group_size = $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}; + } + elsif (exists $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group}) + { + $storage_group_uuid = $storage_group; + $max_storage_group_size = $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}; + } + else + { + # Invalid + print "- The requested storage group: [".$storage_group."] does not appear to be valid. Valid options are;\n" if not $anvil->data->{switches}{options}; + foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}}) + { + print "- Name: [".$storage_group_name."], UUID: [".$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid}."]\n" if not $anvil->data->{switches}{options}; + } + $problem = 1; + } + } + my $say_max_storage_group_size = $max_storage_group_size ? $anvil->Convert->bytes_to_human_readable({"bytes" => $max_storage_group_size}) : ""; + if (not $anvil->data->{switches}{'storage-size'}) + { + if ($max_storage_group_size) + { + print "Missing '--storage-size '\n" if not $anvil->data->{switches}{options}; + } + else + { + print "Missing '--storage-size . Max will depend on selected --storage-group.'\n" if not $anvil->data->{switches}{options}; + } + $problem = 1; + } + else + { + my $requested_disk = $anvil->Convert->human_readable_to_bytes({ + base2 => 1, + size => $anvil->data->{switches}{'storage-size'}, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { requested_disk => $requested_disk }}); + if (($requested_disk eq "!!error!!") or + ($requested_disk < (10*(2**20))) or + ($requested_disk > $max_storage_group_size)) + { + # Invalid + print "The requested disk size: [".$anvil->data->{switches}{'storage-size'}."] is not valid. Must be between: [10MiB] and: [".$say_max_storage_group_size."]\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + } + if ($anvil->Validate->uuid({uuid => $anvil->data->{switches}{uuid}})) + { + $anvil->data->{new_server}{uuid} = $anvil->data->{switches}{uuid}; + } + if (not $anvil->data->{switches}{'install-media'}) + { + print "Missing '--install-media '\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + else + { + # Make sure the file is valid + my $found = 0; + foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}}) + { + my $file_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid}; + my $file_type = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type}; + if ($file_name eq $anvil->data->{switches}{'install-media'}) + { + # Found it. + $found = 1; + if ($file_type eq "iso") + { + # We're good + $anvil->data->{new_server}{install_media} = $anvil->data->{switches}{'install-media'}; + } + else + { + # Not an ISO. + print "The install file: [".$anvil->data->{switches}{'install-media'}."] is not an ISO, so it can't be used to install.\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + } + last if $found; + } + if (not $found) + { + print "The install file: [".$anvil->data->{switches}{'install-media'}."] was not found on this Anvil!.\n" if not $anvil->data->{switches}{options}; + print "Is it in '/mnt/shared/files/' and are the daemons running?\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + } + if ($anvil->data->{switches}{'driver-disc'}) + { + # Make sure it exists + my $found = 0; + foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}}) + { + my $file_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid}; + my $file_type = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type}; + if ($file_name eq $anvil->data->{switches}{'driver-disc'}) + { + # Found it. + $found = 1; + if ($file_type eq "iso") + { + # We're good + $anvil->data->{new_server}{install_media} = $anvil->data->{switches}{'driver-disc'}; + } + else + { + # Not an ISO. + print "The driver file: [".$anvil->data->{switches}{'driver-disc'}."] is not an ISO, so it can't be used as an optical disc.\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + } + last if $found; + } + if (not $found) + { + print "The driver file: [".$anvil->data->{switches}{'driver-disc'}."] was not found on this Anvil!.\n" if not $anvil->data->{switches}{options}; + print "Is it in '/mnt/shared/files/' and are the daemons running?\n" if not $anvil->data->{switches}{options}; + $problem = 1; + } + } + if ($anvil->data->{switches}{options}) + { + if ($anvil->data->{switches}{machine}) + { + print "# Sizes are in bytes\n"; + print "ram:min=65536,max=".$max_ram."\n"; + print "cpu:min=1,max=".$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}."\n"; + foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}}) + { + my $storage_group_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid}; + print "storage_group:name=".$storage_group_name.",uuid=".$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid}.",free_space=".$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}."\n"; + } + foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}}) + { + my $file_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid}; + my $file_type = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type}; + my $file_size = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}; + next if $file_type ne "iso"; + my $say_size = $anvil->Convert->bytes_to_human_readable({"bytes" => $file_size}); + print "iso_file:name=".$file_name.",uuid=".$file_uuid.",size=".$say_size."\n"; + } + } + else + { + # Show valid options to build a VM in a machine-parsable way. + print "Available options + --name - alphanumeric, 1~16 characters long. + --os - Valid options; run: 'osinfo-query os' and reference the 'Short ID' column. + --cpu - 1 ~ ".$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}." + --ram - bytes or human readable, min is 64KiB, max is ".$say_max_ram." + --storage-group - name or uuid. Valid options are:\n"; + foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}}) + { + my $storage_group_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid}; + my $max_storage_group_size = $anvil->data->{anvil_resources}{$anvil_uuid}{storage_group}{$storage_group_uuid}{free_size}; + my $say_max_storage_group_size = $anvil->Convert->bytes_to_human_readable({"bytes" => $max_storage_group_size}); + print " - Name: [".$storage_group_name."], UUID: [".$anvil->data->{anvil_resources}{$anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid}."], free space: [".$say_max_storage_group_size."]\n"; + } + print " --storage-size - Disk size, see above for space available + --install-media - file name or file UUID. Available discs are:\n"; + foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}}) + { + my $file_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid}; + my $file_type = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type}; + my $file_size = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}; + next if $file_type ne "iso"; + my $say_size = $anvil->Convert->bytes_to_human_readable({"bytes" => $file_size}); + print " - File name: [".$file_name."], file UUID: [".$file_uuid."], size: [".$say_size."]\n"; + } + print " --driver-disc - (optional) A driver disc to be added as a second optical drive. Valid options are above.\n"; + } + $anvil->nice_exit({exit_code => 0}); + } + if ($problem) + { + $anvil->nice_exit({exit_code => 1}); + } + + # Save the values. + $anvil->data->{new_server}{name} = $anvil->data->{switches}{name}; + $anvil->data->{new_server}{os} = $anvil->data->{switches}{os}; + $anvil->data->{new_server}{cpu} = $anvil->data->{switches}{cpu}; + $anvil->data->{new_server}{ram} = $anvil->data->{switches}{ram}; + $anvil->data->{new_server}{storage_group} = $storage_group_uuid; + $anvil->data->{new_server}{storage_size} = $anvil->data->{switches}{'storage-size'}; + $anvil->data->{new_server}{install_media} = $anvil->data->{switches}{'install-media'}; + $anvil->data->{new_server}{driver_disc} = $anvil->data->{switches}{'driver-disc'}; + } + my $anvil_uuid = $anvil->data->{new_server}{anvil_uuid}; my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; - + my $storage_group_uuid = $anvil->data->{new_server}{storage_group}; my $say_ram = $anvil->Convert->bytes_to_human_readable({"bytes" => $anvil->data->{new_server}{ram}}); my $say_storage_group = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{group_name}; @@ -2542,27 +2874,34 @@ sub interactive_ask_server_confirm my $driver_disc_file_uuid = $anvil->data->{new_server}{driver_disc}; my $say_driver_disc = $driver_disc_file_uuid eq "none" ? "#!string!unit_0005!#" : $anvil->data->{files}{file_uuid}{$driver_disc_file_uuid}{file_name}; - print $terminal->Tputs('cl'); - print $anvil->Words->string({key => "job_0150"})."\n"; - print $anvil->Words->string({key => "job_0151", variables => { anvil_name => $anvil->data->{new_server}{anvil_name} }})."\n"; - print $anvil->Words->string({key => "job_0157", variables => { server_name => $anvil->data->{new_server}{name} }})."\n"; - print $anvil->Words->string({key => "job_0158", variables => { cpu_cores => $anvil->data->{new_server}{cpu} }})."\n"; - print $anvil->Words->string({key => "job_0165", variables => { ram => $say_ram }})."\n"; - print $anvil->Words->string({key => "job_0170", variables => { storage_group => $say_storage_group }})."\n"; - print $anvil->Words->string({key => "job_0173", variables => { storage_size => $say_storage_size }})."\n"; - print $anvil->Words->string({key => "job_0176", variables => { install_media => $say_install_media }})."\n"; - print $anvil->Words->string({key => "job_0180", variables => { driver_disc => $say_driver_disc }})."\n"; - print $anvil->Words->string({key => "job_0198", variables => { os => $anvil->data->{new_server}{say_os} }})."\n\n"; - print $anvil->Words->string({key => "message_0206"})." "; - my $answer = ; - chomp $answer; - - $answer = "y" if $answer eq ""; - - if ($answer =~ /^y/i) + if (not $anvil->data->{switches}{'ci-test'}) { - # Valid. - my $job_data = "server_name=".$anvil->data->{new_server}{name}." + print $terminal->Tputs('cl'); + print $anvil->Words->string({key => "job_0150"})."\n"; + print $anvil->Words->string({key => "job_0151", variables => { anvil_name => $anvil->data->{new_server}{anvil_name} }})."\n"; + print $anvil->Words->string({key => "job_0157", variables => { server_name => $anvil->data->{new_server}{name} }})."\n"; + print $anvil->Words->string({key => "job_0158", variables => { cpu_cores => $anvil->data->{new_server}{cpu} }})."\n"; + print $anvil->Words->string({key => "job_0165", variables => { ram => $say_ram }})."\n"; + print $anvil->Words->string({key => "job_0170", variables => { storage_group => $say_storage_group }})."\n"; + print $anvil->Words->string({key => "job_0173", variables => { storage_size => $say_storage_size }})."\n"; + print $anvil->Words->string({key => "job_0176", variables => { install_media => $say_install_media }})."\n"; + print $anvil->Words->string({key => "job_0180", variables => { driver_disc => $say_driver_disc }})."\n"; + print $anvil->Words->string({key => "job_0198", variables => { os => $anvil->data->{new_server}{say_os} }})."\n\n"; + print $anvil->Words->string({key => "message_0206"})." "; + my $answer = ; + chomp $answer; + + $answer = "y" if $answer eq ""; + + if ($answer !~ /^y/i) + { + # Abort + print $anvil->Words->string({key => "message_0022"})."\n"; + $anvil->nice_exit({exit_code => 0}); + } + } + + my $job_data = "server_name=".$anvil->data->{new_server}{name}." os=".$anvil->data->{new_server}{os}." cpu_cores=".$anvil->data->{new_server}{cpu}." ram=".$anvil->data->{new_server}{ram}." @@ -2570,40 +2909,34 @@ storage_group_uuid=".$anvil->data->{new_server}{storage_group}." storage_size=".$anvil->data->{new_server}{storage_size}." install_iso=".$anvil->data->{new_server}{install_media}." driver_iso=".$anvil->data->{new_server}{driver_disc}; - if ($anvil->data->{new_server}{uuid}) - { - $job_data .= " -server_uuid=".$anvil->data->{new_server}{name}; - } - print "\n".$anvil->Words->string({key => "job_0183", variables => { job_data => $job_data }})."\n"; - - # Register the job with the primary node on the Anvil! (or node 1, if neither node is primary). - my $target_host_uuid = $anvil->Cluster->get_primary_host_uuid({debug => 2, anvil_uuid => $anvil_uuid}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_host_uuid => $target_host_uuid }}); - if (not $target_host_uuid) - { - $target_host_uuid = $node1_host_uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_host_uuid => $target_host_uuid }}); - } - my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ - debug => 2, - job_command => $anvil->data->{path}{exe}{'anvil-provision-server'}.$anvil->Log->switches, - job_data => $job_data, - job_name => "server::provision", - job_title => "job_0147", - job_description => "job_0148", - job_progress => 0, - job_host_uuid => $target_host_uuid, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); - - print $anvil->Words->string({key => "job_0184", variables => { job_uuid => $job_uuid }})."\n"; + if ($anvil->data->{new_server}{uuid}) + { + $job_data .= " +server_uuid=".$anvil->data->{new_server}{uuid}; } - else + print "\n".$anvil->Words->string({key => "job_0183", variables => { job_data => $job_data }})."\n"; + + # Register the job with the primary node on the Anvil! (or node 1, if neither node is primary). + my $target_host_uuid = $anvil->Cluster->get_primary_host_uuid({debug => 2, anvil_uuid => $anvil_uuid}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_host_uuid => $target_host_uuid }}); + if (not $target_host_uuid) { - # Abort - print $anvil->Words->string({key => "message_0022"})."\n"; + $target_host_uuid = $node1_host_uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_host_uuid => $target_host_uuid }}); } + my ($job_uuid) = $anvil->Database->insert_or_update_jobs({ + debug => 2, + job_command => $anvil->data->{path}{exe}{'anvil-provision-server'}.$anvil->Log->switches, + job_data => $job_data, + job_name => "server::provision", + job_title => "job_0147", + job_description => "job_0148", + job_progress => 0, + job_host_uuid => $target_host_uuid, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }}); + + print $anvil->Words->string({key => "job_0184", variables => { job_uuid => $job_uuid }})."\n"; return(0); } diff --git a/tools/anvil-test-alerts b/tools/anvil-test-alerts new file mode 100755 index 00000000..e69de29b diff --git a/tools/striker-prep-database b/tools/striker-prep-database index 169b6246..68f48159 100755 --- a/tools/striker-prep-database +++ b/tools/striker-prep-database @@ -195,7 +195,7 @@ if ($local_uuid) foreach my $line (split/\n/, $pg_hba_conf) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); - if ($line =~ /^host\s+all\s+all\s+\all\s+md5$/) + if ($line =~ /^host\s+all\s+all\s+all\s+md5$/) { # No need to update. $update_file = 0;