From 7cdd2f60e922a7add1e2ea43add98055fccfc81f Mon Sep 17 00:00:00 2001 From: Digimer Date: Sat, 12 Oct 2019 00:32:32 -0400 Subject: [PATCH] * 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 --- Anvil/Tools.pm | 1 + Anvil/Tools/Database.pm | 248 +++++++++++- Anvil/Tools/Network.pm | 522 +++++++++++++++++++++++- Anvil/Tools/Server.pm | 739 ++++++++++++++++++++-------------- ocf/alteeve/server | 52 +-- share/anvil.sql | 124 +++++- share/words.xml | 8 + tools/anvil-manage-keys | 5 +- tools/anvil-update-states | 169 +++++++- tools/striker-initialize-host | 27 +- 10 files changed, 1521 insertions(+), 374 deletions(-) diff --git a/Anvil/Tools.pm b/Anvil/Tools.pm index de2de911..e6ccf97f 100644 --- a/Anvil/Tools.pm +++ b/Anvil/Tools.pm @@ -1174,6 +1174,7 @@ sub _set_paths }, urls => { skins => "/skins", + oui_file => "http://standards.ieee.org/develop/regauth/oui/oui.txt", }, words => { 'words.xml' => "/usr/share/anvil/words.xml", diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index deb29624..25d34cab 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -26,6 +26,7 @@ my $THIS_FILE = "Database.pm"; # get_jobs # get_local_uuid # initialize +# insert_or_update_bridge_interfaces # insert_or_update_bridges # insert_or_update_bonds # insert_or_update_file_locations @@ -1827,6 +1828,223 @@ sub initialize 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 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. +=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) 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_name = defined $parameter->{bridge_name} ? $parameter->{bridge_name} : ""; 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} : ""; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid, @@ -1892,6 +2120,8 @@ sub insert_or_update_bridges bridge_host_uuid => $bridge_host_uuid, bridge_name => $bridge_name, bridge_id => $bridge_id, + bridge_mac => $bridge_mac, + bridge_mtu => $bridge_mtu, bridge_stp_enabled => $bridge_stp_enabled, }}); @@ -1968,6 +2198,8 @@ INSERT INTO bridge_host_uuid, bridge_name, bridge_id, + bridge_mac, + bridge_mtu, bridge_stp_enabled, modified_date ) VALUES ( @@ -1975,6 +2207,8 @@ INSERT INTO ".$anvil->Database->quote($bridge_host_uuid).", ".$anvil->Database->quote($bridge_name).", ".$anvil->Database->quote($bridge_id).", + ".$anvil->Database->quote($bridge_mac).", + ".$anvil->Database->quote($bridge_mtu).", ".$anvil->Database->quote($bridge_stp_enabled).", ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." ); @@ -1990,6 +2224,8 @@ SELECT bridge_host_uuid, bridge_name, bridge_id, + bridge_mac, + bridge_mtu, bridge_stp_enabled FROM bridges @@ -2015,11 +2251,15 @@ WHERE my $old_bridge_host_uuid = $row->[0]; my $old_bridge_name = $row->[1]; 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 => { old_bridge_host_uuid => $old_bridge_host_uuid, 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, }}); @@ -2027,6 +2267,8 @@ WHERE if (($old_bridge_host_uuid ne $bridge_host_uuid) or ($old_bridge_name ne $bridge_name) 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)) { # Something changed, save. @@ -2037,6 +2279,8 @@ SET bridge_host_uuid = ".$anvil->Database->quote($bridge_host_uuid).", bridge_name = ".$anvil->Database->quote($bridge_name).", 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).", modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})." WHERE diff --git a/Anvil/Tools/Network.pm b/Anvil/Tools/Network.pm index 1a816432..ce967afb 100755 --- a/Anvil/Tools/Network.pm +++ b/Anvil/Tools/Network.pm @@ -12,12 +12,15 @@ our $VERSION = "3.0.0"; my $THIS_FILE = "Network.pm"; ### Methods; +# bridge_info # check_internet +# download # find_matches # get_ips # get_network # is_local # is_remote +# load_ips # ping =pod @@ -79,6 +82,131 @@ sub parent # 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::::::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:::::::: = + +The common variables are; + +* bridge::::::::ifindex = Interface index number. +* bridge::::::::flags = An array reference storing the flags set for the interface on the bridge. +* bridge::::::::mtu = The maximum transmitable unit size, in bytes. +* bridge::::::::state = The state of the bridge. +* bridge::::::::priority = The priority for this interface. +* bridge::::::::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 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 $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()" }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->check_internet()" }}); my $access = 0; my $domains = defined $parameter->{domains} ? $parameter->{domains} : $anvil->data->{defaults}{network}{test}{domains}; @@ -196,6 +324,211 @@ sub check_internet 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 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); } +=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::::interface::::ip >> - If an IP address is set +* C<< network::::interface::::subnet >> - If an IP is set +* C<< network::::interface::::mac >> - Always set. +* C<< network::::interface::::default_gateway >> = C<< 0 >> if not the default gateway, C<< 1 >> if so. +* C<< network::::interface::::gateway >> = If the default gateway, this is the gateway IP address. +* C<< network::::interface::::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 This method checks the local system for interfaces and stores them in: diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index e6a6eaa8..3ff1cb12 100755 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -15,6 +15,7 @@ my $THIS_FILE = "Server.pm"; # boot # find # get_status +# map_network # migrate # shutdown @@ -288,7 +289,7 @@ sub find =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::::from_disk::x' for data from the on-disk XML and 'server::::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::::::from_disk::x >> for data from the on-disk XML and C<< server::>::::from_memory::x >>. 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" }}); 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. $anvil->DRBD->get_devices({ @@ -361,7 +362,7 @@ sub get_status { # Remote call. $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, shell_call => $shell_call, target => $target, @@ -371,39 +372,39 @@ sub get_status }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error, - "server::${server}::from_memory::xml" => $anvil->data->{server}{$server}{from_memory}{xml}, - "server::${server}::from_memory::return_code" => $anvil->data->{server}{$server}{from_memory}{return_code}, + "server::${target}::${server}::from_memory::xml" => $anvil->data->{server}{$target}{$server}{from_memory}{xml}, + "server::${target}::${server}::from_memory::return_code" => $anvil->data->{server}{$target}{$server}{from_memory}{return_code}, }}); } else { # Local. - ($anvil->data->{server}{$server}{from_memory}{xml}, $anvil->data->{server}{$server}{from_memory}{return_code}) = $anvil->System->call({shell_call => $shell_call}); + ($anvil->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 => { - "server::${server}::from_memory::xml" => $anvil->data->{server}{$server}{from_memory}{xml}, - "server::${server}::from_memory::return_code" => $anvil->data->{server}{$server}{from_memory}{return_code}, + "server::${target}::${server}::from_memory::xml" => $anvil->data->{server}{$target}{$server}{from_memory}{xml}, + "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 ($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 { - $anvil->data->{server}{$server}{from_memory}{host} = $host; + $anvil->data->{server}{$target}{$server}{from_memory}{host} = $host; $anvil->Server->_parse_definition({ debug => $debug, host => $host, server => $server, 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. - ($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, password => $password, port => $port, @@ -413,12 +414,12 @@ sub get_status file => $anvil->data->{path}{directories}{shared}{definitions}."/".$server.".xml", }); $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. - $anvil->data->{server}{$server}{from_disk}{xml} = ""; + $anvil->data->{server}{$target}{$server}{from_disk}{xml} = ""; } else { @@ -427,13 +428,226 @@ sub get_status host => $host, server => $server, source => "from_disk", - definition => $anvil->data->{server}{$server}{from_disk}{xml}, + definition => $anvil->data->{server}{$target}{$server}{from_disk}{xml}, }); } 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 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); } -=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 # # Private Functions; @@ -764,6 +882,7 @@ sub _parse_definition my $source = defined $parameter->{source} ? $parameter->{source} : ""; my $definition = defined $parameter->{definition} ? $parameter->{definition} : ""; 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 => { server => $server, source => $source, @@ -801,73 +920,73 @@ sub _parse_definition $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; #die; # Pull out some basic server info. - $anvil->data->{server}{$server}{$source}{info}{uuid} = $server_xml->{uuid}->[0]; - $anvil->data->{server}{$server}{$source}{info}{name} = $server_xml->{name}->[0]; - $anvil->data->{server}{$server}{$source}{info}{on_poweroff} = $server_xml->{on_poweroff}->[0]; - $anvil->data->{server}{$server}{$source}{info}{on_crash} = $server_xml->{on_crash}->[0]; - $anvil->data->{server}{$server}{$source}{info}{on_reboot} = $server_xml->{on_reboot}->[0]; - $anvil->data->{server}{$server}{$source}{info}{boot_menu} = $server_xml->{os}->[0]->{bootmenu}->[0]->{enable}; - $anvil->data->{server}{$server}{$source}{info}{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}{$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}{$server}{$source}{info}{acpi} = exists $server_xml->{features}->[0]->{acpi} ? 1 : 0; + $anvil->data->{server}{$target}{$server}{$source}{info}{uuid} = $server_xml->{uuid}->[0]; + $anvil->data->{server}{$target}{$server}{$source}{info}{name} = $server_xml->{name}->[0]; + $anvil->data->{server}{$target}{$server}{$source}{info}{on_poweroff} = $server_xml->{on_poweroff}->[0]; + $anvil->data->{server}{$target}{$server}{$source}{info}{on_crash} = $server_xml->{on_crash}->[0]; + $anvil->data->{server}{$target}{$server}{$source}{info}{on_reboot} = $server_xml->{on_reboot}->[0]; + $anvil->data->{server}{$target}{$server}{$source}{info}{boot_menu} = $server_xml->{os}->[0]->{bootmenu}->[0]->{enable}; + $anvil->data->{server}{$target}{$server}{$source}{info}{architecture} = $server_xml->{os}->[0]->{type}->[0]->{arch}; + $anvil->data->{server}{$target}{$server}{$source}{info}{machine} = $server_xml->{os}->[0]->{type}->[0]->{machine}; + $anvil->data->{server}{$target}{$server}{$source}{info}{id} = exists $server_xml->{id} ? $server_xml->{id} : 0; + $anvil->data->{server}{$target}{$server}{$source}{info}{emulator} = $server_xml->{devices}->[0]->{emulator}->[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 => { - "server::${server}::${source}::info::uuid" => $anvil->data->{server}{$server}{$source}{info}{uuid}, - "server::${server}::${source}::info::name" => $anvil->data->{server}{$server}{$source}{info}{name}, - "server::${server}::${source}::info::on_poweroff" => $anvil->data->{server}{$server}{$source}{info}{on_poweroff}, - "server::${server}::${source}::info::on_crash" => $anvil->data->{server}{$server}{$source}{info}{on_crash}, - "server::${server}::${source}::info::on_reboot" => $anvil->data->{server}{$server}{$source}{info}{on_reboot}, - "server::${server}::${source}::info::architecture" => $anvil->data->{server}{$server}{$source}{info}{architecture}, - "server::${server}::${source}::info::machine" => $anvil->data->{server}{$server}{$source}{info}{machine}, - "server::${server}::${source}::info::boot_menu" => $anvil->data->{server}{$server}{$source}{info}{boot_menu}, - "server::${server}::${source}::info::id" => $anvil->data->{server}{$server}{$source}{info}{id}, - "server::${server}::${source}::info::emulator" => $anvil->data->{server}{$server}{$source}{info}{emulator}, - "server::${server}::${source}::info::acpi" => $anvil->data->{server}{$server}{$source}{info}{acpi}, + "server::${target}::${server}::${source}::info::uuid" => $anvil->data->{server}{$target}{$server}{$source}{info}{uuid}, + "server::${target}::${server}::${source}::info::name" => $anvil->data->{server}{$target}{$server}{$source}{info}{name}, + "server::${target}::${server}::${source}::info::on_poweroff" => $anvil->data->{server}{$target}{$server}{$source}{info}{on_poweroff}, + "server::${target}::${server}::${source}::info::on_crash" => $anvil->data->{server}{$target}{$server}{$source}{info}{on_crash}, + "server::${target}::${server}::${source}::info::on_reboot" => $anvil->data->{server}{$target}{$server}{$source}{info}{on_reboot}, + "server::${target}::${server}::${source}::info::architecture" => $anvil->data->{server}{$target}{$server}{$source}{info}{architecture}, + "server::${target}::${server}::${source}::info::machine" => $anvil->data->{server}{$target}{$server}{$source}{info}{machine}, + "server::${target}::${server}::${source}::info::boot_menu" => $anvil->data->{server}{$target}{$server}{$source}{info}{boot_menu}, + "server::${target}::${server}::${source}::info::id" => $anvil->data->{server}{$target}{$server}{$source}{info}{id}, + "server::${target}::${server}::${source}::info::emulator" => $anvil->data->{server}{$target}{$server}{$source}{info}{emulator}, + "server::${target}::${server}::${source}::info::acpi" => $anvil->data->{server}{$target}{$server}{$source}{info}{acpi}, }}); # CPU - $anvil->data->{server}{$server}{$source}{cpu}{total_cores} = $server_xml->{vcpu}->[0]->{content}; - $anvil->data->{server}{$server}{$source}{cpu}{sockets} = $server_xml->{cpu}->[0]->{topology}->[0]->{sockets}; - $anvil->data->{server}{$server}{$source}{cpu}{cores} = $server_xml->{cpu}->[0]->{topology}->[0]->{cores}; - $anvil->data->{server}{$server}{$source}{cpu}{threads} = $server_xml->{cpu}->[0]->{topology}->[0]->{threads}; - $anvil->data->{server}{$server}{$source}{cpu}{model_name} = $server_xml->{cpu}->[0]->{model}->[0]->{content}; - $anvil->data->{server}{$server}{$source}{cpu}{model_fallback} = $server_xml->{cpu}->[0]->{model}->[0]->{fallback}; - $anvil->data->{server}{$server}{$source}{cpu}{match} = $server_xml->{cpu}->[0]->{match}; - $anvil->data->{server}{$server}{$source}{cpu}{vendor} = $server_xml->{cpu}->[0]->{vendor}->[0]; - $anvil->data->{server}{$server}{$source}{cpu}{mode} = $server_xml->{cpu}->[0]->{mode}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{total_cores} = $server_xml->{vcpu}->[0]->{content}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{sockets} = $server_xml->{cpu}->[0]->{topology}->[0]->{sockets}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{cores} = $server_xml->{cpu}->[0]->{topology}->[0]->{cores}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{threads} = $server_xml->{cpu}->[0]->{topology}->[0]->{threads}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{model_name} = $server_xml->{cpu}->[0]->{model}->[0]->{content}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{model_fallback} = $server_xml->{cpu}->[0]->{model}->[0]->{fallback}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{match} = $server_xml->{cpu}->[0]->{match}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{vendor} = $server_xml->{cpu}->[0]->{vendor}->[0]; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{mode} = $server_xml->{cpu}->[0]->{mode}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "server::${server}::${source}::cpu::total_cores" => $anvil->data->{server}{$server}{$source}{cpu}{total_cores}, - "server::${server}::${source}::cpu::sockets" => $anvil->data->{server}{$server}{$source}{cpu}{sockets}, - "server::${server}::${source}::cpu::cores" => $anvil->data->{server}{$server}{$source}{cpu}{cores}, - "server::${server}::${source}::cpu::threads" => $anvil->data->{server}{$server}{$source}{cpu}{threads}, - "server::${server}::${source}::cpu::model_name" => $anvil->data->{server}{$server}{$source}{cpu}{model_name}, - "server::${server}::${source}::cpu::model_fallback" => $anvil->data->{server}{$server}{$source}{cpu}{model_fallback}, - "server::${server}::${source}::cpu::match" => $anvil->data->{server}{$server}{$source}{cpu}{match}, - "server::${server}::${source}::cpu::vendor" => $anvil->data->{server}{$server}{$source}{cpu}{vendor}, - "server::${server}::${source}::cpu::mode" => $anvil->data->{server}{$server}{$source}{cpu}{mode}, + "server::${target}::${server}::${source}::cpu::total_cores" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{total_cores}, + "server::${target}::${server}::${source}::cpu::sockets" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{sockets}, + "server::${target}::${server}::${source}::cpu::cores" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{cores}, + "server::${target}::${server}::${source}::cpu::threads" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{threads}, + "server::${target}::${server}::${source}::cpu::model_name" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{model_name}, + "server::${target}::${server}::${source}::cpu::model_fallback" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{model_fallback}, + "server::${target}::${server}::${source}::cpu::match" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{match}, + "server::${target}::${server}::${source}::cpu::vendor" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{vendor}, + "server::${target}::${server}::${source}::cpu::mode" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{mode}, }}); foreach my $hash_ref (@{$server_xml->{cpu}->[0]->{feature}}) { my $name = $hash_ref->{name}; - $anvil->data->{server}{$server}{$source}{cpu}{feature}{$name} = $hash_ref->{policy}; + $anvil->data->{server}{$target}{$server}{$source}{cpu}{feature}{$name} = $hash_ref->{policy}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "server::${server}::${source}::cpu::feature::${name}" => $anvil->data->{server}{$server}{$source}{cpu}{feature}{$name}, + "server::${target}::${server}::${source}::cpu::feature::${name}" => $anvil->data->{server}{$target}{$server}{$source}{cpu}{feature}{$name}, }}); } # Power Management - $anvil->data->{server}{$server}{$source}{pm}{'suspend-to-disk'} = $server_xml->{pm}->[0]->{'suspend-to-disk'}->[0]->{enabled}; - $anvil->data->{server}{$server}{$source}{pm}{'suspend-to-mem'} = $server_xml->{pm}->[0]->{'suspend-to-mem'}->[0]->{enabled}; + $anvil->data->{server}{$target}{$server}{$source}{pm}{'suspend-to-disk'} = $server_xml->{pm}->[0]->{'suspend-to-disk'}->[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 => { - "server::${server}::${source}::pm::suspend-to-disk" => $anvil->data->{server}{$server}{$source}{pm}{'suspend-to-disk'}, - "server::${server}::${source}::pm::suspend-to-mem" => $anvil->data->{server}{$server}{$source}{pm}{'suspend-to-mem'}, + "server::${target}::${server}::${source}::pm::suspend-to-disk" => $anvil->data->{server}{$target}{$server}{$source}{pm}{'suspend-to-disk'}, + "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 @@ -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}).")", }}); - $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 => { - "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 - $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 => { - "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}}) { @@ -904,9 +1023,9 @@ sub _parse_definition foreach my $variable (keys %{$hash_ref}) { 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 => { - "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}; # 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}{$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}{$server}{$source}{device}{channel}{unix}{address}{type} = $address_type; - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{bus} = $address_bus; - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{controller} = $address_controller; - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{port} = $address_port; - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{type} = $hash_ref->{target}->[0]->{type}; - $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'} = 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}{source}{mode} = defined $hash_ref->{source}->[0]->{mode} ? $hash_ref->{source}->[0]->{mode} : ""; + $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}{$target}{$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}{address}{type} = $address_type; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{bus} = $address_bus; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{controller} = $address_controller; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{port} = $address_port; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{target}{type} = $hash_ref->{target}->[0]->{type}; + $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}{$target}{$server}{$source}{device}{channel}{unix}{target}{name} = $hash_ref->{target}->[0]->{name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "server::${server}::${source}::device::channel::unix::source::mode" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{mode}, - "server::${server}::${source}::device::channel::unix::source::path" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{source}{path}, - "server::${server}::${source}::device::channel::unix::alias" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{alias}, - "server::${server}::${source}::device::channel::unix::address::type" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{type}, - "server::${server}::${source}::device::channel::unix::address::bus" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{bus}, - "server::${server}::${source}::device::channel::unix::address::controller" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{controller}, - "server::${server}::${source}::device::channel::unix::address::port" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{address}{port}, - "server::${server}::${source}::device::channel::unix::target::type" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{type}, - "server::${server}::${source}::device::channel::unix::target::state" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{'state'}, - "server::${server}::${source}::device::channel::unix::target::name" => $anvil->data->{server}{$server}{$source}{device}{channel}{unix}{target}{name}, + "server::${target}::${server}::${source}::device::channel::unix::source::mode" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{source}{mode}, + "server::${target}::${server}::${source}::device::channel::unix::source::path" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{source}{path}, + "server::${target}::${server}::${source}::device::channel::unix::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{alias}, + "server::${target}::${server}::${source}::device::channel::unix::address::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{type}, + "server::${target}::${server}::${source}::device::channel::unix::address::bus" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{bus}, + "server::${target}::${server}::${source}::device::channel::unix::address::controller" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{controller}, + "server::${target}::${server}::${source}::device::channel::unix::address::port" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{address}{port}, + "server::${target}::${server}::${source}::device::channel::unix::target::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{target}{type}, + "server::${target}::${server}::${source}::device::channel::unix::target::state" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{unix}{target}{'state'}, + "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". # 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 => { -# "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") @@ -964,30 +1083,30 @@ sub _parse_definition my $address_port = $hash_ref->{address}->[0]->{port}; # Store - $anvil->data->{server}{$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}{$server}{$source}{device}{channel}{spicevmc}{address}{bus} = $address_bus; - $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{controller} = $address_controller; - $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{port} = $address_port; - $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{type} = $hash_ref->{target}->[0]->{type}; - $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'} = 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}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{type} = $address_type; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{bus} = $address_bus; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{controller} = $address_controller; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{port} = $address_port; + $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{target}{type} = $hash_ref->{target}->[0]->{type}; + $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}{$target}{$server}{$source}{device}{channel}{spicevmc}{target}{name} = $hash_ref->{target}->[0]->{name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - "server::${server}::${source}::device::channel::spicevmc::alias" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{alias}, - "server::${server}::${source}::device::channel::spicevmc::address::type" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{type}, - "server::${server}::${source}::device::channel::spicevmc::address::bus" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{bus}, - "server::${server}::${source}::device::channel::spicevmc::address::controller" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{controller}, - "server::${server}::${source}::device::channel::spicevmc::address::port" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{address}{port}, - "server::${server}::${source}::device::channel::spicevmc::target::type" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{type}, - "server::${server}::${source}::device::channel::spicevmc::target::state" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'}, - "server::${server}::${source}::device::channel::spicevmc::target::name" => $anvil->data->{server}{$server}{$source}{device}{channel}{spicevmc}{target}{name}, + "server::${target}::${server}::${source}::device::channel::spicevmc::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{alias}, + "server::${target}::${server}::${source}::device::channel::spicevmc::address::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{type}, + "server::${target}::${server}::${source}::device::channel::spicevmc::address::bus" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{bus}, + "server::${target}::${server}::${source}::device::channel::spicevmc::address::controller" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{controller}, + "server::${target}::${server}::${source}::device::channel::spicevmc::address::port" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{address}{port}, + "server::${target}::${server}::${source}::device::channel::spicevmc::target::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{target}{type}, + "server::${target}::${server}::${source}::device::channel::spicevmc::target::state" => $anvil->data->{server}{$target}{$server}{$source}{device}{channel}{spicevmc}{target}{'state'}, + "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". # 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 => { -# "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 foreach my $hash_ref (@{$server_xml->{devices}->[0]->{console}}) { - $anvil->data->{server}{$server}{$source}{device}{console}{type} = $hash_ref->{type}; - $anvil->data->{server}{$server}{$source}{device}{console}{tty} = 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}{$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}{$server}{$source}{device}{console}{target_port} = $hash_ref->{target}->[0]->{port}; + $anvil->data->{server}{$target}{$server}{$source}{device}{console}{type} = $hash_ref->{type}; + $anvil->data->{server}{$target}{$server}{$source}{device}{console}{tty} = defined $hash_ref->{tty} ? $hash_ref->{tty} : ""; + $anvil->data->{server}{$target}{$server}{$source}{device}{console}{alias} = defined $hash_ref->{alias}->[0]->{name} ? $hash_ref->{alias}->[0]->{name} : ""; + $anvil->data->{server}{$target}{$server}{$source}{device}{console}{source} = defined $hash_ref->{source}->[0]->{path} ? $hash_ref->{source}->[0]->{path} : ""; + $anvil->data->{server}{$target}{$server}{$source}{device}{console}{target_type} = $hash_ref->{target}->[0]->{type}; + $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 => { - "server::${server}::${source}::device::console::type" => $anvil->data->{server}{$server}{$source}{device}{console}{type}, - "server::${server}::${source}::device::console::tty" => $anvil->data->{server}{$server}{$source}{device}{console}{tty}, - "server::${server}::${source}::device::console::alias" => $anvil->data->{server}{$server}{$source}{device}{console}{alias}, - "server::${server}::${source}::device::console::source" => $anvil->data->{server}{$server}{$source}{device}{console}{source}, - "server::${server}::${source}::device::console::target_type" => $anvil->data->{server}{$server}{$source}{device}{console}{target_type}, - "server::${server}::${source}::device::console::target_port" => $anvil->data->{server}{$server}{$source}{device}{console}{target_port}, + "server::${target}::${server}::${source}::device::console::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{type}, + "server::${target}::${server}::${source}::device::console::tty" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{tty}, + "server::${target}::${server}::${source}::device::console::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{alias}, + "server::${target}::${server}::${source}::device::console::source" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{source}, + "server::${target}::${server}::${source}::device::console::target_type" => $anvil->data->{server}{$target}{$server}{$source}{device}{console}{target_type}, + "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 - $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 => { - "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) { - $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 => { - "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) { - $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 => { - "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) { - $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{chassis} = $target_chassis; - $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{port} = $target_port; + $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{chassis} = $target_chassis; + $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 => { - "server::${server}::${source}::device::controller::${type}::index::${index}::target::chassis" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{chassis}, - "server::${server}::${source}::device::controller::${type}::index::${index}::target::port" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{target}{port}, + "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::${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) { - $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{type} = $address_type; - $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{domain} = $address_domain; - $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{bus} = $address_bus; - $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{slot} = $address_slot; - $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{function} = $address_function; + $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{type} = $address_type; + $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{domain} = $address_domain; + $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{bus} = $address_bus; + $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{slot} = $address_slot; + $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 => { - "server::${server}::${source}::device::controller::${type}::index::${index}::address::type" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{type}, - "server::${server}::${source}::device::controller::${type}::index::${index}::address::domain" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{domain}, - "server::${server}::${source}::device::controller::${type}::index::${index}::address::bus" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{bus}, - "server::${server}::${source}::device::controller::${type}::index::${index}::address::slot" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{slot}, - "server::${server}::${source}::device::controller::${type}::index::${index}::address::function" => $anvil->data->{server}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{function}, + "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::${target}::${server}::${source}::device::controller::${type}::index::${index}::address::domain" => $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{domain}, + "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::${target}::${server}::${source}::device::controller::${type}::index::${index}::address::slot" => $anvil->data->{server}{$target}{$server}{$source}{device}{controller}{$type}{'index'}{$index}{address}{slot}, + "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". @@ -1098,9 +1217,9 @@ sub _parse_definition # - Target chassis: [2], port: [0x11] # - Bus type: [pci], domain: [0x0000], bus: [0x00], slot: [0x02], function: [0x1] # server::test_server::from_memory::address::virtio-serial::controller::0::bus::0::port::2: [channel - spicevmc] -# $anvil->data->{server}{$server}{$source}{address}{$address_type}{controller}{$type}{bus}{$address_bus}{bus}{$address_bus}{slot}{$address_slot}{function}{$address_function}{domain} = $address_domain; +# $anvil->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 => { -# "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 - $anvil->data->{server}{$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}{$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}{$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}{$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}{alias} = $alias; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{boot_order} = $boot_order; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{type} = $type; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{type} = $address_type; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{bus} = $address_bus; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{name} = $driver_name; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{device_bus} = $device_bus; + $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 => { - "server::${server}::${source}::device::${device}::target::${device_target}::address::type" => $anvil->data->{server}{$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::${server}::${source}::device::${device}::target::${device_target}::alias" => $anvil->data->{server}{$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::${server}::${source}::device::${device}::target::${device_target}::device_bus" => $anvil->data->{server}{$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::${server}::${source}::device::${device}::target::${device_target}::driver::type" => $anvil->data->{server}{$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}::address::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{type}, + "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::${target}::${server}::${source}::device::${device}::target::${device_target}::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{alias}, + "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::${target}::${server}::${source}::device::${device}::target::${device_target}::device_bus" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{device_bus}, + "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::${target}::${server}::${source}::device::${device}::target::${device_target}::driver::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{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 @@ -1176,46 +1295,46 @@ sub _parse_definition 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} : ""; - $anvil->data->{server}{$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}{$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}{$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}{address}{domain} = $address_domain; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{slot} = $address_slot; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{function} = $address_function; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{path} = $device_path; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{driver}{io} = $driver_io; + $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 => { - "server::${server}::${source}::device::${device}::target::${device_target}::address::domain" => $anvil->data->{server}{$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::${server}::${source}::device::${device}::target::${device_target}::address::function" => $anvil->data->{server}{$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::${server}::${source}::device::${device}::target::${device_target}::driver::io" => $anvil->data->{server}{$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}::address::domain" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{domain}, + "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::${target}::${server}::${source}::device::${device}::target::${device_target}::address::function" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{function}, + "server::${target}::${server}::${source}::device::${device}::target::${device_target}::path" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{path}, + "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::${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 $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}{$server}{device}{$device_path}{resource} = $resource; - $anvil->data->{server}{$server}{device}{$device_path}{target} = $device_target; - $anvil->data->{server}{$server}{resource}{$resource} = 1; + $anvil->data->{server}{$target}{$server}{device}{$device_path}{on_lv} = $on_lv; + $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource} = $resource; + $anvil->data->{server}{$target}{$server}{device}{$device_path}{target} = $device_target; + $anvil->data->{server}{$target}{$server}{resource}{$resource} = 1; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host => $host, - "server::${server}::device::${device_path}::on_lv" => $anvil->data->{server}{$server}{device}{$device_path}{on_lv}, - "server::${server}::device::${device_path}::resource" => $anvil->data->{server}{$server}{device}{$device_path}{resource}, - "server::${server}::device::${device_path}::target" => $anvil->data->{server}{$server}{device}{$device_path}{target}, - "server::${server}::resource::${resource}" => $anvil->data->{server}{$server}{resource}{$resource}, + "server::${target}::${server}::device::${device_path}::on_lv" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{on_lv}, + "server::${target}::${server}::device::${device_path}::resource" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource}, + "server::${target}::${server}::device::${device_path}::target" => $anvil->data->{server}{$target}{$server}{device}{$device_path}{target}, + "server::${target}::${server}::resource::${resource}" => $anvil->data->{server}{$target}{$server}{resource}{$resource}, }}); # Keep a list of DRBD resources used by this server. - my $drbd_resource = $anvil->data->{server}{$server}{device}{$device_path}{resource}; - $anvil->data->{server}{$server}{drbd}{resource}{$drbd_resource} = 1; + my $drbd_resource = $anvil->data->{server}{$target}{$server}{device}{$device_path}{resource}; + $anvil->data->{server}{$target}{$server}{drbd}{resource}{$drbd_resource} = 1; $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". -# $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 => { -# "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 @@ -1225,45 +1344,45 @@ sub _parse_definition my $address_unit = $hash_ref->{address}->[0]->{unit}; 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}{$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}{$server}{$source}{device}{$device}{target}{$device_target}{path} = $device_path; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{controller} = $address_controller; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{unit} = $address_unit; + $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{target} = $address_target; + $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 => { - "server::${server}::${source}::device::${device}::target::${device_target}::address::controller" => $anvil->data->{server}{$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::${server}::${source}::device::${device}::target::${device_target}::address::target" => $anvil->data->{server}{$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}::address::controller" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{controller}, + "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::${target}::${server}::${source}::device::${device}::target::${device_target}::address::target" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{address}{target}, + "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}}) { #print Dumper $hash_ref; my $mac = $hash_ref->{mac}->[0]->{address}; - $anvil->data->{server}{$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}{$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}{$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}{$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}{$server}{$source}{device}{interface}{$mac}{address}{function} = $hash_ref->{address}->[0]->{function}; + $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{bridge} = $hash_ref->{source}->[0]->{bridge}; + $anvil->data->{server}{$target}{$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}{target} = defined $hash_ref->{target}->[0]->{dev} ? $hash_ref->{target}->[0]->{dev} : ""; + $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{model} = $hash_ref->{model}->[0]->{type}; + $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{bus} = $hash_ref->{address}->[0]->{bus}; + $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{domain} = $hash_ref->{address}->[0]->{domain}; + $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{type} = $hash_ref->{address}->[0]->{type}; + $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{slot} = $hash_ref->{address}->[0]->{slot}; + $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 => { - "server::${server}::${source}::device::interface::${mac}::bridge" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{bridge}, - "server::${server}::${source}::device::interface::${mac}::alias" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{alias}, - "server::${server}::${source}::device::interface::${mac}::target" => $anvil->data->{server}{$server}{$source}{device}{interface}{$mac}{target}, - "server::${server}::${source}::device::interface::${mac}::model" => $anvil->data->{server}{$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::${server}::${source}::device::interface::${mac}::address::domain" => $anvil->data->{server}{$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::${server}::${source}::device::interface::${mac}::address::slot" => $anvil->data->{server}{$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}::bridge" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{bridge}, + "server::${target}::${server}::${source}::device::interface::${mac}::alias" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{alias}, + "server::${target}::${server}::${source}::device::interface::${mac}::target" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{target}, + "server::${target}::${server}::${source}::device::interface::${mac}::model" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{model}, + "server::${target}::${server}::${source}::device::interface::${mac}::address::bus" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{bus}, + "server::${target}::${server}::${source}::device::interface::${mac}::address::domain" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{domain}, + "server::${target}::${server}::${source}::device::interface::${mac}::address::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{type}, + "server::${target}::${server}::${source}::device::interface::${mac}::address::slot" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{slot}, + "server::${target}::${server}::${source}::device::interface::${mac}::address::function" => $anvil->data->{server}{$target}{$server}{$source}{device}{interface}{$mac}{address}{function}, }}); } diff --git a/ocf/alteeve/server b/ocf/alteeve/server index 47985e9e..e96381c9 100755 --- a/ocf/alteeve/server +++ b/ocf/alteeve/server @@ -361,7 +361,7 @@ sub stop_drbd_resource }}); # 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}; $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? my $startup_needed = 0; $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. my $role = $anvil->data->{drbd}{status}{$host}{resource}{$resource}{role}; @@ -434,7 +434,7 @@ sub start_drbd_resource } # 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}; $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 (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 => { server => $server, @@ -747,7 +747,7 @@ sub migrate_server host => $host, 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 $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. 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 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 }}); 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'. my $server = $anvil->data->{environment}{OCF_RESKEY_name}; my $source = "from_disk"; - if ($anvil->data->{server}{$server}{from_memory}{host}) + if ($anvil->data->{server}{'local'}{$server}{from_memory}{host}) { $source = "from_memory"; } @@ -1005,13 +1005,13 @@ sub validate_storage ### 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 # 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 }}); if (not -e $file) { @@ -1053,22 +1053,22 @@ sub validate_storage_drbd my $host = $anvil->_short_host_name; # 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; $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->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 $on_lv = $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_device}{on}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { @@ -1122,10 +1122,10 @@ sub validate_emulator # What emulator is this using? 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 => { - emulator => $emulator, - "server::${server}::from_disk::info::emulator" => $anvil->data->{server}{$server}{from_disk}{info}{emulator} + emulator => $emulator, + "server::local::${server}::from_disk::info::emulator" => $anvil->data->{server}{'local'}{$server}{from_disk}{info}{emulator} }}); if (not -e $emulator) { @@ -1154,12 +1154,12 @@ sub validate_name my $server = $anvil->data->{environment}{OCF_RESKEY_name}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { - server => $server, - "server::${server}::from_disk::info::name" => $anvil->data->{server}{$server}{from_disk}{info}{name}, + server => $server, + "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 (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 => { server => $server, @@ -1169,11 +1169,11 @@ sub validate_name } # 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 => { 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}); } @@ -1189,7 +1189,7 @@ sub validate_ram # How mcuh RAM does the server need and how much do we have free? 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}); $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}).")", diff --git a/share/anvil.sql b/share/anvil.sql index 6d81b0e5..61e52b38 100644 --- a/share/anvil.sql +++ b/share/anvil.sql @@ -982,7 +982,9 @@ CREATE TABLE bridges ( bridge_host_uuid uuid not null, bridge_name 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, FOREIGN KEY(bridge_host_uuid) REFERENCES hosts(host_uuid) @@ -995,6 +997,8 @@ CREATE TABLE history.bridges ( bridge_host_uuid uuid, bridge_name text, bridge_id text, + bridge_mac text, + bridge_mtu text, bridge_stp_enabled text, modified_date timestamp with time zone not null ); @@ -1007,17 +1011,21 @@ DECLARE BEGIN SELECT INTO history_bridges * FROM bridges WHERE bridge_uuid = new.bridge_uuid; INSERT INTO history.bridges - (bridge_uuid, - bridge_host_uuid, - bridge_name, - bridge_id, - bridge_stp_enabled, + (bridge_uuid, + bridge_host_uuid, + bridge_name, + bridge_id, + bridge_mac, + bridge_mtu, + bridge_stp_enabled, modified_date) VALUES (history_bridges.bridge_uuid, history_bridges.bridge_host_uuid, history_bridges.bridge_name, history_bridges.bridge_id, + history_bridges.bridge_mac, + history_bridges.bridge_mtu, history_bridges.bridge_stp_enabled, history_bridges.modified_date); RETURN NULL; @@ -1031,6 +1039,63 @@ CREATE TRIGGER trigger_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. CREATE TABLE ip_addresses ( ip_address_uuid uuid not null primary key, @@ -1376,6 +1441,53 @@ CREATE TRIGGER trigger_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. -- -- ------------------------------------------------------------------------------------------------------- -- diff --git a/share/words.xml b/share/words.xml index e35938ca..104721d7 100644 --- a/share/words.xml +++ b/share/words.xml @@ -769,6 +769,7 @@ Failed to promote the DRBD resource: [#!variable!resource!#] primary. Expected a The variable: [#!variable!name!#] is an array reference, but it doesn't have any entries in it. The variable: [#!variable!name!#] was expected to be a positive integer, but: [#!variable!value!#] was received. The domain: [#!variable!name!#] does not appear to be a valid domain name or an ipv4 IP address. Skipping it. + The bridge output wasn't in JSON format. Received: [#!variable!output!#]. Test @@ -1154,6 +1155,13 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp The job_uuid: [#!variable!job_uuid!#] appears valid, but there was no job_data. The state UUID: [#!variable!state_uuid!#] does not appear to be a valid UUID. No (good) state UUIDs found, unable to run this job. + 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. + The URL: [#!variable!url!#] is not supported. The URL must start with 'http://', 'https://' or 'ftp://'. + The requested URL: [#!variable!url!#] was not found on the remote server. + The requested URL: [#!variable!url!#] does not resolve to a known domain. + The requested URL: [#!variable!url!#] failed because the remote host refused the connection. + The requested URL: [#!variable!url!#] failed because there is no route to that host. + The requested URL: [#!variable!url!#] failed because the network is unreachable. Yes diff --git a/tools/anvil-manage-keys b/tools/anvil-manage-keys index 34ef6d44..d29d35a9 100755 --- a/tools/anvil-manage-keys +++ b/tools/anvil-manage-keys @@ -11,8 +11,9 @@ # 2 = Job not 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 -# testing, multiple keys got into a single known_hosts file. +# TODO: Record the keys we remove, then check for the same keys on any other machine we know about. If any +# 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; diff --git a/tools/anvil-update-states b/tools/anvil-update-states index 6c9050e6..0748fd1b 100755 --- a/tools/anvil-update-states +++ b/tools/anvil-update-states @@ -2,10 +2,10 @@ # # This updates things like the current network configuration, shared file data and writes it out to a json file. # -# use strict; use warnings; use Anvil::Tools; +use Data::Dumper; # Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. $| = 1; @@ -62,6 +62,7 @@ sub update_network bridges => {}, }; + # Walk through the sysfs files. local(*DIRECTORY); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0018", variables => { directory => $directory }}); opendir(DIRECTORY, $directory); @@ -111,6 +112,10 @@ sub update_network my $down_delay = ""; 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}) { $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. my $target = readlink($full_path."/master"); $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, 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 => { active_slave => $active_slave, bond_master => $bond_master, bond_mode => $bond_mode, + bridge_id => $bridge_id, + bridge_stp_enabled => $bridge_stp_enabled, down_delay => $down_delay, duplex => $duplex, interface => $interface, @@ -233,28 +267,29 @@ sub update_network } # Find the media, if possible. - my $shell_call = $anvil->data->{path}{exe}{ethtool}." $interface"; - my $ethtool = $anvil->System->call({shell_call => $shell_call}); + my ($ethtool, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{ethtool}." $interface"}); foreach my $line (split/\n/, $ethtool) { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); if ($line =~ /Supported ports: \[ (.*?) \]/i) { $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; } } # Record this interface $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 $anvil->data->{network}{interfaces}{by_name}{$interface} = { active_slave => $active_slave, bond_mode => $bond_mode, bond_master => $bond_master, + bridge_id => $bridge_id, + bridge_stp_enabled => $bridge_stp_enabled, down_delay => $down_delay, duplex => $duplex, 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}::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}::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}::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}, @@ -296,14 +333,25 @@ sub update_network closedir(DIRECTORY); # 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}}) { + # 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 $bond_mode = $anvil->data->{network}{interfaces}{by_name}{$interface}{bond_mode}; 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 $duplex = $anvil->data->{network}{interfaces}{by_name}{$interface}{duplex}; 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 $speed = $anvil->data->{network}{interfaces}{by_name}{$interface}{speed}; 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 $default_gateway = $anvil->data->{network}{'local'}{interface}{$interface}{default_gateway}; my $gateway = $anvil->data->{network}{'local'}{interface}{$interface}{gateway}; @@ -343,13 +390,13 @@ sub update_network primary_slave => $primary_slave, speed => $speed, subnet_mask => $subnet_mask, - type => $type, up_delay => $up_delay, }}); if (($type eq $processing) && ($type eq "bond")) { my $bond_uuid = $anvil->Database->insert_or_update_bonds({ + debug => 3, file => $THIS_FILE, line => __LINE__, bond_name => $interface, @@ -365,10 +412,11 @@ sub update_network bond_up_delay => $up_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->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)) { 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")) { 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})) { $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}, say_bond_uuid => $say_bond_uuid, }}); } my $network_interface_uuid = $anvil->Database->insert_or_update_network_interfaces({ + debug => 3, file => $THIS_FILE, line => __LINE__, network_interface_bond_uuid => $say_bond_uuid, @@ -410,10 +459,10 @@ sub update_network network_interface_mtu => $mtu, network_interface_speed => $speed, }); - $anvil->data->{interface_by_name}{$interface} = $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 => 2, list => { network_interface_uuid => $network_interface_uuid }}); - $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)) { 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. 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. delete $anvil->data->{bonds}{$bond_uuid}; @@ -510,6 +592,8 @@ SELECT bridge_uuid, bridge_name, bridge_id, + bridge_mac, + bridge_mtu, bridge_stp_enabled FROM bridges @@ -527,16 +611,24 @@ AND }}); foreach my $row (@{$results}) { - my $bridge_uuid = $row->[0]; - my $bridge_name = $row->[1]; + my $bridge_uuid = $row->[0]; + 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} = { bridge_name => $bridge_name, - bridge_id => $row->[2], - bridge_stp_enabled => $row->[3], + bridge_id => $bridge_id, + 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 => { "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_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}, }}); @@ -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 .= "]}\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_json => $network_json }}); diff --git a/tools/striker-initialize-host b/tools/striker-initialize-host index e3ceae18..484d7b4d 100755 --- a/tools/striker-initialize-host +++ b/tools/striker-initialize-host @@ -53,8 +53,8 @@ if (not $anvil->data->{sys}{database}{connections}) $anvil->data->{job}{progress} = 0; get_job_details($anvil); wait_for_access($anvil); -set_host_name($anvil); -add_repos($anvil); +#set_host_name($anvil); +#add_repos($anvil); add_databases($anvil); $anvil->nice_exit({code => 0}); @@ -205,12 +205,29 @@ sub add_databases } else { - ### 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"}); - update_progress($anvil, 100, "error_0076"); + ### 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_0084"}); + update_progress($anvil, 100, "error_0084"); $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); }