Updated anvil-manage-server-system to update defined servers.

* Updated Server->locate() to take the new 'anvil' parameter to speed up
  searches.
* Updated Server->update_definition() to use Server->locate() to find
  where updates are needed. It now also defines the server with the new
  config.

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 1 year ago
parent fd461f940d
commit 9b55504872
  1. 1
      Anvil/Tools/Database.pm
  2. 139
      Anvil/Tools/Server.pm
  3. 6
      share/words.xml
  4. 130
      tools/anvil-manage-server-system

@ -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("");
}

@ -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 !~ /<domain/ms))
{
my $host_name = $anvil->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?
}
}

@ -734,6 +734,7 @@ The XML that failed sanity check was:
========
]]></key>
<key name="error_0465"><![CDATA[The file: [#!variable!file!#] doesn't exist on the target: [#!variable!target!#].]]></key>
<key name="error_0466"><![CDATA[The Anvil! string (name or UUID): [#!variable!string!#] didn't match any known Anvil! in the database.]]></key>
<!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which lines are translatable -->
@ -3955,6 +3956,11 @@ We will try to proceed anyway.</key>
<key name="warning_0163"><![CDATA[Failed to read the definition file: [#!variable!file!#] for the server: [#!variable!server_name!#] on the host: [#!variable!host_name!#]. If the host is online, it should update the next time scan-server runs.]]></key>
<key name="warning_0164"><![CDATA[Failed to update the definition file: [#!variable!file!#] for the server: [#!variable!server_name!#] on the host: [#!variable!host_name!#]. If the host is online, it should update the next time scan-server runs.]]></key>
<key name="warning_0165"><![CDATA[A duplicate variable was found! Section: [#!variable!section!#], name: [#!variable!name!#], source table: [#!variable!source_table!#], source_uuid: [#!variable!source_uuid!#], value: [#!variable!value!#]. This is older, so it will be deleted.]]></key>
<key name="warning_0166">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!#
====
</key>
</language>
<!-- 日本語 -->

@ -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);

Loading…
Cancel
Save