* Renamed the database table 'host_keys' to 'ssh_keys' to better represent what it stores.

* Updated 'variables' -> 'variable_source_uuid' to type 'uuid' and removed the 'not null' constraint.
* Updated Database->insert_or_update_variables() to check/update 'variables_source_table' and 'variables_source_uuid'.
* Created the 'trusts' database table which will, when done, tell anvil-daemon which users@machines to trust (setup passwordkess SSH).
* Created (but not finished) System->manage_authorized_keys() and moved the logic over to it from anvil-daemon.
* Changed the host types "dashboard" to "striker".
* Moved the following methods from 'System' to 'Get';
** System->get_host_type to Get->host_type
** System->get_bridges to Get->bridges
** System->get_free_memory to Get->free_memory
** System->get_os_type to Get->os_type
** System->get_uptime to Get->uptime
* Updated striker to include the host_uuid for the 'node1', 'node2' and (if chosen) 'dr1' when running a job manifest.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 5 years ago
parent e9e18f8e3b
commit 726a4374d1
  1. 5
      Anvil/Tools.pm
  2. 190
      Anvil/Tools/Database.pm
  3. 327
      Anvil/Tools/Get.pm
  4. 2
      Anvil/Tools/Server.pm
  5. 2
      Anvil/Tools/Striker.pm
  6. 742
      Anvil/Tools/System.pm
  7. 75
      cgi-bin/striker
  8. 269
      notes
  9. 4
      ocf/alteeve/server
  10. 14
      rpm/SPECS/anvil.spec
  11. 70
      share/anvil.sql
  12. 6
      tools/anvil-configure-host
  13. 427
      tools/anvil-daemon
  14. 88
      tools/anvil-join-anvil
  15. 2
      tools/anvil-manage-firewall
  16. 2
      tools/anvil-manage-power
  17. 8
      tools/anvil-update-states
  18. 6
      tools/striker-manage-install-target
  19. 8
      tools/test.pl

@ -882,7 +882,7 @@ sub _set_defaults
# grep 'CREATE TABLE' share/anvil.sql | grep -v history. | awk '{print $3}'
core_tables => [
"hosts", # Always has to be first.
"host_keys",
"ssh_keys",
"users",
"host_variable",
"sessions", # Has to come after users and hosts
@ -908,6 +908,7 @@ sub _set_defaults
"states",
"manifests",
"fences",
"upses",
],
failed_connection_log_level => 1,
local_lock_active => 0,
@ -1065,7 +1066,7 @@ sub _set_paths
pxe_default => "/var/lib/tftpboot/pxelinux.cfg/default",
pxe_uefi => "/var/lib/tftpboot/pxelinux.cfg/uefi",
ssh_config => "/etc/ssh/ssh_config",
'type.dashboard' => "/etc/anvil/type.dashboard",
'type.striker' => "/etc/anvil/type.striker",
'type.dr' => "/etc/anvil/type.dr",
'type.node' => "/etc/anvil/type.node",
},

@ -40,7 +40,7 @@ my $THIS_FILE = "Database.pm";
# insert_or_update_fences
# insert_or_update_file_locations
# insert_or_update_files
# insert_or_update_host_keys
# insert_or_update_ssh_keys
# insert_or_update_hosts
# insert_or_update_ip_addresses
# insert_or_update_jobs
@ -164,9 +164,9 @@ sub archive_database
}
# If this isn't a dashboard, exit.
my $host_type = $anvil->System->get_host_type();
my $host_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
if ($host_type ne "dashboard")
if ($host_type ne "striker")
{
# Not a dashboard, don't archive
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0452"});
@ -4584,9 +4584,9 @@ WHERE
}
=head2 insert_or_update_host_keys
=head2 insert_or_update_ssh_keys
This updates (or inserts) a record in the 'host_keys' table. The C<< host_key_uuid >> UUID will be returned.
This updates (or inserts) a record in the 'ssh_keys' table. The C<< ssh_key_uuid >> UUID will be returned.
If there is an error, an empty string is returned.
@ -4604,73 +4604,73 @@ If set, this is the file name logged as the source of any INSERTs or UPDATEs.
If set, this is the file line number logged as the source of any INSERTs or UPDATEs.
=head3 host_key_host_uuid (optional, default is Get->host_uuid)
=head3 ssh_key_host_uuid (optional, default is Get->host_uuid)
This is the host that the corresponding user and key belong to.
=head3 host_key_public_key (required)
=head3 ssh_key_public_key (required)
This is the B<<PUBLIC>> key for the user, the full line stored in the user's C<< ~/.ssh/id_rsa.pub >> file.
=head3 host_key_user_name (required)
=head3 ssh_key_user_name (required)
This is the name of the user that the public key belongs to.
=head3 host_key_uuid (optional)
=head3 ssh_key_uuid (optional)
This is the specific record to update. If not provides, a search will be made to find a matching entry. If found, the record will be updated if one of the values has changed. If not, a new record will be inserted.
=cut
sub insert_or_update_host_keys
sub insert_or_update_ssh_keys
{
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->insert_or_update_host_keys()" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->insert_or_update_ssh_keys()" }});
my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : "";
my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $line = defined $parameter->{line} ? $parameter->{line} : "";
my $host_key_host_uuid = defined $parameter->{host_key_host_uuid} ? $parameter->{host_key_host_uuid} : $anvil->Get->host_uuid;
my $host_key_public_key = defined $parameter->{host_key_public_key} ? $parameter->{host_key_public_key} : "";
my $host_key_user_name = defined $parameter->{host_key_user_name} ? $parameter->{host_key_user_name} : "";
my $host_key_uuid = defined $parameter->{host_key_uuid} ? $parameter->{host_key_uuid} : "";
my $ssh_key_host_uuid = defined $parameter->{ssh_key_host_uuid} ? $parameter->{ssh_key_host_uuid} : $anvil->Get->host_uuid;
my $ssh_key_public_key = defined $parameter->{ssh_key_public_key} ? $parameter->{ssh_key_public_key} : "";
my $ssh_key_user_name = defined $parameter->{ssh_key_user_name} ? $parameter->{ssh_key_user_name} : "";
my $ssh_key_uuid = defined $parameter->{ssh_key_uuid} ? $parameter->{ssh_key_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
file => $file,
line => $line,
host_key_host_uuid => $host_key_host_uuid,
host_key_public_key => $host_key_public_key,
host_key_user_name => $host_key_user_name,
host_key_uuid => $host_key_uuid,
ssh_key_host_uuid => $ssh_key_host_uuid,
ssh_key_public_key => $ssh_key_public_key,
ssh_key_user_name => $ssh_key_user_name,
ssh_key_uuid => $ssh_key_uuid,
}});
if (not $host_key_public_key)
if (not $ssh_key_public_key)
{
# 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_host_keys()", parameter => "host_key_public_key" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_ssh_keys()", parameter => "ssh_key_public_key" }});
return("");
}
if (not $host_key_user_name)
if (not $ssh_key_user_name)
{
# 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_host_keys()", parameter => "host_key_user_name" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_ssh_keys()", parameter => "ssh_key_user_name" }});
return("");
}
# If we don't have a UUID, see if we can find one for the given user and host.
if (not $host_key_uuid)
if (not $ssh_key_uuid)
{
my $query = "
SELECT
host_key_uuid
ssh_key_uuid
FROM
host_keys
ssh_keys
WHERE
host_key_user_name = ".$anvil->Database->quote($host_key_user_name)."
ssh_key_user_name = ".$anvil->Database->quote($ssh_key_user_name)."
AND
host_key_host_uuid = ".$anvil->Database->quote($host_key_host_uuid)."
ssh_key_host_uuid = ".$anvil->Database->quote($ssh_key_host_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
@ -4682,33 +4682,33 @@ AND
}});
if ($count)
{
$host_key_uuid = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_key_uuid => $host_key_uuid }});
$ssh_key_uuid = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ssh_key_uuid => $ssh_key_uuid }});
}
}
# If I still don't have an host_key_uuid, we're INSERT'ing .
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_key_uuid => $host_key_uuid }});
if (not $host_key_uuid)
# If I still don't have an ssh_key_uuid, we're INSERT'ing .
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ssh_key_uuid => $ssh_key_uuid }});
if (not $ssh_key_uuid)
{
# INSERT
$host_key_uuid = $anvil->Get->uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_key_uuid => $host_key_uuid }});
$ssh_key_uuid = $anvil->Get->uuid();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ssh_key_uuid => $ssh_key_uuid }});
my $query = "
INSERT INTO
host_keys
ssh_keys
(
host_key_uuid,
host_key_host_uuid,
host_key_public_key,
host_key_user_name,
ssh_key_uuid,
ssh_key_host_uuid,
ssh_key_public_key,
ssh_key_user_name,
modified_date
) VALUES (
".$anvil->Database->quote($host_key_uuid).",
".$anvil->Database->quote($host_key_host_uuid).",
".$anvil->Database->quote($host_key_public_key).",
".$anvil->Database->quote($host_key_user_name).",
".$anvil->Database->quote($ssh_key_uuid).",
".$anvil->Database->quote($ssh_key_host_uuid).",
".$anvil->Database->quote($ssh_key_public_key).",
".$anvil->Database->quote($ssh_key_user_name).",
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
);
";
@ -4720,13 +4720,13 @@ INSERT INTO
# Query the rest of the values and see if anything changed.
my $query = "
SELECT
host_key_host_uuid,
host_key_public_key,
host_key_user_name
ssh_key_host_uuid,
ssh_key_public_key,
ssh_key_user_name
FROM
host_keys
ssh_keys
WHERE
host_key_uuid = ".$anvil->Database->quote($host_key_uuid)."
ssh_key_uuid = ".$anvil->Database->quote($ssh_key_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
@ -4738,37 +4738,37 @@ WHERE
}});
if (not $count)
{
# I have a host_key_uuid but no matching record. Probably an error.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0216", variables => { uuid_name => "host_key_uuid", uuid => $host_key_uuid }});
# I have a ssh_key_uuid but no matching record. Probably an error.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0216", variables => { uuid_name => "ssh_key_uuid", uuid => $ssh_key_uuid }});
return("");
}
foreach my $row (@{$results})
{
my $old_host_key_host_uuid = $row->[0];
my $old_host_key_public_key = $row->[1];
my $old_host_key_user_name = $row->[2];
my $old_ssh_key_host_uuid = $row->[0];
my $old_ssh_key_public_key = $row->[1];
my $old_ssh_key_user_name = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_host_key_host_uuid => $old_host_key_host_uuid,
old_host_key_public_key => $old_host_key_public_key,
old_host_key_user_name => $old_host_key_user_name,
old_ssh_key_host_uuid => $old_ssh_key_host_uuid,
old_ssh_key_public_key => $old_ssh_key_public_key,
old_ssh_key_user_name => $old_ssh_key_user_name,
}});
# Anything change?
if (($old_host_key_host_uuid ne $host_key_host_uuid) or
($old_host_key_public_key ne $host_key_public_key) or
($old_host_key_user_name ne $host_key_user_name))
if (($old_ssh_key_host_uuid ne $ssh_key_host_uuid) or
($old_ssh_key_public_key ne $ssh_key_public_key) or
($old_ssh_key_user_name ne $ssh_key_user_name))
{
# Something changed, save.
my $query = "
UPDATE
host_keys
ssh_keys
SET
host_key_host_uuid = ".$anvil->Database->quote($host_key_host_uuid).",
host_key_public_key = ".$anvil->Database->quote($host_key_public_key).",
host_key_user_name = ".$anvil->Database->quote($host_key_user_name).",
ssh_key_host_uuid = ".$anvil->Database->quote($ssh_key_host_uuid).",
ssh_key_public_key = ".$anvil->Database->quote($ssh_key_public_key).",
ssh_key_user_name = ".$anvil->Database->quote($ssh_key_user_name).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
host_key_uuid = ".$anvil->Database->quote($host_key_uuid)."
ssh_key_uuid = ".$anvil->Database->quote($ssh_key_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__});
@ -4776,8 +4776,8 @@ WHERE
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_key_uuid => $host_key_uuid }});
return($host_key_uuid);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ssh_key_uuid => $ssh_key_uuid }});
return($ssh_key_uuid);
}
@ -4832,7 +4832,7 @@ This default value is the local host name.
=head3 host_type (required)
This default value is the value returned by C<< System->get_host_type >>.
This default value is the value returned by C<< Get->host_type >>.
=head3 host_uuid (required)
@ -4853,7 +4853,7 @@ sub insert_or_update_hosts
my $host_ipmi = defined $parameter->{host_ipmi} ? $parameter->{host_ipmi} : "";
my $host_key = defined $parameter->{host_key} ? $parameter->{host_key} : "";
my $host_name = defined $parameter->{host_name} ? $parameter->{host_name} : $anvil->_host_name;
my $host_type = defined $parameter->{host_type} ? $parameter->{host_type} : $anvil->System->get_host_type;
my $host_type = defined $parameter->{host_type} ? $parameter->{host_type} : $anvil->Get->host_type;
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
@ -6269,11 +6269,9 @@ sub insert_or_update_manifests
return("");
}
# If we don't have a network interface UUID, try to look one up using the MAC address
# If we don't have an install manifest UUID, try to look one up using the manifest name.
if (not $manifest_uuid)
{
# See if I know this NIC by referencing it's MAC and name. The name is needed because virtual
# devices can share the MAC with the real interface.
my $query = "
SELECT
manifest_uuid,
@ -6398,6 +6396,13 @@ WHERE
old_manifest_note => $old_manifest_note,
}});
# If we're here and 'manifest_last_ran' is am empty string, use the old value.
if ($manifest_last_ran eq "")
{
$manifest_last_ran = $old_manifest_last_ran;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { manifest_last_ran => $manifest_last_ran }});
}
# Anything to update? This is a little extra complicated because if a variable was
# not passed in, we want to not compare it.
if (($manifest_name ne $old_manifest_name) or
@ -8817,7 +8822,7 @@ sub insert_or_update_variables
my $variable_default = defined $parameter->{variable_default} ? $parameter->{variable_default} : "";
my $variable_description = defined $parameter->{variable_description} ? $parameter->{variable_description} : "";
my $variable_section = defined $parameter->{variable_section} ? $parameter->{variable_section} : "";
my $variable_source_uuid = defined $parameter->{variable_source_uuid} ? $parameter->{variable_source_uuid} : "";
my $variable_source_uuid = defined $parameter->{variable_source_uuid} ? $parameter->{variable_source_uuid} : "NULL";
my $variable_source_table = defined $parameter->{variable_source_table} ? $parameter->{variable_source_table} : "";
my $update_value_only = defined $parameter->{update_value_only} ? $parameter->{update_value_only} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
@ -8870,7 +8875,7 @@ FROM
variables
WHERE
variable_name = ".$anvil->Database->quote($variable_name);
if (($variable_source_uuid ne "") && ($variable_source_table ne ""))
if (($variable_source_uuid ne "NULL") && ($variable_source_table ne ""))
{
$query .= "
AND
@ -8880,6 +8885,7 @@ AND
";
}
$query .= ";";
$query =~ s/'NULL'/NULL/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
@ -8949,6 +8955,7 @@ INSERT INTO
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
);
";
$query =~ s/'NULL'/NULL/g;
$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__});
@ -8965,7 +8972,7 @@ FROM
variables
WHERE
variable_uuid = ".$anvil->Database->quote($variable_uuid);
if (($variable_source_uuid ne "") && ($variable_source_table ne ""))
if (($variable_source_uuid ne "NULL") && ($variable_source_table ne ""))
{
$query .= "
AND
@ -8975,6 +8982,7 @@ AND
";
}
$query .= ";";
$query =~ s/'NULL'/NULL/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
@ -9010,7 +9018,7 @@ SET
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
variable_uuid = ".$anvil->Database->quote($variable_uuid);
if (($variable_source_uuid ne "") && ($variable_source_table ne ""))
if (($variable_source_uuid ne "NULL") && ($variable_source_table ne ""))
{
$query .= "
AND
@ -9020,6 +9028,7 @@ AND
";
}
$query .= ";";
$query =~ s/'NULL'/NULL/g;
$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__});
@ -9035,12 +9044,15 @@ SELECT
variable_value,
variable_default,
variable_description,
variable_section
variable_section,
variable_source_table,
variable_source_uuid
FROM
variables
WHERE
variable_uuid = ".$anvil->Database->quote($variable_uuid)."
;";
$query =~ s/'NULL'/NULL/g;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
@ -9062,12 +9074,16 @@ WHERE
my $old_variable_default = $row->[2];
my $old_variable_description = $row->[3];
my $old_variable_section = $row->[4];
my $old_variable_source_table = $row->[5];
my $old_variable_source_uuid = defined $row->[6] ? $row->[6] : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_variable_name => $old_variable_name,
old_variable_value => $old_variable_value,
old_variable_default => $old_variable_default,
old_variable_description => $old_variable_description,
old_variable_section => $old_variable_section,
old_variable_source_table => $old_variable_source_table,
old_variable_source_uuid => $old_variable_source_uuid,
}});
# Anything change?
@ -9075,7 +9091,9 @@ WHERE
($old_variable_value ne $variable_value) or
($old_variable_default ne $variable_default) or
($old_variable_description ne $variable_description) or
($old_variable_section ne $variable_section))
($old_variable_section ne $variable_section) or
($old_variable_source_table ne $variable_source_table) or
($old_variable_source_uuid ne $variable_source_uuid))
{
# Something changed, save.
my $query = "
@ -9087,10 +9105,13 @@ SET
variable_default = ".$anvil->Database->quote($variable_default).",
variable_description = ".$anvil->Database->quote($variable_description).",
variable_section = ".$anvil->Database->quote($variable_section).",
variable_source_table = ".$anvil->Database->quote($variable_source_table).",
variable_source_uuid = ".$anvil->Database->quote($variable_source_uuid).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
variable_uuid = ".$anvil->Database->quote($variable_uuid)."
";
$query =~ s/'NULL'/NULL/g;
$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__});
@ -10111,7 +10132,7 @@ sub read
This reads a variable from the C<< variables >> table. Be sure to only use the reply from here to override what might have been set in a config file. This method always returns the data from the database itself.
The method returns an array reference containing, in order, the variable's value, database UUID and last modified date stamp.
The method returns an array reference containing, in order, the variable's value, database UUID and last modified date stamp in unix time (since epoch) and last as a normal time stamp.
If anything goes wrong, C<< !!error!! >> is returned. If the variable didn't exist in the database, an empty string will be returned for the UUID, value and modified date.
@ -10167,7 +10188,8 @@ sub read_variable
SELECT
variable_value,
variable_uuid,
round(extract(epoch from modified_date)) AS mtime
round(extract(epoch from modified_date)) AS mtime,
modified_date
FROM
variables
WHERE ";
@ -10194,6 +10216,7 @@ AND
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0124", variables => { query => $query }});
my $variable_value = "";
my $mtime = "";
my $modified_date = "";
my $results = $anvil->Database->query({uuid => $uuid, query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
@ -10205,10 +10228,12 @@ AND
{
$variable_value = $row->[0];
$variable_uuid = $row->[1];
$modified_date = $row->[2];
$mtime = $row->[2];
$modified_date = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
variable_value => $variable_value,
variable_uuid => $variable_uuid,
mtime => $mtime,
modified_date => $modified_date,
}});
}
@ -10216,9 +10241,10 @@ AND
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
variable_value => $variable_value,
variable_uuid => $variable_uuid,
mtime => $mtime,
modified_date => $modified_date,
}});
return($variable_value, $variable_uuid, $modified_date);
return($variable_value, $variable_uuid, $mtime, $modified_date);
}

@ -16,11 +16,16 @@ my $THIS_FILE = "Get.pm";
### Methods;
# anvil_version
# bridges
# cgi
# date_and_time
# free_memory
# host_type
# host_uuid
# md5sum
# os_type
# switches
# uptime
# users_home
# uuid
# _salt
@ -239,6 +244,98 @@ fi;
return($version);
}
=head2 bridges
This finds a list of bridges on the host. Bridges that are found are stored is '
=cut
sub bridges
{
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 => "Get->bridges()" }});
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{bridge}." -json -details link show"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
# Delete any previously known data
if (exists $anvil->data->{'local'}{network}{bridges})
{
delete $anvil->data->{'local'}{network}{bridges};
};
my $json = JSON->new->allow_nonref;
my $bridge_data = $json->decode($output);
#print Dumper $bridge_data;
foreach my $hash_ref (@{$bridge_data})
{
# If the ifname and master are the same, it's a bridge.
my $type = "interface";
my $interface = $hash_ref->{ifname};
my $master_bridge = $hash_ref->{master};
if ($interface eq $master_bridge)
{
$type = "bridge";
$anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::bridge::${interface}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found},
}});
}
else
{
# Store this interface under the bridge.
$anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::bridge::${master_bridge}::connected_interface::${interface}" => $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface},
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
interface => $interface,
master_bridge => $master_bridge,
type => $type,
}});
foreach my $key (sort {$a cmp $b} keys %{$hash_ref})
{
if (ref($hash_ref->{$key}) eq "ARRAY")
{
$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key} = [];
foreach my $value (sort {$a cmp $b} @{$hash_ref->{$key}})
{
push @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}}, $value;
}
for (my $i = 0; $i < @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}}; $i++)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::${type}::${interface}::${key}->[$i]" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}->[$i],
}});
}
}
else
{
$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key} = $hash_ref->{$key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::${type}::${interface}::${key}" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key},
}});
}
}
}
# Summary of found bridges.
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{'local'}{network}{bridges}{bridge}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::bridge::${interface}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found},
}});
}
return(0);
}
=head2 cgi
This reads in the CGI variables passed in by a form or URL.
@ -561,6 +658,142 @@ WHERE
return($host_name);
}
=head2 free_memory
This returns, in bytes, host much free memory is available on the local system.
=cut
### TODO: Make this work on remote systems.
sub free_memory
{
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 => "Get->free_memory()" }});
my $available = 0;
my ($free_output, $free_rc) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{free}." --bytes"});
foreach my $line (split/\n/, $free_output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line =~ /Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/)
{
my $total = $1;
my $used = $2;
my $free = $3;
my $shared = $4;
my $cache = $5;
$available = $6;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
total => $total." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $total})."})",
used => $used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $used})."})",
free => $free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $free})."})",
shared => $shared." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $shared})."})",
cache => $cache." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $cache})."})",
available => $available." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $available})."})",
}});
}
}
return($available);
}
=head2 host_type
This method tries to determine the host type and returns a value suitable for use is the C<< hosts >> table.
my $type = $anvil->System->host_type();
First, it looks to see if C<< sys::host_type >> is set and, if so, uses that string as it is.
If that isn't set, it then looks to see if the file C<< /etc/anvil/type.X >> exists, where C<< X >> is C<< node >>, C<< striker >> or C<< dr >>. If found, the appropriate type is returned.
If that file doesn't exist, then it then checks to see which C<< anvil-<type> >> rpm is installed. In order, it looks for C<< anvil-striker >>, then C<< anvil-node >> and finally C<< anvil-dr >>. If one of them is found, the appropriate C<< /etc/anvil/type.X >> is created.
=cut
sub host_type
{
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 => "Get->host_type()" }});
my $host_type = "";
my $host_name = $anvil->_short_host_name;
$host_type = "unknown";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_type => $host_type,
host_name => $host_name,
"sys::host_type" => $anvil->data->{sys}{host_type},
}});
if ($anvil->data->{sys}{host_type})
{
$host_type = $anvil->data->{sys}{host_type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
else
{
# Can I determine it by seeing a file?
if (-e $anvil->data->{path}{configs}{'type.node'})
{
$host_type = "node";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
elsif (-e $anvil->data->{path}{configs}{'type.striker'})
{
$host_type = "striker";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
elsif (-e $anvil->data->{path}{configs}{'type.dr'})
{
$host_type = "dr";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
else
{
# Last gasp here is to use 'rpm' to see which RPMs are installed. If we find one,
# we'll touch 'type.X' file
foreach my $rpm ("anvil-striker", "anvil-node", "anvil-dr")
{
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{rpm}." -q ".$rpm});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
if ($return_code eq "0")
{
# Found out what we are.
if ($rpm eq "anvil-striker")
{
$host_type = "striker";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
my $key = "type.".$host_type;
my $file = $anvil->data->{path}{configs}{$key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
key => $key,
file => $file,
}});
# If we have a file and we're root, touch to the file.
if (($file) && (($< == 0) or ($> == 0)))
{
my $error = $anvil->Storage->write_file({
debug => $debug,
body => "",
file => $file,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 0, list => { error => $error }});
}
last;
}
}
}
}
return($host_type);
}
=head2 host_uuid
This returns the local host's system UUID (as reported by 'dmidecode'). If the host UUID isn't available, and the program is not running with root priviledges, C<< #!error!# >> is returned.
@ -704,6 +937,68 @@ sub md5sum
return($sum);
}
=head2 os_type
This returns the operating system type and the system architecture as two separate string variables.
# Run on RHEL 8, on a 64-bit system
my ($os_type, $os_arch) = $anvil->Get->os_type();
# '$os_type' holds 'rhel8' ('rhel' or 'centos' + release version)
# '$os_arch' holds 'x86_64' (specifically, 'uname --hardware-platform')
If either can not be determined, C<< unknown >> will be returned.
This method takes no parameters.
=cut
sub get_os_type
{
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 => "Get->os_type()" }});
my $os_type = "unknown";
my $os_arch = "unknown";
### NOTE: Examples;
# Red Hat Enterprise Linux release 8.0 Beta (Ootpa)
# Red Hat Enterprise Linux Server release 7.5 (Maipo)
# CentOS Linux release 7.5.1804 (Core)
# Read in the /etc/redhat-release file
my $release = $anvil->Storage->read_file({file => $anvil->data->{path}{data}{'redhat-release'}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { release => $release }});
if ($release =~ /Red Hat Enterprise Linux .* (\d+)\./)
{
# RHEL, with the major version number appended
$os_type = "rhel".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }});
}
elsif ($release =~ /CentOS .*? (\d+)\./)
{
# CentOS, with the major version number appended
$os_type = "centos".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }});
}
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{uname}." --hardware-platform"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
if ($output)
{
$os_arch = $output;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_arch => $os_arch }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
os_type => $os_type,
os_arch => $os_arch,
}});
return($os_type, $os_arch);
}
=head2 switches
This reads in the command line switches used to invoke the parent program.
@ -784,6 +1079,38 @@ sub switches
return(0);
}
=head2 uptime
This returns, in seconds, how long the host has been up and running for.
This method takes no parameters.
=cut
### TODO: Make this work on remote hosts
sub uptime
{
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 => "Get->uptime()" }});
my $uptime = $anvil->Storage->read_file({
force_read => 1,
cache => 0,
file => $anvil->data->{path}{proc}{uptime},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uptime => $uptime }});
# Clean it up. We'll have gotten two numbers, the uptime in seconds (to two decimal places) and the
# total idle time. We only care about the int number.
$uptime =~ s/^(\d+)\..*$/$1/;
$uptime =~ s/\n//gs;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uptime => $uptime }});
return($uptime);
}
=head2 users_home
This method takes a user's name and returns the user's home directory. If the home directory isn't found, C<< 0 >> is returned.

@ -226,7 +226,7 @@ sub find
delete $anvil->data->{server}{location};
}
my $host_type = $anvil->System->get_host_type({debug => $debug});
my $host_type = $anvil->Get->host_type({debug => $debug});
my $host = $anvil->_host_name;
my $virsh_output = "";
my $return_code = "";

@ -967,7 +967,7 @@ WHERE
foreach my $machine (sort {$a cmp $b} keys %{$parsed_xml->{machines}})
{
$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{name} = $parsed_xml->{machines}{$machine}{name};
$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ipmi_ip} = $parsed_xml->{machines}{$machine}{ipmi_ip};
$anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ipmi_ip} = defined $parsed_xml->{machines}{$machine}{ipmi_ip} ? $parsed_xml->{machines}{$machine}{ipmi_ip} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::type" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{type},
"manifests::manifest_uuid::${manifest_uuid}::parsed::machine::${machine}::ipmi_ip" => $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{ipmi_ip},

@ -11,6 +11,7 @@ use Time::HiRes qw(gettimeofday tv_interval);
use Proc::Simple;
use NetAddr::IP;
use JSON;
use Text::Diff;
our $VERSION = "3.0.0";
my $THIS_FILE = "System.pm";
@ -26,13 +27,9 @@ my $THIS_FILE = "System.pm";
# disable_daemon
# enable_daemon
# find_matching_ip
# get_bridges
# get_free_memory
# get_host_type
# get_uptime
# get_os_type
# host_name
# maintenance_mode
# manage_authorized_keys
# manage_firewall
# read_ssh_config
# reload_daemon
@ -615,6 +612,373 @@ sub check_memory
return($used_ram);
}
=head2 check_ssh_keys
This method does several things;
1. This makes sure the users on this system have SSH keys, and creates the keys if needed.
2. It records the user's keys in the C<< ssh_keys >> table.
3. For the dashboard machines it uses, it adds their host machine public key (SSH fingerprint) to C<< ~/.ssh/known_hosts >>.
4. If this machine is a node or DR host, it sets up passwordless SSH between the other machines in the same Anvil! system.
This works on the C<< admin >> and C<< root >> users. If the host is a node, it will also work on the c<< hacluster >> user.
B<< Note >>: If a machine's fingerprint changes, this method will NOT update C<< ~/.ssh/known_hosts >>! You will see an alert on the Striker dashboard prompting you to clear the bad keys (or, if that wasn't expected, find the "man in the middle" attacker).
This method takes no parameters.
=cut
sub check_ssh_keys
{
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 => "System->check_memory()" }});
# We do a couple things here. First we make sure our user's keys are up to date and stored in the
# 'ssh_keys' table. Then we look through the 'trusts' table for any other users@hosts we're supposed
# to trust. For each, we make sure that they're in the appropriate local user's authorized_keys file.
my $users = $anvil->Get->host_type eq "node" ? ["root", "admin", "hacluster"] : ["root", "admin"];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { users => \@{$users} }});
# Get a list of machine host keys and user public keys from other machines.
#get_other_keys($anvil);
# Users to check:
foreach my $user (@{$users})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user => $user }});
my $user_home = $anvil->Get->users_home({user => $user});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user_home => $user_home }});
# If the user doesn't exist, their home directory won't either, so skip.
next if not $user_home;
next if not -d $user_home;
# If the user's ~/.ssh directory doesn't exist, we need to create it.
my $ssh_directory = $user_home."/.ssh";
$ssh_directory =~ s/\/\//\//g;
if (not -e $ssh_directory)
{
# Create it.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0272", variables => { user => $user, directory => $ssh_directory }});
$anvil->Storage->make_directory({
debug => $debug,
directory => $ssh_directory,
user => $user,
group => $user,
mode => "0700",
});
if (not -e $ssh_directory)
{
# Failed ?
next;
}
}
my $ssh_private_key_file = $user_home."/.ssh/id_rsa";
my $ssh_public_key_file = $user_home."/.ssh/id_rsa.pub";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
ssh_public_key_file => $ssh_public_key_file,
ssh_private_key_file => $ssh_private_key_file,
}});
if (not -e $ssh_public_key_file)
{
# Generate the SSH keys.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0270", variables => { user => $user }});
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{'ssh-keygen'}." -t rsa -N \"\" -b 8191 -f ".$ssh_private_key_file});
if (-e $ssh_public_key_file)
{
# Success!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0271", variables => { user => $user, output => $output }});
}
else
{
# Failed?
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "error_0057", variables => { user => $user, output => $output }});
next;
}
}
# Now read in the key.
my $users_public_key = $anvil->Storage->read_file({
debug => $debug,
file => $ssh_public_key_file,
});
$users_public_key =~ s/\n$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { users_public_key => $users_public_key }});
# Now store the key in the 'ssh_key' table, if needed.
my $ssh_key_uuid = $anvil->Database->insert_or_update_ssh_keys({
debug => $debug,
ssh_key_host_uuid => $anvil->Get->host_uuid,
ssh_key_public_key => $users_public_key,
ssh_key_user_name => $user,
});
# Read in the existing 'known_hosts' file, if it exists. The 'old' and 'new' variables will
# be used when looking for needed changes.
my $known_hosts_file_body = "";
my $known_hosts_old_body = "";
my $known_hosts_new_body = "";
my $known_hosts_file = $ssh_directory."/known_hosts";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { known_hosts_file => $known_hosts_file }});
if (-e $known_hosts_file)
{
$known_hosts_file_body = $anvil->Storage->read_file({
debug => $debug,
file => $known_hosts_file,
});
$known_hosts_old_body = $known_hosts_file_body;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { known_hosts_file_body => $known_hosts_file_body }});
}
# Read in the existing 'authorized_keys' file, if it exists.
my $authorized_keys_file_body = "";
my $authorized_keys_old_body = "";
my $authorized_keys_new_body = "";
my $authorized_keys_file = $ssh_directory."/authorized_keys";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { authorized_keys_file => $authorized_keys_file }});
if (-e $authorized_keys_file)
{
$authorized_keys_file_body = $anvil->Storage->read_file({
debug => $debug,
file => $authorized_keys_file,
});
$authorized_keys_old_body = $authorized_keys_file_body;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { authorized_keys_file_body => $authorized_keys_file_body }});
}
### Walk through each host we now know of. As we we do, loop through the old file body to see
### if it exists. If it does, and the key has changed, update the line with the new key. If
### it isn't found, add it. Once we check the old body for this entry, change the "old" body
### to the new one, then repeat the process.
# Look at all the hosts I know about (other than myself) and see if any of the machine or
# user keys either don't exist or have changed.
my $update_known_hosts = 0;
my $update_authorized_keys = 0;
my $known_hosts_new_lines = "";
my $authorized_keys_new_lines = "";
# Check for changes to known_hosts
foreach my $host_uuid (keys %{$anvil->data->{peers}{ssh_keys}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{peers}{ssh_keys}{$host_uuid}{host}})
{
my $key = $anvil->data->{peers}{ssh_keys}{$host_uuid}{host}{$host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:host_name' => $host_name,
's2:key' => $key,
}});
# Is this in the file and, if so, has it changed?
my $found = 0;
my $test_line = $host_name." ".$key;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_line => $test_line }});
foreach my $line (split/\n/, $known_hosts_old_body)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line eq $test_line)
{
# No change needed, key is the same.
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
}
elsif ($line =~ /^$host_name /)
{
# Key has changed, update.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0274", variables => {
machine => $host_name,
old_key => $line,
new_key => $test_line,
}});
$found = 1;
$line = $test_line;
$update_known_hosts = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
found => $found,
line => $line,
update_known_hosts => $update_known_hosts,
}});
}
$known_hosts_new_body .= $line."\n";
}
# If we didn't find the key, add it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
if (not $found)
{
$update_known_hosts = 1;
$known_hosts_new_lines .= $test_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:update_known_hosts' => $update_known_hosts,
's2:known_hosts_new_lines' => $known_hosts_new_lines,
}});
}
# Move the new body over to the old body (even though it may not have
# changed) and then clear the new body to prepare for the next pass.
$known_hosts_old_body = $known_hosts_new_body;
$known_hosts_new_body = "";
}
}
# Lastly, copy the last version of the old body to the new body,
$known_hosts_new_body = $known_hosts_old_body.$known_hosts_new_lines;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:update_known_hosts' => $update_known_hosts,
's2:known_hosts_file_body' => $known_hosts_file_body,
's3:known_hosts_new_body' => $known_hosts_new_body,
's4:difference' => diff \$known_hosts_file_body, \$known_hosts_new_body, { STYLE => 'Unified' },
}});
### TODO: Change this to not use all hosts, but on dashboards we use, plus if we're in an Anvil!, those machines.
=cut
# Check for changes to authorized_keys
foreach my $host_uuid (keys %{$anvil->data->{peers}{ssh_keys}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
foreach my $ssh_key_user_name (sort {$a cmp $b} keys %{$anvil->data->{peers}{ssh_keys}{$host_uuid}{user}})
{
my $ssh_key_public_key = $anvil->data->{peers}{ssh_keys}{$host_uuid}{user}{$ssh_key_user_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:ssh_key_user_name' => $ssh_key_user_name,
's2:ssh_key_public_key' => $ssh_key_public_key,
}});
# The key in the file might have a different trailing suffix (user@host_name)
# and doesn't really matter. So we search by the key type and public key to
# see if it exists already.
my $found = 0;
my $test_line = ($ssh_key_public_key =~ /^(ssh-.*? .*?) /)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { test_line => $test_line }});
foreach my $line (split/\n/, $authorized_keys_old_body)
{
# NOTE: Use '\Q...\E' so that the '+' characters in the key aren't
# evaluated as part of the regex.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^\Q$test_line\E/)
{
# No change needed, key is the same.
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
}
# We don't look for changes (yet). Might be worth looking for stale
# keys by ckecking of the host at the end matches an entry in the
# database and then verifying the keys haven't changed, but that's
# for another day.
$authorized_keys_new_body .= $line."\n";
}
# If we didn't find the key, add it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { found => $found }});
if (not $found)
{
$update_authorized_keys = 1;
$authorized_keys_new_lines .= $ssh_key_public_key."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:update_authorized_keys' => $update_authorized_keys,
's2:authorized_keys_new_lines' => $authorized_keys_new_lines,
}});
}
# Move the new body over to the old body (even though it may not have
# changed) and then clear the new body to prepare for the next pass.
$authorized_keys_old_body = $authorized_keys_new_body;
$authorized_keys_new_body = "";
}
}
# Lastly, copy the last version of the old body to the new body,
$authorized_keys_new_body = $authorized_keys_old_body.$authorized_keys_new_lines;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:update_authorized_keys' => $update_authorized_keys,
's2:authorized_keys_file_body' => $authorized_keys_file_body,
's3:authorized_keys_new_body' => $authorized_keys_new_body,
's4:difference' => diff \$authorized_keys_file_body, \$authorized_keys_new_body, { STYLE => 'Unified' },
}});
=cut
# Update the known_hosts files, if needed.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { update_known_hosts => $update_known_hosts }});
if ($update_known_hosts)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0273", variables => { user => $user, file => $known_hosts_file }});
if (-e $known_hosts_file)
{
my $backup_file = $anvil->Storage->backup({
debug => $debug,
fatal => 1,
file => $known_hosts_file,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { backup_file => $backup_file }});
if (-e $backup_file)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0154", variables => { source_file => $known_hosts_file, target_file => $backup_file }});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "error_0058", variables => { file => $known_hosts_file }});
}
}
my $failed = $anvil->Storage->write_file({
debug => $debug,
overwrite => 1,
file => $known_hosts_file,
body => $known_hosts_new_body,
user => $user,
group => $user,
mode => "0644",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { failed => $failed }});
}
# Update the authorized_keys files, if needed.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { update_authorized_keys => $update_authorized_keys }});
if ($update_authorized_keys)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0273", variables => { user => $user, file => $authorized_keys_file }});
if (-e $authorized_keys_file)
{
my $backup_file = $anvil->Storage->backup({
debug => $debug,
fatal => 1,
file => $authorized_keys_file,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { backup_file => $backup_file }});
if (-e $backup_file)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0154", variables => { source_file => $authorized_keys_file, target_file => $backup_file }});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "error_0058", variables => { file => $authorized_keys_file }});
}
}
my $failed = $anvil->Storage->write_file({
debug => $debug,
overwrite => 1,
file => $authorized_keys_file,
body => $authorized_keys_new_body,
user => $user,
group => $user,
mode => "0644",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { failed => $failed }});
}
}
return(0);
}
=head2 check_storage
Thic gathers LVM data from the local system.
@ -1240,139 +1604,6 @@ sub generate_state_json
return(0);
}
=head2 get_bridges
This finds a list of bridges on the host. Bridges that are found are stored is '
=cut
sub get_bridges
{
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 => "System->get_bridges()" }});
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{bridge}." -json -details link show"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
# Delete any previously known data
if (exists $anvil->data->{'local'}{network}{bridges})
{
delete $anvil->data->{'local'}{network}{bridges};
};
my $json = JSON->new->allow_nonref;
my $bridge_data = $json->decode($output);
#print Dumper $bridge_data;
foreach my $hash_ref (@{$bridge_data})
{
# If the ifname and master are the same, it's a bridge.
my $type = "interface";
my $interface = $hash_ref->{ifname};
my $master_bridge = $hash_ref->{master};
if ($interface eq $master_bridge)
{
$type = "bridge";
$anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::bridge::${interface}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found},
}});
}
else
{
# Store this interface under the bridge.
$anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface} = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::bridge::${master_bridge}::connected_interface::${interface}" => $anvil->data->{'local'}{network}{bridges}{bridge}{$master_bridge}{connected_interface}{$interface},
}});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
interface => $interface,
master_bridge => $master_bridge,
type => $type,
}});
foreach my $key (sort {$a cmp $b} keys %{$hash_ref})
{
if (ref($hash_ref->{$key}) eq "ARRAY")
{
$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key} = [];
foreach my $value (sort {$a cmp $b} @{$hash_ref->{$key}})
{
push @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}}, $value;
}
for (my $i = 0; $i < @{$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}}; $i++)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::${type}::${interface}::${key}->[$i]" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key}->[$i],
}});
}
}
else
{
$anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key} = $hash_ref->{$key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::${type}::${interface}::${key}" => $anvil->data->{'local'}{network}{bridges}{$type}{$interface}{$key},
}});
}
}
}
# Summary of found bridges.
foreach my $interface (sort {$a cmp $b} keys %{$anvil->data->{'local'}{network}{bridges}{bridge}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"local::network::bridges::bridge::${interface}::found" => $anvil->data->{'local'}{network}{bridges}{bridge}{$interface}{found},
}});
}
return(0);
}
=head2 get_free_memory
This returns, in bytes, host much free memory is available on the local system.
=cut
### TODO: Make this work on remote systems.
sub get_free_memory
{
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 => "System->get_free_memory()" }});
my $available = 0;
my ($free_output, $free_rc) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{free}." --bytes"});
foreach my $line (split/\n/, $free_output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line =~ /Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/)
{
my $total = $1;
my $used = $2;
my $free = $3;
my $shared = $4;
my $cache = $5;
$available = $6;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
total => $total." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $total})."})",
used => $used." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $used})."})",
free => $free." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $free})."})",
shared => $shared." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $shared})."})",
cache => $cache." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $cache})."})",
available => $available." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $available})."})",
}});
}
}
return($available);
}
=head2 enable_daemon
This method enables a daemon (so that it starts when the OS boots). The return code from the start request will be returned.
@ -1492,175 +1723,6 @@ sub find_matching_ip
return($local_ip);
}
=head2 get_host_type
This method tries to determine the host type and returns a value suitable for use is the C<< hosts >> table.
my $type = $anvil->System->get_host_type();
First, it looks to see if C<< sys::host_type >> is set and, if so, uses that string as it is.
If that isn't set, it then looks to see if the file C<< /etc/anvil/type.X >> exists, where C<< X >> is C<< node >>, C<< dashboard >> or C<< dr >>. If found, the appropriate type is returned.
If that file doesn't exist, then it looks at the short host name. The following rules are used, in order;
1. If the host name ends in C<< n<digits> >> or C<< node<digits> >>, C<< node >> is returned.
2. If the host name ends in C<< striker<digits> >> or C<< dashboard<digits> >>, C<< dashboard >> is returned.
3. If the host name ends in C<< dr<digits> >>, C<< dr >> is returned.
=cut
sub get_host_type
{
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 => "System->get_host_type()" }});
my $host_type = "";
my $host_name = $anvil->_short_host_name;
$host_type = "unknown";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
host_type => $host_type,
host_name => $host_name,
"sys::host_type" => $anvil->data->{sys}{host_type},
}});
if ($anvil->data->{sys}{host_type})
{
$host_type = $anvil->data->{sys}{host_type};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
else
{
# Can I determine it by seeing a file?
if (-e $anvil->data->{path}{configs}{'type.node'})
{
$host_type = "node";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
elsif (-e $anvil->data->{path}{configs}{'type.dashboard'})
{
$host_type = "dashboard";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
elsif (-e $anvil->data->{path}{configs}{'type.dr'})
{
$host_type = "dr";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
elsif (($host_name =~ /n\d+$/) or ($host_name =~ /node\d+$/) or ($host_name =~ /new-node+$/))
{
$host_type = "node";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
elsif (($host_name =~ /striker\d+$/) or ($host_name =~ /dashboard\d+$/))
{
$host_type = "dashboard";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
elsif (($host_name =~ /dr\d+$/) or ($host_name =~ /new-dr$/))
{
$host_type = "dr";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_type => $host_type }});
}
}
return($host_type);
}
=head2 get_uptime
This returns, in seconds, how long the host has been up and running for.
This method takes no parameters.
=cut
sub get_uptime
{
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 => "System->get_uptime()" }});
my $uptime = $anvil->Storage->read_file({
force_read => 1,
cache => 0,
file => $anvil->data->{path}{proc}{uptime},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uptime => $uptime }});
# Clean it up. We'll have gotten two numbers, the uptime in seconds (to two decimal places) and the
# total idle time. We only care about the int number.
$uptime =~ s/^(\d+)\..*$/$1/;
$uptime =~ s/\n//gs;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { uptime => $uptime }});
return($uptime);
}
=head2 get_os_type
This returns the operating system type and the system architecture as two separate string variables.
# Run on RHEL 8, on a 64-bit system
my ($os_type, $os_arch) = $anvil->System->get_os_type();
# '$os_type' holds 'rhel8' ('rhel' or 'centos' + release version)
# '$os_arch' holds 'x86_64' (specifically, 'uname --hardware-platform')
If either can not be determined, C<< unknown >> will be returned.
This method takes no parameters.
=cut
sub get_os_type
{
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 => "System->get_os_type()" }});
my $os_type = "unknown";
my $os_arch = "unknown";
### NOTE: Examples;
# Red Hat Enterprise Linux release 8.0 Beta (Ootpa)
# Red Hat Enterprise Linux Server release 7.5 (Maipo)
# CentOS Linux release 7.5.1804 (Core)
# Read in the /etc/redhat-release file
my $release = $anvil->Storage->read_file({file => $anvil->data->{path}{data}{'redhat-release'}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { release => $release }});
if ($release =~ /Red Hat Enterprise Linux .* (\d+)\./)
{
# RHEL, with the major version number appended
$os_type = "rhel".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }});
}
elsif ($release =~ /CentOS .*? (\d+)\./)
{
# CentOS, with the major version number appended
$os_type = "centos".$1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_type => $os_type }});
}
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{uname}." --hardware-platform"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { output => $output, return_code => $return_code }});
if ($output)
{
$os_arch = $output;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { os_arch => $os_arch }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
os_type => $os_type,
os_arch => $os_arch,
}});
return($os_type, $os_arch);
}
=head2 host_name
Get or set the local host name. The current (or new) "static" (traditional) host name and the "pretty" (descriptive) host names are returned.
@ -1967,7 +2029,7 @@ sub check_firewall
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 => "System->manage_firewall()" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "System->check_firewall()" }});
# Show live or permanent rules? Permanent is default
my $permanent = defined $parameter->{permanent} ? $parameter->{permanent} : 1;
@ -2086,6 +2148,70 @@ sub check_firewall
return(0);
}
=head2 manage_authorized_keys
This takes a host's UUID and will adds or removes their ssh public key to the target host user (or users). On success, C<< 0 >> is returned. Otherwise, C<< 1 >> is returned.
Parameters;
=head3 host_uuid (required)
This is the C<< hosts >> -> C<< host_uuid >> whose key we're adding or removing. When adding, the C<<
=head3 password (optional)
This is the password to use when connecting to a remote machine. If not set, but C<< target >> is, an attempt to connect without a password will be made.
=head3 port (optional)
This is the TCP port to use when connecting to a remote machine. If not set, but C<< target >> is, C<< 22 >> will be used.
=head3 remote_user (optional, default root)
If C<< target >> is set, this will be the user we connect to the remote machine as.
=head3 target (optional, default 'local')
This is the IP or host name of the machine to manage keys on. If not passed, the keys on the local machine will be managed.
=head3 users (optional)
This is a comma separated list of users whose keys are being managed. If not set, the default on Striker and DR Hosts is C<< root,admin >> and on nodes it is C<< root,admin,hacluster >>.
=cut
sub manage_authorized_keys
{
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 => "System->manage_authorized_keys()" }});
my $host_uuid = defined $parameter->{host_uuid} ? $parameter->{host_uuid} : "";
my $password = defined $parameter->{password} ? $parameter->{password} : "";
my $port = defined $parameter->{port} ? $parameter->{port} : "";
my $remote_user = defined $parameter->{remote_user} ? $parameter->{remote_user} : "root";
my $target = defined $parameter->{target} ? $parameter->{target} : "";
my $users = defined $parameter->{users} ? $parameter->{users} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
target => $target,
port => $port,
remote_user => $remote_user,
password => $anvil->Log->is_secure($password),
users => $users,
}});
if (not $users)
{
$users = $anvil->Striker->get_host_type eq "node" ? "root,admin,hacluster" : "root,admin";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { users => $users }});
}
return(0);
}
=head2 manage_firewall
This method manages a firewalld firewall.

@ -1572,7 +1572,7 @@ sub run_manifest
$anvil->data->{cgi}{password}{value} = "" if not defined $anvil->data->{cgi}{password}{value};
$anvil->data->{cgi}{password}{alert} = 0 if not defined $anvil->data->{cgi}{password}{alert};
$anvil->Database->get_hosts();
$anvil->Database->get_hosts({debug => 2});
my $manifest_uuid = $anvil->data->{cgi}{manifest_uuid}{value};
my $problem = $anvil->Striker->load_manifest({
debug => 2,
@ -1671,15 +1671,15 @@ sub run_manifest
}
# Check that the machines selected didn't get added to another anvil while looking.
my $node1_host_name = $anvil->data->{cgi}{node1_host}{value};
my $node1_host_uuid = $anvil->data->{sys}{hosts}{by_name}{$node1_host_name};
my $node1_host_uuid = $anvil->data->{cgi}{node1_host}{value};
my $node1_host_name = $anvil->data->{sys}{hosts}{by_uuid}{$node1_host_uuid};
my $node1_anvil = $anvil->data->{hosts}{host_uuid}{$node1_host_uuid}{anvil_name};
my $node2_host_name = $anvil->data->{cgi}{node2_host}{value};
my $node2_host_uuid = $anvil->data->{sys}{hosts}{by_name}{$node2_host_name};
my $node2_host_uuid = $anvil->data->{cgi}{node2_host}{value};
my $node2_host_name = $anvil->data->{sys}{hosts}{by_uuid}{$node2_host_uuid};
my $node2_anvil = $anvil->data->{hosts}{host_uuid}{$node2_host_uuid}{anvil_name};
my $dr1_host_name = $anvil->data->{cgi}{dr1_host}{value};
my $dr1_host_uuid = $dr1_host_name ? $anvil->data->{sys}{hosts}{by_name}{$dr1_host_name} : "";
my $dr1_anvil = $dr1_host_name ? $anvil->data->{hosts}{host_uuid}{$dr1_host_uuid}{anvil_name} : "";
my $dr1_host_uuid = $anvil->data->{cgi}{dr1_host}{value};
my $dr1_host_name = $dr1_host_uuid ? $anvil->data->{sys}{hosts}{by_uuid}{$dr1_host_uuid} : "";
my $dr1_anvil = $dr1_host_uuid ? $anvil->data->{hosts}{host_uuid}{$dr1_host_uuid}{anvil_name} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
node1_host_name => $node1_host_name,
node1_host_uuid => $node1_host_uuid,
@ -1753,7 +1753,7 @@ sub run_manifest
line => __LINE__,
job_host_uuid => $node1_host_uuid,
job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'},
job_data => "as_machine=node1,manifest_uuid=".$manifest_uuid,
job_data => "as_machine=node1,manifest_uuid=".$manifest_uuid.",node1_host_uuid=".$node1_host_uuid.",node2_host_uuid=".$node2_host_uuid.",dr1_host_uuid=".$dr1_host_uuid,
job_name => "join_anvil::node1",
job_title => "job_0072",
job_description => "job_0073",
@ -1767,7 +1767,7 @@ sub run_manifest
line => __LINE__,
job_host_uuid => $node2_host_uuid,
job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'},
job_data => "as_machine=node2,manifest_uuid=".$manifest_uuid,
job_data => "as_machine=node2,manifest_uuid=".$manifest_uuid.",node1_host_uuid=".$node1_host_uuid.",node2_host_uuid=".$node2_host_uuid.",dr1_host_uuid=".$dr1_host_uuid,
job_name => "join_anvil::node2",
job_title => "job_0072",
job_description => "job_0073",
@ -1783,7 +1783,7 @@ sub run_manifest
line => __LINE__,
job_host_uuid => $dr1_host_uuid,
job_command => $anvil->data->{path}{exe}{'anvil-join-anvil'},
job_data => "as_machine=dr1,manifest_uuid=".$manifest_uuid,
job_data => "as_machine=dr1,manifest_uuid=".$manifest_uuid.",node1_host_uuid=".$node1_host_uuid.",node2_host_uuid=".$node2_host_uuid.",dr1_host_uuid=".$dr1_host_uuid,
job_name => "join_anvil::dr1",
job_title => "job_0072",
job_description => "job_0073",
@ -1829,27 +1829,27 @@ sub run_manifest
if ($host_type eq "node")
{
push @{$nodes}, $host_name;
push @{$nodes}, $host_uuid."#!#".$host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
if ((not defined $anvil->data->{cgi}{node1_host}{value}) && ($host_name eq $node1_name))
{
$anvil->data->{cgi}{node1_host}{value} = $host_name;
$anvil->data->{cgi}{node1_host}{value} = $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node1_host::value" => $anvil->data->{cgi}{node1_host}{value} }});
}
elsif ((not defined $anvil->data->{cgi}{node2_host}{value}) && ($host_name eq $node2_name))
{
$anvil->data->{cgi}{node2_host}{value} = $host_name;
$anvil->data->{cgi}{node2_host}{value} = $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node2_host::value" => $anvil->data->{cgi}{node2_host}{value} }});
}
}
elsif ($host_type eq "dr")
{
push @{$dr_hosts}, $host_name;
push @{$dr_hosts}, $host_uuid."#!#".$host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { host_name => $host_name }});
if ((not defined $anvil->data->{cgi}{dr1_host}{value}) && ($host_name eq $dr1_name))
{
$anvil->data->{cgi}{dr1_host}{value} = $host_name;
$anvil->data->{cgi}{dr1_host}{value} = $host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::dr1_host::value" => $anvil->data->{cgi}{dr1_host}{value} }});
}
}
@ -1857,7 +1857,9 @@ sub run_manifest
# We're going to need three selects; one for each node and one for DR. The DR is allowed to
# be unselected so it has an empty entry.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node1_host::value" => $anvil->data->{cgi}{node1_host}{value} }});
my $select_node1 = $anvil->Template->select_form({
debug => 2,
name => "node1_host",
options => $nodes,
blank => 0,
@ -1866,8 +1868,11 @@ sub run_manifest
class => $anvil->data->{cgi}{node1_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { select_node1 => $select_node1 }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::node2_host::value" => $anvil->data->{cgi}{node2_host}{value} }});
my $select_node2 = $anvil->Template->select_form({
debug => 2,
name => "node2_host",
options => $nodes,
blank => 0,
@ -1876,8 +1881,11 @@ sub run_manifest
class => $anvil->data->{cgi}{node2_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { select_node2 => $select_node2 }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::dr1_host::value" => $anvil->data->{cgi}{dr1_host}{value} }});
my $select_dr1 = $anvil->Template->select_form({
debug => 2,
name => "dr1_host",
options => $dr_hosts,
blank => 1,
@ -1886,6 +1894,7 @@ sub run_manifest
class => $anvil->data->{cgi}{dr1_host}{alert} ? "input_alert" : "input_clear",
style => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { select_dr1 => $select_dr1 }});
# Show the networks.
my $networks = "";
@ -2274,17 +2283,17 @@ sub handle_manifest
if (not $anvil->data->{cgi}{ifn_count}{value})
{
$anvil->data->{cgi}{ifn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{ifn_count};
$anvil->data->{cgi}{ifn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{ifn};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::ifn_count::value" => $anvil->data->{cgi}{ifn_count}{value} }});
}
if (not $anvil->data->{cgi}{sn_count}{value})
{
$anvil->data->{cgi}{sn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{sn_count};
$anvil->data->{cgi}{sn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{sn};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::sn_count::value" => $anvil->data->{cgi}{sn_count}{value} }});
}
if (not $anvil->data->{cgi}{bcn_count}{value})
{
$anvil->data->{cgi}{bcn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{bcn_count};
$anvil->data->{cgi}{bcn_count}{value} = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{networks}{count}{bcn};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { "cgi::bcn_count::value" => $anvil->data->{cgi}{bcn_count}{value} }});
}
}
@ -6570,9 +6579,21 @@ sub configure_striker
{
# Sanity check step1.
my $sane = sanity_check_step1($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { sane => $sane }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
if ($sane)
{
# We're mapping, so tell anvil-daemon to
$anvil->Database->insert_or_update_variables({
debug => 2,
variable_name => "config::map_network",
variable_value => 1,
variable_default => 0,
variable_description => "striker_0202",
variable_section => "config",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
# Step 1 was sane, show step 2.
$anvil->data->{form}{body} = config_step2($anvil);
}
@ -6586,9 +6607,21 @@ sub configure_striker
{
# Sanity check step1.
my $sane = sanity_check_step2($anvil);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { sane => $sane }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { sane => $sane }});
if ($sane)
{
# Also, we're done mapping
$anvil->Database->insert_or_update_variables({
debug => 2,
variable_name => "config::map_network",
variable_value => 0,
variable_default => 0,
variable_description => "striker_0202",
variable_section => "config",
variable_source_uuid => $anvil->Get->host_uuid,
variable_source_table => "hosts",
});
# Step 2 was sane, show step 3.
$anvil->data->{form}{body} = config_step3($anvil);
}

269
notes

@ -42,37 +42,6 @@ DOCS; -
====
dnf download --source awscli booth booth-arbitrator booth-core booth-site booth-test corosync corosync-qdevice corosync-qnetd corosynclib-devel fence-agents-aliyun fence-agents-aws fence-agents-azure-arm fence-agents-gce libknet1 \
libknet1-compress-bzip2-plugin libknet1-compress-lz4-plugin libknet1-compress-lzma-plugin libknet1-compress-lzo2-plugin libknet1-compress-plugins-all libknet1-compress-zlib-plugin libknet1-crypto-nss-plugin \
libknet1-crypto-openssl-plugin libknet1-crypto-plugins-all libknet1-plugins-all pacemaker pacemaker-cli pacemaker-cts pacemaker-doc pacemaker-libs-devel pacemaker-nagios-plugins-metadata pacemaker-remote \
pcs pcs-snmp python3-azure-sdk python3-boto3 python3-botocore python3-fasteners python3-gflags python3-google-api-client python3-httplib2 python3-oauth2client python3-s3transfer python3-uritemplate \
resource-agents resource-agents-aliyun resource-agents-gcp
rpm -Uvh python-s3transfer-0.1.13-1.el8.src.rpm python-oauth2client-4.1.2-6.el8.src.rpm booth-1.0-5.f2d38ce.git.el8.src.rpm google-api-python-client-1.6.5-3.el8.src.rpm python-boto3-1.6.1-2.el8.src.rpm python-httplib2-0.10.3-4.el8.src.rpm python-botocore-1.9.1-2.el8.src.rpm corosync-qdevice-3.0.0-2.el8.src.rpm python-uritemplate-3.0.0-3.el8.src.rpm python3-azure-sdk-4.0.0-9.el8.src.rpm awscli-1.14.50-5.el8.src.rpm python-gflags-2.0-15.el8ost.src.rpm resource-agents-4.1.1-33.el8.src.rpm pcs-0.10.2-4.el8.src.rpm fence-agents-4.2.1-30.el8_1.1.src.rpm
rpm -Uvh python-fasteners-0.14.1-15.el8ost.src.rpm
rpm -Uvh awscli-1.14.50-5.el8.src.rpm booth-1.0-5.f2d38ce.git.el8.src.rpm corosync-qdevice-3.0.0-2.el8.src.rpm fence-agents-4.2.1-30.el8.1.src.rpm google-api-python-client-1.6.5-3.el8.src.rpm pacemaker-2.0.2-3.el8.2.src.rpm \
pcs-0.10.2-4.el8.src.rpm python-boto3-1.6.1-2.el8.src.rpm python-botocore-1.9.1-2.el8.src.rpm python-gflags-2.0-15.el8.src.rpm python-httplib2-0.10.3-4.el8.src.rpm python-oauth2client-4.1.2-6.el8.src.rpm \
python-s3transfer-0.1.13-1.el8.src.rpm python-uritemplate-3.0.0-3.el8.src.rpm python3-azure-sdk-4.0.0-9.el8.src.rpm resource-agents-4.1.1-33.el8.src.rpm
rpmbuild -ba --sign pcs.spec
rpmbuild -ba --sign python3-azure-sdk.spec
rpmbuild -ba --sign python-s3transfer.spec python-oauth2client.spec booth.spec google-api-python-client.spec python-boto3.spec python-httplib2.spec python-botocore.spec corosync-qdevice.spec python-uritemplate.spec awscli.spec python-gflags.spec resource-agents.spec fence-agents.spec
# rpmbuild -ba python-fasteners.spec
### Need to find/build
python2-futures
python2-monotonic
dnf install booth-site corosync corosynclib-devel pacemaker pacemaker-cli pacemaker-libs-devel pcs
Network planning;
10.x.y.z / 255.255.0.0
@ -252,219 +221,6 @@ hosts:
10.255.22.1 m3-a02dr01.ifn
====
### Interface files
#
# Note: Insert the HWADDR's and update the IPs!
#
### BCN #######################################################################
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-BCN_1_-_Link_1 << EOF
# Back-Channel Network 1 - Link 1
HWADDR=""
UUID="${UUID}"
NAME="BCN 1 - Link 1"
DEVICE="bcn1_link1"
TYPE="Ethernet"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
USERCTL="no"
MTU="1500"
NM_CONTROLLED="yes"
SLAVE="yes"
MASTER="bcn1_bond1"
ZONE="BCN1"
EOF
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-BCN_1_-_Link_2 << EOF
# Back-Channel Network 1 - Link 2
HWADDR=""
UUID="${UUID}"
NAME="BCN 1 - Link 2"
DEVICE="bcn1_link2"
TYPE="Ethernet"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
USERCTL="no"
MTU="1500"
NM_CONTROLLED="yes"
SLAVE="yes"
MASTER="bcn1_bond1"
ZONE="BCN1"
EOF
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-BCN_1_-_Bond_1 << EOF
# Back-Channel Network 1 - Bond 1
UUID="${UUID}"
NAME="BCN 1 - Bond 1"
DEVICE="bcn1_bond1"
BRIDGE="bcn1_bridge1"
BONDING_OPTS="mode=active-backup primary=bcn1_link1 updelay=120000 downdelay=0 miimon=100 primary_reselect=better"
TYPE="Bond"
BONDING_MASTER="yes"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
ZONE="BCN1"
EOF
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-BCN_1_-_Bridge_1 << EOF
# Back-Channel Network 1 - Bridge 1
UUID="${UUID}"
STP="yes"
BRIDGING_OPTS="priority=32768"
TYPE="Bridge"
BROWSER_ONLY="no"
NAME="BCN 1 - Bridge 1"
DEVICE="bcn1_bridge1"
ONBOOT="yes"
BOOTPROTO="none"
IPADDR="10.20.10.1"
PREFIX="16"
DEFROUTE="no"
ZONE="BCN1"
EOF
### SN ########################################################################
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-SN_1_-_Link_1 << EOF
# Storage Network 1 - Link 1
HWADDR=""
UUID="${UUID}"
NAME="SN 1 - Link 1"
DEVICE="sn1_link1"
TYPE="Ethernet"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
USERCTL="no"
MTU="1500"
NM_CONTROLLED="yes"
SLAVE="yes"
MASTER="sn1_bond1"
ZONE="SN1"
EOF
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-SN_1_-_Link_2 << EOF
# Storage Network 1 - Link 2
HWADDR=""
UUID="${UUID}"
NAME="SN 1 - Link 2"
DEVICE="sn1_link2"
TYPE="Ethernet"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
USERCTL="no"
MTU="1500"
NM_CONTROLLED="yes"
SLAVE="yes"
MASTER="sn1_bond1"
ZONE="SN1"
EOF
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-SN_1_-_Bond_1 << EOF
# Storage Network 1 - Bond 1
UUID="${UUID}"
NAME="SN 1 - Bond 1"
DEVICE="sn1_bond1"
BONDING_OPTS="mode=active-backup primary=sn1_link1 updelay=120000 downdelay=0 miimon=100 primary_reselect=better"
TYPE="Bond"
BONDING_MASTER="yes"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
IPADDR="10.41.10.1"
PREFIX="16"
DEFROUTE="no"
ZONE="SN1"
EOF
### IFN #######################################################################
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-IFN_1_-_Link_1 << EOF
# Internet-Facing Network 1 - Link 1
HWADDR=""
UUID="${UUID}"
NAME="IFN 1 - Link 1"
DEVICE="ifn1_link1"
TYPE="Ethernet"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
USERCTL="no"
MTU="1500"
NM_CONTROLLED="yes"
SLAVE="yes"
MASTER="ifn1_bond1"
ZONE="IFN1"
EOF
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-IFN_1_-_Link_2 << EOF
# Internet-Facing Network 1 - Link 2
HWADDR=""
UUID="${UUID}"
NAME="IFN 1 - Link 2"
DEVICE="ifn1_link2"
TYPE="Ethernet"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
USERCTL="no"
MTU="1500"
NM_CONTROLLED="yes"
SLAVE="yes"
MASTER="ifn1_bond1"
ZONE="IFN1"
EOF
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-IFN_1_-_Bond_1 << EOF
# Internet-Facing Network 1 - Bond 1
UUID="${UUID}"
NAME="IFN 1 - Bond 1"
DEVICE="ifn1_bond1"
BRIDGE="ifn1_bridge1"
BONDING_OPTS="mode=active-backup primary=ifn1_link1 updelay=120000 downdelay=0 miimon=100 primary_reselect=better"
TYPE="Bond"
BONDING_MASTER="yes"
BOOTPROTO="none"
IPV6INIT="no"
ONBOOT="yes"
MTU="1500"
ZONE="IFN1"
EOF
UUID=$(uuidgen)
cat > /etc/sysconfig/network-scripts/ifcfg-IFN_1_-_Bridge_1 << EOF
# Internet-Facing Network 1 - Bridge 1
UUID="${UUID}"
STP="yes"
BRIDGING_OPTS="priority=32768"
TYPE="Bridge"
BROWSER_ONLY="no"
NAME="IFN 1 - Bridge 1"
DEVICE="ifn1_bridge1"
ONBOOT="yes"
BOOTPROTO="none"
IPADDR="10.255.10.1"
PREFIX="16"
GATEWAY="10.255.255.254"
DNS1="8.8.8.8"
DNS2="8.8.4.4"
DEFROUTE="yes"
ZONE="IFN1"
EOF
====
=======
virt-manager stores information in dconf-editor -> /org/virt-manager/virt-manager/connections ($HOME/.config/dconf/user)
@ -481,30 +237,6 @@ restorecon -rv /var/www
=============================================================
How to rebuild all of the packages in the Alteeve RHEL 8 repo;
# Register if RHEL proper;
subscription-manager register --username <user> --password <secret> --auto-attach --force
subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-source-rpms
subscription-manager repos --enable rhel-8-for-x86_64-supplementary-source-rpms
subscription-manager repos --enable rhel-8-for-x86_64-baseos-rpms
subscription-manager repos --enable rhel-8-for-x86_64-appstream-source-rpms
subscription-manager repos --enable rhel-8-for-x86_64-supplementary-rpms
subscription-manager repos --enable rhel-8-for-x86_64-baseos-source-rpms
subscription-manager repos --enable rhel-8-for-x86_64-highavailability-source-rpms
subscription-manager repos --enable codeready-builder-for-rhel-8-x86_64-rpms
subscription-manager repos --enable rhel-8-for-x86_64-highavailability-rpms
subscription-manager repos --enable rhel-8-for-x86_64-appstream-rpms
repos => {
'rhel-8-for-x86_64-highavailability-rpms' => 0,
'codeready-builder-for-rhel-8-x86_64-rpms' => 0,
}
* Packages to install;
* Network;
** {bc,if,s}nX_{link,bond,bridge}Y naming
** firewall; - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/high_availability_add-on_reference/s1-firewalls-haar
@ -512,6 +244,7 @@ firewall-cmd --permanent --add-service=high-availability
firewall-cmd --add-service=high-availability
firewall-cmd --reload
* Cluster Config;
==== Both nodes
echo Initial1 | passwd hacluster --stdin

@ -947,7 +947,7 @@ sub validate_bridges
my ($anvil) = @_;
# Get my bridge list
$anvil->System->get_bridges({debug => 3});
$anvil->Get->bridges({debug => 3});
# Find the Optical drives and DRBD devices.
my $server = $anvil->data->{environment}{OCF_RESKEY_name};
@ -1190,7 +1190,7 @@ sub validate_ram
# How mcuh RAM does the server need and how much do we have free?
my $server = $anvil->data->{environment}{OCF_RESKEY_name};
my $server_ram_bytes = $anvil->data->{server}{'local'}{$server}{from_disk}{memory};
my $available = $anvil->System->get_free_memory({debug => 3});
my $available = $anvil->Get->free_memory({debug => 3});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
server_ram_bytes => $anvil->Convert->add_commas({number => $server_ram_bytes})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $server_ram_bytes}).")",
available => $anvil->Convert->add_commas({number => $available})." (".$anvil->Convert->bytes_to_human_readable({'bytes' => $available}).")",

@ -247,7 +247,7 @@ elif [ -e '/etc/anvil/type.dr' ]
then
rm -f /etc/anvil/type.dr
fi
touch /etc/anvil/type.dashboard
touch /etc/anvil/type.striker
### TODO: I don't think we need this anymore
@ -266,9 +266,9 @@ firewall-cmd --add-service=postgresql --permanent
%post node
# Touch the system type file.
echo "Touching the system type file"
if [ -e '/etc/anvil/type.dashboard' ]
if [ -e '/etc/anvil/type.striker' ]
then
rm -f /etc/anvil/type.dashboard
rm -f /etc/anvil/type.striker
elif [ -e '/etc/anvil/type.dr' ]
then
rm -f /etc/anvil/type.dr
@ -282,9 +282,9 @@ touch /etc/anvil/type.node
%post dr
# Touch the system type file.
echo "Touching the system type file"
if [ -e '/etc/anvil/type.dashboard' ]
if [ -e '/etc/anvil/type.striker' ]
then
rm -f /etc/anvil/type.dashboard
rm -f /etc/anvil/type.striker
elif [ -e '/etc/anvil/type.node' ]
then
rm -f /etc/anvil/type.node
@ -318,9 +318,9 @@ touch /etc/anvil/type.dr
# systemctl stop postgresql.service
# Remove the system type file.
if [ -e '/etc/anvil/type.dashboard' ]
if [ -e '/etc/anvil/type.striker' ]
then
rm -f /etc/anvil/type.dashboard
rm -f /etc/anvil/type.striker
fi
%postun node

@ -97,60 +97,60 @@ CREATE TRIGGER trigger_hosts
-- This stores the SSH _public_keys for a given user on a host.
CREATE TABLE host_keys (
host_key_uuid uuid not null primary key, -- This is the single most important record in Anvil!. Everything links back to here.
host_key_host_uuid uuid not null,
host_key_user_name text not null, -- This is the user name on the system, not a web interface user.
host_key_public_key text not null, -- Either 'node', 'dashboard' or 'dr'
CREATE TABLE ssh_keys (
ssh_key_uuid uuid not null primary key,
ssh_key_host_uuid uuid not null,
ssh_key_user_name text not null, -- This is the user name on the system, not a web interface user.
ssh_key_public_key text not null, -- Either 'node', 'dashboard' or 'dr'
modified_date timestamp with time zone not null,
FOREIGN KEY(host_key_host_uuid) REFERENCES hosts(host_uuid)
FOREIGN KEY(ssh_key_host_uuid) REFERENCES hosts(host_uuid)
);
ALTER TABLE host_keys OWNER TO admin;
ALTER TABLE ssh_keys OWNER TO admin;
CREATE TABLE history.host_keys (
CREATE TABLE history.ssh_keys (
history_id bigserial,
host_key_uuid uuid,
host_key_host_uuid uuid,
host_key_user_name text,
host_key_public_key text,
ssh_key_uuid uuid,
ssh_key_host_uuid uuid,
ssh_key_user_name text,
ssh_key_public_key text,
modified_date timestamp with time zone not null
);
ALTER TABLE history.host_keys OWNER TO admin;
ALTER TABLE history.ssh_keys OWNER TO admin;
CREATE FUNCTION history_host_keys() RETURNS trigger
CREATE FUNCTION history_ssh_keys() RETURNS trigger
AS $$
DECLARE
history_host_keys RECORD;
history_ssh_keys RECORD;
BEGIN
SELECT INTO history_host_keys * FROM host_keys WHERE host_key_uuid = new.host_key_uuid;
INSERT INTO history.host_keys
(host_key_uuid,
host_key_host_uuid,
host_key_user_name,
host_key_public_key,
SELECT INTO history_ssh_keys * FROM ssh_keys WHERE ssh_key_uuid = new.ssh_key_uuid;
INSERT INTO history.ssh_keys
(ssh_key_uuid,
ssh_key_host_uuid,
ssh_key_user_name,
ssh_key_public_key,
modified_date)
VALUES
(history_host_keys.host_key_uuid,
history_host_keys.host_key_host_uuid,
history_host_keys.host_key_user_name,
history_host_keys.host_key_public_key,
history_host_keys.modified_date);
(history_ssh_keys.ssh_key_uuid,
history_ssh_keys.ssh_key_host_uuid,
history_ssh_keys.ssh_key_user_name,
history_ssh_keys.ssh_key_public_key,
history_ssh_keys.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_host_keys() OWNER TO admin;
ALTER FUNCTION history_ssh_keys() OWNER TO admin;
CREATE TRIGGER trigger_host_keys
AFTER INSERT OR UPDATE ON host_keys
FOR EACH ROW EXECUTE PROCEDURE history_host_keys();
CREATE TRIGGER trigger_ssh_keys
AFTER INSERT OR UPDATE ON ssh_keys
FOR EACH ROW EXECUTE PROCEDURE history_ssh_keys();
-- This stores information about users.
-- Note that is all permissions are left false, the user can still interact with the Anvil! doing safe things, like changing optical media, perform migrations, start servers (but not stop them), etc.
CREATE TABLE users (
user_uuid uuid not null primary key, -- This is the single most important record in Anvil!. Everything links back to here.
user_uuid uuid not null primary key,
user_name text not null,
user_password_hash text not null, -- A user without a password is disabled.
user_salt text not null, -- This is used to enhance the security of the user's password.
@ -223,7 +223,7 @@ CREATE TRIGGER trigger_users
-- This stores special variables for a given host that programs may want to record.
CREATE TABLE host_variable (
host_variable_uuid uuid not null primary key, -- This is the single most important record in ScanCore. Everything links back to here.
host_variable_uuid uuid not null primary key,
host_variable_host_uuid uuid not null,
host_variable_name text not null,
host_variable_value text not null,
@ -274,7 +274,7 @@ CREATE TRIGGER trigger_host_variable
-- This stores user session information on a per-dashboard basis.
CREATE TABLE sessions (
session_uuid uuid not null primary key, -- This is the single most important record in Anvil!. Everything links back to here.
session_uuid uuid not null primary key,
session_host_uuid uuid not null, -- This is the host uuid for this session.
session_user_uuid uuid not null, -- This is the user uuid for the user logging in.
session_salt text not null, -- This is used when generating a session hash for a session when they log in.
@ -642,7 +642,7 @@ CREATE TABLE variables (
variable_default text not null, -- This acts as a reference for the user should they want to roll-back changes.
variable_description text not null, -- This is a string key that describes this variable's use.
variable_section text not null, -- This is a free-form field that is used when displaying the various entries to a user. This allows for the various variables to be grouped into sections.
variable_source_uuid text not null, -- Optional; Marks the variable as belonging to a specific X_uuid, where 'X' is a table name set in 'variable_source_table'
variable_source_uuid uuid, -- Optional; Marks the variable as belonging to a specific X_uuid, where 'X' is a table name set in 'variable_source_table'
variable_source_table text not null, -- Optional; Marks the database table corresponding to the 'variable_source_uuid' value.
modified_date timestamp with time zone not null
);
@ -656,7 +656,7 @@ CREATE TABLE history.variables (
variable_default text,
variable_description text,
variable_section text,
variable_source_uuid text,
variable_source_uuid uuid,
variable_source_table text,
modified_date timestamp with time zone not null
);

@ -168,7 +168,7 @@ sub reconfigure_network
my $sn_count = exists $anvil->data->{variables}{form}{config_step1}{sn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{sn_count}{value} : 0;
my $ifn_count = exists $anvil->data->{variables}{form}{config_step1}{ifn_count}{value} ? $anvil->data->{variables}{form}{config_step1}{ifn_count}{value} : 1;
my $new_host_name = exists $anvil->data->{variables}{form}{config_step2}{host_name}{value} ? $anvil->data->{variables}{form}{config_step2}{host_name}{value} : "";
my $type = $anvil->System->get_host_type();
my $type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, list => {
prefix => $prefix,
sequence => $sequence,
@ -182,7 +182,7 @@ sub reconfigure_network
}});
# If we're configuring a dashboard and no host name was given, generate it.
if (($type eq "dashboard") && (not $new_host_name))
if (($type eq "striker") && (not $new_host_name))
{
$new_host_name = $prefix."-striker".sprintf("%02d", $sequence).".".$domain;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, list => { new_host_name => $new_host_name }});
@ -191,7 +191,7 @@ sub reconfigure_network
if ($new_host_name)
{
my $type_name = "";
if ($type eq "dashboard")
if ($type eq "striker")
{
$type_name = $anvil->Words->string({key => "brand_0003"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, list => { type_name => $type_name }});

@ -81,7 +81,7 @@ if (not $anvil->data->{sys}{database}{connections})
{
# If this is a dashboard, try to configure and then connect to the local database. If this isn't a
# dashboard, then just go into a loop waiting for a database to be configured.
if ($anvil->System->get_host_type eq "dashboard")
if ($anvil->Get->host_type eq "striker")
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, secure => 0, key => "log_0201"});
prep_database($anvil);
@ -232,21 +232,25 @@ sub check_if_mapping
$anvil->data->{sys}{mapping_network} = 0;
if ($anvil->data->{sys}{database}{connections})
{
my ($map_network_value, $map_network_uuid, $map_network_modified_date) = $anvil->Database->read_variable({
my ($map_network_value, $map_network_uuid, $map_network_mtime, $map_network_modified_date) = $anvil->Database->read_variable({
debug => 3,
variable_name => "config::map_network",
variable_source_table => "hosts",
variable_source_uuid => $anvil->data->{sys}{host_uuid},
});
my $expire_age = 1200;
# We'll run for a day (should be cancelled by the program when the user's done, so this
# shouldn't fire in practice).
my $expire_age = 86400;
my $map_network_age = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:map_network_value' => $map_network_value,
's2:map_network_modified_date' => $map_network_modified_date,
's3:map_network_uuid' => $map_network_uuid,
's2:map_network_mtime' => $map_network_mtime,
's3:map_network_modified_date' => $map_network_modified_date,
's4:map_network_uuid' => $map_network_uuid,
}});
if ($map_network_uuid)
{
$map_network_age = time - $map_network_modified_date;
$map_network_age = time - $map_network_mtime;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { map_network_age => $map_network_age }});
}
if ($map_network_value)
@ -255,7 +259,7 @@ sub check_if_mapping
if ($map_network_age >= $expire_age)
{
# Clear it.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0470"});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0470"});
$anvil->Database->insert_or_update_variables({
debug => 3,
variable_value => 0,
@ -268,7 +272,7 @@ sub check_if_mapping
# Mark it so we only track the network.
my $say_age = $anvil->Convert->add_commas({number => $expire_age});
my $timeout = $anvil->Convert->add_commas({number => ($expire_age - $map_network_age)});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0471", variables => {
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0471", variables => {
age => $say_age,
timeout => $timeout,
}});
@ -280,7 +284,7 @@ sub check_if_mapping
foreach my $ssh_fh_key (keys %{$anvil->data->{cache}{ssh_fh}})
{
my $ssh_fh = $anvil->data->{cache}{ssh_fh}{$ssh_fh_key};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 1, list => {
ssh_fh_key => $ssh_fh_key,
ssh_fh => $ssh_fh,
}});
@ -304,9 +308,9 @@ sub set_delay
my ($anvil) = @_;
my $delay = 7200;
my $type = $anvil->System->get_host_type();
my $type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { type => $type }});
if ($type eq "dashboard")
if ($type eq "striker")
{
foreach my $uuid (sort {$a cmp $b} keys %{$anvil->data->{database}})
{
@ -338,7 +342,7 @@ sub handle_periodic_tasks
my ($anvil) = @_;
my $now_time = time;
my $type = $anvil->System->get_host_type();
my $type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"s1:now_time" => $now_time,
"s2:timing::next_minute_check" => $anvil->data->{timing}{next_minute_check},
@ -356,7 +360,7 @@ sub handle_periodic_tasks
check_install_target($anvil);
# Check that the users we care about have ssh public keys and they're recorded in ssh_keys.
check_ssh_keys($anvil);
$anvil->System->check_ssh_keys({debug => 3});
# Check if the files on disk have changed. Even if it is time to check, don't if a job is
# running.
@ -378,7 +382,7 @@ sub handle_periodic_tasks
}});
# If we're a dashboard, see if the fence information needs to be gathered.
if ($type eq "dashboard")
if ($type eq "striker")
{
# Even when this runs, it should finish in under ten seconds so we don't need to background it.
my ($parse_output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{'striker-parse-fence-agents'}, source => $THIS_FILE, line => __LINE__});
@ -429,7 +433,7 @@ sub handle_periodic_tasks
### NOTE: We call it once/day, but this will also trigger on restart of anvil-daemon. As such, we
### don't use '--force' and let striker-manage-install-target skip the repo update if it happened
### recently enough.
if ($type eq "dashboard")
if ($type eq "striker")
{
# Record a job, don't call it directly. It takes too long to run.
my ($job_uuid) = $anvil->Database->insert_or_update_jobs({
@ -482,346 +486,6 @@ sub handle_periodic_tasks
return(0);
}
# Check that the host's fingerprint and users we care about have ssh public keys and they're recorded in ssh_keys.
sub check_ssh_keys
{
my ($anvil) = @_;
### TODO: When a node is rebuilt, this causes the old keys to be reloaded between when we delete the entries. We need to delete the keys for the target IP from the 'ip_addresses' table.
return(0);
# Get a list of machine host keys and user public keys from other machines.
get_other_keys($anvil);
# Users to check:
# root, admin, hacluster
foreach my $user ("root", "admin")
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { user => $user }});
my $user_home = $anvil->Get->users_home({user => $user});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { user_home => $user_home }});
# If the user doesn't exist, their home directory won't either, so skip.
next if not $user_home;
next if not -d $user_home;
# If the user's ~/.ssh directory doesn't exist, we need to create it.
my $ssh_directory = $user_home."/.ssh";
$ssh_directory =~ s/\/\//\//g;
if (not -e $ssh_directory)
{
# Create it.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0272", variables => { user => $user, directory => $ssh_directory }});
$anvil->Storage->make_directory({
debug => 3,
directory => $ssh_directory,
user => $user,
group => $user,
mode => "0700",
});
if (not -e $ssh_directory)
{
# Failed ?
next;
}
}
my $ssh_private_key_file = $user_home."/.ssh/id_rsa";
my $ssh_public_key_file = $user_home."/.ssh/id_rsa.pub";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
ssh_public_key_file => $ssh_public_key_file,
ssh_private_key_file => $ssh_private_key_file,
}});
if (not -e $ssh_public_key_file)
{
# Generate the SSH keys.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0270", variables => { user => $user }});
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{'ssh-keygen'}." -t rsa -N \"\" -b 8191 -f ".$ssh_private_key_file});
if (-e $ssh_public_key_file)
{
# Success!
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0271", variables => { user => $user, output => $output }});
}
else
{
# Failed?
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "error_0057", variables => { user => $user, output => $output }});
next;
}
}
# Now read in the key.
my $users_public_key = $anvil->Storage->read_file({
debug => 3,
file => $ssh_public_key_file,
});
$users_public_key =~ s/\n$//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { users_public_key => $users_public_key }});
# Now store the key in the 'host_key' table, if needed.
my $host_key_uuid = $anvil->Database->insert_or_update_host_keys({
debug => 3,
host_key_host_uuid => $anvil->Get->host_uuid,
host_key_public_key => $users_public_key,
host_key_user_name => $user,
});
# Read in the existing 'known_hosts' file, if it exists. The 'old' and 'new' variables will
# be used when looking for needed changes.
my $known_hosts_file_body = "";
my $known_hosts_old_body = "";
my $known_hosts_new_body = "";
my $known_hosts_file = $ssh_directory."/known_hosts";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { known_hosts_file => $known_hosts_file }});
if (-e $known_hosts_file)
{
$known_hosts_file_body = $anvil->Storage->read_file({
debug => 3,
file => $known_hosts_file,
});
$known_hosts_old_body = $known_hosts_file_body;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { known_hosts_file_body => $known_hosts_file_body }});
}
# Read in the existing 'authorized_keys' file, if it exists.
my $authorized_keys_file_body = "";
my $authorized_keys_old_body = "";
my $authorized_keys_new_body = "";
my $authorized_keys_file = $ssh_directory."/authorized_keys";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { authorized_keys_file => $authorized_keys_file }});
if (-e $authorized_keys_file)
{
$authorized_keys_file_body = $anvil->Storage->read_file({
debug => 3,
file => $authorized_keys_file,
});
$authorized_keys_old_body = $authorized_keys_file_body;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { authorized_keys_file_body => $authorized_keys_file_body }});
}
### Walk through each host we now know of. As we we do, loop through the old file body to see
### if it exists. If it does, and the key has changed, update the line with the new key. If
### it isn't found, add it. Once we check the old body for this entry, change the "old" body
### to the new one, then repeat the process.
# Look at all the hosts I know about (other than myself) and see if any of the machine or
# user keys either don't exist or have changed.
my $update_known_hosts = 0;
my $update_authorized_keys = 0;
my $known_hosts_new_lines = "";
my $authorized_keys_new_lines = "";
# Check for changes to known_hosts
foreach my $host_uuid (keys %{$anvil->data->{peers}{ssh_keys}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { host_uuid => $host_uuid }});
foreach my $host_name (sort {$a cmp $b} keys %{$anvil->data->{peers}{ssh_keys}{$host_uuid}{host}})
{
my $key = $anvil->data->{peers}{ssh_keys}{$host_uuid}{host}{$host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:host_name' => $host_name,
's2:key' => $key,
}});
# Is this in the file and, if so, has it changed?
my $found = 0;
my $test_line = $host_name." ".$key;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { test_line => $test_line }});
foreach my $line (split/\n/, $known_hosts_old_body)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line eq $test_line)
{
# No change needed, key is the same.
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }});
}
elsif ($line =~ /^$host_name /)
{
# Key has changed, update.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0274", variables => {
machine => $host_name,
old_key => $line,
new_key => $test_line,
}});
$found = 1;
$line = $test_line;
$update_known_hosts = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
found => $found,
line => $line,
update_known_hosts => $update_known_hosts,
}});
}
$known_hosts_new_body .= $line."\n";
}
# If we didn't find the key, add it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }});
if (not $found)
{
$update_known_hosts = 1;
$known_hosts_new_lines .= $test_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:update_known_hosts' => $update_known_hosts,
's2:known_hosts_new_lines' => $known_hosts_new_lines,
}});
}
# Move the new body over to the old body (even though it may not have
# changed) and then clear the new body to prepare for the next pass.
$known_hosts_old_body = $known_hosts_new_body;
$known_hosts_new_body = "";
}
}
# Lastly, copy the last version of the old body to the new body,
$known_hosts_new_body = $known_hosts_old_body.$known_hosts_new_lines;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:update_known_hosts' => $update_known_hosts,
's2:known_hosts_file_body' => $known_hosts_file_body,
's3:known_hosts_new_body' => $known_hosts_new_body,
's4:difference' => diff \$known_hosts_file_body, \$known_hosts_new_body, { STYLE => 'Unified' },
}});
# Check for changes to authorized_keys
foreach my $host_uuid (keys %{$anvil->data->{peers}{ssh_keys}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { host_uuid => $host_uuid }});
foreach my $host_key_user_name (sort {$a cmp $b} keys %{$anvil->data->{peers}{ssh_keys}{$host_uuid}{user}})
{
my $host_key_public_key = $anvil->data->{peers}{ssh_keys}{$host_uuid}{user}{$host_key_user_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:host_key_user_name' => $host_key_user_name,
's2:host_key_public_key' => $host_key_public_key,
}});
# The key in the file might have a different trailing suffix (user@host_name)
# and doesn't really matter. So we search by the key type and public key to
# see if it exists already.
my $found = 0;
my $test_line = ($host_key_public_key =~ /^(ssh-.*? .*?) /)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { test_line => $test_line }});
foreach my $line (split/\n/, $authorized_keys_old_body)
{
# NOTE: Use '\Q...\E' so that the '+' characters in the key aren't
# evaluated as part of the regex.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { line => $line }});
if ($line =~ /^\Q$test_line\E/)
{
# No change needed, key is the same.
$found = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }});
}
# We don't look for changes (yet). Might be worth looking for stale
# keys by ckecking of the host at the end matches an entry in the
# database and then verifying the keys haven't changed, but that's
# for another day.
$authorized_keys_new_body .= $line."\n";
}
# If we didn't find the key, add it.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { found => $found }});
if (not $found)
{
$update_authorized_keys = 1;
$authorized_keys_new_lines .= $host_key_public_key."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:update_authorized_keys' => $update_authorized_keys,
's2:authorized_keys_new_lines' => $authorized_keys_new_lines,
}});
}
# Move the new body over to the old body (even though it may not have
# changed) and then clear the new body to prepare for the next pass.
$authorized_keys_old_body = $authorized_keys_new_body;
$authorized_keys_new_body = "";
}
}
# Lastly, copy the last version of the old body to the new body,
$authorized_keys_new_body = $authorized_keys_old_body.$authorized_keys_new_lines;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
's1:update_authorized_keys' => $update_authorized_keys,
's2:authorized_keys_file_body' => $authorized_keys_file_body,
's3:authorized_keys_new_body' => $authorized_keys_new_body,
's4:difference' => diff \$authorized_keys_file_body, \$authorized_keys_new_body, { STYLE => 'Unified' },
}});
# Update the known_hosts files, if needed.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update_known_hosts => $update_known_hosts }});
if ($update_known_hosts)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0273", variables => { user => $user, file => $known_hosts_file }});
if (-e $known_hosts_file)
{
my $backup_file = $anvil->Storage->backup({
debug => 3,
fatal => 1,
file => $known_hosts_file,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { backup_file => $backup_file }});
if (-e $backup_file)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0154", variables => { source_file => $known_hosts_file, target_file => $backup_file }});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "error_0058", variables => { file => $known_hosts_file }});
}
}
my $failed = $anvil->Storage->write_file({
debug => 3,
overwrite => 1,
file => $known_hosts_file,
body => $known_hosts_new_body,
user => $user,
group => $user,
mode => "0644",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { failed => $failed }});
}
# Update the authorized_keys files, if needed.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { update_authorized_keys => $update_authorized_keys }});
if ($update_authorized_keys)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0273", variables => { user => $user, file => $authorized_keys_file }});
if (-e $authorized_keys_file)
{
my $backup_file = $anvil->Storage->backup({
debug => 3,
fatal => 1,
file => $authorized_keys_file,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { backup_file => $backup_file }});
if (-e $backup_file)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0154", variables => { source_file => $authorized_keys_file, target_file => $backup_file }});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, priority => "alert", key => "error_0058", variables => { file => $authorized_keys_file }});
}
}
my $failed = $anvil->Storage->write_file({
debug => 3,
overwrite => 1,
file => $authorized_keys_file,
body => $authorized_keys_new_body,
user => $user,
group => $user,
mode => "0644",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { failed => $failed }});
}
}
return(0);
}
# Get a list of machine host keys and user public keys from other machines.
sub get_other_keys
{
@ -902,13 +566,13 @@ WHERE
# Now read in the public key for other users on other machines.
$query = "
SELECT
host_key_host_uuid,
host_key_user_name,
host_key_public_key
ssh_key_host_uuid,
ssh_key_user_name,
ssh_key_public_key
FROM
host_keys
ssh_keys
WHERE
host_key_host_uuid != ".$anvil->Database->quote($anvil->Get->host_uuid)."
ssh_key_host_uuid != ".$anvil->Database->quote($anvil->Get->host_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { query => $query }});
@ -920,18 +584,18 @@ WHERE
}});
foreach my $row (@{$results})
{
my $host_key_host_uuid = $row->[0];
my $host_key_user_name = $row->[1];
my $host_key_public_key = $row->[2];
my $ssh_key_host_uuid = $row->[0];
my $ssh_key_user_name = $row->[1];
my $ssh_key_public_key = $row->[2];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
host_key_host_uuid => $host_key_host_uuid,
host_key_user_name => $host_key_user_name,
host_key_public_key => $host_key_public_key,
ssh_key_host_uuid => $ssh_key_host_uuid,
ssh_key_user_name => $ssh_key_user_name,
ssh_key_public_key => $ssh_key_public_key,
}});
$anvil->data->{peers}{ssh_keys}{$host_key_host_uuid}{user}{$host_key_user_name} = $host_key_public_key;
$anvil->data->{peers}{ssh_keys}{$ssh_key_host_uuid}{user}{$ssh_key_user_name} = $ssh_key_public_key;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
"peers::ssh_keys::${host_key_host_uuid}::user::${host_key_user_name}" => $anvil->data->{peers}{ssh_keys}{$host_key_host_uuid}{user}{$host_key_user_name},
"peers::ssh_keys::${ssh_key_host_uuid}::user::${ssh_key_user_name}" => $anvil->data->{peers}{ssh_keys}{$ssh_key_host_uuid}{user}{$ssh_key_user_name},
}});
}
@ -945,9 +609,9 @@ sub check_install_target
{
my ($anvil) = @_;
my $system_type = $anvil->System->get_host_type();
my $system_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { system_type => $system_type }});
if ($system_type ne "dashboard")
if ($system_type ne "striker")
{
# Not a dashboard, nothing to do.
return(0);
@ -1005,7 +669,8 @@ sub run_once
boot_time_tasks($anvil);
# Check the ssh stuff.
check_ssh_keys($anvil);
# NOTE: This actually runs again in the minutes tasks, but needs to run on boot as well.
$anvil->System->check_ssh_keys({debug => 3});
# Check setuid wrappers
check_setuid_wrappers($anvil);
@ -1023,9 +688,9 @@ sub check_setuid_wrappers
{
my ($anvil) = @_;
my $host_type = $anvil->System->get_host_type();
my $host_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { host_type => $host_type }});
if ($host_type ne "dashboard")
if ($host_type ne "striker")
{
# Not a dashboard, setuid scripts aren't needed.
return(0);
@ -1136,7 +801,7 @@ sub boot_time_tasks
my ($anvil) = @_;
# If the uptime is less than ten minutes, clear the reboot flag.
my $uptime = $anvil->System->get_uptime;
my $uptime = $anvil->Get->uptime;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uptime => $uptime }});
# Now find out if a reboot is listed as needed and when it was last changed.
@ -1220,9 +885,9 @@ sub prep_database
my ($anvil) = @_;
# Only run this if we're a dashboard.
my $host_type = $anvil->System->get_host_type();
my $host_type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { host_type => $host_type }});
if ($host_type eq "dashboard")
if ($host_type eq "striker")
{
my ($database_output, $return_code) = $anvil->System->call({
debug => 3,
@ -1273,7 +938,7 @@ sub keep_running
}
}
# If we're confiugured, write out the status JSON file. If we're not configured, Update hardware state files.
# If we're configured, write out the status JSON file. If we're not configured, Update hardware state files.
my $configured = $anvil->System->check_if_configured;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { configured => $configured }});
if ((not $anvil->data->{sys}{mapping_network}) && ($configured))
@ -1508,10 +1173,10 @@ sub update_state_file
my ($anvil) = @_;
my ($states_output, $return_code) = $anvil->System->call({debug => 3, shell_call => $anvil->data->{path}{exe}{'anvil-update-states'}, source => $THIS_FILE, line => __LINE__});
if ($states_output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { states_output => $states_output }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
states_output => $states_output,
return_code => $return_code,
}});
return(0);
}

@ -55,6 +55,8 @@ load_manifest($anvil);
# Check if we need to change any IPs or our hostname.
check_local_network($anvil);
# (wait for out peer and) Configure pacemaker
configure_pacemaker($anvil);
$anvil->nice_exit({code => 0});
@ -62,6 +64,49 @@ $anvil->nice_exit({code => 0});
# Functions #
#############################################################################################################
# (wait for out peer and) Configure pacemaker. If this is a DR host, this is skipped.
sub configure_pacemaker
{
my ($anvil) = @_;
my $machine = $anvil->data->{sys}{machine};
my $manifest_uuid = $anvil->data->{sys}{manifest_uuid};
### TODO: Move these to variables in the 'sys' hash
my $anvil_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name};
my $host_name = $anvil->data->{sys}{host_name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:machine' => $machine,
's1:anvil_name' => $anvil_name,
's3:host_name' => $host_name,
}});
=cut
909; xxx::upses::el8-ups01::uuid: [7ebecdda-782d-4624-841d-98d912ed3d50]
909; xxx::upses::el8-ups02::uuid: [7ffb4dc2-8b96-4ca7-80bb-49e309fb2f5f]
918; xxx::fences::an-nas02::uuid: [4117a862-f58f-4676-991a-9ca257a3c612]
949; xxx::networks::name::bcn1::gateway: [], xxx::networks::name::bcn1::network: [10.201.0.0], xxx::networks::name::bcn1::subnet: [255.255.0.0]
949; xxx::networks::name::sn1::gateway: [], xxx::networks::name::sn1::network: [10.101.0.0], xxx::networks::name::sn1::subnet: [255.255.0.0]
949; xxx::networks::name::ifn1::gateway: [10.255.255.254], xxx::networks::name::ifn1::network: [10.255.0.0], xxx::networks::name::ifn1::subnet: [255.255.0.0]
961; xxx::networks::count::bcn: [1], xxx::networks::count::ifn: [1], xxx::networks::count::sn: [1]
971; xxx::machine::node1::ipmi_ip: [], xxx::machine::node1::type: [!!undef!!]
980; xxx::machine::node1::fence::an-nas02::port: [el8-a01n01]
980; xxx::machine::node1::fence::el8-pdu01::port: []
980; xxx::machine::node1::fence::el8-pdu02::port: []
980; xxx::machine::node1::fence::pulsar::port: []
989; xxx::machine::node1::ups::el8-ups01::used: [0]
989; xxx::machine::node1::ups::el8-ups02::used: [0]
998; xxx::machine::node1::network::bcn1::ip: [10.201.10.1]
998; xxx::machine::node1::network::ifn1::ip: [10.255.10.1]
998; xxx::machine::node1::network::sn1::ip: [10.101.10.1]
=cut
return(0);
}
# Check if we need to change any IPs or our hostname.
sub check_local_network
{
@ -71,7 +116,6 @@ sub check_local_network
my $machine = $anvil->data->{sys}{machine};
my $manifest_uuid = $anvil->data->{sys}{manifest_uuid};
my $anvil_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{name};
my $domain = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{domain};
my $old_host_name = $anvil->_host_name;
my $new_host_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{name};
@ -80,12 +124,13 @@ sub check_local_network
$new_host_name = $anvil->data->{manifests}{manifest_uuid}{$manifest_uuid}{parsed}{machine}{$machine}{name}.".".$domain;
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:anvil_name' => $anvil_name,
's2:domain' => $domain,
's3:old_host_name' => $old_host_name,
's4:new_host_name' => $new_host_name,
}});
$anvil->data->{sys}{host_name} = $new_host_name;
# If the hostname isn't the same, change it.
if ($old_host_name ne $new_host_name)
{
@ -770,28 +815,13 @@ sub check_local_network
}
}
# Setup IPMI, if needed.
=cut
909; xxx::upses::el8-ups01::uuid: [7ebecdda-782d-4624-841d-98d912ed3d50]
909; xxx::upses::el8-ups02::uuid: [7ffb4dc2-8b96-4ca7-80bb-49e309fb2f5f]
918; xxx::fences::an-nas02::uuid: [4117a862-f58f-4676-991a-9ca257a3c612]
### TODO: Do we really need passwordless SSH anymore?
# Configure SSH by adding ours and our peer's SSH keys to ~/.ssh/known_hosts
$anvil->System->check_ssh_keys({debug => 2});
949; xxx::networks::name::bcn1::gateway: [], xxx::networks::name::bcn1::network: [10.201.0.0], xxx::networks::name::bcn1::subnet: [255.255.0.0]
949; xxx::networks::name::sn1::gateway: [], xxx::networks::name::sn1::network: [10.101.0.0], xxx::networks::name::sn1::subnet: [255.255.0.0]
949; xxx::networks::name::ifn1::gateway: [10.255.255.254], xxx::networks::name::ifn1::network: [10.255.0.0], xxx::networks::name::ifn1::subnet: [255.255.0.0]
961; xxx::networks::count::bcn: [1], xxx::networks::count::ifn: [1], xxx::networks::count::sn: [1]
971; xxx::machine::node1::ipmi_ip: [], xxx::machine::node1::type: [!!undef!!]
980; xxx::machine::node1::fence::an-nas02::port: [el8-a01n01]
980; xxx::machine::node1::fence::el8-pdu01::port: []
980; xxx::machine::node1::fence::el8-pdu02::port: []
980; xxx::machine::node1::fence::pulsar::port: []
989; xxx::machine::node1::ups::el8-ups01::used: [0]
989; xxx::machine::node1::ups::el8-ups02::used: [0]
998; xxx::machine::node1::network::bcn1::ip: [10.201.10.1]
998; xxx::machine::node1::network::ifn1::ip: [10.255.10.1]
998; xxx::machine::node1::network::sn1::ip: [10.101.10.1]
=cut
# Setup IPMI, if needed.
### TODO: Do this when on real hardware
return(0);
}
@ -815,17 +845,26 @@ sub load_job
update_progress($anvil, ($anvil->data->{job}{progress} += 1), "job_0074,!!job-uuid!".$anvil->data->{switches}{'job-uuid'}."!!");
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "job_0074", variables => { 'job-uuid' => $anvil->data->{switches}{'job-uuid'} }});
my ($machine, $manifest_uuid) = ($anvil->data->{jobs}{job_data} =~ /as_machine=(.*?),manifest_uuid=(.*)$/);
my ($machine, $manifest_uuid, $node1_host_uuid, $node2_host_uuid, $dr1_host_uuid) = ($anvil->data->{jobs}{job_data} =~ /as_machine=(.*?),manifest_uuid=(.*?),node1_host_uuid=(.*?),node2_host_uuid=(.*?),dr1_host_uuid=(.*?)$/);
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
machine => $machine,
manifest_uuid => $manifest_uuid,
node1_host_uuid => $node1_host_uuid,
node2_host_uuid => $node2_host_uuid,
dr1_host_uuid => $dr1_host_uuid,
}});
$anvil->data->{sys}{machine} = $machine;
$anvil->data->{sys}{manifest_uuid} = $manifest_uuid;
$anvil->data->{sys}{node1_host_uuid} = $node1_host_uuid;
$anvil->data->{sys}{node2_host_uuid} = $node2_host_uuid;
$anvil->data->{sys}{node1_host_uuid} = $node1_host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"sys::machine" => $anvil->data->{sys}{machine},
"sys::manifest_uuid" => $anvil->data->{sys}{manifest_uuid},
"sys::node1_host_uuid" => $anvil->data->{sys}{node1_host_uuid},
"sys::node2_host_uuid" => $anvil->data->{sys}{node2_host_uuid},
"sys::dr1_host_uuid" => $anvil->data->{sys}{dr1_host_uuid},
}});
update_progress($anvil, ($anvil->data->{job}{progress} += 1), "job_0075,!!machine!".$anvil->data->{sys}{machine}."!!,!!manifest_uuid!".$anvil->data->{sys}{manifest_uuid}."!!");
@ -868,6 +907,9 @@ sub update_progress
's2:message' => $message,
}});
# Disabled for the moment
return(0);
$progress = 95 if $progress > 100;
if (not $anvil->data->{switches}{'job-uuid'})
{

@ -341,7 +341,7 @@ sub check_initial_setup
}
# NOTE: We may want to do machine-specific stuff down the road.
my $type = $anvil->System->get_host_type();
my $type = $anvil->Get->host_type();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { type => $type }});
return(0);

@ -185,7 +185,7 @@ sub do_poweroff
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { task => $task }});
# We'll wait until the system has at least 10 minutes of uptime, unless '--no-wait' was given.
my $uptime = $anvil->data->{switches}{'no-wait'} ? 0 : $anvil->System->get_uptime;
my $uptime = $anvil->data->{switches}{'no-wait'} ? 0 : $anvil->Get->uptime;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
"switches::no-wait" => $anvil->data->{switches}{'no-delay'},
uptime => $uptime,

@ -92,7 +92,7 @@ sub process_interface_cache
network_interface_operational => $operational,
network_interface_speed => $speed,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { network_interface_uuid => $network_interface_uuid }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { network_interface_uuid => $network_interface_uuid }});
if (not $network_interface_uuid)
{
# Failed to update, could be that we cached data for an interface not yet
@ -146,7 +146,7 @@ sub update_network
next if $file eq ".";
next if $file eq "..";
next if $file eq "lo";
my $full_path = "$directory/$file";
my $full_path = $directory."/".$file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { full_path => $full_path }});
if (-d $full_path)
{
@ -226,7 +226,7 @@ sub update_network
{
### Set some fake values.
# Speed is "as fast as possible", so we'll record 100 Gbps, but that is really kind of arbitrary.
$speed = 100000 if ((not $speed) or ($speed eq "-1"));
$speed = 1000 if ((not $speed) or ($speed eq "-1"));
$duplex = "full" if not $duplex;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
speed => $speed,
@ -991,7 +991,7 @@ WHERE
# Write the JSON file, if we're a dashboard. Nodes and DR hosts don't have a WebUI, so they're not
# needed.
if ($anvil->System->get_host_type eq "dashboard")
if ($anvil->Get->host_type eq "striker")
{
my $output_json = $anvil->data->{path}{directories}{html}."/status/network.json";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output_xml => $output_json }});

@ -192,7 +192,7 @@ if (not $configured)
load_os_info($anvil);
# If this isn't a Striker dashboard, exit.
if ($anvil->System->get_host_type ne "dashboard")
if ($anvil->Get->host_type ne "striker")
{
print $anvil->Words->string({key => "error_0044"})."\n";
update_progress($anvil, 100, "error_0044");
@ -268,7 +268,7 @@ sub load_os_info
{
my ($anvil) = @_;
my ($os_type, $os_arch) = $anvil->System->get_os_type();
my ($os_type, $os_arch) = $anvil->Get->os_type();
$anvil->data->{host_os}{os_type} = $os_type;
$anvil->data->{host_os}{os_arch} = $os_arch;
$anvil->data->{host_os}{version} = ($os_type =~ /(\d+)$/)[0];
@ -2440,7 +2440,7 @@ sub load_packages
],
};
my ($os_type, $os_arch) = $anvil->System->get_os_type();
my ($os_type, $os_arch) = $anvil->Get->os_type();
if ($os_type eq "rhel8")
{
push @{$anvil->data->{packages}{r}}, "redhat-backgrounds.noarch";

@ -25,10 +25,4 @@ $anvil->Database->connect({debug => 3});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, secure => 0, key => "log_0132"});
print "DB Connections: [".$anvil->data->{sys}{database}{connections}."]\n";
$anvil->Striker->get_fence_data();
foreach my $name (sort {$a cmp $b} keys %{$anvil->data->{fence_data}{fence_virsh}{parameters}})
{
#print "Name: [".$name."]: [".sprintf('%vX', $anvil->data->{fence_data}{fence_virsh}{parameters}{$name}{'default'})."]\n";
print "Name: [".$name."]: [".$anvil->data->{fence_data}{fence_virsh}{parameters}{$name}{'default'}."]\n";
}
$anvil->System->check_ssh_keys({debug => 2});

Loading…
Cancel
Save