From e40d0e2444e6c6db2e3e1c9b3d22445c7a924a0c Mon Sep 17 00:00:00 2001 From: Digimer Date: Thu, 26 Aug 2021 23:26:03 -0400 Subject: [PATCH 1/3] Fixed a bug where if a database is pingable but the pgsql database is down, and it's the first database tested (or local), then the DB handle used to read / quote fails. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 128 ++++++++++++++++++----------------- Anvil/Tools/Server.pm | 2 - tools/anvil-provision-server | 2 +- 3 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index a6177d09..ae227823 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -1347,67 +1347,6 @@ sub connect } } - # Before we try to connect, see if this is a local database and, if so, make sure it's setup. - my $is_local = $anvil->Network->is_local({debug => $debug, host => $host}); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); - if ($is_local) - { - $anvil->data->{sys}{database}{read_uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }}); - - # If requested, and if running with root access, set it up (or update it) if needed. - # This method just returns if nothing is needed. - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - check_if_configured => $check_if_configured, - real_uid => $<, - effective_uid => $>, - }}); - if (($check_if_configured) && ($< == 0) && ($> == 0)) - { - $anvil->Database->configure_pgsql({debug => $debug, uuid => $uuid}); - } - } - elsif (not $anvil->data->{sys}{database}{read_uuid}) - { - $anvil->data->{sys}{database}{read_uuid} = $uuid; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }}); - } - - # If this isn't a local database, read the target's Anvil! version (if available) and make - # sure it matches ours. If it doesn't, skip this database. - if (not $is_local) - { - my ($local_anvil_version, $local_schema_version) = $anvil->_anvil_version({debug => $debug}); - my ($remote_anvil_version, $remote_schema_version) = $anvil->Get->anvil_version({ - debug => $debug, - target => $host, - password => $password, - }); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { - 's1:host' => $host, - 's2:local_anvil_version' => $local_anvil_version, - 's3:remote_anvil_version' => $remote_anvil_version, - 's4:local_schema_version' => $local_schema_version, - 's5:remote_schema_version' => $remote_schema_version, - }}); - # TODO: Periodically, we fail to get the remote version. For now, we proceed if - # everything else is OK. Might be better to pause a re-try... To be determined. - if (($remote_schema_version) && ($remote_schema_version ne $local_schema_version)) - { - # Version doesn't match, - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0145", variables => { - host => $host, - local_version => $local_schema_version, - target_version => $remote_schema_version, - }}); - - # Delete the information about this database. We'll try again on nexy - # ->connect(). - delete $anvil->data->{database}{$uuid}; - next; - } - } - # Connect! my $dbh = ""; ### NOTE: The Database->write() method, when passed an array, will automatically disable @@ -1484,11 +1423,12 @@ sub connect }; } $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => $message_key, variables => $variables }); + + next; } elsif ($dbh =~ /^DBI::db=HASH/) { # Woot! - $anvil->data->{sys}{database}{connections}++; push @{$successful_connections}, $uuid; $anvil->data->{cache}{database_handle}{$uuid} = $dbh; @@ -1607,6 +1547,67 @@ sub connect "sys::database::timestamp" => $anvil->data->{sys}{database}{timestamp}, }}); } + + # Before we try to connect, see if this is a local database and, if so, make sure it's setup. + my $is_local = $anvil->Network->is_local({debug => $debug, host => $host}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { is_local => $is_local }}); + if ($is_local) + { + $anvil->data->{sys}{database}{read_uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }}); + + # If requested, and if running with root access, set it up (or update it) if needed. + # This method just returns if nothing is needed. + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + check_if_configured => $check_if_configured, + real_uid => $<, + effective_uid => $>, + }}); + if (($check_if_configured) && ($< == 0) && ($> == 0)) + { + $anvil->Database->configure_pgsql({debug => $debug, uuid => $uuid}); + } + } + elsif (not $anvil->data->{sys}{database}{read_uuid}) + { + $anvil->data->{sys}{database}{read_uuid} = $uuid; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }}); + } + + # If this isn't a local database, read the target's Anvil! version (if available) and make + # sure it matches ours. If it doesn't, skip this database. + if (not $is_local) + { + my ($local_anvil_version, $local_schema_version) = $anvil->_anvil_version({debug => $debug}); + my ($remote_anvil_version, $remote_schema_version) = $anvil->Get->anvil_version({ + debug => $debug, + target => $host, + password => $password, + }); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { + 's1:host' => $host, + 's2:local_anvil_version' => $local_anvil_version, + 's3:remote_anvil_version' => $remote_anvil_version, + 's4:local_schema_version' => $local_schema_version, + 's5:remote_schema_version' => $remote_schema_version, + }}); + # TODO: Periodically, we fail to get the remote version. For now, we proceed if + # everything else is OK. Might be better to pause a re-try... To be determined. + if (($remote_schema_version) && ($remote_schema_version ne $local_schema_version)) + { + # Version doesn't match, + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0145", variables => { + host => $host, + local_version => $local_schema_version, + target_version => $remote_schema_version, + }}); + + # Delete the information about this database. We'll try again on nexy + # ->connect(). + delete $anvil->data->{database}{$uuid}; + next; + } + } } my $total = tv_interval ($start_time, [gettimeofday]); @@ -14991,7 +14992,7 @@ sub resync_databases # Now read in the data from the different databases. foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) { - # ... + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); $anvil->data->{db_resync}{$uuid}{public}{sql} = []; $anvil->data->{db_resync}{$uuid}{history}{sql} = []; @@ -15313,6 +15314,7 @@ sub resync_databases # Do the INSERTs now and then release the memory. foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}}) { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }}); # Merge the queries for both schemas into one array, with public schema # queries being first, then delete the arrays holding them to free memory # before we start the resync. diff --git a/Anvil/Tools/Server.pm b/Anvil/Tools/Server.pm index c50fd4b6..3bf56862 100644 --- a/Anvil/Tools/Server.pm +++ b/Anvil/Tools/Server.pm @@ -1304,8 +1304,6 @@ sub parse_definition } $anvil->data->{server}{$target}{$server}{$source}{parsed} = $server_xml; - #print Dumper $server_xml; - #die; # Get the DRBD data that this server will almost certainly be using. $anvil->DRBD->get_devices({debug => $debug}); diff --git a/tools/anvil-provision-server b/tools/anvil-provision-server index d7866471..efbbccb0 100755 --- a/tools/anvil-provision-server +++ b/tools/anvil-provision-server @@ -1124,7 +1124,7 @@ sub check_drbd_minor_and_port resource_name => $anvil->data->{job}{server_name}, }); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { - 'job::drbd_minor' => $anvil->data->{job}{drbd_minor}, + 'job::drbd_minor' => $anvil->data->{job}{drbd_minor}, 'job::drbd_tcp_port' => $anvil->data->{job}{drbd_tcp_port}, }}); } From 213babaaf2a67dab9e3d364004e0eee8abe1d4c3 Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 30 Aug 2021 14:09:45 -0400 Subject: [PATCH 2/3] Trying to fix a bug where vnet devices keep reporting as having returned. Signed-off-by: Digimer --- Anvil/Tools/Database.pm | 13 +++++++++---- Anvil/Tools/ScanCore.pm | 2 +- scancore-agents/scan-network/scan-network | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Anvil/Tools/Database.pm b/Anvil/Tools/Database.pm index ae227823..cc897f8d 100644 --- a/Anvil/Tools/Database.pm +++ b/Anvil/Tools/Database.pm @@ -9112,16 +9112,21 @@ sub insert_or_update_network_interfaces # If we don't have a network interface UUID, try to look one up using the MAC address if (not $network_interface_uuid) { - # See if I know this NIC by referencing it's MAC and name. The name is needed because virtual - # devices can share the MAC with the real interface. + # See if I know this NIC by referencing it's MAC (if not a vnet device), host_uuid and name. + # The name is needed because virtual devices can share the MAC with the real interface. my $query = " SELECT network_interface_uuid FROM network_interfaces -WHERE +WHERE "; + if ($network_interface_name !~ /^vnet/) + { + $query .= " network_interface_mac_address = ".$anvil->Database->quote($network_interface_mac_address)." -AND +AND "; + } + $query .= " network_interface_name = ".$anvil->Database->quote($network_interface_name)." AND network_interface_host_uuid = ".$anvil->Database->quote($network_interface_host_uuid)." diff --git a/Anvil/Tools/ScanCore.pm b/Anvil/Tools/ScanCore.pm index e80edfef..52272477 100644 --- a/Anvil/Tools/ScanCore.pm +++ b/Anvil/Tools/ScanCore.pm @@ -271,7 +271,7 @@ sub agent_startup } # Connect to DBs. - $anvil->Database->connect({debug => 2}); + $anvil->Database->connect({debug => $debug}); $anvil->Log->entry({source => $agent, line => __LINE__, level => $debug, secure => 0, key => "log_0132"}); if (not $anvil->data->{sys}{database}{connections}) { diff --git a/scancore-agents/scan-network/scan-network b/scancore-agents/scan-network/scan-network index d2449a1c..a99255e7 100755 --- a/scancore-agents/scan-network/scan-network +++ b/scancore-agents/scan-network/scan-network @@ -724,6 +724,7 @@ ORDER BY }}); my $query = "DELETE FROM network_interfaces WHERE network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid).";"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }}); $anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__}); $count--; From 4427fe9f0dd31d73aa655754b639f8fe7861c8b3 Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 30 Aug 2021 17:59:39 -0400 Subject: [PATCH 3/3] * Found the source of the vnet constantly cycling back to 'up' bug. The anvil-update-state tool was marking the vnet device operational state back to 'unknown' and scan-network was marking it back up. Signed-off-by: Digimer --- tools/anvil-update-states | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/anvil-update-states b/tools/anvil-update-states index 8de29695..5c9f8445 100755 --- a/tools/anvil-update-states +++ b/tools/anvil-update-states @@ -65,13 +65,13 @@ sub process_interface_cache # Does the file exist? If so, read it in. if (-e $anvil->data->{path}{data}{network_cache}) { - my $body = $anvil->Storage->read_file({debug => 3, cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}}); + my $body = $anvil->Storage->read_file({debug => 2, cache => 0, force_read => 1, file => $anvil->data->{path}{data}{network_cache}}); foreach my $line (split/\n/, $body) { - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }}); next if $line =~ /^#/; my ($interface, $timestamp, $mac_address, $speed, $link_state, $operational) = (split/,/, $line); - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface, timestamp => $timestamp, speed => $speed, @@ -83,7 +83,7 @@ sub process_interface_cache if ($anvil->data->{sys}{database}{connections}) { my ($network_interface_uuid) = $anvil->Database->insert_or_update_network_interfaces({ - debug => 3, + debug => 2, link_only => 1, timestamp => $timestamp, network_interface_name => $interface, @@ -222,10 +222,21 @@ sub update_network $speed =~ s/\n$//; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { interface => $interface, - speed => $speed, mac_address => $mac_address, + link_state => $link_state, + mtu => $mtu, + duplex => $duplex, + operational => $operational, + speed => $speed, }}); + # If this a vnet device, set 'operational' to 'up'. + if (($interface =~ /^vnet/) && ($operational ne "up")) + { + $operational = "up"; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { operational => $operational }}); + } + # These are variables that will be needed if this is a bond interface. my $ip_address = ""; my $subnet_mask = "";