From 55b1380031e2149758328688eb0fa01bd6fc2a80 Mon Sep 17 00:00:00 2001 From: digimer Date: Tue, 10 Oct 2023 19:14:00 -0400 Subject: [PATCH] Finished (but need more testing) of Server->locate(). This includes the changes in PR#492. Signed-off-by: digimer --- Anvil/Tools/Server.pm | 151 +++++++++++++++++++++++++---------------- share/words.xml | 1 + tools/anvil-join-anvil | 10 ++- 3 files changed, 103 insertions(+), 59 deletions(-) diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index 3ef87853..aa134fde 100644 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -1230,18 +1230,21 @@ sub map_network =head2 locate -B<< Note >>: This is meant to replace C<< Server->find >> and so the hash conflicts. +B<< Note >>: This is meant to replace C<< Server->find >>. -This walks through all known and accessible subnodes and DR hosts looking for a server. If it's found, it's status on that host are stored in the hash; +This walks through all known and accessible subnodes and DR hosts looking for a server. If a specific server is searched for and it's found running, the C<< short_host_name >> is returned. If there is a problem, C<< !!error!! >> is returned. + +If a specific requested server is found, or is being asked to search for all servers, the following data is stored; * server_location::host::::access = [0,1] * server_location::host::::server::::status = * server_location::host::::server::::active_definition = * server_location::host::::server::::inactive_definition = +* server_location::host::::server::::definition_diff = If the target was not accessible, C<< access >> is set to C<< 0 >>. This is meant to allow telling the difference between "we know there's no servers on that host" versus "we don't know what's there because we couldn't access it". -If the server is found to be C<< unknown >> or C<< shut off >>, then C<< inactive_definition >> is not set. In all other states, the inactive XML is stored, but often it's the same as the C<< active_definition >>, so the caller is suggested to diff the XMLs when it might be relevant. +If the server is found to be C<< running >> or C<< paused >>, then C<< active_definition >> is set and, if there's a difference, that will be stored. In all other states, the inactive XML is stored. The C<< status >> can be: @@ -1256,6 +1259,11 @@ The C<< status >> can be: If there is a problem, C<< !!error!! >> is returned. If the server is found on at least one host, C<< 0 >> is returned. If the server is not located anywhere, C<< 1 >> is returned. +The connection to the host and to the server(s) is cached, for your use; + +* server_location::host::::connection = +* server_location::host::::server::::connection = + C<< Note >>: By design, servers are set to 'undefined' on subnodes, so when the server shuts off, it disappears from libvirtd. This is normal and expected. Parameters; @@ -1273,15 +1281,15 @@ 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 = defined $parameter->{server} ? $parameter->{server} : ""; + my $server_name = defined $parameter->{server_name} ? $parameter->{server_name} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - server => $server, + server_name => $server_name, }}); - if (not $server) + if (not $server_name) { - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->locate()", parameter => "server" }}); - return(1); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->locate()", parameter => "server_name" }}); + return('!!error!!'); } if (exists $anvil->data->{server_location}{host}) @@ -1289,6 +1297,9 @@ sub locate delete $anvil->data->{server_location}{host}; } + # This will be set if the server is found to be 'running' on a host. + my $server_host = ""; + # Connect to all hosts. $anvil->Database->get_hosts({debug => $debug}); @@ -1296,7 +1307,7 @@ sub locate { my $host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name}; my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type}; - my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name} + my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 's1:host_name' => $host_name, 's2:host_uuid' => $host_uuid, @@ -1321,63 +1332,87 @@ sub locate { # Try to connect to libvirtd. my $problem = $anvil->Server->connect_to_libvirt({ - debug => $debug, - target => $short_host_name, - target_ip => $target_ip, - server => $server eq "all" ? "" : $server, + debug => $debug, + target => $short_host_name, + target_ip => $target_ip, + server_name => $server_name, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { problem => $problem }}); if (not $problem) { - # We're connected! If we had a specific server - $anvil->data->{libvirtd}{$short_host_name}{connection} + # We're connected! Collect the data on the requested server(s), if applicable. + $anvil->data->{server_location}{host}{$short_host_name}{access} = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "server_location::host::${short_host_name}::access" => $anvil->data->{server_location}{host}{$short_host_name}{access}, + }}); + + if ($server_name) + { + my $connection_handle = $anvil->data->{libvirtd}{$short_host_name}{connection}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { connection_handle => $connection_handle }}); + foreach my $this_server_name (sort {$a cmp $b} keys %{$anvil->data->{libvirtd}{$short_host_name}{server}}) + { + if (($server_name eq "all") or ($server_name eq $this_server_name)) + { + my $server_handle = $anvil->data->{libvirtd}{$short_host_name}{server}{$server_name}{connection}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_handle => $server_handle }}); + + # Get the server's state, then convert to a string + my ($state, $reason) = $server_handle->get_state(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 'state' => $state, + reason => $reason, + }}); + + ### Reasons are dependent on the state. + ### See: https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainShutdownReason + my $server_state = "unknown"; + if ($state == 1) { $server_state = "running"; } # Server is running. + elsif ($state == 2) { $server_state = "blocked"; } # Server is blocked (IO contention?). + elsif ($state == 3) { $server_state = "paused"; } # Server is paused (migration target?). + elsif ($state == 4) { $server_state = "in shutdown"; } # Server is shutting down. + elsif ($state == 5) { $server_state = "shut off"; } # Server is shut off. + elsif ($state == 6) { $server_state = "crashed"; } # Server is crashed! + elsif ($state == 7) { $server_state = "pmsuspended"; } # Server is suspended. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_state => $server_state }}); + + # Get the persistent definition + my $inactive_definition = $server_handle->get_xml_description(Sys::Virt::Domain::XML_INACTIVE); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { inactive_definition => $inactive_definition }}); + + # Get the active definition, if applicable. + my $active_definition = ""; + my $definition_diff = ""; + if (($server_state eq "running") or ($server_state eq "paused")) + { + # Get the active definition + $active_definition = $server_handle->get_xml_description(); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { active_definition => $active_definition }}); + + # Check for a diff. + $definition_diff = diff \$active_definition, \$inactive_definition, { STYLE => 'Unified' }; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { definition_diff => $definition_diff }}); + } + + # If it's running, record the host. + $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{status} = $server_state; + $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{active_definition} = $active_definition; + $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{inactive_definition} = $inactive_definition; + $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{definition_diff} = $definition_diff; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + "server_location::host::${short_host_name}::server::${server_name}::status" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{status}, + "server_location::host::${short_host_name}::server::${server_name}::active_definition" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{active_definition}, + "server_location::host::${short_host_name}::server::${server_name}::inactive_definition" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{inactive_definition}, + "server_location::host::${short_host_name}::server::${server_name}::definition_diff" => $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{definition_diff}, + }}); + } + } + } } - - $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{status} = ""; - $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{active_definition} = ""; - $anvil->data->{server_location}{host}{$short_host_name}{server}{$server_name}{inactive_definition} = ""; - } } - - # Get the inactive XML (changes requested by the user may not match the in-memory XML) - my $virsh_definition_active = $anvil->data->{domain}{$server_name}{handle}->get_xml_description(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { virsh_definition_active => $virsh_definition_active }}); - - my $virsh_definition_inactive = $anvil->data->{domain}{$server_name}{handle}->get_xml_description(Sys::Virt::Domain::XML_INACTIVE); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { virsh_definition_inactive => $virsh_definition_inactive }}); - - my ($anvil, $server_name) = @_; - - ### States: - # 0 = no state - # 1 = running - The domain is currently running on a CPU - # 2 = blocked (idle) - the domain is blocked on resource. This can be caused because the domain is waiting on IO (a traditional wait state) or has gone to sleep because there was nothing else for it to do. - # 3 = paused - The domain has been paused, usually occurring through the administrator running virsh suspend. When in a paused state the domain will still consume allocated resources like memory, but will not be eligible for scheduling by the hypervisor. - # 4 = in shutdown - The domain is in the process of shutting down, i.e. the guest operating system has been notified and should be in the process of stopping its operations gracefully. - # 5 = shut off - The domain is not running. Usually this indicates the domain has been shut down completely, or has not been started. - # 6 = crashed - The domain has crashed, which is always a violent ending. Usually this state can only occur if the domain has been configured not to restart on crash. - # 7 = pmsuspended - The domain has been suspended by guest power management, e.g. entered into s3 state. - my ($state, $reason) = $anvil->data->{domain}{$server_name}{handle}->get_state(); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 'state' => $state, - reason => $reason, - }}); - - ### Reasons are dependent on the state. - ### See: https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainShutdownReason - my $server_state = "unknown"; - if ($state == 1) { $server_state = "running"; } # Server is running. - elsif ($state == 2) { $server_state = "blocked"; } # Server is blocked (IO contention?). - elsif ($state == 3) { $server_state = "paused"; } # Server is paused (migration target?). - elsif ($state == 4) { $server_state = "in shutdown"; } # Server is shutting down. - elsif ($state == 5) { $server_state = "shut off"; } # Server is shut off. - elsif ($state == 6) { $server_state = "crashed"; } # Server is crashed! - elsif ($state == 7) { $server_state = "pmsuspended"; } # Server is suspended. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_state => $server_state }}); - - return($server_state); + return($server_host); } =head2 migrate_virsh diff --git a/share/words.xml b/share/words.xml index 58dcb931..c40d8099 100644 --- a/share/words.xml +++ b/share/words.xml @@ -2623,6 +2623,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is: Deleting the 'files' database entry for the file uuid: [#!variable!file_uuid!#]. There is an existing a functioning connection to: [#!variable!target!#], no need to reconnect. There is an existing a functioning connection to the server: [#!variable!server_name!#], no need to reconnect. + Waiting for: [#!variable!delay!#] seconds. The host name: [#!variable!target!#] does not resolve to an IP address. diff --git a/tools/anvil-join-anvil b/tools/anvil-join-anvil index 5451acfd..17fa14ea 100755 --- a/tools/anvil-join-anvil +++ b/tools/anvil-join-anvil @@ -298,6 +298,9 @@ sub configure_pacemaker my $both_online = 0; until($both_online) { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + 'path::configs::corosync.conf' => $anvil->data->{path}{configs}{'corosync.conf'}, + }}); if (-e $anvil->data->{path}{configs}{'corosync.conf'}) { if (not $start_time) @@ -362,7 +365,12 @@ sub configure_pacemaker # corosync.conf doesn't exist yet. $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "job_0107"}); } - sleep 5 if not $both_online; + if (not $both_online) + { + my $delay = 5; + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0816", variables => { delay => $delay }}); + sleep $delay; + } } } else