Added Server->update_definition()

* This takes a server and new definition XML and updated the database and any available hosts. Does not yet update defined or running servers.

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 1 year ago
parent e361d0b424
commit 245f75de9b
  1. 221
      Anvil/Tools/Server.pm
  2. 9
      share/words.xml
  3. 45
      tools/anvil-manage-server-system

@ -7,6 +7,8 @@ use strict;
use warnings;
use Scalar::Util qw(weaken isweak);
use Data::Dumper;
use Text::Diff;
use Sys::Virt;
our $VERSION = "3.0.0";
my $THIS_FILE = "Server.pm";
@ -24,6 +26,7 @@ my $THIS_FILE = "Server.pm";
# parse_definition
# migrate_virsh
# shutdown_virsh
# update_definition
=cut TODO
@ -2346,6 +2349,224 @@ WHERE
return($success);
}
=head2 update_definition
This takes a new server XML definition and saves it in the database and writes it out to the on-disk files. If either subnode or DR host is inacessible, this still returns success as C<< scan-server >> will pick up the new definition when the server comes back online.
If there is a problem, C<< !!error!! >> is returned. If it is updated, C<< 0 >> is returned.
Parameters;
=head3 server (required)
This is the name or UUID of the server being updated.
=head3 new_definition_xml
This is the new XML definition file. It will be parsed and sanity checked.
=cut
sub update_definition
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Server->update_definition()" }});
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $new_definition_xml = defined $parameter->{new_definition_xml} ? $parameter->{new_definition_xml} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server => $server,
new_definition_xml => $new_definition_xml,
}});
if (not $server)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->update_definition()", parameter => "server" }});
return('!!error!!');
}
if (not $new_definition_xml)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->update_definition()", parameter => "new_definition_xml" }});
return('!!error!!');
}
my ($server_name, $server_uuid) = $anvil->Get->server_from_switch({
debug => $debug,
server_string => $server,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_name => $server_name,
server_uuid => $server_uuid,
}});
# Do we have a valid server UUID?
$anvil->Database->get_anvils({debug => $debug});
$anvil->Database->get_servers({debug => $debug});
if (not exists $anvil->data->{servers}{server_uuid}{$server_uuid})
{
# Invalid.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0463", variables => {
server => $server,
server_uuid => $server_uuid,
}});
return('!!error!!');
}
# Validate the new XML
my $short_host_name = $anvil->Get->short_host_name();
my $problem = $anvil->Server->parse_definition({
debug => 2,
target => $short_host_name,
server => $server_name,
source => "test",
definition => $new_definition_xml,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if ($problem)
{
# Failed to parse.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0464", variables => {
server_name => $server_name,
xml => $new_definition_xml,
}});
return('!!error!!');
}
else
{
my $test_uuid = $anvil->data->{server}{$short_host_name}{$server_name}{test}{info}{uuid} // "";
if ((not $test_uuid) or ($test_uuid ne $server_uuid))
{
# Somehow the new XML is invalid.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0464", variables => {
server_name => $server_name,
xml => $new_definition_xml,
}});
return('!!error!!');
}
}
# 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};
my $node1_host_name = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{host_name};
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,
node1_host_name => $node1_host_name,
node2_host_uuid => $node2_host_uuid,
node2_host_name => $node2_host_name,
}});
# Is there a difference between the new and DB definition?
my $db_difference = diff \$db_definition_xml, \$new_definition_xml, { STYLE => 'Unified' };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { db_difference => $db_difference }});
if ($db_difference)
{
# Update the DB.
$anvil->Database->insert_or_update_server_definitions({
debug => $debug,
server_definition_uuid => $definition_uuid,
server_definition_server_uuid => $server_uuid,
server_definition_xml => $new_definition_xml,
});
}
# Look for definitions
my $hosts = [$node1_host_uuid, $node2_host_uuid];
foreach my $dr_host_name (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}})
{
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}{$dr_host_name}{dr_link_uuid};
my $dr_host_uuid = $anvil->data->{dr_links}{dr_link_uuid}{$dr_link_uuid}{dr_link_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:dr_host_name' => $dr_host_name,
's2:dr_host_uuid' => $dr_host_uuid,
's3:dr_link_uuid' => $dr_link_uuid,
}});
push @{$hosts}, $dr_host_uuid;
}
# Get the host UUIDs for the node this server is hosted by.
my $definition_file = $anvil->data->{path}{directories}{shared}{definitions}."/".$server_name.".xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { definition_file => $definition_file }});
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({
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 }});
if ($target_ip)
{
# Read the old definition.
my $old_definition_xml = $anvil->Storage->read_file({
debug => $debug,
file => $definition_file,
target => $target_ip,
});
$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,
file => $definition_file,
}});
}
else
{
my $file_difference = diff \$old_definition_xml, \$new_definition_xml, { STYLE => 'Unified' };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_difference => $file_difference }});
if ($file_difference)
{
# Update
my $error = $anvil->Storage->write_file({
debug => $debug,
file => $definition_file,
body => $new_definition_xml,
backup => 1,
overwrite => 1,
mode => "0644",
group => "root",
user => "root",
target => $target_ip,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { error => $error }});
if ($error)
{
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_0164", variables => {
server_name => $server_name,
host_name => $host_name,
file => $definition_file,
}});
}
}
}
# If the server running or defined here?
}
}
return(0);
}
# =head3
#
# Private Functions;

@ -726,6 +726,13 @@ The creation of the new replicatedd disk is incomplete, manual intervention is r
====================
The creation of the new replicated disk is incomplete, manual intervention is required!]]></key>
<key name="error_0462"><![CDATA[The switch '--immediate' can not be used with '--server all'.]]></key>
<key name="error_0463"><![CDATA[Failed to translate the 'server' string: [#!variable!server!#] to a UUID: [#!variable!server_uuid!#].]]></key>
<key name="error_0464"><![CDATA[There was a problem parsing the new XML definition for the server: [#!variable!server_name!#]. Either the XML failed to parse, or the server's UUID doesn't match.
The XML that failed sanity check was:
========
#!variable!xml!#
========
]]></key>
<!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which lines are translatable -->
@ -3933,6 +3940,8 @@ We will try to proceed anyway.</key>
#!variable!error!#
====
</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>
</language>
<!-- 日本語 -->

@ -271,12 +271,6 @@ sub manage_boot_menu
my $new_definition = "";
my $in_os = 0;
my $bootmenu_seen = 0;
=cut
<os>
<type arch='x86_64' machine='pc-q35-rhel8.6.0'>hvm</type>
<bootmenu enable='yes'/>
</os>
=cut
foreach my $line (split/\n/, $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
@ -289,23 +283,14 @@ sub manage_boot_menu
{
if ($line =~ /<bootmenu enable='(.*?)'\/>/)
{
my $old_value = $1;
$bootmenu_seen = 1;
my $old_value = $1;
$bootmenu_seen = 1;
$line =~ s/<bootmenu enable='.*?'\/>/<bootmenu enable='$new_boot_menu'\/>/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
old_value => $old_value,
bootmenu_seen => $bootmenu_seen,
line => $line,
}});
if ($old_value eq $anvil->data->{switches}{'boot-menu'})
{
# Update not needed.
print "The boot menu is already: [".$anvil->data->{switches}{'boot-menu'}."], update not needed.\n";
}
else
{
# Update is needed.
$line =~ s/<bootmenu enable='.*?'\/>/<bootmenu enable='$new_boot_menu'\/>/;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
}
}
if ($line =~ /<\/os>/)
{
@ -322,21 +307,13 @@ sub manage_boot_menu
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_definition => $new_definition }});
my $difference = diff \$anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml}, \$new_definition, { STYLE => 'Unified' };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { difference => $difference }});
if ($difference)
{
# Test parse it.
my $problem = $anvil->Server->parse_definition({
debug => 2,
host => $short_host_name,
server => $server_name,
source => "test",
definition => $new_definition,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
}
# Always call this, as a previous run may have only updated some definitions.
my $problem = $anvil->Server->update_definition({
debug => 2,
server => $server_uuid,
new_definition_xml => $new_definition,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
}
else
{

Loading…
Cancel
Save