* Created Network->download() to handle downloading a file on the local system. Created ->bridge_info() to parse 'bridge' output. Created ->load_ips() to load IP address information from the database (as opposed to ->get_ips() which queries a system).

* Created Database->insert_or_update_bridge_interfaces() to handle updating the new bridge_interfaces database table that records which network interfaces are connected to which bridges.
* Added 'bridge_mac' and 'bridge_mtu' to the 'bridges' table.
* Started Server->map_network which will, eventually, try to map MAC addresses to IPs and record server -> vnetX -> bridge data. Made getting a server status target-dependent.
* Worked on anvil-update-states to parse and record bridge data.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent 183d2d9cce
commit 7cdd2f60e9
  1. 1
      Anvil/Tools.pm
  2. 246
      Anvil/Tools/Database.pm
  3. 522
      Anvil/Tools/Network.pm
  4. 739
      Anvil/Tools/Server.pm
  5. 52
      ocf/alteeve/server
  6. 114
      share/anvil.sql
  7. 8
      share/words.xml
  8. 5
      tools/anvil-manage-keys
  9. 169
      tools/anvil-update-states
  10. 27
      tools/striker-initialize-host

@ -1174,6 +1174,7 @@ sub _set_paths
}, },
urls => { urls => {
skins => "/skins", skins => "/skins",
oui_file => "http://standards.ieee.org/develop/regauth/oui/oui.txt",
}, },
words => { words => {
'words.xml' => "/usr/share/anvil/words.xml", 'words.xml' => "/usr/share/anvil/words.xml",

@ -26,6 +26,7 @@ my $THIS_FILE = "Database.pm";
# get_jobs # get_jobs
# get_local_uuid # get_local_uuid
# initialize # initialize
# insert_or_update_bridge_interfaces
# insert_or_update_bridges # insert_or_update_bridges
# insert_or_update_bonds # insert_or_update_bonds
# insert_or_update_file_locations # insert_or_update_file_locations
@ -1827,6 +1828,223 @@ sub initialize
return($success); return($success);
}; };
=head2 insert_or_update_bridge_interfaces
This updates (or inserts) a record in the 'bridge_interfaces' table. The C<< bridge_interface_uuid >> referencing the database row will be returned.
If there is an error, an empty string is returned.
Parameters;
=head3 uuid (optional)
If set, only the corresponding database will be written to.
=head3 file (optional)
If set, this is the file name logged as the source of any INSERTs or UPDATEs.
=head3 line (optional)
If set, this is the file line number logged as the source of any INSERTs or UPDATEs.
=head2 bridge_interface_uuid (optional)
If not passed, a check will be made to see if an existing entry is found for C<< bridge_interface_bridge_uuid >> and C<< bridge_interface_network_interface_uuid >>. If found, that entry will be updated. If not found, a new record will be inserted.
=head2 bridge_interface_host_uuid (optional)
This is the host that the IP address is on. If not passed, the local C<< sys::host_uuid >> will be used (indicating it is a local IP address).
=head2 bridge_interface_bridge_uuid (required)
This is the C<< bridges -> bridge_uuid >> of the bridge that this interface is connected to.
=head2 bridge_interface_network_interface_uuid (required)
This is the C<< network_interfaces -> network_interface_uuid >> if the interface connected to the specified bridge.
=cut
sub insert_or_update_bridge_interfaces
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_bridge_interfaces()" }});
my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : "";
my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $line = defined $parameter->{line} ? $parameter->{line} : "";
my $bridge_interface_uuid = defined $parameter->{bridge_interface_uuid} ? $parameter->{bridge_interface_uuid} : "";
my $bridge_interface_host_uuid = defined $parameter->{bridge_interface_host_uuid} ? $parameter->{bridge_interface_host_uuid} : $anvil->data->{sys}{host_uuid};
my $bridge_interface_bridge_uuid = defined $parameter->{bridge_interface_bridge_uuid} ? $parameter->{bridge_interface_bridge_uuid} : "";
my $bridge_interface_network_interface_uuid = defined $parameter->{bridge_interface_network_interface_uuid} ? $parameter->{bridge_interface_network_interface_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
file => $file,
line => $line,
bridge_interface_uuid => $bridge_interface_uuid,
bridge_interface_host_uuid => $bridge_interface_host_uuid,
bridge_interface_bridge_uuid => $bridge_interface_bridge_uuid,
bridge_interface_network_interface_uuid => $bridge_interface_network_interface_uuid,
}});
if (not $bridge_interface_bridge_uuid)
{
# Throw an error and exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_bridge_interfaces()", parameter => "bridge_interface_bridge_uuid" }});
return("");
}
if (not $bridge_interface_network_interface_uuid)
{
# Throw an error and exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_bridge_interfaces()", parameter => "bridge_interface_network_interface_uuid" }});
return("");
}
# If we don't have a UUID, see if we can find one for the given bridge_interface server name.
if (not $bridge_interface_uuid)
{
my $query = "
SELECT
bridge_interface_uuid
FROM
bridge_interfaces
WHERE
bridge_interface_bridge_uuid = ".$anvil->Database->quote($bridge_interface_bridge_uuid)."
AND
bridge_interface_network_interface_uuid = ".$anvil->Database->quote($bridge_interface_network_interface_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if ($count)
{
$bridge_interface_uuid = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bridge_interface_uuid => $bridge_interface_uuid }});
}
}
# If I still don't have an bridge_interface_uuid, we're INSERT'ing .
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bridge_interface_uuid => $bridge_interface_uuid }});
if (not $bridge_interface_uuid)
{
# It's possible that this is called before the host is recorded in the database. So to be
# safe, we'll return without doing anything if there is no host_uuid in the database.
my $hosts = $anvil->Database->get_hosts();
my $found = 0;
foreach my $hash_ref (@{$hosts})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"hash_ref->{host_uuid}" => $hash_ref->{host_uuid},
"sys::host_uuid" => $anvil->data->{sys}{host_uuid},
}});
if ($hash_ref->{host_uuid} eq $anvil->data->{sys}{host_uuid})
{
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
}
}
if (not $found)
{
# We're out.
return("");
}
# INSERT
$bridge_interface_uuid = $anvil->Get->uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bridge_interface_uuid => $bridge_interface_uuid }});
my $query = "
INSERT INTO
bridge_interfaces
(
bridge_interface_uuid,
bridge_interface_host_uuid,
bridge_interface_bridge_uuid,
bridge_interface_network_interface_uuid,
modified_date
) VALUES (
".$anvil->Database->quote($bridge_interface_uuid).",
".$anvil->Database->quote($bridge_interface_host_uuid).",
".$anvil->Database->quote($bridge_interface_bridge_uuid).",
".$anvil->Database->quote($bridge_interface_network_interface_uuid).",
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
);
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
else
{
# Query the rest of the values and see if anything changed.
my $query = "
SELECT
bridge_interface_host_uuid,
bridge_interface_bridge_uuid,
bridge_interface_network_interface_uuid
FROM
bridge_interfaces
WHERE
bridge_interface_uuid = ".$anvil->Database->quote($bridge_interface_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if (not $count)
{
# I have a bridge_interface_uuid but no matching record. Probably an error.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0216", variables => { uuid_name => "bridge_interface_uuid", uuid => $bridge_interface_uuid }});
return("");
}
foreach my $row (@{$results})
{
my $old_bridge_interface_host_uuid = $row->[0];
my $old_bridge_interface_bridge_uuid = $row->[1];
my $old_bridge_interface_network_interface_uuid = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_bridge_interface_host_uuid => $old_bridge_interface_host_uuid,
old_bridge_interface_bridge_uuid => $old_bridge_interface_bridge_uuid,
old_bridge_interface_network_interface_uuid => $old_bridge_interface_network_interface_uuid,
}});
# Anything change?
if (($old_bridge_interface_host_uuid ne $bridge_interface_host_uuid) or
($old_bridge_interface_bridge_uuid ne $bridge_interface_bridge_uuid) or
($old_bridge_interface_network_interface_uuid ne $bridge_interface_network_interface_uuid))
{
# Something changed, save.
my $query = "
UPDATE
bridge_interfaces
SET
bridge_interface_host_uuid = ".$anvil->Database->quote($bridge_interface_host_uuid).",
bridge_interface_bridge_uuid = ".$anvil->Database->quote($bridge_interface_bridge_uuid).",
bridge_interface_network_interface_uuid = ".$anvil->Database->quote($bridge_interface_network_interface_uuid).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
bridge_interface_uuid = ".$anvil->Database->quote($bridge_interface_uuid)."
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
}
}
return($bridge_interface_uuid);
}
=head2 insert_or_update_bridges =head2 insert_or_update_bridges
This updates (or inserts) a record in the 'bridges' table. The C<< bridge_uuid >> referencing the database row will be returned. This updates (or inserts) a record in the 'bridges' table. The C<< bridge_uuid >> referencing the database row will be returned.
@ -1863,6 +2081,14 @@ This is the bridge's device name.
This is the unique identifier for the bridge. This is the unique identifier for the bridge.
=head2 bridge_mac (optional)
This is the MAC address of the bridge.
=head2 bridge_mto (optional)
This is the MTU (maximum transfer unit, size in bytes) of the bridge.
=head2 bridge_stp_enabled (optional) =head2 bridge_stp_enabled (optional)
This is set to C<< yes >> or C<< no >> to indicate if spanning tree protocol is enabled on the switch. This is set to C<< yes >> or C<< no >> to indicate if spanning tree protocol is enabled on the switch.
@ -1883,6 +2109,8 @@ sub insert_or_update_bridges
my $bridge_host_uuid = defined $parameter->{bridge_host_uuid} ? $parameter->{bridge_host_uuid} : $anvil->data->{sys}{host_uuid}; my $bridge_host_uuid = defined $parameter->{bridge_host_uuid} ? $parameter->{bridge_host_uuid} : $anvil->data->{sys}{host_uuid};
my $bridge_name = defined $parameter->{bridge_name} ? $parameter->{bridge_name} : ""; my $bridge_name = defined $parameter->{bridge_name} ? $parameter->{bridge_name} : "";
my $bridge_id = defined $parameter->{bridge_id} ? $parameter->{bridge_id} : ""; my $bridge_id = defined $parameter->{bridge_id} ? $parameter->{bridge_id} : "";
my $bridge_mac = defined $parameter->{bridge_mac} ? $parameter->{bridge_mac} : "";
my $bridge_mtu = defined $parameter->{bridge_mtu} ? $parameter->{bridge_mtu} : "";
my $bridge_stp_enabled = defined $parameter->{bridge_stp_enabled} ? $parameter->{bridge_stp_enabled} : ""; my $bridge_stp_enabled = defined $parameter->{bridge_stp_enabled} ? $parameter->{bridge_stp_enabled} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid, uuid => $uuid,
@ -1892,6 +2120,8 @@ sub insert_or_update_bridges
bridge_host_uuid => $bridge_host_uuid, bridge_host_uuid => $bridge_host_uuid,
bridge_name => $bridge_name, bridge_name => $bridge_name,
bridge_id => $bridge_id, bridge_id => $bridge_id,
bridge_mac => $bridge_mac,
bridge_mtu => $bridge_mtu,
bridge_stp_enabled => $bridge_stp_enabled, bridge_stp_enabled => $bridge_stp_enabled,
}}); }});
@ -1968,6 +2198,8 @@ INSERT INTO
bridge_host_uuid, bridge_host_uuid,
bridge_name, bridge_name,
bridge_id, bridge_id,
bridge_mac,
bridge_mtu,
bridge_stp_enabled, bridge_stp_enabled,
modified_date modified_date
) VALUES ( ) VALUES (
@ -1975,6 +2207,8 @@ INSERT INTO
".$anvil->Database->quote($bridge_host_uuid).", ".$anvil->Database->quote($bridge_host_uuid).",
".$anvil->Database->quote($bridge_name).", ".$anvil->Database->quote($bridge_name).",
".$anvil->Database->quote($bridge_id).", ".$anvil->Database->quote($bridge_id).",
".$anvil->Database->quote($bridge_mac).",
".$anvil->Database->quote($bridge_mtu).",
".$anvil->Database->quote($bridge_stp_enabled).", ".$anvil->Database->quote($bridge_stp_enabled).",
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
); );
@ -1990,6 +2224,8 @@ SELECT
bridge_host_uuid, bridge_host_uuid,
bridge_name, bridge_name,
bridge_id, bridge_id,
bridge_mac,
bridge_mtu,
bridge_stp_enabled bridge_stp_enabled
FROM FROM
bridges bridges
@ -2015,11 +2251,15 @@ WHERE
my $old_bridge_host_uuid = $row->[0]; my $old_bridge_host_uuid = $row->[0];
my $old_bridge_name = $row->[1]; my $old_bridge_name = $row->[1];
my $old_bridge_id = $row->[2]; my $old_bridge_id = $row->[2];
my $old_bridge_stp_enabled = $row->[3]; my $old_bridge_mac = $row->[3];
my $old_bridge_mtu = $row->[4];
my $old_bridge_stp_enabled = $row->[5];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_bridge_host_uuid => $old_bridge_host_uuid, old_bridge_host_uuid => $old_bridge_host_uuid,
old_bridge_name => $old_bridge_name, old_bridge_name => $old_bridge_name,
old_bridge_id => $old_bridge_id, old_bridge_id => $old_bridge_id,
old_bridge_mac => $old_bridge_mac,
old_bridge_mtu => $old_bridge_mtu,
old_bridge_stp_enabled => $old_bridge_stp_enabled, old_bridge_stp_enabled => $old_bridge_stp_enabled,
}}); }});
@ -2027,6 +2267,8 @@ WHERE
if (($old_bridge_host_uuid ne $bridge_host_uuid) or if (($old_bridge_host_uuid ne $bridge_host_uuid) or
($old_bridge_name ne $bridge_name) or ($old_bridge_name ne $bridge_name) or
($old_bridge_id ne $bridge_id) or ($old_bridge_id ne $bridge_id) or
($old_bridge_mac ne $bridge_mac) or
($old_bridge_mtu ne $bridge_mtu) or
($old_bridge_stp_enabled ne $bridge_stp_enabled)) ($old_bridge_stp_enabled ne $bridge_stp_enabled))
{ {
# Something changed, save. # Something changed, save.
@ -2037,6 +2279,8 @@ SET
bridge_host_uuid = ".$anvil->Database->quote($bridge_host_uuid).", bridge_host_uuid = ".$anvil->Database->quote($bridge_host_uuid).",
bridge_name = ".$anvil->Database->quote($bridge_name).", bridge_name = ".$anvil->Database->quote($bridge_name).",
bridge_id = ".$anvil->Database->quote($bridge_id).", bridge_id = ".$anvil->Database->quote($bridge_id).",
bridge_mac = ".$anvil->Database->quote($bridge_mac).",
bridge_mtu = ".$anvil->Database->quote($bridge_mtu).",
bridge_stp_enabled = ".$anvil->Database->quote($bridge_stp_enabled).", bridge_stp_enabled = ".$anvil->Database->quote($bridge_stp_enabled).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE WHERE

@ -12,12 +12,15 @@ our $VERSION = "3.0.0";
my $THIS_FILE = "Network.pm"; my $THIS_FILE = "Network.pm";
### Methods; ### Methods;
# bridge_info
# check_internet # check_internet
# download
# find_matches # find_matches
# get_ips # get_ips
# get_network # get_network
# is_local # is_local
# is_remote # is_remote
# load_ips
# ping # ping
=pod =pod
@ -79,6 +82,131 @@ sub parent
# Public methods # # Public methods #
############################################################################################################# #############################################################################################################
=head2 bridge_info
This calls C<< bridge >> to get data on interfaces connected to bridges. A list of interfaces to connected to each bridge is stored here;
* bridge::<target>::<bridge_name>::interfaces = Array reference of interfaces connected this bridge
The rest of the variable / value pairs are stored here. See C<< man bridge -> state >> for more information of these values
* bridge::<target>::<bridge_name>::<interface_name>::<variable> = <value>
The common variables are;
* bridge::<target>::<bridge_name>::<interface_name>::ifindex = Interface index number.
* bridge::<target>::<bridge_name>::<interface_name>::flags = An array reference storing the flags set for the interface on the bridge.
* bridge::<target>::<bridge_name>::<interface_name>::mtu = The maximum transmitable unit size, in bytes.
* bridge::<target>::<bridge_name>::<interface_name>::state = The state of the bridge.
* bridge::<target>::<bridge_name>::<interface_name>::priority = The priority for this interface.
* bridge::<target>::<bridge_name>::<interface_name>::cost = The cost of this interface.
Paramters;
=head3 password (optional)
If C<< target >> is set, this is the password used to log into the remote system as the C<< remote_user >>. If it is not set, an attempt to connect without a password will be made (though this will usually fail).
=head3 port (optional, default 22)
If C<< target >> is set, this is the TCP port number used to connect to the remote machine.
=head3 remote_user (optional)
If C<< target >> is set, this is the user account that will be used when connecting to the remote system.
=head3 target (optional, default 'local')
If set, the bridge data will be read from the target machine. This needs to be the IP address or (resolvable) host name of the target.
=cut
sub bridge_info
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->bridge_info()" }});
my $password = defined $parameter->{password} ? $parameter->{password} : "";
my $port = defined $parameter->{port} ? $parameter->{port} : 22;
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $target = defined $parameter->{target} ? $parameter->{target} : "local";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
password => $anvil->Log->is_secure($password),
port => $port,
remote_user => $remote_user,
target => $target,
}});
my $shell_call = $anvil->data->{path}{exe}{bridge}." -json -pretty link show";
my $output = "";
if ($anvil->Network->is_remote($target))
{
# Remote call
($output, my $error, my $return_code) = $anvil->Remote->call({
debug => $debug,
shell_call => $shell_call,
target => $target,
user => $remote_user,
password => $password,
remote_user => $remote_user,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:output' => $output,
's2:error' => $error,
's3:return_code' => $return_code,
}});
}
else
{
# Local call.
($output, my $return_code) = $anvil->System->call({debug => $debug, shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:output' => $output,
's2:return_code' => $return_code,
}});
}
# Did I get usable data?
if ($output !~ /^\[/)
{
# Bad data.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0443", variables => { output => $output }});
return(1);
}
my $json = JSON->new->allow_nonref;
my $bridge_data = $json->decode($output);
foreach my $hash_ref (@{$bridge_data})
{
my $bridge = $hash_ref->{master};
my $interface = $hash_ref->{ifname};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:bridge' => $bridge,
's2:interface' => $interface,
}});
if ((not exists $anvil->data->{bridge}{$target}{$bridge}) or (ref($anvil->data->{bridge}{$target}{$bridge}{interfaces}) ne "ARRAY"))
{
$anvil->data->{bridge}{$target}{$bridge}{interfaces} = [];
}
push @{$anvil->data->{bridge}{$target}{$bridge}{interfaces}}, $interface;
# Now store the rest of the data.
foreach my $key (sort {$a cmp $b} keys %{$hash_ref})
{
next if $key eq "master";
next if $key eq "ifname";
$anvil->data->{bridge}{$target}{$bridge}{$interface}{$key} = $hash_ref->{$key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"bridge::${target}::${bridge}::${interface}::${key}" => $anvil->data->{bridge}{$target}{$bridge}{$interface}{$key},
}});
}
}
return(0);
}
=head2 check_internet =head2 check_internet
This method tries to connect to the internet. If successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. This method tries to connect to the internet. If successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned.
@ -118,7 +246,7 @@ sub check_internet
my $parameter = shift; my $parameter = shift;
my $anvil = $self->parent; my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; 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_matches()" }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->check_internet()" }});
my $access = 0; my $access = 0;
my $domains = defined $parameter->{domains} ? $parameter->{domains} : $anvil->data->{defaults}{network}{test}{domains}; my $domains = defined $parameter->{domains} ? $parameter->{domains} : $anvil->data->{defaults}{network}{test}{domains};
@ -196,6 +324,211 @@ sub check_internet
return($access); return($access);
} }
=head2 download
This downloads a file from a network target and saves it to a local file. This must be called on a local system so that the download progress can be reported.
On success, the saved file is returned. On failure, an empty string is returned.
Parameters;
=head3 save_to (optional)
If set, this is where the file will be downloaded to. If this ends with C<< / >>, the file name is preserved from the C<< url >> and will be saved in the C<< save_to >>'s directory with the original file name. Otherwise, the downlaoded file is saved with the file name given. As such, be careful about the trailing C<< / >>!
When not specified, the file name in the URL will be used and the file will be saved in the active user's home directory.
=head3 status (optional, default '1')
When set to C<< 1 >>, a periodic status message is printed. When set to C<< 0 >>, no status will be printed.
=head3 url (required)
This is the URL to the file to download.
=cut
sub download
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->get_ips()" }});
my $save_to = defined $parameter->{save_to} ? $parameter->{save_to} : "";
my $status = defined $parameter->{status} ? $parameter->{status} : 1;
my $url = defined $parameter->{url} ? $parameter->{url} : "";
my $uuid = $anvil->Get->uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
save_to => $save_to,
status => $status,
url => $url,
uuid => $uuid,
}});
if (not $url)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->download()", parameter => "url" }});
return("");
}
elsif (($url !~ /^ftp\:\/\//) && ($url !~ /^http\:\/\//) && ($url !~ /^https\:\/\//))
{
# Invalid URL.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0085", variables => { url => $url }});
return("");
}
# The name of the file to be downloaded will be used if the path isn't specified, or if it ends in '/'.
my $source_file = ($url =~ /^.*\/(.*)$/)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { source_file => $source_file }});
if (not $save_to)
{
$save_to = $anvil->Get->users_home({debug => $debug})."/".$source_file;
$save_to =~ s/\/\//\//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { save_to => $save_to }});
}
elsif ($save_to =~ /\/$/)
{
$save_to .= "/".$source_file;
$save_to =~ s/\/\//\//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { save_to => $save_to }});
}
### TODO: Make this work well as a job
my $status_file = "/tmp/".$source_file.".download_status";
my $bytes_downloaded = 0;
my $running_time = 0;
my $average_rate = 0;
my $start_printed = 0;
my $percent = 0;
my $rate = 0; # Bytes/sec
my $downloaded = 0; # Bytes
my $time_left = 0; # Seconds
my $report_interval = 5; # Seconds between status file update
my $next_report = time + $report_interval;
# This should print to a status file
print "uuid=$uuid bytes_downloaded=0 percent=0 current_rate=0 average_rate=0 seconds_running=0 seconds_left=0 url=$url save_to=$save_to\n" if $status;;
# Download command
my $unix_start = 0;
my $shell_call = $anvil->data->{path}{exe}{wget}." -c --progress=dot:binary ".$url." -O ".$save_to;
my $output = "";
open (my $file_handle, $shell_call." 2>&1 |") or $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, priority => "err", key => "log_0014", variables => { shell_call => $shell_call, error => $! }});
while(<$file_handle>)
{
chomp;
my $line = $_;
$line =~ s/^\s+//;
$line =~ s/\s+$//;
$line =~ s/\s+/ /g;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, key => "log_0017", variables => { line => $line }});
if (($line =~ /404/) && ($line =~ /Not Found/i))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, priority => "err", key => "error_0086", variables => { urk => $url }});
return("");
}
if ($line =~ /Name or service not known/i)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, priority => "err", key => "error_0087", variables => { urk => $url }});
return("");
}
if ($line =~ /Connection refused/i)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, priority => "err", key => "error_0088", variables => { urk => $url }});
return("");
}
if ($line =~ /route to host/i)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, priority => "err", key => "error_0089", variables => { urk => $url }});
return("");
}
if ($line =~ /Network is unreachable/i)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, secure => 0, priority => "err", key => "error_0090", variables => { urk => $url }});
return("");
}
if ($line =~ /^(\d+)K .*? (\d+)% (.*?) (\d+.*)$/)
{
$downloaded = $1;
$percent = $2;
$rate = $3;
$time_left = $4;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
downloaded => $downloaded,
percent => $percent,
rate => $rate,
time_left => $time_left,
}});
if (not $start_printed)
{
### NOTE: This is meant to be parsed by a script, so don't translate it.
print "started:$uuid\n" if $status;
$start_printed = 1;
}
### NOTE: According to: http://savannah.gnu.org/bugs/index.php?22765, wget uses base-2.
# Convert
$bytes_downloaded = $downloaded * 1024;
my $say_downloaded = $anvil->Convert->bytes_to_human_readable({'bytes' => $bytes_downloaded});
my $say_percent = $percent."%";
my $byte_rate = $anvil->Convert->human_readable_to_bytes({size => $rate, base2 => 1});
my $say_rate = $anvil->Convert->bytes_to_human_readable({'bytes' => $byte_rate})."/s";
$running_time = time - $unix_start;
my $say_running_time = $anvil->Convert->time({'time' => $running_time, translate => 1});
# Time left is a bit more complicated
my $days = 0;
my $hours = 0;
my $minutes = 0;
my $seconds = 0;
if ($time_left =~ /(\d+)d/)
{
$days = $1;
#print "$THIS_FILE ".__LINE__."; == days: [$days]\n";
}
if ($time_left =~ /(\d+)h/)
{
$hours = $1;
#print "$THIS_FILE ".__LINE__."; == hours: [$hours]\n";
}
if ($time_left =~ /(\d+)m/)
{
$minutes = $1;
#print "$THIS_FILE ".__LINE__."; == minutes: [$minutes]\n";
}
if ($time_left =~ /(\d+)s/)
{
$seconds = $1;
#print "$THIS_FILE ".__LINE__."; == seconds: [$seconds]\n";
}
my $seconds_left = (($days * 86400) + ($hours * 3600) + ($minutes * 60) + $seconds);
my $say_time_left = $anvil->Convert->time({'time' => $seconds_left, long => 1, translate => 1});
$running_time = 1 if not $running_time;
$average_rate = int($bytes_downloaded / $running_time);
my $say_average_rate = $anvil->Convert->bytes_to_human_readable({'bytes' => $average_rate})."/s";
#print "$THIS_FILE ".__LINE__."; downloaded: [$downloaded], bytes_downloaded: [$bytes_downloaded], say_downloaded: [$say_downloaded], percent: [$percent], rate: [$rate], byte_rate: [$byte_rate], say_rate: [$say_rate], time_left: [$time_left]\n";
if (time > $next_report)
{
#print "$THIS_FILE ".__LINE__."; say_downloaded: [$say_downloaded], percent: [$percent], say_rate: [$say_rate], running_time: [$running_time], say_running_time: [$say_running_time], seconds_left: [$seconds_left], say_time_left: [$say_time_left]\n";
#print "$file; Downloaded: [$say_downloaded]/[$say_percent], Rate/Avg: [$say_rate]/[$say_average_rate], Running: [$say_running_time], Left: [$say_time_left]\n";
#print "$THIS_FILE ".__LINE__."; bytes_downloaded=$bytes_downloaded, percent=$percent, current_rate=$byte_rate, average_rate=$average_rate, seconds_running=$running_time, seconds_left=$seconds_left, save_to=$save_to\n";
$next_report += $report_interval;
# This should print to a status file
print "uuid=$uuid bytes_downloaded=$bytes_downloaded percent=$percent current_rate=$byte_rate average_rate=$average_rate seconds_running=$running_time seconds_left=$seconds_left url=$url save_to=$save_to\n" if $status;
}
}
}
close $file_handle;
chomp($output);
return($save_to);
}
=head2 find_matches =head2 find_matches
This takes two hash keys from prior C<< Network->get_ips() >> runs and finds which are on the same network. This takes two hash keys from prior C<< Network->get_ips() >> runs and finds which are on the same network.
@ -301,6 +634,193 @@ sub find_matches
return($match); return($match);
} }
=head2 load_ips
This method loads and stores the same data as the C<< get_ips >> method, but does so by loading data from the database, instead of collecting it directly from the host. As such, it can also be used by C<< find_matches >>.
The loaded data will be stored as:
* C<< network::<target>::interface::<iface_name>::ip >> - If an IP address is set
* C<< network::<target>::interface::<iface_name>::subnet >> - If an IP is set
* C<< network::<target>::interface::<iface_name>::mac >> - Always set.
* C<< network::<target>::interface::<iface_name>::default_gateway >> = C<< 0 >> if not the default gateway, C<< 1 >> if so.
* C<< network::<target>::interface::<iface_name>::gateway >> = If the default gateway, this is the gateway IP address.
* C<< network::<target>::interface::<iface_name>::dns >> = If the default gateway, this is the comma-separated list of active DNS servers.
Parameters;
=head3 host_uuid (required)
This is the C<< host_uuid >> of the hosts whose IP and interface data that you want to load.
=head3 target (optional, default is 'host_uuid' value)
This is the optional C<< target >> string to use in the hash where the data is stored.
=cut
sub load_ips
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->find_matches()" }});
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : "";
my $target = defined $parameter->{target} ? $parameter->{target} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
target => $target,
host_uuid => $host_uuid,
}});
if (not $host_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->get_network()", parameter => "ip" }});
return("");
}
if (not $target)
{
$target = $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target => $target }});
}
my $query = "
SELECT
ip_address_address,
ip_address_subnet_mask,
ip_address_gateway,
ip_address_default_gateway,
ip_address_dns,
ip_address_on_type,
ip_address_on_uuid
FROM
ip_addresses
WHERE
ip_address_on_type != 'DELETED'
AND
ip_address_host_uuid = ".$anvil->Database->quote($host_uuid)."
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $ip_address_address = $row->[0];
my $ip_address_subnet_mask = $row->[1];
my $ip_address_gateway = $row->[2];
my $ip_address_default_gateway = $row->[3];
my $ip_address_dns = $row->[4];
my $ip_address_on_type = $row->[5];
my $ip_address_on_uuid = $row->[6];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ip_address_address => $ip_address_address,
ip_address_subnet_mask => $ip_address_subnet_mask,
ip_address_gateway => $ip_address_gateway,
ip_address_default_gateway => $ip_address_default_gateway,
ip_address_dns => $ip_address_dns,
ip_address_on_type => $ip_address_on_type,
ip_address_on_uuid => $ip_address_on_uuid,
}});
my $interface_name = "";
my $interface_mac = "";
if ($ip_address_on_type eq "interface")
{
my $query = "
SELECT
network_interface_name,
network_interface_mac_address
FROM
network_interfaces
WHERE
network_interface_uuid = ".$anvil->Database->quote($ip_address_on_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
$interface_name = $results->[0]->[0];
$interface_mac = $results->[0]->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
interface_name => $interface_name,
interface_mac => $interface_mac,
}});
}
elsif ($ip_address_on_type eq "bond")
{
my $query = "
SELECT
bond_name,
bond_mac_address
FROM
bonds
WHERE
bond_uuid = ".$anvil->Database->quote($ip_address_on_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
$interface_name = $results->[0]->[0];
$interface_mac = $results->[0]->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
interface_name => $interface_name,
interface_mac => $interface_mac,
}});
}
elsif ($ip_address_on_type eq "bridge")
{
my $query = "
SELECT
bond_name,
bond_mac_address
FROM
bonds
WHERE
bond_uuid = ".$anvil->Database->quote($ip_address_on_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
$interface_name = $results->[0]->[0];
$interface_mac = $results->[0]->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
interface_name => $interface_name,
interface_mac => $interface_mac,
}});
}
$anvil->data->{network}{$target}{interface}{$interface_name}{ip} = "" if not defined $anvil->data->{network}{$target}{interface}{$interface_name}{ip};
$anvil->data->{network}{$target}{interface}{$interface_name}{subnet} = "" if not defined $anvil->data->{network}{$target}{interface}{$interface_name}{subnet};
$anvil->data->{network}{$target}{interface}{$interface_name}{mac} = "" if not defined $anvil->data->{network}{$target}{interface}{$interface_name}{mac};
$anvil->data->{network}{$target}{interface}{$interface_name}{default_gateway} = 0 if not defined $anvil->data->{network}{$target}{interface}{$interface_name}{default_gateway};
$anvil->data->{network}{$target}{interface}{$interface_name}{gateway} = "" if not defined $anvil->data->{network}{$target}{interface}{$interface_name}{gateway};
$anvil->data->{network}{$target}{interface}{$interface_name}{dns} = "" if not defined $anvil->data->{network}{$target}{interface}{$interface_name}{dns};
}
return(0);
}
=head2 get_ips =head2 get_ips
This method checks the local system for interfaces and stores them in: This method checks the local system for interfaces and stores them in:

@ -15,6 +15,7 @@ my $THIS_FILE = "Server.pm";
# boot # boot
# find # find
# get_status # get_status
# map_network
# migrate # migrate
# shutdown # shutdown
@ -288,7 +289,7 @@ sub find
=head2 get_status =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 under 'server::<server_name>::from_disk::x' for data from the on-disk XML and 'server::<server_name>::from_memory::x'. 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 under C<< server::<target>::<server_name>::from_disk::x >> for data from the on-disk XML and C<< server::<target>>::<server_name>::from_memory::x >>.
Any pre-existing data on the server is flushed before the new information is processed. Any pre-existing data on the server is flushed before the new information is processed.
@ -339,11 +340,11 @@ sub get_status
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->get_status()", parameter => "server" }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->get_status()", parameter => "server" }});
return(1); return(1);
} }
if (exists $anvil->data->{server}{$server}) if (exists $anvil->data->{server}{$target}{$server})
{ {
delete $anvil->data->{server}{$server}; delete $anvil->data->{server}{$target}{$server};
} }
$anvil->data->{server}{$server}{from_memory}{host} = ""; $anvil->data->{server}{$target}{$server}{from_memory}{host} = "";
# We're going to map DRBD devices to resources, so we need to collect that data now. # We're going to map DRBD devices to resources, so we need to collect that data now.
$anvil->DRBD->get_devices({ $anvil->DRBD->get_devices({
@ -361,7 +362,7 @@ sub get_status
{ {
# Remote call. # Remote call.
$host = $target; $host = $target;
($anvil->data->{server}{$server}{from_memory}{xml}, my $error, $anvil->data->{server}{$server}{from_memory}{return_code}) = $anvil->Remote->call({ ($anvil->data->{server}{$target}{$server}{from_memory}{xml}, my $error, $anvil->data->{server}{$target}{$server}{from_memory}{return_code}) = $anvil->Remote->call({
debug => $debug, debug => $debug,
shell_call => $shell_call, shell_call => $shell_call,
target => $target, target => $target,
@ -371,39 +372,39 @@ sub get_status
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
error => $error, error => $error,
"server::${server}::from_memory::xml" => $anvil->data->{server}{$server}{from_memory}{xml}, "server::${target}::${server}::from_memory::xml" => $anvil->data->{server}{$target}{$server}{from_memory}{xml},
"server::${server}::from_memory::return_code" => $anvil->data->{server}{$server}{from_memory}{return_code}, "server::${target}::${server}::from_memory::return_code" => $anvil->data->{server}{$target}{$server}{from_memory}{return_code},
}}); }});
} }
else else
{ {
# Local. # Local.
($anvil->data->{server}{$server}{from_memory}{xml}, $anvil->data->{server}{$server}{from_memory}{return_code}) = $anvil->System->call({shell_call => $shell_call}); ($anvil->data->{server}{$target}{$server}{from_memory}{xml}, $anvil->data->{server}{$target}{$server}{from_memory}{return_code}) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::from_memory::xml" => $anvil->data->{server}{$server}{from_memory}{xml}, "server::${target}::${server}::from_memory::xml" => $anvil->data->{server}{$target}{$server}{from_memory}{xml},
"server::${server}::from_memory::return_code" => $anvil->data->{server}{$server}{from_memory}{return_code}, "server::${target}::${server}::from_memory::return_code" => $anvil->data->{server}{$target}{$server}{from_memory}{return_code},
}}); }});
} }
# If the return code was non-zero, we can't parse the XML. # If the return code was non-zero, we can't parse the XML.
if ($anvil->data->{server}{$server}{from_memory}{return_code}) if ($anvil->data->{server}{$target}{$server}{from_memory}{return_code})
{ {
$anvil->data->{server}{$server}{from_memory}{xml} = ""; $anvil->data->{server}{$target}{$server}{from_memory}{xml} = "";
} }
else else
{ {
$anvil->data->{server}{$server}{from_memory}{host} = $host; $anvil->data->{server}{$target}{$server}{from_memory}{host} = $host;
$anvil->Server->_parse_definition({ $anvil->Server->_parse_definition({
debug => $debug, debug => $debug,
host => $host, host => $host,
server => $server, server => $server,
source => "from_memory", source => "from_memory",
definition => $anvil->data->{server}{$server}{from_memory}{xml}, definition => $anvil->data->{server}{$target}{$server}{from_memory}{xml},
}); });
} }
# Now get the on-disk XML. # Now get the on-disk XML.
($anvil->data->{server}{$server}{from_disk}{xml}) = $anvil->Storage->read_file({ ($anvil->data->{server}{$target}{$server}{from_disk}{xml}) = $anvil->Storage->read_file({
debug => $debug, debug => $debug,
password => $password, password => $password,
port => $port, port => $port,
@ -413,12 +414,12 @@ sub get_status
file => $anvil->data->{path}{directories}{shared}{definitions}."/".$server.".xml", file => $anvil->data->{path}{directories}{shared}{definitions}."/".$server.".xml",
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::from_disk::xml" => $anvil->data->{server}{$server}{from_disk}{xml}, "server::${target}::${server}::from_disk::xml" => $anvil->data->{server}{$target}{$server}{from_disk}{xml},
}}); }});
if (($anvil->data->{server}{$server}{from_disk}{xml} eq "!!errer!!") or (not $anvil->data->{server}{$server}{from_disk}{xml})) if (($anvil->data->{server}{$target}{$server}{from_disk}{xml} eq "!!errer!!") or (not $anvil->data->{server}{$target}{$server}{from_disk}{xml}))
{ {
# Failed to read it. # Failed to read it.
$anvil->data->{server}{$server}{from_disk}{xml} = ""; $anvil->data->{server}{$target}{$server}{from_disk}{xml} = "";
} }
else else
{ {
@ -427,13 +428,226 @@ sub get_status
host => $host, host => $host,
server => $server, server => $server,
source => "from_disk", source => "from_disk",
definition => $anvil->data->{server}{$server}{from_disk}{xml}, definition => $anvil->data->{server}{$target}{$server}{from_disk}{xml},
}); });
} }
return(0); return(0);
} }
=head2 map_network
This method maps the network for any servers B<< running >> on the C<< target >>.
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 refresh (optional, default '1')
Is set to C<< 0 >>, any previously seen servers and their information is cleared.
=head3 remote_user (optional, default 'root')
If C<< target >> is set, this will be the user we connect to the remote machine as.
=head3 target (optional, default 'local')
This is the IP or host name of the host to map the network of hosted servers on.
=cut
sub map_network
{
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->is_secure($password),
port => $port,
remote_user => $remote_user,
target => $target,
}});
# NOTE: We don't use 'Server->find' as the hassle of tracking hosts to target isn't worth it.
# Get a list of servers.
my $shell_call = $anvil->data->{path}{exe}{virsh}." list";
my $output = "";
if ($anvil->Network->is_remote($target))
{
# Remote call.
($output, my $error, my $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,
output => $output,
return_code => $return_code,
}});
}
else
{
# Local.
($output, my $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
}
foreach my $line (split/\n/, $output)
{
$line = $anvil->Words->clean_spaces({string => $line});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^\d+ (.*) (.*?)$/)
{
my $server = $1;
my $state = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server => $server,
'state' => $state,
}});
# Parse the data on this server.
$anvil->Server->get_status({
debug => $debug,
server => $server,
password => $password,
port => $port,
remote_user => $remote_user,
target => $target,
});
foreach my $mac (sort {$a cmp $b} keys %{$anvil->data->{server}{$target}{$server}{from_memory}{device}{interface}})
{
my $device = $anvil->data->{server}{$target}{$server}{from_memory}{device}{interface}{$mac}{target};
my $bridge = $anvil->data->{server}{$target}{$server}{from_memory}{device}{interface}{$mac}{bridge};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:device' => $device,
's2:mac' => $mac,
's3:bridge' => $bridge,
}});
}
}
}
return(0);
}
=head2 migrate
This will migrate (push or pull) a server from one node to another. If the migration was successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned with a (hopefully) useful error being logged.
NOTE: It is assumed that sanity checks are completed before this method is called.
Parameters;
=head3 server (required)
This is the name of the server being migrated.
=head3 source (optional)
This is the host name (or IP) of the host that we're pulling the server from.
If set, the server will be pulled.
=head3 target (optional, defaukt is the full local host name)
This is the host name (or IP) Of the host that the server will be pushed to, if C<< source >> is not set. When this is not passed, the local full host name is used as default.
=cut
sub migrate
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $source = defined $parameter->{source} ? $parameter->{source} : "";
my $target = defined $parameter->{target} ? $parameter->{target} : $anvil->_host_name;
#my $target = defined $parameter->{target} ? $parameter->{target} : "local";
my $success = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server => $server,
source => $source,
target => $target,
}});
if (not $server)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->migrate()", parameter => "server" }});
return($success);
}
# Enable dual-primary for any resources we know about for this server.
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$target}{$server}{resource}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { resource => $resource }});
my ($return_code) = $anvil->DRBD->allow_two_primaries({
debug => $debug,
resource => $resource,
});
}
my $migration_command = $anvil->data->{path}{exe}{virsh}." migrate --undefinesource --tunnelled --p2p --live ".$server." qemu+ssh://".$target."/system";
if ($source)
{
$migration_command = $anvil->data->{path}{exe}{virsh}." -c qemu+ssh://root\@".$source."/system migrate --undefinesource --tunnelled --p2p --live ".$server." qemu+ssh://".$target."/system";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { migration_command => $migration_command }});
# Call the migration now
my ($output, $return_code) = $anvil->System->call({shell_call => $migration_command});
if ($return_code)
{
# Something went wrong.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0353", variables => {
server => $server,
target => $target,
return_code => $return_code,
output => $output,
}});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0354"});
$success = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { success => $success }});
}
# Switch off dual-primary.
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$target}{$server}{resource}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { resource => $resource }});
$anvil->DRBD->reload_defaults({
debug => $debug,
resource => $resource,
});
}
return($success);
}
=head2 shutdown =head2 shutdown
This takes a server name and tries to shut it down. If the server was found locally, the shut down is requested and this method will wait for the server to actually shut down before returning. This takes a server name and tries to shut it down. If the server was found locally, the shut down is requested and this method will wait for the server to actually shut down before returning.
@ -644,102 +858,6 @@ sub shutdown
return($success); return($success);
} }
=head2 migrate
This will migrate (push or pull) a server from one node to another. If the migration was successful, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned with a (hopefully) useful error being logged.
NOTE: It is assumed that sanity checks are completed before this method is called.
Parameters;
=head3 server (required)
This is the name of the server being migrated.
=head3 source (optional)
This is the host name (or IP) of the host that we're pulling the server from.
If set, the server will be pulled.
=head3 target (optional, defaukt is the full local host name)
This is the host name (or IP) Of the host that the server will be pushed to, if C<< source >> is not set. When this is not passed, the local full host name is used as default.
=cut
sub migrate
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $source = defined $parameter->{source} ? $parameter->{source} : "";
my $target = defined $parameter->{target} ? $parameter->{target} : $anvil->_host_name;
my $success = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server => $server,
source => $source,
target => $target,
}});
if (not $server)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->migrate()", parameter => "server" }});
return($success);
}
# Enable dual-primary for any resources we know about for this server.
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{resource}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { resource => $resource }});
my ($return_code) = $anvil->DRBD->allow_two_primaries({
debug => $debug,
resource => $resource,
});
}
my $migration_command = $anvil->data->{path}{exe}{virsh}." migrate --undefinesource --tunnelled --p2p --live ".$server." qemu+ssh://".$target."/system";
if ($source)
{
$migration_command = $anvil->data->{path}{exe}{virsh}." -c qemu+ssh://root\@".$source."/system migrate --undefinesource --tunnelled --p2p --live ".$server." qemu+ssh://".$target."/system";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { migration_command => $migration_command }});
# Call the migration now
my ($output, $return_code) = $anvil->System->call({shell_call => $migration_command});
if ($return_code)
{
# Something went wrong.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0353", variables => {
server => $server,
target => $target,
return_code => $return_code,
output => $output,
}});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0354"});
$success = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { success => $success }});
}
# Switch off dual-primary.
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{resource}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { resource => $resource }});
$anvil->DRBD->reload_defaults({
debug => $debug,
resource => $resource,
});
}
return($success);
}
# =head3 # =head3
# #
# Private Functions; # Private Functions;
@ -764,6 +882,7 @@ sub _parse_definition
my $source = defined $parameter->{source} ? $parameter->{source} : ""; my $source = defined $parameter->{source} ? $parameter->{source} : "";
my $definition = defined $parameter->{definition} ? $parameter->{definition} : ""; my $definition = defined $parameter->{definition} ? $parameter->{definition} : "";
my $host = defined $parameter->{host} ? $parameter->{host} : $anvil->_short_host_name; my $host = defined $parameter->{host} ? $parameter->{host} : $anvil->_short_host_name;
my $target = "local";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server => $server, server => $server,
source => $source, source => $source,
@ -801,73 +920,73 @@ sub _parse_definition
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
$anvil->data->{server}{$server}{$source}{parsed} = $server_xml; $anvil->data->{server}{$target}{$server}{$source}{parsed} = $server_xml;
#print Dumper $server_xml; #print Dumper $server_xml;
#die; #die;
# Pull out some basic server info. # Pull out some basic server info.
$anvil->data->{server}{$server}{$source}{info}{uuid} = $server_xml->{uuid}->[0]; $anvil->data->{server}{$target}{$server}{$source}{info}{uuid} = $server_xml->{uuid}->[0];
$anvil->data->{server}{$server}{$source}{info}{name} = $server_xml->{name}->[0]; $anvil->data->{server}{$target}{$server}{$source}{info}{name} = $server_xml->{name}->[0];
$anvil->data->{server}{$server}{$source}{info}{on_poweroff} = $server_xml->{on_poweroff}->[0]; $anvil->data->{server}{$target}{$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}{$target}{$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}{$target}{$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}{$target}{$server}{$source}{info}{boot_menu} = $server_xml->{os}->[0]->{bootmenu}->[0]->{enable};
$anvil->data->{server}{$server}{$source}{info}{architecture} = $server_xml->{os}->[0]->{type}->[0]->{arch}; $anvil->data->{server}{$target}{$server}{$source}{info}{architecture} = $server_xml->{os}->[0]->{type}->[0]->{arch};
$anvil->data->{server}{$server}{$source}{info}{machine} = $server_xml->{os}->[0]->{type}->[0]->{machine}; $anvil->data->{server}{$target}{$server}{$source}{info}{machine} = $server_xml->{os}->[0]->{type}->[0]->{machine};
$anvil->data->{server}{$server}{$source}{info}{id} = exists $server_xml->{id} ? $server_xml->{id} : 0; $anvil->data->{server}{$target}{$server}{$source}{info}{id} = exists $server_xml->{id} ? $server_xml->{id} : 0;
$anvil->data->{server}{$server}{$source}{info}{emulator} = $server_xml->{devices}->[0]->{emulator}->[0]; $anvil->data->{server}{$target}{$server}{$source}{info}{emulator} = $server_xml->{devices}->[0]->{emulator}->[0];
$anvil->data->{server}{$server}{$source}{info}{acpi} = exists $server_xml->{features}->[0]->{acpi} ? 1 : 0; $anvil->data->{server}{$target}{$server}{$source}{info}{acpi} = exists $server_xml->{features}->[0]->{acpi} ? 1 : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::info::uuid" => $anvil->data->{server}{$server}{$source}{info}{uuid}, "server::${target}::${server}::${source}::info::uuid" => $anvil->data->{server}{$target}{$server}{$source}{info}{uuid},
"server::${server}::${source}::info::name" => $anvil->data->{server}{$server}{$source}{info}{name}, "server::${target}::${server}::${source}::info::name" => $anvil->data->{server}{$target}{$server}{$source}{info}{name},
"server::${server}::${source}::info::on_poweroff" => $anvil->data->{server}{$server}{$source}{info}{on_poweroff}, "server::${target}::${server}::${source}::info::on_poweroff" => $anvil->data->{server}{$target}{$server}{$source}{info}{on_poweroff},
"server::${server}::${source}::info::on_crash" => $anvil->data->{server}{$server}{$source}{info}{on_crash}, "server::${target}::${server}::${source}::info::on_crash" => $anvil->data->{server}{$target}{$server}{$source}{info}{on_crash},
"server::${server}::${source}::info::on_reboot" => $anvil->data->{server}{$server}{$source}{info}{on_reboot}, "server::${target}::${server}::${source}::info::on_reboot" => $anvil->data->{server}{$target}{$server}{$source}{info}{on_reboot},
"server::${server}::${source}::info::architecture" => $anvil->data->{server}{$server}{$source}{info}{architecture}, "server::${target}::${server}::${source}::info::architecture" => $anvil->data->{server}{$target}{$server}{$source}{info}{architecture},
"server::${server}::${source}::info::machine" => $anvil->data->{server}{$server}{$source}{info}{machine}, "server::${target}::${server}::${source}::info::machine" => $anvil->data->{server}{$target}{$server}{$source}{info}{machine},
"server::${server}::${source}::info::boot_menu" => $anvil->data->{server}{$server}{$source}{info}{boot_menu}, "server::${target}::${server}::${source}::info::boot_menu" => $anvil->data->{server}{$target}{$server}{$source}{info}{boot_menu},
"server::${server}::${source}::info::id" => $anvil->data->{server}{$server}{$source}{info}{id}, "server::${target}::${server}::${source}::info::id" => $anvil->data->{server}{$target}{$server}{$source}{info}{id},
"server::${server}::${source}::info::emulator" => $anvil->data->{server}{$server}{$source}{info}{emulator}, "server::${target}::${server}::${source}::info::emulator" => $anvil->data->{server}{$target}{$server}{$source}{info}{emulator},
"server::${server}::${source}::info::acpi" => $anvil->data->{server}{$server}{$source}{info}{acpi}, "server::${target}::${server}::${source}::info::acpi" => $anvil->data->{server}{$target}{$server}{$source}{info}{acpi},
}}); }});
# CPU # CPU
$anvil->data->{server}{$server}{$source}{cpu}{total_cores} = $server_xml->{vcpu}->[0]->{content}; $anvil->data->{server}{$target}{$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}{$target}{$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}{$target}{$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}{$target}{$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}{$target}{$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}{$target}{$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}{$target}{$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}{$target}{$server}{$source}{cpu}{vendor} = $server_xml->{cpu}->[0]->{vendor}->[0];
$anvil->data->{server}{$server}{$source}{cpu}{mode} = $server_xml->{cpu}->[0]->{mode}; $anvil->data->{server}{$target}{$server}{$source}{cpu}{mode} = $server_xml->{cpu}->[0]->{mode};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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::${target}::${server}::${source}::cpu::total_cores" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{total_cores},
"server::${server}::${source}::cpu::sockets" => $anvil->data->{server}{$server}{$source}{cpu}{sockets}, "server::${target}::${server}::${source}::cpu::sockets" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{sockets},
"server::${server}::${source}::cpu::cores" => $anvil->data->{server}{$server}{$source}{cpu}{cores}, "server::${target}::${server}::${source}::cpu::cores" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{cores},
"server::${server}::${source}::cpu::threads" => $anvil->data->{server}{$server}{$source}{cpu}{threads}, "server::${target}::${server}::${source}::cpu::threads" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{threads},
"server::${server}::${source}::cpu::model_name" => $anvil->data->{server}{$server}{$source}{cpu}{model_name}, "server::${target}::${server}::${source}::cpu::model_name" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{model_name},
"server::${server}::${source}::cpu::model_fallback" => $anvil->data->{server}{$server}{$source}{cpu}{model_fallback}, "server::${target}::${server}::${source}::cpu::model_fallback" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{model_fallback},
"server::${server}::${source}::cpu::match" => $anvil->data->{server}{$server}{$source}{cpu}{match}, "server::${target}::${server}::${source}::cpu::match" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{match},
"server::${server}::${source}::cpu::vendor" => $anvil->data->{server}{$server}{$source}{cpu}{vendor}, "server::${target}::${server}::${source}::cpu::vendor" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{vendor},
"server::${server}::${source}::cpu::mode" => $anvil->data->{server}{$server}{$source}{cpu}{mode}, "server::${target}::${server}::${source}::cpu::mode" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{mode},
}}); }});
foreach my $hash_ref (@{$server_xml->{cpu}->[0]->{feature}}) foreach my $hash_ref (@{$server_xml->{cpu}->[0]->{feature}})
{ {
my $name = $hash_ref->{name}; my $name = $hash_ref->{name};
$anvil->data->{server}{$server}{$source}{cpu}{feature}{$name} = $hash_ref->{policy}; $anvil->data->{server}{$target}{$server}{$source}{cpu}{feature}{$name} = $hash_ref->{policy};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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}, "server::${target}::${server}::${source}::cpu::feature::${name}" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{feature}{$name},
}}); }});
} }
# Power Management # Power Management
$anvil->data->{server}{$server}{$source}{pm}{'suspend-to-disk'} = $server_xml->{pm}->[0]->{'suspend-to-disk'}->[0]->{enabled}; $anvil->data->{server}{$target}{$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->data->{server}{$target}{$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 => { $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::${target}::${server}::${source}::pm::suspend-to-disk" => $anvil->data->{server}{$target}{$server}{$source}{pm}{'suspend-to-disk'},
"server::${server}::${source}::pm::suspend-to-mem" => $anvil->data->{server}{$server}{$source}{pm}{'suspend-to-mem'}, "server::${target}::${server}::${source}::pm::suspend-to-mem" => $anvil->data->{server}{$target}{$server}{$source}{pm}{'suspend-to-mem'},
}}); }});
# RAM - 'memory' is as set at boot, 'currentMemory' is the RAM used at polling (so only useful when # RAM - 'memory' is as set at boot, 'currentMemory' is the RAM used at polling (so only useful when
@ -888,15 +1007,15 @@ sub _parse_definition
ram_bytes => $anvil->Convert->add_commas({number => $ram_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $ram_bytes}).")", 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->data->{server}{$target}{$server}{$source}{memory} = $current_ram_bytes > $ram_bytes ? $current_ram_bytes : $ram_bytes;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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}}).")", "server::${target}::${server}::${source}::memory" => $anvil->Convert->add_commas({number => $anvil->data->{server}{$target}{$server}{$source}{memory}})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{server}{$target}{$server}{$source}{memory}}).")",
}}); }});
# Clock info # Clock info
$anvil->data->{server}{$server}{$source}{clock}{offset} = $server_xml->{clock}->[0]->{offset}; $anvil->data->{server}{$target}{$server}{$source}{clock}{offset} = $server_xml->{clock}->[0]->{offset};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::clock::offset" => $anvil->data->{server}{$server}{$source}{clock}{offset}, "server::${target}::${server}::${source}::clock::offset" => $anvil->data->{server}{$target}{$server}{$source}{clock}{offset},
}}); }});
foreach my $hash_ref (@{$server_xml->{clock}->[0]->{timer}}) foreach my $hash_ref (@{$server_xml->{clock}->[0]->{timer}})
{ {
@ -904,9 +1023,9 @@ sub _parse_definition
foreach my $variable (keys %{$hash_ref}) foreach my $variable (keys %{$hash_ref})
{ {
next if $variable eq "name"; next if $variable eq "name";
$anvil->data->{server}{$server}{$source}{clock}{$name}{$variable} = $hash_ref->{$variable}; $anvil->data->{server}{$target}{$server}{$source}{clock}{$name}{$variable} = $hash_ref->{$variable};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::clock::${name}::${variable}" => $anvil->data->{server}{$server}{$source}{clock}{$name}{$variable}, "server::${target}::${server}::${source}::clock::${name}::${variable}" => $anvil->data->{server}{$target}{$server}{$source}{clock}{$name}{$variable},
}}); }});
} }
} }
@ -925,34 +1044,34 @@ sub _parse_definition
my $address_port = $hash_ref->{address}->[0]->{port}; my $address_port = $hash_ref->{address}->[0]->{port};
# Store # Store
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode} = defined $hash_ref->{source}->[0]->{mode} ? $hash_ref->{source}->[0]->{mode} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{source}{mode} = defined $hash_ref->{source}->[0]->{mode} ? $hash_ref->{source}->[0]->{mode} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{path} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{source}{path} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{type} = $address_type; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{bus} = $address_bus; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{controller} = $address_controller; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{controller} = $address_controller;
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{port} = $address_port; $anvil->data->{server}{$target}{$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}{$target}{$server}{$source}{device}{channel}{unix}{target}{type} = $hash_ref->{target}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'} = defined $hash_ref->{target}->[0]->{'state'} ? $hash_ref->{target}->[0]->{'state'} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{target}{'state'} = defined $hash_ref->{target}->[0]->{'state'} ? $hash_ref->{target}->[0]->{'state'} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{name} = $hash_ref->{target}->[0]->{name}; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{target}{name} = $hash_ref->{target}->[0]->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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::${target}::${server}::${source}::device::channel::unix::source::mode" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::unix::source::path" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{source}{path},
"server::${server}::${source}::device::channel::unix::alias" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias}, "server::${target}::${server}::${source}::device::channel::unix::alias" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::unix::address::type" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::unix::address::bus" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::unix::address::controller" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::unix::address::port" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::unix::target::type" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::unix::target::state" => $anvil->data->{server}{$target}{$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}, "server::${target}::${server}::${source}::device::channel::unix::target::name" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{target}{name},
}}); }});
### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots". ### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots".
# Add to system bus list # 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->data->{server}{$target}{$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 => { # $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}, # "server::${target}::${server}::${source}::address::${address_type}::controller::${address_controller}::bus::${address_bus}::port::${address_port}" => $anvil->data->{server}{$target}{$server}{$source}{address}{$address_type}{controller}{$address_controller}{bus}{$address_bus}{port}{$address_port},
# }}); # }});
} }
elsif ($type eq "spicevmc") elsif ($type eq "spicevmc")
@ -964,30 +1083,30 @@ sub _parse_definition
my $address_port = $hash_ref->{address}->[0]->{port}; my $address_port = $hash_ref->{address}->[0]->{port};
# Store # Store
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{type} = $address_type; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{bus} = $address_bus; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{controller} = $address_controller; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{controller} = $address_controller;
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{port} = $address_port; $anvil->data->{server}{$target}{$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}{$target}{$server}{$source}{device}{channel}{spicevmc}{target}{type} = $hash_ref->{target}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'} = defined $hash_ref->{target}->[0]->{'state'} ? $hash_ref->{target}->[0]->{'state'} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'} = defined $hash_ref->{target}->[0]->{'state'} ? $hash_ref->{target}->[0]->{'state'} : "";
$anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{name} = $hash_ref->{target}->[0]->{name}; $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{target}{name} = $hash_ref->{target}->[0]->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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::${target}::${server}::${source}::device::channel::spicevmc::alias" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::spicevmc::address::type" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::spicevmc::address::bus" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::spicevmc::address::controller" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::spicevmc::address::port" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::spicevmc::target::type" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::channel::spicevmc::target::state" => $anvil->data->{server}{$target}{$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}, "server::${target}::${server}::${source}::device::channel::spicevmc::target::name" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{target}{name},
}}); }});
### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots". ### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots".
# Add to system bus list # 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->data->{server}{$target}{$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 => { # $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}, # "server::${target}::${server}::${source}::address::${address_type}::controller::${address_controller}::bus::${address_bus}::port::${address_port}" => $anvil->data->{server}{$target}{$server}{$source}{address}{$address_type}{controller}{$address_controller}{bus}{$address_bus}{port}{$address_port},
# }}); # }});
} }
} }
@ -995,19 +1114,19 @@ sub _parse_definition
# Pull out console data # Pull out console data
foreach my $hash_ref (@{$server_xml->{devices}->[0]->{console}}) foreach my $hash_ref (@{$server_xml->{devices}->[0]->{console}})
{ {
$anvil->data->{server}{$server}{$source}{device}{console}{type} = $hash_ref->{type}; $anvil->data->{server}{$target}{$server}{$source}{device}{console}{type} = $hash_ref->{type};
$anvil->data->{server}{$server}{$source}{device}{console}{tty} = defined $hash_ref->{tty} ? $hash_ref->{tty} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{console}{tty} = defined $hash_ref->{tty} ? $hash_ref->{tty} : "";
$anvil->data->{server}{$server}{$source}{device}{console}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{console}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->data->{server}{$server}{$source}{device}{console}{source} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{console}{source} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : "";
$anvil->data->{server}{$server}{$source}{device}{console}{target_type} = $hash_ref->{target}->[0]->{type}; $anvil->data->{server}{$target}{$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->data->{server}{$target}{$server}{$source}{device}{console}{target_port} = $hash_ref->{target}->[0]->{port};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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::${target}::${server}::${source}::device::console::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{type},
"server::${server}::${source}::device::console::tty" => $anvil->data->{server}{$server}{$source}{device}{console}{tty}, "server::${target}::${server}::${source}::device::console::tty" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{tty},
"server::${server}::${source}::device::console::alias" => $anvil->data->{server}{$server}{$source}{device}{console}{alias}, "server::${target}::${server}::${source}::device::console::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{alias},
"server::${server}::${source}::device::console::source" => $anvil->data->{server}{$server}{$source}{device}{console}{source}, "server::${target}::${server}::${source}::device::console::source" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{source},
"server::${server}::${source}::device::console::target_type" => $anvil->data->{server}{$server}{$source}{device}{console}{target_type}, "server::${target}::${server}::${source}::device::console::target_type" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{target_type},
"server::${server}::${source}::device::console::target_port" => $anvil->data->{server}{$server}{$source}{device}{console}{target_port}, "server::${target}::${server}::${source}::device::console::target_port" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{target_port},
}}); }});
} }
@ -1049,46 +1168,46 @@ sub _parse_definition
} }
# Store the data # Store the data
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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}, "server::${target}::${server}::${source}::device::controller::${type}::index::${index}::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{alias},
}}); }});
if ($model) if ($model)
{ {
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{model} = $model; $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{model} = $model;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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}, "server::${target}::${server}::${source}::device::controller::${type}::index::${index}::model" => $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{model},
}}); }});
} }
if ($ports) if ($ports)
{ {
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{ports} = $ports; $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{ports} = $ports;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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}, "server::${target}::${server}::${source}::device::controller::${type}::index::${index}::ports" => $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{ports},
}}); }});
} }
if ($target_chassis) if ($target_chassis)
{ {
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{chassis} = $target_chassis; $anvil->data->{server}{$target}{$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->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{port} = $target_port;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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::${target}::${server}::${source}::device::controller::${type}::index::${index}::target::chassis" => $anvil->data->{server}{$target}{$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}, "server::${target}::${server}::${source}::device::controller::${type}::index::${index}::target::port" => $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{port},
}}); }});
} }
if ($address_type) if ($address_type)
{ {
$anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{type} = $address_type; $anvil->data->{server}{$target}{$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}{$target}{$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}{$target}{$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}{$target}{$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->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{function} = $address_function;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $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::${target}::${server}::${source}::device::controller::${type}::index::${index}::address::type" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::controller::${type}::index::${index}::address::domain" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::controller::${type}::index::${index}::address::bus" => $anvil->data->{server}{$target}{$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::${target}::${server}::${source}::device::controller::${type}::index::${index}::address::slot" => $anvil->data->{server}{$target}{$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}, "server::${target}::${server}::${source}::device::controller::${type}::index::${index}::address::function" => $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{function},
}}); }});
### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots". ### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots".
@ -1098,9 +1217,9 @@ sub _parse_definition
# - Target chassis: [2], port: [0x11] # - Target chassis: [2], port: [0x11]
# - Bus type: [pci], domain: [0x0000], bus: [0x00], slot: [0x02], function: [0x1] # - 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] # 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->data->{server}{$target}{$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 => { # $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}, # "server::${target}::${server}::${source}::address::${address_type}::controller::${type}::bus::${address_bus}::slot::${address_slot}::function::${address_function}::domain" => $anvil->data->{server}{$target}{$server}{$source}{address}{$address_type}{controller}{$type}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain},
# }}); # }});
} }
} }
@ -1148,23 +1267,23 @@ sub _parse_definition
} }
# Record common data # Record common data
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{alias} = $alias; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{alias} = $alias;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{boot_order} = $boot_order; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{boot_order} = $boot_order;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{type} = $type; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{type} = $type;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{type} = $address_type; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{type} = $address_type;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{bus} = $address_bus; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{bus} = $address_bus;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{name} = $driver_name; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{name} = $driver_name;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{device_bus} = $device_bus; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{device_bus} = $device_bus;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{type} = $driver_type; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{type} = $driver_type;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::${device}::target::${device_target}::address::type" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{type}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::address::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{type},
"server::${server}::${source}::device::${device}::target::${device_target}::address::bus" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{bus}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::address::bus" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{bus},
"server::${server}::${source}::device::${device}::target::${device_target}::alias" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{alias}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{alias},
"server::${server}::${source}::device::${device}::target::${device_target}::boot_order" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{boot_order}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::boot_order" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{boot_order},
"server::${server}::${source}::device::${device}::target::${device_target}::device_bus" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{device_bus}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::device_bus" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{device_bus},
"server::${server}::${source}::device::${device}::target::${device_target}::driver::name" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{name}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::driver::name" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{name},
"server::${server}::${source}::device::${device}::target::${device_target}::driver::type" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{type}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::driver::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{type},
"server::${server}::${source}::device::${device}::target::${device_target}::type" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{type}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{type},
}}); }});
# Record type-specific data # Record type-specific data
@ -1176,46 +1295,46 @@ sub _parse_definition
my $driver_io = defined $hash_ref->{driver}->[0]->{io} ? $hash_ref->{driver}->[0]->{io} : ""; my $driver_io = defined $hash_ref->{driver}->[0]->{io} ? $hash_ref->{driver}->[0]->{io} : "";
my $driver_cache = defined $hash_ref->{driver}->[0]->{cache} ? $hash_ref->{driver}->[0]->{cache} : ""; my $driver_cache = defined $hash_ref->{driver}->[0]->{cache} ? $hash_ref->{driver}->[0]->{cache} : "";
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{domain} = $address_domain; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{domain} = $address_domain;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{slot} = $address_slot; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{slot} = $address_slot;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{function} = $address_function; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{function} = $address_function;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{path} = $device_path; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{path} = $device_path;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{io} = $driver_io; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{io} = $driver_io;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{cache} = $driver_cache; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{cache} = $driver_cache;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::${device}::target::${device_target}::address::domain" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{domain}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::address::domain" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{domain},
"server::${server}::${source}::device::${device}::target::${device_target}::address::slot" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{slot}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::address::slot" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{slot},
"server::${server}::${source}::device::${device}::target::${device_target}::address::function" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{function}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::address::function" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{function},
"server::${server}::${source}::device::${device}::target::${device_target}::path" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{path}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::path" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{path},
"server::${server}::${source}::device::${device}::target::${device_target}::driver::io" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{io}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::driver::io" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{io},
"server::${server}::${source}::device::${device}::target::${device_target}::driver::cache" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{cache}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::driver::cache" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{cache},
}}); }});
my $on_lv = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} : ""; my $on_lv = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} : "";
my $resource = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} : ""; my $resource = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} : "";
$anvil->data->{server}{$server}{device}{$device_path}{on_lv} = $on_lv; $anvil->data->{server}{$target}{$server}{device}{$device_path}{on_lv} = $on_lv;
$anvil->data->{server}{$server}{device}{$device_path}{resource} = $resource; $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource} = $resource;
$anvil->data->{server}{$server}{device}{$device_path}{target} = $device_target; $anvil->data->{server}{$target}{$server}{device}{$device_path}{target} = $device_target;
$anvil->data->{server}{$server}{resource}{$resource} = 1; $anvil->data->{server}{$target}{$server}{resource}{$resource} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host => $host, host => $host,
"server::${server}::device::${device_path}::on_lv" => $anvil->data->{server}{$server}{device}{$device_path}{on_lv}, "server::${target}::${server}::device::${device_path}::on_lv" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{on_lv},
"server::${server}::device::${device_path}::resource" => $anvil->data->{server}{$server}{device}{$device_path}{resource}, "server::${target}::${server}::device::${device_path}::resource" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource},
"server::${server}::device::${device_path}::target" => $anvil->data->{server}{$server}{device}{$device_path}{target}, "server::${target}::${server}::device::${device_path}::target" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{target},
"server::${server}::resource::${resource}" => $anvil->data->{server}{$server}{resource}{$resource}, "server::${target}::${server}::resource::${resource}" => $anvil->data->{server}{$target}{$server}{resource}{$resource},
}}); }});
# Keep a list of DRBD resources used by this server. # Keep a list of DRBD resources used by this server.
my $drbd_resource = $anvil->data->{server}{$server}{device}{$device_path}{resource}; my $drbd_resource = $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource};
$anvil->data->{server}{$server}{drbd}{resource}{$drbd_resource} = 1; $anvil->data->{server}{$target}{$server}{drbd}{resource}{$drbd_resource} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::drbd::resource::${drbd_resource}" => $anvil->data->{server}{$server}{drbd}{resource}{$drbd_resource}, "server::${target}::${server}::drbd::resource::${drbd_resource}" => $anvil->data->{server}{$target}{$server}{drbd}{resource}{$drbd_resource},
}}); }});
### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots". ### TODO: Store the parts in some format that allows representing it better to the user and easier to find "open slots".
# $anvil->data->{server}{$server}{$source}{address}{$device_bus}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain} = $address_domain; # $anvil->data->{server}{$target}{$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 => { # $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}, # "server::${target}::${server}::${source}::address::${address_type}::controller::${type}::bus::${address_bus}::slot::${address_slot}::function::${address_function}::domain" => $anvil->data->{server}{$target}{$server}{$source}{address}{$address_type}{controller}{$type}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain},
# }}); # }});
} }
else else
@ -1225,45 +1344,45 @@ sub _parse_definition
my $address_unit = $hash_ref->{address}->[0]->{unit}; my $address_unit = $hash_ref->{address}->[0]->{unit};
my $address_target = $hash_ref->{address}->[0]->{target}; my $address_target = $hash_ref->{address}->[0]->{target};
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{controller} = $address_controller; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{controller} = $address_controller;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{unit} = $address_unit; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{unit} = $address_unit;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{target} = $address_target; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{target} = $address_target;
$anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{path} = $device_path; $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{path} = $device_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::${device}::target::${device_target}::address::controller" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{controller}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::address::controller" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{controller},
"server::${server}::${source}::device::${device}::target::${device_target}::address::unit" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{unit}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::address::unit" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{unit},
"server::${server}::${source}::device::${device}::target::${device_target}::address::target" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{address}{target}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::address::target" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{target},
"server::${server}::${source}::device::${device}::target::${device_target}::path" => $anvil->data->{server}{$server}{$source}{device}{$device}{target}{$device_target}{path}, "server::${target}::${server}::${source}::device::${device}::target::${device_target}::path" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{path},
}}); }});
} }
} }
# Pull out console data # Pull out network data
foreach my $hash_ref (@{$server_xml->{devices}->[0]->{interface}}) foreach my $hash_ref (@{$server_xml->{devices}->[0]->{interface}})
{ {
#print Dumper $hash_ref; #print Dumper $hash_ref;
my $mac = $hash_ref->{mac}->[0]->{address}; my $mac = $hash_ref->{mac}->[0]->{address};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{bridge} = $hash_ref->{source}->[0]->{bridge}; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{bridge} = $hash_ref->{source}->[0]->{bridge};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : "";
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target} = defined $hash_ref->{target}->[0]->{dev} ? $hash_ref->{target}->[0]->{dev} : ""; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{target} = defined $hash_ref->{target}->[0]->{dev} ? $hash_ref->{target}->[0]->{dev} : "";
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{model} = $hash_ref->{model}->[0]->{type}; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{model} = $hash_ref->{model}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{bus} = $hash_ref->{address}->[0]->{bus}; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{bus} = $hash_ref->{address}->[0]->{bus};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{domain} = $hash_ref->{address}->[0]->{domain}; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{domain} = $hash_ref->{address}->[0]->{domain};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{type} = $hash_ref->{address}->[0]->{type}; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{type} = $hash_ref->{address}->[0]->{type};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{slot} = $hash_ref->{address}->[0]->{slot}; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{slot} = $hash_ref->{address}->[0]->{slot};
$anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{function} = $hash_ref->{address}->[0]->{function}; $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{function} = $hash_ref->{address}->[0]->{function};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${server}::${source}::device::interface::${mac}::bridge" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{bridge}, "server::${target}::${server}::${source}::device::interface::${mac}::bridge" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{bridge},
"server::${server}::${source}::device::interface::${mac}::alias" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias}, "server::${target}::${server}::${source}::device::interface::${mac}::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{alias},
"server::${server}::${source}::device::interface::${mac}::target" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target}, "server::${target}::${server}::${source}::device::interface::${mac}::target" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{target},
"server::${server}::${source}::device::interface::${mac}::model" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{model}, "server::${target}::${server}::${source}::device::interface::${mac}::model" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{model},
"server::${server}::${source}::device::interface::${mac}::address::bus" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{bus}, "server::${target}::${server}::${source}::device::interface::${mac}::address::bus" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{bus},
"server::${server}::${source}::device::interface::${mac}::address::domain" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{domain}, "server::${target}::${server}::${source}::device::interface::${mac}::address::domain" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{domain},
"server::${server}::${source}::device::interface::${mac}::address::type" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{type}, "server::${target}::${server}::${source}::device::interface::${mac}::address::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{type},
"server::${server}::${source}::device::interface::${mac}::address::slot" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{slot}, "server::${target}::${server}::${source}::device::interface::${mac}::address::slot" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{slot},
"server::${server}::${source}::device::interface::${mac}::address::function" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{address}{function}, "server::${target}::${server}::${source}::device::interface::${mac}::address::function" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{function},
}}); }});
} }

@ -361,7 +361,7 @@ sub stop_drbd_resource
}}); }});
# Start DRBD locally. # Start DRBD locally.
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{resource}}) foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{resource}})
{ {
my $peer_ip = $anvil->data->{drbd}{config}{$host}{resource}{$resource}{connection}{$peer}{ip_address}; my $peer_ip = $anvil->data->{drbd}{config}{$host}{resource}{$resource}{connection}{$peer}{ip_address};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0408", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0408", variables => {
@ -405,7 +405,7 @@ sub start_drbd_resource
# Do we need startup? # Do we need startup?
my $startup_needed = 0; my $startup_needed = 0;
$anvil->DRBD->get_status({debug => 3}); $anvil->DRBD->get_status({debug => 3});
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{resource}}) foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{resource}})
{ {
# Is the current resource up locally already? If it is, we're done. # Is the current resource up locally already? If it is, we're done.
my $role = $anvil->data->{drbd}{status}{$host}{resource}{$resource}{role}; my $role = $anvil->data->{drbd}{status}{$host}{resource}{$resource}{role};
@ -434,7 +434,7 @@ sub start_drbd_resource
} }
# Start DRBD locally. # Start DRBD locally.
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{resource}}) foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{resource}})
{ {
my $peer_ip = $anvil->data->{drbd}{config}{$host}{resource}{$resource}{connection}{$peer}{ip_address}; my $peer_ip = $anvil->data->{drbd}{config}{$host}{resource}{$resource}{connection}{$peer}{ip_address};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0419", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0419", variables => {
@ -504,7 +504,7 @@ sub start_drbd_resource
# If auto-promote isn't set, promote the resource. # If auto-promote isn't set, promote the resource.
if (not $anvil->data->{drbd}{config}{$host}{'auto-promote'}) if (not $anvil->data->{drbd}{config}{$host}{'auto-promote'})
{ {
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{resource}}) foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{resource}})
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0420", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0420", variables => {
server => $server, server => $server,
@ -747,7 +747,7 @@ sub migrate_server
host => $host, host => $host,
peer_name => $peer_name, peer_name => $peer_name,
}}); }});
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{resource}}) foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{resource}})
{ {
my $connection_state = $anvil->data->{drbd}{status}{$host}{resource}{$resource}{connection}{$peer_name}{'connection-state'}; my $connection_state = $anvil->data->{drbd}{status}{$host}{resource}{$resource}{connection}{$peer_name}{'connection-state'};
my $peer_node_id = $anvil->data->{drbd}{status}{$host}{resource}{$resource}{connection}{$peer_name}{'peer-node-id'}; my $peer_node_id = $anvil->data->{drbd}{status}{$host}{resource}{$resource}{connection}{$peer_name}{'peer-node-id'};
@ -951,11 +951,11 @@ sub validate_bridges
# Find the Optical drives and DRBD devices. # Find the Optical drives and DRBD devices.
my $server = $anvil->data->{environment}{OCF_RESKEY_name}; my $server = $anvil->data->{environment}{OCF_RESKEY_name};
foreach my $mac (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{from_disk}{device}{interface}}) foreach my $mac (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{from_disk}{device}{interface}})
{ {
# See if we have this bridge # See if we have this bridge
my $found = 0; my $found = 0;
my $bridge = $anvil->data->{server}{$server}{from_disk}{device}{interface}{$mac}{bridge}; my $bridge = $anvil->data->{server}{'local'}{$server}{from_disk}{device}{interface}{$mac}{bridge};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge => $bridge }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge => $bridge }});
foreach my $interface_name (sort {$a cmp $b} keys %{$anvil->data->{'local'}{network}{bridges}{bridge}}) foreach my $interface_name (sort {$a cmp $b} keys %{$anvil->data->{'local'}{network}{bridges}{bridge}})
{ {
@ -992,7 +992,7 @@ sub validate_storage
### TODO: When checking on a running server, use 'from_memory'. ### TODO: When checking on a running server, use 'from_memory'.
my $server = $anvil->data->{environment}{OCF_RESKEY_name}; my $server = $anvil->data->{environment}{OCF_RESKEY_name};
my $source = "from_disk"; my $source = "from_disk";
if ($anvil->data->{server}{$server}{from_memory}{host}) if ($anvil->data->{server}{'local'}{$server}{from_memory}{host})
{ {
$source = "from_memory"; $source = "from_memory";
} }
@ -1005,13 +1005,13 @@ sub validate_storage
### For now, we just fault out. ### For now, we just fault out.
# Do the optical discs in the drive exist? If not, we'll eject it if we're about to boot and fail if # Do the optical discs in the drive exist? If not, we'll eject it if we're about to boot and fail if
# we're about to migrate. We skip this check if we're migrating off or shutting down the server. # we're about to migrate. We skip this check if we're migrating off or shutting down the server.
if ((exists $anvil->data->{server}{$server}{$source}{device}{cdrom}) && (not $anvil->data->{switches}{migrate_to}) && (not $anvil->data->{switches}{stop})) if ((exists $anvil->data->{server}{'local'}{$server}{$source}{device}{cdrom}) && (not $anvil->data->{switches}{migrate_to}) && (not $anvil->data->{switches}{stop}))
{ {
foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{$source}{device}{cdrom}{target}}) foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{$source}{device}{cdrom}{target}})
{ {
if ($anvil->data->{server}{$server}{$source}{device}{cdrom}{target}{$device_target}{path}) if ($anvil->data->{server}{'local'}{$server}{$source}{device}{cdrom}{target}{$device_target}{path})
{ {
my $file = $anvil->data->{server}{$server}{$source}{device}{cdrom}{target}{$device_target}{path}; my $file = $anvil->data->{server}{'local'}{$server}{$source}{device}{cdrom}{target}{$device_target}{path};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file => $file }});
if (not -e $file) if (not -e $file)
{ {
@ -1053,22 +1053,22 @@ sub validate_storage_drbd
my $host = $anvil->_short_host_name; my $host = $anvil->_short_host_name;
# Did I find a resource for each disk? # Did I find a resource for each disk?
foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{device}}) foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{device}})
{ {
next if not $device_path; next if not $device_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"server::${server}::device::${device_path}::resource" => $anvil->data->{server}{$server}{device}{$device_path}{resource}, "server::local::${server}::device::${device_path}::resource" => $anvil->data->{server}{'local'}{$server}{device}{$device_path}{resource},
}}); }});
if (not $anvil->data->{server}{$server}{device}{$device_path}{resource}) if (not $anvil->data->{server}{'local'}{$server}{device}{$device_path}{resource})
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 0, priority => "err", key => "log_0414", variables => { drbd_device => $device_path }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 0, level => 0, priority => "err", key => "log_0414", variables => { drbd_device => $device_path }});
$anvil->nice_exit({exit_code => 5}); $anvil->nice_exit({exit_code => 5});
} }
} }
foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$server}{$source}{device}{disk}{target}}) foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{'local'}{$server}{$source}{device}{disk}{target}})
{ {
my $drbd_device = $anvil->data->{server}{$server}{$source}{device}{disk}{target}{$device_target}{path}; my $drbd_device = $anvil->data->{server}{'local'}{$server}{$source}{device}{disk}{target}{$device_target}{path};
my $drbd_resource = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{resource}; my $drbd_resource = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{resource};
my $on_lv = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{on}; my $on_lv = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{on};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
@ -1122,10 +1122,10 @@ sub validate_emulator
# What emulator is this using? # What emulator is this using?
my $server = $anvil->data->{environment}{OCF_RESKEY_name}; my $server = $anvil->data->{environment}{OCF_RESKEY_name};
my $emulator = $anvil->data->{server}{$server}{from_disk}{info}{emulator}; my $emulator = $anvil->data->{server}{'local'}{$server}{from_disk}{info}{emulator};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
emulator => $emulator, emulator => $emulator,
"server::${server}::from_disk::info::emulator" => $anvil->data->{server}{$server}{from_disk}{info}{emulator} "server::local::${server}::from_disk::info::emulator" => $anvil->data->{server}{'local'}{$server}{from_disk}{info}{emulator}
}}); }});
if (not -e $emulator) if (not -e $emulator)
{ {
@ -1154,12 +1154,12 @@ sub validate_name
my $server = $anvil->data->{environment}{OCF_RESKEY_name}; my $server = $anvil->data->{environment}{OCF_RESKEY_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
server => $server, server => $server,
"server::${server}::from_disk::info::name" => $anvil->data->{server}{$server}{from_disk}{info}{name}, "server::local::${server}::from_disk::info::name" => $anvil->data->{server}{'local'}{$server}{from_disk}{info}{name},
}}); }});
# If we failed to read the XML, the server probably doesn't exist. # If we failed to read the XML, the server probably doesn't exist.
if (not $anvil->data->{server}{$server}{from_disk}{xml}) if (not $anvil->data->{server}{'local'}{$server}{from_disk}{xml})
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0403", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0403", variables => {
server => $server, server => $server,
@ -1169,11 +1169,11 @@ sub validate_name
} }
# Is the name in the definition file what we expect? # Is the name in the definition file what we expect?
if ($server ne $anvil->data->{server}{$server}{from_disk}{info}{name}) if ($server ne $anvil->data->{server}{'local'}{$server}{from_disk}{info}{name})
{ {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0403", variables => { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "log_0403", variables => {
server => $server, server => $server,
name => $anvil->data->{server}{$server}{from_disk}{info}{name}, name => $anvil->data->{server}{'local'}{$server}{from_disk}{info}{name},
}}); }});
$anvil->nice_exit({exit_code => 1}); $anvil->nice_exit({exit_code => 1});
} }
@ -1189,7 +1189,7 @@ sub validate_ram
# How mcuh RAM does the server need and how much do we have free? # How mcuh RAM does the server need and how much do we have free?
my $server = $anvil->data->{environment}{OCF_RESKEY_name}; my $server = $anvil->data->{environment}{OCF_RESKEY_name};
my $server_ram_bytes = $anvil->data->{server}{$server}{from_disk}{memory}; my $server_ram_bytes = $anvil->data->{server}{'local'}{$server}{from_disk}{memory};
my $available = $anvil->System->get_free_memory({debug => 3}); my $available = $anvil->System->get_free_memory({debug => 3});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
server_ram_bytes => $anvil->Convert->add_commas({number => $server_ram_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $server_ram_bytes}).")", server_ram_bytes => $anvil->Convert->add_commas({number => $server_ram_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $server_ram_bytes}).")",

@ -982,7 +982,9 @@ CREATE TABLE bridges (
bridge_host_uuid uuid not null, bridge_host_uuid uuid not null,
bridge_name text not null, bridge_name text not null,
bridge_id text not null, bridge_id text not null,
bridge_stp_enabled text not null, bridge_mac text not null,
bridge_mtu text not null,
bridge_stp_enabled text not null, -- 0 = disabled, 1 = kernel STP, 2 = user STP
modified_date timestamp with time zone not null, modified_date timestamp with time zone not null,
FOREIGN KEY(bridge_host_uuid) REFERENCES hosts(host_uuid) FOREIGN KEY(bridge_host_uuid) REFERENCES hosts(host_uuid)
@ -995,6 +997,8 @@ CREATE TABLE history.bridges (
bridge_host_uuid uuid, bridge_host_uuid uuid,
bridge_name text, bridge_name text,
bridge_id text, bridge_id text,
bridge_mac text,
bridge_mtu text,
bridge_stp_enabled text, bridge_stp_enabled text,
modified_date timestamp with time zone not null modified_date timestamp with time zone not null
); );
@ -1011,6 +1015,8 @@ BEGIN
bridge_host_uuid, bridge_host_uuid,
bridge_name, bridge_name,
bridge_id, bridge_id,
bridge_mac,
bridge_mtu,
bridge_stp_enabled, bridge_stp_enabled,
modified_date) modified_date)
VALUES VALUES
@ -1018,6 +1024,8 @@ BEGIN
history_bridges.bridge_host_uuid, history_bridges.bridge_host_uuid,
history_bridges.bridge_name, history_bridges.bridge_name,
history_bridges.bridge_id, history_bridges.bridge_id,
history_bridges.bridge_mac,
history_bridges.bridge_mtu,
history_bridges.bridge_stp_enabled, history_bridges.bridge_stp_enabled,
history_bridges.modified_date); history_bridges.modified_date);
RETURN NULL; RETURN NULL;
@ -1031,6 +1039,63 @@ CREATE TRIGGER trigger_bridges
FOR EACH ROW EXECUTE PROCEDURE history_bridges(); FOR EACH ROW EXECUTE PROCEDURE history_bridges();
-- This records which interfaces are connect to which bridges
CREATE TABLE bridge_interfaces (
bridge_interface_uuid uuid not null primary key,
bridge_interface_host_uuid uuid not null,
bridge_interface_bridge_uuid uuid not null,
bridge_interface_network_interface_uuid uuid not null,
bridge_interface_note text not null, -- Will have 'DELETED' when removed, or the server name the device connects to otherwise.
modified_date timestamp with time zone not null,
FOREIGN KEY(bridge_interface_host_uuid) REFERENCES hosts(host_uuid),
FOREIGN KEY(bridge_interface_bridge_uuid) REFERENCES bridges(bridge_uuid),
FOREIGN KEY(bridge_interface_network_interface_uuid) REFERENCES network_interfaces(network_interface_uuid)
);
ALTER TABLE bridge_interfaces OWNER TO admin;
CREATE TABLE history.bridge_interfaces (
history_id bigserial,
bridge_interface_uuid uuid,
bridge_interface_host_uuid uuid,
bridge_interface_bridge_uuid uuid,
bridge_interface_network_interface_uuid uuid,
bridge_interface_note text,
modified_date timestamp with time zone not null
);
ALTER TABLE history.bridge_interfaces OWNER TO admin;
CREATE FUNCTION history_bridge_interfaces() RETURNS trigger
AS $$
DECLARE
history_bridge_interfaces RECORD;
BEGIN
SELECT INTO history_bridge_interfaces * FROM bridge_interfaces WHERE bridge_interface_uuid = new.bridge_interface_uuid;
INSERT INTO history.bridge_interfaces
(bridge_interface_uuid,
bridge_interface_host_uuid,
bridge_interface_bridge_uuid,
bridge_interface_network_interface_uuid,
bridge_interface_note,
modified_date)
VALUES
(history_bridge_interfaces.bridge_interface_uuid,
history_bridge_interfaces.bridge_interface_host_uuid,
history_bridge_interfaces.bridge_interface_bridge_uuid,
history_bridge_interfaces.bridge_interface_network_interface_uuid,
history_bridge_interfaces.bridge_interface_note,
history_bridge_interfaces.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_bridge_interfaces() OWNER TO admin;
CREATE TRIGGER trigger_bridge_interfaces
AFTER INSERT OR UPDATE ON bridge_interfaces
FOR EACH ROW EXECUTE PROCEDURE history_bridge_interfaces();
-- This stores information about network ip addresss. -- This stores information about network ip addresss.
CREATE TABLE ip_addresses ( CREATE TABLE ip_addresses (
ip_address_uuid uuid not null primary key, ip_address_uuid uuid not null primary key,
@ -1376,6 +1441,53 @@ CREATE TRIGGER trigger_definitions
FOR EACH ROW EXECUTE PROCEDURE history_definitions(); FOR EACH ROW EXECUTE PROCEDURE history_definitions();
-- It stores a general list of OUI (Organizationally Unique Identifier) to allow lookup of MAC address to
-- owning company. Data for this comes from http://standards-oui.ieee.org/oui/oui.txt and is stored by
-- striker-parse-oui. It is a generic reference table, so it's not bound to any one host.
CREATE TABLE oui (
oui_uuid uuid not null primary key,
oui_mac_prefix text not null, -- This is the first 12 bits / 3 bytes of the MAC address
oui_company_name text not null, -- This is the name of the owning company, as recorded in the OUI list.
modified_date timestamp with time zone not null
);
ALTER TABLE oui OWNER TO admin;
CREATE TABLE history.oui (
history_id bigserial,
oui_uuid uuid,
oui_mac_prefix text,
oui_company_name text,
modified_date timestamp with time zone not null
);
ALTER TABLE history.oui OWNER TO admin;
CREATE FUNCTION history_oui() RETURNS trigger
AS $$
DECLARE
history_oui RECORD;
BEGIN
SELECT INTO history_oui * FROM oui WHERE oui_uuid = new.oui_uuid;
INSERT INTO history.oui
(oui_uuid,
oui_mac_prefix,
oui_company_name,
modified_date)
VALUES
(history_oui.oui_uuid,
history_oui.oui_mac_prefix,
history_oui.oui_company_name,
history_oui.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_oui() OWNER TO admin;
CREATE TRIGGER trigger_oui
AFTER INSERT OR UPDATE ON oui
FOR EACH ROW EXECUTE PROCEDURE history_oui();
-- ------------------------------------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------------------------------------- --
-- These are special tables with no history or tracking UUIDs that simply record transient information. -- -- These are special tables with no history or tracking UUIDs that simply record transient information. --
-- ------------------------------------------------------------------------------------------------------- -- -- ------------------------------------------------------------------------------------------------------- --

@ -769,6 +769,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a
<key name="log_0440">The variable: [#!variable!name!#] is an array reference, but it doesn't have any entries in it.</key> <key name="log_0440">The variable: [#!variable!name!#] is an array reference, but it doesn't have any entries in it.</key>
<key name="log_0441">The variable: [#!variable!name!#] was expected to be a positive integer, but: [#!variable!value!#] was received.</key> <key name="log_0441">The variable: [#!variable!name!#] was expected to be a positive integer, but: [#!variable!value!#] was received.</key>
<key name="log_0442">The domain: [#!variable!name!#] does not appear to be a valid domain name or an ipv4 IP address. Skipping it.</key> <key name="log_0442">The domain: [#!variable!name!#] does not appear to be a valid domain name or an ipv4 IP address. Skipping it.</key>
<key name="log_0443">The bridge output wasn't in JSON format. Received: [#!variable!output!#].</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. --> <!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key> <key name="t_0000">Test</key>
@ -1154,6 +1155,13 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp
<key name="error_0081">The job_uuid: [#!variable!job_uuid!#] appears valid, but there was no job_data.</key> <key name="error_0081">The job_uuid: [#!variable!job_uuid!#] appears valid, but there was no job_data.</key>
<key name="error_0082">The state UUID: [#!variable!state_uuid!#] does not appear to be a valid UUID.</key> <key name="error_0082">The state UUID: [#!variable!state_uuid!#] does not appear to be a valid UUID.</key>
<key name="error_0083">No (good) state UUIDs found, unable to run this job.</key> <key name="error_0083">No (good) state UUIDs found, unable to run this job.</key>
<key name="error_0084">Unable to find a common network between the target and this machine. This shouldn't be possible, given we're able to talk to it. This is probably a program error.</key>
<key name="error_0085">The URL: [#!variable!url!#] is not supported. The URL must start with 'http://', 'https://' or 'ftp://'.</key>
<key name="error_0086">The requested URL: [#!variable!url!#] was not found on the remote server.</key>
<key name="error_0087">The requested URL: [#!variable!url!#] does not resolve to a known domain.</key>
<key name="error_0088">The requested URL: [#!variable!url!#] failed because the remote host refused the connection.</key>
<key name="error_0089">The requested URL: [#!variable!url!#] failed because there is no route to that host.</key>
<key name="error_0090">The requested URL: [#!variable!url!#] failed because the network is unreachable.</key>
<!-- These are units, words and so on used when displaying information. --> <!-- These are units, words and so on used when displaying information. -->
<key name="unit_0001">Yes</key> <key name="unit_0001">Yes</key>

@ -11,8 +11,9 @@
# 2 = Job not found. # 2 = Job not found.
# 3 = No offending keys found. # 3 = No offending keys found.
# #
# TODO: We might want to offer an option to remove all keys found for a given target. Somehow, at least in # TODO: Record the keys we remove, then check for the same keys on any other machine we know about. If any
# testing, multiple keys got into a single known_hosts file. # are found on those machines, create a job for that host to remove the same.
# Also, look in the 'ip_addresses' table for any matching keys and delete them.
# #
use strict; use strict;

@ -2,10 +2,10 @@
# #
# This updates things like the current network configuration, shared file data and writes it out to a json file. # This updates things like the current network configuration, shared file data and writes it out to a json file.
# #
#
use strict; use strict;
use warnings; use warnings;
use Anvil::Tools; use Anvil::Tools;
use Data::Dumper;
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. # Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1; $| = 1;
@ -62,6 +62,7 @@ sub update_network
bridges => {}, bridges => {},
}; };
# Walk through the sysfs files.
local(*DIRECTORY); local(*DIRECTORY);
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0018", variables => { directory => $directory }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0018", variables => { directory => $directory }});
opendir(DIRECTORY, $directory); opendir(DIRECTORY, $directory);
@ -111,6 +112,10 @@ sub update_network
my $down_delay = ""; my $down_delay = "";
my $bond_master = ""; my $bond_master = "";
# These are variables that will be needed if this is a bridge interface
my $bridge_id = "";
my $bridge_stp_enabled = "";
if (exists $anvil->data->{network}{'local'}{interface}{$interface}) if (exists $anvil->data->{network}{'local'}{interface}{$interface})
{ {
$ip_address = $anvil->data->{network}{'local'}{interface}{$interface}{ip} ? $anvil->data->{network}{'local'}{interface}{$interface}{ip} : ""; $ip_address = $anvil->data->{network}{'local'}{interface}{$interface}{ip} ? $anvil->data->{network}{'local'}{interface}{$interface}{ip} : "";
@ -190,16 +195,45 @@ sub update_network
# No, but it's slaved to one. # No, but it's slaved to one.
my $target = readlink($full_path."/master"); my $target = readlink($full_path."/master");
$bond_master = ($target =~ /^.*\/(.*)$/)[0]; $bond_master = ($target =~ /^.*\/(.*)$/)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
target => $target, target => $target,
bond_master => $bond_master, bond_master => $bond_master,
}}); }});
} }
elsif (-d $full_path."/bridge")
{
# It's a bridge
$type = "bridge";
$bridge_id = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/bridge_id"});
$bridge_stp_enabled = $anvil->Storage->read_file({debug => 3, file => $full_path."/bridge/stp_state"});
$bridge_id =~ s/\n$//;
$bridge_stp_enabled =~ s/\n$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
bridge_id => $bridge_id,
bridge_stp_enabled => $bridge_stp_enabled,
type => $type,
}});
if ($bridge_stp_enabled eq "0")
{
$bridge_stp_enabled = "disabled";
}
elsif ($bridge_stp_enabled eq "1")
{
$bridge_stp_enabled = "enabled_kernel";
}
elsif ($bridge_stp_enabled eq "2")
{
$bridge_stp_enabled = "enabled_userland";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bridge_stp_enabled => $bridge_stp_enabled }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
active_slave => $active_slave, active_slave => $active_slave,
bond_master => $bond_master, bond_master => $bond_master,
bond_mode => $bond_mode, bond_mode => $bond_mode,
bridge_id => $bridge_id,
bridge_stp_enabled => $bridge_stp_enabled,
down_delay => $down_delay, down_delay => $down_delay,
duplex => $duplex, duplex => $duplex,
interface => $interface, interface => $interface,
@ -233,28 +267,29 @@ sub update_network
} }
# Find the media, if possible. # Find the media, if possible.
my $shell_call = $anvil->data->{path}{exe}{ethtool}." $interface"; my ($ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"});
my $ethtool = $anvil->System->call({shell_call => $shell_call});
foreach my $line (split/\n/, $ethtool) foreach my $line (split/\n/, $ethtool)
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line =~ /Supported ports: \[ (.*?) \]/i) if ($line =~ /Supported ports: \[ (.*?) \]/i)
{ {
$media = lc($1); $media = lc($1);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { media => $media }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { media => $media }});
last; last;
} }
} }
# Record this interface # Record this interface
$anvil->data->{seen}{$type}{$interface} = 1; $anvil->data->{seen}{$type}{$interface} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "seen::${type}::${interface}" => $anvil->data->{seen}{$type}{$interface} }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "seen::${type}::${interface}" => $anvil->data->{seen}{$type}{$interface} }});
# Log # Log
$anvil->data->{network}{interfaces}{by_name}{$interface} = { $anvil->data->{network}{interfaces}{by_name}{$interface} = {
active_slave => $active_slave, active_slave => $active_slave,
bond_mode => $bond_mode, bond_mode => $bond_mode,
bond_master => $bond_master, bond_master => $bond_master,
bridge_id => $bridge_id,
bridge_stp_enabled => $bridge_stp_enabled,
down_delay => $down_delay, down_delay => $down_delay,
duplex => $duplex, duplex => $duplex,
ip_address => $ip_address, ip_address => $ip_address,
@ -275,6 +310,8 @@ sub update_network
"network::interfaces::by_name::${interface}::active_slave" => $anvil->data->{network}{interfaces}{by_name}{$interface}{active_slave}, "network::interfaces::by_name::${interface}::active_slave" => $anvil->data->{network}{interfaces}{by_name}{$interface}{active_slave},
"network::interfaces::by_name::${interface}::bond_mode" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode}, "network::interfaces::by_name::${interface}::bond_mode" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode},
"network::interfaces::by_name::${interface}::bond_master" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_master}, "network::interfaces::by_name::${interface}::bond_master" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_master},
"network::interfaces::by_name::${interface}::bridge_id" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bridge_id},
"network::interfaces::by_name::${interface}::bridge_stp_enabled" => $anvil->data->{network}{interfaces}{by_name}{$interface}{bridge_stp_enabled},
"network::interfaces::by_name::${interface}::down_delay" => $anvil->data->{network}{interfaces}{by_name}{$interface}{down_delay}, "network::interfaces::by_name::${interface}::down_delay" => $anvil->data->{network}{interfaces}{by_name}{$interface}{down_delay},
"network::interfaces::by_name::${interface}::duplex" => $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex}, "network::interfaces::by_name::${interface}::duplex" => $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex},
"network::interfaces::by_name::${interface}::ip_address" => $anvil->data->{network}{interfaces}{by_name}{$interface}{ip_address}, "network::interfaces::by_name::${interface}::ip_address" => $anvil->data->{network}{interfaces}{by_name}{$interface}{ip_address},
@ -296,14 +333,25 @@ sub update_network
closedir(DIRECTORY); closedir(DIRECTORY);
# We need to record bonds first so that their UUIDs are available when recording interfaces. # We need to record bonds first so that their UUIDs are available when recording interfaces.
foreach my $processing ("bond", "interface") foreach my $processing ("bond", "interface", "bridge")
{ {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { processing => $processing }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { processing => $processing }});
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{interfaces}{by_name}}) foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{network}{interfaces}{by_name}})
{ {
# Skip if this isn't the device type we're working on.
my $type = $anvil->data->{network}{interfaces}{by_name}{$interface}{type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:interface' => $interface,
's2:type' => $type,
's3:processing' => $processing,
}});
next if $processing ne $anvil->data->{network}{interfaces}{by_name}{$interface}{type};
my $active_slave = $anvil->data->{network}{interfaces}{by_name}{$interface}{active_slave}; my $active_slave = $anvil->data->{network}{interfaces}{by_name}{$interface}{active_slave};
my $bond_mode = $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode}; my $bond_mode = $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode};
my $bond_master = $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_master}; my $bond_master = $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_master};
my $bridge_id = $anvil->data->{network}{interfaces}{by_name}{$interface}{bridge_id};
my $bridge_stp_enabled = $anvil->data->{network}{interfaces}{by_name}{$interface}{bridge_stp_enabled};
my $down_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{down_delay}; my $down_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{down_delay};
my $duplex = $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex}; my $duplex = $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex};
my $ip_address = $anvil->data->{network}{interfaces}{by_name}{$interface}{ip_address}; my $ip_address = $anvil->data->{network}{interfaces}{by_name}{$interface}{ip_address};
@ -317,7 +365,6 @@ sub update_network
my $primary_slave = $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_slave}; my $primary_slave = $anvil->data->{network}{interfaces}{by_name}{$interface}{primary_slave};
my $speed = $anvil->data->{network}{interfaces}{by_name}{$interface}{speed}; my $speed = $anvil->data->{network}{interfaces}{by_name}{$interface}{speed};
my $subnet_mask = $anvil->data->{network}{interfaces}{by_name}{$interface}{subnet_mask}; my $subnet_mask = $anvil->data->{network}{interfaces}{by_name}{$interface}{subnet_mask};
my $type = $anvil->data->{network}{interfaces}{by_name}{$interface}{type};
my $up_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{up_delay}; my $up_delay = $anvil->data->{network}{interfaces}{by_name}{$interface}{up_delay};
my $default_gateway = $anvil->data->{network}{'local'}{interface}{$interface}{default_gateway}; my $default_gateway = $anvil->data->{network}{'local'}{interface}{$interface}{default_gateway};
my $gateway = $anvil->data->{network}{'local'}{interface}{$interface}{gateway}; my $gateway = $anvil->data->{network}{'local'}{interface}{$interface}{gateway};
@ -343,13 +390,13 @@ sub update_network
primary_slave => $primary_slave, primary_slave => $primary_slave,
speed => $speed, speed => $speed,
subnet_mask => $subnet_mask, subnet_mask => $subnet_mask,
type => $type,
up_delay => $up_delay, up_delay => $up_delay,
}}); }});
if (($type eq $processing) && ($type eq "bond")) if (($type eq $processing) && ($type eq "bond"))
{ {
my $bond_uuid = $anvil->Database->insert_or_update_bonds({ my $bond_uuid = $anvil->Database->insert_or_update_bonds({
debug => 3,
file => $THIS_FILE, file => $THIS_FILE,
line => __LINE__, line => __LINE__,
bond_name => $interface, bond_name => $interface,
@ -365,10 +412,11 @@ sub update_network
bond_up_delay => $up_delay, bond_up_delay => $up_delay,
bond_down_delay => $down_delay, bond_down_delay => $down_delay,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_uuid => $bond_uuid }});
$anvil->data->{bond_by_name}{$interface} = $bond_uuid; $anvil->data->{bond_by_name}{$interface} = $bond_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "bond_by_name::${interface}" => $anvil->data->{bond_by_name}{$interface} }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bond_by_name::${interface}" => $anvil->data->{bond_by_name}{$interface} }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_uuid => $bond_uuid }});
if (($bond_uuid) && ($ip_address)) if (($bond_uuid) && ($ip_address))
{ {
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
@ -388,16 +436,17 @@ sub update_network
if (($type eq $processing) && ($type eq "interface")) if (($type eq $processing) && ($type eq "interface"))
{ {
my $say_bond_uuid = ""; my $say_bond_uuid = "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { bond_master => $bond_master }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bond_master => $bond_master }});
if (($bond_master) && ($anvil->data->{bond_by_name}{$bond_master})) if (($bond_master) && ($anvil->data->{bond_by_name}{$bond_master}))
{ {
$say_bond_uuid = $anvil->data->{bond_by_name}{$bond_master}; $say_bond_uuid = $anvil->data->{bond_by_name}{$bond_master};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"bond_by_name::${bond_master}" => $anvil->data->{bond_by_name}{$bond_master}, "bond_by_name::${bond_master}" => $anvil->data->{bond_by_name}{$bond_master},
say_bond_uuid => $say_bond_uuid, say_bond_uuid => $say_bond_uuid,
}}); }});
} }
my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({
debug => 3,
file => $THIS_FILE, file => $THIS_FILE,
line => __LINE__, line => __LINE__,
network_interface_bond_uuid => $say_bond_uuid, network_interface_bond_uuid => $say_bond_uuid,
@ -410,10 +459,10 @@ sub update_network
network_interface_mtu => $mtu, network_interface_mtu => $mtu,
network_interface_speed => $speed, network_interface_speed => $speed,
}); });
$anvil->data->{interface_by_name}{$interface} = $network_interface_uuid; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { "interface_by_name::${interface}" => $anvil->data->{interface_by_name}{$interface} }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }}); $anvil->data->{interface_by_name}{$interface} = $network_interface_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "interface_by_name::${interface}" => $anvil->data->{interface_by_name}{$interface} }});
if (($network_interface_uuid) && ($ip_address)) if (($network_interface_uuid) && ($ip_address))
{ {
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({ my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
@ -429,6 +478,39 @@ sub update_network
}); });
} }
} }
### TODO: Left off here. Add 'insert_or_update_bridge_interfaces' and see why bridges aren't being saved.
if (($type eq $processing) && ($type eq "bridge"))
{
my $bridge_uuid = $anvil->Database->insert_or_update_bridges({
debug => 3,
file => $THIS_FILE,
line => __LINE__,
bridge_name => $interface,
bridge_id => $bridge_id,
bridge_mac => $mac_address,
bridge_mtu => $mtu,
bridge_stp_enabled => $bridge_stp_enabled,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { bridge_uuid => $bridge_uuid }});
$anvil->data->{bridge_by_name}{$interface} = $bridge_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "bridge_by_name::${interface}" => $anvil->data->{bridge_by_name}{$interface} }});
if (($bridge_uuid) && ($ip_address))
{
my $ip_address_uuid = $anvil->Database->insert_or_update_ip_addresses({
file => $THIS_FILE,
line => __LINE__,
ip_address_on_type => $type,
ip_address_on_uuid => $bridge_uuid,
ip_address_address => $ip_address,
ip_address_subnet_mask => $subnet_mask,
ip_address_gateway => $gateway,
ip_address_default_gateway => $default_gateway,
ip_address_dns => $dns,
});
}
}
} }
} }
@ -498,7 +580,7 @@ AND
{ {
# Mark it as deleted. # Mark it as deleted.
my $query = "UPDATE bonds SET bond_mode = 'DELETED' WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";"; my $query = "UPDATE bonds SET bond_mode = 'DELETED' WHERE bond_uuid = ".$anvil->Database->quote($bond_uuid).";";
$anvil->Database->write({debug => 2, query => $query, source => $THIS_FILE, line => __LINE__}); $anvil->Database->write({debug => 3, query => $query, source => $THIS_FILE, line => __LINE__});
# Remove it from the hash so we don't add it to the .json and .xml files. # Remove it from the hash so we don't add it to the .json and .xml files.
delete $anvil->data->{bonds}{$bond_uuid}; delete $anvil->data->{bonds}{$bond_uuid};
@ -510,6 +592,8 @@ SELECT
bridge_uuid, bridge_uuid,
bridge_name, bridge_name,
bridge_id, bridge_id,
bridge_mac,
bridge_mtu,
bridge_stp_enabled bridge_stp_enabled
FROM FROM
bridges bridges
@ -527,16 +611,24 @@ AND
}}); }});
foreach my $row (@{$results}) foreach my $row (@{$results})
{ {
my $bridge_uuid = $row->[0]; my $bridge_uuid = $row->[0];
my $bridge_name = $row->[1]; my $bridge_name = $row->[1];
my $bridge_id = $row->[2];
my $bridge_mac = $row->[3];
my $bridge_mtu = $row->[4];
my $bridge_stp_enabled = $row->[5];
$anvil->data->{bridges}{$bridge_uuid} = { $anvil->data->{bridges}{$bridge_uuid} = {
bridge_name => $bridge_name, bridge_name => $bridge_name,
bridge_id => $row->[2], bridge_id => $bridge_id,
bridge_stp_enabled => $row->[3], bridge_mac => $bridge_mac,
bridge_mtu => $bridge_mtu,
bridge_stp_enabled => $bridge_stp_enabled,
}; };
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"bridges::${bridge_uuid}::bridge_name" => $anvil->data->{bridges}{$bridge_uuid}{bridge_name}, "bridges::${bridge_uuid}::bridge_name" => $anvil->data->{bridges}{$bridge_uuid}{bridge_name},
"bridges::${bridge_uuid}::bridge_id" => $anvil->data->{bridges}{$bridge_uuid}{bridge_id}, "bridges::${bridge_uuid}::bridge_id" => $anvil->data->{bridges}{$bridge_uuid}{bridge_id},
"bridges::${bridge_uuid}::bridge_mac" => $anvil->data->{bridges}{$bridge_uuid}{bridge_mac},
"bridges::${bridge_uuid}::bridge_mtu" => $anvil->data->{bridges}{$bridge_uuid}{bridge_mtu},
"bridges::${bridge_uuid}::bridge_stp_enabled" => $anvil->data->{bridges}{$bridge_uuid}{bridge_stp_enabled}, "bridges::${bridge_uuid}::bridge_stp_enabled" => $anvil->data->{bridges}{$bridge_uuid}{bridge_stp_enabled},
}}); }});
@ -746,6 +838,39 @@ WHERE
} }
} }
# Now record the interfaces on bridges.
$anvil->Network->bridge_info({debug => 2});
foreach my $bridge_name (sort {$a cmp $b} keys %{$anvil->data->{bridge}{'local'}})
{
my $bridge_uuid = $anvil->data->{bridge_by_name}{$bridge_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bridge_name => $bridge_name,
bridge_uuid => $bridge_uuid,
}});
foreach my $interface_name (sort {$a cmp $b} @{$anvil->data->{bridge}{'local'}{$bridge_name}{interfaces}})
{
my $interface_uuid = exists $anvil->data->{bond_by_name}{$interface_name} ? $anvil->data->{bond_by_name}{$interface_name} : $anvil->data->{interface_by_name}{$interface_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
interface_name => $interface_name,
interface_uuid => $interface_uuid,
}});
my $bridge_interfaces_uuid = $anvil->Database->insert_or_update_bridge_interfaces({
debug => 2,
file => $THIS_FILE,
line => __LINE__,
bridge_interface_bridge_uuid => $bridge_uuid,
bridge_interface_network_interface_uuid => $interface_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
bridge_interfaces_uuid => $bridge_interfaces_uuid,
}});
}
}
die;
$network_json =~ s/,$//s; $network_json =~ s/,$//s;
$network_json .= "]}\n"; $network_json .= "]}\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_json => $network_json }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_json => $network_json }});

@ -53,8 +53,8 @@ if (not $anvil->data->{sys}{database}{connections})
$anvil->data->{job}{progress} = 0; $anvil->data->{job}{progress} = 0;
get_job_details($anvil); get_job_details($anvil);
wait_for_access($anvil); wait_for_access($anvil);
set_host_name($anvil); #set_host_name($anvil);
add_repos($anvil); #add_repos($anvil);
add_databases($anvil); add_databases($anvil);
$anvil->nice_exit({code => 0}); $anvil->nice_exit({code => 0});
@ -205,12 +205,29 @@ sub add_databases
} }
else else
{ {
### TODO: LEft off here; change the message to a proper one. ### TODO: Left off here; change the message to a proper one.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0076"}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, key => "error_0084"});
update_progress($anvil, 100, "error_0076"); update_progress($anvil, 100, "error_0084");
$anvil->nice_exit({exit_code => 6}); $anvil->nice_exit({exit_code => 6});
} }
# Now add any peers we know about.
foreach my $uuid (keys %{$anvil->data->{database}})
{
next if $uuid eq $anvil->data->{sys}{host_uuid};
# This is a peer.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"database::${uuid}::host" => $anvil->data->{database}{$uuid}{host},
"database::${uuid}::port" => $anvil->data->{database}{$uuid}{port},
"database::${uuid}::password" => $anvil->Log->is_secure($anvil->data->{database}{$uuid}{password}),
"database::${uuid}::ping" => $anvil->data->{database}{$uuid}{ping},
}});
# The host may not be able to reach the 'host' that we can. So get the IPs we know about for
# this host and see if we can find a match.
}
return(0); return(0);
} }

Loading…
Cancel
Save