Local modifications to ClusterLabs/Anvil by Alteeve
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

656 lines
37 KiB

package Anvil::Tools::Server;
#
# This module contains methods used to manager servers
#
use strict;
use warnings;
use Scalar::Util qw(weaken isweak);
use Data::Dumper;
our $VERSION = "3.0.0";
my $THIS_FILE = "Server.pm";
### Methods;
# get_status
=pod
=encoding utf8
=head1 NAME
Anvil::Tools::Server
Provides all methods related to (virtual) servers.
=head1 SYNOPSIS
use Anvil::Tools;
# Get a common object handle on all Anvil::Tools modules.
my $anvil = Anvil::Tools->new();
# Access to methods using '$anvil->Server->X'.
#
#
=head1 METHODS
Methods in this module;
=cut
sub new
{
my $class = shift;
my $self = {
};
bless $self, $class;
return ($self);
}
# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more
# sense in this case to think of it as a parent.
sub parent
{
my $self = shift;
my $parent = shift;
$self->{HANDLE}{TOOLS} = $parent if $parent;
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});;
}
return ($self->{HANDLE}{TOOLS});
}
#############################################################################################################
# Public methods #
#############################################################################################################
=head2 find
This looks on an Anvil! for what servers are running where.
=cut
=head2 get_status
This reads in a server's XML definition file from disk, if available, and from memory, if the server is running. The XML is analyzed and data is stored in the following locations;
-
Any pre-existing data on the server is flushed before the new information is processed.
Parameters;
=head3 password (optional)
This is the password to use when connecting to a remote machine. If not set, but C<< target >> is, an attempt to connect without a password will be made.
=head3 port (optional)
This is the TCP port to use when connecting to a remote machine. If not set, but C<< target >> is, C<< 22 >> will be used.
=head3 remote_user (optional, default 'root')
If C<< target >> is set, this will be the user we connect to the remote machine as.
=head3 server (required)
This is the name of the server we're gathering data on.
=head3 target (optional)
This is the IP or host name of the machine to read the version of. If this is not set, the local system's version is checked.
=cut
# NOTE: the version is set in anvil.spec by sed'ing the release and arch onto anvil.version in anvil-core's %post
sub get_status
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $password = defined $parameter->{password} ? $parameter->{password} : "";
my $port = defined $parameter->{port} ? $parameter->{port} : "";
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $target = defined $parameter->{target} ? $parameter->{target} : "local";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
password => $anvil->Log->secure ? $password : $anvil->Words->string({key => "log_0186"}),
port => $port,
remote_user => $remote_user,
target => $target,
}});
if (not $server)
{
return(1);
}
if (exists $anvil->data->{server}{$server})
{
delete $anvil->data->{server}{$server};
}
$anvil->data->{server}{$server}{from_memory}{host} = "";
# Is this a local call or a remote call?
my $shell_call = $anvil->data->{path}{exe}{virsh}." dumpxml ".$server;
my $host = $anvil->_short_hostname;
if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname))
{
# Remote call.
$host = $target;
($anvil->data->{server}{$server}{from_memory}{xml}, my $error, $anvil->data->{server}{$server}{from_memory}{return_code}) = $anvil->Remote->call({
debug => $debug,
shell_call => $shell_call,
target => $target,
port => $port,
password => $password,
remote_user => $remote_user,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error,
"server::${server}::from_memory::xml" => $anvil->data->{server}{$server}{from_memory}{xml},
"server::${server}::from_memory::return_code" => $anvil->data->{server}{$server}{from_memory}{return_code},
}});
}
else
{
# Local.
($anvil->data->{server}{$server}{from_memory}{xml}, $anvil->data->{server}{$server}{from_memory}{return_code}) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::from_memory::xml" => $anvil->data->{server}{$server}{from_memory}{xml},
"server::${server}::from_memory::return_code" => $anvil->data->{server}{$server}{from_memory}{return_code},
}});
}
# If the return code was non-zero, we can't parse the XML.
if ($anvil->data->{server}{$server}{from_memory}{return_code})
{
$anvil->data->{server}{$server}{from_memory}{xml} = "";
}
else
{
$anvil->data->{server}{$server}{from_memory}{host} = $host;
$anvil->Server->_parse_definition({
debug => $debug,
server => $server,
source => "from_memory",
definition => $anvil->data->{server}{$server}{from_memory}{xml},
});
}
# Now get the on-disk XML.
($anvil->data->{server}{$server}{from_disk}{xml}) = $anvil->Storage->read_file({
debug => $debug,
password => $password,
port => $port,
remote_user => $remote_user,
target => $target,
force_read => 1,
file => $anvil->data->{path}{directories}{shared}{definitions}."/".$server.".xml",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::disk::xml" => $anvil->data->{server}{$server}{disk}{xml},
}});
if ($anvil->data->{server}{$server}{disk}{xml})
{
$anvil->Server->_parse_definition({
debug => $debug,
server => $server,
source => "from_disk",
definition => $anvil->data->{server}{$server}{from_disk}{xml},
});
}
return(0);
}
# =head3
#
# Private Functions;
#
# =cut
#############################################################################################################
# Private functions #
#############################################################################################################
### NOTE: This is a work in progress. As of now, it parses out what ocf:alteeve:server needs.
# This pulls apart specific data out of a definition file.
sub _parse_definition
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
# Source is required.
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $source = defined $parameter->{source} ? $parameter->{source} : "";
my $definition = defined $parameter->{definition} ? $parameter->{definition} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
source => $source,
definition => $definition,
}});
if (not $server)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->_parse_definition()", parameter => "server" }});
return(1);
}
if (not $source)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->_parse_definition()", parameter => "source" }});
return(1);
}
if (not $definition)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->_parse_definition()", parameter => "definition" }});
return(1);
}
# We're going to map DRBD devices to resources, so we need to collect that data now.
$anvil->DRBD->get_devices({debug => $debug});
my $xml = XML::Simple->new();
my $server_xml = "";
eval { $server_xml = $xml->XMLin($definition, KeyAttr => {}, ForceArray => 1) };
if ($@)
{
chomp $@;
my $error = "[ Error ] - The was a problem parsing: [$definition]. The error was:\n";
$error .= "===========================================================\n";
$error .= $@."\n";
$error .= "===========================================================\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", list => { error => $error }});
$anvil->nice_exit({exit_code => 1});
}
$anvil->data->{server}{$server}{$source}{parsed} = $server_xml;
#print Dumper $server_xml;
# Pull out some basic server info.
$anvil->data->{server}{$server}{$source}{info}{uuid} = $server_xml->{uuid}->[0];
$anvil->data->{server}{$server}{$source}{info}{name} = $server_xml->{name}->[0];
$anvil->data->{server}{$server}{$source}{info}{on_poweroff} = $server_xml->{on_poweroff}->[0];
$anvil->data->{server}{$server}{$source}{info}{on_crash} = $server_xml->{on_crash}->[0];
$anvil->data->{server}{$server}{$source}{info}{on_reboot} = $server_xml->{on_reboot}->[0];
$anvil->data->{server}{$server}{$source}{info}{boot_menu} = $server_xml->{os}->[0]->{bootmenu}->[0]->{enable};
$anvil->data->{server}{$server}{$source}{info}{id} = $server_xml->{id};
$anvil->data->{server}{$server}{$source}{info}{emulator} = $server_xml->{devices}->[0]->{emulator}->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::info::uuid" => $anvil->data->{server}{$server}{$source}{info}{uuid},
"server::${server}::${source}::info::name" => $anvil->data->{server}{$server}{$source}{info}{name},
"server::${server}::${source}::info::on_poweroff" => $anvil->data->{server}{$server}{$source}{info}{on_poweroff},
"server::${server}::${source}::info::on_crash" => $anvil->data->{server}{$server}{$source}{info}{on_crash},
"server::${server}::${source}::info::on_reboot" => $anvil->data->{server}{$server}{$source}{info}{on_reboot},
"server::${server}::${source}::info::boot_menu" => $anvil->data->{server}{$server}{$source}{info}{boot_menu},
"server::${server}::${source}::info::id" => $anvil->data->{server}{$server}{$source}{info}{id},
"server::${server}::${source}::info::emulator" => $anvil->data->{server}{$server}{$source}{info}{emulator},
}});
# CPU
$anvil->data->{server}{$server}{$source}{cpu}{total_cores} = $server_xml->{vcpu}->[0]->{content};
$anvil->data->{server}{$server}{$source}{cpu}{sockets} = $server_xml->{cpu}->[0]->{topology}->[0]->{sockets};
$anvil->data->{server}{$server}{$source}{cpu}{cores} = $server_xml->{cpu}->[0]->{topology}->[0]->{cores};
$anvil->data->{server}{$server}{$source}{cpu}{threads} = $server_xml->{cpu}->[0]->{topology}->[0]->{threads};
$anvil->data->{server}{$server}{$source}{cpu}{model_name} = $server_xml->{cpu}->[0]->{model}->[0]->{content};
$anvil->data->{server}{$server}{$source}{cpu}{model_fallback} = $server_xml->{cpu}->[0]->{model}->[0]->{fallback};
$anvil->data->{server}{$server}{$source}{cpu}{match} = $server_xml->{cpu}->[0]->{match};
$anvil->data->{server}{$server}{$source}{cpu}{vendor} = $server_xml->{cpu}->[0]->{vendor}->[0];
$anvil->data->{server}{$server}{$source}{cpu}{mode} = $server_xml->{cpu}->[0]->{mode};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::cpu::total_cores" => $anvil->data->{server}{$server}{$source}{cpu}{total_cores},
"server::${server}::${source}::cpu::sockets" => $anvil->data->{server}{$server}{$source}{cpu}{sockets},
"server::${server}::${source}::cpu::cores" => $anvil->data->{server}{$server}{$source}{cpu}{cores},
"server::${server}::${source}::cpu::threads" => $anvil->data->{server}{$server}{$source}{cpu}{threads},
"server::${server}::${source}::cpu::model_name" => $anvil->data->{server}{$server}{$source}{cpu}{model_name},
"server::${server}::${source}::cpu::model_fallback" => $anvil->data->{server}{$server}{$source}{cpu}{model_fallback},
"server::${server}::${source}::cpu::match" => $anvil->data->{server}{$server}{$source}{cpu}{match},
"server::${server}::${source}::cpu::vendor" => $anvil->data->{server}{$server}{$source}{cpu}{vendor},
"server::${server}::${source}::cpu::mode" => $anvil->data->{server}{$server}{$source}{cpu}{mode},
}});
foreach my $hash_ref (@{$server_xml->{cpu}->[0]->{feature}})
{
my $name = $hash_ref->{name};
$anvil->data->{server}{$server}{$source}{cpu}{feature}{$name} = $hash_ref->{policy};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::cpu::feature::${name}" => $anvil->data->{server}{$server}{$source}{cpu}{feature}{$name},
}});
}
# Power Management
$anvil->data->{server}{$server}{$source}{pm}{'suspend-to-disk'} = $server_xml->{pm}->[0]->{'suspend-to-disk'}->[0]->{enabled};
$anvil->data->{server}{$server}{$source}{pm}{'suspend-to-mem'} = $server_xml->{pm}->[0]->{'suspend-to-mem'}->[0]->{enabled};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::pm::suspend-to-disk" => $anvil->data->{server}{$server}{$source}{pm}{'suspend-to-disk'},
"server::${server}::${source}::pm::suspend-to-mem" => $anvil->data->{server}{$server}{$source}{pm}{'suspend-to-mem'},
}});
# RAM - 'memory' is as set at boot, 'currentMemory' is the RAM used at polling (so only useful when
# running). In the Anvil!, we don't support memory ballooning, so we're use whichever is
# higher.
my $current_ram_value = $server_xml->{currentMemory}->[0]->{content};
my $current_ram_unit = $server_xml->{currentMemory}->[0]->{unit};
my $current_ram_bytes = $anvil->Convert->human_readable_to_bytes({size => $current_ram_value, type => $current_ram_unit});
my $ram_value = $server_xml->{memory}->[0]->{content};
my $ram_unit = $server_xml->{memory}->[0]->{unit};
my $ram_bytes = $anvil->Convert->human_readable_to_bytes({size => $ram_value, type => $ram_unit});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
current_ram_value => $current_ram_value,
current_ram_unit => $current_ram_unit,
current_ram_bytes => $anvil->Convert->add_commas({number => $current_ram_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $current_ram_bytes}).")",
ram_value => $ram_value,
ram_unit => $ram_unit,
ram_bytes => $anvil->Convert->add_commas({number => $ram_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_bytes}).")",
}});
$anvil->data->{server}{$server}{$source}{memory} = $current_ram_bytes > $ram_bytes ? $current_ram_bytes : $ram_bytes;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::memory" => $anvil->Convert->add_commas({number => $anvil->data->{server}{$server}{$source}{memory}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{server}{$server}{$source}{memory}}).")",
}});
# Pull out my channels
foreach my $hash_ref (@{$server_xml->{devices}->[0]->{channel}})
{
my $type = $hash_ref->{type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { type => $type }});
if ($type eq "unix")
{
# Bus stuff
my $address_type = $hash_ref->{address}->[0]->{type};
my $address_controller = $hash_ref->{address}->[0]->{controller};
my $address_bus = $hash_ref->{address}->[0]->{bus};
my $address_port = $hash_ref->{address}->[0]->{port};
# Store
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode} = $hash_ref->{source}->[0]->{mode};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{path} = $hash_ref->{source}->[0]->{path};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{controller} = $address_controller;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{port} = $address_port;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{type} = $hash_ref->{target}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'} = $hash_ref->{target}->[0]->{'state'};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{name} = $hash_ref->{target}->[0]->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::channel::unix::source::mode" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode},
"server::${server}::${source}::device::channel::unix::source::path" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{path},
"server::${server}::${source}::device::channel::unix::alias" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias},
"server::${server}::${source}::device::channel::unix::address::type" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{type},
"server::${server}::${source}::device::channel::unix::address::bus" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{bus},
"server::${server}::${source}::device::channel::unix::address::controller" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{controller},
"server::${server}::${source}::device::channel::unix::address::port" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{port},
"server::${server}::${source}::device::channel::unix::target::type" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{type},
"server::${server}::${source}::device::channel::unix::target::state" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'},
"server::${server}::${source}::device::channel::unix::target::name" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{name},
}});
# Add to system bus list
$anvil->data->{server}{$server}{$source}{address}{$address_type}{controller}{$address_controller}{bus}{$address_bus}{port}{$address_port} = "channel - ".$type;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::address::${address_type}::controller::${address_controller}::bus::${address_bus}::port::${address_port}" => $anvil->data->{server}{$server}{$source}{address}{$address_type}{controller}{$address_controller}{bus}{$address_bus}{port}{$address_port},
}});
}
elsif ($type eq "spicevmc")
{
# Bus stuff
my $address_type = $hash_ref->{address}->[0]->{type};
my $address_controller = $hash_ref->{address}->[0]->{controller};
my $address_bus = $hash_ref->{address}->[0]->{bus};
my $address_port = $hash_ref->{address}->[0]->{port};
# Store
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{controller} = $address_controller;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{port} = $address_port;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{type} = $hash_ref->{target}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'} = $hash_ref->{target}->[0]->{'state'};
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{name} = $hash_ref->{target}->[0]->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::channel::spicevmc::alias" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias},
"server::${server}::${source}::device::channel::spicevmc::address::type" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{type},
"server::${server}::${source}::device::channel::spicevmc::address::bus" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{bus},
"server::${server}::${source}::device::channel::spicevmc::address::controller" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{controller},
"server::${server}::${source}::device::channel::spicevmc::address::port" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{port},
"server::${server}::${source}::device::channel::spicevmc::target::type" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{type},
"server::${server}::${source}::device::channel::spicevmc::target::state" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'},
"server::${server}::${source}::device::channel::spicevmc::target::name" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{name},
}});
# Add to system bus list
$anvil->data->{server}{$server}{$source}{address}{$address_type}{controller}{$address_controller}{bus}{$address_bus}{port}{$address_port} = "channel - ".$type;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::address::${address_type}::controller::${address_controller}::bus::${address_bus}::port::${address_port}" => $anvil->data->{server}{$server}{$source}{address}{$address_type}{controller}{$address_controller}{bus}{$address_bus}{port}{$address_port},
}});
}
}
# Pull out console data
foreach my $hash_ref (@{$server_xml->{devices}->[0]->{console}})
{
$anvil->data->{server}{$server}{$source}{device}{console}{type} = $hash_ref->{type};
$anvil->data->{server}{$server}{$source}{device}{console}{tty} = $hash_ref->{tty};
$anvil->data->{server}{$server}{$source}{device}{console}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->data->{server}{$server}{$source}{device}{console}{source} = $hash_ref->{source}->[0]->{path};
$anvil->data->{server}{$server}{$source}{device}{console}{target_type} = $hash_ref->{target}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{console}{target_port} = $hash_ref->{target}->[0]->{port};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::console::type" => $anvil->data->{server}{$server}{$source}{device}{console}{type},
"server::${server}::${source}::device::console::tty" => $anvil->data->{server}{$server}{$source}{device}{console}{tty},
"server::${server}::${source}::device::console::alias" => $anvil->data->{server}{$server}{$source}{device}{console}{alias},
"server::${server}::${source}::device::console::source" => $anvil->data->{server}{$server}{$source}{device}{console}{source},
"server::${server}::${source}::device::console::target_type" => $anvil->data->{server}{$server}{$source}{device}{console}{target_type},
"server::${server}::${source}::device::console::target_port" => $anvil->data->{server}{$server}{$source}{device}{console}{target_port},
}});
}
# Controllers is a big chunk
foreach my $hash_ref (@{$server_xml->{devices}->[0]->{controller}})
{
my $type = $hash_ref->{type};
my $index = $hash_ref->{'index'};
my $ports = exists $hash_ref->{ports} ? $hash_ref->{ports} : "";
my $target_chassis = exists $hash_ref->{target} ? $hash_ref->{target}->[0]->{chassis} : "";
my $target_port = exists $hash_ref->{target} ? $hash_ref->{target}->[0]->{port} : "";
my $address_type = defined $hash_ref->{address}->[0]->{type} ? $hash_ref->{address}->[0]->{type} : "";
my $address_domain = defined $hash_ref->{address}->[0]->{domain} ? $hash_ref->{address}->[0]->{domain} : "";
my $address_bus = defined $hash_ref->{address}->[0]->{bus} ? $hash_ref->{address}->[0]->{bus} : "";
my $address_slot = defined $hash_ref->{address}->[0]->{slot} ? $hash_ref->{address}->[0]->{slot} : "";
my $address_function = defined $hash_ref->{address}->[0]->{function} ? $hash_ref->{address}->[0]->{function} : "";
# Model is weird, it can be at '$hash_ref->{model}->[X]' or '$hash_ref->{model}->[Y]->{name}'
# as 'model' is both an attribute and a child element.
$hash_ref->{model} = "" if not defined $hash_ref->{model};
my $model = "";
if (not ref($hash_ref->{model}))
{
$model = $hash_ref->{model};
}
else
{
foreach my $entry (@{$hash_ref->{model}})
{
if (ref($entry))
{
$model = $entry->{name} if $entry->{name};
}
else
{
$model = $entry if $entry;
}
}
}
# Store the data
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias} = $hash_ref->{alias}->[0]->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::controller::${type}::index::${index}::alias" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias},
}});
if ($model)
{
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{model} = $model;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::controller::${type}::index::${index}::model" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{model},
}});
}
if ($ports)
{
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{ports} = $ports;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::controller::${type}::index::${index}::ports" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{ports},
}});
}
if ($target_chassis)
{
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{chassis} = $target_chassis;
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{port} = $target_port;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::controller::${type}::index::${index}::target::chassis" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{chassis},
"server::${server}::${source}::device::controller::${type}::index::${index}::target::port" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{port},
}});
}
if ($address_type)
{
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{domain} = $address_domain;
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{slot} = $address_slot;
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{function} = $address_function;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::controller::${type}::index::${index}::address::type" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{type},
"server::${server}::${source}::device::controller::${type}::index::${index}::address::domain" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{domain},
"server::${server}::${source}::device::controller::${type}::index::${index}::address::bus" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{bus},
"server::${server}::${source}::device::controller::${type}::index::${index}::address::slot" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{slot},
"server::${server}::${source}::device::controller::${type}::index::${index}::address::function" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{function},
}});
# Add to system bus list
# Controller type: [pci], alias: (pci.2), index: [2]
# - Model: [pcie-root-port]
# - Target chassis: [2], port: [0x11]
# - Bus type: [pci], domain: [0x0000], bus: [0x00], slot: [0x02], function: [0x1]
# server::test_server::from_memory::address::virtio-serial::controller::0::bus::0::port::2: [channel - spicevmc]
$anvil->data->{server}{$server}{$source}{address}{$address_type}{controller}{$type}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain} = $address_domain;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::address::${address_type}::controller::${type}::bus::${address_bus}::slot::${address_slot}::function::${address_function}::domain" => $anvil->data->{server}{$server}{$source}{address}{$address_type}{controller}{$type}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain},
}});
}
}
# Find what drives (disk and "optical") this server uses.
foreach my $hash_ref (@{$server_xml->{devices}->[0]->{disk}})
{
#print Dumper $hash_ref;
my $device = $hash_ref->{device};
my $type = $hash_ref->{type};
my $device_target = $hash_ref->{target}->[0]->{dev};
my $device_bus = $hash_ref->{target}->[0]->{bus};
my $address_type = $hash_ref->{address}->[0]->{type};
my $address_bus = $hash_ref->{address}->[0]->{bus};
my $boot_order = defined $hash_ref->{boot}->[0]->{order} ? $hash_ref->{boot}->[0]->{order} : 99;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
device => $device,
type => $type,
device_target => $device_target,
device_bus => $device_bus,
address_type => $address_type,
address_bus => $address_bus,
boot_order => $boot_order,
}});
if ($device eq "disk")
{
my $address_slot = $hash_ref->{address}->[0]->{slot};
my $address_domain = $hash_ref->{address}->[0]->{domain};
my $address_function = $hash_ref->{address}->[0]->{function};
my $device_path = $hash_ref->{source}->[0]->{dev};
$anvil->data->{server}{$server}{$source}{device}{$device}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{$device}{address}{domain} = $address_domain;
$anvil->data->{server}{$server}{$source}{device}{$device}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{$device}{address}{slot} = $address_slot;
$anvil->data->{server}{$server}{$source}{device}{$device}{address}{function} = $address_function;
$anvil->data->{server}{$server}{$source}{device}{$device}{path} = $device_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::${device}::address::type" => $anvil->data->{server}{$server}{$source}{device}{$device}{address}{type},
"server::${server}::${source}::device::${device}::address::domain" => $anvil->data->{server}{$server}{$source}{device}{$device}{address}{domain},
"server::${server}::${source}::device::${device}::address::bus" => $anvil->data->{server}{$server}{$source}{device}{$device}{address}{bus},
"server::${server}::${source}::device::${device}::address::slot" => $anvil->data->{server}{$server}{$source}{device}{$device}{address}{slot},
"server::${server}::${source}::device::${device}::address::function" => $anvil->data->{server}{$server}{$source}{device}{$device}{address}{function},
"server::${server}::${source}::device::${device}::path" => $anvil->data->{server}{$server}{$source}{device}{$device}{path},
}});
$anvil->data->{server}{$server}{$source}{device}{$device_path}{on_lv} = defined $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{on} : "";
$anvil->data->{server}{$server}{$source}{device}{$device_path}{resource} = defined $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{'local'}{drbd_path}{$device_path}{resource} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::${device_path}::on_lv" => $anvil->data->{server}{$server}{$source}{device}{$device_path}{on_lv},
"server::${server}::${source}::device::${device_path}::resource" => $anvil->data->{server}{$server}{$source}{device}{$device_path}{resource},
}});
# $anvil->data->{server}{$server}{$source}{address}{$device_bus}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain} = $address_domain;
# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
# "server::${server}::${source}::address::${address_type}::controller::${type}::bus::${address_bus}::slot::${address_slot}::function::${address_function}::domain" => $anvil->data->{server}{$server}{$source}{address}{$address_type}{controller}{$type}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain},
# }});
}
else
{
# Looks like IDE is no longer supported on RHEL 8.
my $device_path = defined $hash_ref->{source}->[0]->{file} ? $hash_ref->{source}->[0]->{file} : "";
my $address_controller = $hash_ref->{address}->[0]->{controller};
my $address_unit = $hash_ref->{address}->[0]->{unit};
my $address_target = $hash_ref->{address}->[0]->{target};
$anvil->data->{server}{$server}{$source}{device}{$device}{address}{controller} = $address_controller;
$anvil->data->{server}{$server}{$source}{device}{$device}{address}{unit} = $address_unit;
$anvil->data->{server}{$server}{$source}{device}{$device}{address}{target} = $address_target;
$anvil->data->{server}{$server}{$source}{device}{$device}{path} = $device_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::${device}::address::controller" => $anvil->data->{server}{$server}{$source}{device}{$device}{address}{controller},
"server::${server}::${source}::device::${device}::address::unit" => $anvil->data->{server}{$server}{$source}{device}{$device}{address}{unit},
"server::${server}::${source}::device::${device}::address::target" => $anvil->data->{server}{$server}{$source}{device}{$device}{address}{target},
"server::${server}::${source}::device::${device}::path" => $anvil->data->{server}{$server}{$source}{device}{$device}{path},
}});
}
}
die;
# Pull out other devices
foreach my $device (sort {$a cmp $b} keys %{$server_xml->{devices}->[0]})
{
next if $device eq "emulator";
next if $device eq "channel";
print "Device: [$device] -> [".$server_xml->{devices}->[0]->{$device}."] (".@{$server_xml->{devices}->[0]->{$device}}."))\n";
foreach my $hash_ref (@{$server_xml->{devices}->[0]->{$device}})
{
# video, memballoon, rng and sound don't have type.
my $type = defined $hash_ref->{type} ? $hash_ref->{type} : "";
print "- Type: [$type]\n";
#print Dumper $hash_ref;
if ($type)
{
}
}
}
die;
return(0);
}