diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index 18192ded..b7a2bd76 100755 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -8,6 +8,7 @@ use warnings; use DBI; use Scalar::Util qw(weaken isweak); use Data::Dumper; +use Time::HiRes qw(gettimeofday tv_interval); our $VERSION = "3.0.0"; my $THIS_FILE = "Database.pm"; @@ -637,6 +638,9 @@ sub connect test_table => $test_table, }}); + my $start_time = [gettimeofday]; + print "Start time: [".$start_time->[0].".".$start_time->[1]."]\n"; + $anvil->data->{sys}{db_timestamp} = "" if not defined $anvil->data->{sys}{db_timestamp}; # We need the host_uuid before we connect. @@ -715,10 +719,15 @@ sub connect db_connect_string => $db_connect_string, "database::${id}::ping_before_connect" => $anvil->data->{database}{$id}{ping_before_connect}, }}); - if ($anvil->data->{database}{$id}{ping_before_connect}) + #if ($anvil->data->{database}{$id}{ping_before_connect}) + if (0) { # Can I ping? my ($pinged) = $anvil->System->ping({ping => $host, count => 1}); + + my $ping_time = tv_interval ($start_time, [gettimeofday]); + print "[".$ping_time."] - Pinged: [$host:$port:$name:$user]\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { pinged => $pinged }}); if (not $pinged) { @@ -945,6 +954,9 @@ sub connect } } + my $total = tv_interval ($start_time, [gettimeofday]); + print "Total runtime: [".$total."]\n"; + # Do I have any connections? Don't die, if not, just return. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { connections => $connections }}); if (not $connections) diff --git a/Anvil/Tools/Get.pm b/Anvil/Tools/Get.pm index 40d8bfcd..a9c50a77 100755 --- a/Anvil/Tools/Get.pm +++ b/Anvil/Tools/Get.pm @@ -115,7 +115,7 @@ sub anvil_version my $debug = $parameter->{debug} ? $parameter->{debug} : 2; my $password = $parameter->{password} ? $parameter->{password} : ""; my $port = $parameter->{port} ? $parameter->{port} : ""; - my $target = $parameter->{target} ? $parameter->{target} : ""; + my $target = $parameter->{target} ? $parameter->{target} : "local"; my $version = 0; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { password => $anvil->Log->secure ? $password : "--", @@ -128,9 +128,9 @@ sub anvil_version { # Remote call. my $shell_call = " -if [ -e ".$anvil->data->{path}{exe}{'anvil.version'}." ]; +if [ -e ".$anvil->data->{path}{configs}{'anvil.version'}." ]; then - cat ".$anvil->data->{path}{exe}{'anvil.version'}."; + cat ".$anvil->data->{path}{configs}{'anvil.version'}."; else echo 0; fi; @@ -147,7 +147,7 @@ fi; else { # Local. - $version = $anvil->Storage->read_file({file => $anvil->data->{path}{exe}{'anvil.version'}}); + $version = $anvil->Storage->read_file({file => $anvil->data->{path}{configs}{'anvil.version'}}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { version => $version }}); # Did we actually read a version? diff --git a/Anvil/Tools/System.pm b/Anvil/Tools/System.pm index b26bd8fa..d9558c69 100755 --- a/Anvil/Tools/System.pm +++ b/Anvil/Tools/System.pm @@ -8,6 +8,7 @@ use warnings; use Data::Dumper; use Net::SSH2; use Scalar::Util qw(weaken isweak); +use Time::HiRes qw(gettimeofday tv_interval); our $VERSION = "3.0.0"; my $THIS_FILE = "System.pm"; @@ -846,6 +847,12 @@ sub ping my $parameter = shift; my $anvil = $self->parent; +# my $start_time = [gettimeofday]; +# print "Start time: [".$start_time->[0].".".$start_time->[1]."]\n"; +# +# my $ping_time = tv_interval ($start_time, [gettimeofday]); +# print "[".$ping_time."] - Pinged: [$host]\n"; + # If we were passed a target, try pinging from it instead of locally my $count = $parameter->{count} ? $parameter->{count} : 1; # How many times to try to ping it? Will exit as soon as one succeeds my $debug = $parameter->{debug} ? $parameter->{deug} : 3; @@ -874,7 +881,7 @@ sub ping # Build the call. Note that we use 'timeout' because if there is no connection and the hostname is # used to ping and DNS is not available, it could take upwards of 30 seconds time timeout otherwise. - my $shell_call = $anvil->data->{path}{exe}{timeout}." 2 ".$anvil->data->{path}{exe}{'ping'}." -W 1 -n $ping -c 1"; + my $shell_call = $anvil->data->{path}{exe}{timeout}." 1 ".$anvil->data->{path}{exe}{'ping'}." -W 1 -n $ping -c 1"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }}); if (not $fragment) { @@ -1176,7 +1183,17 @@ sub remote_call } # Make sure the port is valid. - if (($port !~ /^\d+$/) or ($port < 0) or ($port > 65536)) + if ($port eq "") + { + $port = 22; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $log_level, list => { port => $port }}); + } + elsif ($port !~ /^\d+$/) + { + $port = getservbyname($port, 'tcp'); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $log_level, list => { port => $port }}); + } + if ((not defined $port) or (($port !~ /^\d+$/) or ($port < 0) or ($port > 65536))) { $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0058", variables => { port => $port }}); return("!!error!!"); @@ -1212,11 +1229,20 @@ sub remote_call # If I don't already have an active SSH file handle, connect now. $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $log_level, list => { ssh_fh => $ssh_fh }}); + if ($ssh_fh !~ /^Net::SSH2/) { - $ssh_fh = Net::SSH2->new(); - if (not $ssh_fh->connect($target, $port, Timeout => 10)) + ### NOTE: Nevermind, timeout isn't supported... >_< Find a newer version if IO::Socket::IP? + ### TODO: Make the timeout user-configurable to handle slow connections. Make it + ### 'sys::timeout::{all|host} = x' + my $start_time = [gettimeofday]; + $ssh_fh = Net::SSH2->new(timeout => 1000); + if (not $ssh_fh->connect($target, $port)) { + + my $connect_time = tv_interval ($start_time, [gettimeofday]); + print "[".$connect_time."] - Connection failed time to: [$target:$port]\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", list => { user => $user, target => $target, @@ -1249,10 +1275,13 @@ sub remote_call { $message_key = "message_0004"; } - $error = $anvil->Words->string({key => $message_key, variables => { $variables }}); - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => $message_key, variables => { $variables }}); + $error = $anvil->Words->string({key => $message_key, variables => $variables}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => $message_key, variables => $variables}); } + my $connect_time = tv_interval ($start_time, [gettimeofday]); + print "[".$connect_time."] - Connect time to: [$target:$port]\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $log_level, list => { error => $error, ssh_fh => $ssh_fh }}); if (not $error) { diff --git a/notes b/notes index 309408c6..69d306a2 100644 --- a/notes +++ b/notes @@ -1,5 +1,12 @@ All systems have a UUID, even VMs. Use that for system UUID in the future. +virt-manager stores information in dconf-editor -> /org/virt-manager/virt-manager/connections ($HOME/.config/dconf/user) + +==== dconf read /org/virt-manager/virt-manager/connections/uris +['qemu+ssh://root@localhost/system', 'qemu+ssh://root@wp-a01n02.remote/system', 'qemu+ssh://root@an-nas02.kw01.alteeve.ca/system', 'qemu+ssh://root@hb-a01n01.remote/system', 'qemu+ssh://root@hb-a01n02.remote/system', 'qemu:///system'] +==== dconf read /org/virt-manager/virt-manager/connections/autoconnect +['qemu+ssh://root@localhost/system'] +==== diff --git a/tools/anvil-scan-network b/tools/anvil-scan-network new file mode 100755 index 00000000..412e39a9 --- /dev/null +++ b/tools/anvil-scan-network @@ -0,0 +1,111 @@ +#!/usr/bin/perl +# +# This daemon watches for network changes and updates a cache file when changes are found. +# +# NOTE: This daemon does NOT connect to the databases. This is meant to be as quick as possible and to use as +# few resources as possible. It will exit with 'ok' or 'change' depending on if something in the +# network changed. +# +# Exit codes; +# 0 = Normal exit +# +# TODO: +# + +use strict; +use warnings; +use Time::HiRes qw(gettimeofday tv_interval); +my $start_time = [gettimeofday]; +use Anvil::Tools; + +my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; +my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; +if (($running_directory =~ /^\./) && ($ENV{PWD})) +{ + $running_directory =~ s/^\./$ENV{PWD}/; +} + +# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. +$| = 1; + +my $anvil = Anvil::Tools->new(); +$anvil->Log->level({set => 2}); + +scan($anvil); + +my $total = tv_interval ($start_time, [gettimeofday]); +print "Total runtime: [".$total."]\n"; +$anvil->nice_exit({exit_code => 0}); + + +############################################################################################################# +# Functions # +############################################################################################################# + +sub scan +{ + my ($anvil) = @_; + + my $directory = $anvil->data->{path}{sysfs}{network_interfaces}; + print $THIS_FILE." ".__LINE__."; directory: [".$directory."]\n"; + local(*DIRECTORY); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0018", variables => { directory => $directory }}); + opendir(DIRECTORY, $directory); + while(my $file = readdir(DIRECTORY)) + { + next if $file eq "."; + next if $file eq ".."; + next if $file eq "lo"; + my $full_path = "$directory/$file"; + print $THIS_FILE." ".__LINE__."; full_path: [".$full_path."]\n"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { full_path => $full_path }}); + if (-d $full_path) + { + # Pull out the data I want. Note that some of these don't exist with virtio-net interfaces. + my $interface = $file; + my $mac_address = -e $full_path."/address" ? $anvil->Storage->read_file({file => $full_path."/address"}) : ""; + my $link_state = -e $full_path."/carrier" ? $anvil->Storage->read_file({file => $full_path."/carrier"}) : 0; + my $mtu = -e $full_path."/mtu" ? $anvil->Storage->read_file({file => $full_path."/mtu"}) : 0; + my $duplex = -e $full_path."/duplex" ? $anvil->Storage->read_file({file => $full_path."/duplex"}) : "unknown"; # full or half? + my $operational = -e $full_path."/operstate" ? $anvil->Storage->read_file({file => $full_path."/operstate"}) : "unknown"; # up or down + my $speed = $link_state ? $anvil->Storage->read_file({file => $full_path."/speed"}) : 0; # Mbps (ie: 1000 = Gbps), gives a very high number for unplugged link + if ($speed > 100000) + { + # NOTE: This is probably 0 now... Though someday >100 Gbps will be reasonable + # and we'll need to change this. + $speed = 0; + } + + # Find the media, if possible. + my $media = "unknown"; + my $shell_call = $anvil->data->{path}{exe}{ethtool}." $interface"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { shell_call => $shell_call }}); + my $ethtool = $anvil->System->call({shell_call => $shell_call}); + 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 }}); + last; + } + } + + # Log + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + interface => $interface, + mac_address => $mac_address, + link_state => $link_state, + mtu => $mtu, + duplex => $duplex, + operational => $operational, + speed => $speed, + media => $media, + }}); + } + } + closedir(DIRECTORY); + + return(0); +} diff --git a/tools/anvil-update-states b/tools/anvil-update-states index 9414ed96..4a572f67 100755 --- a/tools/anvil-update-states +++ b/tools/anvil-update-states @@ -18,7 +18,6 @@ if (($running_directory =~ /^\./) && ($ENV{PWD})) } my $anvil = Anvil::Tools->new(); -print $THIS_FILE." ".__LINE__."; anvil: [".$anvil."]\n"; $anvil->Log->level({set => 2}); $anvil->Storage->read_config({file => "/etc/anvil/anvil.conf"}); @@ -26,6 +25,7 @@ my $connections = $anvil->Database->connect({ sql_file => $anvil->data->{sys}{database}{schema}, test_table => "network_interfaces", }); + print $THIS_FILE." ".__LINE__."; connections: [".$connections."]\n"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0132", variables => { connections => $connections }}); if (not $connections) @@ -37,7 +37,7 @@ if (not $connections) report_network($anvil); -exit(0); +$anvil->nice_exit({exit_code => 0}); ############################################################################################################# # Functions # @@ -50,7 +50,7 @@ sub report_network # Write out the data in json format. my $directory = $anvil->data->{path}{sysfs}{network_interfaces}; - print $THIS_FILE." ".__LINE__."; directory: [".$directory."]\n"; + #print $THIS_FILE." ".__LINE__."; directory: [".$directory."]\n"; local(*DIRECTORY); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0018", variables => { directory => $directory }}); opendir(DIRECTORY, $directory); @@ -60,7 +60,7 @@ sub report_network next if $file eq ".."; next if $file eq "lo"; my $full_path = "$directory/$file"; - print $THIS_FILE." ".__LINE__."; full_path: [".$full_path."]\n"; + #print $THIS_FILE." ".__LINE__."; full_path: [".$full_path."]\n"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { full_path => $full_path }}); if (-d $full_path) {