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