This commit has more changes than I would normally like, but it's all linked to changing file uploads to rsync serially.

* To update file handling for the new DR host linking mechanism, file_locations -> file_location_anvil_uuid was changed to file_location_host_uuid.
  This required a fair number of changes elsewhere to handle this, with a particular noted change to Database->get_anvils() to look at host_uuid's for the subnodes in an Anvil! and, if either is marked as needing a file, make sure the peer is as well. Similarly, any linked DRs are set to have the file as well.
* Created a new Network->find_access that simply takes a target host name or UUID, and it returns a list of networks and IPs that the target can be accessed by.
* Updated Network->load_ips() to find the network interface being used for traffic so that things like the interface speed can be recorded, even when an IP is on a bridge or bond.

Unrelated, but in this commit, is a restoration of calling scan agents with a timeout now that the virsh hang issue has been resolved.

Signed-off-by: digimer <mkelly@alteeve.ca>
main
digimer 2 years ago
parent 7710d9d109
commit 645f54ab89
  1. 214
      Anvil/Tools/Database.pm
  2. 208
      Anvil/Tools/Network.pm
  3. 16
      Anvil/Tools/ScanCore.pm
  4. 2
      Anvil/Tools/Storage.pm
  5. 2
      notes
  6. 10
      share/anvil.sql
  7. 21
      share/words.xml
  8. 2
      tools/anvil-manage-files
  9. 200
      tools/anvil-sync-shared
  10. 135
      tools/anvil-version-changes
  11. 11
      tools/striker-purge-target

@ -386,7 +386,7 @@ sub backup_database
=head2 check_file_locations
This method checks to see that there is a corresponding entry in C<< file_locations >> for all Anvil! systems and files in the database. Any that are found to be missing will be set to C<< file_location_active >> -> c<< true >>.
This method checks to see that there is a corresponding entry in C<< file_locations >> for all hosts and files in the database. Any that are found to be missing will be set to C<< file_location_active >> -> c<< true >>.
This method takes no parameters.
@ -400,31 +400,31 @@ sub check_file_locations
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->check_file_locations()" }});
# Get all the Anvil! systems we know of.
$anvil->Database->get_anvils({debug => $debug});
$anvil->Database->get_hosts({debug => $debug});
$anvil->Database->get_files({debug => $debug});
$anvil->Database->get_file_locations({debug => $debug});
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{hosts}{host_name}})
{
my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
my $host_uuid = $anvil->data->{hosts}{host_name}{$host_name}{host_uuid};
foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{files}{file_name}})
{
my $file_uuid = $anvil->data->{files}{file_name}{$file_name}{file_uuid};
# Does this file exist for this Anvil! system?
if (not exists $anvil->data->{file_locations}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_location_uuid})
if (not exists $anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}{file_location_uuid})
{
# Add this entry.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0613", variables => {
anvil_name => $anvil_name,
host_name => $host_name,
file_name => $file_name,
}});
my $file_location_uuid = $anvil->Database->insert_or_update_file_locations({
debug => $debug,
file_location_file_uuid => $file_uuid,
file_location_anvil_uuid => $anvil_uuid,
file_location_host_uuid => $host_uuid,
file_location_active => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_location_uuid => $file_location_uuid }});
@ -2710,7 +2710,6 @@ SELECT
anvil_password,
anvil_node1_host_uuid,
anvil_node2_host_uuid,
anvil_dr1_host_uuid,
modified_date
FROM
anvils ";
@ -2737,8 +2736,7 @@ WHERE
my $anvil_password = $row->[3];
my $anvil_node1_host_uuid = defined $row->[4] ? $row->[4] : "";
my $anvil_node2_host_uuid = defined $row->[5] ? $row->[5] : "";
my $anvil_dr1_host_uuid = defined $row->[6] ? $row->[6] : "";
my $modified_date = $row->[7];
my $modified_date = $row->[6];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid,
anvil_name => $anvil_name,
@ -2746,7 +2744,6 @@ WHERE
anvil_password => $anvil->Log->is_secure($anvil_password),
anvil_node1_host_uuid => $anvil_node1_host_uuid,
anvil_node2_host_uuid => $anvil_node2_host_uuid,
anvil_dr1_host_uuid => $anvil_dr1_host_uuid,
modified_date => $modified_date,
}});
@ -2756,7 +2753,6 @@ WHERE
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password} = $anvil_password;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid} = $anvil_node1_host_uuid;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid} = $anvil_node2_host_uuid;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid} = $anvil_dr1_host_uuid;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{modified_date} = $modified_date;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::anvil_uuid::${anvil_uuid}::anvil_name" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name},
@ -2764,7 +2760,6 @@ WHERE
"anvils::anvil_uuid::${anvil_uuid}::anvil_password" => $anvil->Log->is_secure($anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_password}),
"anvils::anvil_uuid::${anvil_uuid}::anvil_node1_host_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid},
"anvils::anvil_uuid::${anvil_uuid}::anvil_node2_host_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid},
"anvils::anvil_uuid::${anvil_uuid}::anvil_dr1_host_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid},
"anvils::anvil_uuid::${anvil_uuid}::modified_date" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{modified_date},
}});
@ -2775,7 +2770,6 @@ WHERE
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_password} = $anvil_password;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node1_host_uuid} = $anvil_node1_host_uuid;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node2_host_uuid} = $anvil_node2_host_uuid;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_dr1_host_uuid} = $anvil_dr1_host_uuid;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{modified_date} = $modified_date;
$anvil->data->{anvils}{anvil_name}{$anvil_name}{query_time} = time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -2784,7 +2778,6 @@ WHERE
"anvils::anvil_name::${anvil_name}::anvil_password" => $anvil->Log->is_secure($anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_password}),
"anvils::anvil_name::${anvil_name}::anvil_node1_host_uuid" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node1_host_uuid},
"anvils::anvil_name::${anvil_name}::anvil_node2_host_uuid" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node2_host_uuid},
"anvils::anvil_name::${anvil_name}::anvil_dr1_host_uuid" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_dr1_host_uuid},
"anvils::anvil_name::${anvil_name}::modified_date" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{modified_date},
"anvils::anvil_name::${anvil_name}::query_time" => $anvil->data->{anvils}{anvil_name}{$anvil_name}{query_time},
}});
@ -2811,31 +2804,114 @@ WHERE
"anvils::host_uuid::${anvil_node2_host_uuid}::role" => $anvil->data->{anvils}{host_uuid}{$anvil_node2_host_uuid}{role},
}});
}
### TODO: Remove this once the switch over to 'dr_links' is done.
if ($anvil_dr1_host_uuid)
# Process DR hosts this Anvil! is allowed to use.
if (exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid})
{
$anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_name} = $anvil_name;
$anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_uuid} = $anvil_uuid;
$anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{role} = "dr1";
foreach my $dr_link_host_uuid (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}})
{
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$dr_link_host_uuid}{dr_link_uuid};
my $dr_link_note = $anvil->data->{dr_links}{dr_link_uuid}{$dr_link_uuid}{dr_link_note};
my $dr_link_short_host_name = $anvil->data->{hosts}{host_uuid}{$dr_link_host_uuid}{short_host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:dr_link_host_uuid" => $dr_link_host_uuid,
"s2:dr_link_uuid" => $dr_link_uuid,
"s3:dr_link_note" => $dr_link_note,
"s4:dr_link_short_host_name" => $dr_link_short_host_name,
}});
next if $dr_link_note eq "DELETED";
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}{$dr_link_host_uuid}{dr_link_uuid} = $dr_link_uuid;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}{$dr_link_host_uuid}{short_host_name} = $dr_link_short_host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::host_uuid::${anvil_dr1_host_uuid}::anvil_name" => $anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_name},
"anvils::host_uuid::${anvil_dr1_host_uuid}::anvil_uuid" => $anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{anvil_uuid},
"anvils::host_uuid::${anvil_dr1_host_uuid}::role" => $anvil->data->{anvils}{host_uuid}{$anvil_dr1_host_uuid}{role},
"s1:anvils::anvil_uuid::${anvil_uuid}::dr_host::${dr_link_host_uuid}::dr_link_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}{$dr_link_host_uuid}{dr_link_uuid},
"s2:anvils::anvil_uuid::${anvil_uuid}::dr_host::${dr_link_host_uuid}::short_host_name" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}{$dr_link_host_uuid}{short_host_name},
}});
}
}
# Track the files on this Anvil!
foreach my $file_location_uuid (keys %{$anvil->data->{file_locations}{file_location_uuid}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_location_uuid => $file_location_uuid }});
# If either node is set have this file, make sure both are.
my $file_uuid = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_file_uuid};
my $anvil_needs_file = 0;
$anvil->{needs_file}{$file_uuid}{$anvil_node1_host_uuid} = 0;
$anvil->{needs_file}{$file_uuid}{$anvil_node2_host_uuid} = 0;
if ((exists $anvil->data->{file_locations}{host_uuid}{$anvil_node1_host_uuid}{file_uuid}{$file_uuid}) &&
($anvil->data->{file_locations}{host_uuid}{$anvil_node1_host_uuid}{file_uuid}{$file_uuid}{file_location_uuid}))
{
my $file_location_uuid = $anvil->data->{file_locations}{host_uuid}{$anvil_node1_host_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
my $file_location_active = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"file_locations::file_location_uuid::${file_location_uuid}::file_location_anvil_uuid" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_anvil_uuid},
"file_locations::file_location_uuid::${file_location_uuid}::file_location_active" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active},
file_location_uuid => $file_location_uuid,
file_location_active => $file_location_active,
}});
next if $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_anvil_uuid} ne $anvil_uuid;
next if not $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active};
my $file_uuid = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_file_uuid};
if (not $file_location_active)
{
$anvil->{needs_file}{$file_uuid}{$anvil_node1_host_uuid} = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"needs_file::${file_uuid}::${anvil_node1_host_uuid}" => $anvil->{needs_file}{$file_uuid}{$anvil_node1_host_uuid},
}});
}
}
if ((exists $anvil->data->{file_locations}{host_uuid}{$anvil_node2_host_uuid}{file_uuid}{$file_uuid}) &&
($anvil->data->{file_locations}{host_uuid}{$anvil_node2_host_uuid}{file_uuid}{$file_uuid}{file_location_uuid}))
{
my $file_location_uuid = $anvil->data->{file_locations}{host_uuid}{$anvil_node2_host_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
my $file_location_active = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file_location_uuid => $file_location_uuid,
file_location_active => $file_location_active,
}});
if (not $file_location_active)
{
$anvil->{needs_file}{$file_uuid}{$anvil_node2_host_uuid} = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"needs_file::${file_uuid}::${anvil_node2_host_uuid}" => $anvil->{needs_file}{$file_uuid}{$anvil_node2_host_uuid},
}});
}
}
# If either node has the file, both nodes (and all DRs) need the file.
if (($anvil->{needs_file}{$file_uuid}{$anvil_node1_host_uuid}) or ($anvil->{needs_file}{$file_uuid}{$anvil_node2_host_uuid}))
{
$anvil_needs_file = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_needs_file => $anvil_needs_file }});
}
foreach my $host_uuid ($anvil_node1_host_uuid, $anvil_node2_host_uuid)
{
# If the Anvil! needs the file, make sure that both nodes and any connected DRs have it as well.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
}});
if ($anvil_needs_file)
{
if (not $anvil->{needs_file}{$file_uuid}{$host_uuid})
{
$anvil->Database->insert_or_update_file_locations({
debug => $debug,
file_location_file_uuid => $file_location_uuid,
file_location_host_uuid => $host_uuid,
file_location_active => 1,
});
}
}
}
# If the Anvil! node needs the file, record it as being on this Anvil! node.
if ($anvil_needs_file)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"file_locations::file_location_uuid::${file_location_uuid}::file_location_host_uuid" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_host_uuid},
"file_locations::file_location_uuid::${file_location_uuid}::file_location_active" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active},
}});
next if not exists $anvil->data->{files}{file_uuid}{$file_uuid};
my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name};
@ -2864,31 +2940,23 @@ WHERE
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::anvil_uuid::${anvil_uuid}::file_name::${file_name}::file_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid},
}});
}
# Process DR hosts this Anvil! is allowed to use.
if (exists $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid})
{
foreach my $dr_link_host_uuid (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}})
# Make sure linked DR hosts have this file, also.
foreach my $host_uuid (keys %{$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}})
{
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}{$dr_link_host_uuid}{dr_link_uuid};
my $dr_link_note = $anvil->data->{dr_links}{dr_link_uuid}{$dr_link_uuid}{dr_link_note};
my $dr_link_short_host_name = $anvil->data->{hosts}{host_uuid}{$dr_link_host_uuid}{short_host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:dr_link_host_uuid" => $dr_link_host_uuid,
"s2:dr_link_uuid" => $dr_link_uuid,
"s3:dr_link_note" => $dr_link_note,
"s4:dr_link_short_host_name" => $dr_link_short_host_name,
}});
next if $dr_link_note eq "DELETED";
my $file_location_uuid = $anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
my $file_location_active = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active};
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}{$dr_link_host_uuid}{dr_link_uuid} = $dr_link_uuid;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}{$dr_link_host_uuid}{short_host_name} = $dr_link_short_host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:anvils::anvil_uuid::${anvil_uuid}::dr_host::${dr_link_host_uuid}::dr_link_uuid" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}{$dr_link_host_uuid}{dr_link_uuid},
"s2:anvils::anvil_uuid::${anvil_uuid}::dr_host::${dr_link_host_uuid}::short_host_name" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{dr_host}{$dr_link_host_uuid}{short_host_name},
}});
if (not $file_location_active)
{
$anvil->Database->insert_or_update_file_locations({
debug => $debug,
file_location_file_uuid => $file_location_uuid,
file_location_host_uuid => $host_uuid,
file_location_active => 1,
});
}
}
}
}
}
@ -3238,7 +3306,7 @@ WHERE
This loads the known install file_locations into the C<< anvil::data >> hash at:
* file_locations::file_location_uuid::<file_location_uuid>::file_location_file_uuid
* file_locations::file_location_uuid::<file_location_uuid>::file_location_anvil_uuid
* file_locations::file_location_uuid::<file_location_uuid>::file_location_host_uuid
* file_locations::file_location_uuid::<file_location_uuid>::file_location_active
* file_locations::file_location_uuid::<file_location_uuid>::modified_date
@ -3264,7 +3332,7 @@ sub get_file_locations
SELECT
file_location_uuid,
file_location_file_uuid,
file_location_anvil_uuid,
file_location_host_uuid,
file_location_active,
modified_date
FROM
@ -3281,33 +3349,33 @@ FROM
{
my $file_location_uuid = $row->[0];
my $file_location_file_uuid = $row->[1];
my $file_location_anvil_uuid = $row->[2];
my $file_location_host_uuid = $row->[2];
my $file_location_active = $row->[3];
my $modified_date = $row->[4];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file_location_uuid => $file_location_uuid,
file_location_file_uuid => $file_location_file_uuid,
file_location_anvil_uuid => $file_location_anvil_uuid,
file_location_host_uuid => $file_location_host_uuid,
file_location_active => $file_location_active,
modified_date => $modified_date,
}});
# Record the data in the hash, too.
$anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_file_uuid} = $file_location_file_uuid;
$anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_anvil_uuid} = $file_location_anvil_uuid;
$anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_host_uuid} = $file_location_host_uuid;
$anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active} = $file_location_active;
$anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{modified_date} = $modified_date;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"file_locations::file_location_uuid::${file_location_uuid}::file_location_file_uuid" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_file_uuid},
"file_locations::file_location_uuid::${file_location_uuid}::file_location_anvil_uuid" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_anvil_uuid},
"file_locations::file_location_uuid::${file_location_uuid}::file_location_host_uuid" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_host_uuid},
"file_locations::file_location_uuid::${file_location_uuid}::file_location_active" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_active},
"file_locations::file_location_uuid::${file_location_uuid}::modified_date" => $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{modified_date},
}});
# Make it easy to find files by anvil and file UUID.
$anvil->data->{file_locations}{anvil_uuid}{$file_location_anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_location_uuid} = $file_location_uuid;
$anvil->data->{file_locations}{host_uuid}{$file_location_host_uuid}{file_uuid}{$file_location_file_uuid}{file_location_uuid} = $file_location_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"file_locations::anvil_uuid::${file_location_anvil_uuid}::file_uuid::${file_location_file_uuid}::file_location_uuid" => $anvil->data->{file_locations}{anvil_uuid}{$file_location_anvil_uuid}{file_uuid}{$file_location_file_uuid}{file_location_uuid},
"file_locations::host_uuid::${file_location_host_uuid}::file_uuid::${file_location_file_uuid}::file_location_uuid" => $anvil->data->{file_locations}{host_uuid}{$file_location_host_uuid}{file_uuid}{$file_location_file_uuid}{file_location_uuid},
}});
}
@ -7924,7 +7992,7 @@ INSERT INTO
This updates (or inserts) a record in the 'file_locations' table. The C<< file_location_uuid >> referencing the database row will be returned.
This table is used to track which files on Striker dashboards need to be on given Anvil! members.
This table is used to track which files on Striker dashboards need to be on given Anvil! members and DR hosts.
If there is an error, an empty string is returned.
@ -7938,9 +8006,9 @@ If not passed, a check will be made to see if an existing entry is found for C<<
This is the C<< files >> -> C<< file_uuid >> being referenced.
=head3 file_location_anvil_uuid (required)
=head3 file_location_host_uuid (required)
This is the C<< anvils >> -> C<< anvil_uuid >> being referenced.
This is the C<< hosts >> -> C<< host_uuid >> being referenced.
=head3 file_location_active (required)
@ -7962,7 +8030,7 @@ sub insert_or_update_file_locations
my $line = defined $parameter->{line} ? $parameter->{line} : "";
my $file_location_uuid = defined $parameter->{file_location_uuid} ? $parameter->{file_location_uuid} : "";
my $file_location_file_uuid = defined $parameter->{file_location_file_uuid} ? $parameter->{file_location_file_uuid} : "";
my $file_location_anvil_uuid = defined $parameter->{file_location_anvil_uuid} ? $parameter->{file_location_anvil_uuid} : "";
my $file_location_host_uuid = defined $parameter->{file_location_host_uuid} ? $parameter->{file_location_host_uuid} : "";
my $file_location_active = defined $parameter->{file_location_active} ? $parameter->{file_location_active} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
@ -7970,7 +8038,7 @@ sub insert_or_update_file_locations
line => $line,
file_location_uuid => $file_location_uuid,
file_location_file_uuid => $file_location_file_uuid,
file_location_anvil_uuid => $file_location_anvil_uuid,
file_location_host_uuid => $file_location_host_uuid,
file_location_active => $file_location_active,
}});
@ -7980,10 +8048,10 @@ sub insert_or_update_file_locations
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_file_locations()", parameter => "file_location_file_uuid" }});
return("");
}
if (not $file_location_anvil_uuid)
if (not $file_location_host_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_file_locations()", parameter => "file_location_anvil_uuid" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_file_locations()", parameter => "file_location_host_uuid" }});
return("");
}
if (($file_location_active ne "0") && ($file_location_active ne "1"))
@ -8004,7 +8072,7 @@ FROM
WHERE
file_location_file_uuid = ".$anvil->Database->quote($file_location_file_uuid)."
AND
file_location_anvil_uuid = ".$anvil->Database->quote($file_location_anvil_uuid)."
file_location_host_uuid = ".$anvil->Database->quote($file_location_host_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
@ -8035,13 +8103,13 @@ INSERT INTO
(
file_location_uuid,
file_location_file_uuid,
file_location_anvil_uuid,
file_location_host_uuid,
file_location_active,
modified_date
) VALUES (
".$anvil->Database->quote($file_location_uuid).",
".$anvil->Database->quote($file_location_file_uuid).",
".$anvil->Database->quote($file_location_anvil_uuid).",
".$anvil->Database->quote($file_location_host_uuid).",
".$anvil->Database->quote($file_location_active).",
".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);
@ -8055,7 +8123,7 @@ INSERT INTO
my $query = "
SELECT
file_location_file_uuid,
file_location_anvil_uuid,
file_location_host_uuid,
file_location_active,
FROM
file_locations
@ -8079,17 +8147,17 @@ WHERE
foreach my $row (@{$results})
{
my $old_file_location_file_uuid = $row->[0];
my $old_file_location_anvil_uuid = $row->[1];
my $old_file_location_host_uuid = $row->[1];
my $old_file_location_active = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_file_location_file_uuid => $old_file_location_file_uuid,
old_file_location_anvil_uuid => $old_file_location_anvil_uuid,
old_file_location_host_uuid => $old_file_location_host_uuid,
old_file_location_active => $old_file_location_active,
}});
# Anything change?
if (($old_file_location_file_uuid ne $file_location_file_uuid) or
($old_file_location_anvil_uuid ne $file_location_anvil_uuid) or
($old_file_location_host_uuid ne $file_location_host_uuid) or
($old_file_location_active ne $file_location_active))
{
# Something changed, save.
@ -8098,7 +8166,7 @@ UPDATE
file_locations
SET
file_location_file_uuid = ".$anvil->Database->quote($file_location_file_uuid).",
file_location_anvil_uuid = ".$anvil->Database->quote($file_location_anvil_uuid).",
file_location_host_uuid = ".$anvil->Database->quote($file_location_host_uuid).",
file_location_active = ".$anvil->Database->quote($file_location_active).",
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE

@ -18,6 +18,7 @@ my $THIS_FILE = "Network.pm";
# check_network
# check_internet
# download
# find_access
# find_matches
# find_target_ip
# get_company_from_mac
@ -1186,6 +1187,169 @@ sub download
}
=head2 find_access
This takes a host's UUID or name, and finds networks that this host can reach it on. If the target is not found in the database, C<< !!error!! >> is returned. Otherwise, the number of matches found is returned.
B<< Note >>: This requires that the target has recorded it's network in the database.
It was written to be a saner version of C<< Network->find_matches() >>
Matches will be stored as:
* network_access::<network_name>::local_ip_address = <local_ip_address>
* network_access::<network_name>::local_subnet_mask = <local_subnet_mask>
* network_access::<network_name>::local_interface = <local_interface_with_ip>
* network_access::<network_name>::local_speed = <speed_in_Mbps>
* network_access::<network_name>::target_ip_address = <target_ip_address>
* network_access::<network_name>::target_subnet_mask = <target_subnet_mask>
* network_access::<network_name>::target_interface = <target_interface_with_ip>
* network_access::<network_name>::target_speed = <speed_in_Mbps>
Where C<< network_name >> will be C<< bcnX >>, C<< ifnX >>, etc.
Paramters;
=head3 target (required)
This is the host we're looking for connection options with.
=cut
sub find_access
{
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_access()" }});
my $target = defined $parameter->{target} ? $parameter->{target} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
target => $target,
}});
if (not $target)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->find_access()", parameter => "target" }});
return("!!error!!");
}
# Take the target and find the host_uuid and host_name.
my $target_host_uuid = $anvil->Database->get_host_uuid_from_string({debug => $debug, string => $target});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target_host_uuid => $target_host_uuid }});
if (not $target_host_uuid)
{
# Bad target.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0414", variables => { target => $target }});
return("!!error!!");
}
my $host_uuid = $anvil->Get->host_uuid;
my $short_host_name = $anvil->Get->short_host_name;
my $target_short_host_name = $anvil->data->{hosts}{host_uuid}{$target_host_uuid}{short_host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
short_host_name => $short_host_name,
target_short_host_name => $target_short_host_name,
}});
# Load our IPs
$anvil->Network->load_ips({
debug => $debug,
host => $short_host_name,
});
# Load our target's IPs.
$anvil->Network->load_ips({
debug => $debug,
host => $target_short_host_name,
host_uuid => $target_host_uuid,
});
# Loop through the first, and on each interface with an IP/subnet mask, look for a match in the second.
foreach my $local_interface (sort {$b cmp $a} keys %{$anvil->data->{network}{$short_host_name}{interface}})
{
my $local_ip = $anvil->data->{network}{$short_host_name}{interface}{$local_interface}{ip};
my $local_subnet_mask = $anvil->data->{network}{$short_host_name}{interface}{$local_interface}{subnet_mask};
my $local_speed = $anvil->data->{network}{$short_host_name}{interface}{$local_interface}{speed};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
local_interface => $local_interface,
local_ip => $local_ip,
local_subnet_mask => $local_subnet_mask,
local_speed => $local_speed,
}});
if (($local_ip) && ($local_subnet_mask))
{
# Look for a match.
my $local_network = $anvil->Network->get_network({
debug => $debug,
ip => $local_ip,
subnet_mask => $local_subnet_mask,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { local_network => $local_network }});
foreach my $target_interface (sort {$b cmp $a} keys %{$anvil->data->{network}{$target_short_host_name}{interface}})
{
my $target_ip = $anvil->data->{network}{$target_short_host_name}{interface}{$target_interface}{ip};
my $target_subnet_mask = $anvil->data->{network}{$target_short_host_name}{interface}{$target_interface}{subnet_mask};
my $target_speed = $anvil->data->{network}{$target_short_host_name}{interface}{$target_interface}{speed};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
target_interface => $target_interface,
target_ip => $target_ip,
target_subnet_mask => $target_subnet_mask,
target_speed => $target_speed,
}});
if (($target_ip) && ($target_subnet_mask))
{
# Do we have a match?
my $target_network = $anvil->Network->get_network({
debug => $debug,
ip => $target_ip,
subnet_mask => $target_subnet_mask,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
local_network => $local_network,
target_network => $target_network,
}});
if ($local_network eq $target_network)
{
# Match!
my $network_name = $target_interface;
$network_name =~ s/^(\w+\d+)_.*$/$1/;
$anvil->data->{network_access}{$network_name}{local_interface} = $local_interface;
$anvil->data->{network_access}{$network_name}{local_speed} = $local_speed;
$anvil->data->{network_access}{$network_name}{local_ip_address} = $local_ip;
$anvil->data->{network_access}{$network_name}{local_subnet_mask} = $local_subnet_mask;
$anvil->data->{network_access}{$network_name}{target_interface} = $target_interface;
$anvil->data->{network_access}{$network_name}{target_speed} = $target_speed;
$anvil->data->{network_access}{$network_name}{target_ip_address} = $target_ip;
$anvil->data->{network_access}{$network_name}{target_subnet_mask} = $target_subnet_mask;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:network_access::${network_name}::local_interface" => $anvil->data->{network_access}{$network_name}{local_interface},
"s2:network_access::${network_name}::local_speed" => $anvil->data->{network_access}{$network_name}{local_speed},
"s3:network_access::${network_name}::local_ip_address" => $anvil->data->{network_access}{$network_name}{local_ip_address},
"s4:network_access::${network_name}::local_subnet_mask" => $anvil->data->{network_access}{$network_name}{local_subnet_mask},
"s5:network_access::${network_name}::target_interface" => $anvil->data->{network_access}{$network_name}{target_interface},
"s6:network_access::${network_name}::target_speed" => $anvil->data->{network_access}{$network_name}{target_speed},
"s7:network_access::${network_name}::target_ip_address" => $anvil->data->{network_access}{$network_name}{target_ip_address},
"s8:network_access::${network_name}::target_subnet_mask" => $anvil->data->{network_access}{$network_name}{target_subnet_mask},
}});
}
}
}
}
}
my $matches = keys %{$anvil->data->{network_access}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { matches => $matches }});
return($matches);
}
=head2 find_matches
This takes two hash keys from prior C<< Network->get_ips() >> or C<< ->load_ips() >> runs and finds which are on the same network.
@ -2763,7 +2927,7 @@ sub load_ips
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Network->load_ips()" }});
my $clear = defined $parameter->{clear} ? $parameter->{clear} : 1;
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid;
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : "";
my $host = defined $parameter->{host} ? $parameter->{host} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
clear => $clear,
@ -2773,8 +2937,8 @@ sub load_ips
if (not $host_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Network->load_ips()", parameter => "ip" }});
return("");
$host_uuid = $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
}
if (not $host)
@ -2834,7 +2998,39 @@ AND
my $interface_name = "";
my $interface_mac = "";
my $network_interface_uuid = "";
if ($ip_address_on_type eq "interface")
{
$network_interface_uuid = $ip_address_on_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { network_interface_uuid => $network_interface_uuid }});
}
else
{
my $query = "";
if ($ip_address_on_type eq "bridge")
{
# What's the bridge UUID?
$query = "SELECT bond_active_interface FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($ip_address_on_uuid).";";
}
else
{
$query = "SELECT bond_active_interface 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 $active_interface = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { active_interface => $active_interface }});
if ($active_interface)
{
my $query = "SELECT network_interface_uuid FROM network_interfaces WHERE network_interface_host_uuid = ".$anvil->Database->quote($host_uuid)." AND network_interface_name = ".$anvil->Database->quote($active_interface).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$network_interface_uuid = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { active_interface => $active_interface }});
}
}
if ($network_interface_uuid)
{
my $query = "
SELECT
@ -2852,7 +3048,7 @@ SELECT
FROM
network_interfaces
WHERE
network_interface_uuid = ".$anvil->Database->quote($ip_address_on_uuid)."
network_interface_uuid = ".$anvil->Database->quote($network_interface_uuid)."
AND
network_interface_operational != 'DELETED'
;";
@ -2886,8 +3082,8 @@ AND
$anvil->data->{network}{$host}{interface}{$interface_name}{operational} = $results->[0]->[6];
$anvil->data->{network}{$host}{interface}{$interface_name}{duplex} = $results->[0]->[7];
$anvil->data->{network}{$host}{interface}{$interface_name}{medium} = $results->[0]->[8];
$anvil->data->{network}{$host}{interface}{$interface_name}{bond_uuid} = $results->[0]->[9];
$anvil->data->{network}{$host}{interface}{$interface_name}{bridge_uuid} = $results->[0]->[10];
$anvil->data->{network}{$host}{interface}{$interface_name}{bond_uuid} = defined $results->[0]->[9] ? $results->[0]->[9] : "";
$anvil->data->{network}{$host}{interface}{$interface_name}{bridge_uuid} = defined $results->[0]->[10] ? $results->[0]->[10] : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"network::${host}::interface::${interface_name}::network_interface_uuid" => $anvil->data->{network}{$host}{interface}{$interface_name}{network_interface_uuid},
"network::${host}::interface::${interface_name}::mac_address" => $anvil->data->{network}{$host}{interface}{$interface_name}{mac_address},

@ -404,15 +404,13 @@ sub call_scan_agents
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
# Tell the user this agent is about to run...
# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => $debug, key => "log_0252", variables => {
# agent_name => $agent_name,
# timeout => $timeout,
# }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => $debug, key => "log_0701", variables => { agent_name => $agent_name }});
### TODO: Timeout, when called / set here, was hanging virsh calls. Unknown why yet, but temp
### fix is to just not use timeouts for calls.
#my ($output, $return_code) = $anvil->System->call({timeout => $timeout, shell_call => $shell_call});
my ($output, $return_code) = $anvil->System->call({shell_call => $shell_call});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => $debug, key => "log_0252", variables => {
agent_name => $agent_name,
timeout => $timeout,
}});
# $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => $debug, key => "log_0701", variables => { agent_name => $agent_name }});
my ($output, $return_code) = $anvil->System->call({timeout => $timeout, shell_call => $shell_call});
# my ($output, $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)
{

@ -5246,7 +5246,7 @@ Parameters;
This is the full path to the file. If the file is not found, C<< !!error!! >> is returned.
=head3 delay (optional, default '2')
=head3 delay (optional, default '10')
This is how long to wait before checking to see if the file has changed.

@ -1,6 +1,4 @@
Add 'lsof' and 'strace' to Required
When pairing Striker, make sure new config goes to all known nodes!

@ -1232,12 +1232,12 @@ CREATE TRIGGER trigger_files
CREATE TABLE file_locations (
file_location_uuid uuid not null primary key,
file_location_file_uuid uuid not null, -- This is file to be moved to (or restored to) this machine.
file_location_anvil_uuid uuid not null, -- This is the sum as calculated when the file_location is first uploaded. Once recorded, it can't change.
file_location_host_uuid uuid not null, -- This is the sum as calculated when the file_location is first uploaded. Once recorded, it can't change.
file_location_active boolean not null default TRUE, -- This is set to true when the file should be on Anvil! machines, triggering rsyncs when needed. When set to false, the file will be deleted from members, if they exist.
modified_date timestamp with time zone not null,
FOREIGN KEY(file_location_file_uuid) REFERENCES files(file_uuid),
FOREIGN KEY(file_location_anvil_uuid) REFERENCES anvils(anvil_uuid)
FOREIGN KEY(file_location_host_uuid) REFERENCES hosts(host_uuid)
);
ALTER TABLE file_locations OWNER TO admin;
@ -1245,7 +1245,7 @@ CREATE TABLE history.file_locations (
history_id bigserial,
file_location_uuid uuid,
file_location_file_uuid text,
file_location_anvil_uuid uuid,
file_location_host_uuid uuid,
file_location_active boolean,
modified_date timestamp with time zone not null
);
@ -1260,13 +1260,13 @@ BEGIN
INSERT INTO history.file_locations
(file_location_uuid,
file_location_file_uuid,
file_location_anvil_uuid,
file_location_host_uuid,
file_location_active,
modified_date)
VALUES
(history_file_locations.file_location_uuid,
history_file_locations.file_location_file_uuid,
history_file_locations.file_location_anvil_uuid,
history_file_locations.file_location_host_uuid,
history_file_locations.file_location_active,
history_file_locations.modified_date);
RETURN NULL;

@ -586,6 +586,7 @@ The definition data passed in was:
<key name="error_0411"><![CDATA[The server: [#!variable!server!#] was not found. Exiting.]]></key>
<key name="error_0412"><![CDATA[The server: [#!variable!server!#] is on the Anvil! node: [#!variable!on_anvil!#], and this is: [#!variable!this_anvil!#]. Exiting.]]></key>
<key name="error_0413"><![CDATA[You need to specify the server with '--server <name or uuid>'. Available servers are;]]></key>
<key name="error_0414"><![CDATA[The target host: [#!variable!target!#] was not found in the database.]]></key>
<!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which lines are translatable -->
@ -2236,7 +2237,7 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0610">We're online as: [#!variable!node_name!#], but we're not quorate yet. Continuing to wait.</key>
<key name="log_0611">We're online as: [#!variable!node_name!#] and quorate!</key>
<key name="log_0612">We're not online yet. Waiting for 'in_ccm/crmd/join': [#!variable!in_ccm!#/#!variable!crmd!#/#!variable!join!#]. ('in_ccm' = consensus cluster member, communication layer. 'crmd' = cluster resource manager daemon is up, 'join' = allowed to host resources).</key>
<key name="log_0613">The file: [#!variable!file_name!#] is not recorded for the Anvil! [#!variable!anvil_name!#] yet. Registering it now as not sync'ed to this Anvil! system.</key>
<key name="log_0613">The file: [#!variable!file_name!#] is not recorded for the host [#!variable!host_name!#] yet. Registering it now as not sync'ed to this system.</key>
<key name="log_0614">Asking 'anvil-boot-server' to boot the servers now.</key>
<key name="log_0615">We were asked to delete the file: [#!variable!file!#], but it doesn't exist, so nothing to do.</key>
<key name="log_0616">The file: [#!variable!file!#] has been successfully removed.</key>
@ -2657,8 +2658,11 @@ About to try to download aproximately: [#!variable!packages!#] packages needed t
<key name="message_0192">Moving the file: [#!variable!file!#] to: [#!data!path::directories::shared::files!#].</key>
<key name="message_0193">Calculating the md5sum. This can take a little while for large files, please be patient.</key>
<key name="message_0194">The md5sum is: [#!variable!md5sum!#]. Storing details in the database.</key>
<key name="message_0195">Copying the file over to: [#!variable!host!#]. Please be patient, this could take a bit for large files.</key>
<key name="message_0196">Registering the file to be downloaded to the Anvil!: [#!variable!anvil_name!#]. Anvil! members will sync this file shortly. Member machines that are not online will sync the file when they do return.</key>
<key name="message_0195">
Copying the file: [#!variable!source_file!#] over to: [#!variable!host!#:#!variable!target_directory!#] using: [#!variable!ip_address!# (#!variable!network!#)].
The file size is: [#!variable!size!#], and the link speed appears to be: [#!variable!link_speed!#], for an estimated copy time of about: [#!variable!eta_copy_time!#].
Please be patient, this could take a bit for large files.</key>
<key name="message_0196">Registering the file to be downloaded to host: [#!variable!host!#]. Hosts that are not online will sync the file when they do return.</key>
<key name="message_0197">Upload is complete!</key>
<key name="message_0198">Processing the pull of a file from Striker.</key>
<key name="message_0199">We're a DR host and there are: [#!variable!strikers!#] dashboards, so we will wait to pull the file until after the nodes are done. We're currently waiting on; Node 1? [#!variable!node1_waiting!#], Node 2? [#!variable!node2_waiting!#]. We'll check again at: [#!variable!wait_until!#].</key>
@ -2860,6 +2864,8 @@ Proceed? [y/N]</key>
<key name="message_0306">This is a test alert message sent at alert level: [#!variable!level!#].</key>
<key name="message_0307">Failed to send a test alert at level: [#!variable!level!#]. Is anyone listening at that level? Is the mail server configured?</key>
<key name="message_0308">The DRBD config file was not found. A protect job needs to be run from the Anvil! node hosting the server to be protected.</key>
<key name="message_0309">Waiting a bit to make sure the file: [#!variable!file!#] is done uploading...</key>
<key name="message_0310">Upload complete.</key>
<!-- Translate names (protocols, etc) -->
<key name="name_0001">Normal Password</key> <!-- none in mail-server -->
@ -3264,6 +3270,15 @@ If you are comfortable that the target has changed for a known reason, you can s
<key name="suffix_0055">Zbps</key> <!-- Short suffix for 'zettabits per second' (1,000,000,000,000,000,000,000 bits per second). -->
<key name="suffix_0056">Ybps</key> <!-- Short suffix for 'yotabits per second' (1,000,000,000,000,000,000,000,000 bits per second). -->
<key name="suffix_0057">Bytes</key>
<key name="suffix_0058">Bytes/sec</key>
<key name="suffix_0059">KiB/sec</key> <!-- Short suffix for 'kibibyte/sec' transfer rate. -->
<key name="suffix_0060">MiB/sec</key> <!-- Short suffix for 'mebibyte/sec' transfer rate. -->
<key name="suffix_0061">GiB/sec</key> <!-- Short suffix for 'gibibyte/sec' transfer rate. -->
<key name="suffix_0062">TiB/sec</key> <!-- Short suffix for 'tebibyte/sec' transfer rate. -->
<key name="suffix_0063">PiB/sec</key> <!-- Short suffix for 'pebibyte/sec' transfer rate. -->
<key name="suffix_0064">EiB/sec</key> <!-- Short suffix for 'exbibyte/sec' transfer rate. -->
<key name="suffix_0065">ZiB/sec</key> <!-- Short suffix for 'zebibyte/sec' transfer rate. -->
<key name="suffix_0066">YiB/sec</key> <!-- Short suffix for 'yobibyte/sec' transfer rate. -->
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>

@ -567,7 +567,7 @@ sub check_incoming
my $file_md5sum = $recorded_md5sum;
if ((not $file_uuid) or ($file_size != $recorded_size))
{
# It's possible the file is still uploading, so sleep for 2 seconds and see if the
# It's possible the file is still uploading, so sleep for a bit and see if the
# size is still changing.
my $last_size = $file_size;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {

@ -48,10 +48,11 @@ if (not $anvil->data->{switches}{'job-uuid'})
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'} }});
}
# If we still don't have a job-uuid, go into interactive mode.
# If we have a job-uuid, process it.
if ($anvil->data->{switches}{'job-uuid'})
{
# Load the job data.
$anvil->Database->get_anvils({debug => 3});
$anvil->Job->get_job_details({debug => 3});
$anvil->Job->clear({debug => 3});
@ -440,14 +441,25 @@ sub process_incoming_file
$anvil->nice_exit({exit_code => 1});
}
# Make sure the file actually done uploading.
$anvil->data->{sys}{progress} = 5;
$anvil->Job->update_progress({
progress => $anvil->data->{sys}{progress},
message => "message_0309,!!file!".$file."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0309", variables => { file => $file }});
$anvil->Storage->_wait_if_changing({
debug => 2,
file => $file,
});
# Move it over to files.
$anvil->data->{sys}{progress} = 10;
$anvil->data->{sys}{progress} = 5;
$anvil->Job->update_progress({
progress => $anvil->data->{sys}{progress},
message => "message_0192,!!file!".$file."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0192", variables => { file => $file }});
$anvil->Storage->move_file({
debug => 2,
overwrite => 1,
@ -455,7 +467,6 @@ sub process_incoming_file
target_file => $anvil->data->{path}{directories}{shared}{files}."/",
});
my $file_name = ($file =~ /\/.*\/(.*?)$/)[0];
my $target_file = $anvil->data->{path}{directories}{shared}{files}."/".$file_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
@ -561,76 +572,147 @@ sub process_incoming_file
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }});
# Now copy this to our peers.
foreach my $host_uuid (sort {$a cmp $b} keys %{$anvil->data->{database}})
# Now copy this to our peers. We're going to do this serially so that we don't overwhelm the system,
# Any hosts not currently online will have a job registered.
$anvil->Database->get_hosts;
my $host_uuid = $anvil->Get->host_uuid();
my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
my $target_directory = $anvil->data->{path}{directories}{shared}{files}."/";
foreach my $do_host_type ("striker", "node", "dr")
{
# Periodically, autovivication causes and empty key to appear.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_uuid => $host_uuid }});
next if ((not $host_uuid) or (not $anvil->Validate->uuid({uuid => $host_uuid})));
next if $host_uuid eq $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { do_host_type => $do_host_type }});
foreach my $target_host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}})
{
my $target_host_uuid = $anvil->data->{sys}{hosts}{by_name}{$target_host_name};
my $target_host_type = $anvil->data->{hosts}{host_uuid}{$target_host_uuid}{host_type};
my $target_short_host_name = $anvil->data->{hosts}{host_uuid}{$target_host_uuid}{short_host_name};
next if $target_host_uuid eq $host_uuid;
next if $target_host_type ne $do_host_type;
my $host = $anvil->data->{database}{$host_uuid}{host};
my $password = $anvil->data->{database}{$host_uuid}{password};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host => $host,
password => $anvil->Log->is_secure($password),
's1:target_host_name' => $target_host_name,
's2:target_host_uuid' => $target_host_uuid,
's3:target_host_type' => $target_host_type,
's4:target_short_host_name' => $target_short_host_name,
}});
my $matches = $anvil->Network->find_access({
debug => 2,
target => $target_short_host_name,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { matches => $matches }});
next if not $matches;
next if $matches =~ /\D/;
# Find a matching IP.
# We prefer to use least to most used networks, with the IFN being the last choice.
my $copied = 0;
foreach my $network ("mn", "bcn", "sn", "ifn")
{
next if $copied;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network => $network }});
foreach my $network_name (sort {$a cmp $b} keys %{$anvil->data->{network_access}})
{
next if $copied;
next if $network_name !~ /^$network/i;
my $local_interface = $anvil->data->{network_access}{$network_name}{local_interface};
my $local_speed = $anvil->data->{network_access}{$network_name}{local_speed};
my $local_ip_address = $anvil->data->{network_access}{$network_name}{local_ip_address};
my $local_subnet_mask = $anvil->data->{network_access}{$network_name}{local_subnet_mask};
my $target_interface = $anvil->data->{network_access}{$network_name}{target_interface};
my $target_speed = $anvil->data->{network_access}{$network_name}{target_speed};
my $target_ip_address = $anvil->data->{network_access}{$network_name}{target_ip_address};
my $target_subnet_mask = $anvil->data->{network_access}{$network_name}{target_subnet_mask};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:local_interface' => $local_interface,
's2:local_speed' => $local_speed,
's3:local_ip_address' => $local_ip_address,
's4:local_subnet_mask' => $local_subnet_mask,
's5:target_interface' => $target_interface,
's6:target_speed' => $target_speed,
's7:target_ip_address' => $target_ip_address,
's8:target_subnet_mask' => $target_subnet_mask,
}});
my $striker_name = $anvil->Get->host_name_from_uuid({host_uuid => $host_uuid});
my $say_host = $striker_name." (".$host.")";
my $access = $anvil->Remote->test_access({target => $target_ip_address});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { access => $access }});
if ($access)
{
### Rsync!
# Estimate how long this will take. First, get the speed in
# Mbps and turn it into bytes per second, then into bytes per
# second. We'll take 10% off, then calculate how many seconds
# the copy will take.
my $link_mbps = $target_speed > $local_speed ? $target_speed : $local_speed;
my $link_bps = $link_mbps * 1000000;
my $link_bytes_sec = int($link_bps / 8);
my $adjusted_byptes_sec = int($link_bytes_sec * 0.9);
my $copy_seconds = int($file_size / $adjusted_byptes_sec);
my $say_copy_time = $anvil->Convert->time({'time' => $copy_seconds, translate => 1});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:link_mbps' => $anvil->Convert->add_commas({number => $link_mbps})." ".$anvil->Words->string({string => "#!string!suffix_0050!#"}),
's2:link_bps' => $anvil->Convert->add_commas({number => $link_bps})." ".$anvil->Words->string({string => "#!string!suffix_0048!#"}),
's3:link_bytes_sec' => $anvil->Convert->add_commas({number => $link_bytes_sec})." ".$anvil->Words->string({string => "#!string!suffix_0060!#"}),
's4:adjusted_byptes_sec' => $anvil->Convert->add_commas({number => $adjusted_byptes_sec})." ".$anvil->Words->string({string => "#!string!suffix_0060!#"}),
's5:copy_seconds' => $anvil->Convert->add_commas({number => $copy_seconds})." ".$anvil->Words->string({string => "#!string!suffix_0007!#"}),
's6:say_copy_time' => $say_copy_time,
}});
# Rsync the file.
$anvil->data->{sys}{progress} += 10;
my $variables = {
host => $target_short_host_name,
network => $network_name,
ip_address => $target_ip_address,
source_file => $file,
target_directory => $target_directory,
size => $anvil->Convert->bytes_to_human_readable({"bytes" => $file_size}),
link_speed => $anvil->Convert->add_commas({number => $link_mbps})." ".$anvil->Words->string({string => "#!string!suffix_0050!#"}),
eta_copy_time => $say_copy_time,
};
$anvil->data->{sys}{progress} += 2;
$anvil->data->{sys}{progress} = 90 if $anvil->data->{sys}{progress} > 90;
$anvil->Job->update_progress({
progress => $anvil->data->{sys}{progress},
message => "message_0195,!!host!".$say_host."!!",
message => "message_0195",
variables => $variables,
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0195", variables => { host => $say_host }});
$anvil->Storage->rsync({
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0195", variables => $variables});
my $problem = $anvil->Storage->rsync({
debug => 2,
source => $target_file,
destination => "root\@".$host.":".$anvil->data->{path}{directories}{shared}{files}."/",
source => $file,
destination => "root\@".$target_ip_address.":".$target_directory,
try_again => 1,
});
}
# Tell other Anvil! systems to download this file.
$anvil->Database->get_anvils({debug => 2});
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if (not $problem)
{
my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
my $anvil_node1_host_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node1_host_uuid};
my $anvil_node2_host_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_node2_host_uuid};
my $anvil_dr1_host_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_dr1_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_uuid => $anvil_uuid,
anvil_node1_host_uuid => $anvil_node1_host_uuid,
anvil_node2_host_uuid => $anvil_node2_host_uuid,
anvil_dr1_host_uuid => $anvil_dr1_host_uuid,
}});
$copied = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { copied => $copied }});
$anvil->data->{sys}{progress} += 5;
$anvil->data->{sys}{progress} = 90 if $anvil->data->{sys}{progress} > 90;
$anvil->Job->update_progress({
progress => $anvil->data->{sys}{progress},
message => "message_0196,!!anvil_name!".$anvil_name."!!",
message => "message_0310",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0196", variables => { anvil_name => $anvil_name }});
my $file_location_uuid = $anvil->Database->insert_or_update_file_locations({
debug => 2,
file_location_file_uuid => $file_uuid,
file_location_anvil_uuid => $anvil_uuid,
file_location_active => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_uuid => $file_location_uuid }});
# Register a job to call anvil-sync-shared
foreach my $host_uuid ($anvil_node1_host_uuid, $anvil_node2_host_uuid, $anvil_dr1_host_uuid)
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0310"});
}
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { copied => $copied }});
if (not $copied)
{
next if not $host_uuid;
# Failed to connect, register a job instead.
my $variables = { host => $target_host_name };
$anvil->data->{sys}{progress} += 5;
$anvil->data->{sys}{progress} = 90 if $anvil->data->{sys}{progress} > 90;
$anvil->Job->update_progress({
progress => $anvil->data->{sys}{progress},
message => "message_0196",
variables => $variables,
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0196", variables => $variables});
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
@ -640,10 +722,20 @@ sub process_incoming_file
job_title => "job_0132",
job_description => "job_0133",
job_progress => 0,
job_host_uuid => $host_uuid,
job_host_uuid => $target_host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
}
# Mark the file as being on this host
my $file_location_uuid = $anvil->Database->insert_or_update_file_locations({
debug => 2,
file_location_file_uuid => $file_uuid,
file_location_host_uuid => $host_uuid,
file_location_active => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_uuid => $file_location_uuid }});
}
}
# Done!

@ -63,6 +63,10 @@ sub striker_checks
{
my ($anvil) = @_;
# This replaces anvil_uuid with host_uuid to support more granular location info to support the new
# multi-target DR system
update_file_locations($anvil);
# This converts the old/broken 'notifications' tables with the more appropriately named 'alert-override'
update_notifications($anvil);
@ -365,6 +369,133 @@ CREATE TRIGGER trigger_storage_group_members
return(0);
}
# This replaces anvil_uuid with host_uuid to support more granular location info to support the new
# multi-target DR system
sub update_file_locations
{
my ($anvil) = @_;
my $updated = 0;
foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
{
my $query = "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'file_locations' AND column_name = 'file_location_anvil_uuid';";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
uuid => $uuid,
count => $count,
}});
# Wipe it out, then re-add
if ($count)
{
$updated = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { updated => $updated }});
my $queries = [];
push @{$queries}, "DROP TABLE public.file_locations;";
push @{$queries}, "DROP TABLE history.file_locations;";
push @{$queries}, "DROP FUNCTION history_file_locations() CASCADE;";
push @{$queries}, q|CREATE TABLE file_locations (
file_location_uuid uuid not null primary key,
file_location_file_uuid uuid not null, -- This is file to be moved to (or restored to) this machine.
file_location_host_uuid uuid not null, -- This is the sum as calculated when the file_location is first uploaded. Once recorded, it can't change.
file_location_active boolean not null default TRUE, -- This is set to true when the file should be on Anvil! machines, triggering rsyncs when needed. When set to false, the file will be deleted from members, if they exist.
modified_date timestamp with time zone not null,
FOREIGN KEY(file_location_file_uuid) REFERENCES files(file_uuid),
FOREIGN KEY(file_location_host_uuid) REFERENCES hosts(host_uuid)
);
ALTER TABLE file_locations OWNER TO admin;
CREATE TABLE history.file_locations (
history_id bigserial,
file_location_uuid uuid,
file_location_file_uuid text,
file_location_host_uuid uuid,
file_location_active boolean,
modified_date timestamp with time zone not null
);
ALTER TABLE history.file_locations OWNER TO admin;
CREATE FUNCTION history_file_locations() RETURNS trigger
AS $$
DECLARE
history_file_locations RECORD;
BEGIN
SELECT INTO history_file_locations * FROM file_locations WHERE file_location_uuid = new.file_location_uuid;
INSERT INTO history.file_locations
(file_location_uuid,
file_location_file_uuid,
file_location_host_uuid,
file_location_active,
modified_date)
VALUES
(history_file_locations.file_location_uuid,
history_file_locations.file_location_file_uuid,
history_file_locations.file_location_host_uuid,
history_file_locations.file_location_active,
history_file_locations.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_file_locations() OWNER TO admin;
CREATE TRIGGER trigger_file_locations
AFTER INSERT OR UPDATE ON file_locations
FOR EACH ROW EXECUTE PROCEDURE history_file_locations();
|;
foreach my $query (@{$queries})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0124", variables => { query => $query }});
}
$anvil->Database->write({debug => 2, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
}
}
# Make sure all files are linked to all nodes and dr_hosts
if ($updated)
{
$anvil->Database->get_hosts();
$anvil->Database->get_files();
$anvil->Database->get_file_locations();
foreach my $file_name (sort {$a cmp $b} keys %{$anvil->data->{files}{file_name}})
{
my $file_uuid = $anvil->data->{files}{file_name}{$file_name}{file_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:file_name' => $file_name,
's2:file_uuid' => $file_uuid,
}});
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{sys}{hosts}{by_name}})
{
my $host_uuid = $anvil->data->{sys}{hosts}{by_name}{$host_name};
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
my $host_key = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:host_name' => $host_name,
's2:host_uuid' => $host_uuid,
's3:host_type' => $host_type,
's4:host_key' => $host_key,
}});
next if $host_type eq "striker";
next if $host_key eq "DELETED";
my $file_location_uuid = $anvil->Database->insert_or_update_file_locations({
debug => 2,
file_location_file_uuid => $file_uuid,
file_location_host_uuid => $host_uuid,
file_location_active => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_location_uuid => $file_location_uuid }});
}
}
}
return(0);
}
# This converts the old/broken 'notifications' tables with the more appropriately named 'alert-override'
sub update_notifications
{
@ -373,9 +504,9 @@ sub update_notifications
foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{cache}{database_handle}})
{
my $query = "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_catalog = 'anvil' AND table_name = 'notifications';";
$anvil->Log->variables({source => $THIS_FILE, uuid => $uuid, line => __LINE__, level => 2, list => { query => $query }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
my $count = $anvil->Database->query({query => $query, uuid => $uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
if ($count)

@ -281,18 +281,9 @@ WHERE
}
}
# If deleting an Anvil!, we need to clear any Anvil! references from file_locations and storage groups.
# If deleting an Anvil!, we need to clear any Anvil! references from storage groups.
if (($table eq "anvils") && ($anvil->data->{purge}{anvil_uuid}))
{
#
my $query = "DELETE FROM history.file_locations WHERE file_location_anvil_uuid = ".$anvil->Database->quote($anvil->data->{purge}{anvil_uuid}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
$query = "DELETE FROM file_locations WHERE file_location_anvil_uuid = ".$anvil->Database->quote($anvil->data->{purge}{anvil_uuid}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
push @{$queries}, $query;
# Storage groups
$query = "
SELECT

Loading…
Cancel
Save