* Got a lot of work done in generating emails. Doesn't work yet, but the code to generate emails for recipients using their preferred language and alert level is done (though limited testing so far).

* Dropped support for supporting imperial measurements in generated emails.
* Created Database->get_alerts() to read in alert data and ->get_recipients() to get the list of alert recipients.
* SQL Schema changes;
** Added 'alert_processed' to 'alerts' to track what alerts have been processed.
** Changed 'recipient_new_level' to 'recipient_level' now that we're only using 'notifications' as a per-host override for user/hosts alert levels.
** Removed 'recipient_units' as we're no longer supporting non-metric values.
* Updated Alert->register() to take strings for the alert level (which gets translated to integers).
* Created Email->get_current_server() to returned the mail_server_uuid of the active mail server (if any). Created ->send_alerts() to process unprocessed alerts and send emails to recipients.
* Updated Words->parse_banged_string() to take the 'language' parameter.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 4 years ago
parent 4f39272d9a
commit 911523dfce
  1. 137
      Anvil/Tools/Alert.pm
  2. 475
      Anvil/Tools/Database.pm
  3. 279
      Anvil/Tools/Email.pm
  4. 29
      Anvil/Tools/Words.pm
  5. 150
      cgi-bin/striker
  6. 13
      html/skins/alteeve/email.html
  7. 79
      notes
  8. 5
      rpm/SPECS/anvil.spec
  9. 49
      share/anvil.sql
  10. 25
      share/words.xml
  11. 16
      tools/test.pl

@ -77,7 +77,7 @@ sub parent
=head2 check_alert_sent
This is used by scan agents that need to track whether an alert was sent when a sensor dropped below/rose above a set alert threshold. For example, if a sensor alerts at 20°C and clears at 25°C, this will be called when either value is passed. When passing the warning threshold, the alert is registered and sent to the user. Once set, no further warning alerts are sent. When the value passes over the clear threshold, this is checked and if an alert was previously registered, it is removed and an "all clear" message is sent. In this way, multiple alerts will not go out if a sensor floats around the warning threshold and a "cleared" message won't be sent unless a "warning" message was previously sent.
This is used by programs, usually scancore scan agents, that need to track whether an alert was sent when a sensor dropped below/rose above a set alert threshold. For example, if a sensor alerts at 20°C and clears at 25°C, this will be called when either value is passed. When passing the warning threshold, the alert is registered and sent to the user. Once set, no further warning alerts are sent. When the value passes over the clear threshold, this is checked and if an alert was previously registered, it is removed and an "all clear" message is sent. In this way, multiple alerts will not go out if a sensor floats around the warning threshold and a "cleared" message won't be sent unless a "warning" message was previously sent.
If there is a problem, C<< !!error!! >> is returned.
@ -284,17 +284,17 @@ WHERE
=head2 register
This registers an alert to be sent later.
This registers an alert to be sent later by C<< Email->send_alerts >>.
The C<< alert_uuid >> is returned on success. If anything goes wrong, C<< !!error!! >> will be returned.
The C<< alert_uuid >> is returned on success. If anything goes wrong, C<< !!error!! >> is returned. If there are no recipients who would receive the alert, it will not be recorded and an empty string is returned.
Parameters;
=head3 alert_level (required)
This assigns an severity level to the alert. Any recipient listening to this level or higher will receive this alert.
This assigns an severity level to the alert. Any recipient listening to this level or higher will receive this alert. This value can be set as a numeric value or as a string.
=head4 1 (critical)
=head4 1 / critical
Alerts at this level will go to all recipients, except for those ignoring the source system entirely.
@ -302,19 +302,19 @@ This is reserved for alerts that could lead to imminent service interruption or
Alerts at this level should trigger alarm systems for all administrators as well as management who may be impacted by service interruptions.
=head4 2 (warning)
=head4 2 / warning
This is used for alerts that require attention from administrators. Examples include intentional loss of redundancy caused by load shedding, hardware in pre-failure, loss of input power, temperature anomalies, etc.
Alerts at this level should trigger alarm systems for administrative staff.
=head4 3 (notice)
=head4 3 / notice
This is used for alerts that are generally safe to ignore, but might provide early warnings of developing issues or insight into system behaviour.
Alerts at this level should not trigger alarm systems. Periodic review is sufficient.
=head4 4 (info)
=head4 4 / info
This is used for alerts that are almost always safe to ignore, but may be useful in testing and debugging.
@ -353,7 +353,7 @@ NOTE: The timestamp is generally set for a given program or agent run (set when
=head3 title (optional)
NOTE: This is required if C<< show_header >> is set!
NOTE: If not set and C<< show_header >> is set to C<< 1 >>, a generic title will be added based on the C<< alert_level >> and if C<< clear_alert >> is set or not.
This is the title of the alert. It is expected to be in the format C<< <string_key> >>. If variables are to be injected into the C<< string_key >>, a comma-separated list in the format C<< !!variable_name1!value1!![,!!variable_nameN!valueN!!] >> is used.
@ -385,6 +385,7 @@ sub register
title => $title,
}});
# Missing parameters?
if (not $alert_level)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Alert->register()", parameter => "alert_level" }});
@ -400,13 +401,44 @@ sub register
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Alert->register()", parameter => "message" }});
return("!!error!!");
}
# If the alert level was a string, convert it to the numerical version. Also check that we've got a
# sane alert level at all.
if (lc($alert_level) eq "critical")
{
$alert_level = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { alert_level => $alert_level }});
}
elsif (lc($alert_level) eq "warning")
{
$alert_level = 2;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { alert_level => $alert_level }});
}
elsif (lc($alert_level) eq "notice")
{
$alert_level = 3;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { alert_level => $alert_level }});
}
elsif (lc($alert_level) eq "info")
{
$alert_level = 4;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { alert_level => $alert_level }});
}
elsif (($alert_level =~ /\D/) or ($alert_level < 1) or ($alert_level > 4))
{
# Invalid
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0142", variables => { alert_level => $alert_level }});
return("!!error!!");
}
# Do we need to generate a header?
if (($show_header) && (not $title))
{
# Set it based on the alert_level.
if ($alert_level eq "1") { $title = $clear_alert ? "alert_title_0005" : "alert_title_0001"; } # Critical (or Critical Cleared)
elsif ($alert_level eq "2") { $title = $clear_alert ? "alert_title_0006" : "alert_title_0002"; } # Warning (or Warning Cleared)
elsif ($alert_level eq "3") { $title = $clear_alert ? "alert_title_0007" : "alert_title_0003"; } # Notice (or Notice Cleared)
elsif ($alert_level eq "4") { $title = $clear_alert ? "alert_title_0008" : "alert_title_0004"; } # Info (or Info Cleared)
if ($alert_level == 1) { $title = $clear_alert ? "alert_title_0005" : "alert_title_0001"; } # Critical (or Critical Cleared)
elsif ($alert_level == 2) { $title = $clear_alert ? "alert_title_0006" : "alert_title_0002"; } # Warning (or Warning Cleared)
elsif ($alert_level == 3) { $title = $clear_alert ? "alert_title_0007" : "alert_title_0003"; } # Notice (or Notice Cleared)
elsif ($alert_level == 4) { $title = $clear_alert ? "alert_title_0008" : "alert_title_0004"; } # Info (or Info Cleared)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { title => $title }});
}
@ -417,65 +449,35 @@ sub register
# Before we actually record the alert, see if there are any recipients listening. For example, very
# rarely is anyone listening to alert level 4 (info), so skipping recording it saves unnecessary
# growth of the history.alerts table.
=cut
# In most cases, no one is listening to 'debug' or 'info' level alerts. If that is the case here,
# don't record the alert because it can cause the history.alerts table to grow needlessly. So find
# the lowest level log level actually being listened to and simply skip anything lower than that.
# 5 == debug
# 1 == critical
my $lowest_log_level = 5;
foreach my $integer (sort {$a cmp $b} keys %{$anvil->data->{alerts}{recipient}})
my $proceed = 0;
$anvil->Database->get_recipients({debug => $debug});
foreach my $recipient_uuid (keys %{$anvil->data->{recipients}{recipient_uuid}})
{
# We want to know the alert level, regardless of whether the recipient is an email of file
# target.
my $this_level;
if ($anvil->data->{alerts}{recipient}{$integer}{email})
{
# Email recipient
$this_level = ($anvil->data->{alerts}{recipient}{$integer}{email} =~ /level="(.*?)"/)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_level => $this_level }});
}
elsif ($anvil->data->{alerts}{recipient}{$integer}{file})
{
# File target
$this_level = ($anvil->data->{alerts}{recipient}{$integer}{file} =~ /level="(.*?)"/)[0];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_level => $this_level }});
}
my $recipient_email = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_email};
my $recipient_level = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:recipient_uuid' => $recipient_uuid,
's2:recipient_level' => $recipient_level,
's3:recipient_email' => $recipient_email,
}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { this_level => $this_level }});
if ($this_level)
if ($recipient_level >= $alert_level)
{
$this_level = $anvil->Alert->convert_level_name_to_number({level => $this_level});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
this_level => $this_level,
lowest_log_level => $lowest_log_level,
}});
if ($this_level < $lowest_log_level)
{
$lowest_log_level = $this_level;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { lowest_log_level => $lowest_log_level }});
}
# Someone wants to hear about this.
$proceed = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { proceed => $proceed }});
last;
}
}
# Now get the numeric value of this alert and return if it is higher.
my $this_level = $anvil->Alert->convert_level_name_to_number({level => $level});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
alert_level => $level,
this_level => $this_level,
lowest_log_level => $lowest_log_level,
}});
if ($this_level > $lowest_log_level)
if (not $proceed)
{
# Return.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0102", variables => { message => $message }});
return(0);
# No one is listening, ignore.
return("");
}
# Always INSERT. ScanCore removes them as they're acted on (copy is left in history.alerts).
my $alert_uuid = $anvil->Get->uuid();
my $query = "
INSERT INTO
alerts
@ -490,10 +492,10 @@ INSERT INTO
alert_show_header,
modified_date
) VALUES (
".$anvil->Database->quote($anvil->Get->uuid()).",
".$anvil->Database->quote($anvil->data->{sys}{host_uuid}).",
".$anvil->Database->quote($alert_uuid).",
".$anvil->Database->quote($anvil->Get->host_uuid()).",
".$anvil->Database->quote($set_by).",
".$anvil->Database->quote($level).",
".$anvil->Database->quote($alert_level).",
".$anvil->Database->quote($title).",
".$anvil->Database->quote($message).",
".$anvil->Database->quote($sort_position).",
@ -503,9 +505,10 @@ INSERT INTO
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
=cut
return(0);
### TODO: Add an optional 'send_now' parameter to causes us to call 'Email->send_alerts'
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { alert_uuid => $alert_uuid }});
return($alert_uuid);
}
### TODO: Write this, maybe? Or remove it and ->warning()?

@ -20,6 +20,7 @@ my $THIS_FILE = "Database.pm";
# configure_pgsql
# connect
# disconnect
# get_alerts
# get_anvils
# get_fences
# get_host_from_uuid
@ -1252,7 +1253,7 @@ sub connect
}});
# Copy my alert hash before I delete the uuid.
my $error_array = [];
# my $error_array = [];
# Delete this DB so that we don't try to use it later. This is a quiet alert because the
# original connection error was likely logged.
@ -1263,40 +1264,40 @@ sub connect
delete $anvil->data->{database}{$uuid};
# If I've not sent an alert about this DB loss before, send one now.
my $set = $anvil->Alert->check_alert_sent({
debug => $debug,
type => "set",
set_by => $THIS_FILE,
record_locator => $uuid,
name => "connect_to_db",
modified_date => $anvil->data->{sys}{database}{timestamp},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set }});
if ($set)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error_array => $error_array }});
foreach my $hash (@{$error_array})
{
my $message_key = $hash->{message_key};
my $message_variables = $hash->{message_variables};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
hash => $hash,
message_key => $message_key,
message_variables => $message_variables,
}});
# These are warning level alerts.
$anvil->Alert->register({
debug => $debug,
alert_level => "warning",
alert_set_by => $THIS_FILE,
alert_title_key => "alert_title_0003",
alert_message_key => $message_key,
alert_message_variables => $message_variables,
});
}
}
# my $set = $anvil->Alert->check_alert_sent({
# debug => $debug,
# type => "set",
# set_by => $THIS_FILE,
# record_locator => $uuid,
# name => "connect_to_db",
# modified_date => $anvil->data->{sys}{database}{timestamp},
# });
# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { set => $set }});
#
# if ($set)
# {
# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error_array => $error_array }});
# foreach my $hash (@{$error_array})
# {
# my $message = $hash->{message_key};
# my $variable_count = keys
# my $message_key = $hash->{message_key};
# my $message_variables = $hash->{message_variables};
# $anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
# hash => $hash,
# message_key => $message_key,
# message_variables => $message_variables,
# }});
#
# # These are warning level alerts.
# $anvil->Alert->register({
# debug => $debug,
# alert_level => "warning",
# set_by => $THIS_FILE,
# message => $message,
# });
# }
# }
}
# Send an 'all clear' message if a now-connected DB previously wasn't.
@ -1324,29 +1325,29 @@ sub connect
#
# if ($count > 0)
# {
my $cleared = $anvil->Alert->check_alert_sent({
debug => $debug,
type => "clear",
set_by => $THIS_FILE,
record_locator => $uuid,
name => "connect_to_db",
modified_date => $anvil->data->{sys}{database}{timestamp},
});
if ($cleared)
{
$anvil->Alert->register({
debug => $debug,
level => "warning",
agent_name => "Anvil!",
title_key => "an_title_0006",
message_key => "cleared_log_0055",
message_variables => {
name => $database_name,
host => $anvil->data->{database}{$uuid}{host},
port => defined $anvil->data->{database}{$uuid}{port} ? $anvil->data->{database}{$uuid}{port} : 5432,
},
});
}
# my $cleared = $anvil->Alert->check_alert_sent({
# debug => $debug,
# type => "clear",
# set_by => $THIS_FILE,
# record_locator => $uuid,
# name => "connect_to_db",
# modified_date => $anvil->data->{sys}{database}{timestamp},
# });
# if ($cleared)
# {
# $anvil->Alert->register({
# debug => $debug,
# level => "warning",
# agent_name => "Anvil!",
# title_key => "an_title_0006",
# message_key => "cleared_log_0055",
# message_variables => {
# name => $database_name,
# host => $anvil->data->{database}{$uuid}{host},
# port => defined $anvil->data->{database}{$uuid}{port} ? $anvil->data->{database}{$uuid}{port} : 5432,
# },
# });
# }
# }
}
@ -1439,35 +1440,94 @@ sub disconnect
}
=head2 get_recipients
=head2 get_alerts
This returns a list of users listening to alerts for a given host, along with their alert level.
This reads in alerts from the C<< alerts >> table.
This method takes no parameters.
Data is stored as:
alerts::alert_uuid::<alert_uuid>::alert_host_uuid
alerts::alert_uuid::<alert_uuid>::alert_set_by
alerts::alert_uuid::<alert_uuid>::alert_level
alerts::alert_uuid::<alert_uuid>::alert_title
alerts::alert_uuid::<alert_uuid>::alert_message
alerts::alert_uuid::<alert_uuid>::alert_sort_position
alerts::alert_uuid::<alert_uuid>::alert_show_header
alerts::alert_uuid::<alert_uuid>::alert_processed
alerts::alert_uuid::<alert_uuid>::unix_modified_date
alerts::alert_uuid::<alert_uuid>::modified_date
The C<< unix_modified_date >> is the unix timestamp to facilitate sorting by alert age.
Parameters;
=head3 include_processed (Optional, default 0)
By default, only unprocessed alerts are loaded. If this is set to C<< 1 >>, alerts that have already been processed will also be loaded.
=head3 all_hosts (Optional, default 0)
By default, only alerts registered on the load host are loaded. If this is set to C<< 1 >>, alerts from all hosts are loaded.
=cut
sub get_recipients
sub get_alerts
{
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_recipients()" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Database->get_manifests()" }});
my $all_hosts = defined $parameter->{all_hosts} ? $parameter->{all_hosts} : 0;
my $include_processed = defined $parameter->{include_processed} ? $parameter->{include_processed} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
all_hosts => $all_hosts,
include_processed => $include_processed,
}});
if (exists $anvil->data->{alerts})
{
delete $anvil->data->{alerts};
}
my $query = "
SELECT
recipient_uuid,
recipient_name,
recipient_email,
recipient_language,
recipient_units,
recipient_new_level
alert_uuid,
alert_host_uuid,
alert_set_by,
alert_level,
alert_title,
alert_message,
alert_sort_position,
alert_show_header,
alert_processed,
round(extract(epoch from modified_date)) AS unix_modified_date,
modified_date
FROM
recipients
alerts ";
if ((not $include_processed) && (not $all_hosts))
{
$query .= "
WHERE
alert_processed = '0'
AND
alert_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." ";
}
elsif (not $include_processed)
{
$query .= "
WHERE
alert_processed = '0' ";
}
elsif (not $all_hosts)
{
$query .= "
WHERE
alert_host_uuid = ".$anvil->Database->quote($anvil->Get->host_uuid)." "
}
$query .= "
;";
$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 => {
@ -1476,39 +1536,53 @@ FROM
}});
foreach my $row (@{$results})
{
my $recipient_uuid = $row->[0];
my $recipient_name = $row->[1];
my $recipient_email = $row->[2];
my $recipient_language = $row->[3];
my $recipient_units = $row->[4];
my $recipient_new_level = $row->[5];
my $alert_uuid = $row->[0];
my $alert_host_uuid = $row->[1];
my $alert_set_by = $row->[2];
my $alert_level = $row->[3];
my $alert_title = $row->[4];
my $alert_message = $row->[5];
my $alert_sort_position = $row->[6];
my $alert_show_header = $row->[7];
my $alert_processed = $row->[8];
my $unix_modified_date = $row->[9];
my $modified_date = $row->[10];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_units => $recipient_units,
recipient_new_level => $recipient_new_level,
}});
# Store the data
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_name} = $recipient_name;
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_email} = $recipient_email;
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_language} = $recipient_language;
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_units} = $recipient_units;
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_new_level} = $recipient_new_level;
$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_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_units" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_units},
"recipients::recipient_uuid::${recipient_uuid}}::recipient_new_level" => $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_new_level},
alert_uuid => $alert_uuid,
alert_host_uuid => $alert_host_uuid,
alert_set_by => $alert_set_by,
alert_level => $anvil->Log->is_secure($alert_level),
alert_title => $alert_title,
alert_message => $alert_message,
alert_sort_position => $alert_sort_position,
alert_show_header => $alert_show_header,
alert_processed => $alert_processed,
unix_modified_date => $unix_modified_date,
modified_date => $modified_date,
}});
# Make it easy to look up the mail server's UUID from the server address.
$anvil->data->{recipients}{email_to_uuid}{$recipient_email} = $recipient_uuid;
# Record the data in the hash, too.
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_host_uuid} = $alert_host_uuid;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_set_by} = $alert_set_by;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_level} = $alert_level;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_title} = $alert_title;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_message} = $alert_message;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_sort_position} = $alert_sort_position;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_show_header} = $alert_show_header;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_processed} = $alert_processed;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{unix_modified_date} = $unix_modified_date;
$anvil->data->{alerts}{alert_uuid}{$alert_uuid}{modified_date} = $modified_date;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"recipients::email_to_uuid::${recipient_email}" => $anvil->data->{recipients}{email_to_uuid}{$recipient_email},
"alerts::alert_uuid::${alert_uuid}::alert_host_uuid" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_host_uuid},
"alerts::alert_uuid::${alert_uuid}::alert_set_by" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_set_by},
"alerts::alert_uuid::${alert_uuid}::alert_level" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_level},
"alerts::alert_uuid::${alert_uuid}::alert_title" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_title},
"alerts::alert_uuid::${alert_uuid}::alert_message" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_message},
"alerts::alert_uuid::${alert_uuid}::alert_sort_position" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_sort_position},
"alerts::alert_uuid::${alert_uuid}::alert_show_header" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_show_header},
"alerts::alert_uuid::${alert_uuid}::alert_processed" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_processed},
"alerts::alert_uuid::${alert_uuid}::unix_modified_date" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{unix_modified_date},
"alerts::alert_uuid::${alert_uuid}::modified_date" => $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{modified_date},
}});
}
@ -2978,6 +3052,108 @@ FROM
}
=head2 get_recipients
This returns a list of users listening to alerts for a given host, along with their alert level.
This method takes no parameters.
=cut
sub get_recipients
{
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_recipients()" }});
# 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
recipient_uuid,
recipient_name,
recipient_email,
recipient_language,
recipient_level
FROM
recipients
;";
$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 $recipient_uuid = $row->[0];
my $recipient_name = $row->[1];
my $recipient_email = $row->[2];
my $recipient_language = $row->[3];
my $recipient_level = $row->[4];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_level => $recipient_level,
}});
# Store the data
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_name} = $recipient_name;
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_email} = $recipient_email;
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_language} = $recipient_language;
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_level} = $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 => {
"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_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}}::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.
$anvil->data->{recipients}{email_to_uuid}{$recipient_email} = $recipient_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"recipients::email_to_uuid::${recipient_email}" => $anvil->data->{recipients}{email_to_uuid}{$recipient_email},
}});
# If there is an override for a given recipient on this host, mark it as such.
foreach my $notification_uuid (keys %{$anvil->data->{notifications}{notification_uuid}})
{
my $notification_recipient_uuid = $anvil->data->{notifications}{notification_uuid}{$notification_uuid}{notification_recipient_uuid};
my $notification_host_uuid = $anvil->data->{notifications}{notification_uuid}{$notification_uuid}{notification_host_uuid};
my $notification_alert_level = $anvil->data->{notifications}{notification_uuid}{$notification_uuid}{notification_alert_level};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
notification_recipient_uuid => $notification_recipient_uuid,
notification_host_uuid => $notification_host_uuid,
notification_alert_level => $notification_alert_level,
}});
if (($notification_host_uuid eq $host_uuid) && ($notification_recipient_uuid eq $recipient_uuid))
{
$anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host} = $notification_alert_level;
$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},
}});
last;
}
}
}
return(0);
}
=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.
@ -7960,7 +8136,7 @@ This is the language that alert emails are crafted using for this recipient. Thi
This is the name of the recipient, and is used when crafting the email body and reply-to lists.
=head3 recipient_new_level (optional, default '2')
=head3 recipient_level (optional, default '2')
When adding a new Anvil! to the system, the recipient will automatically start monitoring the new Anvil! using this alert level. This can be set to C<< 0 >> to prevent auto-monitoring of new systems.
@ -7982,10 +8158,6 @@ Warning alerts. These are alerts that likely require the attention of an adminis
Notice alerts. These are generally low priority alerts that do not need attention, but might be indicators of developing problems. (ie: UPSes transfering to batteries, server migration/shut down/boot up, etc)
=head3 recipient_units (optional, default 'metric')
This can be set to 'imperial' if the user wants to receive values in imperial units. Currently, this causes temperatures to be returned in C<< °F >> instead of C<< °C >>.
=head3 recipient_uuid (optional)
If set, this is the UUID that will be used to update a record in the database. If not set, it will be searched for by looking for a matching C<< recipient_email >>.
@ -7999,27 +8171,25 @@ sub insert_or_update_recipients
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_recipients()" }});
my $delete = defined $parameter->{'delete'} ? $parameter->{'delete'} : 0;
my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : "";
my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $line = defined $parameter->{line} ? $parameter->{line} : "";
my $recipient_email = defined $parameter->{recipient_email} ? $parameter->{recipient_email} : "";
my $recipient_language = defined $parameter->{recipient_language} ? $parameter->{recipient_language} : "en_CA";
my $recipient_name = defined $parameter->{recipient_name} ? $parameter->{recipient_name} : "";
my $recipient_new_level = defined $parameter->{recipient_new_level} ? $parameter->{recipient_new_level} : "2";
my $recipient_units = defined $parameter->{recipient_units} ? $parameter->{recipient_units} : "metric";
my $recipient_uuid = defined $parameter->{recipient_uuid} ? $parameter->{recipient_uuid} : "";
my $delete = defined $parameter->{'delete'} ? $parameter->{'delete'} : 0;
my $uuid = defined $parameter->{uuid} ? $parameter->{uuid} : "";
my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $line = defined $parameter->{line} ? $parameter->{line} : "";
my $recipient_email = defined $parameter->{recipient_email} ? $parameter->{recipient_email} : "";
my $recipient_language = defined $parameter->{recipient_language} ? $parameter->{recipient_language} : "en_CA";
my $recipient_name = defined $parameter->{recipient_name} ? $parameter->{recipient_name} : "";
my $recipient_level = defined $parameter->{recipient_level} ? $parameter->{recipient_level} : "2";
my $recipient_uuid = defined $parameter->{recipient_uuid} ? $parameter->{recipient_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
'delete' => $delete,
uuid => $uuid,
file => $file,
line => $line,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_name => $recipient_name,
recipient_new_level => $recipient_new_level,
recipient_units => $recipient_units,
recipient_uuid => $recipient_uuid,
'delete' => $delete,
uuid => $uuid,
file => $file,
line => $line,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_name => $recipient_name,
recipient_level => $recipient_level,
recipient_uuid => $recipient_uuid,
}});
# Did we get a mail server name?
@ -8029,10 +8199,10 @@ sub insert_or_update_recipients
return("");
}
# Make sure the recipient_new_level is 0, 1, 2 or 3
if (($recipient_new_level ne "0") && ($recipient_new_level ne "1") && ($recipient_new_level ne "2") && ($recipient_new_level ne "3"))
# Make sure the recipient_level is 0, 1, 2 or 3
if (($recipient_level ne "0") && ($recipient_level ne "1") && ($recipient_level ne "2") && ($recipient_level ne "3"))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0108", variables => { recipient_new_level => $recipient_new_level }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0108", variables => { recipient_level => $recipient_level }});
return("");
}
@ -8132,16 +8302,14 @@ INSERT INTO
recipient_email,
recipient_language,
recipient_name,
recipient_new_level,
recipient_units,
recipient_level,
modified_date
) VALUES (
".$anvil->Database->quote($recipient_uuid).",
".$anvil->Database->quote($recipient_email).",
".$anvil->Database->quote($recipient_language).",
".$anvil->Database->quote($recipient_name).",
".$anvil->Database->quote($recipient_new_level).",
".$anvil->Database->quote($recipient_units).",
".$anvil->Database->quote($recipient_level).",
".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
);
";
@ -8156,8 +8324,7 @@ SELECT
recipient_email,
recipient_language,
recipient_name,
recipient_new_level,
recipient_units
recipient_level
FROM
recipients
WHERE
@ -8179,39 +8346,35 @@ WHERE
}
foreach my $row (@{$results})
{
my $old_recipient_email = $row->[0];
my $old_recipient_language = $row->[1];
my $old_recipient_name = $row->[2];
my $old_recipient_new_level = $row->[3];
my $old_recipient_units = $row->[4];
my $old_recipient_email = $row->[0];
my $old_recipient_language = $row->[1];
my $old_recipient_name = $row->[2];
my $old_recipient_level = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
old_recipient_email => $old_recipient_email,
old_recipient_language => $old_recipient_language,
old_recipient_name => $old_recipient_name,
old_recipient_new_level => $old_recipient_new_level,
old_recipient_units => $old_recipient_units,
old_recipient_email => $old_recipient_email,
old_recipient_language => $old_recipient_language,
old_recipient_name => $old_recipient_name,
old_recipient_level => $old_recipient_level,
}});
# Anything change?
if (($old_recipient_email ne $recipient_email) or
($old_recipient_language ne $recipient_language) or
($old_recipient_name ne $recipient_name) or
($old_recipient_new_level ne $recipient_new_level) or
($old_recipient_units ne $recipient_units))
if (($old_recipient_email ne $recipient_email) or
($old_recipient_language ne $recipient_language) or
($old_recipient_name ne $recipient_name) or
($old_recipient_level ne $recipient_level))
{
# Something changed, save.
my $query = "
UPDATE
recipients
SET
recipient_email = ".$anvil->Database->quote($recipient_email).",
recipient_language = ".$anvil->Database->quote($recipient_language).",
recipient_name = ".$anvil->Database->quote($recipient_name).",
recipient_new_level = ".$anvil->Database->quote($recipient_new_level).",
recipient_units = ".$anvil->Database->quote($recipient_units).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
recipient_email = ".$anvil->Database->quote($recipient_email).",
recipient_language = ".$anvil->Database->quote($recipient_language).",
recipient_name = ".$anvil->Database->quote($recipient_name).",
recipient_level = ".$anvil->Database->quote($recipient_level).",
modified_date = ".$anvil->Database->quote($anvil->data->{sys}{database}{timestamp})."
WHERE
recipient_uuid = ".$anvil->Database->quote($recipient_uuid)."
recipient_uuid = ".$anvil->Database->quote($recipient_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__});

@ -19,8 +19,11 @@ our $VERSION = "3.0.0";
my $THIS_FILE = "Email.pm";
### Methods;
# check_queue
# check_config
# check_queue
# get_current_server
# get_next_server
# send_alerts
#
=pod
@ -249,6 +252,53 @@ sub check_queue
return($oldest_message);
}
=head2 get_current_server
This method returns of the C<< mail_server_uuid >> of the currently configured mail server. If no mail server is currently configured, an empty string is returned.
This method takes no parameters.
=cut
sub get_current_server
{
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 => "Email->get_current_server()" }});
if (not exists $anvil->data->{mail_servers}{mail_server})
{
# Try loading the mail server data.
$anvil->Database->get_mail_servers({debug => $debug});
}
my $newest_mail_server_time = 0;
my $newest_mail_server_uuid = "";
foreach my $mail_server_uuid (keys %{$anvil->data->{mail_servers}{mail_server}})
{
my $last_used = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{last_used};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
mail_server_uuid => $mail_server_uuid,
last_used => $last_used,
}});
if ($last_used > $newest_mail_server_time)
{
$newest_mail_server_time = $last_used;
$newest_mail_server_uuid = $mail_server_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
newest_mail_server_time => $newest_mail_server_time,
newest_mail_server_uuid => $newest_mail_server_uuid,
}});
}
}
# TODO: Verify that this mail server is actually configured.
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { newest_mail_server_uuid => $newest_mail_server_uuid }});
return($newest_mail_server_uuid);
}
=head2 get_next_server
When two or more mail servers are configured, this will return the C<< mail_server_uuid >> of the mail server used in the most distant past. If two or more mail servers have never been used before, a random unused server is returned.
@ -264,8 +314,7 @@ sub get_next_server
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 => "Email->check_queue()" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0125", variables => { method => "Email->get_next_server()" }});
# If configured/running, the number of messages in queue is checked. If '0',
# 'mail_server::queue_empty' is updated with the current time. If 1 or more, the time since the queue
@ -296,6 +345,230 @@ sub get_next_server
return($oldest_mail_server_uuid);
}
=head2 send_alerts
This method looks for registered alerts, creates an email for recipients, and sends the resulting emails into the mail server queue for dispatch.
This method takes no parameters.
=cut
sub send_alerts
{
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 => "Email->send_alerts()" }});
# Load the alerts
$anvil->Database->get_recipients({debug => 2});
$anvil->Database->get_alerts({debug => 2});
foreach my $alert_uuid (keys %{$anvil->data->{alerts}{alert_uuid}})
{
my $alert_host_uuid = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_host_uuid};
my $alert_set_by = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_set_by};
my $alert_level = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_level};
my $alert_title = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_title};
my $alert_message = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_message};
my $alert_sort_position = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_sort_position};
my $alert_show_header = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_show_header};
my $alert_processed = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_processed};
my $unix_modified_date = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{unix_modified_date};
my $modified_date = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{modified_date};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
alert_host_uuid => $alert_host_uuid,
alert_set_by => $alert_set_by,
alert_level => $alert_level,
alert_title => $alert_title,
alert_message => $alert_message,
alert_sort_position => $alert_sort_position,
alert_show_header => $alert_show_header,
alert_processed => $alert_processed,
unix_modified_date => $unix_modified_date,
modified_date => $modified_date,
}});
# Walk through the recipients to see who wants to hear about this.
foreach my $recipient_uuid (keys %{$anvil->data->{recipients}{recipient_uuid}})
{
my $recipient_name = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_name};
my $recipient_email = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_email};
my $recipient_language = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_language};
my $recipient_level = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{level_on_host};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_level => $recipient_level,
}});
### NOTE: Levels;
# 1 - critical
# 2 - warning
# 3 - notice
# 4 - info
if ($recipient_level <= $alert_level)
{
# The user wants it.
my $message = $anvil->Words->parse_banged_string({
language => $recipient_language,
key_string => $alert_message,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { message => $message }});
if ($alert_title)
{
my $title = $anvil->Words->parse_banged_string({
language => $recipient_language,
key_string => $alert_title,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { title => $title }});
$message = $title."\n".$message."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { message => $message }});
}
# Store it in a sortable hash.
$anvil->data->{alerts}{queue}{$recipient_uuid}{$alert_sort_position}{$alert_level}{$unix_modified_date}{$alert_uuid} = $message;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"alerts::queue::${recipient_uuid}::${alert_sort_position}::${alert_level}::${unix_modified_date}::${alert_uuid}" => $anvil->data->{alerts}{queue}{$recipient_uuid}{$alert_sort_position}{$alert_level}{$unix_modified_date}{$alert_uuid},
}});
# This stores all recipients used in the 'Reply To' section. It also stores
# the highest alert level for the email subject line.
if (not exists $anvil->data->{alerts}{reply_to}{$recipient_uuid})
{
$anvil->data->{alerts}{reply_to}{$recipient_uuid}{highest_alert_level} = $alert_level;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"alerts::reply_to::${recipient_uuid}::highest_alert_level" => $anvil->data->{alerts}{reply_to}{$recipient_uuid}{highest_alert_level},
}});
}
elsif ($alert_level < $anvil->data->{alerts}{reply_to}{$recipient_uuid})
{
$anvil->data->{alerts}{reply_to}{$recipient_uuid}{highest_alert_level} = $alert_level;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"alerts::reply_to::${recipient_uuid}::highest_alert_level" => $anvil->data->{alerts}{reply_to}{$recipient_uuid}{highest_alert_level},
}});
}
}
}
}
# Build the emails now.
my $host_name = $anvil->_host_name;
foreach my $recipient_uuid (keys %{$anvil->data->{alerts}{queue}})
{
my $recipient_name = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_name};
my $recipient_email = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_email};
my $recipient_language = $anvil->data->{recipients}{recipient_uuid}{$recipient_uuid}{recipient_language};
my $highest_alert_level = $anvil->data->{alerts}{reply_to}{$recipient_uuid}{highest_alert_level};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
highest_alert_level => $highest_alert_level,
}});
# Build the message subject (I know I could be clever and append the level to 'email_000' but
# that makes it harder to search the code to uses of keys).
my $subject_key = "email_0004";
if ($highest_alert_level == 3) { $subject_key = "email_0003"; }
elsif ($highest_alert_level == 2) { $subject_key = "email_0002"; }
elsif ($highest_alert_level == 1) { $subject_key = "email_0001"; }
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { subject_key => $subject_key }});
my $subject = $anvil->Words->string({
language => $recipient_language,
key => $subject_key,
variables => {
host_name => $host_name,
},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { subject => $subject }});
my $footer = $anvil->Words->string({
language => $recipient_language,
key => "email_0005",
variables => {
host_name => $host_name,
},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { footer => $footer }});
### TODO: Determine if any of the sorts need to be reversed
# Build the message body now.
my $body = "";
foreach my $alert_sort_position (sort {$a cmp $b} keys %{$anvil->data->{alerts}{queue}{$recipient_uuid}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { alert_sort_position => $alert_sort_position }});
foreach my $alert_level (sort {$a cmp $b} keys %{$anvil->data->{alerts}{queue}{$recipient_uuid}{$alert_sort_position}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { alert_level => $alert_level }});
foreach my $unix_modified_date (sort {$a cmp $b} keys %{$anvil->data->{alerts}{queue}{$recipient_uuid}{$alert_sort_position}{$alert_level}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { unix_modified_date => $unix_modified_date }});
foreach my $alert_uuid (keys %{$anvil->data->{alerts}{queue}{$recipient_uuid}{$alert_sort_position}{$alert_level}{$unix_modified_date}})
{
my $message = $anvil->data->{alerts}{queue}{$recipient_uuid}{$alert_sort_position}{$alert_level}{$unix_modified_date}{$alert_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:alert_uuid' => $alert_uuid,
's2:message' => $message,
}});
$body .= $message."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { body => $body }});
}
}
}
}
# Not build the "Reply To" line.
my $reply_to = "";
foreach my $other_recipient_uuid (keys %{$anvil->data->{alerts}{queue}})
{
next if $recipient_uuid eq $other_recipient_uuid;
my $other_recipient_email = $anvil->data->{recipients}{recipient_uuid}{$other_recipient_uuid}{recipient_email};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
other_recipient_uuid => $other_recipient_uuid,
other_recipient_email => $other_recipient_email,
}});
$reply_to .= $other_recipient_email.", ";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reply_to => $reply_to }});
}
$reply_to =~ s/, $//;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reply_to => $reply_to }});
# Who are we sending as?
my $mail_server_uuid = $anvil->Email->get_current_server({debug => 2});
my $from = $mail_server_uuid ? $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_username} : "root\@".$host_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
mail_server_uuid => $mail_server_uuid,
from => $from,
}});
# Ready!
my $email_body = "
From: ".$from."
To: ".$recipient_name." <".$recipient_email.">
Subject: ".$subject."
Reply-To: ".$reply_to."
".$body."
".$footer."
";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { email_body => $email_body }});
# Write it to a file.
# Call mailx to read it in
}
return(0);
}
# =head3
#
# Private Functions;

@ -337,7 +337,17 @@ sub parse_banged_string
# Setup default values
my $out_string = "";
my $key_string = defined $parameter->{key_string} ? $parameter->{key_string} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { key_string => $key_string }});
my $language = defined $parameter->{language} ? $parameter->{language} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
key_string => $key_string,
language => $language,
}});
if (not $language)
{
$language = $anvil->Words->language();
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { language => $language }});
}
# Some variable values will be multi-line strings. We need to replace the new-lines in those
# multi-line values into '##br##' so that we can do a proper variable insertion. We can't simply
@ -462,13 +472,22 @@ sub parse_banged_string
}
# Parse the line now.
$out_string .= $anvil->Words->string({debug => $debug, key => $key, variables => $variables});
$out_string .= $anvil->Words->string({
test => 0,
key => $key,
variables => $variables,
language => $language,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { out_string => $out_string }});
}
else
{
# This key is just a key, no variables.
$out_string .= $anvil->Words->string({test => 0, key => $message});
$out_string .= $anvil->Words->string({
test => 0,
key => $message,
language => $language,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { out_string => $out_string }});
}
}
@ -728,8 +747,8 @@ sub string
# Setup default values
my $key = defined $parameter->{key} ? $parameter->{key} : "";
my $language = defined $parameter->{language} ? $parameter->{language} : $anvil->Words->language;
my $file = defined $parameter->{file} ? $parameter->{file} : $anvil->data->{path}{words}{'words.xml'};
my $language = $parameter->{language} ? $parameter->{language} : $anvil->Words->language;
my $file = $parameter->{file} ? $parameter->{file} : $anvil->data->{path}{words}{'words.xml'};
my $string = defined $parameter->{string} ? $parameter->{string} : "";
my $variables = defined $parameter->{variables} ? $parameter->{variables} : "";
### NOTE: Don't call Log->entry here, or we'll get a recursive loop! Use 'test' to debug.

@ -412,27 +412,25 @@ sub process_email_recipient_page
{
my ($anvil) = @_;
my $recipient_uuid = defined $anvil->data->{cgi}{recipient_uuid}{value} ? $anvil->data->{cgi}{recipient_uuid}{value} : "";
my $recipient_name = defined $anvil->data->{cgi}{recipient_name}{value} ? $anvil->data->{cgi}{recipient_name}{value} : "";
my $recipient_email = defined $anvil->data->{cgi}{recipient_email}{value} ? $anvil->data->{cgi}{recipient_email}{value} : "";
my $recipient_language = defined $anvil->data->{cgi}{recipient_language}{value} ? $anvil->data->{cgi}{recipient_language}{value} : "en_CA";
my $recipient_units = defined $anvil->data->{cgi}{recipient_units}{value} ? $anvil->data->{cgi}{recipient_units}{value} : "metric";
my $recipient_new_level = defined $anvil->data->{cgi}{recipient_new_level}{value} ? $anvil->data->{cgi}{recipient_new_level}{value} : "2";
my $delete = defined $anvil->data->{cgi}{'delete'}{value} ? $anvil->data->{cgi}{'delete'}{value} : "";
my $back = defined $anvil->data->{cgi}{back}{value} ? $anvil->data->{cgi}{back}{value} : "";
my $save = defined $anvil->data->{cgi}{save}{value} ? $anvil->data->{cgi}{save}{value} : "";
my $confirm = defined $anvil->data->{cgi}{confirm}{value} ? $anvil->data->{cgi}{confirm}{value} : "";
my $recipient_uuid = defined $anvil->data->{cgi}{recipient_uuid}{value} ? $anvil->data->{cgi}{recipient_uuid}{value} : "";
my $recipient_name = defined $anvil->data->{cgi}{recipient_name}{value} ? $anvil->data->{cgi}{recipient_name}{value} : "";
my $recipient_email = defined $anvil->data->{cgi}{recipient_email}{value} ? $anvil->data->{cgi}{recipient_email}{value} : "";
my $recipient_language = defined $anvil->data->{cgi}{recipient_language}{value} ? $anvil->data->{cgi}{recipient_language}{value} : "en_CA";
my $recipient_level = defined $anvil->data->{cgi}{recipient_level}{value} ? $anvil->data->{cgi}{recipient_level}{value} : "2";
my $delete = defined $anvil->data->{cgi}{'delete'}{value} ? $anvil->data->{cgi}{'delete'}{value} : "";
my $back = defined $anvil->data->{cgi}{back}{value} ? $anvil->data->{cgi}{back}{value} : "";
my $save = defined $anvil->data->{cgi}{save}{value} ? $anvil->data->{cgi}{save}{value} : "";
my $confirm = defined $anvil->data->{cgi}{confirm}{value} ? $anvil->data->{cgi}{confirm}{value} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_units => $recipient_units,
recipient_new_level => $recipient_new_level,
back => $back,
save => $save,
'delete' => $delete,
confirm => $confirm,
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_level => $recipient_level,
back => $back,
save => $save,
'delete' => $delete,
confirm => $confirm,
}});
if ($back)
@ -456,8 +454,7 @@ SELECT
recipient_name,
recipient_email,
recipient_language,
recipient_units,
recipient_new_level
recipient_level
FROM
recipients
WHERE
@ -473,17 +470,15 @@ WHERE
}});
foreach my $row (@{$results})
{
$recipient_name = $row->[0];
$recipient_email = $row->[1];
$recipient_language = $row->[2];
$recipient_units = $row->[3];
$recipient_new_level = $row->[4];
$recipient_name = $row->[0];
$recipient_email = $row->[1];
$recipient_language = $row->[2];
$recipient_level = $row->[3];
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_units => $recipient_units,
recipient_new_level => $recipient_new_level,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_level => $recipient_level,
}});
if ($delete)
@ -503,11 +498,10 @@ WHERE
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $ok_message }});
# Clear the form
$recipient_name = "";
$recipient_email = "";
$recipient_language = "en_CA";
$recipient_units = "metric";
$recipient_new_level = "2";
$recipient_name = "";
$recipient_email = "";
$recipient_language = "en_CA";
$recipient_level = "2";
}
else
{
@ -576,13 +570,12 @@ WHERE
if ($confirm)
{
($recipient_uuid) = $anvil->Database->insert_or_update_recipients({
debug => 2,
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_units => $recipient_units,
recipient_new_level => $recipient_new_level,
debug => 2,
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
recipient_level => $recipient_level,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { recipient_uuid => $recipient_uuid }});
if ($recipient_uuid)
@ -592,12 +585,11 @@ WHERE
$anvil->data->{form}{ok_message} = $anvil->Template->get({file => "main.html", name => "ok_message", variables => { ok_message => $ok_message }});
# Clear the form
$recipient_uuid = "";
$recipient_name = "";
$recipient_email = "";
$recipient_language = "en_CA";
$recipient_units = "metric";
$recipient_new_level = "2";
$recipient_uuid = "";
$recipient_name = "";
$recipient_email = "";
$recipient_language = "en_CA";
$recipient_level = "2";
}
else
{
@ -608,27 +600,22 @@ WHERE
}
else
{
my $say_recipient_units = "#!string!unit_0027!#";
if ($recipient_language eq "imperial")
{
$say_recipient_units = "#!string!unit_0028!#";
}
# Ignore
my $say_recipient_new_level = "#!string!unit_0023!#";
if ($recipient_new_level eq "1")
my $say_recipient_level = "#!string!unit_0023!#";
if ($recipient_level eq "1")
{
# Critical
$say_recipient_new_level = "#!string!unit_0024!#";
$say_recipient_level = "#!string!unit_0024!#";
}
elsif ($recipient_new_level eq "2")
elsif ($recipient_level eq "2")
{
# Warning
$say_recipient_new_level = "#!string!unit_0025!#";
$say_recipient_level = "#!string!unit_0025!#";
}
elsif ($recipient_new_level eq "3")
elsif ($recipient_level eq "3")
{
# Notice
$say_recipient_new_level = "#!string!unit_0026!#";
$say_recipient_level = "#!string!unit_0026!#";
}
my $say_recipient_language = $anvil->Words->language({iso => $recipient_language, long => 1});
$say_recipient_language = "???" if not $say_recipient_language;
@ -639,15 +626,13 @@ WHERE
$anvil->data->{form}{back_link} =~ s/save=.*?$//;
$anvil->data->{form}{refresh_link} = "";
$anvil->data->{form}{body} = $anvil->Template->get({file => "email.html", name => "recipient-confirm", variables => {
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
say_recipient_language => $say_recipient_language,
recipient_units => $recipient_units,
say_recipient_units => $say_recipient_units,
recipient_new_level => $recipient_new_level,
say_recipient_new_level => $say_recipient_new_level,
recipient_uuid => $recipient_uuid,
recipient_name => $recipient_name,
recipient_email => $recipient_email,
recipient_language => $recipient_language,
say_recipient_language => $say_recipient_language,
recipient_level => $recipient_level,
say_recipient_level => $say_recipient_level,
}});
return(0);
}
@ -728,21 +713,9 @@ WHERE
class => $anvil->data->{cgi}{recipient_language}{alert} ? "input_alert" : "input_clear",
});
# Units (select)
my $recipient_units_select = $anvil->Template->select_form({
name => "recipient_units",
options => [
"metric#!#".$anvil->Words->string({key => "unit_0027"}),
"imperial#!#".$anvil->Words->string({key => "unit_0028"}),
],
blank => 0,
selected => $recipient_units,
class => $anvil->data->{cgi}{recipient_units}{alert} ? "input_alert" : "input_clear",
});
# Log Level (select)
my $recipient_new_level_select = $anvil->Template->select_form({
name => "recipient_new_level",
my $recipient_level_select = $anvil->Template->select_form({
name => "recipient_level",
options => [
"0#!#".$anvil->Words->string({key => "unit_0023"}),
"1#!#".$anvil->Words->string({key => "unit_0024"}),
@ -750,8 +723,8 @@ WHERE
"3#!#".$anvil->Words->string({key => "unit_0026"}),
],
blank => 0,
selected => $recipient_new_level,
class => $anvil->data->{cgi}{recipient_new_level}{alert} ? "input_alert" : "input_clear",
selected => $recipient_level,
class => $anvil->data->{cgi}{recipient_level}{alert} ? "input_alert" : "input_clear",
});
# Show the menu.
@ -762,8 +735,7 @@ WHERE
recipient_name => $recipient_name_form,
recipient_email => $recipient_email_form,
language => $recipient_language_select,
units => $recipient_units_select,
new_level => $recipient_new_level_select,
new_level => $recipient_level_select,
recipient_uuid => $recipient_uuid,
}});

@ -352,8 +352,8 @@
#!string!striker_0191!#
</td>
<td class="column_row_value_fixed">
&nbsp; #!variable!say_recipient_new_level!#
<input type="hidden" name="recipient_new_level" id="recipient_new_level" value="#!variable!recipient_new_level!#"/>
&nbsp; #!variable!say_recipient_level!#
<input type="hidden" name="recipient_level" id="recipient_level" value="#!variable!recipient_level!#"/>
</td>
</tr>
<tr>
@ -365,15 +365,6 @@
<input type="hidden" name="recipient_language" id="recipient_language" value="#!variable!recipient_language!#"/>
</td>
</tr>
<tr>
<td class="column_header">
#!string!striker_0193!#
</td>
<td class="column_row_value_fixed">
&nbsp; #!variable!say_recipient_units!#
<input type="hidden" name="recipient_units" id="recipient_units" value="#!variable!recipient_units!#"/>
</td>
</tr>
<tr>
<td colspan="2" class="close_top">
&nbsp;

79
notes

@ -1,3 +1,82 @@
BEGIN TRANSACTION;
ALTER TABLE history.recipients RENAME recipient_new_level TO recipient_level;
ALTER TABLE history.recipients DROP COLUMN recipient_units;
ALTER TABLE recipients RENAME recipient_new_level TO recipient_level;
ALTER TABLE recipients DROP COLUMN recipient_units;
DROP FUNCTION history_recipients() CASCADE;
CREATE FUNCTION history_recipients() RETURNS trigger
AS $$
DECLARE
history_recipients RECORD;
BEGIN
SELECT INTO history_recipients * FROM recipients WHERE recipient_uuid = new.recipient_uuid;
INSERT INTO history.recipients
(recipient_uuid,
recipient_name,
recipient_email,
recipient_language,
recipient_level,
modified_date)
VALUES
(history_recipients.recipient_uuid,
history_recipients.recipient_name,
history_recipients.recipient_email,
history_recipients.recipient_language,
history_recipients.recipient_level,
history_recipients.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_recipients() OWNER TO admin;
CREATE TRIGGER trigger_recipients
AFTER INSERT OR UPDATE ON recipients
FOR EACH ROW EXECUTE PROCEDURE history_recipients();
ALTER TABLE alerts ADD COLUMN alert_processed integer not null default 0;
ALTER TABLE history.alerts ADD COLUMN alert_processed integer;
DROP FUNCTION history_alerts() CASCADE;
CREATE FUNCTION history_alerts() RETURNS trigger
AS $$
DECLARE
history_alerts RECORD;
BEGIN
SELECT INTO history_alerts * FROM alerts WHERE alert_uuid = new.alert_uuid;
INSERT INTO history.alerts
(alert_uuid,
alert_host_uuid,
alert_set_by,
alert_level,
alert_title,
alert_message,
alert_sort_position,
alert_show_header,
alert_processed,
modified_date)
VALUES
(history_alerts.alert_uuid,
history_alerts.alert_host_uuid,
history_alerts.alert_set_by,
history_alerts.alert_level,
history_alerts.alert_title,
history_alerts.alert_message,
history_alerts.alert_sort_position,
history_alerts.alert_show_header,
history_alerts.alert_processed,
history_alerts.modified_date);
RETURN NULL;
END;
$$
LANGUAGE plpgsql;
ALTER FUNCTION history_alerts() OWNER TO admin;
CREATE TRIGGER trigger_alerts
AFTER INSERT OR UPDATE ON alerts
FOR EACH ROW EXECUTE PROCEDURE history_alerts();
COMMIT;
============
From: test-alert@alert.alteeve.com
To: Madison Kelly <debug@alteeve.com>

@ -3,7 +3,7 @@
%define anvilgroup admin
Name: anvil
Version: 3.0
Release: 35%{?dist}
Release: 36%{?dist}
Summary: Alteeve Anvil! complete package.
License: GPLv2+
@ -374,6 +374,9 @@ fi
%changelog
* tbd Madison Kelly <mkelly@alteeve.ca> 3.0-36
- Updated source.
* Thu Sep 03 2020 Madison Kelly <mkelly@alteeve.ca> 3.0-35
- Added screen as a core module dependency
- Updated source.

@ -403,6 +403,7 @@ CREATE TABLE alerts (
alert_message text not null, -- ScanCore will read in the agents <name>.xml words file and look for this message key
alert_sort_position integer not null default 9999, -- The alerts will sort on this column. It allows for an optional sorting of the messages in the alert.
alert_show_header integer not null default 1, -- This can be set to have the alert be printed with only the contents of the string, no headers.
alert_processed integer not null default 0, -- This is set to '1' when an alert has been processed (sent to recipients)
modified_date timestamp with time zone not null,
FOREIGN KEY(alert_host_uuid) REFERENCES hosts(host_uuid)
@ -419,6 +420,7 @@ CREATE TABLE history.alerts (
alert_message text,
alert_sort_position integer,
alert_show_header integer,
alert_processed integer,
modified_date timestamp with time zone not null
);
ALTER TABLE history.alerts OWNER TO admin;
@ -438,6 +440,7 @@ BEGIN
alert_message,
alert_sort_position,
alert_show_header,
alert_processed,
modified_date)
VALUES
(history_alerts.alert_uuid,
@ -448,6 +451,7 @@ BEGIN
history_alerts.alert_message,
history_alerts.alert_sort_position,
history_alerts.alert_show_header,
history_alerts.alert_processed,
history_alerts.modified_date);
RETURN NULL;
END;
@ -460,28 +464,24 @@ CREATE TRIGGER trigger_alerts
FOR EACH ROW EXECUTE PROCEDURE history_alerts();
-- NOTE: This doesn't store the user's level, as it might be unique per Anvil!.
-- This is the list of alert recipients.
CREATE TABLE recipients (
recipient_uuid uuid not null primary key,
recipient_name text not null, -- This is the recipient's name
recipient_email text not null, -- This is the recipient's email address or the file name, depending.
recipient_language text not null, -- If set, this is the language the user wants to receive alerts in. If not set, the default language is used.
recipient_units text not null, -- This can be set to 'imperial' if the user prefers temperatures in °F
recipient_new_level integer not null, -- This is the alert level to use when automatically adding watch links to new systems. '0' tells us to ignore new systems, 1 is critical, 2 is warning, and 3 is notice
modified_date timestamp with time zone not null
recipient_uuid uuid not null primary key,
recipient_name text not null, -- This is the recipient's name
recipient_email text not null, -- This is the recipient's email address or the file name, depending.
recipient_language text not null, -- If set, this is the language the user wants to receive alerts in. If not set, the default language is used.
recipient_level integer not null, -- This is the default alert level this recipient is interested in. It can be adjusted on a per-host basis via the 'notifications' table.
modified_date timestamp with time zone not null
);
ALTER TABLE recipients OWNER TO admin;
CREATE TABLE history.recipients (
history_id bigserial,
recipient_uuid uuid,
recipient_name text,
recipient_email text,
recipient_language text,
recipient_units text,
recipient_new_level integer,
modified_date timestamp with time zone not null
history_id bigserial,
recipient_uuid uuid,
recipient_name text,
recipient_email text,
recipient_language text,
recipient_level integer,
modified_date timestamp with time zone not null
);
ALTER TABLE history.recipients OWNER TO admin;
@ -496,16 +496,14 @@ BEGIN
recipient_name,
recipient_email,
recipient_language,
recipient_units,
recipient_new_level,
recipient_level,
modified_date)
VALUES
(history_recipients.recipient_uuid,
history_recipients.recipient_name,
history_recipients.recipient_email,
history_recipients.recipient_language,
history_recipients.recipient_units,
history_recipients.recipient_new_level,
history_recipients.recipient_level,
history_recipients.modified_date);
RETURN NULL;
END;
@ -518,8 +516,8 @@ CREATE TRIGGER trigger_recipients
FOR EACH ROW EXECUTE PROCEDURE history_recipients();
-- This creates links between recipients and Anvil! systems, with a request alert level, so that we can
-- decide who gets what alerts for a given Anvil! system
-- This table is used when a user wants to set a custom alert level for a given machine. Typically this is
-- used to ignore test Anvil! systems.
CREATE TABLE notifications (
notification_uuid uuid not null primary key,
notification_recipient_uuid uuid not null, -- The recipient we're linking.
@ -536,7 +534,7 @@ CREATE TABLE history.notifications (
history_id bigserial,
notification_uuid uuid,
notification_recipient_uuid uuid,
notification_host_uuid uuid,
notification_host_uuid uuid,
notification_alert_level integer,
modified_date timestamp with time zone not null
);
@ -1647,7 +1645,8 @@ ALTER TABLE updated OWNER TO admin;
-- To avoid "waffling" when a sensor is close to an alert (or cleared) threshold, a gap between the alarm
-- value and the clear value is used. If the sensor climbs above (or below) the "clear" value, but didn't
-- previously pass the "alert" threshold, we DON'T want to send an "all clear" message. So do solve that,
-- this table is used by agents to record when a warning message was sent.
-- this table is used by agents to record when a warning message was sent (and as such, which need to be
-- cleared).
CREATE TABLE alert_sent (
alert_sent_uuid uuid not null primary key,
alert_sent_host_uuid uuid not null, -- The node associated with this alert

@ -35,6 +35,23 @@ Author: Madison Kelly <mkelly@alteeve.ca>
<key name="brand_0008">DR Host</key>
<key name="brand_0009">Unknown Type</key>
<!-- Emails messages -->
<key name="email_0001">[ #!string!brand_0004!# ] - Critical level alert from #!variable!host_name!#</key>
<key name="email_0002">[ #!string!brand_0004!# ] - Warning level alert from #!variable!host_name!#</key>
<key name="email_0003">[ #!string!brand_0004!# ] - Notice level alert from #!variable!host_name!#</key>
<key name="email_0004">[ #!string!brand_0004!# ] - Informational level alert from #!variable!host_name!#</key>
<key name="email_0005">
--
This alert email was sent from the machine:
- #!variable!host_name!#
It was generated by #!string!brand_0004!#, which is part of the #!string!brand_0002!# Intelligent Availability platform running on the host above.
This email was *not* sent by #!string!scancore_brand_0001!#. If you do not know why you are receiving this email, please speak to your system's administrator.
If you need any assistance, please feel free to contact #!string!brand_0001!# (https://alteeve.com) and we will do our best to assist.
</key>
<!-- Errors -->
<key name="error_0001">There are not enough network interfaces on this machine. You have: [#!variable!interface_count!#] interface(s), and you need at least: [#!variable!required_interfaces_for_single!#] interfaces to connect to the requested networks (one for Back-Channel and one for each Internet-Facing network).</key>
<key name="error_0002">The local system UUID can't be read yet. This might be because the system is brand new and/or ScanCore hasn't run yet. Please try again in a minute.</key>
@ -158,7 +175,7 @@ Failed to generate an RSA public key for the user: [#!variable!user!#]. The outp
<key name="error_0105">The file: [#!variable!file!#] was not found.</key>
<key name="error_0106"><![CDATA[The method Network->find_matches() was given the hash key: [#!variable!key!#], but it does not reference a hash. Are any IPs associated with this target?]]></key>
<key name="error_0107">Failed to reconnect after reconfiguring the network, exiting.</key>
<key name="error_0108">The 'recipient_new_level': [#!variable!recipient_new_level!#] is invalid. It should be '0', '1', '2', or '3'.</key>
<key name="error_0108">The 'recipient_level': [#!variable!recipient_level!#] is invalid. It should be '0', '1', '2', or '3'.</key>
<key name="error_0109">The 'notification_alert_level': [#!variable!notification_alert_level!#] is invalid. It should be '0', '1', '2', or '3'.</key>
<key name="error_0110">The 'notification_uuid': [#!variable!notification_uuid!#] was not found in the database.</key>
<key name="error_0111">
@ -210,6 +227,7 @@ The error was:
===========================================================
</key>
<key name="error_0141">There appears to be no mail server in the database with the UUID: [#!variable!uuid!#].</key>
<key name="error_0142">There alert level: [#!variable!alert_level!#] is invalid. Valid values are '1' / 'critical', '2' / 'warning, '3' / 'notice', and '4' / 'info'.</key>
<!-- Table headers -->
<key name="header_0001">Current Network Interfaces and States</key>
@ -1289,6 +1307,7 @@ About to try to download aproximately: [#!variable!packages!#] packages needed t
#############################################################################################################
</key> <!-- Translation note: System->update_hosts() looks for '##] anvil-daemon [##' to know if this alert was added to /etc/hosts. As such, please retain that exact string in your translation. -->
<key name="message_0178">Hosts added or updated by the #!string!brand_0002!# on: [#!variable!date!#]:</key>
<key name="message_0179">ScanCore has started.</key>
<!-- Success messages shown to the user -->
<key name="ok_0001">Saved the mail server information successfully!</key>
@ -1699,8 +1718,8 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="unit_0024">Critical</key> <!-- Alert level 1 -->
<key name="unit_0025">Warning</key> <!-- Alert level 2 -->
<key name="unit_0026">Notice</key> <!-- Alert level 3 -->
<key name="unit_0027">Metric</key>
<key name="unit_0028">Imperial</key>
<key name="unit_0027">Info</key> <!-- Alert level 4 -->
<key name="unit_0028"></key> <!-- free -->
<key name="unit_0029">Up</key>
<key name="unit_0030">Down</key>
<key name="unit_0031">Mbps</key>

@ -28,7 +28,17 @@ $anvil->Get->switches;
print "Connecting to the database(s);\n";
$anvil->Database->connect({debug => 2});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, secure => 0, key => "log_0132"});
#
# my ($oldest_message) = $anvil->Email->check_queue({debug => 2});
# print "Oldest message: [".$oldest_message."]\n";
if (0)
{
$anvil->Alert->register({
debug => 2,
alert_level => "warning",
message => "message_0179",
set_by => $THIS_FILE,
});
}
if (1)
{
$anvil->Email->send_alerts({debug => 2});
}

Loading…
Cancel
Save