* Created Tools->refresh to reload anvil.conf in one call. * Created Anvil::Tools::Network to hold network-related tasks. ** Created Network->is_remote() that tests to see if a string (containing a target) refers to the remote machine (versus a local machine). Updated all previous checks to use this new method. ** Moved Get->network_details() and Get->network() to the new Network module. Renamed Get->network() to Network->get_network(). ** Made Network->get_ips() work locally and remotely. ** Created Network->find_matches() that compares two scanned machines IPs (via two previous calls to Network->get_ips()) * Created Database->manage_anvil_conf() that will add, update or remove a given database connection in a local or remote anvil.conf file. * Fixed bugs in Storage->backup() where the bash calls were quite broken. I'm not sure how it ever worked before... x_x * Updated anvil-daemon to not initialize a database unless it's running on dashboard. Also added a check at the startup of anvil-daemon where it will go into a loop waiting for a database to become available, re-reading anvil.conf each loop. Signed-off-by: Digimer <digimer@alteeve.ca>main
parent
a54e0d4e22
commit
b9a0cc4d56
19 changed files with 1456 additions and 559 deletions
@ -0,0 +1,676 @@ |
|||||||
|
package Anvil::Tools::Network; |
||||||
|
# |
||||||
|
# This module contains methods used to deal with networking stuff. |
||||||
|
# |
||||||
|
|
||||||
|
use strict; |
||||||
|
use warnings; |
||||||
|
use Data::Dumper; |
||||||
|
use Scalar::Util qw(weaken isweak); |
||||||
|
|
||||||
|
our $VERSION = "3.0.0"; |
||||||
|
my $THIS_FILE = "Network.pm"; |
||||||
|
|
||||||
|
### Methods; |
||||||
|
# find_matches |
||||||
|
# get_ips |
||||||
|
# get_network |
||||||
|
# is_local |
||||||
|
|
||||||
|
=pod |
||||||
|
|
||||||
|
=encoding utf8 |
||||||
|
|
||||||
|
=head1 NAME |
||||||
|
|
||||||
|
Anvil::Tools::Network |
||||||
|
|
||||||
|
Provides all methods related to networking. |
||||||
|
|
||||||
|
=head1 SYNOPSIS |
||||||
|
|
||||||
|
use Anvil::Tools; |
||||||
|
|
||||||
|
# Get a common object handle on all Anvil::Tools modules. |
||||||
|
my $anvil = Anvil::Tools->new(); |
||||||
|
|
||||||
|
# Access to methods using '$anvil->Storage->X'. |
||||||
|
# |
||||||
|
|
||||||
|
=head1 METHODS |
||||||
|
|
||||||
|
Methods in this module; |
||||||
|
|
||||||
|
=cut |
||||||
|
sub new |
||||||
|
{ |
||||||
|
my $class = shift; |
||||||
|
my $self = { |
||||||
|
}; |
||||||
|
|
||||||
|
bless $self, $class; |
||||||
|
|
||||||
|
return ($self); |
||||||
|
} |
||||||
|
|
||||||
|
# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more |
||||||
|
# sense in this case to think of it as a parent. |
||||||
|
sub parent |
||||||
|
{ |
||||||
|
my $self = shift; |
||||||
|
my $parent = shift; |
||||||
|
|
||||||
|
$self->{HANDLE}{TOOLS} = $parent if $parent; |
||||||
|
|
||||||
|
# Defend against memory leads. See Scalar::Util'. |
||||||
|
if (not isweak($self->{HANDLE}{TOOLS})) |
||||||
|
{ |
||||||
|
weaken($self->{HANDLE}{TOOLS}); |
||||||
|
} |
||||||
|
|
||||||
|
return ($self->{HANDLE}{TOOLS}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
############################################################################################################# |
||||||
|
# Public methods # |
||||||
|
############################################################################################################# |
||||||
|
|
||||||
|
=head2 find_matches |
||||||
|
|
||||||
|
This takes two hash keys from prior C<< Network->get_ips() >> runs and finds which are on the same network. |
||||||
|
|
||||||
|
Paramters; |
||||||
|
|
||||||
|
=head3 first (required) |
||||||
|
|
||||||
|
This is the hash key of the first machine being compared. |
||||||
|
|
||||||
|
=head3 second (required) |
||||||
|
|
||||||
|
This is the hash key of the second machine being compared. |
||||||
|
|
||||||
|
=cut |
||||||
|
sub find_matches |
||||||
|
{ |
||||||
|
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 $first = defined $parameter->{first} ? $parameter->{first} : ""; |
||||||
|
my $second = defined $parameter->{second} ? $parameter->{second} : ""; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
first => $first, |
||||||
|
second => $second, |
||||||
|
}}); |
||||||
|
|
||||||
|
if (ref($anvil->data->{network}{$first}) ne "HASH") |
||||||
|
{ |
||||||
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_matches()", parameter => "first" }}); |
||||||
|
return(""); |
||||||
|
} |
||||||
|
if (ref($anvil->data->{network}{$second}) ne "HASH") |
||||||
|
{ |
||||||
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_matches()", parameter => "second" }}); |
||||||
|
return(""); |
||||||
|
} |
||||||
|
|
||||||
|
# Loop through the first, and on each interface with an IP/subnet, look for a match in the second. |
||||||
|
my $match = {}; |
||||||
|
foreach my $first_interface (sort {$b cmp $a} keys %{$anvil->data->{network}{$first}{interface}}) |
||||||
|
{ |
||||||
|
my $first_ip = $anvil->data->{network}{$first}{interface}{$first_interface}{ip}; |
||||||
|
my $first_subnet = $anvil->data->{network}{$first}{interface}{$first_interface}{subnet}; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
first => $first, |
||||||
|
first_interface => $first_interface, |
||||||
|
first_ip => $first_ip, |
||||||
|
first_subnet => $first_subnet, |
||||||
|
}}); |
||||||
|
|
||||||
|
if (($first_ip) && ($first_subnet)) |
||||||
|
{ |
||||||
|
# Look for a match. |
||||||
|
my $first_network = $anvil->Network->get_network({ |
||||||
|
debug => $debug, |
||||||
|
ip => $first_ip, |
||||||
|
subnet => $first_subnet, |
||||||
|
}); |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { a_network => $first_network }}); |
||||||
|
|
||||||
|
foreach my $second_interface (sort {$b cmp $a} keys %{$anvil->data->{network}{$second}{interface}}) |
||||||
|
{ |
||||||
|
my $second_ip = $anvil->data->{network}{$second}{interface}{$second_interface}{ip}; |
||||||
|
my $second_subnet = $anvil->data->{network}{$second}{interface}{$second_interface}{subnet}; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
second => $second, |
||||||
|
second_interface => $second_interface, |
||||||
|
second_ip => $second_ip, |
||||||
|
second_subnet => $second_subnet, |
||||||
|
}}); |
||||||
|
if (($second_ip) && ($second_subnet)) |
||||||
|
{ |
||||||
|
# Do we have a match? |
||||||
|
my $second_network = $anvil->Network->get_network({ |
||||||
|
debug => $debug, |
||||||
|
ip => $second_ip, |
||||||
|
subnet => $second_subnet, |
||||||
|
}); |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
a_network => $first_network, |
||||||
|
b_network => $second_network, |
||||||
|
}}); |
||||||
|
|
||||||
|
if ($first_network eq $second_network) |
||||||
|
{ |
||||||
|
# Match! |
||||||
|
$match->{$first}{$first_interface} = $second_network; |
||||||
|
$match->{$second}{$second_interface} = $second_network; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"${first}::${first_interface}" => $match->{$first}{$first_interface}, |
||||||
|
"${second}::${second_interface}" => $match->{$second}{$second_interface}, |
||||||
|
}}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return($match); |
||||||
|
} |
||||||
|
|
||||||
|
=head2 get_ips |
||||||
|
|
||||||
|
This method checks the local system for interfaces and stores them in: |
||||||
|
|
||||||
|
* C<< network::<target>::interface::<iface_name>::ip >> - If an IP address is set |
||||||
|
* C<< network::<target>::interface::<iface_name>::subnet >> - If an IP is set |
||||||
|
* C<< network::<target>::interface::<iface_name>::mac >> - Always set. |
||||||
|
* C<< network::<target>::interface::<iface_name>::default_gateway >> = C<< 0 >> if not the default gateway, C<< 1 >> if so. |
||||||
|
* C<< network::<target>::interface::<iface_name>::gateway >> = If the default gateway, this is the gateway IP address. |
||||||
|
* C<< network::<target>::interface::<iface_name>::dns >> = If the default gateway, this is the comma-separated list of active DNS servers. |
||||||
|
|
||||||
|
When called without a C<< target >>, C<< local >> is used. |
||||||
|
|
||||||
|
To aid in look-up by MAC address, C<< network::mac::<mac_address>::iface >> is also set. Note that this is not target-dependent. |
||||||
|
|
||||||
|
Parameters; |
||||||
|
|
||||||
|
=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) |
||||||
|
|
||||||
|
If set, the file will be read from the target machine. This must be either an IP address or a resolvable host name. |
||||||
|
|
||||||
|
The file will be copied to the local system using C<< $anvil->Storage->rsync() >> and stored in C<< /tmp/<file_path_and_name>.<target> >>. if C<< cache >> is set, the file will be preserved locally. Otherwise it will be deleted once it has been read into memory. |
||||||
|
|
||||||
|
B<< Note >>: the temporary file will be prefixed with the path to the file name, with the C<< / >> converted to C<< _ >>. |
||||||
|
|
||||||
|
=cut |
||||||
|
sub get_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->get_ips()" }}); |
||||||
|
|
||||||
|
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, |
||||||
|
}}); |
||||||
|
|
||||||
|
# Reading locally or remote? |
||||||
|
my $in_iface = ""; |
||||||
|
my $shell_call = $anvil->data->{path}{exe}{ip}." addr 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, |
||||||
|
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, |
||||||
|
}}); |
||||||
|
} |
||||||
|
foreach my $line (split/\n/, $output) |
||||||
|
{ |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); |
||||||
|
if ($line =~ /^\d+: (.*?): /) |
||||||
|
{ |
||||||
|
$in_iface = $1; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_iface => $in_iface }}); |
||||||
|
|
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{ip} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{ip}; |
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{subnet} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{subnet}; |
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{mac} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{mac}; |
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{default_gateway} = 0 if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{default_gateway}; |
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{gateway} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{gateway}; |
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{dns} = "" if not defined $anvil->data->{network}{$target}{interface}{$in_iface}{dns}; |
||||||
|
} |
||||||
|
next if not $in_iface; |
||||||
|
if ($in_iface eq "lo") |
||||||
|
{ |
||||||
|
# We don't care about 'lo'. |
||||||
|
delete $anvil->data->{network}{$target}{interface}{$in_iface}; |
||||||
|
next; |
||||||
|
} |
||||||
|
if ($line =~ /inet (.*?)\/(.*?) /) |
||||||
|
{ |
||||||
|
my $ip = $1; |
||||||
|
my $cidr = $2; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ip => $ip, cidr => $cidr }}); |
||||||
|
|
||||||
|
my $subnet = $cidr; |
||||||
|
if (($cidr =~ /^\d{1,2}$/) && ($cidr >= 0) && ($cidr <= 32)) |
||||||
|
{ |
||||||
|
# Convert to subnet |
||||||
|
$subnet = $anvil->Convert->cidr({cidr => $cidr}); |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { subnet => $subnet }}); |
||||||
|
} |
||||||
|
|
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{ip} = $ip; |
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{subnet} = $subnet; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"s1:network::${target}::interface::${in_iface}::ip" => $anvil->data->{network}{$target}{interface}{$in_iface}{ip}, |
||||||
|
"s2:network::${target}::interface::${in_iface}::subnet" => $anvil->data->{network}{$target}{interface}{$in_iface}{subnet}, |
||||||
|
}}); |
||||||
|
} |
||||||
|
if ($line =~ /ether ([0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}) /i) |
||||||
|
{ |
||||||
|
my $mac = $1; |
||||||
|
$anvil->data->{network}{$target}{interface}{$in_iface}{mac} = $mac; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"network::${target}::interface::${in_iface}::mac" => $anvil->data->{network}{$target}{interface}{$in_iface}{mac}, |
||||||
|
}}); |
||||||
|
|
||||||
|
# We only record the mac in 'network::mac' if this isn't a bond. |
||||||
|
my $test_file = "/proc/net/bonding/".$in_iface; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_file => $test_file }}); |
||||||
|
if (not -e $test_file) |
||||||
|
{ |
||||||
|
$anvil->data->{network}{mac}{$mac}{iface} = $in_iface; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"network::mac::${mac}::iface" => $anvil->data->{network}{mac}{$mac}{iface}, |
||||||
|
}}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# Read the config files for the interfaces we've found. Use 'ls' to find the interface files. Then |
||||||
|
# we'll read them all in. |
||||||
|
$shell_call = $anvil->data->{path}{exe}{ls}." ".$anvil->data->{path}{directories}{ifcfg}; |
||||||
|
$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, |
||||||
|
}}); |
||||||
|
} |
||||||
|
foreach my $line (split/\n/, $output) |
||||||
|
{ |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); |
||||||
|
next if $line !~ /^ifcfg-/; |
||||||
|
my $full_path = $anvil->data->{path}{directories}{ifcfg}."/".$line; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { full_path => $full_path }}); |
||||||
|
|
||||||
|
my $file_body = $anvil->Storage->read_file({ |
||||||
|
debug => $debug, |
||||||
|
file => $full_path, |
||||||
|
target => $target, |
||||||
|
password => $password, |
||||||
|
port => $port, |
||||||
|
remote_user => $remote_user, |
||||||
|
}); |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"s1:full_path" => $full_path, |
||||||
|
"s2:file_body" => $file_body, |
||||||
|
}}); |
||||||
|
|
||||||
|
# Break it apart and store any variables. |
||||||
|
my $temp = {}; |
||||||
|
my $interface = ""; |
||||||
|
foreach my $line (split/\n/, $file_body) |
||||||
|
{ |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); |
||||||
|
next if $line =~ /^#/; |
||||||
|
if ($line =~ /(.*?)=(.*)/) |
||||||
|
{ |
||||||
|
my $variable = $1; |
||||||
|
my $value = $2; |
||||||
|
$value =~ s/^"(.*)"$/$1/; |
||||||
|
$temp->{$variable} = $value; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "temp->{$variable}" => $temp->{$variable} }}); |
||||||
|
|
||||||
|
if (uc($variable) eq "DEVICE") |
||||||
|
{ |
||||||
|
$interface = $value; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "interface" => $interface }}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if ($interface) |
||||||
|
{ |
||||||
|
$anvil->data->{network}{$target}{interface}{$interface}{file} = $full_path; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"network::${target}::interface::${interface}::file" => $anvil->data->{network}{$target}{interface}{$interface}{file}, |
||||||
|
}}); |
||||||
|
foreach my $variable (sort {$a cmp $b} keys %{$temp}) |
||||||
|
{ |
||||||
|
$anvil->data->{network}{$target}{interface}{$interface}{variable}{$variable} = $temp->{$variable}; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"network::${target}::interface::${interface}::file::variable::${variable}" => $anvil->data->{network}{$target}{interface}{$interface}{variable}{$variable}, |
||||||
|
}}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
# Get the routing info. |
||||||
|
my $lowest_metric = 99999999; |
||||||
|
my $route_interface = ""; |
||||||
|
my $route_ip = ""; |
||||||
|
$shell_call = $anvil->data->{path}{exe}{ip}." route show"; |
||||||
|
$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, |
||||||
|
}}); |
||||||
|
} |
||||||
|
foreach my $line (split/\n/, $output) |
||||||
|
{ |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); |
||||||
|
if ($line =~ /default via (.*?) dev (.*?) proto .*? metric (\d+)/i) |
||||||
|
{ |
||||||
|
my $this_ip = $1; |
||||||
|
my $this_interface = $2; |
||||||
|
my $metric = $3; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
's1:this_ip' => $this_ip, |
||||||
|
's2:this_interface' => $this_interface, |
||||||
|
's3:metric' => $metric, |
||||||
|
's4:lowest_metric' => $lowest_metric, |
||||||
|
}}); |
||||||
|
|
||||||
|
if ($metric < $lowest_metric) |
||||||
|
{ |
||||||
|
$lowest_metric = $metric; |
||||||
|
$route_interface = $this_interface; |
||||||
|
$route_ip = $this_ip; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
lowest_metric => $lowest_metric, |
||||||
|
route_interface => $route_interface, |
||||||
|
route_ip => $route_ip, |
||||||
|
}}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
route_interface => $route_interface, |
||||||
|
route_ip => $route_ip, |
||||||
|
}}); |
||||||
|
|
||||||
|
# If I got a route, get the DNS. |
||||||
|
if ($route_interface) |
||||||
|
{ |
||||||
|
# I want to build the DNS list from only the interface that is used for routing. |
||||||
|
my $in_interface = ""; |
||||||
|
my $dns_list = ""; |
||||||
|
my $dns_hash = {}; |
||||||
|
my $shell_call = $anvil->data->{path}{exe}{nmcli}." dev 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, |
||||||
|
}}); |
||||||
|
} |
||||||
|
foreach my $line (split/\n/, $output) |
||||||
|
{ |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }}); |
||||||
|
if ($line =~ /GENERAL.DEVICE:\s+(.*)$/) |
||||||
|
{ |
||||||
|
$in_interface = $1; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_interface => $in_interface }}); |
||||||
|
} |
||||||
|
if (not $line) |
||||||
|
{ |
||||||
|
$in_interface = ""; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { in_interface => $in_interface }}); |
||||||
|
} |
||||||
|
|
||||||
|
next if $in_interface ne $route_interface; |
||||||
|
|
||||||
|
if ($line =~ /IP4.DNS\[(\d+)\]:\s+(.*)/i) |
||||||
|
{ |
||||||
|
my $order = $1; |
||||||
|
my $ip = $2; |
||||||
|
|
||||||
|
$dns_hash->{$order} = $ip; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "dns_hash->{$order}" => $dns_hash->{$order} }}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
foreach my $order (sort {$a cmp $b} keys %{$dns_hash}) |
||||||
|
{ |
||||||
|
$dns_list .= $dns_hash->{$order}.", "; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"s1:dns_hash->{$order}" => $dns_hash->{$order}, |
||||||
|
"s2:dns_list" => $dns_list, |
||||||
|
}}); |
||||||
|
} |
||||||
|
$dns_list =~ s/, $//; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { dns_list => $dns_list }}); |
||||||
|
|
||||||
|
$anvil->data->{network}{$target}{interface}{$route_interface}{default_gateway} = 1; |
||||||
|
$anvil->data->{network}{$target}{interface}{$route_interface}{gateway} = $route_ip; |
||||||
|
$anvil->data->{network}{$target}{interface}{$route_interface}{dns} = $dns_list; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
"network::${target}::interface::${route_interface}::default_gateway" => $anvil->data->{network}{$target}{interface}{$route_interface}{default_gateway}, |
||||||
|
"network::${target}::interface::${route_interface}::gateway" => $anvil->data->{network}{$target}{interface}{$route_interface}{gateway}, |
||||||
|
"network::${target}::interface::${route_interface}::dns" => $anvil->data->{network}{$target}{interface}{$route_interface}{dns}, |
||||||
|
}}); |
||||||
|
} |
||||||
|
|
||||||
|
return(0); |
||||||
|
} |
||||||
|
|
||||||
|
=head2 get_network |
||||||
|
|
||||||
|
This takes an IP address and subnet and returns the network it belongs too. For example; |
||||||
|
|
||||||
|
my $network = $anvil->Network->get_network({ip => "10.2.4.1", subnet => "255.255.0.0"}); |
||||||
|
|
||||||
|
This would set C<< $network >> to C<< 10.2.0.0 >>. |
||||||
|
|
||||||
|
If the network can't be caluclated for any reason, and empty string will be returned. |
||||||
|
|
||||||
|
Parameters; |
||||||
|
|
||||||
|
=head3 ip (required) |
||||||
|
|
||||||
|
This is the IPv4 IP address being calculated. |
||||||
|
|
||||||
|
=head3 subnet (required) |
||||||
|
|
||||||
|
This is the subnet of the IP address being calculated. |
||||||
|
|
||||||
|
=cut |
||||||
|
sub get_network |
||||||
|
{ |
||||||
|
my $self = shift; |
||||||
|
my $parameter = shift; |
||||||
|
my $anvil = $self->parent; |
||||||
|
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3; |
||||||
|
|
||||||
|
my $network = ""; |
||||||
|
my $ip = defined $parameter->{ip} ? $parameter->{ip} : ""; |
||||||
|
my $subnet = defined $parameter->{subnet} ? $parameter->{subnet} : ""; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { |
||||||
|
ip => $ip, |
||||||
|
subnet => $subnet, |
||||||
|
}}); |
||||||
|
|
||||||
|
if (not $ip) |
||||||
|
{ |
||||||
|
$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 $subnet) |
||||||
|
{ |
||||||
|
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->get_network()", parameter => "subnet" }}); |
||||||
|
return(""); |
||||||
|
} |
||||||
|
|
||||||
|
my $block = Net::Netmask->new($ip."/".$subnet); |
||||||
|
my $base = $block->base(); |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { base => $base }}); |
||||||
|
|
||||||
|
if ($anvil->Validate->is_ipv4({ip => $base})) |
||||||
|
{ |
||||||
|
$network = $base; |
||||||
|
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network => $network }}); |
||||||
|
} |
||||||
|
|
||||||
|
return($network); |
||||||
|
} |
||||||
|
|
||||||
|
=head2 is_remote |
||||||
|
|
||||||
|
This looks at the C<< target >> and determines if it relates to the local system or not. If the C<< target >> is remote, C<< 1 >> is returned. Otherwise, C<< 0 >> is returned. |
||||||
|
|
||||||
|
if ($anvil->Network->is_remote($target)) |
||||||
|
{ |
||||||
|
# Do something remotely |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
# Do something locally |
||||||
|
} |
||||||
|
|
||||||
|
B<< NOTE >>: Unlike most methods, this one does not take a hash reference for the parameters. It takes the string directly. |
||||||
|
|
||||||
|
=cut |
||||||
|
sub is_remote |
||||||
|
{ |
||||||
|
my $self = shift; |
||||||
|
my $target = shift; |
||||||
|
my $anvil = $self->parent; |
||||||
|
|
||||||
|
my $remote = 0; |
||||||
|
if (($target) && ($target ne "local") && ($target ne $anvil->_hostname) && ($target ne $anvil->_short_hostname)) |
||||||
|
{ |
||||||
|
# It's a remote system |
||||||
|
$remote = 1; |
||||||
|
} |
||||||
|
|
||||||
|
return($remote); |
||||||
|
} |
||||||
|
|
||||||
|
# =head3 |
||||||
|
# |
||||||
|
# Private Functions; |
||||||
|
# |
||||||
|
# =cut |
||||||
|
|
||||||
|
############################################################################################################# |
||||||
|
# Private functions # |
||||||
|
############################################################################################################# |
||||||
|
|
||||||
|
1; |
Loading…
Reference in new issue