Local modifications to ClusterLabs/Anvil by Alteeve
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1261 lines
53 KiB

package Anvil::Tools::Email;
#
# This module contains methods used to manage the local postfix server and handle and dispatch email via
# mailx.
#
### TODO: By default, a recipient receives all alerts at their default level. Later, we'll add an
### override table to allow a user to ignore a given striker or Anvil! node / dr host set. So
### creating this list is no longer needed.
use strict;
use warnings;
use Data::Dumper;
use JSON;
use Scalar::Util qw(weaken isweak);
use Text::Diff;
our $VERSION = "3.0.0";
my $THIS_FILE = "Email.pm";
### Methods;
# check_config
# check_queue
# get_current_server
# get_next_server
# send_alerts
#
=pod
=encoding utf8
=head1 NAME
Anvil::Tools::Email
Provides all methods used to manage the local C<< postfix >> server and handle and dispatch email via C<< mailx >>
=head1 SYNOPSIS
use Anvil::Tools;
# Get a common object handle on all Anvil::Tools modules.
my $anvil = Anvil::Tools->new();
# Access to methods using '$anvil->Email->X'.
#
#
=head1 METHODS
Methods in this module;
=cut
sub new
{
my $class = shift;
my $self = {
};
bless $self, $class;
return ($self);
}
# Get a handle on the Anvil::Tools object. I know that technically that is a sibling module, but it makes more
# sense in this case to think of it as a parent.
sub parent
{
my $self = shift;
my $parent = shift;
$self->{HANDLE}{TOOLS} = $parent if $parent;
# Defend against memory leads. See Scalar::Util'.
if (not isweak($self->{HANDLE}{TOOLS}))
{
weaken($self->{HANDLE}{TOOLS});
}
return ($self->{HANDLE}{TOOLS});
}
#############################################################################################################
# Public methods #
#############################################################################################################
=head2 check_config
This method checks the current postfix server configuration to see if it needs to be updated, then checks to see if the local C<< postfix >> daemon is enabled and started.
If any problem is encountered, C<< 1 >> is returned. Otherwise, if all is well, C<< 0 >> is returned.
This method takes no parameters.
=cut
sub check_config
{
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->check_config()" }});
my $problem = 0;
# We check to see if there are any emails in the queue. If we see queued emails for more than five
# minutes, and a second mail server is configured, we'll automatically reconfigure for the next
# known server.
$anvil->Database->get_mail_servers({debug => $debug});
my ($oldest_message) = $anvil->Email->check_queue({debug => $debug});
if ($oldest_message eq "!!error!!")
{
# Something went wrong, but the problem would already be logged, so just return.
$problem = 1;
}
elsif ($oldest_message > 600)
{
# Switch out mail servers. If there's only one mail server, this just checks the existing
# config.
my $mail_server_uuid = $anvil->Email->get_next_server({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mail_server_uuid => $mail_server_uuid }});
$anvil->Email->_configure_for_server({
debug => $debug,
mail_server_uuid => $mail_server_uuid,
});
return($problem);
}
# If not configured look in variables for 'mail_server::last_used::<mail_server_uuid>'. The first one
# that doesn't have an existing variable will be used. If all known mail servers have variables, the
# oldest is used.
#
# In any case where the mail server is configured, the server that is used has their
# 'mail_server::last_used::<mail_server_uuid>' variable set to the current time stamp.
# Get the list of mail servers.
my $reconfigure = 1;
# What, if anything, is the current mail server?
my $current_mail_server = "";
my $postfix_main = $anvil->Storage->read_file({
debug => $debug,
file => $anvil->data->{path}{configs}{postfix_main},
});
foreach my $line (split/\n/, $postfix_main)
{
if (($line =~ /relayhost = \[(.*?)\]:/) or ($line =~ /relayhost = (.*?):/))
{
$current_mail_server = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { current_mail_server => $current_mail_server }});
# What is the UUID for this mail server?
my $mail_server_uuid = $anvil->data->{mail_servers}{address_to_uuid}{$current_mail_server} ? $anvil->data->{mail_servers}{address_to_uuid}{$current_mail_server} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mail_server_uuid => $mail_server_uuid }});
if ($mail_server_uuid)
{
# Looks OK, so run the configure (it'll do nothing if there are no changes).
$reconfigure = 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reconfigure => $reconfigure }});
$anvil->Email->_configure_for_server({
debug => $debug,
mail_server_uuid => $mail_server_uuid,
});
}
}
}
if ($reconfigure)
{
my $used_mail_server_count = exists $anvil->data->{mail_servers}{use_order} ? keys %{$anvil->data->{mail_servers}{use_order}} : 0;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { used_mail_server_count => $used_mail_server_count }});
if (not $used_mail_server_count)
{
# Just pick the first one.
foreach my $mail_server_uuid (keys %{$anvil->data->{mail_servers}{mail_server}})
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mail_server_uuid => $mail_server_uuid }});
$anvil->Email->_configure_for_server({
debug => $debug,
mail_server_uuid => $mail_server_uuid,
});
}
}
}
return($problem);
}
=head2 check_queue
This method looks to see how many email messages are in the send queue and how long they've been there. The age of the older queued message is returned (in seconds). If there is a problem, C<< !!error!! >> is returned.
This method takes no parameters.
=cut
sub check_queue
{
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->check_queue()" }});
my $oldest_message = 0;
my ($queue, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{postqueue}." -j"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
queue => $queue,
return_code => $return_code,
}});
if ($queue =~ /^postqueue: warning:/)
{
# Something is up, we can't proceed.
if (($queue =~ /Mail system is down/) && (($< == 0) or ($> == 0)))
{
# Enable and start the postfix daemon.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0076", variables => { output => $queue }});
$anvil->System->enable_daemon({debug => $debug, daemon => "postfix.service"});
$anvil->System->start_daemon({debug => $debug, daemon => "postfix.service"});
# Try to check the queue again.
($queue, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{postqueue}." -j"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
queue => $queue,
return_code => $return_code,
}});
if ($queue =~ /^postqueue: warning:/)
{
# Still down
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0077", variables => { output => $queue }});
return("!!error!!");
}
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "warning_0069", variables => { output => $queue }});
return("!!error!!");
}
}
# This is empty if there is nothing in the queue.
foreach my $email (split/\n/, $queue)
{
### TODO: Wrap this in an eval
my $json = JSON->new->allow_nonref;
my $postqueueu = $json->decode($email);
my $queue_id = $postqueueu->{queue_id};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { queue_id => $queue_id }});
$anvil->data->{mail}{queue}{$queue_id}{sender} = $postqueueu->{sender};
$anvil->data->{mail}{queue}{$queue_id}{queue_name} = $postqueueu->{queue_name};
$anvil->data->{mail}{queue}{$queue_id}{arrival_time} = $postqueueu->{arrival_time};
$anvil->data->{mail}{queue}{$queue_id}{message_age} = time - $postqueueu->{arrival_time};
$anvil->data->{mail}{queue}{$queue_id}{message_size} = $postqueueu->{message_size};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"mail::queue::${queue_id}::sender" => $anvil->data->{mail}{queue}{$queue_id}{sender},
"mail::queue::${queue_id}::queue_name" => $anvil->data->{mail}{queue}{$queue_id}{queue_name},
"mail::queue::${queue_id}::arrival_time" => $anvil->data->{mail}{queue}{$queue_id}{arrival_time},
"mail::queue::${queue_id}::message_age" => $anvil->data->{mail}{queue}{$queue_id}{message_age},
"mail::queue::${queue_id}::message_size" => $anvil->data->{mail}{queue}{$queue_id}{message_size},
}});
foreach my $recipient_hash (@{$postqueueu->{recipients}})
{
my $address = $recipient_hash->{address};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { queue_id => $queue_id }});
$anvil->data->{mail}{queue}{$queue_id}{recipient}{$address}{delay_reason} = $recipient_hash->{delay_reason};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
"mail::queue::${queue_id}::recipient::${address}::delay_reason" => $anvil->data->{mail}{queue}{$queue_id}{recipient}{$address}{delay_reason},
}});
}
if ($anvil->data->{mail}{queue}{$queue_id}{message_age} > $oldest_message)
{
$oldest_message = $anvil->data->{mail}{queue}{$queue_id}{message_age};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { oldest_message => $oldest_message }});
}
};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { oldest_message => $oldest_message }});
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.
If only one mail servers exists, its UUID is returned, making this method safe to call without concern for configured mail server count.
This method takes no parameters.
=cut
sub get_next_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_next_server()" }});
if (not exists $anvil->data->{mail_servers}{mail_server})
{
$anvil->Database->get_mail_servers({debug => $debug});
}
# 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
# was last 0 is checked. If > 300, the mail server is reconfigured to use the mail server with the
# oldest 'mail_server::last_used::<mail_server_uuid>' time.
my $oldest_mail_server_time = time;
my $oldest_mail_server_uuid = "";
foreach my $mail_server_uuid (keys %{$anvil->data->{mail_servers}{mail_server}})
{
# HELO domain is 'DELETED' is the mail server is not used anymore
my $last_used = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{last_used};
my $helo_domain = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_helo_domain};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
mail_server_uuid => $mail_server_uuid,
last_used => $last_used,
helo_domain => $helo_domain,
}});
next if $helo_domain eq "DELETED";
if ($last_used < $oldest_mail_server_time)
{
$oldest_mail_server_time = $last_used;
$oldest_mail_server_uuid = $mail_server_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
oldest_mail_server_time => $oldest_mail_server_time,
oldest_mail_server_uuid => $oldest_mail_server_uuid,
}});
}
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { oldest_mail_server_uuid => $oldest_mail_server_uuid }});
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.
B<< Note >>: If there is no configured mail servers, this method returns with C<< 1 >> without actually doing anything. Otherwise, it returns C<< 0 >>.
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()" }});
# If we don't have a configured mail server, there's no reason processing alerts.
my $active_mail_server = $anvil->Email->get_current_server({debug => $debug});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { active_mail_server => $active_mail_server }});
if (not $active_mail_server)
{
# No mail server, no sense proceeding.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0543"});
return(1);
}
# Load the alerts
* Created Database->get_bridges() that, surprise, loads data from the 'bridges' table. * Started work on Get->available_resources() that will take an 'anvil_uuid' and figure out what resources are still available for use by new servers or that can be added to existing servers. * Fixed a bug in ScanCore->agent_startup() where tables weren't being generated properly from the agent's SQL file. * Made Storage->change_mode() return silently if it's called without a mode being passed. This happens frequently and is harmless so it's not worth filling the logs with errors. * Renamed the 'start_time' key to 'at_start' when recording files' MD5 sums in Storage->record_md5sums and ->check_md5sums. * When we moved the directory scan logic out of the 'scancore' daemon and into 'Storage->scan_directory', the logic to record scan agent names in 'scancore::agent::<file>' was removed. This broke a few things and, so, it was restored when it was found that a file starts with 'scan-' and the directory matches the scancore agent directory. * Moved the 'scancore' daemon's 'load_agent_strings' to 'Words' * Updated Words->parse_banged_string() to look for variables in the format 'value=X:units=Y' and translate it properly. * Fixed a bug in scan-ipmitool where discovered sensor INSERT SQL queries were queued, but not committed. * Fixed a bug in scan-storcli where a while loop was broken, preventing execution. * Fixed a bug in the 'scancore' daemon where it wouldn't exit if sums changed. Fixed a bug where alerts weren't being sent between loops. Fixed a bug where command-line log level wasn't surviving inside the main loop. Signed-off-by: Digimer <digimer@alteeve.ca>
4 years ago
$anvil->Database->get_alerts({debug => $debug});
$anvil->Database->get_recipients({debug => $debug});
my $host_uuid = $anvil->Get->host_uuid;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { host_uuid => $host_uuid }});
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_uuid => $alert_uuid,
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,
}});
# We should never have a processed alert or an alert for another host here, but just in case;
next if $alert_processed;
next if $alert_host_uuid ne $host_uuid;
# 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({
debug => $debug,
language => $recipient_language,
key_string => $alert_message,
});
* Created Database->get_bridges() that, surprise, loads data from the 'bridges' table. * Started work on Get->available_resources() that will take an 'anvil_uuid' and figure out what resources are still available for use by new servers or that can be added to existing servers. * Fixed a bug in ScanCore->agent_startup() where tables weren't being generated properly from the agent's SQL file. * Made Storage->change_mode() return silently if it's called without a mode being passed. This happens frequently and is harmless so it's not worth filling the logs with errors. * Renamed the 'start_time' key to 'at_start' when recording files' MD5 sums in Storage->record_md5sums and ->check_md5sums. * When we moved the directory scan logic out of the 'scancore' daemon and into 'Storage->scan_directory', the logic to record scan agent names in 'scancore::agent::<file>' was removed. This broke a few things and, so, it was restored when it was found that a file starts with 'scan-' and the directory matches the scancore agent directory. * Moved the 'scancore' daemon's 'load_agent_strings' to 'Words' * Updated Words->parse_banged_string() to look for variables in the format 'value=X:units=Y' and translate it properly. * Fixed a bug in scan-ipmitool where discovered sensor INSERT SQL queries were queued, but not committed. * Fixed a bug in scan-storcli where a while loop was broken, preventing execution. * Fixed a bug in the 'scancore' daemon where it wouldn't exit if sums changed. Fixed a bug where alerts weren't being sent between loops. Fixed a bug where command-line log level wasn't surviving inside the main loop. Signed-off-by: Digimer <digimer@alteeve.ca>
4 years ago
# A lot of multi-line strings start with an opening new line. This removes that.
$message =~ s/^\n//;
$message =~ s/\n$//s;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { message => $message }});
if ($alert_title)
{
* Created Database->get_bridges() that, surprise, loads data from the 'bridges' table. * Started work on Get->available_resources() that will take an 'anvil_uuid' and figure out what resources are still available for use by new servers or that can be added to existing servers. * Fixed a bug in ScanCore->agent_startup() where tables weren't being generated properly from the agent's SQL file. * Made Storage->change_mode() return silently if it's called without a mode being passed. This happens frequently and is harmless so it's not worth filling the logs with errors. * Renamed the 'start_time' key to 'at_start' when recording files' MD5 sums in Storage->record_md5sums and ->check_md5sums. * When we moved the directory scan logic out of the 'scancore' daemon and into 'Storage->scan_directory', the logic to record scan agent names in 'scancore::agent::<file>' was removed. This broke a few things and, so, it was restored when it was found that a file starts with 'scan-' and the directory matches the scancore agent directory. * Moved the 'scancore' daemon's 'load_agent_strings' to 'Words' * Updated Words->parse_banged_string() to look for variables in the format 'value=X:units=Y' and translate it properly. * Fixed a bug in scan-ipmitool where discovered sensor INSERT SQL queries were queued, but not committed. * Fixed a bug in scan-storcli where a while loop was broken, preventing execution. * Fixed a bug in the 'scancore' daemon where it wouldn't exit if sums changed. Fixed a bug where alerts weren't being sent between loops. Fixed a bug where command-line log level wasn't surviving inside the main loop. Signed-off-by: Digimer <digimer@alteeve.ca>
4 years ago
my $title = "[ ".$alert_set_by." ] ".$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->Get->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 }});
# 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 $to = $recipient_name." <".$recipient_email.">";
my $email_body = "From: ".$from."
To: ".$to."
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.
my $file_time = $anvil->Get->date_and_time({file_name => 1});
my $short_uuid = $anvil->Get->uuid({short => 1});
my $file_name = $anvil->data->{path}{directories}{alert_emails}."/alert_email.".$file_time.".".$short_uuid;
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0541", variables => { file => $file_name }});
my $problem = $anvil->Storage->write_file({
file => $file_name,
body => $email_body,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { problem => $problem }});
# Call mailx to read it in
if ($problem)
{
# Something went wrong
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0143", variables => { file => $file_name }});
}
else
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0542", variables => { to => $to }});
my $shell_call = $anvil->data->{path}{exe}{mailx}." -t < ".$file_name;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { shell_call => $shell_call }});
my ($output, $return_code) = $anvil->System->call({debug => 3, shell_call => $shell_call });
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
}
}
### NOTE: We don't block setting this alert to processed because some alerts may have gotten out and
### we don't want to risk whatever went wrong leading to a flood or alert email files being
### generated or dispatched.
# Update the database to mark that the alerts have been processed
foreach my $alert_uuid (keys %{$anvil->data->{alerts}{alert_uuid}})
{
my $alert_processed = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_processed};
my $alert_host_uuid = $anvil->data->{alerts}{alert_uuid}{$alert_uuid}{alert_host_uuid};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
alert_uuid => $alert_uuid,
alert_host_uuid => $alert_host_uuid,
alert_processed => $alert_processed,
}});
# We should never have a processed alert or an alert for another host here, but just in case;
next if $alert_processed;
next if $alert_host_uuid ne $host_uuid;
my $query = "
UPDATE
alerts
SET
alert_processed = 1,
modified_date = ".$anvil->Database->quote($anvil->Database->refresh_timestamp)."
WHERE
alert_uuid = ".$anvil->Database->quote($alert_uuid)."
;";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { query => $query }});
$anvil->Database->write({query => $query, source => $THIS_FILE, line => __LINE__});
}
return(0);
}
# =head3
#
# Private Functions;
#
# =cut
#############################################################################################################
# Private functions #
#############################################################################################################
# This does the actual work of configuring postfix for a give mail server. Returns '1' if reconfigured,
# returns '0' if not.
sub _configure_for_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->_configure_for_server()" }});
my $reload = 0;
my $mail_server_uuid = defined $parameter->{mail_server_uuid} ? $parameter->{mail_server_uuid} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
mail_server_uuid => $mail_server_uuid,
}});
if (not $mail_server_uuid)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Email->register()", parameter => "_configure_for_server" }});
return($reload);
}
if (not exists $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid})
{
# Try loading the mail server data.
$anvil->Database->get_mail_servers({debug => $debug});
if (not exists $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid})
{
# Invalid UUID / mail server
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "error_0141", variables => { uuid => $mail_server_uuid }});
return($reload);
}
}
### Check / update / create relay_password
my $mail_server_address = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_address};
my $mail_server_port = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_port};
my $mail_server_username = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_username};
my $mail_server_password = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_password};
my $mail_server_security = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_security};
my $mail_server_authentication = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_authentication};
my $mail_server_helo_domain = $anvil->data->{mail_servers}{mail_server}{$mail_server_uuid}{mail_server_helo_domain};
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
mail_server_address => $mail_server_address,
mail_server_port => $mail_server_port,
mail_server_username => $mail_server_username,
mail_server_password => $mail_server_password,
mail_server_security => $mail_server_security,
mail_server_authentication => $mail_server_authentication,
mail_server_helo_domain => $mail_server_helo_domain,
}});
my $old_postfix_relay_file = "";
if (-e $anvil->data->{path}{configs}{postfix_relay_password})
{
$old_postfix_relay_file = $anvil->Storage->read_file({
debug => $debug,
secure => 1,
file => $anvil->data->{path}{configs}{postfix_relay_password},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => {
old_postfix_relay_file => $old_postfix_relay_file,
}});
}
my $new_postfix_relay_file = "[".$mail_server_address."]:".$mail_server_port." ".$mail_server_username.":".$mail_server_password."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, secure => 1, list => { new_postfix_relay_file => $new_postfix_relay_file }});
if ($new_postfix_relay_file ne $old_postfix_relay_file)
{
# Create the new relay file.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0530"});
$reload = 1;
my $error = $anvil->Storage->write_file({
backup => 0,
debug => $debug,
body => $new_postfix_relay_file,
file => $anvil->data->{path}{configs}{postfix_relay_password},
mode => "0644",
user => "root",
group => "root",
overwrite => 1,
secure => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
reload => $reload,
error => $error,
}});
# Generate the binary version.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0531"});
my ($output, $return_code) = $anvil->System->call({debug => $debug, shell_call => $anvil->data->{path}{exe}{postmap}." ".$anvil->data->{path}{configs}{postfix_relay_password}});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
output => $output,
return_code => $return_code,
}});
}
### Check / update main.cf
my $new_postfix_main = "";
my $old_postfix_main = $anvil->Storage->read_file({
debug => $debug,
file => $anvil->data->{path}{configs}{postfix_main},
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { old_postfix_relay_file => $old_postfix_relay_file }});
my $last_line = "";
my $relayhost_seen = 0;
my $relayhost_line = "relayhost = [".$mail_server_address."]:".$mail_server_port;
my $smtp_helo_name_seen = 0;
my $smtp_helo_name_line = "smtp_helo_name = ".$anvil->Get->domain_name();
my $smtp_use_tls_seen = 0;
my $smtp_use_tls_line = "smtp_use_tls = yes";
my $smtp_sasl_auth_enable_seen = 0;
my $smtp_sasl_auth_enable_line = "smtp_sasl_auth_enable = yes";
my $smtp_sasl_password_maps_seen = 0;
my $smtp_sasl_password_maps_line = "smtp_sasl_password_maps = hash:".$anvil->data->{path}{configs}{postfix_relay_password};
my $smtp_sasl_security_options_seen = 0;
my $smtp_sasl_security_options_line = "smtp_sasl_security_options =";
my $smtp_tls_CAfile_seen = 0;
my $smtp_tls_CAfile_line = "smtp_tls_CAfile = /etc/pki/tls/certs/ca-bundle.crt";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
relayhost_line => $relayhost_line,
smtp_helo_name_line => $smtp_helo_name_line,
smtp_use_tls_line => $smtp_use_tls_line,
smtp_sasl_auth_enable_line => $smtp_sasl_auth_enable_line,
smtp_sasl_password_maps_line => $smtp_sasl_password_maps_line,
smtp_sasl_security_options_line => $smtp_sasl_security_options_line,
smtp_tls_CAfile_line => $smtp_tls_CAfile_line,
}});
# Before we start, we'll see if our variables have been seen. If not, we'll inject the below the
# 'relay_host' section.
foreach my $line (split/\n/, $old_postfix_main)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^relayhost = /)
{
$relayhost_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { relayhost_seen => $relayhost_seen }});
}
if ($line =~ /^smtp_helo_name =/)
{
$smtp_helo_name_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { smtp_helo_name_seen => $smtp_helo_name_seen }});
}
if ($line =~ /^smtp_use_tls =/)
{
$smtp_use_tls_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { smtp_use_tls_seen => $smtp_use_tls_seen }});
}
if ($line =~ /^smtp_sasl_auth_enable =/)
{
$smtp_sasl_auth_enable_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { smtp_sasl_auth_enable_seen => $smtp_sasl_auth_enable_seen }});
}
if ($line =~ /^smtp_sasl_password_maps =/)
{
$smtp_sasl_password_maps_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { smtp_sasl_password_maps_seen => $smtp_sasl_password_maps_seen }});
}
if ($line =~ /^smtp_sasl_security_options =/)
{
$smtp_sasl_security_options_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { smtp_sasl_security_options_seen => $smtp_sasl_security_options_seen }});
}
if ($line =~ /^smtp_tls_CAfile =/)
{
$smtp_tls_CAfile_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { smtp_tls_CAfile_seen => $smtp_tls_CAfile_seen }});
}
}
foreach my $line (split/\n/, $old_postfix_main)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { line => $line }});
if ($line =~ /^relayhost = /)
{
$relayhost_seen = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { relayhost_seen => $relayhost_seen }});
if ($line ne $relayhost_line)
{
# Rewrite the line.
$line = $relayhost_line;
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:line' => $line,
's2:reload' => $reload,
}});
}
}
if (($last_line eq "#relayhost = [an.ip.add.ress]") && ($line eq "") && (not $relayhost_seen))
{
# Never configured before, inject our line.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0532"});
$new_postfix_main .= $relayhost_line."\n";
$relayhost_seen = 1;
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:relayhost_line' => $relayhost_line,
's2:relayhost_seen' => $relayhost_seen,
's3:reload' => $reload,
}});
# Inject any other variables we've not seen yet.
if (not $smtp_helo_name_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_helo_name_line }});
$reload = 1;
$smtp_helo_name_seen = 1;
$new_postfix_main .= $smtp_helo_name_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_helo_name_line' => $smtp_helo_name_line,
's2:smtp_helo_name_seen' => $smtp_helo_name_seen,
's3:reload' => $reload,
}});
}
if (not $smtp_use_tls_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_use_tls_line }});
$reload = 1;
$smtp_use_tls_seen = 1;
$new_postfix_main .= $smtp_use_tls_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_use_tls_line' => $smtp_use_tls_line,
's2:smtp_use_tls_seen' => $smtp_use_tls_seen,
's3:reload' => $reload,
}});
}
if (not $smtp_sasl_auth_enable_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_sasl_auth_enable_line }});
$reload = 1;
$smtp_sasl_auth_enable_seen = 1;
$new_postfix_main .= $smtp_sasl_auth_enable_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_sasl_auth_enable_line' => $smtp_sasl_auth_enable_line,
's2:smtp_sasl_auth_enable_seen' => $smtp_sasl_auth_enable_seen,
's3:reload' => $reload,
}});
}
if (not $smtp_sasl_password_maps_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_sasl_password_maps_line }});
$reload = 1;
$smtp_sasl_password_maps_seen = 1;
$new_postfix_main .= $smtp_sasl_password_maps_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_sasl_password_maps_line' => $smtp_sasl_password_maps_line,
's2:smtp_sasl_password_maps_seen' => $smtp_sasl_password_maps_seen,
's3:reload' => $reload,
}});
}
if (not $smtp_sasl_security_options_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_sasl_security_options_line }});
$reload = 1;
$smtp_sasl_security_options_seen = 1;
$new_postfix_main .= $smtp_sasl_security_options_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_sasl_security_options_line' => $smtp_sasl_security_options_line,
's2:smtp_sasl_security_options_seen' => $smtp_sasl_security_options_seen,
's3:reload' => $reload,
}});
}
if (not $smtp_tls_CAfile_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_tls_CAfile_line }});
$reload = 1;
$smtp_tls_CAfile_seen = 1;
$new_postfix_main .= $smtp_tls_CAfile_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_tls_CAfile_line' => $smtp_tls_CAfile_line,
's2:smtp_tls_CAfile_seen' => $smtp_tls_CAfile_seen,
's3:reload' => $reload,
}});
}
}
# Any other existing config lines
if ($line =~ /^smtp_helo_name =/)
{
if ($line ne $smtp_helo_name_line)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0534", variables => {
old_line => $line,
new_line => $smtp_tls_CAfile_line,
}});
$line = $smtp_helo_name_line;
$smtp_helo_name_seen = 1;
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:line' => $line,
's2:smtp_helo_name_seen' => $smtp_helo_name_seen,
's2:reload' => $reload,
}});
}
}
if ($line =~ /^smtp_use_tls =/)
{
if ($line ne $smtp_use_tls_line)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0534", variables => {
old_line => $line,
new_line => $smtp_use_tls_line,
}});
$line = $smtp_use_tls_line;
$smtp_use_tls_seen = 1;
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:line' => $line,
's2:smtp_use_tls_seen' => $smtp_use_tls_seen,
's2:reload' => $reload,
}});
}
}
if ($line =~ /^smtp_sasl_auth_enable =/)
{
if ($line ne $smtp_sasl_auth_enable_line)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0534", variables => {
old_line => $line,
new_line => $smtp_sasl_auth_enable_line,
}});
$line = $smtp_sasl_auth_enable_line;
$smtp_sasl_auth_enable_seen = 1;
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:line' => $line,
's2:smtp_sasl_auth_enable_seen' => $smtp_sasl_auth_enable_seen,
's2:reload' => $reload,
}});
}
}
if ($line =~ /^smtp_sasl_password_maps =/)
{
if ($line ne $smtp_sasl_password_maps_line)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0534", variables => {
old_line => $line,
new_line => $smtp_sasl_password_maps_line,
}});
$line = $smtp_sasl_password_maps_line;
$smtp_sasl_password_maps_seen = 1;
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:line' => $line,
's2:smtp_sasl_password_maps_seen' => $smtp_sasl_password_maps_seen,
's2:reload' => $reload,
}});
}
}
if ($line =~ /^smtp_sasl_security_options =/)
{
if ($line ne $smtp_sasl_security_options_line)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0534", variables => {
old_line => $line,
new_line => $smtp_sasl_security_options_line,
}});
$line = $smtp_sasl_security_options_line;
$smtp_sasl_security_options_seen = 1;
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:line' => $line,
's2:smtp_sasl_security_options_seen' => $smtp_sasl_security_options_seen,
's2:reload' => $reload,
}});
}
}
if ($line =~ /^smtp_tls_CAfile =/)
{
if ($line ne $smtp_tls_CAfile_line)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0534", variables => {
old_line => $line,
new_line => $smtp_tls_CAfile_line,
}});
$line = $smtp_tls_CAfile_line;
$smtp_tls_CAfile_seen = 1;
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:line' => $line,
's2:smtp_tls_CAfile_seen' => $smtp_tls_CAfile_seen,
's2:reload' => $reload,
}});
}
}
$new_postfix_main .= $line."\n";
$last_line = $line;
}
if (not $relayhost_seen)
{
# We apparently missed our injection point, append it to the end of the file.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $relayhost_line }});
$new_postfix_main .= $relayhost_line."\n";
$reload = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:relayhost_line' => $relayhost_line,
's2:reload' => $reload,
}});
}
if (not $smtp_helo_name_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_helo_name_line }});
$reload = 1;
$new_postfix_main .= $smtp_helo_name_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_helo_name_line' => $smtp_helo_name_line,
's2:reload' => $reload,
}});
}
if (not $smtp_use_tls_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_use_tls_line }});
$reload = 1;
$new_postfix_main .= $smtp_use_tls_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_use_tls_line' => $smtp_use_tls_line,
's2:reload' => $reload,
}});
}
if (not $smtp_sasl_auth_enable_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_sasl_auth_enable_line }});
$reload = 1;
$new_postfix_main .= $smtp_sasl_auth_enable_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_sasl_auth_enable_line' => $smtp_sasl_auth_enable_line,
's2:reload' => $reload,
}});
}
if (not $smtp_sasl_password_maps_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_sasl_password_maps_line }});
$reload = 1;
$new_postfix_main .= $smtp_sasl_password_maps_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_sasl_password_maps_line' => $smtp_sasl_password_maps_line,
's2:reload' => $reload,
}});
}
if (not $smtp_sasl_security_options_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_sasl_security_options_line }});
$reload = 1;
$new_postfix_main .= $smtp_sasl_security_options_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_sasl_security_options_line' => $smtp_sasl_security_options_line,
's2:reload' => $reload,
}});
}
if (not $smtp_tls_CAfile_seen)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0533", variables => { line => $smtp_tls_CAfile_line }});
$reload = 1;
$new_postfix_main .= $smtp_tls_CAfile_line."\n";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
's1:smtp_tls_CAfile_line' => $smtp_tls_CAfile_line,
's2:reload' => $reload,
}});
}
# Write out the file, if needed.
if ($old_postfix_main ne $new_postfix_main)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0517", variables => {
file => $anvil->data->{path}{configs}{postfix_main},
diff => diff \$old_postfix_main, \$new_postfix_main, { STYLE => 'Unified' },
}});
# Create the new relay file.
$reload = 1;
my $error = $anvil->Storage->write_file({
debug => $debug,
backup => 1,
body => $new_postfix_main,
file => $anvil->data->{path}{configs}{postfix_main},
mode => "0644",
user => "root",
group => "root",
overwrite => 1,
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
reload => $reload,
error => $error,
}});
}
# Make sure the postfix daemon is running and enabled.
my $postfix_started = 0;
# Is the postfix daemon running?
my $postfix_running = $anvil->System->check_daemon({daemon => "postfix.service"});
if (not $postfix_running)
{
# Start it.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0535", variables => { daemon => "postfix.service" }});
my $start_return_code = $anvil->System->start_daemon({daemon => "postfix.service"});
my $enable_return_code = $anvil->System->enable_daemon({daemon => "postfix.service"});
$postfix_started = 1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
start_return_code => $start_return_code,
enable_return_code => $enable_return_code,
postfix_started => $postfix_started,
}});
}
if ($reload)
{
# Record that we've switched to this mail server.
my $variable_uuid = $anvil->Database->insert_or_update_variables({
variable_name => "mail_server::last_used::${mail_server_uuid}",
variable_value => time,
variable_source_table => "hosts",
variable_source_uuid => $anvil->Get->host_uuid,
variable_section => "email::servers",
variable_description => "striker_0276",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { variable_uuid => $variable_uuid }});
# In some cases, postfix will already be running, but won't be enabled.
my $enable_return_code = $anvil->System->enable_daemon({daemon => "postfix.service"});
# Start the daemon
if (not $postfix_started)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "job_0091", variables => { daemon => "postfix.service" }});
my $restart_return_code = $anvil->System->restart_daemon({daemon => "postfix.service"});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { restart_return_code => $restart_return_code }});
}
}
# Lastly, make sure the alert email directory exists.
if (not -d $anvil->data->{path}{directories}{alert_emails})
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 1, key => "log_0536"});
my $failed = $anvil->Storage->make_directory({
debug => $debug,
directory => $anvil->data->{path}{directories}{alert_emails},
mode => "0775",
user => "root",
group => "root",
});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { failed => $failed }});
}
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { reload => $reload }});
return($reload);
}