From a3d97e4c92ae4058b48278aa01aa54358b9bb0e5 Mon Sep 17 00:00:00 2001 From: Digimer Date: Mon, 18 Jun 2018 16:29:27 -0400 Subject: [PATCH] * Updated anvil-update-states to mark interfaces, bonds, bridges and IP addresses as DELETEd when they disappear. Signed-off-by: Digimer --- tools/anvil-update-states | 135 +++++++++++++++++++++++++++++++------- 1 file changed, 111 insertions(+), 24 deletions(-) diff --git a/tools/anvil-update-states b/tools/anvil-update-states index 400a83e8..76b3a31e 100755 --- a/tools/anvil-update-states +++ b/tools/anvil-update-states @@ -37,7 +37,7 @@ if (not $connections) $anvil->nice_exit({exit_code => 2}); } -report_network($anvil); +update_network($anvil); $anvil->nice_exit({exit_code => 0}); @@ -46,7 +46,7 @@ $anvil->nice_exit({exit_code => 0}); ############################################################################################################# # This reports the current network interface states, tracked by the MAC address. -sub report_network +sub update_network { my ($anvil) = @_; @@ -59,6 +59,14 @@ sub report_network my $directory = "/sys/class/net"; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { directory => $directory }}); + # We'll need to know what interfaces to remove, if any. This will store the interfaces we've seen and + # any others will be removed. + $anvil->data->{seen} = { + interfaces => {}, + bonds => {}, + bridges => {}, + }; + local(*DIRECTORY); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0018", variables => { directory => $directory }}); opendir(DIRECTORY, $directory); @@ -222,6 +230,10 @@ sub report_network } } + # Record this interface + $anvil->data->{seen}{$type}{$interface} = 1; + $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, @@ -427,7 +439,9 @@ SELECT FROM bonds WHERE - bond_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." + bond_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." +AND + bond_mode != 'DELETED' ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); @@ -439,8 +453,9 @@ WHERE foreach my $row (@{$results}) { my $bond_uuid = $row->[0]; + my $bond_name = $row->[1]; $anvil->data->{bonds}{$bond_uuid} = { - bond_name => $row->[1], + bond_name => $bond_name, bond_mode => $row->[2], bond_mtu => $row->[3], bond_primary_slave => $row->[4], @@ -465,6 +480,17 @@ WHERE "bonds::${bond_uuid}::bond_mac_address" => $anvil->data->{bonds}{$bond_uuid}{bond_mac_address}, "bonds::${bond_uuid}::bond_operational" => $anvil->data->{bonds}{$bond_uuid}{bond_operational}, }}); + + # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. + if ((not exists $anvil->data->{seen}{bond}{$bond_name}) or (not $anvil->data->{seen}{bond}{$bond_name})) + { + # Mark it as deleted. + my $query = "UPDATE bonds SET bond_mode = 'DELETED' WHERE bond_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($bond_uuid).";"; + $anvil->Database->write({debug => 2, 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}; + } } $query = " @@ -476,7 +502,9 @@ SELECT FROM bridges WHERE - bridge_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." + bridge_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." +AND + bridge_id != 'DELETED' ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); @@ -488,8 +516,9 @@ WHERE foreach my $row (@{$results}) { my $bridge_uuid = $row->[0]; + my $bridge_name = $row->[1]; $anvil->data->{bridges}{$bridge_uuid} = { - bridge_name => $row->[1], + bridge_name => $bridge_name, bridge_id => $row->[2], bridge_stp_enabled => $row->[3], }; @@ -498,6 +527,17 @@ WHERE "bridges::${bridge_uuid}::bridge_id" => $anvil->data->{bridges}{$bridge_uuid}{bridge_id}, "bridges::${bridge_uuid}::bridge_stp_enabled" => $anvil->data->{bridges}{$bridge_uuid}{bridge_stp_enabled}, }}); + + # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. + if ((not exists $anvil->data->{seen}{bridge}{$bridge_name}) or (not $anvil->data->{seen}{bridge}{$bridge_name})) + { + # Mark it as deleted. + my $query = "UPDATE bridges SET bridge_id = 'DELETED' WHERE bridge_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($bridge_uuid).";"; + $anvil->Database->write({debug => 2, 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->{bridges}{$bridge_uuid}; + } } $query = " @@ -516,11 +556,13 @@ SELECT FROM network_interfaces WHERE - network_interface_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." + network_interface_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." +AND + network_interface_operational != 'DELETED' ORDER BY modified_date DESC ;"; - $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); + $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }}); $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); $count = @{$results}; $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { @@ -536,9 +578,10 @@ ORDER BY foreach my $row (@{$results}) { my $network_interface_uuid = $row->[0]; + my $network_interface_name = $row->[2]; $anvil->data->{network_interfaces}{$network_interface_uuid} = { network_interface_mac_address => $row->[1], - network_interface_name => $row->[2], + network_interface_name => $network_interface_name, network_interface_speed => $row->[3], network_interface_mtu => $row->[4], network_interface_link_state => $row->[5], @@ -548,7 +591,7 @@ ORDER BY network_interface_bond_uuid => defined $row->[9] ? $row->[9] : 'NULL', network_interface_bridge_uuid => defined $row->[10] ? $row->[10] : 'NULL', }; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "network_interfaces::${network_interface_uuid}::network_interface_mac_address" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_mac_address}, "network_interfaces::${network_interface_uuid}::network_interface_name" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_name}, "network_interfaces::${network_interface_uuid}::network_interface_speed" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_speed}, @@ -561,6 +604,21 @@ ORDER BY "network_interfaces::${network_interface_uuid}::network_interface_bridge_uuid" => $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bridge_uuid}, order => $order, }}); + + # Make sure I've seen this interface in this scan and, if not, update this entry to remove it. + if ((not exists $anvil->data->{seen}{interface}{$network_interface_name}) or (not $anvil->data->{seen}{interface}{$network_interface_name})) + { + # Mark it as deleted. + my $query = "UPDATE network_interfaces SET network_interface_operational = 'DELETED' WHERE network_interface_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($network_interface_uuid).";"; + $anvil->Database->write({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->{interfaces}{$network_interface_uuid}; + + # Loop so we don't try to process any further. + next; + } + my $say_bond = ""; my $network_interface_bond_uuid = $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bond_uuid}; my $network_interface_bridge_uuid = $anvil->data->{network_interfaces}{$network_interface_uuid}{network_interface_bridge_uuid}; @@ -597,7 +655,9 @@ SELECT FROM ip_addresses WHERE - ip_address_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." + ip_address_host_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($anvil->Get->host_uuid)." + AND + ip_address_on_type != 'DELETED' ;"; $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0124", variables => { query => $query }}); $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__}); @@ -626,25 +686,52 @@ WHERE ip_address_dns => $ip_address_dns, }}); - my $say_on = ""; - if ($ip_address_on_type eq "interface") + # Did we see this IP on this scan? If not, set on_type to DELETEd. + my $found = 0; + foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{sys}{network}{interface}}) { - $say_on = $anvil->data->{network_interfaces}{$ip_address_on_uuid}{network_interface_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_on => $say_on }}); + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { + interface => $interface, + ip_address_address => $ip_address_address, + "sys::network::interface::${interface}::ip" => $anvil->data->{sys}{network}{interface}{$interface}{ip}, + }}); + if ((defined $anvil->data->{sys}{network}{interface}{$interface}{ip}) && ($anvil->data->{sys}{network}{interface}{$interface}{ip} eq $ip_address_address)) + { + $found = 1; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + last; + } } - elsif ($ip_address_on_type eq "bond") + + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { found => $found }}); + if ($found) { - $say_on = $anvil->data->{bonds}{$ip_address_on_uuid}{bond_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_on => $say_on }}); + my $say_on = ""; + if ($ip_address_on_type eq "interface") + { + $say_on = $anvil->data->{network_interfaces}{$ip_address_on_uuid}{network_interface_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_on => $say_on }}); + } + elsif ($ip_address_on_type eq "bond") + { + $say_on = $anvil->data->{bonds}{$ip_address_on_uuid}{bond_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_on => $say_on }}); + } + elsif ($ip_address_on_type eq "bridge") + { + $say_on = $anvil->data->{bridges}{$ip_address_on_uuid}{bridge_name}; + $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_on => $say_on }}); + } + + $network_json .= " { \"address\":\"$ip_address_address\", \"on\":\"$say_on\", \"subnet\":\"$ip_address_subnet_mask\", \"gateway\":\"$ip_address_gateway\", \"default_gateway\":\"$ip_address_default_gateway\", \"dns\":\"$ip_address_dns\" },\n"; + $network_xml .= " \n"; } - elsif ($ip_address_on_type eq "bridge") + else { - $say_on = $anvil->data->{bridges}{$ip_address_on_uuid}{bridge_name}; - $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { say_on => $say_on }}); + # Stale, mark it as deleted. + my $query = "UPDATE ip_addresses SET ip_address_on_type = 'DELETED' WHERE ip_address_uuid = ".$anvil->data->{sys}{use_db_fh}->quote($ip_address_uuid).";"; + $anvil->Database->write({debug => 2, query => $query, source => $THIS_FILE, line => __LINE__}); } - - $network_json .= " { \"address\":\"$ip_address_address\", \"on\":\"$say_on\", \"subnet\":\"$ip_address_subnet_mask\", \"gateway\":\"$ip_address_gateway\", \"default_gateway\":\"$ip_address_default_gateway\", \"dns\":\"$ip_address_dns\" },\n"; - $network_xml .= " \n"; } $network_json =~ s/,$//s;