* Updated the variables used for logging and log handles to be more inline with other variable names.

* Renamed Alert->register_alert() to ->register() and updated it to take 'clear_alert' and used it and the alert level to set the title automatically if not set by the user.
* Updated Log->_adjust_log_level() to record when the user set the log level at the command line so that invoked child processes get called with the same log level switch.
* Got the framework for actually calling scan agents in scancore in place. Untested so far.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 6 years ago
parent 8fad67fc5a
commit 53295a0d7f
  1. 21
      Anvil/Tools.pm
  2. 28
      Anvil/Tools/Alert.pm
  3. 20
      Anvil/Tools/Log.pm
  4. 27
      share/words.xml
  5. 64
      tools/scancore

@ -129,7 +129,9 @@ sub new
WORDS => Anvil::Tools::Words->new(),
VALIDATE => Anvil::Tools::Validate->new(),
# This is to be removed before development ends.
log_file => "",
'log' => {
main => "",
},
},
DATA => {},
ENV_VALUES => {
@ -389,10 +391,10 @@ sub nice_exit
}});
# Close the log file.
if ($anvil->data->{HANDLE}{log_file})
if ($anvil->data->{HANDLE}{'log'}{main})
{
close $anvil->data->{HANDLE}{log_file};
$anvil->data->{HANDLE}{log_file} = "";
close $anvil->data->{HANDLE}{'log'}{main};
$anvil->data->{HANDLE}{'log'}{main} = "";
}
exit($exit_code);
@ -800,8 +802,12 @@ sub _set_defaults
host_type => "",
host_uuid => "",
language => "en_CA",
log_date => 1,
log_file => "/var/log/anvil.log",
'log' => {
date => 1,
# Stores the '-v|...|-vvv' so that shell calls can be run at the same level as the
# avtive program when set by the user at the command line.
level => "",
},
manage => {
firewall => 1,
},
@ -1012,6 +1018,9 @@ sub _set_paths
'lock' => {
database => "/tmp/anvil-tools.database.lock",
},
'log' => {
main => "/var/log/anvil.log",
},
proc => {
uptime => "/proc/uptime",
},

@ -13,7 +13,7 @@ my $THIS_FILE = "Alert.pm";
### Methods;
# check_alert_sent
# error
# register_alert
# register
=pod
@ -282,7 +282,7 @@ WHERE
return($set);
}
=head2 register_alert
=head2 register
This registers an alert to be sent later.
@ -318,6 +318,10 @@ Alerts at this level should not trigger alarm systems. Periodic review is suffic
This is used for alerts that are almost always safe to ignore, but may be useful in testing and debugging.
=head3 clear_alert (optional, default '0')
If set, this indicate that the alert has returned to an OK state. Alert level is still honoured for notification target delivery decisions, but some internal values are adjusted.
=head3 message (required)
This is the message body 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.
@ -355,7 +359,7 @@ Example with a message alone; C<< foo_0001 >>.
Example with two variables; C<< foo_0002,!!bar!abc!!,!!baz!123!! >>.
=cut
sub register_alert
sub register
{
my $self = shift;
my $parameter = shift;
@ -363,13 +367,15 @@ sub register_alert
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
my $alert_level = defined $parameter->{alert_level} ? $parameter->{alert_level} : 0;
my $clear_alert = defined $parameter->{clear_alert} ? $parameter->{clear_alert} : 0;
my $message = defined $parameter->{message} ? $parameter->{message} : "";
my $set_by = defined $parameter->{set_by} ? $parameter->{set_by} : "";
my $show_header = defined $parameter->{show_header} ? $parameter->{show_header} : 1;
my $sort_position = defined $parameter->{sort_position} ? $parameter->{sort_position} : 9999;
my $title = defined $parameter->{title} ? $parameter->{title} : "title_0003";
my $title = defined $parameter->{title} ? $parameter->{title} : "";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
show_header => $show_header,
clear_alert => $clear_alert,
alert_level => $alert_level,
message => $message,
set_by => $set_by,
@ -379,23 +385,27 @@ sub register_alert
if (not $alert_level)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Alert->register_alert()", parameter => "alert_level" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Alert->register()", parameter => "alert_level" }});
return("!!error!!");
}
if (not $set_by)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Alert->register_alert()", parameter => "set_by" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Alert->register()", parameter => "set_by" }});
return("!!error!!");
}
if (not $message)
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Alert->register_alert()", parameter => "message" }});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0020", variables => { method => "Alert->register()", parameter => "message" }});
return("!!error!!");
}
if (($show_header) && (not $title))
{
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0101"});
return("!!error!!");
# 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)
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { title => $title }});
}
# zero-pad sort numbers so that they sort properly.

@ -278,7 +278,7 @@ sub entry
# Log the file and line, if passed.
my $string = "";
my $print_string = "";
if ($anvil->data->{sys}{log_date})
if ($anvil->data->{sys}{'log'}{date})
{
# Keep the debug level super high to avoid Get->date_and_time() going into an infinite loop.
$string .= $anvil->Get->date_and_time({debug => 99}).":";
@ -317,7 +317,7 @@ sub entry
}
# If the user set a log file, log to that. Otherwise, log via Log::Journald.
if ($anvil->data->{sys}{log_file})
if ($anvil->data->{path}{'log'}{main})
{
# TODO: Switch back to journald later, using a file for testing for now
if ($string !~ /\n$/)
@ -326,10 +326,10 @@ sub entry
}
# Open the file?
if (not $anvil->data->{HANDLE}{log_file})
if (not $anvil->data->{HANDLE}{'log'}{main})
{
# If the file doesn't start with a '/', we'll put it under /var/log.
my $log_file = $anvil->data->{sys}{log_file} =~ /^\// ? $anvil->data->{sys}{log_file} : "/var/log/".$anvil->data->{sys}{log_file};
my $log_file = $anvil->data->{path}{'log'}{main} =~ /^\// ? $anvil->data->{path}{'log'}{main} : "/var/log/".$anvil->data->{path}{'log'}{main};
my ($directory, $file) = ($log_file =~ /^(\/.*)\/(.*)$/);
### WARNING: We MUST set the debug level really high, or else we'll go into a deep
@ -342,20 +342,20 @@ sub entry
# NOTE: Don't call '$anvil->Log->entry()' here, it will cause a loop!
open (my $file_handle, ">>", $shell_call) or die "Failed to open: [$shell_call] for writing. The error was: $!\n";
$file_handle->autoflush(1);
$anvil->data->{HANDLE}{log_file} = $file_handle;
$anvil->data->{HANDLE}{'log'}{main} = $file_handle;
# Make sure it can be written to by apache.
$anvil->Storage->change_mode({debug => $debug, target => $log_file, mode => "0666"});
}
if (not $anvil->data->{HANDLE}{log_file})
if (not $anvil->data->{HANDLE}{'log'}{main})
{
# NOTE: This can't be a normal error because we can't write to the logs.
die $THIS_FILE." ".__LINE__."; log file handle doesn't exist, but it should by now.\n";
}
# The handle has to be wrapped in a block to make 'print' happy as it doesn't like non-scalars for file handles
print { $anvil->data->{HANDLE}{log_file} } $string;
print { $anvil->data->{HANDLE}{'log'}{main} } $string;
}
else
{
@ -716,25 +716,31 @@ sub _adjust_log_level
my $anvil = $self->parent;
my $debug = defined $parameter->{debug} ? $parameter->{debug} : 3;
### TODO: Support '--secure' and '--no-secure'
if ($anvil->data->{switches}{V})
{
$anvil->Log->level({set => 0});
$anvil->data->{sys}{'log'}{level} = "-V";
}
elsif ($anvil->data->{switches}{v})
{
$anvil->Log->level({set => 1});
$anvil->data->{sys}{'log'}{level} = "-v";
}
elsif ($anvil->data->{switches}{vv})
{
$anvil->Log->level({set => 2});
$anvil->data->{sys}{'log'}{level} = "-vv";
}
elsif ($anvil->data->{switches}{vvv})
{
$anvil->Log->level({set => 3});
$anvil->data->{sys}{'log'}{level} = "-vvv";
}
elsif ($anvil->data->{switches}{vvvv})
{
$anvil->Log->level({set => 4});
$anvil->data->{sys}{'log'}{level} = "-vvvv";
}
return(0);

@ -12,14 +12,17 @@ Author: Madison Kelly <mkelly@alteeve.ca>
<language name="en_CA" long_name="Canadian English" description="Anvil! language file.">
<!-- Alert titles -->
<key name="alert_title_0001">Debug</key>
<key name="alert_title_0002">Information</key>
<key name="alert_title_0001">Critical</key>
<key name="alert_title_0002">Warning</key>
<key name="alert_title_0003">Notice</key>
<key name="alert_title_0004">Warning</key>
<key name="alert_title_0005">Critical</key>
<key name="alert_title_0006">Warning Cleared</key>
<key name="alert_title_0007">Critical Cleared</key>
<key name="alert_title_0008">Important</key> <!-- This is used for 'warning' level alerts that aren't a problem, but important information. -->
<key name="alert_title_0004">Info</key>
<key name="alert_title_0005">Critical Cleared!</key>
<key name="alert_title_0006">Warning Cleared!</key>
<key name="alert_title_0007">Notice Cleared!</key>
<key name="alert_title_0008">Info Cleared!</key>
<!-- Alert messages -->
<key name="alert_message_0001">The scan agent: [#!variable!agent_name!#] timed out! It was given: [#!variable!timeout!#] seconds to run, but it didn't return, so it was terminated.</key>
<!-- Messages for users (less technical than log entries), though sometimes used for logs, too. -->
<key name="message_0001">The host name: [#!variable!target!#] does not resolve to an IP address.</key>
@ -91,7 +94,7 @@ The '-y' option prevents a confirmation prompt.
</key>
<key name="message_0053">This system needs to be rebooted.</key>
<key name="message_0054">This system does NOT need to be rebooted.</key>
<key name="message_0055">Exiting to '--run-once' switch.</key>
<key name="message_0055">Asked to only run once, so exiting now.</key>
<key name="message_0056">Previous run exited early. Restarting momentarily.</key>
<key name="message_0057">No updates were found or needed.</key>
<!-- NOTE: If you change the variable names below, you have to update 'anvil-update-system' as well. -->
@ -378,7 +381,7 @@ The database connection error was:
</key>
<key name="log_0099">[ Error ] - There is no Anvil! database user set for the local machine. Please check: [#!data!path::config::anvil.conf!#]'s DB entry: [#!variable!uuid!#].</key>
<key name="log_0100">Database user: [#!variable!user!#] password has been set/updated.</key>
<key name="log_0101"><![CDATA[[ Error ] - The method Alert->register_alert() was called but the 'title_key' parameter was not passed or it is empty and 'header' is enable (default).]]></key>
<key name="log_0101">#!free!#</key>
<key name="log_0102">I am not recording the alert with message_key: [#!variable!message_key!#] to the database because its log level was lower than any recipients.</key>
<key name="log_0103">The local machine's UUID was not read properly. It should be stored in: [#!data!sys::host_uuid!#] and contain hexadecimal characters in the format: '012345-6789-abcd-ef01-23456789abcd' and usually matches the output of 'dmidecode --string system-uuid'. If this file exists and if there is a string in the file, please verify that it is structured correctly.</key>
<key name="log_0104">The database with UUID: [#!variable!uuid!#] for: [#!variable!file!#] is behind.</key>
@ -536,6 +539,8 @@ The body of the file: [#!variable!file!#] does not match the new body. The file
The md5sum of: [#!variable!file!#] has changed since the daemon started.
* [#!variable!old_sum!#] -> [#!variable!new_sum!#]
</key>
<key name="log_0251">Reading the scan agent: [#!variable!agent_name!#]'s words file: [#!variable!file!#].</key>
<key name="log_0252">Running the scan agent: [#!variable!agent_name!#] with a timeout of: [#!variable!timeout!#] seconds now...</key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key>
@ -748,9 +753,9 @@ Here we will inject 't_0006', which injects 't_0001' which has a variable: [#!st
<key name="error_0025"><![CDATA[The user ID passed in to Account->read_details: [#!variable!uuid!#] is not a valid UUID.]]></key>
<key name="error_0026"><![CDATA[The user ID passed in to Account->read_details: [#!variable!uuid!#] was not found in the database.]]></key>
<key name="error_0027">Login failed, please try again.</key>
<key name="error_0028"><![CDATA[There appears to be a problem with Striker. The login failed, please check: [<span class="code">#!data!sys::log_file!#</span>] for details.]]></key>
<key name="error_0028"><![CDATA[There appears to be a problem with Striker. The login failed, please check: [<span class="code">#!data!path::log::file!#</span>] for details.]]></key>
<key name="error_0029"><![CDATA[Failed to find the template: [<span class="code">#!variable!template!#</span>] in the template file: [<span class="code">#!variable!file!#</span>].]]></key>
<key name="error_0030"><![CDATA[Failed to process the template: [<span class="code">#!variable!template!#</span>] in the template file: [<span class="code">#!variable!file!#</span>]. Details of the problem should be in: [<span class="code">#!data!sys::log_file!#</span>].]]></key>
<key name="error_0030"><![CDATA[Failed to process the template: [<span class="code">#!variable!template!#</span>] in the template file: [<span class="code">#!variable!file!#</span>]. Details of the problem should be in: [<span class="code">#!data!path::log::file!#</span>].]]></key>
<key name="error_0031">The 'host-uuid': [#!variable!host_uuid!#] is not valid.</key>
<key name="error_0032">The '#!variable!switch!#' switch is missing.</key>
<key name="error_0033">The job UUID was passed via '--job-uuid' but the passed in value: [#!variable!uuid!#] is not a valid UUID.</key>

@ -47,7 +47,7 @@ wait_until_configured($anvil);
# Disconnect. We'll reconnect inside the loop
$anvil->Database->disconnect();
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0203"});
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 3, key => "log_0203"});
# The main loop
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0248"});
@ -119,16 +119,74 @@ sub call_agents
scan_directory($anvil, $anvil->data->{path}{directories}{scan_agents});
# Now loop through the agents I found and call them.
my $default_timeout = 30;
if ((exists $anvil->data->{scancore}{timing}{agent_runtime}) && ($anvil->data->{scancore}{timing}{agent_runtime} =~ /^\d+$/))
{
$default_timeout = $anvil->data->{scancore}{timing}{agent_runtime};
}
foreach my $agent_name (sort {$a cmp $b} keys %{$anvil->data->{scancore}{agent}})
{
my $agent_path = $anvil->data->{scancore}{agent}{$agent_name};
my $agent_words = $agent_path.".xml";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
agent_name => $agent_name,
agent_path => $agent_path,
agent_words => $agent_words,
}});
if ((-e $agent_words) && (-r $agent_words))
{
# Read the words file so that we can generate alerts later.
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, level => 2, key => "log_0251", variables => {
agent_name => $agent_name,
file => $agent_path,
}});
$anvil->Words->read({file => $agent_words});
}
# Now call the agent.
my $start_time = time;
my $return_code = 9999;
my $timeout = $default_timeout;
if ((exists $anvil->data->{scancore}{agent}{$agent_name}{agent_runtime}) && ($anvil->data->{scancore}{agent}{$agent_name}{agent_runtime} =~ /^\d+$/))
{
$timeout = $anvil->data->{scancore}{agent}{$agent_name}{agent_runtime};
}
my $shell_call = $anvil->data->{path}{exe}{timeout}." ".$timeout." ".$agent_path;
if ($anvil->data->{sys}{'log'}{level})
{
$shell_call .= ." ".$anvil->data->{sys}{'log'}{level};
}
$shell_call .= "; ".$anvil->data->{path}{exe}{echo}." return_code:\$?";
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { shell_call => $shell_call }});
# Tell the user this agent is about to run...
$anvil->Log->entry({source => $THIS_FILE, line => __LINE__, 'print' => 1, level => 2, key => "log_0252", variables => {
agent_name => $agent_name,
timeout => $timeout,
}});
my $output = $anvil->System->call({shell_call => $shell_call});
foreach my $line (split/\n/, $output)
{
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { line => $line }});
if ($line =~ /return_code:(\d+)$/)
{
$return_code = $1;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { return_code => $return_code }});
}
}
# If the return code is '124', timeout popped.
if ($return_code eq "124")
{
# Register an alert...
$anvil->Alert->register({
alert_level => "notice",
set_by => $THIS_FILE,
message => "alert_message_0001,!!agent_name!".$agent_name."!!,!!timeout!".$timeout."!!",
});
}
}
return(0);
@ -189,7 +247,7 @@ sub scan_directory
{
my ($anvil, $directory) = @_;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { directory => $directory }});
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { directory => $directory }});
local(*DIRECTORY);
opendir(DIRECTORY, $directory);
while(my $file = readdir(DIRECTORY))
@ -197,7 +255,7 @@ sub scan_directory
next if $file eq ".";
next if $file eq "..";
my $full_path = $directory."/".$file;
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => {
$anvil->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => {
file => $file,
full_path => $full_path,
}});

Loading…
Cancel
Save