* Created Cluster->get_anvil_uuid() that returns the 'anvil_uuid' of a given 'host_uuid'.

* Renamed the 'defitintions' table to 'server_definitions' to clarify the purpose, and made all the 'server' columns have then 'not null' constraint.
* Created Database->insert_or_update_servers(), ->get_servers(), ->insert_or_update_server_definitions() and ->get_server_definitions().
* Updated scancore, anvil-daemon, and scan agents to not run unless they're run with root privs.
* Got scan-server to update the servers / server_definition tables and the on-disk file when needed.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 4 years ago
parent e85823fe16
commit 1a1fa7ce88
  1. 55
      Anvil/Tools/Cluster.pm
  2. 342
      Anvil/Tools/Database.pm
  3. 3
      Anvil/Tools/ScanCore.pm
  4. 145
      notes
  5. 15
      scancore-agents/scan-cluster/scan-cluster
  6. 15
      scancore-agents/scan-hardware/scan-hardware
  7. 199
      scancore-agents/scan-server/scan-server
  8. 15
      scancore-agents/scan-server/scan-server.xml
  9. 62
      share/anvil.sql
  10. 29
      share/words.xml
  11. 15
      tools/anvil-daemon
  12. 16
      tools/scancore

@ -288,6 +288,61 @@ sub check_node_status
return($anvil->data->{cib}{parsed}{data}{node}{$node_name}{node_state}{ready}); return($anvil->data->{cib}{parsed}{data}{node}{$node_name}{node_state}{ready});
} }
=head2 get_anvil_uuid
This returns the C<< anvils >> -> C<< anvil_uuid >> that a host belongs to. If the host is not found in any Anvil!, an empty string is returned.
Parameters;
=head3 host_uuid (optional, default Get->host_uuid)
This is the C<< host_uuid >> of the host who we're looking for Anvil! membership of.
=cut
sub get_anvil_uuid
{
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 => "Cluster->check_node_status()" }});
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 => {
host_uuid => $host_uuid,
}});
# Load the Anvil! data.
$anvil->Database->get_anvils({debug => $debug});
my $member_anvil_uuid = "";
foreach my $anvil_uuid (keys %{$anvil->data->{anvils}{anvil_uuid}})
{
my $anvil_name = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_name};
my $anvil_node1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node1_host_uuid};
my $anvil_node2_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_node2_host_uuid};
my $anvil_dr1_host_uuid = $anvil->data->{anvils}{anvil_uuid}{$anvil_uuid}{anvil_dr1_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
anvil_name => $anvil_name,
anvil_node1_host_uuid => $anvil_node1_host_uuid,
anvil_node2_host_uuid => $anvil_node2_host_uuid,
anvil_dr1_host_uuid => $anvil_dr1_host_uuid,
}});
if (($host_uuid eq $anvil_node1_host_uuid) or
($host_uuid eq $anvil_node2_host_uuid) or
($host_uuid eq $anvil_dr1_host_uuid))
{
# Found ot!
$member_anvil_uuid = $anvil_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { member_anvil_uuid => $member_anvil_uuid }});
last;
}
}
return($member_anvil_uuid);
}
=head2 get_peers =head2 get_peers
This method uses the local machine's host UUID and finds the host names of the cluster memebers. If this host is in a cluster and it is a node, the peer's short host name is returned. Otherwise, an empty string is returned. This method uses the local machine's host UUID and finds the host names of the cluster memebers. If this host is in a cluster and it is a node, the peer's short host name is returned. Otherwise, an empty string is returned.

@ -8,8 +8,9 @@ use warnings;
use DBI; use DBI;
use Scalar::Util qw(weaken isweak); use Scalar::Util qw(weaken isweak);
use Data::Dumper; use Data::Dumper;
use Time::HiRes qw(gettimeofday tv_interval);
use Text::Diff; use Text::Diff;
use Time::HiRes qw(gettimeofday tv_interval);
use XML::LibXML;
our $VERSION = "3.0.0"; our $VERSION = "3.0.0";
my $THIS_FILE = "Database.pm"; my $THIS_FILE = "Database.pm";
@ -58,6 +59,8 @@ my $THIS_FILE = "Database.pm";
# insert_or_update_oui # insert_or_update_oui
# insert_or_update_power # insert_or_update_power
# insert_or_update_recipients # insert_or_update_recipients
# insert_or_update_servers
# insert_or_update_server_definitions
# insert_or_update_sessions # insert_or_update_sessions
# insert_or_update_ssh_keys # insert_or_update_ssh_keys
# insert_or_update_states # insert_or_update_states
@ -3184,13 +3187,13 @@ FROM
$anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_authentication} = $mail_server_authentication; $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_authentication} = $mail_server_authentication;
$anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_helo_domain} = $mail_server_helo_domain; $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_helo_domain} = $mail_server_helo_domain;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"mail_servers::mail_server::${mail_server_uuid}}::mail_server_address" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_address}, "mail_servers::mail_server::${mail_server_uuid}::mail_server_address" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_address},
"mail_servers::mail_server::${mail_server_uuid}}::mail_server_port" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_port}, "mail_servers::mail_server::${mail_server_uuid}::mail_server_port" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_port},
"mail_servers::mail_server::${mail_server_uuid}}::mail_server_username" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_username}, "mail_servers::mail_server::${mail_server_uuid}::mail_server_username" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_username},
"mail_servers::mail_server::${mail_server_uuid}}::mail_server_password" => $anvil->Log->is_secure($anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_password}), "mail_servers::mail_server::${mail_server_uuid}::mail_server_password" => $anvil->Log->is_secure($anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_password}),
"mail_servers::mail_server::${mail_server_uuid}}::mail_server_security" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_security}, "mail_servers::mail_server::${mail_server_uuid}::mail_server_security" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_security},
"mail_servers::mail_server::${mail_server_uuid}}::mail_server_authentication" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_authentication}, "mail_servers::mail_server::${mail_server_uuid}::mail_server_authentication" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_authentication},
"mail_servers::mail_server::${mail_server_uuid}}::mail_server_helo_domain" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_helo_domain}, "mail_servers::mail_server::${mail_server_uuid}::mail_server_helo_domain" => $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_helo_domain},
}}); }});
# Make it easy to look up the mail server's UUID from the server address. # Make it easy to look up the mail server's UUID from the server address.
@ -3510,11 +3513,11 @@ WHERE
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_level} = $recipient_level; $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_level} = $recipient_level;
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host} = $recipient_level; $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host} = $recipient_level;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"recipients::recipient_uuid::${recipient_uuid}}::recipient_name" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_name}, "recipients::recipient_uuid::${recipient_uuid}::recipient_name" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_name},
"recipients::recipient_uuid::${recipient_uuid}}::recipient_email" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_email}, "recipients::recipient_uuid::${recipient_uuid}::recipient_email" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_email},
"recipients::recipient_uuid::${recipient_uuid}}::recipient_language" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_language}, "recipients::recipient_uuid::${recipient_uuid}::recipient_language" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_language},
"recipients::recipient_uuid::${recipient_uuid}}::recipient_level" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_level}, "recipients::recipient_uuid::${recipient_uuid}::recipient_level" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_level},
"recipients::recipient_uuid::${recipient_uuid}}::level_on_host" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host}, "recipients::recipient_uuid::${recipient_uuid}::level_on_host" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host},
}}); }});
# Make it easy to look up the mail server's UUID from the server address. # Make it easy to look up the mail server's UUID from the server address.
@ -3538,7 +3541,7 @@ WHERE
{ {
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host} = $notification_alert_level; $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host} = $notification_alert_level;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"recipients::recipient_uuid::${recipient_uuid}}::level_on_host" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host}, "recipients::recipient_uuid::${recipient_uuid}::level_on_host" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host},
}}); }});
last; last;
} }
@ -3582,7 +3585,7 @@ sub get_servers
delete $anvil->data->{sys}{servers}{by_uuid}; delete $anvil->data->{sys}{servers}{by_uuid};
delete $anvil->data->{sys}{servers}{by_name}; delete $anvil->data->{sys}{servers}{by_name};
my $query = " my $query = "
SELECT SELECT
server_uuid, server_uuid,
server_name, server_name,
@ -3602,18 +3605,12 @@ FROM
;"; ;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }}); $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__}); my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results}; my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results, results => $results,
count => $count, count => $count,
}}); }});
if (not $count)
{
# I have a server_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 => "server_uuid", uuid => $server_uuid }});
return("");
}
foreach my $row (@{$results}) foreach my $row (@{$results})
{ {
my $server_uuid = $row->[0]; my $server_uuid = $row->[0];
@ -3658,7 +3655,6 @@ FROM
$anvil->data->{servers}{server_uuid}{$server_uuid}{server_post_migration_file_uuid} = $server_post_migration_file_uuid; $anvil->data->{servers}{server_uuid}{$server_uuid}{server_post_migration_file_uuid} = $server_post_migration_file_uuid;
$anvil->data->{servers}{server_uuid}{$server_uuid}{server_post_migration_arguments} = $server_post_migration_arguments; $anvil->data->{servers}{server_uuid}{$server_uuid}{server_post_migration_arguments} = $server_post_migration_arguments;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"servers::server_uuid::${server_uuid}::" => $anvil->data->{servers}{server_uuid}{$server_uuid}{},
"servers::server_uuid::${server_uuid}::server_anvil_uuid" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid}, "servers::server_uuid::${server_uuid}::server_anvil_uuid" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_anvil_uuid},
"servers::server_uuid::${server_uuid}::server_clean_stop" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_clean_stop}, "servers::server_uuid::${server_uuid}::server_clean_stop" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_clean_stop},
"servers::server_uuid::${server_uuid}::server_start_after_server_uuid" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_start_after_server_uuid}, "servers::server_uuid::${server_uuid}::server_start_after_server_uuid" => $anvil->data->{servers}{server_uuid}{$server_uuid}{server_start_after_server_uuid},
@ -3677,6 +3673,96 @@ FROM
} }
=head2 get_server_definitions
This loads all known server definition records from the database.
Data is stored in two formats;
server_definitions::server_definition_uuid::<server_definition_uuid>::server_definition_server_uuid
server_definitions::server_definition_uuid::<server_definition_uuid>::server_definition_xml
server_definitions::server_definition_uuid::<server_definition_uuid>::unix_modified_time
And;
server_definitions::server_definition_server_uuid::<server_definition_server_uuid>::$server_definition_uuid
server_definitions::server_definition_server_uuid::<server_definition_server_uuid>::server_definition_xml
server_definitions::server_definition_server_uuid::<server_definition_server_uuid>::unix_modified_time
This method takes no parameters.
=cut
sub get_server_definitions
{
my $self = shift;
my $parameter = shift;
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_server_definitions()" }});
# We're going to include the alert levels for this host based on overrides that might exist in the
# 'notifications' table. If the data hasn't already been loaded, we'll load it now.
if (not $anvil->data->{notifications}{notification_uuid})
{
$anvil->Database->get_notifications({debug => $debug});
}
my $host_uuid = $anvil->Get->host_uuid();
my $query = "
SELECT
server_definition_uuid,
server_definition_server_uuid,
server_definition_xml,
round(extract(epoch from modified_date)) AS mtime
FROM
server_definitions
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
my $results = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $server_definition_uuid = $row->[0];
my $server_definition_server_uuid = $row->[1];
my $server_definition_xml = $row->[2];
my $unix_modified_time = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server_definition_uuid => $server_definition_uuid,
server_definition_server_uuid => $server_definition_server_uuid,
server_definition_xml => $server_definition_xml,
unix_modified_time => $unix_modified_time,
}});
# Store the data
$anvil->data->{server_definitions}{server_definition_uuid}{$server_definition_uuid}{server_definition_server_uuid} = $server_definition_server_uuid;
$anvil->data->{server_definitions}{server_definition_uuid}{$server_definition_uuid}{server_definition_xml} = $server_definition_xml;
$anvil->data->{server_definitions}{server_definition_uuid}{$server_definition_uuid}{unix_modified_time} = $unix_modified_time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server_definitions::server_definition_uuid::${server_definition_uuid}::server_definition_server_uuid" => $anvil->data->{server_definitions}{server_definition_uuid}{$server_definition_uuid}{server_definition_server_uuid},
"server_definitions::server_definition_uuid::${server_definition_uuid}::server_definition_xml" => $anvil->data->{server_definitions}{server_definition_uuid}{$server_definition_uuid}{server_definition_xml},
"server_definitions::server_definition_uuid::${server_definition_uuid}::unix_modified_time" => $anvil->data->{server_definitions}{server_definition_uuid}{$server_definition_uuid}{unix_modified_time},
}});
# Make it easy to locate records by 'server_uuid' as well.
$anvil->data->{server_definitions}{server_definition_server_uuid}{$server_definition_server_uuid}{server_definition_uuid} = $server_definition_uuid;
$anvil->data->{server_definitions}{server_definition_server_uuid}{$server_definition_server_uuid}{server_definition_xml} = $server_definition_xml;
$anvil->data->{server_definitions}{server_definition_server_uuid}{$server_definition_server_uuid}{unix_modified_time} = $unix_modified_time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"server_definitions::server_definition_server_uuid::${server_definition_server_uuid}::$server_definition_uuid" => $anvil->data->{server_definitions}{server_definition_server_uuid}{$server_definition_server_uuid}{server_definition_uuid},
"server_definitions::server_definition_server_uuid::${server_definition_server_uuid}::server_definition_xml" => $anvil->data->{server_definitions}{server_definition_server_uuid}{$server_definition_server_uuid}{server_definition_xml},
"server_definitions::server_definition_server_uuid::${server_definition_server_uuid}::unix_modified_time" => $anvil->data->{server_definitions}{server_definition_server_uuid}{$server_definition_server_uuid}{unix_modified_time},
}});
}
return(0);
}
=head2 get_ssh_keys =head2 get_ssh_keys
This loads all known user's SSH public keys and all known machine's public keys into the data hash. On success, this method returns C<< 0 >>. If any problems occur, C<< 1 >> is returned. This loads all known user's SSH public keys and all known machine's public keys into the data hash. On success, this method returns C<< 0 >>. If any problems occur, C<< 1 >> is returned.
@ -9274,7 +9360,7 @@ sub insert_or_update_servers
# Do we already know about this # Do we already know about this
my $exists = 0; my $exists = 0;
my $query = "SELECT COUNT(*) FROM servers WHERE server_uuid = ".$anvil->Database->quote($server_uuid).";"; my $query = "SELECT COUNT(*) FROM servers WHERE server_uuid = ".$anvil->Database->quote($server_uuid).";";
my $count = $anvil->Database->query({query => $function_query, source => $THIS_FILE, line => __LINE__})->[0]->[0]; my $count = $anvil->Database->query({query => $query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }});
if ($count) if ($count)
{ {
@ -9305,7 +9391,7 @@ sub insert_or_update_servers
my $old_server_state = $results->[0]->[0]; my $old_server_state = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_server_state => $old_server_state }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_server_state => $old_server_state }});
if ($old_server_name ne "DELETED") if ($old_server_state ne "DELETED")
{ {
my $query = " my $query = "
UPDATE UPDATE
@ -9474,6 +9560,212 @@ WHERE
} }
=head2 insert_or_update_server_definitions
This inserts or updates the C<< server_definitions >> table used to store (virtual) server XML definitions.
Parameters;
=head3 server_definition_uuid (optional)
This is the server_definition UUID of a specific record to update.
=head3 server_definition_server_uuid (required)
This is the C<< servers >> -> C<< server_uuid >> of the server whose server_definition this belongs to.
server_definition_xml (required)
This is the server's XML definition file itself.
=cut
sub insert_or_update_server_definitions
{
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_server_definitions()" }});
my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : "";
my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $line = defined $parameter->{line} ? $parameter->{line} : "";
my $server_definition_uuid = defined $parameter->{server_definition_uuid} ? $parameter->{server_definition_uuid} : "";
my $server_definition_server_uuid = defined $parameter->{server_definition_server_uuid} ? $parameter->{server_definition_server_uuid} : "";
my $server_definition_xml = defined $parameter->{server_definition_xml} ? $parameter->{server_definition_xml} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
uuid => $uuid,
file => $file,
line => $line,
server_definition_uuid => $server_definition_uuid,
server_definition_server_uuid => $server_definition_server_uuid,
server_definition_xml => $server_definition_xml,
}});
if (not $server_definition_server_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_server_definitions()", parameter => "server_definition_server_uuid" }});
return("!!error!!");
}
if (not $anvil->Validate->uuid({uuid => $server_definition_server_uuid}))
{
# Bad UUID.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0130", variables => { method => "Database->insert_or_update_server_definitions()", parameter => "server_definition_server_uuid", uuid => $server_definition_server_uuid }});
return("!!error!!");
}
if (not $server_definition_xml)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Database->insert_or_update_server_definitions()", parameter => "server_definition_xml" }});
return("!!error!!");
}
# Make sure the server_definition_xml looks valid.
local $@;
my $dom = eval { XML::LibXML->load_xml(string => $server_definition_xml); };
if ($@)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0066", variables => {
xml => $server_definition_xml,
error => $@,
}});
return("!!error!!");
}
# Verify that I can read the UUID from the XML and verify that it matches the
# 'server_definition_server_uuid'.
my $server_name = $dom->findvalue('/domain/name');
my $read_uuid = $dom->findvalue('/domain/uuid');
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
server_name => $server_name,
read_uuid => $read_uuid,
}});
if (not $read_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "warning_0067", variables => { xml => $server_definition_xml }});
return("!!error!!");
}
elsif ($read_uuid ne $server_definition_server_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "warning_0067", variables => {
passed_uuid => $server_definition_server_uuid,
read_uuid => $read_uuid,
xml => $server_definition_xml,
}});
return("!!error!!");
}
# If we don't have a server_definition_uuid, look for one using the server_uuid.
if (not $server_definition_uuid)
{
my $query = "
SELECT
server_definition_uuid
FROM
server_definitions
WHERE
server_definition_server_uuid = ".$anvil->Database->quote($server_definition_server_uuid)."
;";
$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__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
if ($count)
{
$server_definition_uuid = $results->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { server_definition_uuid => $server_definition_uuid }});
}
}
# UPDATE or INSERT.
if ($server_definition_uuid)
{
# Is there any difference?
my $query = "
SELECT
server_definition_server_uuid,
server_definition_xml
FROM
server_definitions
WHERE
server_definition_uuid = ".$anvil->Database->quote($server_definition_uuid)."
;";
$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__});
my $count = @{$results};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
results => $results,
count => $count,
}});
foreach my $row (@{$results})
{
my $old_server_definition_server_uuid = $row->[0];
my $old_server_definition_xml = $row->[1];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_server_definition_server_uuid => $old_server_definition_server_uuid,
old_server_definition_xml => $old_server_definition_xml,
}});
if (($old_server_definition_server_uuid ne $server_definition_server_uuid) or
($old_server_definition_xml ne $server_definition_xml))
{
# If the server_definition is what changed, log the diff.
if ($old_server_definition_xml ne $server_definition_xml)
{
my $difference = diff \$old_server_definition_xml, \$server_definition_xml, { STYLE => 'Unified' };
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0556", variables => {
server_name => $server_name,
server_definition_server_uuid => $server_definition_server_uuid,
difference => $difference,
}});
}
# Save the changes.
my $query = "
UPDATE
server_definitions
SET
server_definition_xml = ".$anvil->Database->quote($server_definition_xml).",
server_definition_server_uuid = ".$anvil->Database->quote($server_definition_server_uuid).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
server_definition_uuid = ".$anvil->Database->quote($server_definition_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query =~ /passw/ ? $anvil->Log->is_secure($query) : $query }});
$anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
}
}
else
{
$server_definition_uuid = $anvil->Get->uuid();
my $query = "
INSERT INTO
server_definitions
(
server_definition_uuid,
server_definition_server_uuid,
server_definition_xml,
modified_date
) VALUES (
".$anvil->Database->quote($server_definition_uuid).",
".$anvil->Database->quote($server_definition_server_uuid).",
".$anvil->Database->quote($server_definition_xml).",
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
);
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query =~ /passw/ ? $anvil->Log->is_secure($query) : $query }});
$anvil->Database->write({uuid => $uuid, query => $query, source => $file ? $file." -> ".$THIS_FILE : $THIS_FILE, line => $line ? $line." -> ".__LINE__ : __LINE__});
}
return($server_definition_uuid);
}
=head2 insert_or_update_sessions =head2 insert_or_update_sessions
This updates (or inserts) a record in the 'sessions' table. The C<< session_uuid >> referencing the database row will be returned. This updates (or inserts) a record in the 'sessions' table. The C<< session_uuid >> referencing the database row will be returned.

@ -132,6 +132,9 @@ sub agent_startup
return("!!error!!"); return("!!error!!");
} }
my $table_count = @{$tables};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { table_count => $table_count }});
# It's possible that some agents don't have a database (or use core database tables only) # It's possible that some agents don't have a database (or use core database tables only)
if (@{$tables} > 0) if (@{$tables} > 0)
{ {

145
notes

@ -264,6 +264,151 @@ CREATE TRIGGER trigger_temperature
AFTER INSERT OR UPDATE ON temperature AFTER INSERT OR UPDATE ON temperature
FOR EACH ROW EXECUTE PROCEDURE history_temperature(); FOR EACH ROW EXECUTE PROCEDURE history_temperature();
DROP FUNCTION history_definitions() CASCADE;
DROP TABLE history.definitions;
DROP TABLE definitions;
DROP FUNCTION history_servers() CASCADE;
DROP TABLE history.servers;
DROP TABLE servers;
-- This stores servers made available to Anvil! systems and DR hosts.
CREATE TABLE servers (
server_uuid uuid not null primary key,
server_name text not null, -- This is the server's name. It can change without re-uploading the server.
server_anvil_uuid uuid not null, -- This is the Anvil! system that the server lives on. It can move to another Anvil!, so this can change.
server_clean_stop boolean not null default FALSE, -- When set, the server was stopped by a user. The Anvil! will not start a server that has been cleanly stopped.
server_start_after_server_uuid uuid not null, -- This can be the server_uuid of another server. If set, this server will boot 'server_start_delay' seconds after the referenced server boots. A value of '00000000-0000-0000-0000-000000000000' will tell 'anvil-safe-start' to not boot the server at all. If a server is set not to start, any dependent servers will also stay off.
server_start_delay integer not null default 0, -- See above.
server_host_uuid uuid not null, -- This is the current hosts -> host_uuid for this server. If the server is off, this will be blank.
server_state text not null, -- This is the current state of this server.
server_live_migration boolean not null default TRUE, -- When false, servers will be stopped and then rebooted when a migration is requested. Also, when false, preventative migrations will not happen.
server_pre_migration_file_uuid uuid not null, -- This is set to the files -> file_uuid of a script to run BEFORE migrating a server. If the file isn't found or can't run, the script is ignored.
server_pre_migration_arguments text not null, -- These are arguments to pass to the pre-migration script
server_post_migration_file_uuid uuid not null, -- This is set to the files -> file_uuid of a script to run AFTER migrating a server. If the file isn't found or can't run, the script is ignored.
server_post_migration_arguments text not null, -- These are arguments to pass to the post-migration script
modified_date timestamp with time zone not null,
FOREIGN KEY(server_anvil_uuid) REFERENCES anvils(anvil_uuid),
FOREIGN KEY(server_start_after_server_uuid) REFERENCES servers(server_uuid),
FOREIGN KEY(server_host_uuid) REFERENCES hosts(host_uuid),
FOREIGN KEY(server_pre_migration_file_uuid) REFERENCES files(file_uuid),
FOREIGN KEY(server_post_migration_file_uuid) REFERENCES files(file_uuid)
);
ALTER TABLE servers OWNER TO admin;
CREATE TABLE history.servers (
history_id bigserial,
server_uuid uuid,
server_name text,
server_anvil_uuid uuid,
server_clean_stop boolean,
server_start_after_server_uuid uuid,
server_start_delay integer,
server_host_uuid uuid,
server_state text,
server_live_migration boolean,
server_pre_migration_file_uuid uuid,
server_pre_migration_arguments text,
server_post_migration_file_uuid uuid,
server_post_migration_arguments text,
modified_date timestamp with time zone not null
);
ALTER TABLE history.servers OWNER TO admin;
CREATE FUNCTION history_servers() RETURNS trigger
AS $$
DECLARE
history_servers RECORD;
BEGIN
SELECT INTO history_servers * FROM servers WHERE server_uuid = new.server_uuid;
INSERT INTO history.servers
(server_uuid,
server_name,
server_anvil_uuid,
server_clean_stop,
server_start_after_server_uuid,
server_start_delay,
server_host_uuid,
server_state,
server_live_migration,
server_pre_migration_file_uuid,
server_pre_migration_arguments,
server_post_migration_file_uuid,
server_post_migration_arguments,
modified_date)
VALUES
(history_servers.server_uuid,
history_servers.server_name,
history_servers.server_clean_stop,
history_servers.server_start_after_server_uuid,
history_servers.server_start_delay,
history_servers.server_host_uuid,
history_servers.server_state,
history_servers.server_live_migration,
history_servers.server_pre_migration_file_uuid,
history_servers.server_pre_migration_arguments,
history_servers.server_post_migration_file_uuid,
history_servers.server_post_migration_arguments,
history_servers.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_servers() OWNER TO admin;
CREATE TRIGGER trigger_servers
AFTER INSERT OR UPDATE ON servers
FOR EACH ROW EXECUTE PROCEDURE history_servers();
-- This stores the XML definition for a server. Whenever a server_definition is found missing on a node or DR host,
-- it will be rewritten from here. If this copy changes, it will be updated on the hosts.
CREATE TABLE server_definitions (
server_definition_uuid uuid not null primary key,
server_definition_server_uuid uuid not null, -- This is the servers -> server_uuid of the server
server_definition_xml text not null, -- This is the XML body.
modified_date timestamp with time zone not null,
FOREIGN KEY(server_definition_server_uuid) REFERENCES servers(server_uuid)
);
ALTER TABLE server_definitions OWNER TO admin;
CREATE TABLE history.server_definitions (
history_id bigserial,
server_definition_uuid uuid,
server_definition_server_uuid uuid,
server_definition_xml text,
modified_date timestamp with time zone not null
);
ALTER TABLE history.server_definitions OWNER TO admin;
CREATE FUNCTION history_server_definitions() RETURNS trigger
AS $$
DECLARE
history_server_definitions RECORD;
BEGIN
SELECT INTO history_server_definitions * FROM server_definitions WHERE server_definition_uuid = new.server_definition_uuid;
INSERT INTO history.server_definitions
(server_definition_uuid,
server_definition_server_uuid,
server_definition_xml,
modified_date)
VALUES
(history_server_definitions.server_definition_uuid,
history_server_definitions.server_definition_server_uuid,
history_server_definitions.server_definition_xml,
history_server_definitions.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_server_definitions() OWNER TO admin;
CREATE TRIGGER trigger_server_definitions
AFTER INSERT OR UPDATE ON server_definitions
FOR EACH ROW EXECUTE PROCEDURE history_server_definitions();
COMMIT; COMMIT;
============ ============

@ -9,7 +9,7 @@
# #
# Exit codes; # Exit codes;
# 0 = Normal exit. # 0 = Normal exit.
# 1 = Startup failure (no DB, bad file read, etc) # 1 = Startup failure (not running as root, no DB, bad file read, etc)
# #
# TODO: # TODO:
# - # -
@ -23,6 +23,10 @@ use Data::Dumper;
# Disable buffering # Disable buffering
$| = 1; $| = 1;
# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error.
$< = $>;
$( = $);
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD})) if (($running_directory =~ /^\./) && ($ENV{PWD}))
@ -34,6 +38,15 @@ my $anvil = Anvil::Tools->new({log_level => 2, log_secure => 1});
$anvil->Log->level({set => 2}); $anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1}); $anvil->Log->secure({set => 1});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
# Not root
print $anvil->Words->string({key => "error_0005"})."\n";
$anvil->nice_exit({exit_code => 1});
}
$anvil->data->{scancore}{'scan-cluster'}{disable} = 0; $anvil->data->{scancore}{'scan-cluster'}{disable} = 0;
$anvil->data->{switches}{force} = 0; $anvil->data->{switches}{force} = 0;

@ -6,7 +6,7 @@
# #
# Exit codes; # Exit codes;
# 0 = Normal exit. # 0 = Normal exit.
# 1 = Startup failure (no DB, bad file read, etc) # 1 = Startup failure (not running as root, no DB, bad file read, etc)
# #
# TODO: # TODO:
# - # -
@ -20,6 +20,10 @@ use Data::Dumper;
# Disable buffering # Disable buffering
$| = 1; $| = 1;
# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error.
$< = $>;
$( = $);
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD})) if (($running_directory =~ /^\./) && ($ENV{PWD}))
@ -31,6 +35,15 @@ my $anvil = Anvil::Tools->new({log_level => 2, log_secure => 1});
$anvil->Log->level({set => 2}); $anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1}); $anvil->Log->secure({set => 1});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
# Not root
print $anvil->Words->string({key => "error_0005"})."\n";
$anvil->nice_exit({exit_code => 1});
}
# These are the threasholds for when to alert when swap is running out. # These are the threasholds for when to alert when swap is running out.
$anvil->data->{scancore}{'scan-hardware'}{disable} = 0; $anvil->data->{scancore}{'scan-hardware'}{disable} = 0;
$anvil->data->{scancore}{'scan-hardware'}{ram}{clear_threshold} = 134217728; # 128 MiB $anvil->data->{scancore}{'scan-hardware'}{ram}{clear_threshold} = 134217728; # 128 MiB

@ -8,7 +8,7 @@
# #
# Exit codes; # Exit codes;
# 0 = Normal exit. # 0 = Normal exit.
# 1 = Startup failure (no DB, bad file read, etc) # 1 = Startup failure (not running as root, no DB, bad file read, etc)
# 2 = libvirtd is not running. # 2 = libvirtd is not running.
# #
# TODO: # TODO:
@ -19,10 +19,15 @@ use strict;
use warnings; use warnings;
use Anvil::Tools; use Anvil::Tools;
use Data::Dumper; use Data::Dumper;
use Text::Diff;
# Disable buffering # Disable buffering
$| = 1; $| = 1;
# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error.
$< = $>;
$( = $);
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD})) if (($running_directory =~ /^\./) && ($ENV{PWD}))
@ -34,6 +39,15 @@ my $anvil = Anvil::Tools->new({log_level => 2, log_secure => 1});
$anvil->Log->level({set => 2}); $anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1}); $anvil->Log->secure({set => 1});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
# Not root
print $anvil->Words->string({key => "error_0005"})."\n";
$anvil->nice_exit({exit_code => 1});
}
$anvil->data->{scancore}{'scan-server'}{disable} = 0; $anvil->data->{scancore}{'scan-server'}{disable} = 0;
$anvil->data->{switches}{force} = 0; $anvil->data->{switches}{force} = 0;
@ -50,7 +64,7 @@ if (($anvil->data->{scancore}{'scan-server'}{disable}) && (not $anvil->data->{sw
} }
# This scan agent only uses core tables (server and definitions). # This scan agent only uses core tables (server and definitions).
$anvil->data->{scancore}{'scan-server'}{tables} = [""]; $anvil->data->{scancore}{'scan-server'}{tables} = [];
# Handle start-up tasks # Handle start-up tasks
my $problem = $anvil->ScanCore->agent_startup({ my $problem = $anvil->ScanCore->agent_startup({
@ -103,6 +117,10 @@ sub collect_data
$anvil->nice_exit({exit_code => 2}); $anvil->nice_exit({exit_code => 2});
} }
# Load data we know about
$anvil->Database->get_servers({debug => 2});
$anvil->Database->get_server_definitions({debug => 2});
my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{virsh}." list --all", source => $THIS_FILE, line => __LINE__}); my ($output, $return_code) = $anvil->System->call({shell_call => $anvil->data->{path}{exe}{virsh}." list --all", source => $THIS_FILE, line => __LINE__});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, return_code => $return_code }}); $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output, return_code => $return_code }});
foreach my $line (split/\n/, $output) foreach my $line (split/\n/, $output)
@ -112,8 +130,8 @@ sub collect_data
if ($line =~ /^\d+ (.*?) (.*)$/) if ($line =~ /^\d+ (.*?) (.*)$/)
{ {
my $server = $1; my $server = $1;
my $state = $2; my $state = $2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
server => $server, server => $server,
'state' => $state, 'state' => $state,
@ -165,25 +183,174 @@ sub collect_data
} }
my $server_uuid = $anvil->data->{server}{$target}{$server}{$source}{info}{uuid}; my $server_uuid = $anvil->data->{server}{$target}{$server}{$source}{info}{uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { server_uuid => $server_uuid }}); my $server_name = $anvil->data->{server}{$target}{$server}{$source}{info}{name};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
server_uuid => $server_uuid,
server_name => $server_name,
}});
# See if this server is in the database. # See if this server is in the database.
my $query = "SELECT COUNT(*) FROM servers WHERE server_uuid = ".$anvil->Database->quote($server_uuid).";"; if (not exists $anvil->data->{servers}{server_uuid}{$server_uuid})
my $count = $anvil->Database->query({query => $function_query, source => $THIS_FILE, line => __LINE__})->[0]->[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { count => $count }});
if (not $count)
{ {
# Add it. # Add it. I'll need my anvil_uuid first.
my $anvil_uuid = $anvil->Cluster->get_anvil_uuid({debug => 2});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { anvil_uuid => $anvil_uuid }});
my $got_server_uuid = $anvil->Database->insert_or_update_servers({
debug => 2,
server_uuid => $server_uuid,
server_name => $server_name,
server_anvil_uuid => $anvil_uuid,
server_clean_stop => "",
server_start_after_server_uuid => "",
server_start_delay => 0,
server_host_uuid => $anvil->Get->host_uuid,
server_state => $anvil->data->{'scan-server'}{server}{$server}{'state'},
server_live_migration => 1,
server_pre_migration_file_uuid => "",
server_pre_migration_arguments => "",
server_post_migration_file_uuid => "",
server_post_migration_arguments => "",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { got_server_uuid => $got_server_uuid }});
if ((not $got_server_uuid) or ($got_server_uuid eq "!!error!!"))
{
# What?
next;
}
else
{
# Store the definition from memory
my $server_definition_uuid = $anvil->Database->insert_or_update_server_definitions({
debug => 2,
server_definition_xml => $definition,
server_definition_server_uuid => $server_uuid,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_definition_uuid => $server_definition_uuid }});
if ((not $server_definition_uuid) or ($server_definition_uuid ne "!!error!!"))
{
# What?
next;
}
}
# Reload the servers.
$anvil->Database->get_servers({debug => 2});
$anvil->Database->get_server_definitions({debug => 2});
} }
### TODO: left off here, look for the XML file on disk. If it's not found, write it. # If the defition in the database isn't the same as the definition in memory, update it.
my $xml_file = $anvil->data->{path}{directories}{shared}{definitions}."/".$server.".xml"; if ($definition ne $anvil->data->{server_definitions}{server_definition_server_uuid}{$server_uuid}{server_definition_xml})
if (-e $xml_file)
{ {
$anvil->Storage->get_file_stats({ # Register a notice-level alert.
debug => 2, my $difference = diff \$anvil->data->{server_definitions}{server_definition_server_uuid}{$server_uuid}{server_definition_xml}, \$definition, { STYLE => 'Unified' };
file_path => $xml_file, my $variables = {
server => $server,
difference => $difference,
};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0001", variables => $variables});
$anvil->Alert->register({
alert_level => "notice",
message => "scan_server_alert_0001",
message_variables => $variables,
set_by => $THIS_FILE,
});
# Update the definition in the database.
my $server_definition_uuid = $anvil->Database->insert_or_update_server_definitions({
debug => 2,
server_definition_xml => $definition,
server_definition_server_uuid => $server_uuid,
}); });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { server_definition_uuid => $server_definition_uuid }});
if ((not $server_definition_uuid) or ($server_definition_uuid ne "!!error!!"))
{
# What?
next;
}
$anvil->Database->get_server_definitions({debug => 2});
}
### NOTE: If the disk version differs from the in-memory or in-database copy, and the
### age of the file on disk is newer than the age of the database record (which will
### match the in-memory definition by this point), we'll leave the disk version alone.
### This is done so that a manual edit of the definition file won't be immediately
### overwritten by the definition in memory.
# If the file doesn't exist, we'll write it out.
# If it does exist, but differs from the version in memory, we'll write the file.
my $write_file = 0;
my $xml_file = $anvil->data->{path}{directories}{shared}{definitions}."/".$server.".xml";
if (not -e $xml_file)
{
$write_file = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { write_file => $write_file }});
}
else
{
my $on_disk_definition = $anvil->Storage->read_file({
debug => 2,
file => $xml_file,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { on_disk_definition => $on_disk_definition }});
if (($on_disk_definition ne "!!error!!") && ($on_disk_definition) && ($definition ne $on_disk_definition))
{
$anvil->Storage->get_file_stats({
debug => 2,
file_path => $xml_file,
});
my $current_time = time;
my $file_modified_time = $anvil->data->{file_stat}{$xml_file}{modified_time};
my $database_modified_time = $anvil->data->{server_definitions}{server_definition_server_uuid}{$server_uuid}{unix_modified_time};
my $file_age = $current_time - $file_modified_time;
my $database_age = $current_time - $database_modified_time;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
's1:current_time' => $current_time,
's2:file_modified_time' => $file_modified_time,
's3:database_modified_time' => $database_modified_time,
's4:file_age' => $file_age,
's5:database_age' => $database_age,
}});
# Compare the age of the on-disk file with the age of the database record. If
# the database age is newer, update the on-disk copy.
if ($file_age >= $database_age)
{
# Update the disk copy.
my $difference = diff \$anvil->data->{server_definitions}{server_definition_server_uuid}{$server_uuid}{server_definition_xml}, \$definition, { STYLE => 'Unified' };
my $variables = {
server => $server,
difference => $difference,
};
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "scan_server_alert_0002", variables => $variables});
$anvil->Alert->register({
alert_level => "notice",
message => "scan_server_alert_0002",
message_variables => $variables,
set_by => $THIS_FILE,
});
$write_file = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { write_file => $write_file }});
}
}
}
if ($write_file)
{
my $return = $anvil->Storage->write_file({
debug => 3,
body => $definition,
file => $xml_file,
overwrite => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'return' => $return }});
if ($return)
{
# Something went wrong.
next;
}
} }
} }

@ -14,7 +14,20 @@ NOTE: All string keys MUST be prefixed with the agent name! ie: 'scan_server_log
<language name="en_CA" long_name="Canadian English" description="ScanCore scan agent that monitors hardware, like RAM modules, CSS LED status, CPU information, etc."> <language name="en_CA" long_name="Canadian English" description="ScanCore scan agent that monitors hardware, like RAM modules, CSS LED status, CPU information, etc.">
<!-- Alert entries --> <!-- Alert entries -->
<key name="scan_server_alert_0001"></key> <key name="scan_server_alert_0001">
The definition file for the server: [#!variable!server!#] has changed relative to the database record. This is usually harmless.
The differences are:
====
#!variable!difference!#
====
</key>
<key name="scan_server_alert_0002">
The definition file for the server: [#!variable!server!#] has changed relative to disk record. This is usually harmless.
The differences are:
====
#!variable!difference!#
====
</key>
<!-- Log entries --> <!-- Log entries -->
<key name="scan_server_log_0001">Starting: [#!variable!program!#].</key> <key name="scan_server_log_0001">Starting: [#!variable!program!#].</key>

@ -1325,52 +1325,52 @@ CREATE TRIGGER trigger_servers
FOR EACH ROW EXECUTE PROCEDURE history_servers(); FOR EACH ROW EXECUTE PROCEDURE history_servers();
-- This stores the XML definition for a server. Whenever a definition is found missing on a node or DR host, -- This stores the XML definition for a server. Whenever a server_definition is found missing on a node or DR host,
-- it will be rewritten from here. If this copy changes, it will be updated on the hosts. -- it will be rewritten from here. If this copy changes, it will be updated on the hosts.
CREATE TABLE definitions ( CREATE TABLE server_definitions (
definition_uuid uuid not null primary key, server_definition_uuid uuid not null primary key,
definition_server_uuid uuid not null, -- This is the servers -> server_uuid of the server server_definition_server_uuid uuid not null, -- This is the servers -> server_uuid of the server
definition_xml text not null, -- This is the XML body. server_definition_xml text not null, -- This is the XML body.
modified_date timestamp with time zone not null, modified_date timestamp with time zone not null,
FOREIGN KEY(definition_server_uuid) REFERENCES servers(server_uuid) FOREIGN KEY(server_definition_server_uuid) REFERENCES servers(server_uuid)
); );
ALTER TABLE definitions OWNER TO admin; ALTER TABLE server_definitions OWNER TO admin;
CREATE TABLE history.definitions ( CREATE TABLE history.server_definitions (
history_id bigserial, history_id bigserial,
definition_uuid uuid, server_definition_uuid uuid,
definition_server_uuid uuid, server_definition_server_uuid uuid,
definition_xml text, server_definition_xml text,
modified_date timestamp with time zone not null modified_date timestamp with time zone not null
); );
ALTER TABLE history.definitions OWNER TO admin; ALTER TABLE history.server_definitions OWNER TO admin;
CREATE FUNCTION history_definitions() RETURNS trigger CREATE FUNCTION history_server_definitions() RETURNS trigger
AS $$ AS $$
DECLARE DECLARE
history_definitions RECORD; history_server_definitions RECORD;
BEGIN BEGIN
SELECT INTO history_definitions * FROM definitions WHERE definition_uuid = new.definition_uuid; SELECT INTO history_server_definitions * FROM server_definitions WHERE server_definition_uuid = new.server_definition_uuid;
INSERT INTO history.definitions INSERT INTO history.server_definitions
(definition_uuid, (server_definition_uuid,
definition_server_uuid, server_definition_server_uuid,
definition_xml, server_definition_xml,
modified_date) modified_date)
VALUES VALUES
(history_definitions.definition_uuid, (history_server_definitions.server_definition_uuid,
history_definitions.definition_server_uuid, history_server_definitions.server_definition_server_uuid,
history_definitions.definition_xml, history_server_definitions.server_definition_xml,
history_definitions.modified_date); history_server_definitions.modified_date);
RETURN NULL; RETURN NULL;
END; END;
$$ $$
LANGUAGE plpgsql; LANGUAGE plpgsql;
ALTER FUNCTION history_definitions() OWNER TO admin; ALTER FUNCTION history_server_definitions() OWNER TO admin;
CREATE TRIGGER trigger_definitions CREATE TRIGGER trigger_server_definitions
AFTER INSERT OR UPDATE ON definitions AFTER INSERT OR UPDATE ON server_definitions
FOR EACH ROW EXECUTE PROCEDURE history_definitions(); FOR EACH ROW EXECUTE PROCEDURE history_server_definitions();
-- It stores a general list of OUI (Organizationally Unique Identifier) to allow lookup of MAC address to -- It stores a general list of OUI (Organizationally Unique Identifier) to allow lookup of MAC address to

@ -1058,6 +1058,11 @@ The file: [#!variable!file!#] needs to be updated. The difference is:
<key name="log_0553">The server: [#!variable!server!#] has booted!</key> <key name="log_0553">The server: [#!variable!server!#] has booted!</key>
<key name="log_0554">Waiting for the server: [#!variable!server!#] to shut down...</key> <key name="log_0554">Waiting for the server: [#!variable!server!#] to shut down...</key>
<key name="log_0555">The server: [#!variable!server!#] is now off.</key> <key name="log_0555">The server: [#!variable!server!#] is now off.</key>
<key name="log_0556">The server: [#!variable!server!#] (#!variable!server_uuid!#) has a definition change:
====
#!variable!difference!#
====
</key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. --> <!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key> <key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -1857,6 +1862,30 @@ The error was:
</key> </key>
<key name="warning_0064">[ Warning ] - The server: [#!variable!server!#] was asked to be migrated to: [#!variable!requested_node!#], but the server is shutting down. Aborting.</key> <key name="warning_0064">[ Warning ] - The server: [#!variable!server!#] was asked to be migrated to: [#!variable!requested_node!#], but the server is shutting down. Aborting.</key>
<key name="warning_0065">[ Warning ] - The server: [#!variable!server!#] was asked to be migrated to: [#!variable!requested_node!#], but the server is already in the middle of a migration. Aborting.</key> <key name="warning_0065">[ Warning ] - The server: [#!variable!server!#] was asked to be migrated to: [#!variable!requested_node!#], but the server is already in the middle of a migration. Aborting.</key>
<key name="warning_0066">[ Warning ] - Failed to parse the XML:
========
#!variable!xml!#
========
The error was:
========
#!variable!error!#
========
</key>
<key name="warning_0067">[ Warning ] - Failed to find the server's UUID from the definition XML:
========
#!variable!xml!#
========
</key>
<key name="warning_0068">[ Warning ] - The server UUID read: from the definition XML doesn't match the passed-in server UUID.
Passed in UUID: [#!variable!passed_uuid!#]
Read UUID: .... [#!variable!read_uuid!#]
========
#!variable!xml!#
========
</key>
</language> </language>
<!-- 日本語 --> <!-- 日本語 -->

@ -5,7 +5,7 @@
# #
# Exit codes; # Exit codes;
# 0 = Normal exit or md5sum of this program changed and it exited to reload. # 0 = Normal exit or md5sum of this program changed and it exited to reload.
# 1 = # 1 = Not running as root.
# 2 = Unable to connect to any database, even after trying to initialize the local system. # 2 = Unable to connect to any database, even after trying to initialize the local system.
# #
# TODO: # TODO:
@ -65,6 +65,10 @@ if (($running_directory =~ /^\./) && ($ENV{PWD}))
# Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete. # Turn off buffering so that the pinwheel will display while waiting for the SSH call(s) to complete.
$| = 1; $| = 1;
# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error.
$< = $>;
$( = $);
# NOTE: Setting 'log_level' and 'log_secure' here will get overridden in the main lopp. Use the Log methods # NOTE: Setting 'log_level' and 'log_secure' here will get overridden in the main lopp. Use the Log methods
# in the loop as well to override defaults in code. # in the loop as well to override defaults in code.
my $anvil = Anvil::Tools->new(); my $anvil = Anvil::Tools->new();
@ -72,6 +76,15 @@ $anvil->Log->level({set => 2});
$anvil->Log->secure({set => 1}); $anvil->Log->secure({set => 1});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }}); $anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, secure => 0, key => "log_0115", variables => { program => $THIS_FILE }});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
# Not root
print $anvil->Words->string({key => "error_0005"})."\n";
$anvil->nice_exit({exit_code => 1});
}
# Connect to the database(s). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks # Connect to the database(s). If we have no connections, we'll proceed anyway as one of the 'run_once' tasks
# is to setup the database server. # is to setup the database server.
$anvil->Database->connect({debug => 3, check_if_configured => 1}); $anvil->Database->connect({debug => 3, check_if_configured => 1});

@ -6,7 +6,8 @@
# #
# Exit codes; # Exit codes;
# 0 = Normal exit. # 0 = Normal exit.
# 1 = No database connections available. # 1 = Not running as root.
# 2 =
# #
# TODO: # TODO:
# - Decide if it's worth having a separate ScanCore.log file or just feed into anvil.log. # - Decide if it's worth having a separate ScanCore.log file or just feed into anvil.log.
@ -20,6 +21,10 @@ use Data::Dumper;
# Disable buffering # Disable buffering
$| = 1; $| = 1;
# Prevent a discrepency between UID/GID and EUID/EGID from throwing an error.
$< = $>;
$( = $);
my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0]; my $THIS_FILE = ($0 =~ /^.*\/(.*)$/)[0];
my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0]; my $running_directory = ($0 =~ /^(.*?)\/$THIS_FILE$/)[0];
if (($running_directory =~ /^\./) && ($ENV{PWD})) if (($running_directory =~ /^\./) && ($ENV{PWD}))
@ -29,6 +34,15 @@ if (($running_directory =~ /^\./) && ($ENV{PWD}))
my $anvil = Anvil::Tools->new({log_level => 2, log_secure => 1}); my $anvil = Anvil::Tools->new({log_level => 2, log_secure => 1});
# Make sure we're running as 'root'
# $< == real UID, $> == effective UID
if (($< != 0) && ($> != 0))
{
# Not root
print $anvil->Words->string({key => "error_0005"})."\n";
$anvil->nice_exit({exit_code => 1});
}
$anvil->data->{scancore} = { $anvil->data->{scancore} = {
threshold => { threshold => {
warning_temperature => 5, warning_temperature => 5,

Loading…
Cancel
Save