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

Anvil tools dev
main
Digimer 2 years ago committed by GitHub
commit 26a69653f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Anvil/Tools.pm
  2. 7
      Anvil/Tools/Cluster.pm
  3. 2
      Anvil/Tools/DRBD.pm
  4. 347
      Anvil/Tools/Database.pm
  5. 3
      Anvil/Tools/Get.pm
  6. 1
      Anvil/Tools/System.pm
  7. 16
      anvil.spec.in
  8. 11
      man/Makefile.am
  9. 12
      man/anvil-manage-dr.8
  10. 0
      man/anvil-manage-storage-groups.8
  11. 18
      scancore-agents/scan-apc-pdu/scan-apc-pdu
  12. 2
      scancore-agents/scan-apc-pdu/scan-apc-pdu.xml
  13. 4
      share/anvil.sql
  14. 21
      share/words.xml
  15. 1
      tools/Makefile.am
  16. 718
      tools/anvil-manage-dr
  17. 35
      tools/anvil-manage-firewall
  18. 608
      tools/anvil-manage-storage-groups
  19. 6
      tools/anvil-provision-server
  20. 61
      tools/anvil-version-changes
  21. 3
      tools/fence_pacemaker
  22. 22
      tools/striker-manage-peers
  23. 1
      tools/unfence_pacemaker

@ -1261,7 +1261,6 @@ sub _set_paths
'ssh-keygen' => "/usr/bin/ssh-keygen",
'ssh-keyscan' => "/usr/bin/ssh-keyscan",
'stat' => "/usr/bin/stat",
stonith_admin => "/usr/sbin/stonith_admin",
storcli64 => "/opt/MegaRAID/storcli/storcli64",
strings => "/usr/bin/strings",
'striker-auto-initialize-all' => "/usr/sbin/striker-auto-initialize-all",

@ -462,6 +462,7 @@ ORDER BY
storage_group_member_storage_group_uuid => $storage_group_uuid,
storage_group_member_host_uuid => $host_uuid,
storage_group_member_vg_uuid => $storage_group_member_vg_uuid,
storage_group_member_note => "auto-created",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_uuid => $storage_group_member_uuid }});
@ -525,6 +526,7 @@ ORDER BY
storage_group_member_storage_group_uuid => $storage_group_uuid,
storage_group_member_host_uuid => $host_uuid,
storage_group_member_vg_uuid => $storage_group_member_vg_uuid,
storage_group_member_note => "auto-created",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { storage_group_member_uuid => $storage_group_member_uuid }});
@ -537,6 +539,11 @@ 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 }});
}
return(0);

@ -602,7 +602,7 @@ sub delete_resource
# Wipe the DRBD MDs from each backing LV
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0590", variables => { resource => $resource }});
my $shell_call = $anvil->data->{path}{exe}{echo}." yes | ".$anvil->data->{path}{exe}{drbdadm}." wipe-md ".$resource;
my $shell_call = $anvil->data->{path}{exe}{drbdadm}." --force wipe-md ".$resource;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 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 => {

@ -26,6 +26,7 @@ my $THIS_FILE = "Database.pm";
# disconnect
# find_host_uuid_columns
# get_alert_overrides
# get_anvil_uuid_from_string
# get_alerts
# get_anvils
# get_bridges
@ -34,6 +35,7 @@ my $THIS_FILE = "Database.pm";
# get_file_locations
# get_files
# get_host_from_uuid
# get_host_uuid_from_string
# get_hosts
# get_hosts_info
# get_ip_addresses
@ -43,6 +45,7 @@ my $THIS_FILE = "Database.pm";
# get_mail_servers
# get_manifests
# get_recipients
# get_server_uuid_from_string
# get_servers
# get_storage_group_data
# get_ssh_keys
@ -1327,10 +1330,11 @@ sub connect
$anvil->data->{sys}{database}{timestamp} = "" if not defined $anvil->data->{sys}{database}{timestamp};
# We need the host_uuid before we connect.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::host_uuid" => $anvil->data->{sys}{host_uuid} }});
if (not $anvil->data->{sys}{host_uuid})
{
$anvil->data->{sys}{host_uuid} = $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::host_uuid" => $anvil->data->{sys}{host_uuid} }});
$anvil->data->{sys}{host_uuid} = $anvil->Get->host_uuid({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "sys::host_uuid" => $anvil->data->{sys}{host_uuid} }});
}
# This will be set to '1' if either DB needs to be initialized or if the last_updated differs on any node.
@ -1614,15 +1618,24 @@ sub connect
}});
# Set this database handle as the one to use for reading, if no handle is yet set.
if (not $anvil->Database->read)
if (($is_local) or (not $anvil->data->{sys}{database}{read_uuid}) or (not $anvil->Database->read))
{
$anvil->data->{sys}{database}{read_uuid} = $uuid;
$anvil->Database->read({set => $dbh});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'anvil->Database->read' => $anvil->Database->read }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'anvil->Database->read' => $anvil->Database->read,
"sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid},
}});
}
if (not $anvil->data->{sys}{database}{read_uuid})
# Only the first database to connect will be "Active". What this means will expand
# over time. As of now, only the active DB will do resyncs.
if (not $anvil->data->{sys}{database}{active_uuid})
{
$anvil->data->{sys}{database}{read_uuid} = $uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }});
$anvil->data->{sys}{database}{active_uuid} = $uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::active_uuid" => $anvil->data->{sys}{database}{active_uuid},
}});
}
# Read the DB identifier and then check that we've not already connected to this DB.
@ -1739,19 +1752,6 @@ sub connect
"db_status::${uuid}::active" => $anvil->data->{db_status}{$uuid}{active},
}});
# Set the first ID to be the one I read from later. Alternatively, if this host is
# local, use it.
if (($is_local) or (not $anvil->data->{sys}{database}{read_uuid}))
{
$anvil->data->{sys}{database}{read_uuid} = $uuid;
$anvil->Database->read({set => $anvil->data->{cache}{database_handle}{$uuid}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid},
'anvil->Database->read' => $anvil->Database->read(),
}});
}
# Get a time stamp for this run, if not yet gotten.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"cache::database_handle::${uuid}" => $anvil->data->{cache}{database_handle}{$uuid},
@ -1775,14 +1775,6 @@ sub connect
push @{$successful_connections}, $uuid;
}
# We always use the first DB we connect to, even if we're a DB ourselves. This helps with
# consistency and leaves second (or third...) as backups.
if (not $anvil->data->{sys}{database}{read_uuid})
{
$anvil->data->{sys}{database}{read_uuid} = $uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { "sys::database::read_uuid" => $anvil->data->{sys}{database}{read_uuid} }});
}
# Before we try to connect, see if this is a local database and, if so, make sure it's setup.
if ($is_local)
{
@ -1842,7 +1834,8 @@ sub connect
# Delete the information about this database. We'll try again on next
# ->connect().
$anvil->data->{sys}{database}{read_uuid} = "" if $anvil->data->{sys}{database}{read_uuid} eq $uuid;
$anvil->data->{sys}{database}{active_uuid} = "" if $anvil->data->{sys}{database}{read_active} eq $uuid;
$anvil->data->{sys}{database}{read_uuid} = "" if $anvil->data->{sys}{database}{read_uuid} eq $uuid;
$anvil->data->{sys}{database}{connections}--;
delete $anvil->data->{database}{$uuid};
next;
@ -1850,7 +1843,7 @@ sub connect
}
}
# If we're a striker and no connections were found, start our database.
# If we're a striker, no connections were found, and we have peers, start our database.
my $configured_databases = keys %{$anvil->data->{database}};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
local_host_type => $local_host_type,
@ -2186,11 +2179,16 @@ sub connect
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { check_for_resync => $check_for_resync }});
}
# Check for behind databases only if there are 2+ DBs, we're the active DB, and we're set to do so.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"sys::database::connections" => $anvil->data->{sys}{database}{connections},
"sys::database::active_uuid" => $anvil->data->{sys}{database}{active_uuid},
"sys::host_uuid" => $anvil->data->{sys}{host_uuid},
check_for_resync => $check_for_resync,
}});
if (($anvil->data->{sys}{database}{connections} > 1) && ($check_for_resync))
if (($anvil->data->{sys}{database}{connections} > 1) &&
(($anvil->data->{sys}{database}{active_uuid} eq $anvil->data->{sys}{host_uuid}) or
($check_for_resync)))
{
$anvil->Database->_find_behind_databases({
debug => $debug,
@ -2373,6 +2371,58 @@ sub find_host_uuid_columns
}
=head2 get_anvil_uuid_from_string
This takes a string and uses it to look for an Anvil! node. This string can being either a UUID or the name of the Anvil!. The matched C<< anvil_uuid >> is returned, if found. If no match is found, and empty string is returned.
This is meant to handle '--anvil' switches.
Parameters;
=head3 string
This is the string to search for.
=cut
sub get_anvil_uuid_from_string
{
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->get_anvil_uuid_from_string()" }});
my $string = defined $parameter->{string} ? $parameter->{string} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
string => $string,
}});
# Nothing to do unless we were called with a string.
if (not $string)
{
return("");
}
$anvil->Database->get_anvils({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};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_name => $anvil_name,
anvil_uuid => $anvil_uuid,
}});
if (($string eq $anvil_uuid) or
($string eq $anvil_name))
{
return($anvil_uuid);
}
}
return("");
}
=head2 get_alerts
This reads in alerts from the C<< alerts >> table.
@ -2652,9 +2702,6 @@ sub get_anvils
$anvil->Database->get_files({debug => $debug});
$anvil->Database->get_file_locations({debug => $debug});
# Also pull in DRs so we can link them.
$anvil->Database->get_dr_links({debug => $debug});
my $query = "
SELECT
anvil_uuid,
@ -2997,10 +3044,8 @@ sub get_dr_links
include_deleted => $include_deleted,
}});
if (exists $anvil->data->{dr_links})
{
delete $anvil->data->{dr_links};
}
# Hosts loads anvils.
$anvil->Database->get_hosts({debug => $debug});
my $query = "
SELECT
@ -3053,11 +3098,22 @@ WHERE
"dr_links::dr_link_uuid::${dr_link_uuid}::modified_date" => $anvil->data->{dr_links}{dr_link_uuid}{$dr_link_uuid}{modified_date},
}});
my $dr_link_host_name = $anvil->data->{hosts}{host_uuid}{$dr_link_host_uuid}{short_host_name};
my $dr_link_anvil_name = $anvil->data->{anvils}{anvil_uuid}{$dr_link_anvil_uuid}{anvil_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
dr_link_host_name => $dr_link_host_name,
dr_link_anvil_name => $dr_link_anvil_name,
}});
$anvil->data->{dr_links}{by_anvil_uuid}{$dr_link_anvil_uuid}{dr_link_host_uuid}{$dr_link_host_uuid}{dr_link_uuid} = $dr_link_uuid;
$anvil->data->{dr_links}{by_anvil_uuid}{$dr_link_anvil_uuid}{dr_link_host_name}{$dr_link_host_name}{dr_link_uuid} = $dr_link_uuid;
$anvil->data->{dr_links}{by_host_uuid}{$dr_link_host_uuid}{dr_link_anvil_uuid}{$dr_link_anvil_uuid}{dr_link_uuid} = $dr_link_uuid;
$anvil->data->{dr_links}{by_host_uuid}{$dr_link_host_uuid}{dr_link_anvil_name}{$dr_link_anvil_name}{dr_link_uuid} = $dr_link_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"dr_links::by_anvil_uuid::${dr_link_anvil_uuid}::dr_link_host_uuid::${dr_link_host_uuid}::dr_link_uuid" => $anvil->data->{dr_links}{by_anvil_uuid}{$dr_link_anvil_uuid}{dr_link_host_uuid}{$dr_link_host_uuid}{dr_link_uuid},
"dr_links::by_host_uuid::${dr_link_host_uuid}::dr_link_anvil_uuid::${dr_link_anvil_uuid}::dr_link_uuid" => $anvil->data->{dr_links}{by_host_uuid}{$dr_link_host_uuid}{dr_link_anvil_uuid}{$dr_link_anvil_uuid}{dr_link_uuid},
"s1:dr_links::by_anvil_uuid::${dr_link_anvil_uuid}::dr_link_host_uuid::${dr_link_host_uuid}::dr_link_uuid" => $anvil->data->{dr_links}{by_anvil_uuid}{$dr_link_anvil_uuid}{dr_link_host_uuid}{$dr_link_host_uuid}{dr_link_uuid},
"s2:dr_links::by_anvil_uuid::${dr_link_anvil_uuid}::dr_link_host_name::${dr_link_host_name}::dr_link_uuid" => $anvil->data->{dr_links}{by_anvil_uuid}{$dr_link_anvil_uuid}{dr_link_host_name}{$dr_link_host_name}{dr_link_uuid},
"s3:dr_links::by_host_uuid::${dr_link_host_uuid}::dr_link_anvil_uuid::${dr_link_anvil_uuid}::dr_link_uuid" => $anvil->data->{dr_links}{by_host_uuid}{$dr_link_host_uuid}{dr_link_anvil_uuid}{$dr_link_anvil_uuid}{dr_link_uuid},
"s4:dr_links::by_host_uuid::${dr_link_host_uuid}::dr_link_anvil_name::${dr_link_anvil_name}::dr_link_uuid" => $anvil->data->{dr_links}{by_host_uuid}{$dr_link_host_uuid}{dr_link_anvil_name}{$dr_link_anvil_name}{dr_link_uuid},
}});
}
@ -3503,6 +3559,61 @@ AND
}
=head2 get_host_uuid_from_string
This takes a string and uses it to look for a host UUID. This string can being either a UUID, short or full host name. The matched C<< host_uuid >> is returned, if found. If no match is found, and empty string is returned.
This is meant to handle '--host' switches.
Parameters;
=head3 string
This is the string to search for.
=cut
sub get_host_uuid_from_string
{
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->get_host_uuid_from_string()" }});
my $string = defined $parameter->{string} ? $parameter->{string} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
string => $string,
}});
# Nothing to do unless we were called with a string.
if (not $string)
{
return("");
}
$anvil->Database->get_hosts({debug => $debug});
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 $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_uuid => $host_uuid,
host_name => $host_name,
short_host_name => $short_host_name,
}});
if (($string eq $host_uuid) or
($string eq $host_name) or
($string eq $short_host_name))
{
# Found it.
return($host_uuid);
}
}
return("");
}
=head2 get_hosts
Get a list of hosts from the c<< hosts >> table, returned as an array of hash references.
@ -4818,6 +4929,58 @@ WHERE
}
=head2 get_server_uuid_from_string
This takes a string and uses it to look for an server UUID. This string can being either a UUID or the server's name. The matched C<< server_uuid >> is returned, if found. If no match is found, and empty string is returned.
This is meant to handle '--server' switches.
Parameters;
=head3 string
This is the string to search for.
=cut
sub get_server_uuid_from_string
{
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->get_server_uuid_from_string()" }});
my $string = defined $parameter->{string} ? $parameter->{string} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
string => $string,
}});
# Nothing to do unless we were called with a string.
if (not $string)
{
return("");
}
$anvil->Database->get_servers({debug => $debug});
foreach my $server_uuid (sort {$a cmp $b} keys %{$anvil->data->{servers}{server_uuid}})
{
my $server_name = $anvil->data->{servers}{server_uuid}{$server_uuid}{server_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server_uuid => $server_uuid,
server_name => $server_name,
}});
if (($string eq $server_uuid) or
($string eq $server_name))
{
return($server_uuid);
}
}
return("");
}
=head2 get_servers
This loads all known servers from the database, including the corresponding C<< server_definition_xml >> from the C<< server_definitions >> table.
@ -5142,7 +5305,8 @@ SELECT
a.storage_group_name,
b.storage_group_member_uuid,
b.storage_group_member_host_uuid,
b.storage_group_member_vg_uuid
b.storage_group_member_vg_uuid,
b.storage_group_member_note
FROM
storage_groups a,
storage_group_members b
@ -5167,6 +5331,8 @@ ORDER BY
my $storage_group_member_uuid = $row->[3];
my $storage_group_member_host_uuid = $row->[4];
my $storage_group_member_vg_uuid = $row->[5]; # This is the VG's internal UUID
my $storage_group_member_note = $row->[6]; # If this is 'DELETED', the link isn't used anymore
my $storage_group_member_host_name = $anvil->data->{hosts}{host_uuid}{$storage_group_member_host_uuid}{short_host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
storage_group_uuid => $storage_group_uuid,
storage_group_anvil_uuid => $storage_group_anvil_uuid,
@ -5174,19 +5340,25 @@ ORDER BY
storage_group_member_uuid => $storage_group_member_uuid,
storage_group_member_host_uuid => $storage_group_member_host_uuid,
storage_group_member_vg_uuid => $storage_group_member_vg_uuid,
storage_group_member_note => $storage_group_member_note,
storage_group_member_host_name => $storage_group_member_host_name,
}});
# Store the data
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{group_name} = $storage_group_name;
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{short_host_name}{$storage_group_member_host_name}{host_uuid} = $storage_group_member_host_uuid;
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{storage_group_member_uuid} = $storage_group_member_uuid;
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{vg_internal_uuid} = $storage_group_member_vg_uuid;
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{vg_size} = 0;
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{vg_free} = 0;
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{storage_group_member_note} = $storage_group_member_note;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_uuid::${storage_group_uuid}::group_name" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{group_name},
"storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_uuid::${storage_group_uuid}::short_host_name::${storage_group_member_host_name}::host_uuid" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{short_host_name}{$storage_group_member_host_name}{host_uuid},
"storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_uuid::${storage_group_uuid}::host_uuid::${storage_group_member_host_uuid}::storage_group_member_uuid" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{storage_group_member_uuid},
"storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_uuid::${storage_group_uuid}::host_uuid::${storage_group_member_host_uuid}::vg_size" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{vg_size}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{vg_size}}).")",
"storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_uuid::${storage_group_uuid}::host_uuid::${storage_group_member_host_uuid}::vg_free" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{vg_free}." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{vg_free}}).")",
"storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_uuid::${storage_group_uuid}::host_uuid::${storage_group_member_host_uuid}::storage_group_member_note" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$storage_group_member_host_uuid}{storage_group_member_note},
}});
# Make it easier to use the VG UUID to find the storage_group_uuid.
@ -7369,6 +7541,7 @@ sub insert_or_update_dr_links
uuid => $uuid,
file => $file,
line => $line,
dr_link_uuid => $dr_link_uuid,
dr_link_host_uuid => $dr_link_host_uuid,
dr_link_anvil_uuid => $dr_link_anvil_uuid,
dr_link_note => $dr_link_note,
@ -7376,7 +7549,10 @@ sub insert_or_update_dr_links
# Make sure that the UUIDs are valid.
$anvil->Database->get_hosts({deubg => $debug});
$anvil->Database->get_dr_links({debug => $debug});
$anvil->Database->get_dr_links({
debug => $debug,
include_deleted => 1,
});
# If deleting, and if we have a valid 'dr_link_uuid' UUID, delete now and be done,
if ($delete)
@ -7399,7 +7575,7 @@ sub insert_or_update_dr_links
UPDATE
dr_links
SET
dr_link_node = 'DELETED',
dr_link_note = 'DELETED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE
dr_link_uuid = ".$anvil->Database->quote($dr_link_uuid)."
@ -12813,25 +12989,21 @@ AND
{
# It's possible that this is called before the host is recorded in the database. So to be
# safe, we'll return without doing anything if there is no host_uuid in the database.
my $hosts = $anvil->Database->get_hosts({debug => $debug});
my $found = 0;
foreach my $hash_ref (@{$hosts})
foreach my $db_uuid (@{$db_uuids})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"hash_ref->{host_uuid}" => $hash_ref->{host_uuid},
"sys::host_uuid" => $anvil->data->{sys}{host_uuid},
}});
if ($hash_ref->{host_uuid} eq $anvil->data->{sys}{host_uuid})
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { db_uuid => $db_uuid }});
my $query = "SELECT COUNT(*) FROM hosts WHERE host_uuid = ".$anvil->Database->quote($anvil->data->{sys}{host_uuid}).";";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $count = $anvil->Database->query({query => $query, uuid => $db_uuid, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }});
if (not $count)
{
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
# We're out.
return("");
}
}
if (not $found)
{
# We're out.
return("");
}
# INSERT
$state_uuid = $anvil->Get->uuid();
@ -12895,6 +13067,8 @@ This is the Anvil! UUID that the storage group belongs to.
This is the name of the new storage group, as shown to the user when they provision servers. If this is not set, the word string 'striker_0280' is used with increasing integer until a unique name is found.
This is set to C<< DELETED >> if the group is deleted.
If this is set and the given name is already in use, C<< !!error!! >> is returned.
=head3 storage_group_uuid (optional)
@ -13109,6 +13283,10 @@ This will remove the VG from the storage group.
If set, C<< storage_group_member_uuid >> is required and it is the only required attribute.
=head3 storage_group_member_note (optional)
This is a note that can be placed about this member. When the member is deleted, this is set to C<< DELETED >>.
=head3 storage_group_member_uuid (optional)
If set, a specific storage group member is updated or deleted.
@ -13143,12 +13321,14 @@ sub insert_or_update_storage_group_members
my $storage_group_member_storage_group_uuid = defined $parameter->{storage_group_member_storage_group_uuid} ? $parameter->{storage_group_member_storage_group_uuid} : "";
my $storage_group_member_host_uuid = defined $parameter->{storage_group_member_host_uuid} ? $parameter->{storage_group_member_host_uuid} : "";
my $storage_group_member_vg_uuid = defined $parameter->{storage_group_member_vg_uuid} ? $parameter->{storage_group_member_vg_uuid} : "";
my $storage_group_member_note = defined $parameter->{storage_group_member_note} ? $parameter->{storage_group_member_note} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
file => $file,
line => $line,
'delete' => $delete,
storage_group_member_uuid => $storage_group_member_uuid,
storage_group_member_note => $storage_group_member_note,
storage_group_member_storage_group_uuid => $storage_group_member_storage_group_uuid,
storage_group_member_host_uuid => $storage_group_member_host_uuid,
storage_group_member_vg_uuid => $storage_group_member_vg_uuid,
@ -13167,10 +13347,10 @@ sub insert_or_update_storage_group_members
UPDATE
storage_group_members
SET
storage_group_member_vg_uuid = 'DELETED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
storage_group_member_note = 'DELETED',
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE
storage_group_member_uuid = ".$anvil->Database->quote($storage_group_member_uuid)."
storage_group_member_uuid = ".$anvil->Database->quote($storage_group_member_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__});
@ -13240,12 +13420,14 @@ INSERT INTO
storage_group_member_storage_group_uuid,
storage_group_member_host_uuid,
storage_group_member_vg_uuid,
storage_group_member_note,
modified_date
) VALUES (
".$anvil->Database->quote($storage_group_member_uuid).",
".$anvil->Database->quote($storage_group_member_storage_group_uuid).",
".$anvil->Database->quote($storage_group_member_host_uuid).",
".$anvil->Database->quote($storage_group_member_vg_uuid).",
".$anvil->Database->quote($storage_group_member_note).",
".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
);";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
@ -13258,7 +13440,8 @@ INSERT INTO
SELECT
storage_group_member_storage_group_uuid,
storage_group_member_host_uuid,
storage_group_member_vg_uuid
storage_group_member_vg_uuid,
storage_group_member_note
FROM
storage_group_members
WHERE
@ -13273,15 +13456,18 @@ WHERE
my $old_storage_group_member_storage_group_uuid = $results->[0]->[0];
my $old_storage_group_member_host_uuid = $results->[0]->[1];
my $old_storage_group_member_vg_uuid = $results->[0]->[2];
my $old_storage_group_member_note = $results->[0]->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_storage_group_member_storage_group_uuid => $old_storage_group_member_storage_group_uuid,
old_storage_group_member_host_uuid => $old_storage_group_member_host_uuid,
old_storage_group_member_vg_uuid => $old_storage_group_member_vg_uuid,
old_storage_group_member_note => $old_storage_group_member_note,
}});
if (($old_storage_group_member_storage_group_uuid ne $storage_group_member_storage_group_uuid) or
($old_storage_group_member_host_uuid ne $storage_group_member_host_uuid) or
($old_storage_group_member_vg_uuid ne $storage_group_member_vg_uuid))
($old_storage_group_member_vg_uuid ne $storage_group_member_vg_uuid) or
($old_storage_group_member_note ne $storage_group_member_note))
{
# Something changed, UPDATE
my $query = "
@ -13291,6 +13477,7 @@ SET
storage_group_member_storage_group_uuid = ".$anvil->Database->quote($storage_group_member_storage_group_uuid).",
storage_group_member_host_uuid = ".$anvil->Database->quote($storage_group_member_host_uuid).",
storage_group_member_vg_uuid = ".$anvil->Database->quote($storage_group_member_vg_uuid).",
storage_group_member_note = ".$anvil->Database->quote($storage_group_member_note).",
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE
storage_group_member_uuid = ".$anvil->Database->quote($storage_group_member_uuid)."
@ -17603,7 +17790,7 @@ sub write
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0090", variables => {
query => (not $secure) ? $query : $anvil->Log->is_secure($query),
server => $say_server,
server => $say_server." (".$uuid.")",
db_error => $DBI::errstr,
}});
if (($count) or ($transaction))
@ -17749,6 +17936,25 @@ sub _age_out_data
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uuid => $uuid }});
# Before I proceed, see when the last age-out happened. If it's less than 24 hours ago, don't
# bother. Of course, if we've been specfiically asked to age out data, proceed.
if (not $anvil->data->{switches}{"age-out-database"})
{
my ($last_age_out, undef, undef) = $anvil->Database->read_variable({
debug => $debug,
variable_name => "database::".$uuid."::aged-out",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { last_age_out => $last_age_out }});
if (($last_age_out) && ($last_age_out =~ /^\d+$/))
{
my $age = time - $last_age_out;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { age => $age }});
next if $age < 86400;
}
}
my $queries = [];
my $query = "SELECT job_uuid FROM jobs WHERE modified_date <= '".$old_timestamp."' AND job_progress = 100;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
@ -17782,6 +17988,17 @@ sub _age_out_data
$anvil->Database->write({debug => $debug, uuid => $uuid, query => $queries, source => $THIS_FILE, line => __LINE__});
}
my $variable_uuid = $anvil->Database->insert_or_update_variables({
variable_name => "database::".$uuid."::aged-out",
variable_value => time,
variable_default => "0",
variable_description => "striker_0199",
variable_section => "database",
variable_source_uuid => "NULL",
variable_source_table => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable_uuid => $variable_uuid }});
$anvil->Database->locking({debug => $debug, renew => 1});
}
@ -18422,7 +18639,7 @@ sub _find_behind_databases
}});
# If we're not a striker, return.
my $host_type = $anvil->Get->host_type();
my $host_type = $anvil->Get->host_type({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
if ($host_type ne "striker")
{

@ -1629,7 +1629,7 @@ sub host_type
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Get->host_type()" }});
my $host_type = "";
my $host_name = $anvil->Get->short_host_name;
my $host_name = $anvil->Get->short_host_name();
$host_type = "unknown";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_type => $host_type,
@ -2417,6 +2417,7 @@ sub switches
foreach my $set_switch (sort {$a cmp $b} keys %{$anvil->data->{switches}})
{
next if $set_switch eq "?";
next if $set_switch eq "age-out-database";
next if $set_switch eq "h";
next if $set_switch eq "help";
next if $set_switch eq "job-uuid";

@ -630,6 +630,7 @@ sub check_if_configured
{
# Write the database entry.
my $variable_uuid = $anvil->Database->insert_or_update_variables({
debug => 2,
variable_name => "system::configured",
variable_value => 1,
variable_default => "",

@ -60,6 +60,7 @@ Requires: kernel-core
Requires: kernel-devel
Requires: kernel-headers
Requires: lsscsi
Requires: lsof
Requires: mailx
Requires: mlocate
Requires: net-snmp-utils
@ -101,6 +102,7 @@ Requires: postgresql-plperl
Requires: rsync
Requires: screen
Requires: smartmontools
Requires: strace
Requires: syslinux
Requires: tar
Requires: tcpdump
@ -238,15 +240,13 @@ sed -i.anvil 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config
setenforce 0
# Enable and start the anvil-daemon
### TODO: check it if was disabled (if it existed before) and, if so, leave it disabled.
systemctl enable chronyd.service
systemctl start chronyd.service
systemctl enable anvil-daemon.service
systemctl restart anvil-daemon.service
systemctl enable scancore.service
systemctl restart scancore.service
systemctl enable striker-ui-api.service
systemctl enable --now chronyd.service
systemctl enable --now anvil-daemon.service
systemctl enable --now scancore.service
systemctl enable --now striker-ui-api.service
systemctl restart striker-ui-api.service
echo "Running 'anvil-version-changes' to update Anvil! systems
anvil-version-changes -vv
%post striker
### NOTE: PostgreSQL is initialized and enabled by striker-prep-database later.

@ -9,7 +9,16 @@ dist_man5_MANS = \
dist_man8_MANS = \
alteeve-repo-setup.8 \
anvil-boot-server.8 \
anvil-change-password.8 \
anvil-check-memory.8 \
anvil-configure-host.8 \
anvil-daemon.8 \
scancore.8
anvil-delete-server.8 \
anvil-manage-alerts.8 \
anvil-manage-dr.8 \
anvil-manage-files.8 \
anvil-manage-keys.1 \
anvil-manage-server.8 \
anvil-manage-storage-groups.8 \
scancore.8 \
striker-initialize-host.8

@ -27,6 +27,15 @@ Connect a server already on DR to it's DR copy, update the data there if needed
\fB\-\-disconnect\fR
Disconnect a server from the DR image. This will end streaming replication.
.TP
\fB\-\-dr-host\fR
This is the host name or host UUID for the DR to use. It is optional if only one DR host is connected to this Anvil! node, but required if two or more are defined.
.TP
\fB\-\-license-file\fR
This is the path to the license file, needed when setting up "long-throw" DR for the first time.
.TP
\fB\-\-link\fR
This takes an --anvil and a --dr-host to enable using the DR host as a target for the Anvil! node.
.TP
\fB\-\-protect\fR
The sets up the server to be imaged on DR, if it isn't already protected.
.TP
@ -73,6 +82,9 @@ This removes the DR image from the DR host for the server, freeing up space on D
\fB\-\-server\fB <server name or uuid> (required)
This is the name or UUID of the server being worked on.
.TP
\fB\-\-unlink\fR
This takes an --anvil and a --dr-host to disable using the DR host as a target for the Anvil! node.
.TP
\fB\-\-update\fB
This tells the DR to be connected and sync, Once the volume(s) on DR are 'UpToDate', the connection is closed. This provides a point in time update of the server's image on DR.
.TP

@ -160,7 +160,7 @@ $anvil->Storage->read_config();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0115", variables => { program => $THIS_FILE }});
# Read switches
$anvil->Get->switches;
$anvil->Get->switches({debug => 3, list => ["force", "purge"]});
# Handle start-up tasks
my $problem = $anvil->ScanCore->agent_startup({agent => $THIS_FILE});
@ -169,13 +169,17 @@ if ($problem)
$anvil->nice_exit({exit_code => 1});
}
# The PDUs don't allow multiple connections at the same time. This causes a lot of false alerts when many
# machines try to scan. As such, only Striker dashboards watch APC PDUs.
my $host_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_type => $host_type }});
if (($host_type ne "striker") && (not $anvil->data->{switches}{force}))
# The APC PDUs only allow one connection at a time. As such, we only run on the striker that is also the
# active DB.
my $host_uuid = $anvil->Get->host_uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
"sys::database::active_uuid" => $anvil->data->{sys}{database}{active_uuid},
"switches::force" => $anvil->data->{switches}{force},
}});
if ((not $anvil->data->{switches}{force}) && ($anvil->data->{sys}{database}{active_uuid} ne $host_uuid))
{
# Exit.
# Don't run.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "scan_apc_pdu_message_0041", variables => { program => $THIS_FILE }});
$anvil->nice_exit({exit_code => 0});
}

@ -81,7 +81,7 @@ A new PDU: [#!variable!name!#] has been found
<key name="scan_apc_pdu_message_0038">- Phase: [#!variable!phase!#] current amperage draw: [#!variable!amps!#].</key>
<key name="scan_apc_pdu_message_0039">- Outlet: [#!variable!outlet!#], on phase: [#!variable!on_phase!#] is: [#!variable!state!#] (name: [#!variable!name!#]).</key>
<key name="scan_apc_pdu_message_0040">The PDU model: [#!variable!model!#] at the IP address: [#!variable!ip_address!#] has vanished! Did the network cable come unplugged?</key>
<key name="scan_apc_pdu_message_0041">APC PDUs only allow one connection at a time. To avoid contention, only Striker dashboards scan APC PDUs. If you want this to run, you can use '--force'. Exiting.</key>
<key name="scan_apc_pdu_message_0041">APC PDUs only allow one connection at a time. To avoid contention, only the Striker dashboards which is also the active database is allowed to run this agent. If you want this to run, you can use '--force'. Exiting.</key>
<!-- Units -->
<key name="scan_apc_pdu_unit_0001">Unknown</key>

@ -1742,6 +1742,7 @@ CREATE TABLE storage_group_members (
storage_group_member_storage_group_uuid uuid not null,
storage_group_member_host_uuid uuid not null, -- The host this VG comes from.
storage_group_member_vg_uuid text not null, -- This is the VG's internal "uuid". It's not a valid UUID string format, but it's what LVM calls a 'uuid'.
storage_group_member_note text not null, -- This is set to DELETED when the link is removed.
modified_date timestamp with time zone not null,
FOREIGN KEY(storage_group_member_storage_group_uuid) REFERENCES storage_groups(storage_group_uuid),
@ -1755,6 +1756,7 @@ CREATE TABLE history.storage_group_members (
storage_group_member_storage_group_uuid uuid,
storage_group_member_host_uuid uuid,
storage_group_member_vg_uuid text,
storage_group_member_note text,
modified_date timestamp with time zone not null
);
ALTER TABLE history.storage_group_members OWNER TO admin;
@ -1770,12 +1772,14 @@ BEGIN
storage_group_member_storage_group_uuid,
storage_group_member_host_uuid,
storage_group_member_vg_uuid,
storage_group_member_note,
modified_date)
VALUES
(history_storage_group_members.storage_group_member_uuid,
history_storage_group_members.storage_group_member_storage_group_uuid,
history_storage_group_members.storage_group_member_host_uuid,
history_storage_group_members.storage_group_member_vg_uuid,
history_storage_group_members.storage_group_member_note,
history_storage_group_members.modified_date);
RETURN NULL;
END;

@ -455,7 +455,7 @@ Failed to parse the XML in the new definition file. The error was:
Giving up.
</key>
<key name="error_0332">This must be run on a node active in the cluster hosting the server being managed. Exiting.</key>
<key name="error_0333">This Anvil! does not seem to have a DR host. Exiting.</key>
<key name="error_0333">There are no DR hosts connected to this Anvil! node yet.</key>
<key name="error_0334">Failed to find an IP we can access the DR host: [#!variable!host_name!#]. Has it been configured? Is it running? Exiting.</key>
<key name="error_0335">Failed to access the DR host: [#!variable!host_name!#] using the IP: [#!variable!ip_address!#]. Is it running? Exiting.</key>
<key name="error_0336">Failed to parse the CIB. Is this node in the cluster? Exiting.</key>
@ -572,6 +572,20 @@ The definition data passed in was:
<key name="error_0397">[ Error ] - The DR link UUID: [#!variable!uuid!#] was not found.</key>
<key name="error_0398">[ Error ] - There was a problem processing the requested network: [#!variable!network!#]. Details should be logged.</key>
<key name="error_0399">[ Error ] - It looks like the new device: [#!variable!resource!#] failed to appear. Unable to proceed.</key>
<key name="error_0400">[ Error ] - The requested DR host: [#!variable!dr_host!#] was not found.</key>
<key name="error_0401">[ Error ] - The requested DR host: [#!variable!dr_host!#] is not configured as a DR host for this Anvil! node.</key>
<key name="error_0402">There are multiple DR hosts connected to this Anvil! node. Please specify which you want to use to protect this server;</key>
<key name="error_0403"> - DR Host: [#!variable!host_name!#], Host UUID: [#!variable!host_uuid!#].</key>
<key name="error_0404">This needs to be run on an Anvil! sub-node.</key>
<key name="error_0405">The requested Anvil! node: [#!variable!anvil!#] appears to be invalid. Valid options are:</key>
<key name="error_0406"><![CDATA[You need to specify an Anvil! node to (un)link. Specify with '--anvil <name or UUID>'. Valid options are:]]></key>
<key name="error_0407"><![CDATA[The requested DR host: [#!variable!host!#] appears to be invalid. Specify with '--dr-host <name or UUID>'. Valid options are:]]></key>
<key name="error_0408"><![CDATA[The requested host: [#!variable!host!#] is not a DR host. Specify with '--dr-host <name or UUID>'. Valid options are:]]></key>
<key name="error_0409"><![CDATA[You need to specify a DR host to (un)link. Valid options are:]]></key>
<key name="error_0410"><![CDATA[Existing Anvil! <-> DR links:]]></key>
<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>
<!-- Files templates -->
<!-- NOTE: Translating these files requires an understanding of which lines are translatable -->
@ -2351,6 +2365,9 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0731">The DRBD Proxy license file: [#!data!path::configs::drbd-proxy.license!#] is missing expected data or is malformed.</key>
<key name="log_0732">Updating logind to ignore ACPI power button events so that IPMI-based fence requests don't trigger an attempt to gracefully shut down. For more information, see: https://access.redhat.com/solutions/1578823</key>
<key name="log_0733">Restarting the daemon: [#!variable!daemon!#].</key>
<key name="log_0734">The DR host: [#!variable!host!#] as been linked to the Anvil! node: [#!variable!anvil!#].</key>
<key name="log_0735">The DR host: [#!variable!host!#] as been _unlinked_ to the Anvil! node: [#!variable!anvil!#].</key>
<key name="log_0736">The DR host: [#!variable!host!#] was not linked to the Anvil! node: [#!variable!anvil!#], nothing to do.</key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -3085,7 +3102,7 @@ If you are comfortable that the target has changed for a known reason, you can s
<key name="striker_0196">Recipient's Email</key>
<key name="striker_0197">The email that alerts are sent to.</key>
<key name="striker_0198">The language the user will receive alerts in.</key>
<key name="striker_0199"></key> <!-- free -->
<key name="striker_0199">This records when the database was last "aged out". That is to say; When did that last purge of old records happen. Normally, aging out only runs once per day. An age-out can be forced from any command line tool with '--age-out-database'.</key>
<key name="striker_0200">The alert level used for new (and existing) #!string!brand_0006!# systems.</key>
<key name="striker_0201">Existing alert recipients:</key>
<key name="striker_0202">This puts the host into network mapping mode. In this most, most functions are disabled and the link status of network interfaces are closely monitored.</key>

@ -26,6 +26,7 @@ dist_sbin_SCRIPTS = \
anvil-manage-keys \
anvil-manage-power \
anvil-manage-server \
anvil-manage-storage-groups \
anvil-migrate-server \
anvil-network-profiler \
anvil-parse-fence-agents \

File diff suppressed because it is too large Load Diff

@ -39,22 +39,21 @@ if (($running_directory =~ /^\./) && ($ENV{PWD}))
my $anvil = Anvil::Tools->new();
# If the user has disabled auto-management of the firewall, exit.
if (not $anvil->data->{sys}{manage}{firewall})
# Read switches
$anvil->Get->switches({list => [
'job-uuid',
"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 }});
$anvil->Database->connect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132" });
if (not $anvil->data->{sys}{database}{connections})
{
# Do nothing.
$anvil->nice_exit({exit_code => 0});
# No databases, exit.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, 'print' => 1, priority => "err", key => "error_0003"});
$anvil->nice_exit({exit_code => 1});
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# Read switches
$anvil->data->{switches}{'job-uuid'} = "";
$anvil->data->{switches}{server} = "";
$anvil->Get->switches;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
'switches::job-uuid' => $anvil->data->{switches}{'job-uuid'},
'switches::server' => $anvil->data->{switches}{server},
}});
# Log our start.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 1, key => "message_0134"});
@ -91,6 +90,14 @@ if ($anvil->data->{switches}{'job-uuid'})
}
exit(0);
# If the user has disabled auto-management of the firewall, exit.
if (not $anvil->data->{sys}{manage}{firewall})
{
# Do nothing.
$anvil->nice_exit({exit_code => 0});
}
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# This used to do all the work, but that's now moved to the method below. So all we do here now is call it.
$anvil->Network->manage_firewall();
if ($anvil->data->{switches}{'job-uuid'})

@ -0,0 +1,608 @@
#!/usr/bin/perl
#
# This allows users to link volume groups across machines into storage groups.
#
# NOTE: This will be expanded on much more later. For now, it's "enough".
#
# Exit codes;
# 0 = Normal exit.
# 1 = Any problem that causes an early exit.
#
# Examples;
# - TODO: Write the man page!
# - anvil-manage-storage-groups -vv --log-secure --anvil mk-anvil-07 --rename --group "Storage group 2" --new-name "HDD Group 1"
# - anvil-manage-storage-groups -vv --log-secure --anvil mk-anvil-07 --add --group "HDD Group 1" --member xidRiS-KT4K-cmVN-MRbK-tI2c-jhK6-VCCLau
use strict;
use warnings;
use Anvil::Tools;
require POSIX;
use Term::Cap;
use Text::Diff;
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();
$anvil->Get->switches({list => [
"add",
"anvil",
"remove",
"rename",
"group",
"host",
"member",
"new-name",
"show",
"vg"], 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();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, 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_0306"});
sleep 10;
$anvil->nice_exit({exit_code => 1});
}
$anvil->Database->get_hosts({include_deleted => 1});
$anvil->Database->get_anvils();
$anvil->Database->get_storage_group_data();
get_vg_data($anvil);
get_storage_data($anvil);
if ($anvil->data->{switches}{show})
{
show_data($anvil);
$anvil->nice_exit({exit_code => 0});
}
if ($anvil->data->{switches}{member})
{
manage_group_member($anvil);
}
if ($anvil->data->{switches}{group})
{
manage_group($anvil);
}
show_data($anvil);
$anvil->nice_exit({exit_code => 0});
#############################################################################################################
# Functions #
#############################################################################################################
sub manage_group
{
my ($anvil) = @_;
my $group = $anvil->data->{switches}{group};
my $new_name = $anvil->data->{switches}{'new-name'};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
group => $group,
new_name => $new_name
}});
if ($group eq "#!SET!#")
{
print "When adding, removing or renaming a group, '--group' needs to be set to the (new) group name.\n";
$anvil->nice_exit({exit_code => 1});
}
# If both are set, what?
if ((($anvil->data->{switches}{add}) && ($anvil->data->{switches}{remove})) or
(($anvil->data->{switches}{add}) && ($anvil->data->{switches}{'rename'})) or
(($anvil->data->{switches}{remove}) && ($anvil->data->{switches}{'rename'})))
{
print "You can only use '--add', '--remove' or '--rename', please use only one at a time.\n";
$anvil->nice_exit({exit_code => 1});
}
my $anvil_uuid = $anvil->Database->get_anvil_uuid_from_string({string => $anvil->data->{switches}{anvil}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
if (not $anvil_uuid)
{
if ($anvil->data->{switches}{anvil})
{
print "The Anvil! node: [".$anvil->data->{switches}{anvil}."] was not found.\n";
}
else
{
print "When managing a storage group, '--anvil <name or UUID>' is required as storage group names are not globally unique.\n";
}
$anvil->nice_exit({exit_code => 1});
}
my $anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_name => $anvil_name }});
# If the group is 'DELETED', um, what the fuck?
if (($group eq "DELETED") or ($new_name eq "DELETED"))
{
print "You want to name your group 'DELETED'? Well that's cheaky... Exiting.\n";
$anvil->nice_exit({exit_code => 1});
}
my $storage_group_uuid = "";
my $storage_group_name = "";
if (exists $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$group})
{
$storage_group_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$group}{storage_group_uuid};
$storage_group_name = $group;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
storage_group_uuid => $storage_group_uuid,
storage_group_name => $storage_group_name,
}});
}
elsif (exists $anvil->data->{storage_groups}{storage_group_uuid}{$group})
{
$storage_group_uuid = $group;
$storage_group_name = $anvil->data->{storage_groups}{storage_group_uuid}{$group}{anvil_uuid}{$anvil_uuid}{storage_group_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
storage_group_uuid => $storage_group_uuid,
storage_group_name => $storage_group_name,
}});
}
if ($anvil->data->{switches}{add})
{
# Does it already exist?
if ($storage_group_uuid)
{
print "The storage group: [".$storage_group_name."] on the Anvil! node: [".$anvil_name."] already exists, nothing to do.\n";
$anvil->nice_exit({exit_code => 0});
}
# Add it.
$storage_group_uuid = $anvil->Database->insert_or_update_storage_groups({
debug => 2,
storage_group_anvil_uuid => $anvil_uuid,
storage_group_name => $storage_group_name,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { storage_group_uuid => $storage_group_uuid }});
print "The storage group: [".$storage_group_name."] on the Anvil! node: [".$anvil_name."] has been created with the UUID: [".$storage_group_uuid."].\n";
$anvil->nice_exit({exit_code => 0});
}
elsif ($anvil->data->{switches}{remove})
{
# Does it exist?
if (not $storage_group_uuid)
{
print "The storage group: [".$group."] wasn't found on the Anvil! node: [".$anvil_name."], nothing to do.\n";
$anvil->nice_exit({exit_code => 0});
}
# Remove it.
$storage_group_uuid = $anvil->Database->insert_or_update_storage_groups({
debug => 2,
storage_group_anvil_uuid => $anvil_uuid,
storage_group_name => "DELETED",
storage_group_name => $storage_group_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { storage_group_uuid => $storage_group_uuid }});
print "The storage group: [".$storage_group_name."] on the Anvil! node: [".$anvil_name."] has been deleted.\n";
$anvil->nice_exit({exit_code => 0});
}
elsif ($anvil->data->{switches}{'rename'})
{
# Do we have a new name?
if (not $new_name)
{
print "The storage group: [".$storage_group_name."] exists on the Anvil! node: [".$anvil_name."], but no new name was given via '--new-name <name>' nothing to do.\n";
$anvil->nice_exit({exit_code => 1});
}
# Has the name changed?
if (($storage_group_name) eq ($new_name))
{
print "The storage group: [".$new_name."] already has the desired name on the: [".$anvil_name."], nothing to do.\n";
$anvil->nice_exit({exit_code => 0});
}
# Rename it.
$storage_group_uuid = $anvil->Database->insert_or_update_storage_groups({
debug => 2,
storage_group_uuid => $storage_group_uuid,
storage_group_anvil_uuid => $anvil_uuid,
storage_group_name => $new_name,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { storage_group_uuid => $storage_group_uuid }});
print "The storage group: [".$storage_group_name."] on the Anvil! node: [".$anvil_name."] has been renamed to: [".$new_name."].\n";
$anvil->nice_exit({exit_code => 0});
}
return(0);
}
sub manage_group_member
{
my ($anvil) = @_;
my $group = $anvil->data->{switches}{group};
my $anvil_uuid = $anvil->Database->get_anvil_uuid_from_string({string => $anvil->data->{switches}{anvil}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
if (not $anvil_uuid)
{
if ($anvil->data->{switches}{anvil})
{
print "The Anvil! node: [".$anvil->data->{switches}{anvil}."] was not found.\n";
}
else
{
print "When managing a storage group members, '--anvil <name or UUID>' is required as storage group names are not globally unique.\n";
}
$anvil->nice_exit({exit_code => 1});
}
my $anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_name => $anvil_name }});
my $storage_group_uuid = "";
my $storage_group_name = "";
foreach my $this_storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}})
{
my $this_storage_group_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$this_storage_group_name}{storage_group_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
this_storage_group_name => $this_storage_group_name,
this_storage_group_uuid => $this_storage_group_uuid,
}});
if (($group eq $this_storage_group_name) or ($group eq $this_storage_group_uuid))
{
# Found it.
$storage_group_uuid = $this_storage_group_uuid;
$storage_group_name = $this_storage_group_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
storage_group_uuid => $storage_group_uuid,
storage_group_name => $storage_group_name,
}});
last;
}
}
if (not $storage_group_uuid)
{
# Group not found.
print "The storage group: [".$group."] was not found on the Anvil! node: [".$anvil_name."].\n";
print "Call with '--show' to see Anvil! nodes, DR hosts and existing storage groups.\n";
$anvil->nice_exit({exit_code => 1});
}
my $internal_vg_uuid = "";
my $host_uuid = "";
my $short_host_name = "";
my $lvm_vg_name = "";
if (($anvil->data->{switches}{add}) or ($anvil->data->{switches}{remove}))
{
# If both are set, what?
if (($anvil->data->{switches}{add}) && ($anvil->data->{switches}{remove}))
{
print "Both '--add' and '--remove' specified, please use only one at a time.\n";
$anvil->nice_exit({exit_code => 1});
}
# These need to be valid VG internal UUID
my $member_vg_uuid = $anvil->data->{switches}{member};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { member_vg_uuid => $member_vg_uuid }});
# Find the VG internal UUID.
if (not exists $anvil->data->{vgs}{scan_lvm_vg_internal_uuid}{$member_vg_uuid})
{
print "The volume group with the internal UUID: [".$member_vg_uuid."] was not found.\n";
print "Call with '--show' to see Anvil! nodes, DR hosts and existing storage groups.\n";
$anvil->nice_exit({exit_code => 1});
}
# Now that we have an VG internal UUID, is it a node in the Anvil!, or a DR host?
$internal_vg_uuid = $member_vg_uuid;
$host_uuid = $anvil->data->{vgs}{scan_lvm_vg_internal_uuid}{$member_vg_uuid}{host_uuid};
my $host_type = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_type};
my $host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_name};
$short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
my $host_key = $anvil->data->{hosts}{host_uuid}{$host_uuid}{host_key};
my $host_anvil_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_name};
my $host_anvil_uuid = $anvil->data->{hosts}{host_uuid}{$host_uuid}{anvil_uuid};
$lvm_vg_name = $anvil->data->{vgs}{host_uuid}{$host_uuid}{scan_lvm_vg_internal_uuid}{$internal_vg_uuid}{scan_lvm_vg_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
internal_vg_uuid => $internal_vg_uuid,
lvm_vg_name => $lvm_vg_name,
host_uuid => $host_uuid,
host_type => $host_type,
short_host_name => $short_host_name,
host_key => $host_key,
host_anvil_name => $host_anvil_name,
host_anvil_uuid => $host_anvil_uuid,
}});
if ($host_key eq "DELETED")
{
print "The volume group: [".$lvm_vg_name."] is on the deleted host: [".$host_name."]\n";
print "Call with '--show' to see Anvil! nodes, DR hosts and existing storage groups.\n";
$anvil->nice_exit({exit_code => 1});
}
if ($host_type eq "striker")
{
print "The volume group: [".$lvm_vg_name."] is on the Striker dashboard: [".$host_name."].\n";
print "There's no point in a Striker being part of a storage group.\n";
print "Call with '--show' to see Anvil! nodes, DR hosts and existing storage groups.\n";
$anvil->nice_exit({exit_code => 1});
}
if (($host_type eq "node") && ($anvil_uuid ne $host_anvil_uuid))
{
print "The volume group: [".$lvm_vg_name."] is on the sub node: [".$host_name."]. This is part of\n";
print "the Anvil! node: [".$host_anvil_name."], but: [".$anvil_name."] was specified with '--anvil'.\n";
$anvil->nice_exit({exit_code => 1});
}
}
# Add needs to be the internal UUID
if ($anvil->data->{switches}{add})
{
# Add the VG, if needed.
if (exists $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid})
{
# If the note is not 'DELETED', we don't need to add it.
my $storage_group_member_note = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{storage_group_member_note};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { storage_group_member_note => $storage_group_member_note }});
if ($storage_group_member_note ne "DELETED")
{
# Nothing to do.
print "The volume group: [".$lvm_vg_name."] on the host: [".$short_host_name."] is already a member of the storage group: [".$storage_group_name."]. Nothing to do.\n";
$anvil->nice_exit({exit_code => 0});
}
}
# Still here? Add or update!
my $storage_group_member_uuid = $anvil->Database->insert_or_update_storage_group_members({
debug => 2,
storage_group_member_storage_group_uuid => $storage_group_uuid,
storage_group_member_host_uuid => $host_uuid,
storage_group_member_vg_uuid => $internal_vg_uuid,
storage_group_member_note => "user-created",
});
print "Added the volume group: [".$lvm_vg_name."] on the host: [".$short_host_name."] to the storage group: [".$storage_group_name."]. The new member UUID is: [".$storage_group_member_uuid."].\n";
}
else
{
# If there's no existing entry, there's nothing to remove.
if (not exists $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid})
{
# Nothing to do.
print "The volume group: [".$lvm_vg_name."] on the host: [".$short_host_name."] has never been a member of the storage group: [".$storage_group_name."]. Nothing to do.\n";
$anvil->nice_exit({exit_code => 0});
}
# If the note is not 'DELETED', we don't need to add it.
if ($anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$host_uuid}{storage_group_member_note} eq "DELETED")
{
# Nothing to do.
print "The volume group: [".$lvm_vg_name."] on the host: [".$short_host_name."] has already been removed from the storage group: [".$storage_group_name."]. Nothing to do.\n";
$anvil->nice_exit({exit_code => 0});
}
# Still here? update!
my $storage_group_member_uuid = $anvil->Database->insert_or_update_storage_group_members({
debug => 2,
storage_group_member_storage_group_uuid => $storage_group_uuid,
storage_group_member_host_uuid => $host_uuid,
storage_group_member_vg_uuid => $internal_vg_uuid,
storage_group_member_note => "DELETED",
});
print "Added the volume group: [".$lvm_vg_name."] on the host: [".$short_host_name."] has been removed from storage group: [".$storage_group_name."].\n";
}
return(0);
}
sub show_data
{
my ($anvil) = @_;
my $show_anvil_uuid = $anvil->Database->get_anvil_uuid_from_string({string => $anvil->data->{switches}{anvil}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { show_anvil_uuid => $show_anvil_uuid }});
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};
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};
if (($show_anvil_uuid) && ($anvil_uuid ne $show_anvil_uuid))
{
next;
}
print "Anvil: [".$anvil_name."] - ".$anvil_description."\n";
foreach my $node_host_uuid ($anvil_node1_host_uuid, $anvil_node2_host_uuid)
{
my $node_host_name = $anvil->data->{hosts}{host_uuid}{$node_host_uuid}{short_host_name};
print "- Node: [".$node_host_name."] volume groups;\n";
foreach my $scan_lvm_vg_name (sort {$a cmp $b} keys %{$anvil->data->{vgs}{host_uuid}{$node_host_uuid}{scan_lvm_vg_name}})
{
my $scan_lvm_vg_internal_uuid = $anvil->data->{vgs}{host_uuid}{$node_host_uuid}{scan_lvm_vg_name}{$scan_lvm_vg_name}{scan_lvm_vg_internal_uuid};
my $scan_lvm_vg_size = $anvil->data->{vgs}{host_uuid}{$node_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_size};
my $scan_lvm_vg_free = $anvil->data->{vgs}{host_uuid}{$node_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_free};
my $say_size_hr = $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_size});
my $say_free_hr = $anvil->Convert->bytes_to_human_readable({'bytes' => $scan_lvm_vg_free});
print " ^- [".$scan_lvm_vg_name."], size: [".$say_size_hr."], free: [".$say_free_hr."], internal UUID: [".$scan_lvm_vg_internal_uuid."]\n";
}
}
foreach my $storage_group_name (sort {$a cmp $b} keys %{$anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}})
{
my $storage_group_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid};
print "- Storage group: [".$storage_group_name."], UUID: [".$storage_group_uuid."]\n";
foreach my $member_short_host_name (sort {$a cmp $b} keys %{$anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{short_host_name}})
{
my $member_host_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{short_host_name}{$member_short_host_name}{host_uuid};
my $storage_group_member_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$member_host_uuid}{storage_group_member_uuid};
my $vg_internal_uuid = $anvil->data->{storage_groups}{anvil_uuid}{$anvil_uuid}{storage_group_uuid}{$storage_group_uuid}{host_uuid}{$member_host_uuid}{vg_internal_uuid};
my $vg_name = $anvil->data->{vgs}{host_uuid}{$member_host_uuid}{scan_lvm_vg_internal_uuid}{$vg_internal_uuid}{scan_lvm_vg_name};
print " ^- [".$member_short_host_name."]:[".$vg_name."]\n";
}
}
print "\n";
}
# Show DR hosts and their VGs
print "Disaster Recovery Hosts:\n";
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 $short_host_name = $anvil->data->{hosts}{host_uuid}{$host_uuid}{short_host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
host_uuid => $host_uuid,
host_name => $host_name,
host_type => $host_type,
short_host_name => $short_host_name,
}});
next if $host_type ne "dr";
print "- DR Host: [".$short_host_name."] VGs:\n";
foreach my $vg_name (sort {$a cmp $b} keys %{$anvil->data->{vgs}{host_uuid}{$host_uuid}{scan_lvm_vg_name}})
{
my $vg_internal_uuid = $anvil->data->{vgs}{host_uuid}{$host_uuid}{scan_lvm_vg_name}{$vg_name}{scan_lvm_vg_internal_uuid};
my $vg_size = $anvil->data->{vgs}{host_uuid}{$host_uuid}{scan_lvm_vg_internal_uuid}{$vg_internal_uuid}{scan_lvm_vg_size};
my $vg_free = $anvil->data->{vgs}{host_uuid}{$host_uuid}{scan_lvm_vg_internal_uuid}{$vg_internal_uuid}{scan_lvm_vg_free};
my $say_size_hr = $anvil->Convert->bytes_to_human_readable({'bytes' => $vg_size});
my $say_free_hr = $anvil->Convert->bytes_to_human_readable({'bytes' => $vg_free});
print " ^- [".$vg_name."], size: [".$say_size_hr."], free: [".$say_free_hr."], internal UUID: [".$vg_internal_uuid."]\n";
}
}
print "\n";
return(0);
}
sub get_vg_data
{
my ($anvil) = @_;
my $query = "
SELECT
scan_lvm_vg_uuid,
scan_lvm_vg_host_uuid,
scan_lvm_vg_internal_uuid,
scan_lvm_vg_name,
scan_lvm_vg_attributes,
scan_lvm_vg_extent_size,
scan_lvm_vg_size,
scan_lvm_vg_free
FROM
scan_lvm_vgs
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $scan_lvm_vg_uuid = $row->[0];
my $scan_lvm_vg_host_uuid = $row->[1];
my $scan_lvm_vg_internal_uuid = $row->[2];
my $scan_lvm_vg_name = $row->[3];
my $scan_lvm_vg_attributes = $row->[4];
my $scan_lvm_vg_extent_size = $row->[5];
my $scan_lvm_vg_size = $row->[6];
my $scan_lvm_vg_free = $row->[7];
my $host_name = $anvil->data->{hosts}{host_uuid}{$scan_lvm_vg_host_uuid}{host_name};
my $host_type = $anvil->data->{hosts}{host_uuid}{$scan_lvm_vg_host_uuid}{host_type};
my $host_key = $anvil->data->{hosts}{host_uuid}{$scan_lvm_vg_host_uuid}{host_key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
scan_lvm_vg_uuid => $scan_lvm_vg_uuid,
scan_lvm_vg_host_uuid => $scan_lvm_vg_host_uuid,
scan_lvm_vg_internal_uuid => $scan_lvm_vg_internal_uuid,
scan_lvm_vg_name => $scan_lvm_vg_name,
scan_lvm_vg_attributes => $scan_lvm_vg_attributes,
scan_lvm_vg_extent_size => $scan_lvm_vg_extent_size,
scan_lvm_vg_size => $scan_lvm_vg_size,
scan_lvm_vg_free => $scan_lvm_vg_free,
host_name => $host_name,
host_type => $host_type,
host_key => $host_type,
}});
next if $host_key eq "DELETED";
next if $host_type eq "striker";
$anvil->data->{vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{host_uuid} = $scan_lvm_vg_host_uuid;
$anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_name}{$scan_lvm_vg_name}{scan_lvm_vg_internal_uuid} = $scan_lvm_vg_internal_uuid;
$anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_uuid} = $scan_lvm_vg_uuid;
$anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_name} = $scan_lvm_vg_name;
$anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_attributes} = $scan_lvm_vg_attributes;
$anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_extent_size} = $scan_lvm_vg_extent_size;
$anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_size} = $scan_lvm_vg_size;
$anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_free} = $scan_lvm_vg_free;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"vgs::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::host_uuid" => $anvil->data->{vgs}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{host_uuid},
"vgs::host_uuid::${scan_lvm_vg_host_uuid}::scan_lvm_vg_name::${scan_lvm_vg_name}::scan_lvm_vg_internal_uuid" => $anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_name}{$scan_lvm_vg_name}{scan_lvm_vg_internal_uuid},
"vgs::host_uuid::${scan_lvm_vg_host_uuid}::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_uuid" => $anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_uuid},
"vgs::host_uuid::${scan_lvm_vg_host_uuid}::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_name" => $anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_name},
"vgs::host_uuid::${scan_lvm_vg_host_uuid}::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_attributes" => $anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_attributes},
"vgs::host_uuid::${scan_lvm_vg_host_uuid}::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_extent_size" => $anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_extent_size},
"vgs::host_uuid::${scan_lvm_vg_host_uuid}::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_size" => $anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_size},
"vgs::host_uuid::${scan_lvm_vg_host_uuid}::scan_lvm_vg_internal_uuid::${scan_lvm_vg_internal_uuid}::scan_lvm_vg_free" => $anvil->data->{vgs}{host_uuid}{$scan_lvm_vg_host_uuid}{scan_lvm_vg_internal_uuid}{$scan_lvm_vg_internal_uuid}{scan_lvm_vg_free},
}});
}
}
sub get_storage_data
{
my ($anvil) = @_;
my $query = "
SELECT
storage_group_uuid,
storage_group_anvil_uuid,
storage_group_name
FROM
storage_groups
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, 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 => 3, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $storage_group_uuid = $row->[0];
my $storage_group_anvil_uuid = $row->[1];
my $storage_group_name = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
storage_group_uuid => $storage_group_uuid,
storage_group_anvil_uuid => $storage_group_anvil_uuid,
storage_group_name => $storage_group_name,
}});
$anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid} = $storage_group_uuid;
$anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name} = $storage_group_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"storage_groups::anvil_uuid::${storage_group_anvil_uuid}::storage_group_name::${storage_group_name}::storage_group_uuid" => $anvil->data->{storage_groups}{anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name}{$storage_group_name}{storage_group_uuid},
"storage_groups::storage_group_uuid::${storage_group_uuid}::storage_group_anvil_uuid::${storage_group_anvil_uuid}::storage_group_name" => $anvil->data->{storage_groups}{storage_group_uuid}{$storage_group_uuid}{storage_group_anvil_uuid}{$storage_group_anvil_uuid}{storage_group_name},
}});
}
return(0);
}

@ -32,8 +32,7 @@ $| = 1;
my $anvil = Anvil::Tools->new();
# Read switches (target ([user@]host[:port]) and the file with the target's password. If the password is
# passed directly, it will be used. Otherwise, the password will be read from the database.
# Read switches
$anvil->Get->switches({list => [
"anvil",
"anvil-name",
@ -2742,7 +2741,7 @@ sub interactive_ask_server_os
}
}
$anvil->Get->virsh_list_os({debug => 2});
$anvil->Get->virsh_list_os();
foreach my $os_code (split/,/, $anvil->data->{sys}{servers}{os_short_list})
{
$os_code =~ s/ //g;
@ -2842,6 +2841,7 @@ sub interactive_ask_server_confirm
$anvil->Database->get_anvils();
$anvil->Database->get_files();
$anvil->Database->get_file_locations();
$anvil->Get->virsh_list_os();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"new_server::anvil_uuid" => $anvil->data->{new_server}{anvil_uuid},

@ -66,6 +66,9 @@ sub striker_checks
# This converts the old/broken 'notifications' tables with the more appropriately named 'alert-override'
update_notifications($anvil);
# This adds notes to storage_group_members
update_storage_group_members($anvil);
### NOTE: Disabled until review complete
# This checks to make sure that the 'audits' table exists (added late into M3.0 pre-release)
#update_audits($anvil);
@ -304,6 +307,64 @@ CREATE TRIGGER trigger_audits
return(0);
}
sub update_storage_group_members
{
my ($anvil) = @_;
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 = 'storage_group_members' AND column_name = 'storage_group_member_note';";
$anvil->Log->variables({source => $THIS_FILE, uuid => $uuid, line => __LINE__, level => 2, list => { query => $query }});
my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { count => $count }});
if (not $count)
{
my $queries = [];
push @{$queries}, "ALTER TABLE public.storage_group_members ADD COLUMN storage_group_member_note text not null DEFAULT '';";
push @{$queries}, "ALTER TABLE history.storage_group_members ADD COLUMN storage_group_member_note text not null DEFAULT '';";
push @{$queries}, "DROP FUNCTION history_storage_group_members() CASCADE;";
push @{$queries}, q|CREATE FUNCTION history_storage_group_members() RETURNS trigger
AS $$
DECLARE
history_storage_group_members RECORD;
BEGIN
SELECT INTO history_storage_group_members * FROM storage_group_members WHERE storage_group_member_uuid = new.storage_group_member_uuid;
INSERT INTO history.storage_group_members
(storage_group_member_uuid,
storage_group_member_storage_group_uuid,
storage_group_member_host_uuid,
storage_group_member_vg_uuid,
storage_group_member_note,
modified_date)
VALUES
(history_storage_group_members.storage_group_member_uuid,
history_storage_group_members.storage_group_member_storage_group_uuid,
history_storage_group_members.storage_group_member_host_uuid,
history_storage_group_members.storage_group_member_vg_uuid,
history_storage_group_members.storage_group_member_note,
history_storage_group_members.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_storage_group_members() OWNER TO admin;
CREATE TRIGGER trigger_storage_group_members
AFTER INSERT OR UPDATE ON storage_group_members
FOR EACH ROW EXECUTE PROCEDURE history_storage_group_members();|;
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__});
}
}
return(0);
}
# This converts the old/broken 'notifications' tables with the more appropriately named 'alert-override'
sub update_notifications
{

@ -82,7 +82,6 @@ my $conf = {
getent => "/usr/bin/getent",
logger => "/usr/bin/logger",
pcs => "/usr/sbin/pcs",
stonith_admin => "/usr/sbin/stonith_admin",
},
},
# The script will set this.
@ -738,7 +737,7 @@ sub kill_target
my ($conf) = @_;
# Variables
my $shell_call = $conf->{path}{exe}{stonith_admin}." --fence ".$conf->{cluster}{target_node}." --reboot --verbose; RC=\$?; ".$conf->{path}{exe}{crm_error}." \$RC; ".$conf->{path}{exe}{echo}." rc:\$RC";
my $shell_call = $conf->{path}{exe}{pcs}." stonith fence ".$conf->{cluster}{target_node}."; ".$conf->{path}{exe}{echo}." rc:\$?";
to_log($conf, {message => "Calling: [".$shell_call."]", 'line' => __LINE__, level => 2});
open (my $file_handle, $shell_call." 2>&1 |") or die "Failed to call: [".$shell_call."]. The error was: $!\n";
while(<$file_handle>)

@ -41,17 +41,14 @@ $| = 1;
my $anvil = Anvil::Tools->new();
# Read switches
$anvil->data->{switches}{list} = "";
$anvil->data->{switches}{add} = 0;
$anvil->data->{switches}{remove} = 0;
$anvil->data->{switches}{'job-uuid'} = "";
$anvil->data->{switches}{'host-uuid'} = "";
$anvil->data->{switches}{'host'} = "";
$anvil->data->{switches}{'port'} = 5432;
$anvil->data->{switches}{'password-file'} = "";
$anvil->data->{switches}{'ping'} = 0;
$anvil->Get->switches;
$anvil->Get->switches({list => ["add", "list", "remove", "host", "host-uuid", "job-uuid", "port", "password-file", "ping"], 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, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
if ($anvil->data->{switches}{'port'} eq "")
{
$anvil->data->{switches}{'port'} = 5432;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, secure => 1, level => 3, list => { "switches::port" => $anvil->data->{switches}{'port'} }});
}
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
@ -63,7 +60,10 @@ if (($< != 0) && ($> != 0))
}
# We'll try to connect in case we're adding additional peers.
$anvil->Database->connect({check_for_resync => 1});
$anvil->Database->connect({
debug => 3,
check_for_resync => 1,
});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
# Am I adding, editing or deleting?

@ -50,7 +50,6 @@ my $conf = {
getent => "/usr/bin/getent",
logger => "/usr/bin/logger",
pcs => "/usr/sbin/pcs",
stonith_admin => "/usr/sbin/stonith_admin",
},
},
# The script will set this.

Loading…
Cancel
Save