diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 3e7617be..3618d0dd 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -2392,6 +2392,7 @@ sub get_anvil_uuid_from_string } } + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0466", variables => { string => $anvil }}); return(""); } diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index 9d82781e..6004c131 100644 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -1272,6 +1272,10 @@ C<< Note >>: By design, servers are set to 'undefined' on subnodes, so when the Parameters; +=head3 anvil (optional, name or uuid) + +If set, it restricts the search for a server to a specific Anvil! (and DR hosts, if protected). This will improve search performance on systems with nodes or DR hosts that are offline. + =head3 server_name (required) This is the name of the server being located. It can be set to C<< all >>, in which case all servers on all hosts are located. @@ -1285,9 +1289,11 @@ sub locate my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Server->locate()" }}); - my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : ""; + my $anvil_string = defined $parameter->{anvil} ? $parameter->{anvil} : ""; + my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - server_name => $server_name, + anvil_string => $anvil_string, + server_name => $server_name, }}); if (not $server_name) @@ -1296,6 +1302,24 @@ sub locate return('!!error!!'); } + my $anvil_uuid = ""; + my $anvil_name = ""; + if ($anvil_string) + { + $anvil_uuid = $anvil->Database->get_anvil_uuid_from_string({ + debug => $debug, + string => $anvil_string, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_uuid => $anvil_uuid }}); + if (not $anvil_uuid) + { + # Anvil! not found. Will be logged in Database->get_anvil_uuid_from_string(). + return('!!error!!'); + } + $anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_name => $anvil_name }}); + } + if (exists $anvil->data->{server_location}{host}) { delete $anvil->data->{server_location}{host}; @@ -1307,6 +1331,38 @@ sub locate # Connect to all hosts. $anvil->Database->get_hosts({debug => $debug}); + if ($anvil_uuid) + { + my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; + my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; + + $anvil->data->{host_search}{$node1_host_uuid}{short_host_name} = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{short_host_name}; + $anvil->data->{host_search}{$node2_host_uuid}{short_host_name} = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{short_host_name}; + + # Add DR hosts, if any. + if (exists $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}) + { + foreach my $host_uuid (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}}) + { + $anvil->data->{host_search}{$host_uuid}{short_host_name} = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name}; + } + } + + # Log the hosts we'll search (alphabetically). + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}}) + { + my $host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name}; + if (exists $anvil->data->{host_search}{$host_uuid}) + { + # Searching this + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:host_name' => $host_name, + 's2:host_uuid' => $host_uuid, + }}); + } + } + } + foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}}) { my $host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name}; @@ -1320,6 +1376,15 @@ sub locate }}); next if $host_type eq "striker"; + if ($anvil_uuid) + { + # Skip if this isn't a host we're searching. + if (not exists $anvil->data->{host_search}{$host_uuid}) + { + next; + } + } + # This will switch to '1' if we connect to libvirtd. $anvil->data->{server_location}{host}{$short_host_name}{access} = 0; @@ -1934,6 +1999,7 @@ sub parse_definition source => $source, definition => $definition, host => $host, + target => $target, }}); if (not $target) @@ -1983,6 +2049,9 @@ sub parse_definition } $anvil->data->{server}{$target}{$server}{$source}{parsed} = $server_xml; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => { + "server::${target}::${server}::${source}::parsed" => $anvil->data->{server}{$target}{$server}{$source}{parsed}, + }}); # Get the DRBD data that this server will almost certainly be using. $anvil->DRBD->get_devices({ @@ -2851,6 +2920,15 @@ sub update_definition return('!!error!!'); } + # Find where the server exists. + my $anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }}); + $anvil->Server->locate({ + debug => $debug, + server_name => $server_name, + anvil => $anvil_uuid, + }); + # Validate the new XML my $short_host_name = $anvil->Get->short_host_name(); my $problem = $anvil->Server->parse_definition({ @@ -2885,7 +2963,6 @@ sub update_definition } # Prep our variables. - my $anvil_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid}; my $definition_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_uuid}; my $db_definition_xml = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml}; my $node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid}; @@ -2893,7 +2970,6 @@ sub update_definition my $node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid}; my $node2_host_name = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{host_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - anvil_uuid => $anvil_uuid, definition_uuid => $definition_uuid, db_definition_xml => $db_definition_xml, node1_host_uuid => $node1_host_uuid, @@ -2937,29 +3013,29 @@ sub update_definition foreach my $host_uuid (@{$hosts}) { # Find a target_ip (local will be detected as local in the file read/write) - my $target_ip = $anvil->Network->find_target_ip({ + my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name}; + my $target_ip = $anvil->Network->find_target_ip({ debug => 2, host_uuid => $host_uuid, test_access => 1, networks => "bcn,mn,sn,ifn,any", }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + target_ip => $target_ip, + short_host_name => $short_host_name, + }}); if ($target_ip) { - # Read the old definition. - my $old_definition_xml = $anvil->Storage->read_file({ - debug => $debug, - file => $definition_file, - target => $target_ip, - }); + # The definition was read by Server->locate, so we can use it. + my $old_definition_xml = defined $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{file_definition} ? $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{file_definition} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { old_definition_xml => $old_definition_xml }}); + ### TODO: Handle when the definition file simply doesn't exist. if ((not $old_definition_xml) or ($old_definition_xml eq "!!error!!") or ($old_definition_xml !~ /data->{hosts}{host_uuid}{$host_uuid}{host_name}; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "warning_0163", variables => { server_name => $server_name, - host_name => $host_name, + host_name => $short_host_name, file => $definition_file, }}); } @@ -2993,10 +3069,39 @@ sub update_definition }}); } } + + # If the server is defined, update that also. + if ((exists $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{inactive_definition}) && + ($anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{inactive_definition})) + { + # This will always differ, so just update. + my $problem = $anvil->Server->connect_to_libvirt({ + debug => $debug, + target => $short_host_name, + target_ip => $target_ip, + server_name => $server_name, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + if (not $problem) + { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "libvirtd::${short_host_name}::connection" => $anvil->data->{libvirtd}{$short_host_name}{connection}, + }}); + + # Define the server + eval { $anvil->data->{libvirtd}{$short_host_name}{connection}->define_domain($new_definition_xml); }; + if ($@) + { + # Throw an error, then clear the URI so that we just update the DB/on-disk definitions. + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0166", variables => { + host_name => $short_host_name, + server_name => $server_name, + error => $@, + }}); + } + } + } } - - # If the server running or defined here? - } } diff --git a/share/words.xml b/share/words.xml index 5600ecd1..aba0d9c7 100644 --- a/share/words.xml +++ b/share/words.xml @@ -734,6 +734,7 @@ The XML that failed sanity check was: ======== ]]> + @@ -3955,6 +3956,11 @@ We will try to proceed anyway. + Failed to update the in-memory definition for the server: [#!variable!server_name!#] on the host: [#!variable!host_name!#]. The error, if any, was: +==== +#!variable!error!# +==== + diff --git a/tools/anvil-manage-server-system b/tools/anvil-manage-server-system index d1502c4a..2ef5ba8f 100755 --- a/tools/anvil-manage-server-system +++ b/tools/anvil-manage-server-system @@ -133,94 +133,6 @@ $anvil->nice_exit({exit_code => 0}); # Functions # ############################################################################################################# -sub connect_to_libvirt -{ - my ($anvil) = @_; - - my $short_host_name = $anvil->Get->short_host_name; - my $host_uuid = $anvil->Get->host_uuid; - my $server_name = $anvil->data->{switches}{server_name}; - my $server_uuid = $anvil->data->{switches}{server_uuid}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 's1:short_host_name' => $short_host_name, - 's2:host_uuid' => $host_uuid, - 's3:server_name' => $server_name, - 's4:server_uuid' => $server_uuid, - }}); - - my $from_source = get_definition_source($anvil); - my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - from_source => $from_source, - server_state => $server_state, - }}); - - # We'll make changes to the DB and on-disk definitions if the server isn't running. If it is, we'll - # update the live system as well. - my $uri = ""; - if ($server_state eq "running") - { - if ($server_uuid eq $anvil->Get->host_uuid) - { - ### NOTE: Don't use 'localhost', Sys::Virt translates it to '::1' which Net::OpenSSH - ### breaks on. - # Connect to the local libvirtd API, and handle problems if not. - $uri = "qemu+ssh://".$short_host_name."/system"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uri => $uri }}); - } - else - { - my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid}; - my $server_host_name = $anvil->Database->get_host_from_uuid({ - short => 1, - host_uuid => $server_host_uuid, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_host_name => $server_host_name }}); - - my $target_ip = $anvil->Network->find_target_ip({ - debug => 2, - host_uuid => $server_host_uuid, - test_access => 1, - networks => "bcn,mn,sn,ifn,any", - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }}); - if ($target_ip) - { - # Connect using this URI - $uri = "qemu+ssh://".$target_ip."/system"; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uri => $uri }}); - } - } - } - - my $connection = ""; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uri => $uri }}); - eval { $connection = Sys::Virt->new(uri => $uri); }; - if ($@) - { - # Throw an error, then clear the URI so that we just update the DB/on-disk definitions. - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0162", variables => { - host_name => $short_host_name, - uri => $uri, - error => $@, - }}); - return(1); - } - - my $domain = ""; - my @domains = $connection->list_all_domains(); - foreach my $domain_handle (@domains) - { - my $this_server_name = $domain_handle->get_name; - next if $this_server_name ne $server_name; - - $domain = $domain_handle; - last; - } - - return($domain); -} - sub manage_boot_menu { my ($anvil) = @_; @@ -230,6 +142,7 @@ sub manage_boot_menu my $server_name = $anvil->data->{switches}{server_name}; my $server_uuid = $anvil->data->{switches}{server_uuid}; my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_uuid}; + my $server_host_name = ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 's1:short_host_name' => $short_host_name, 's2:host_uuid' => $host_uuid, @@ -238,20 +151,19 @@ sub manage_boot_menu 's5:server_host_uuid' => $server_host_uuid, }}); - my $domain_handle = connect_to_libvirt($anvil); - my $from_source = get_definition_source($anvil); - my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state}; + my $from_source = get_definition_source($anvil); + my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - domain_handle => $domain_handle, from_source => $from_source, server_state => $server_state, }}); if ($server_state eq "running") { - my $server_host_name = $anvil->Database->get_host_from_uuid({ + $server_host_name = $anvil->Database->get_host_from_uuid({ short => 1, host_uuid => $server_host_uuid, }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_host_name => $server_host_name }}); } my $say_yes = $anvil->Words->string({key => 'unit_0001'}); @@ -265,8 +177,12 @@ sub manage_boot_menu new_boot_menu => $new_boot_menu, }}); - if (($anvil->data->{switches}{'boot-menu'} eq "yes") or ($anvil->data->{switches}{'boot-menu'} eq "no")) + if ((lc($anvil->data->{switches}{'boot-menu'}) eq "yes") or (lc($anvil->data->{switches}{'boot-menu'}) eq "no")) { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + "servers::server_uuid::${server_uuid}::server_definition_xml" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml}, + }}); + # We need to rewrite the boot menu manually. my $new_definition = ""; my $in_os = 0; @@ -314,11 +230,35 @@ sub manage_boot_menu new_definition_xml => $new_definition, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }}); + + # Reload and parse from the DB to confirm things are updated. + delete $anvil->data->{servers}{server_uuid}{$server_uuid}; + $anvil->Database->get_servers(); + my $server_definition_xml = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_definition_xml => $server_definition_xml }}); + + undef $anvil->data->{server}{$short_host_name}{$server_name}{from_db}; + $anvil->Server->parse_definition({ + debug => 2, + host => $short_host_name, + server => $server_name, + source => "from_db", + definition => $server_definition_xml, + }); + + my $new_boot_menu = lc($anvil->data->{server}{$short_host_name}{$server_name}{from_db}{info}{boot_menu}); + my $say_new_boot_menu = $new_boot_menu eq "yes" ? $say_yes : $say_no; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + new_boot_menu => $new_boot_menu, + say_new_boot_menu => $say_new_boot_menu, + }}); + print "Boot Menu enabled now: [".$say_new_boot_menu."]\n"; + print "- The boot menu has been updated.\n"; } else { print "Boot Menu enabled: [".$say_old_boot_menu."]\n"; - print "- You can change this using '--boot-menu off' or '--boot-menu on'.\n"; + print "- You can change this using '--boot-menu yes' or '--boot-menu no'.\n"; } return(0);