Improved the logic behind Network->find_target_ip()

* This adds the new 'networks' and 'test_access' parameters to allow
  restricting/ordering matched networks, and adds 'test_access' to
  validate the link is working.
* Continued work on anvil-manage-server-system

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 1 year ago
parent 62fe62a44b
commit 201cd53265
  1. 97
      Anvil/Tools/Network.pm
  2. 5
      man/anvil-manage-server-system.8
  3. 226
      tools/anvil-manage-server-system

@ -1525,6 +1525,20 @@ Parameters;
This is the target's C<< host_uuid >> that we're looking to contact.
=head3 networks (optional, default 'bcn,mn,sn,ifn,any')
This is the comma-separated list of networks to search for access over. The order presented is the order searched. Valid values are;
* bcn (Back-Channel Network)
* mn (Migration Network)
* sn (Storage Network)
* ifn (Internet-Facing Network)
* any (Any other interface)
=head3 test_access (optional, default '0')
If set to C<< 1 >>, any matched IP will be tested. If this is set and the target can't be reached using that IP, it is skipped. If this is not set, the first match is returned.
=cut
sub find_target_ip
{
@ -1534,10 +1548,13 @@ sub find_target_ip
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->find_target_ip()" }});
my $target_ip = "";
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : "";
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : "";
my $networks = defined $parameter->{networks} ? $parameter->{networks} : "";
my $test_access = defined $parameter->{test_access} ? $parameter->{test_access} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
host_uuid => $host_uuid,
networks => $networks,
test_access => $test_access,
}});
if (not $host_uuid)
@ -1554,6 +1571,12 @@ sub find_target_ip
return("");
}
if (not $networks)
{
$networks = "bcn,mn,sn,ifn,any";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { networks => $networks }});
}
my $target_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
my $short_host_name = $anvil->Get->short_host_name({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -1561,38 +1584,52 @@ sub find_target_ip
short_host_name => $short_host_name,
}});
$anvil->Network->load_ips({
debug => $debug,
host_uuid => $anvil->Get->host_uuid,
host => $short_host_name,
clear => 1,
});
$anvil->Network->load_ips({
debug => $debug,
host_uuid => $host_uuid,
host => $target_host_name,
clear => 1,
});
my ($match) = $anvil->Network->find_matches({
my $target_ip = "";
my $matches = $anvil->Network->find_access({
debug => $debug,
first => $short_host_name,
second => $target_host_name,
source => $THIS_FILE,
line => __LINE__,
target => $target_host_name,
});
if ($match)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { matches => $matches }});
foreach my $preferred_network (split/,/, $networks)
{
# Yup!
my $match_found = 0;
foreach my $interface (sort {$a cmp $b} keys %{$match->{$target_host_name}})
last if $target_ip;
$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}})
{
$target_ip = $match->{$target_host_name}{$interface}{ip};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_ip => $target_ip }});
last;
$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 $this_target_ip = $anvil->data->{network_access}{$network_name}{target_ip_address};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { this_target_ip => $this_target_ip }});
if ($test_access)
{
my $access = $anvil->Remote->test_access({target => $this_target_ip});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:network_name' => $network_name,
's2:this_target_ip' => $this_target_ip,
's3:access' => $access,
}});
if ($access)
{
# We can use this one.
$target_ip = $this_target_ip;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }});
last;
}
}
else
{
# We're done.
$target_ip = $this_target_ip;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target_ip => $target_ip }});
}
}
}
return($target_ip);

@ -23,8 +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\-\-\fR
\fB\-\-boot\-menu\fR <off,on>
.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.
.TP
\fB\-\-job\-uuid\fR
This is the jobs -> job_uuid to execute. Generally this is only used by other programs.

@ -21,6 +21,7 @@ require POSIX;
use Term::Cap;
use Text::Diff;
use Data::Dumper;
use Sys::Virt;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
@ -38,6 +39,8 @@ my $anvil = Anvil::Tools->new();
$anvil->Get->switches({list => [
"add",
"anvil",
"boot",
"boot-menu",
"confirm",
"disk",
"eject",
@ -101,10 +104,18 @@ if ($anvil->data->{switches}{cpu})
{
#manage_cpu($anvil);
}
elsif ($anvil->data->{switches}{cpu})
elsif ($anvil->data->{switches}{ram})
{
#manage_ram($anvil);
}
elsif ($anvil->data->{switches}{boot})
{
#manage_boot($anvil);
}
elsif ($anvil->data->{switches}{'boot-menu'})
{
manage_boot_menu($anvil);
}
else
{
show_server_details($anvil, 1);
@ -122,6 +133,219 @@ $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)
{
# Local
$uri = "qemu+ssh://".$localhost."/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 }});
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")
{
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;
}
}
}
}
}
$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 => $@,
},
});
return(1);
}
my $stream = $connection->new_stream();
my @domains = $connection->list_all_domains();
foreach my $domain (@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 ($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,
},
});
}
return(0);
}
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};
$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,
}});
if ($server_state eq "running")
{
my $server_host_name = $anvil->Database->get_host_from_uuid({
short => 1,
host_uuid => $server_host_uuid,
});
}
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")
{
}
else
{
print "Boot Menu enabled: [".$say_boot_menu."]\n";
print "- You can change this using '--boot-menu off' or '--boot-menu on'.\n";
}
return(0);
}
sub show_server_details
{
my ($anvil, $show_nodes) = @_;

Loading…
Cancel
Save