More progress on anvil-manage-server-system

* It now edits the XML to change the boot menu, but doesn't save yet.

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 1 year ago
parent 201cd53265
commit e361d0b424
  1. 4
      Anvil/Tools/Server.pm
  2. 4
      man/anvil-manage-server-system.8
  3. 1
      tools/anvil-manage-server-storage
  4. 243
      tools/anvil-manage-server-system

@ -1462,6 +1462,10 @@ The XML was dumped by C<< virsh >> from memory.
The XML was read from the C<< definitions >> database table.
=head4 C<< test >>
The XML is a test definition, and not actually from anywhere.
=head3 definition (required)
This is the actual XML to be parsed.

@ -23,9 +23,9 @@ When logging, record sensitive data, like passwords.
Set the log level to 1, 2 or 3 respectively. Be aware that level 3 generates a significant amount of log data.
.SS "Commands:"
.TP
\fB\-\-boot\-menu\fR <off,on>
\fB\-\-boot\-menu\fR <yes,no>
.TP
When called without a value, it shows if the boot menu is enabled or not. If called with 'on', it enables the boot menu. If called with 'off', the boot meny is disabled.
When called without a value, it shows if the boot menu is enabled or not. If called with 'yes', it enables the boot menu. If called with 'no', the boot meny is disabled.
.TP
\fB\-\-job\-uuid\fR
This is the jobs -> job_uuid to execute. Generally this is only used by other programs.

@ -8,6 +8,7 @@
# 1 = No database connection.
#
# TODO:
# - Update the target_ip search to use the new Network->find_target_ip().
#
# USAGE:
# - Show

@ -162,8 +162,10 @@ sub connect_to_libvirt
{
if ($server_uuid eq $anvil->Get->host_uuid)
{
# Local
$uri = "qemu+ssh://".$localhost."/system";
### 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
@ -182,143 +184,67 @@ sub connect_to_libvirt
networks => "bcn,mn,sn,ifn,any",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }});
my $matches = $anvil->Network->find_access({
debug => 2,
target => $server_host_name,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { matches => $matches }});
foreach my $preferred_network ("bcn", "mn", "sn", "ifn", "any")
if ($target_ip)
{
next if $uri;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { preferred_network => $preferred_network }});
foreach my $network_name (sort {$a cmp $b} keys %{$anvil->data->{network_access}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_name => $network_name }});
if (($network_name !~ /^$preferred_network/) && ($preferred_network ne "any"))
{
next;
}
my $target_ip = $anvil->data->{network_access}{$network_name}{target_ip_address};
my $test_access = $anvil->Remote->test_access({target => $target_ip});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:network_name' => $network_name,
's2:target_ip' => $target_ip,
's3:test_access' => $test_access,
}});
if ($test_access)
{
# Connect using this URI
$uri = "qemu+ssh://".$target_ip."/system";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { uri => $uri }});
last;
}
}
# 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 ($@)
{
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "warning_0162",
log_level => 1,
priority => "alert",
variables => {
host_name => $short_host_name,
uri => $uri,
error => $@,
},
});
# 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 $stream = $connection->new_stream();
my $domain = "";
my @domains = $connection->list_all_domains();
foreach my $domain (@domains)
foreach my $domain_handle (@domains)
{
my $server_name = $domain->get_name;
my $server_id = $domain->get_id == -1 ? "" : $domain->get_id;
my $server_uuid = $domain->get_uuid_string;
my $server_xml = $domain->get_xml_description;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_name => $server_name,
server_id => $server_id,
server_uuid => $server_uuid,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { server_xml => $server_xml }});
my $this_server_name = $domain_handle->get_name;
next if $this_server_name ne $server_name;
my ($state, $reason) = $domain->get_state();
### 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.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
'state' => $state,
reason => $reason,
}});
### Reasons are dependent on the state.
### See: https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainShutdownReason
if ($state == 1) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "unit_0041"}); } # Server is running.
elsif ($state == 2) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "unit_0042"}); } # Server is blocked (IO contention?).
elsif ($state == 3) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "unit_0043"}); } # Server is paused (migration target?).
elsif ($state == 4) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "unit_0044"}); } # Server is shutting down.
elsif ($state == 5) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "unit_0045"}); } # Server is shut off.
elsif ($state == 6) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "unit_0046"}); } # Server is crashed!
elsif ($state == 7) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "unit_0047"}); } # Server is suspended.
else { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "unit_0048", variables => { 'state' => $state }}); } # Server is in an unknown state
# Only take screenshots of running servers.
return(1) if $state != 1;
$anvil->Job->update_progress({
progress => $anvil->data->{job}{progress} < 99 ? ++$anvil->data->{job}{progress} : $anvil->data->{job}{progress},
message => "log_0805",
log_level => 2,
variables => {
server_name => $server_name,
server_uuid => $server_uuid,
host_name => $short_host_name,
},
});
$domain = $domain_handle;
last;
}
return(0);
return($domain);
}
sub manage_boot_menu
{
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};
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};
my $server_host_uuid = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_host_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,
's1:short_host_name' => $short_host_name,
's2:host_uuid' => $host_uuid,
's3:server_name' => $server_name,
's4:server_uuid' => $server_uuid,
's5:server_host_uuid' => $server_host_uuid,
}});
my $from_source = get_definition_source($anvil);
my $server_state = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_state};
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};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
from_source => $from_source,
server_state => $server_state,
domain_handle => $domain_handle,
from_source => $from_source,
server_state => $server_state,
}});
if ($server_state eq "running")
{
@ -328,18 +254,93 @@ sub manage_boot_menu
});
}
my $say_yes = $anvil->Words->string({key => 'unit_0001'});
my $say_no = $anvil->Words->string({key => 'unit_0002'});
my $say_boot_menu = lc($anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{info}{boot_menu}) eq "yes" ? $say_yes : $say_no;
if ($anvil->data->{switches}{'boot-menu'} eq "on")
{
}
elsif ($anvil->data->{switches}{'boot-menu'} eq "off")
my $say_yes = $anvil->Words->string({key => 'unit_0001'});
my $say_no = $anvil->Words->string({key => 'unit_0002'});
my $current_boot_menu = lc($anvil->data->{server}{$short_host_name}{$server_name}{$from_source}{info}{boot_menu});
my $say_old_boot_menu = $current_boot_menu eq "yes" ? $say_yes : $say_no;
my $new_boot_menu = $anvil->data->{switches}{'boot-menu'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
current_boot_menu => $current_boot_menu,
say_old_boot_menu => $say_old_boot_menu,
new_boot_menu => $new_boot_menu,
}});
if (($anvil->data->{switches}{'boot-menu'} eq "yes") or ($anvil->data->{switches}{'boot-menu'} eq "no"))
{
# We need to rewrite the boot menu manually.
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 }});
if ($line =~ /<os>/)
{
$in_os = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { in_os => $in_os }});
}
if ($in_os)
{
if ($line =~ /<bootmenu enable='(.*?)'\/>/)
{
my $old_value = $1;
$bootmenu_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
old_value => $old_value,
bootmenu_seen => $bootmenu_seen,
}});
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>/)
{
$in_os = 0;
if (not $bootmenu_seen)
{
# Insert it
$new_definition .= " <bootmenu enable='".$new_boot_menu."'\/>\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { new_definition => $new_definition }});
}
}
}
$new_definition .= $line."\n";
}
$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 }});
}
}
else
{
print "Boot Menu enabled: [".$say_boot_menu."]\n";
print "Boot Menu enabled: [".$say_old_boot_menu."]\n";
print "- You can change this using '--boot-menu off' or '--boot-menu on'.\n";
}

Loading…
Cancel
Save