Merge pull request #308 from ClusterLabs/anvil-tools-dev

Anvil tools dev
main
Digimer 2 years ago committed by GitHub
commit 656c4daafe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 175
      Anvil/Tools/Cluster.pm
  2. 254
      Anvil/Tools/DRBD.pm
  3. 502
      Anvil/Tools/Database.pm
  4. 61
      Anvil/Tools/Get.pm
  5. 269
      Anvil/Tools/Network.pm
  6. 16
      Anvil/Tools/ScanCore.pm
  7. 24
      Anvil/Tools/Server.pm
  8. 270
      Anvil/Tools/Storage.pm
  9. 1
      man/Makefile.am
  10. 0
      man/anvil-manage-server-storage.8
  11. 5
      notes
  12. 10
      scancore-agents/scan-drbd/scan-drbd
  13. 28
      share/anvil.sql
  14. 22
      share/words.xml
  15. 2
      tools/Makefile.am
  16. 49
      tools/anvil-configure-host
  17. 2
      tools/anvil-daemon
  18. 14
      tools/anvil-manage-dr
  19. 63
      tools/anvil-manage-files
  20. 31
      tools/anvil-manage-host
  21. 398
      tools/anvil-manage-server-storage
  22. 111
      tools/anvil-sync-shared
  23. 135
      tools/anvil-version-changes
  24. 11
      tools/striker-purge-target

@ -299,8 +299,7 @@ sub assemble_storage_groups
SELECT
anvil_name,
anvil_node1_host_uuid,
anvil_node2_host_uuid,
anvil_dr1_host_uuid
anvil_node2_host_uuid
FROM
anvils
WHERE
@ -321,15 +320,13 @@ WHERE
}
# Get the details.
my $anvil_name = $results->[0]->[0];
my $node1_host_uuid = $results->[0]->[1];
my $node2_host_uuid = $results->[0]->[2];
my $dr1_host_uuid = defined $results->[0]->[3] ? $results->[0]->[3] : "";
my $anvil_name = $results->[0]->[0];
my $node1_host_uuid = $results->[0]->[1];
my $node2_host_uuid = $results->[0]->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_name => $anvil_name,
node1_host_uuid => $node1_host_uuid,
node2_host_uuid => $node2_host_uuid,
dr1_host_uuid => $dr1_host_uuid,
}});
# Load known storage groups.
@ -337,20 +334,9 @@ WHERE
# Look for ungrouped VGs and see if we can group them by matching identical sizes together.
my $hosts = [$node1_host_uuid, $node2_host_uuid];
if ($dr1_host_uuid)
{
push @{$hosts}, $dr1_host_uuid;
}
else
{
# No DR.
$anvil->data->{ungrouped_vg_count}{dr1} = 0;
}
foreach my $host_uuid (@{$hosts})
{
my $this_is = "node1";
if ($host_uuid eq $node2_host_uuid) { $this_is = "node2"; }
elsif ($host_uuid eq $dr1_host_uuid) { $this_is = "dr1"; }
my $this_is = $host_uuid eq $node2_host_uuid ? "node2" : "node1";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_is => $this_is }});
$anvil->data->{ungrouped_vg_count}{$this_is} = 0;
@ -432,13 +418,13 @@ ORDER BY
my $reload_storage_groups = 0;
foreach my $scan_lvm_vg_size (sort {$a cmp $b} keys %{$anvil->data->{ungrouped_vgs}})
{
# If there are two or three VGs, we can create a group.
# If there are two VGs, we can create a group.
my $count = keys %{$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
scan_lvm_vg_size => $scan_lvm_vg_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}).")",
count => $count,
}});
if (($count == 2) or ($count == 3))
if ($count == 2)
{
# Create the volume group ... group. First we need a group number
my $storage_group_uuid = $anvil->Database->insert_or_update_storage_groups({
@ -447,11 +433,10 @@ ORDER BY
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_uuid => $storage_group_uuid }});
# Now add the VGs as members.
foreach my $host_uuid (keys %{$anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}})
{
my $this_is = "node1";
if ($host_uuid eq $node2_host_uuid) { $this_is = "node2"; }
elsif ($host_uuid eq $dr1_host_uuid) { $this_is = "dr1"; }
my $this_is = $host_uuid eq $node2_host_uuid ? "node2" : "node1";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_is => $this_is }});
my $storage_group_member_vg_uuid = $anvil->data->{ungrouped_vgs}{$scan_lvm_vg_size}{host_uuid}{$host_uuid}{vg_internal_uuid};
@ -482,27 +467,21 @@ ORDER BY
}
# If there's only one VG on each node that is ungrouped, group them even though they're not the same
# size. If DR also has only 1 VG ungrouped, it'll be added, too.
# size.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"ungrouped_vg_count::node1" => $anvil->data->{ungrouped_vg_count}{node1},
"ungrouped_vg_count::node2" => $anvil->data->{ungrouped_vg_count}{node2},
"ungrouped_vg_count::dr1" => $anvil->data->{ungrouped_vg_count}{dr1},
}});
if (($anvil->data->{ungrouped_vg_count}{node1} == 1) && ($anvil->data->{ungrouped_vg_count}{node2} == 1))
{
# We do!
my $storage_group_uuid = $anvil->Database->create_storage_group({
debug => $debug,
my $storage_group_uuid = $anvil->Database->insert_or_update_storage_groups({
debug => 2,
storage_group_anvil_uuid => $anvil_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_uuid => $storage_group_uuid }});
my $hosts = [$node1_host_uuid, $node2_host_uuid];
if ($anvil->data->{ungrouped_vg_count}{dr1} == 1)
{
push @{$hosts}, $dr1_host_uuid;
}
foreach my $host_uuid (@{$hosts})
foreach my $host_uuid ($node1_host_uuid, $node2_host_uuid)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
@ -539,13 +518,131 @@ ORDER BY
if ($reload_storage_groups)
{
$anvil->Database->get_storage_group_data({debug => $debug});
my $storage_group_uuid = $anvil->Database->insert_or_update_storage_groups({
debug => 2,
storage_group_anvil_uuid => $anvil_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_uuid => $storage_group_uuid }});
}
# Now loop through any attached DRs and add the VGs that are closest in sizes to the VGs we have in
# this Anvil! node.
$anvil->Database->get_dr_links({debug => 2});
# This was going to automatically add VGs from DR hosts to an Anvil's Storage Group, but given now
# that things can be linked in random ways, this doesn't seem to make sense anymore. So the code is
# (not complete but) preserved here in case we change out mind later.
=cut
foreach my $dr_link_host_name (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}})
{
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_name}{$dr_link_host_name}{dr_link_uuid};
my $dr_link_host_uuid = $anvil->Database->get_host_uuid_from_string({debug => $debug, string => $dr_link_host_name});
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_name' => $dr_link_host_name,
's2:dr_link_host_uuid' => $dr_link_host_uuid,
's3:dr_link_short_host_name' => $dr_link_short_host_name,
's4:dr_link_uuid' => $dr_link_uuid,
}});
# What VGs do these DR hosts have, and are they in any storage groups yet?
my $query = "
SELECT
scan_lvm_vg_uuid,
scan_lvm_vg_name,
scan_lvm_vg_size,
scan_lvm_vg_internal_uuid
FROM
scan_lvm_vgs
WHERE
scan_lvm_vg_host_uuid = ".$anvil->Database->quote($dr_link_uuid)."
AND
scan_lvm_vg_name != 'DELETED'
ORDER BY
scan_lvm_vg_size ASC
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $scan_lvm_vg_uuid = $row->[0];
my $scan_lvm_vg_name = $row->[1];
my $scan_lvm_vg_size = $row->[2];
my $scan_lvm_vg_internal_uuid = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:scan_lvm_vg_uuid' => $scan_lvm_vg_uuid,
's2:scan_lvm_vg_name' => $scan_lvm_vg_name,
's3:scan_lvm_vg_size' => $scan_lvm_vg_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size}).")",
's4:scan_lvm_vg_internal_uuid' => $scan_lvm_vg_internal_uuid,
}});
# Is this VG already in a storage group for this anvil! node?
my $vg_found = 0;
foreach my $storage_group_uuid (keys %{$anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}})
{
my $storage_group_name = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{group_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:storage_group_uuid' => $storage_group_uuid,
's2:storage_group_name' => $storage_group_name,
}});
foreach my $this_host_uuid (sort {$a cmp $b} keys %{$anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{short_host_name}})
{
next if $this_host_uuid eq $dr_link_host_uuid;
my $storage_group_member_note = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$$this_host_uuid}{storage_group_member_note};
my $storage_group_member_vg_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$this_host_uuid}{vg_internal_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:this_host_uuid' => $this_host_uuid,
's2:storage_group_member_vg_uuid' => $storage_group_member_vg_uuid,
's3:storage_group_member_note' => $storage_group_member_note,
}});
next if $storage_group_member_note eq "DELETED";
if ($storage_group_member_vg_uuid eq $scan_lvm_vg_internal_uuid)
{
$vg_found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { vg_found => $vg_found }});
}
}
}
if (not $vg_found)
{
# Find the smallest
my $query = "
SELECT
scan_lvm_vg_uuid,
scan_lvm_vg_name,
scan_lvm_vg_size,
scan_lvm_vg_internal_uuid
FROM
scan_lvm_vgs
WHERE
scan_lvm_vg_host_uuid = ".$anvil->Database->quote($dr_link_uuid)."
AND
scan_lvm_vg_name != 'DELETED'
ORDER BY
scan_lvm_vg_size ASC
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $scan_lvm_vg_uuid = $row->[0];
my $scan_lvm_vg_name = $row->[1];
my $scan_lvm_vg_size = $row->[2];
my $scan_lvm_vg_internal_uuid = $row->[3];
}
}
}
}
=cut
return(0);
}

@ -24,6 +24,7 @@ my $THIS_FILE = "DRBD.pm";
# get_next_resource
# get_status
# manage_resource
# parse_resource
# reload_defaults
# remove_backing_lv
# resource_uuid
@ -1492,7 +1493,7 @@ LIMIT 1
my $value = $option_ref->{value};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
variable => $variable,
value => $variable,
value => $value,
}});
if ($variable eq "auto-promote")
{
@ -1581,10 +1582,14 @@ LIMIT 1
if (($anvil->data->{drbd}{config}{$host}{host}) && ($anvil->data->{drbd}{config}{$host}{host} eq $this_host))
{
$anvil->data->{drbd}{config}{$host}{by_res}{$by_res}{on} = $lv_path;
$anvil->data->{drbd}{config}{$host}{by_res}{$by_res}{resource} = $this_resource;
$anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{on} = $lv_path;
$anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{resource} = $this_resource;
$anvil->data->{drbd}{config}{$host}{lv_path}{$lv_path}{under} = $drbd_path;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"drbd::config::${host}::by_res::${by_res}::on" => $anvil->data->{drbd}{config}{$host}{by_res}{$by_res}{on},
"drbd::config::${host}::by_res::${by_res}::resource" => $anvil->data->{drbd}{config}{$host}{by_res}{$by_res}{resource},
"drbd::config::${host}::drbd_path::${drbd_path}::on" => $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{on},
"drbd::config::${host}::drbd_path::${drbd_path}::resource" => $anvil->data->{drbd}{config}{$host}{drbd_path}{$drbd_path}{resource},
"drbd::config::${host}::lv_path::${lv_path}::under" => $anvil->data->{drbd}{config}{$host}{lv_path}{$lv_path}{under},
@ -2357,6 +2362,253 @@ sub manage_resource
return($return_code);
}
=head2 parse_resource
This takes the XML from a specific DRBD resource and parses it.
Parameters;
=head3 xml (required)
This is the XML to parse, generally as stored in the C<< scan_drbd_resources >> -> C<< scan_drbd_resource_xml >>.
=cut
sub parse_resource
{
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 => "DRBD->parse_resource()" }});
my $xml = defined $parameter->{xml} ? $parameter->{xml} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
xml => $xml,
}});
if (not $xml)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "DRBD->parse_resource()", parameter => "xml" }});
return("!!error!!");
}
local $@;
my $dom = eval { XML::LibXML->load_xml(string => $xml); };
if ($@)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "error_0253", variables => {
xml => $xml,
error => $@,
}});
return(1);
}
else
{
# Successful parse!
=cut
<resource name="srv01-fs37" conf-file-line="/etc/drbd.d/srv01-fs37.res:2">
<host name="vm-a01n01">
<volume vnr="0">
<device minor="0">/dev/drbd_srv01-fs37_0</device>
<disk>/dev/cs_vm-a01n01/srv01-fs37_0</disk>
<meta-disk>internal</meta-disk>
</volume>
<volume vnr="1">
<device minor="1">/dev/drbd_srv01-fs37_1</device>
<disk>/dev/cs_vm-a01n01/srv01-fs37_1</disk>
<meta-disk>internal</meta-disk>
</volume>
<address family="(null)" port="(null)">(null)</address>
</host>
<host name="vm-a01n02">
<volume vnr="0">
<device minor="0">/dev/drbd_srv01-fs37_0</device>
<disk>/dev/cs_vm-a01n02/srv01-fs37_0</disk>
<meta-disk>internal</meta-disk>
</volume>
<volume vnr="1">
<device minor="1">/dev/drbd_srv01-fs37_1</device>
<disk>/dev/cs_vm-a01n02/srv01-fs37_1</disk>
<meta-disk>internal</meta-disk>
</volume>
<address family="(null)" port="(null)">(null)</address>
</host>
<host name="vm-a01dr01">
<volume vnr="0">
<device minor="0">/dev/drbd_srv01-fs37_0</device>
<disk>/dev/cs_vm-a01dr01/srv01-fs37_0</disk>
<meta-disk>internal</meta-disk>
</volume>
<volume vnr="1">
<device minor="1">/dev/drbd_srv01-fs37_1</device>
<disk>/dev/cs_vm-a01dr01/srv01-fs37_1</disk>
<meta-disk>internal</meta-disk>
</volume>
<address family="(null)" port="(null)">(null)</address>
</host>
<connection>
<host name="vm-a01n01"><address family="ipv4" port="7788">10.101.10.1</address></host>
<host name="vm-a01n02"><address family="ipv4" port="7788">10.101.10.2</address></host>
<section name="net">
<option name="protocol" value="C"/>
<option name="verify-alg" value="md5"/>
<option name="fencing" value="resource-and-stonith"/>
</section>
<section name="disk">
<option name="c-max-rate" value="500M"/>
</section>
</connection>
<connection>
<host name="vm-a01n01"><address family="ipv4" port="7789">10.201.10.1</address></host>
<host name="vm-a01dr01"><address family="ipv4" port="7789">10.201.10.3</address></host>
<section name="net">
<option name="protocol" value="A"/>
<option name="verify-alg" value="md5"/>
<option name="fencing" value="dont-care"/>
</section>
<section name="disk">
<option name="c-max-rate" value="500M"/>
</section>
</connection>
<connection>
<host name="vm-a01n02"><address family="ipv4" port="7790">10.201.10.2</address></host>
<host name="vm-a01dr01"><address family="ipv4" port="7790">10.201.10.3</address></host>
<section name="net">
<option name="protocol" value="A"/>
<option name="verify-alg" value="md5"/>
<option name="fencing" value="dont-care"/>
</section>
<section name="disk">
<option name="c-max-rate" value="500M"/>
</section>
</connection>
</resource>
=cut
foreach my $name ($dom->findnodes('/resource'))
{
my $resource = $name->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { resource => $resource }});
foreach my $host ($name->findnodes('./host'))
{
my $this_host_name = $host->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_host_name => $this_host_name }});
# Record the details under the hosts
foreach my $volume_vnr ($host->findnodes('./volume'))
{
my $volume = $volume_vnr->{vnr};
my $meta_disk = $volume_vnr->findvalue('./meta-disk');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:volume' => $volume,
's2:meta_disk' => $meta_disk,
}});
my $host_uuid = $anvil->Get->host_uuid_from_name({host_name => $this_host_name});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
$anvil->data->{new}{resource}{$resource}{host_name}{$this_host_name}{host_uuid} = $host_uuid;
$anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{device_path} = $volume_vnr->findvalue('./device');
$anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{backing_disk} = $volume_vnr->findvalue('./disk');
$anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{device_minor} = $volume_vnr->findvalue('./device/@minor');
$anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{meta_disk} = $meta_disk;
$anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{size} = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:new::resource::${resource}::host_name::${this_host_name}::host_uuid" => $anvil->data->{new}{resource}{$resource}{host_name}{$this_host_name}{host_uuid},
"s2:new::resource::${resource}::host_uuid::${host_uuid}::volume_number::${volume}::device_path" => $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{device_path},
"s3:new::resource::${resource}::host_uuid::${host_uuid}::volume_number::${volume}::backing_disk" => $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{backing_disk},
"s4:new::resource::${resource}::host_uuid::${host_uuid}::volume_number::${volume}::device_minor" => $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{device_minor},
"s5:new::resource::${resource}::host_uuid::${host_uuid}::volume_number::${volume}::meta_disk" => $anvil->data->{new}{resource}{$resource}{host_uuid}{$host_uuid}{volume_number}{$volume}{meta_disk},
}});
}
}
foreach my $connection ($name->findnodes('./connection'))
{
my $host1_name = "";
my $host1_ip_address = "";
my $host1_tcp_port = "";
my $host2_name = "";
my $host2_ip_address = "";
my $host2_tcp_port = "";
my $peer = "";
foreach my $host ($connection->findnodes('./host'))
{
my $this_host_name = $host->{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_host_name => $this_host_name }});
if (not $host1_name)
{
$host1_name = $this_host_name;
$host1_ip_address = $host->findvalue('./address');
$host1_tcp_port = $host->findvalue('./address/@port');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host1_name => $host1_name,
host1_ip_address => $host1_ip_address,
host1_tcp_port => $host1_tcp_port,
}});
}
else
{
$host2_name = $this_host_name;
$host2_ip_address = $host->findvalue('./address');
$host2_tcp_port = $host->findvalue('./address/@port');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host2_name => $host2_name,
host2_ip_address => $host2_ip_address,
host2_tcp_port => $host2_tcp_port,
}});
$anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host1_ip_address} = $host1_ip_address;
$anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host1_tcp_port} = $host1_tcp_port;
$anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_ip_address} = $host2_ip_address;
$anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_tcp_port} = $host2_tcp_port;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host1_ip_address" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host1_ip_address},
"s2:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host1_tcp_port" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host1_tcp_port},
"s3:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_ip_address" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_ip_address},
"s4:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_tcp_port" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_tcp_port},
}});
foreach my $proxy ($host->findnodes('./proxy'))
{
my $host_name = $proxy->{hostname};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_name => $host_name }});
# This should always be the target, but lets be safe/careful
next if $host_name ne $host2_name;
$anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_ip_address} = $proxy->findvalue('./inside');
$anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_tcp_port} = $proxy->findvalue('./inside/@port');
$anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_ip_address} = $proxy->findvalue('./outside');
$anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_tcp_port} = $proxy->findvalue('./outside/@port');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"s1:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_inside_ip_address" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_ip_address},
"s2:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_inside_tcp_port" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_inside_tcp_port},
"s3:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_outside_ip_address" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_ip_address},
"s4:new::resource::${resource}::host1_to_host2::${host1_name}::${host2_name}::host2_outside_tcp_port" => $anvil->data->{new}{resource}{$resource}{host1_to_host2}{$host1_name}{$host2_name}{host2_outside_tcp_port},
}});
$anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{inside}{ip_address} = $proxy->findvalue('./inside');
$anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{inside}{tcp_port} = $proxy->findvalue('./inside/@port');
$anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{outside}{ip_address} = $proxy->findvalue('./outside');
$anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{outside}{tcp_port} = $proxy->findvalue('./outside/@port');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"new::resource::${resource}::proxy::${host_name}::inside::ip_address" => $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{inside}{ip_address},
"new::resource::${resource}::proxy::${host_name}::inside::tcp_port" => $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{inside}{tcp_port},
"new::resource::${resource}::proxy::${host_name}::outside::ip_address" => $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{outside}{ip_address},
"new::resource::${resource}::proxy::${host_name}::outside::tcp_port" => $anvil->data->{new}{resource}{$resource}{proxy}{$host_name}{outside}{tcp_port},
}});
}
}
}
}
}
}
return(0);
}
=head2 reload_defaults
This switches DRBD back to running using the values in the config files. Specifically, it calls C<< drbdadm adjust all >>.

@ -97,6 +97,7 @@ my $THIS_FILE = "Database.pm";
# refresh_timestamp
# resync_databases
# shutdown
# track_files
# update_host_status
# write
# _add_to_local_config
@ -386,7 +387,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,32 +401,32 @@ 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_files({debug => $debug});
$anvil->Database->get_file_locations({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,
file_name => $file_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_active => 1,
debug => $debug,
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 => $debug, list => { file_location_uuid => $file_location_uuid }});
}
@ -2710,7 +2711,6 @@ SELECT
anvil_password,
anvil_node1_host_uuid,
anvil_node2_host_uuid,
anvil_dr1_host_uuid,
modified_date
FROM
anvils ";
@ -2737,8 +2737,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 +2745,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 +2754,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 +2761,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 +2771,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 +2779,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,60 +2805,6 @@ 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)
{
$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";
$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},
}});
}
# 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_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},
}});
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};
next if not exists $anvil->data->{files}{file_uuid}{$file_uuid};
my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file_uuid => $file_uuid,
file_name => $file_name,
}});
# If the file was deleted, this won't exist
next if not exists $anvil->data->{files}{file_uuid}{$file_uuid};
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_name} = $file_name;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_directory} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_directory};
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_size};
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_md5sum} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_md5sum};
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_name" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_name},
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_directory" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_directory},
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_size" => $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}})." (".$anvil->Convert->add_commas({number => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}}).")",
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_md5sum" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_md5sum},
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_type" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type},
}});
# Make it so that we can list the files by name.
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid} = $file_uuid;
$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})
@ -3238,7 +3178,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 +3204,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
@ -3279,35 +3219,47 @@ FROM
}});
foreach my $row (@{$results})
{
my $file_location_uuid = $row->[0];
my $file_location_file_uuid = $row->[1];
my $file_location_anvil_uuid = $row->[2];
my $file_location_active = $row->[3];
my $modified_date = $row->[4];
my $file_location_uuid = $row->[0];
my $file_location_file_uuid = $row->[1];
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_active => $file_location_active,
modified_date => $modified_date,
file_location_uuid => $file_location_uuid,
file_location_file_uuid => $file_location_file_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_active} = $file_location_active;
$anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{modified_date} = $modified_date;
$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_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_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},
"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_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},
}});
### TODO: Remove this when the WebUI is updated.
# If this host is a node in an Anvil!, set the old 'file_location_anvil_uuid' to maintain
# backwards compatibility.
if ((exists $anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}) &&
($anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}{anvil_uuid}))
{
$anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_anvil_uuid} = $anvil->data->{hosts}{host_uuid}{$file_location_host_uuid}{anvil_uuid};
$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},
}});
}
# 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},
}});
}
@ -5297,6 +5249,12 @@ sub get_storage_group_data
$scan_lvm_exists = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { scan_lvm_exists => $scan_lvm_exists }});
}
# Loads hosts, if it hasn't been before.
if (not exists $anvil->data->{hosts}{host_uuid})
{
$anvil->Database->get_hosts({debug => $debug});
}
$query = "
SELECT
@ -7918,7 +7876,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.
@ -7928,13 +7886,19 @@ Parameters;
If not passed, a check will be made to see if an existing entry is found for C<< file_location_file_uuid >>. If found, that entry will be updated. If not found, a new record will be inserted.
=head3 file_location_anvil_uuid (required)
This is the C<< anvils >> -> C<< anvil_uuid >> being referenced. This works by figuring out which hosts are a member of the Anvil! node, and which DR hosts are linked, and makes a recursive call to this method for each of their C<< hosts >> -> C<< host_uuid >>.
B<< Note >>: When this is used, a comma-separated list of C<< host_uuid=file_location_uuid >> is returned.
=head3 file_location_file_uuid (required)
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)
@ -7955,16 +7919,18 @@ sub insert_or_update_file_locations
my $file = defined $parameter->{file} ? $parameter->{file} : "";
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_file_uuid = defined $parameter->{file_location_file_uuid} ? $parameter->{file_location_file_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,
file => $file,
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_file_uuid => $file_location_file_uuid,
file_location_host_uuid => $file_location_host_uuid,
file_location_active => $file_location_active,
}});
@ -7974,10 +7940,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"))
@ -7987,6 +7953,59 @@ sub insert_or_update_file_locations
return("");
}
# If we've got an Anvil! uuid, find out the hosts and DR links connected to the Anvil! are found and
# this method is recursively called for each host.
if ($file_location_anvil_uuid)
{
$anvil->Database->get_anvils({debug => $debug});
if (not exists $anvil->data->{anvils}{anvil_uuid}{$file_location_anvil_uuid})
{
# Bad Anvil! UUID.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0169", variables => { anvil_uuid => $file_location_anvil_uuid }});
return("");
}
my $hosts = ();
push @{$hosts}, $anvil->data->{anvils}{anvil_uuid}{$file_location_anvil_uuid}{anvil_node1_host_uuid};
push @{$hosts}, $anvil->data->{anvils}{anvil_uuid}{$file_location_anvil_uuid}{anvil_node2_host_uuid};
if (exists $anvil->data->{dr_links}{by_anvil_uuid}{$file_location_anvil_uuid})
{
foreach my $dr_link_host_uuid (sort {$a cmp $b} keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$file_location_anvil_uuid}{dr_link_host_uuid}})
{
my $dr_link_uuid = $anvil->data->{dr_links}{by_anvil_uuid}{$file_location_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";
push @{$hosts}, $dr_link_host_uuid;
}
}
my $file_location_uuids = "";
foreach my $host_uuid (@{$hosts})
{
my $file_location_uuid = $anvil->Database->insert_or_update_file_locations({
debug => $debug,
file_location_file_uuid => $file_location_file_uuid,
file_location_host_uuid => $host_uuid,
file_location_active => $file_location_active,
});
$file_location_uuids .= $host_uuid."=".$file_location_uuid.",";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file_location_uuid => $file_location_uuid,
file_location_uuids => $file_location_uuids,
}});
}
$file_location_uuids =~ s/,$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_location_uuids => $file_location_uuids }});
return($file_location_uuids);
}
# If we don't have a UUID, see if we can find one for the given md5sum.
if (not $file_location_uuid)
{
@ -7996,9 +8015,9 @@ SELECT
FROM
file_locations
WHERE
file_location_file_uuid = ".$anvil->Database->quote($file_location_file_uuid)."
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 }});
@ -8029,15 +8048,15 @@ 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)."
".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
@ -8049,8 +8068,8 @@ INSERT INTO
my $query = "
SELECT
file_location_file_uuid,
file_location_anvil_uuid,
file_location_active,
file_location_host_uuid,
file_location_active
FROM
file_locations
WHERE
@ -8072,31 +8091,31 @@ 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_active = $row->[2];
my $old_file_location_file_uuid = $row->[0];
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_active => $old_file_location_active,
old_file_location_file_uuid => $old_file_location_file_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_active ne $file_location_active))
if (($old_file_location_file_uuid ne $file_location_file_uuid) or
($old_file_location_host_uuid ne $file_location_host_uuid) or
($old_file_location_active ne $file_location_active))
{
# Something changed, save.
my $query = "
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_active = ".$anvil->Database->quote($file_location_active).",
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
file_location_file_uuid = ".$anvil->Database->quote($file_location_file_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
file_location_uuid = ".$anvil->Database->quote($file_location_uuid)."
file_location_uuid = ".$anvil->Database->quote($file_location_uuid)."
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
@ -13409,7 +13428,7 @@ AND
if (not $storage_group_member_uuid)
{
# INSERT
my $storage_group_member_uuid = $anvil->Get->uuid();
$storage_group_member_uuid = $anvil->Get->uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_uuid => $storage_group_member_uuid }});
my $query = "
@ -17501,6 +17520,237 @@ AND
}
=head2 track_file
This looks at all files in the database, and then for all Anvil! systems and linked DR hosts, ensures that there's a corresponding C<< file_locations >> entry.
This method takes no parameters.
=cut
sub track_files
{
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 => "Database->track_files()" }});
my $anvils = keys %{$anvil->data->{anvils}{anvil_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvils => $anvils }});
if (not $anvils)
{
$anvil->Database->get_anvils({debug => $debug});
}
my $files = keys %{$anvil->data->{files}{file_uuid}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { files => $files }});
if (not $files)
{
$anvil->Database->get_files({debug => $debug});
}
my $file_locations = keys %{$anvil->data->{file_locations}{file_location_uuid}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { file_locations => $file_locations }});
if (not $file_locations)
{
$anvil->Database->get_file_locations({debug => $debug});
}
my $dr_link_uuid = keys %{$anvil->data->{dr_links}{dr_link_uuid}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { dr_link_uuid => $dr_link_uuid }});
if (not $dr_link_uuid)
{
$anvil->Database->get_dr_links({debug => $debug});
}
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
{
my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
my $anvil_description = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_description};
my $anvil_node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
my $anvil_node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:anvil_name' => $anvil_name,
's2:anvil_uuid' => $anvil_uuid,
's3:anvil_description' => $anvil_description,
's4:anvil_node1_host_uuid' => $anvil_node1_host_uuid,
's5:anvil_node2_host_uuid' => $anvil_node2_host_uuid,
}});
# Loop through all files and see if there's a corresponding file_location for each sub-node.
my $reload = 0;
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 => $debug, list => {
's1:file_name' => $file_name,
's2:file_uuid' => $file_uuid,
}});
foreach my $host_uuid ($anvil_node1_host_uuid, $anvil_node2_host_uuid)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
if ((not exists $anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}) or
($anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}{file_location_uuid}))
{
# Add it
$reload = 1;
my ($file_location_uuid) = $anvil->Database->insert_or_update_file_locations({
debug => $debug,
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 => $debug, list => {
reload => $reload,
file_location_uuid => $file_location_uuid,
}});
}
}
}
if ($reload)
{
$anvil->Database->get_file_locations({debug => $debug});
}
# Track the files on this Anvil!
foreach my $file_location_uuid (keys %{$anvil->data->{file_locations}{file_location_uuid}})
{
my $file_uuid = $anvil->data->{file_locations}{file_location_uuid}{$file_location_uuid}{file_location_file_uuid};
my $file_type = $anvil->data->{files}{file_uuid}{$file_uuid}{file_type};
my $file_name = $anvil->data->{files}{file_uuid}{$file_uuid}{file_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file_location_uuid => $file_location_uuid,
file_uuid => $file_uuid,
file_type => $file_type,
file_name => $file_name,
}});
next if $file_type eq "DELETED";
### TODO - Left off here, not adding DR links.
my $anvil_needs_file = 0;
foreach my $host_uuid ($anvil_node1_host_uuid, $anvil_node2_host_uuid)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
if ((exists $anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}) &&
($anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}{file_location_uuid}))
{
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->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file_location_uuid => $file_location_uuid,
file_location_active => $file_location_active,
}});
if ($file_location_active)
{
$anvil_needs_file = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_needs_file => $anvil_needs_file }});
}
}
}
# If either node wanted the file, both nodes and all linked DRs need it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { anvil_needs_file => $anvil_needs_file }});
if ($anvil_needs_file)
{
# Update the hosts
foreach my $host_uuid ($anvil_node1_host_uuid, $anvil_node2_host_uuid)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
my ($file_location_uuid) = $anvil->Database->insert_or_update_file_locations({
debug => $debug,
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 => $debug, list => { file_location_uuid => $file_location_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 $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};
if (not $file_location_active)
{
my ($file_location_uuid) = $anvil->Database->insert_or_update_file_locations({
debug => $debug,
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 => $debug, list => { file_location_uuid => $file_location_uuid }});
}
}
# If the file was deleted, this won't exist
next if not exists $anvil->data->{files}{file_uuid}{$file_uuid};
# Record that this Anvil! node has this file.
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_name} = $file_name;
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_directory} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_directory};
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_size};
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_md5sum} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_md5sum};
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type} = $anvil->data->{files}{file_uuid}{$file_uuid}{file_type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_name" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_name},
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_directory" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_directory},
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_size" => $anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}})." (".$anvil->Convert->add_commas({number => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_size}}).")",
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_md5sum" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_md5sum},
"anvils::anvil_uuid::${anvil_uuid}::file_uuid::${file_uuid}::file_type" => $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_uuid}{$file_uuid}{file_type},
}});
# Make it so that we can list the files by name.
$anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{file_name}{$file_name}{file_uuid} = $file_uuid;
$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},
}});
# Make sure linked DR hosts have this file, also.
foreach my $host_uuid (keys %{$anvil->data->{dr_links}{by_anvil_uuid}{$anvil_uuid}{dr_link_host_uuid}})
{
my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_name => $host_name,
host_uuid => $host_uuid,
}});
my $file_location_uuid = "";
my $file_location_active = 0;
if (exists $anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid})
{
$file_location_uuid = $anvil->data->{file_locations}{host_uuid}{$host_uuid}{file_uuid}{$file_uuid}{file_location_uuid};
$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)
{
my ($file_location_uuid) = $anvil->Database->insert_or_update_file_locations({
debug => $debug,
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 => $debug, list => { file_location_uuid => $file_location_uuid }});
}
}
}
}
}
return(0);
}
=head2 update_host_status
This is a variant on C<< insert_or_update_hosts >> designed only to update the power status of a host.

@ -643,7 +643,7 @@ WHERE
# How many cores?
if ((not $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores}) or
($scan_hardware_cpu_cores < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores}))
($scan_hardware_cpu_cores < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores}))
{
$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores} = $scan_hardware_cpu_cores;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -651,15 +651,25 @@ WHERE
}});
}
if ((not $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}) or
($scan_hardware_cpu_threads < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}))
($scan_hardware_cpu_threads < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads}))
{
$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} = $scan_hardware_cpu_threads;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvil_resources::${anvil_uuid}::cpu::threads" => $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads},
}});
}
# If there are less threads than cores, set the cores to be equal to threads.
if ($anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} < $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores})
{
$anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads} = $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{cores};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"anvil_resources::${anvil_uuid}::cpu::threads" => $anvil->data->{anvil_resources}{$anvil_uuid}{cpu}{threads},
}});
}
if ((not $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{available}) or
($scan_hardware_ram_total < $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{hardware}))
($scan_hardware_ram_total < $anvil->data->{anvil_resources}{$anvil_uuid}{ram}{hardware}))
{
$anvil->data->{anvil_resources}{$anvil_uuid}{ram}{available} = $scan_hardware_ram_total;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -2114,9 +2124,9 @@ sub server_from_switch
server_string => $server_string,
}});
if ((not $server_string) && ($anvil->data->{switches}{'anvil'}))
if ((not $server_string) && ($anvil->data->{switches}{'server'}))
{
$server_string = $anvil->data->{switches}{'anvil'};
$server_string = $anvil->data->{switches}{'server'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_string => $server_string }});
}
if (not $server_string)
@ -2125,10 +2135,16 @@ sub server_from_switch
return("!!error!!", "");
}
$anvil->Database->get_anvils({debug => $debug});
$anvil->Database->get_servers({debug => $debug});
$anvil->data->{switches}{server_name} = "" if not exists $anvil->data->{switches}{server_name};
$anvil->data->{switches}{server_uuid} = "" if not exists $anvil->data->{switches}{server_uuid};
if (exists $anvil->data->{servers}{server_uuid}{$server_string}{server_name})
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server_string => $server_string,
"switches::server_name" => $anvil->data->{switches}{server_name},
"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
}});
if (exists $anvil->data->{servers}{server_uuid}{$server_string})
{
# Found it by UUID.
$anvil->data->{switches}{server_name} = $anvil->data->{anvils}{server_uuid}{$server_string}{server_name};
@ -2138,14 +2154,33 @@ sub server_from_switch
"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
}});
}
elsif (exists $anvil->data->{anvils}{server_uuid}{$server_string})
else
{
$anvil->data->{switches}{server_name} = $server_string;
$anvil->data->{switches}{server_uuid} = $anvil->data->{anvils}{server_uuid}{$server_string}{server_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"switches::server_name" => $anvil->data->{switches}{server_name},
"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
}});
# If we have an anvil_uuid, see if the server exists there.
foreach my $this_anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
{
my $this_anvil_uuid = $anvil->data->{anvils}{anvil_name}{$this_anvil_name}{anvil_uuid};
if (($anvil_uuid) && ($anvil_uuid ne $this_anvil_uuid))
{
next;
}
foreach my $this_server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$this_anvil_uuid}{server_name}})
{
my $this_server_uuid = $anvil->data->{servers}{anvil_uuid}{$this_anvil_uuid}{server_name}{$this_server_name}{server_uuid};
if (($server_string eq $this_server_name) or
($server_string eq $this_server_uuid))
{
# Found it
$anvil->data->{switches}{server_name} = $this_server_name;
$anvil->data->{switches}{server_uuid} = $this_server_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"switches::server_name" => $anvil->data->{switches}{server_name},
"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
}});
last;
}
}
}
}
return($anvil->data->{switches}{server_name}, $anvil->data->{switches}{server_uuid});

@ -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.
@ -2583,7 +2747,7 @@ AND
"network::${host}::interface::${bond_name}::down_delay" => $anvil->data->{network}{$host}{interface}{$bond_name}{down_delay},
"network::${host}::interface::${bond_name}::mac_address" => $anvil->data->{network}{$host}{interface}{$bond_name}{mac_address},
"network::${host}::interface::${bond_name}::operational" => $anvil->data->{network}{$host}{interface}{$bond_name}{operational},
"network::${host}::interface::${bond_name}::bridge_uuid" => $anvil->data->{network}{$host}{interface}{$bond_name}{bridge},
"network::${host}::interface::${bond_name}::bridge_uuid" => $anvil->data->{network}{$host}{interface}{$bond_name}{bridge_uuid},
"network::${host}::interface::${bond_name}::type" => $anvil->data->{network}{$host}{interface}{$bond_name}{type},
}});
}
@ -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)
@ -2832,9 +2996,56 @@ AND
ip_address_on_uuid => $ip_address_on_uuid,
}});
my $interface_name = "";
my $interface_mac = "";
my $bridge_name = "";
my $bond_name = "";
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_name, bond_active_interface FROM bonds WHERE bond_bridge_uuid = ".$anvil->Database->quote($ip_address_on_uuid).";";
# Get the bridge name, also.
if (1)
{
my $query = "SELECT bridge_name FROM bridges WHERE bridge_uuid = ".$anvil->Database->quote($ip_address_on_uuid).";";
$bridge_name = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { bridge_name => $bridge_name }});
}
}
else
{
$query = "SELECT bond_name, 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 $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
$bond_name = $results->[0]->[0];
my $active_interface = $results->[0]->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
interface_name => $interface_name,
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 +3063,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'
;";
@ -2872,22 +3083,34 @@ AND
interface_mac => $interface_mac,
}});
$anvil->data->{network}{$host}{interface}{$interface_name}{network_interface_uuid} = $results->[0]->[0];
$anvil->data->{network}{$host}{interface}{$interface_name}{mac_address} = $interface_mac;
$anvil->data->{network}{$host}{interface}{$interface_name}{ip} = $ip_address_address;
$anvil->data->{network}{$host}{interface}{$interface_name}{subnet_mask} = $ip_address_subnet_mask;
$anvil->data->{network}{$host}{interface}{$interface_name}{default_gateway} = $ip_address_default_gateway;
$anvil->data->{network}{$host}{interface}{$interface_name}{gateway} = $ip_address_gateway;
$anvil->data->{network}{$host}{interface}{$interface_name}{dns} = $ip_address_dns;
$anvil->data->{network}{$host}{interface}{$interface_name}{type} = $ip_address_on_type;
$anvil->data->{network}{$host}{interface}{$interface_name}{speed} = $results->[0]->[3];
$anvil->data->{network}{$host}{interface}{$interface_name}{mtu} = $results->[0]->[4];
$anvil->data->{network}{$host}{interface}{$interface_name}{link_state} = $results->[0]->[5];
$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];
# If this is a bridge or a bond, use that name for the interface.
if ($bridge_name)
{
$interface_name = $bridge_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface_name => $interface_name }});
}
if ($bond_name)
{
$interface_name = $bond_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { interface_name => $interface_name }});
}
$anvil->data->{network}{$host}{interface}{$interface_name}{network_interface_uuid} = $results->[0]->[0];
$anvil->data->{network}{$host}{interface}{$interface_name}{mac_address} = $interface_mac;
$anvil->data->{network}{$host}{interface}{$interface_name}{ip} = $ip_address_address;
$anvil->data->{network}{$host}{interface}{$interface_name}{subnet_mask} = $ip_address_subnet_mask;
$anvil->data->{network}{$host}{interface}{$interface_name}{default_gateway} = $ip_address_default_gateway;
$anvil->data->{network}{$host}{interface}{$interface_name}{gateway} = $ip_address_gateway;
$anvil->data->{network}{$host}{interface}{$interface_name}{dns} = $ip_address_dns;
$anvil->data->{network}{$host}{interface}{$interface_name}{type} = $ip_address_on_type;
$anvil->data->{network}{$host}{interface}{$interface_name}{speed} = $results->[0]->[3];
$anvil->data->{network}{$host}{interface}{$interface_name}{mtu} = $results->[0]->[4];
$anvil->data->{network}{$host}{interface}{$interface_name}{link_state} = $results->[0]->[5];
$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} = 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)
{

@ -1385,7 +1385,7 @@ sub parse_definition
my $server = defined $parameter->{server} ? $parameter->{server} : "";
my $source = defined $parameter->{source} ? $parameter->{source} : "";
my $definition = defined $parameter->{definition} ? $parameter->{definition} : "";
my $host = defined $parameter->{host} ? $parameter->{host} : $anvil->Get->short_host_name;
my $host = defined $parameter->{host} ? $parameter->{host} : "";
my $target = $anvil->Get->short_host_name();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_uuid => $anvil_uuid,
@ -1395,6 +1395,12 @@ sub parse_definition
host => $host,
}});
if (not $target)
{
$target = $anvil->Get->short_host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target => $target }});
}
if (not $server)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Server->parse_definition()", parameter => "server" }});
@ -1805,6 +1811,16 @@ sub parse_definition
"server::${target}::${server}::${source}::device::${device}::target::${device_target}::type" => $anvil->data->{server}{$target}{$server}{$source}{device}{$device}{target}{$device_target}{type},
}});
if (($boot_order) && ($boot_order =~ /^\d+$/))
{
$anvil->data->{server}{$target}{$server}{$source}{boot_order}{$boot_order}{device_target} = $device_target;
$anvil->data->{server}{$target}{$server}{$source}{boot_order}{$boot_order}{device_type} = $device;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server::${target}::${server}::${source}::boot_order::${boot_order}::device_target" => $anvil->data->{server}{$target}{$server}{$source}{boot_order}{$boot_order}{device_target},
"server::${target}::${server}::${source}::boot_order::${boot_order}::device_type" => $anvil->data->{server}{$target}{$server}{$source}{boot_order}{$boot_order}{device_type},
}});
}
# Record type-specific data
if ($device eq "disk")
{
@ -1832,8 +1848,10 @@ sub parse_definition
my $on_lv = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{on} : "";
my $resource = defined $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} ? $anvil->data->{drbd}{config}{$host}{drbd_path}{$device_path}{resource} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
on_lv => $on_lv,
resource => $resource,
's1:host' => $host,
's2:device_path' => $device_path,
's3:on_lv' => $on_lv,
's4:resource' => $resource,
}});
if ((not $resource) && ($anvil->data->{drbd}{config}{$host}{'by-res'}{$device_path}{resource}))
{

@ -35,6 +35,7 @@ my $THIS_FILE = "Storage.pm";
# move_file
# parse_df
# parse_lsblk
# push_file
# read_config
# read_file
# read_mode
@ -3451,6 +3452,273 @@ sub parse_lsblk
}
=head2 push_file
This takes a file and pushes it to all other machines in the cluster, serially. For machines that can't be accessed, a job is registered to pull the file.
If C<< switches::job-uuid >> is set, the corresponding job will be updated. The progress assumes that C<< sys::progress >> is set.
Parameters;
=head3 file (required)
This is the source file to copy from locally and push it to all peers' C<< /mnt/shared/files/ >> directory.
=cut
sub push_file
{
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 => "Storage->push_file()" }});
# Setup default values
my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $file_uuid = defined $parameter->{file_uuid} ? $parameter->{file_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file => $file,
file_uuid => $file_uuid,
}});
if (not $file)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Storage->push_file()", parameter => "file" }});
return("!!error!!");
}
if (not -f $file)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0105", variables => { file => $file }});
return("!!error!!");
}
$anvil->Database->get_files({debug => $debug});
my $file_size = 0;
my ($file_directory, $file_name) = ($file =~ /^(.*)\/(.*?)$/);
$file_directory =~ s/\/$//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:file_directory' => $file_directory,
's2:file_name' => $file_name,
}});
if (not $file_uuid)
{
# Can we find the file?
foreach my $this_file_uuid (keys %{$anvil->data->{files}{file_uuid}})
{
my $this_file_name = $anvil->data->{files}{file_uuid}{$this_file_uuid}{file_name};
my $this_file_directory = $anvil->data->{files}{file_uuid}{$this_file_uuid}{file_directory};
$this_file_directory =~ s/\/$//g;
my $this_file_size = $anvil->data->{files}{file_uuid}{$this_file_uuid}{file_size};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
this_file_uuid => $this_file_uuid,
this_file_directory => $this_file_directory,
this_file_name => $this_file_name,
this_file_size => $this_file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $this_file_size}).")",
}});
if (($file_name eq $this_file_name) &&
($file_directory eq $this_file_directory))
{
# Found it.
$file_uuid = $this_file_uuid;
$file_size = $this_file_size;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file_uuid => $file_uuid,
file_size => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")",
}});
last;
}
}
}
if ((not $file_uuid) or (not $file_size))
{
$file_size = (stat($file))[7];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file_size => $file_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $file_size}).")",
}});
}
# 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")
{
$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;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'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 $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,
's7:file_size' => $anvil->Convert->bytes_to_human_readable({"bytes" => $file_size}),
}});
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",
variables => $variables,
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0195", variables => $variables});
my $problem = $anvil->Storage->rsync({
debug => 2,
source => $file,
destination => "root\@".$target_ip_address.":".$target_directory,
try_again => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if (not $problem)
{
$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_0310",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0310"});
}
}
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }});
if ($file_uuid)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { copied => $copied }});
if (not $copied)
{
# 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__,
job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}.$anvil->Log->switches,
job_data => "file_uuid=".$file_uuid,
job_name => "storage::pull_file",
job_title => "job_0132",
job_description => "job_0133",
job_progress => 0,
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
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { do_host_type => $do_host_type }});
if ($do_host_type ne "striker")
{
my $file_location_uuid = $anvil->Database->insert_or_update_file_locations({
debug => 2,
file_location_file_uuid => $file_uuid,
file_location_host_uuid => $target_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);
}
=head2 read_config
This method is used to read 'Anvil::Tools' style configuration files. These configuration files are in the format:
@ -5246,7 +5514,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.

@ -19,6 +19,7 @@ dist_man8_MANS = \
anvil-manage-files.8 \
anvil-manage-keys.1 \
anvil-manage-server.8 \
anvil-manage-server-storage.8 \
anvil-manage-storage-groups.8 \
scancore.8 \
striker-initialize-host.8

@ -1,5 +1,8 @@
Add 'lsof' and 'strace' to Required
Common queries;
* SELECT a.job_uuid, b.host_name, a.job_command, a.job_data, a.job_progress, a.job_status FROM jobs a, hosts b WHERE a.job_host_uuid = b.host_uuid AND a.job_progress != 100;
* SELECT a.host_name, b.file_name, c.file_location_active FROM hosts a, files b, file_locations c WHERE a.host_uuid = c.file_location_host_uuid AND b.file_uuid = c.file_location_file_uuid ORDER BY b.file_name ASC, a.host_name ASC;
* SELECT a.dr_link_uuid, b.host_name, c.anvil_name, a.dr_link_note FROM dr_links a, hosts b, anvils c WHERE a.dr_link_host_uuid = b.host_uuid AND a.dr_link_anvil_uuid = c.anvil_uuid ORDER BY c.anvil_name ASC, b.host_name ASC;
When pairing Striker, make sure new config goes to all known nodes!

@ -914,6 +914,16 @@ sub process_volumes
"s4:old_scan_drbd_volume_size" => $old_scan_drbd_volume_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $old_scan_drbd_volume_size}).")",
}});
# If the $new_scan_drbd_volume_size is '0', the device is down. Don't update it so we can
# recall the last known size.
if ($new_scan_drbd_volume_size == 0)
{
$new_scan_drbd_volume_size = $old_scan_drbd_volume_size;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
new_scan_drbd_volume_size => $new_scan_drbd_volume_size." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $new_scan_drbd_volume_size}).")",
}});
}
my $update = 0;
if ($new_scan_drbd_volume_device_path ne $old_scan_drbd_volume_device_path)
{

@ -1230,24 +1230,24 @@ CREATE TRIGGER trigger_files
-- This tracks which files on Strikers should be on Anvils!
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_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,
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_anvil_uuid) REFERENCES anvils(anvil_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_anvil_uuid uuid,
file_location_active boolean,
modified_date timestamp with time zone not null
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;
@ -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>
@ -2859,6 +2863,9 @@ Proceed? [y/N]</key>
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 -->
@ -3263,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>

@ -26,6 +26,7 @@ dist_sbin_SCRIPTS = \
anvil-manage-keys \
anvil-manage-power \
anvil-manage-server \
anvil-manage-server-storage \
anvil-manage-storage-groups \
anvil-migrate-server \
anvil-network-profiler \
@ -76,4 +77,3 @@ sharedir = ${datarootdir}/anvil
dist_share_DATA = striker-auto-initialize-all.example
# -rwxr-xr-x. 1 digimer digimer 34K Feb 1 2020 tool-fio-tester

@ -174,21 +174,48 @@ sub update_passwords
}
else
{
my ($output, $return_code) = $anvil->System->call({debug => 2, shell_call => $anvil->data->{path}{exe}{'anvil-change-password'}." -y --password-file ".$temp_file.$anvil->Log->switches });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
foreach my $line (split/\n/, $output)
my $wait_until = time + 120;
my $waiting = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
waiting => $waiting,
wait_until => $wait_until,
}});
while ($waiting)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
my $shell_call = $anvil->data->{path}{exe}{'anvil-change-password'}." -y --password-file ".$temp_file.$anvil->Log->switches;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => 2, timeout => 15, shell_call => $shell_call });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output, return_code => $return_code }});
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
}
if ($return_code)
{
# Something went wrong
if (time > $wait_until)
{
# Give up.
$waiting = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0011", variables => { return_code => $return_code }});
}
}
else
{
# Success
$waiting = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { waiting => $waiting }});
}
}
# Unlink the temp file.
unlink $temp_file;
if ($return_code)
{
# Something went wrong
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, key => "error_0011", variables => { return_code => $return_code }});
}
}
}
@ -408,7 +435,7 @@ ORDER BY
}});
# An undefined interface will have the MAC address value set to '1', ignore those.
next if $variable_value = 1;
next if $variable_value == 1;
if ($variable_name =~ /form::config_step2::(.*?)_mac_to_set::value/)
{

@ -766,7 +766,7 @@ sub check_db_in_use_states
my ($anvil) = @_;
# We only reap db_in_use entries for us.
$anvil->System->pids();
$anvil->System->pids({debug => 2});
my $query = "
SELECT
state_uuid,

@ -6,6 +6,8 @@
# This behaviour is likely to change later as it's not ideal.
#
# TODO: --remove is not yet implemented, this needs to be done. Use anvil-delete-server for methods to delete.
# EXAMPLES:
# - anvil-manage-dr --link --dr-host vm-a01dr02 --anvil vm-anvil-01
#
# Exit codes;
# 0 = Normal exit.
@ -2174,7 +2176,7 @@ sub process_protect
});
$anvil->DRBD->gather_data({debug => 2});
my $server_ram = $anvil->data->{server}{$short_host_name}{$server_name}{'from_db'}{memory};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_ram => $anvil->Convert->add_commas({number => $server_ram})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $server_ram}).")",
@ -2182,6 +2184,7 @@ sub process_protect
foreach my $resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{drbd}{resource}})
{
next if $resource eq "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { resource => $resource }});
foreach my $this_host_name (sort {$a cmp $b} keys %{$anvil->data->{new}{resource}{$resource}{host}})
@ -2559,6 +2562,15 @@ sub process_protect
my $record_job = 0;
if (not $anvil->data->{switches}{Yes})
{
# If there's no config file, this might be being run from DR which doesn't have info about
# the resource yet.
if ((not $config_file) && (not $anvil->data->{switches}{'job-uuid'}))
{
# Bail out.
print $anvil->Words->string({key => "message_0308"})."\n";
$anvil->nice_exit({exit_code => 1});
}
# Ask the user to confirm.
print "\n".$anvil->Words->string({key => "message_0021"})."\n";
my $answer = <STDIN>;

@ -564,10 +564,11 @@ sub check_incoming
}});
# Calculate the md5sum?
my $file_md5sum = $recorded_md5sum;
my $added_to_db = 0;
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 => {
@ -608,7 +609,7 @@ sub check_incoming
# Insert or update the files entry.
($file_uuid) = $anvil->Database->insert_or_update_files({
debug => 3,
debug => 2,
file_uuid => $file_uuid,
file_name => $file_name,
file_directory => $file_directory,
@ -617,15 +618,21 @@ sub check_incoming
file_mtime => $file_mtime,
file_type => $say_mimetype,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file_uuid => $file_uuid }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }});
if ($file_uuid)
{
$added_to_db = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { added_to_db => $added_to_db }});
}
}
# If we still don't have a file UUID for some reason, skip this file.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file_uuid => $file_uuid }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }});
next if not $file_uuid;
# Are we in the incoming directory? If so, move the file.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
full_path => $full_path,
incoming_directory => $incoming_directory,
}});
@ -640,28 +647,34 @@ sub check_incoming
my $target = $say_mimetype eq "definition" ? $anvil->data->{path}{directories}{shared}{definitions} : $anvil->data->{path}{directories}{shared}{files};
$target .= "/";
$target =~ s/\/\//\//g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { target => $target }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target => $target }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "log_0268", variables => {
file => $full_path,
target => $target,
}});
# Wait in case it's still being uploaded.
$anvil->Storage->_wait_if_changing({
file => $full_path,
last_size => $file_size,
});
$anvil->Storage->move_file({
debug => 3,
my $problem = $anvil->Storage->move_file({
debug => 2,
source_file => $full_path,
target_file => $target,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { problem => $problem }});
if (not $problem)
{
$full_path = $target."/".$file_name;
$file_directory = $target;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
file_directory => $file_directory,
full_path => $full_path,
}});
}
# Update the file_directory.
($file_uuid) = $anvil->Database->insert_or_update_files({
debug => 3,
$target =~ s/\/$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { target => $target }});
($file_uuid) = $anvil->Database->insert_or_update_files({
debug => 2,
file_uuid => $file_uuid,
file_name => $file_name,
file_directory => $target,
@ -670,7 +683,20 @@ sub check_incoming
file_mtime => $file_mtime,
file_type => $say_mimetype,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file_uuid => $file_uuid }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { file_uuid => $file_uuid }});
}
if ($added_to_db)
{
# Push it to all other hosts now.
$anvil->Storage->push_file({
debug => 2,
file => $full_path,
file_uuid => $file_uuid,
});
# Call track_files, it'll make sure the file_locations are setup.
$anvil->Database->track_files({debug => 2});
}
}
@ -729,6 +755,7 @@ WHERE
{
$query .= " file_name = ".$anvil->Database->quote($file_name)."\n";
}
$query .= ";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};

@ -24,26 +24,17 @@ if (($running_directory =~ /^\./) && ($ENV{PWD}))
my $anvil = Anvil::Tools->new();
# Read switches
$anvil->data->{switches}{'age-out-database'} = "";
$anvil->data->{switches}{'check-configured'} = "";
$anvil->data->{switches}{'check-database'} = "";
$anvil->data->{switches}{'database-active'} = "";
$anvil->data->{switches}{'database-inactive'} = "";
$anvil->data->{switches}{'mark-configured'} = "";
$anvil->data->{switches}{'mark-unconfigured'} = "";
$anvil->data->{switches}{'resync-database'} = "";
$anvil->Get->switches;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::age-out-database' => $anvil->data->{switches}{'age-out-database'},
'switches::check-configured' => $anvil->data->{switches}{'check-configured'},
'switches::check-database' => $anvil->data->{switches}{'check-database'},
'switches::database-active' => $anvil->data->{switches}{'database-active'},
'switches::database-inactive' => $anvil->data->{switches}{'database-inactive'},
'switches::mark-configured' => $anvil->data->{switches}{'mark-configured'},
'switches::mark-unconfigured' => $anvil->data->{switches}{'mark-unconfigured'},
'switches::resync-database' => $anvil->data->{switches}{'resync-database'},
}});
$anvil->Get->switches({list => [
"age-out-database",
"check-configured",
"check-database",
"database-active",
"database-inactive",
"mark-configured",
"mark-unconfigured",
"resync-database"], man => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});
$anvil->Database->connect({all => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});

@ -0,0 +1,398 @@
#!/usr/bin/perl
#
# This program will manage servers; Changing RAM, CPU cores, Growing virtual disks, adding virtual disks,
# inserting and ejecting ISO images into virtual optical media.
#
# Exit codes;
# 0 = Normal exit.
# 1 = No database connection.
#
# TODO:
#
use strict;
use warnings;
use Anvil::Tools;
require POSIX;
use Term::Cap;
use Data::Dumper;
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD}))
{
$running_directory =~ s/^\./$ENV{PWD}/;
}
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1;
my $anvil = Anvil::Tools->new();
### TODO: Remove this before final release
$anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1});
##########################################
# Read switches (target ([user@]host[:port]) and the file with the target's password.
$anvil->Get->switches({list => [
"add",
"anvil",
"grow",
"server",
], man => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => $anvil->data->{switches}});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});
# Connect to the database(s). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks
# is to setup the database server.
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0132"});
if (not $anvil->data->{sys}{database}{connections})
{
# No databases, update the job, sleep for a bit and then exit. The daemon will pick it up and try
# again after we exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 0, priority => "err", key => "error_0305"});
sleep 10;
$anvil->nice_exit({exit_code => 1});
}
# If we don't have a job UUID, try to find one.
if (not $anvil->data->{switches}{'job-uuid'})
{
# Load the job data.
$anvil->data->{switches}{'job-uuid'} = $anvil->Job->get_job_uuid({program => $THIS_FILE});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "switches::job-uuid" => $anvil->data->{switches}{'job-uuid'} }});
}
$anvil->Database->get_hosts();
$anvil->Database->get_anvils();
$anvil->Database->get_servers();
if ($anvil->data->{switches}{anvil})
{
# Make sure they asked for a real anvil.
$anvil->Get->anvil_from_switch({string => $anvil->data->{switches}{anvil}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::anvil_name" => $anvil->data->{switches}{anvil_name},
"switches::anvil_uuid" => $anvil->data->{switches}{anvil_uuid},
}});
}
if (not $anvil->data->{switches}{server})
{
# Show the list of servers.
show_server_list($anvil);
print "\nPlease specify which server you want to modify using '--server <name or uuid>'.\n\n";
$anvil->nice_exit({exit_code => 0});
}
manage_server($anvil);
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
sub manage_server
{
my ($anvil) = @_;
$anvil->Get->server_from_switch({
debug => 2,
string => $anvil->data->{switches}{server},
anvil_uuid => $anvil->data->{switches}{anvil_uuid},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::server_name" => $anvil->data->{switches}{server_name},
"switches::server_uuid" => $anvil->data->{switches}{server_uuid},
}});
if (not $anvil->data->{switches}{server_uuid})
{
show_server_list($anvil);
if ($anvil->data->{switches}{anvil_uuid})
{
# Not found on the requested Anvil! node.
print "\nThe server: [".$anvil->data->{switches}{server}."] was not found on the Anvil! node: [".$anvil->data->{switches}{anvil_name}."]. Valid servers are above.\n\n";
}
else
{
# Not found at all.
print "\nThe server: [".$anvil->data->{switches}{server}."] was not found. Valid servers are above.\n\n";
}
$anvil->nice_exit({exit_code => 1});
}
print "Working with the server: [".$anvil->data->{switches}{server_name}."], UUID: [".$anvil->data->{switches}{server_uuid}."]\n";
my $short_host_name = $anvil->Get->short_host_name;
my $server_name = $anvil->data->{switches}{server_name};
my $server_uuid = $anvil->data->{switches}{server_uuid};
my $server_definition = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_definition_xml};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:server_name' => $server_name,
's3:server_uuid' => $server_uuid,
's4:server_definition' => $server_definition,
}});
# Parse the definition.
$anvil->Server->parse_definition({
debug => 3,
host => $short_host_name,
server => $server_name,
source => "from_virsh",
definition => $server_definition,
});
#$anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{boot_order}
foreach my $device ("disk", "cdrom")
{
if ($device eq "disk")
{
print "\nDisk Drives:\n";
}
else
{
print "\nOptical Drives:\n";
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { device => $device }});
next if $device ne "cdrom" && $device ne "disk";
foreach my $device_target (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}})
{
my $alias = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{alias};
my $boot_order = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{boot_order};
my $say_boot = $boot_order eq "99" ? "--" : sprintf("%02d", $boot_order);
my $type = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{type};
my $address_type = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{type};
my $address_bus = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{bus};
my $driver_name = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{driver}{name};
my $device_bus = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{device_bus};
my $driver_type = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{driver}{type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's01:device_target' => $device_target,
's02:alias' => $alias,
's03:boot_order' => $boot_order,
's04:say_boot' => $say_boot,
's05:type' => $type,
's06:address_type' => $address_type,
's07:address_bus' => $address_bus,
's08:driver_name' => $driver_name,
's09:device_bus' => $device_bus,
's10:driver_type' => $driver_type,
}});
if ($device eq "disk")
{
my $address_domain = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{domain};
my $address_slot = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{slot};
my $address_function = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{function};
my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{path};
my $driver_io = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{driver}{io};
my $driver_cache = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{driver}{cache};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:address_domain' => $address_domain,
's2:address_slot' => $address_slot,
's3:address_function' => $address_function,
's4:device_path' => $device_path,
's5:driver_io' => $driver_io,
's6:driver_cache' => $driver_cache,
}});
print "- Target: [".$device_target."], boot: [".$say_boot."], path: [".$device_path."], cache: [".$driver_cache."], driver type: [".$driver_type."]\n";
}
else
{
my $address_controller = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{controller};
my $address_unit = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{unit};
my $address_target = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{address}{target};
my $device_path = $anvil->data->{server}{$short_host_name}{$server_name}{from_virsh}{device}{$device}{target}{$device_target}{path};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:address_controller' => $address_controller,
's2:address_unit' => $address_unit,
's3:address_target' => $address_target,
's4:device_path' => $device_path,
}});
print "- Target: [".$device_target."], boot: [".$say_boot."], ISO: [".$device_path."]\n";
}
}
}
print "\n";
my $drbd_resource = "";
foreach my $device_path (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{device}})
{
my $on_lv = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{on_lv};
$drbd_resource = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{resource};
my $device_target = $anvil->data->{server}{$short_host_name}{$server_name}{device}{$device_path}{target};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:device_path' => $device_path,
's2:on_lv' => $on_lv,
's3:drbd_resource' => $drbd_resource,
's4:device_target' => $device_target,
}});
}
foreach my $drbd_resource (sort {$a cmp $b} keys %{$anvil->data->{server}{$short_host_name}{$server_name}{drbd}{resource}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { drbd_resource => $drbd_resource }});
}
# Get the DRBD volume data
# Get the DRBD volume data
my $query = "
SELECT
a.host_uuid,
b.scan_drbd_resource_xml,
c.scan_drbd_volume_number,
c.scan_drbd_volume_device_path,
c.scan_drbd_volume_device_minor,
c.scan_drbd_volume_size
FROM
hosts a,
scan_drbd_resources b,
scan_drbd_volumes c
WHERE
a.host_uuid = b.scan_drbd_resource_host_uuid
AND
b.scan_drbd_resource_uuid = c.scan_drbd_volume_scan_drbd_resource_uuid
AND
b.scan_drbd_resource_name = ".$anvil->Database->quote($drbd_resource)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $host_uuid = $row->[0];
my $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
my $scan_drbd_volume_number = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:host_uuid' => $host_uuid,
's2:host_type' => $host_type,
's3:short_host_name' => $short_host_name,
's4:scan_drbd_volume_number' => $scan_drbd_volume_number,
}});
$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_path} = $row->[3];
$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_minor} = $row->[4];
$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{volume_size} = $row->[5];
$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid} = $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"s1:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::device_path" => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_path},
"s2:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::device_minor" => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{device_minor},
"s3:drbd_resource::${drbd_resource}::host_uuid::${host_uuid}::volume_number::${scan_drbd_volume_number}::volume_size" => $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$scan_drbd_volume_number}{volume_size},
"s4:drbd_resource::${drbd_resource}::host_type::${host_type}::short_host_name::${short_host_name}::host_uuid" => $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid},
}});
if (not exists $anvil->data->{drbd_resource}{$drbd_resource}{xml})
{
$anvil->data->{drbd_resource}{$drbd_resource}{xml} = $row->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"drbd_resource::${drbd_resource}::xml" => $anvil->data->{drbd_resource}{$drbd_resource}{xml},
}});
$anvil->DRBD->parse_resource({
debug => 2,
xml => $anvil->data->{drbd_resource}{$drbd_resource}{xml},
});
}
}
print "Sub-Nodes:\n";
show_volume($anvil, $drbd_resource, "node");
my $dr_count = keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{dr}{short_host_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { dr_count => $dr_count }});
if ($dr_count)
{
print "DR Hosts:\n";
show_volume($anvil, $drbd_resource, "dr");
}
return(0);
}
sub show_volume
{
my ($anvil, $drbd_resource, $host_type) = @_;
foreach my $short_host_name (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}})
{
my $host_uuid = $anvil->data->{drbd_resource}{$drbd_resource}{host_type}{$host_type}{short_host_name}{$short_host_name}{host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:short_host_name' => $short_host_name,
's2:host_uuid' => $host_uuid,
}});
print " |- Name: [".$short_host_name."], UUID: [".$host_uuid."]\n";
foreach my $volume_number (sort {$a cmp $b} keys %{$anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}})
{
my $device_path = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_path};
my $device_minor = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{device_minor};
my $volume_size = $anvil->data->{drbd_resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{volume_size};
my $backing_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{backing_disk};
my $meta_disk = $anvil->data->{new}{resource}{$drbd_resource}{host_uuid}{$host_uuid}{volume_number}{$volume_number}{meta_disk};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:volume_number' => $volume_number,
's2:device_path' => $device_path,
's3:device_minor' => $device_minor,
's4:volume_size' => $volume_size,
's5:backing_disk' => $backing_disk,
's6:meta_disk' => $meta_disk,
}});
print " ^- Volume: [".$volume_number."], backing device: [".$backing_disk."], DRBD minor: [".$device_minor."], size: [".$anvil->Convert->bytes_to_human_readable({'bytes' => $volume_size})."]\n";
}
}
return(0);
}
sub show_server_list
{
my ($anvil) = @_;
# Loop through all Anvil! nodes, then all server in that Anvil!
foreach my $anvil_name (sort {$a cmp $b} keys %{$anvil->data->{anvils}{anvil_name}})
{
my $anvil_uuid = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_uuid};
my $anvil_description = $anvil->data->{anvils}{anvil_name}{$anvil_name}{anvil_description};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
anvil_name => $anvil_name,
anvil_uuid => $anvil_uuid,
anvil_description => $anvil_description,
}});
if (($anvil->data->{switches}{anvil_uuid}) && ($anvil->data->{switches}{anvil_uuid} ne $anvil_uuid))
{
next;
}
print "\nAnvil! Node: [".$anvil_name."], UUID: [".$anvil_uuid."] - Description: [".$anvil_description."]\n";
my $server_count = 0;
if (exists $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name})
{
$server_count = keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_count => $server_count }});
}
if (not $server_count)
{
print "- No servers on this node yet\n";
}
else
{
foreach my $server_name (sort {$a cmp $b} keys %{$anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}})
{
my $server_uuid = $anvil->data->{servers}{anvil_uuid}{$anvil_uuid}{server_name}{$server_name}{server_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_name => $server_name,
server_uuid => $server_uuid,
}});
print "^- Server: [".$server_name."], UUID: [".$server_uuid."]\n";
}
}
}
return(0);
}

@ -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,21 +441,31 @@ 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,
source_file => $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;
@ -561,90 +572,16 @@ 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}})
{
# 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;
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),
}});
my $striker_name = $anvil->Get->host_name_from_uuid({host_uuid => $host_uuid});
my $say_host = $striker_name." (".$host.")";
# Rsync the file.
$anvil->data->{sys}{progress} += 10;
$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."!!",
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "message_0195", variables => { host => $say_host }});
$anvil->Storage->rsync({
debug => 2,
source => $target_file,
destination => "root\@".$host.":".$anvil->data->{path}{directories}{shared}{files}."/",
try_again => 1,
});
}
# 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->Storage->push_file({
debug => 2,
file => $target_file,
file_uuid => $file_uuid,
});
# 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}})
{
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,
}});
$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."!!",
});
$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)
{
next if not $host_uuid;
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
file => $THIS_FILE,
line => __LINE__,
job_command => $anvil->data->{path}{exe}{'anvil-sync-shared'}.$anvil->Log->switches,
job_data => "file_uuid=".$file_uuid,
job_name => "storage::pull_file",
job_title => "job_0132",
job_description => "job_0133",
job_progress => 0,
job_host_uuid => $host_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { job_uuid => $job_uuid }});
}
}
# Call track_files, it'll make sure the file_locations are setup.
$anvil->Database->track_files({debug => 2});
# Done!
$anvil->Job->update_progress({

@ -62,6 +62,10 @@ $anvil->nice_exit({exit_code => 0});
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