wip omnishell, command executor and directories
This commit is contained in:
parent
c78e3f4184
commit
2daf473ba9
|
@ -36,6 +36,8 @@ mkdir -p temp_package/usr/bin/
|
|||
mkdir -p temp_package/usr/sbin/
|
||||
mkdir -p temp_package/etc/pandora/plugins
|
||||
mkdir -p temp_package/etc/pandora/collections
|
||||
mkdir -p temp_package/etc/pandora/trans
|
||||
mkdir -p temp_package/etc/pandora/commands
|
||||
mkdir -p temp_package/etc/init.d/
|
||||
mkdir -p temp_package/var/log/pandora/
|
||||
mkdir -p temp_package/usr/share/man/man1/
|
||||
|
|
|
@ -324,6 +324,11 @@ install () {
|
|||
cp -r collections $PANDORA_BASE$PANDORA_HOME
|
||||
chmod -R 700 $PANDORA_BASE$PANDORA_HOME/collections
|
||||
ln -s $PANDORA_BASE$PANDORA_HOME/collections $PANDORA_BASE$PANDORA_CFG
|
||||
|
||||
echo "Copying Pandora FMS Agent commands to $PANDORA_BASE$PANDORA_HOME/commands..."
|
||||
cp -r commands $PANDORA_BASE$PANDORA_HOME
|
||||
chmod -R 700 $PANDORA_BASE$PANDORA_HOME/commands
|
||||
ln -s $PANDORA_BASE$PANDORA_HOME/commands $PANDORA_BASE$PANDORA_CFG
|
||||
|
||||
echo "Copying tentacle server to $PANDORA_BASE$TENTACLE_SERVER"
|
||||
cp tentacle_server $PANDORA_BASE$TENTACLE_SERVER
|
||||
|
|
|
@ -36,6 +36,8 @@ mkdir -p temp_package/usr/bin/
|
|||
mkdir -p temp_package/usr/sbin/
|
||||
mkdir -p temp_package/etc/pandora/plugins
|
||||
mkdir -p temp_package/etc/pandora/collections
|
||||
mkdir -p temp_package/etc/pandora/trans
|
||||
mkdir -p temp_package/etc/pandora/commands
|
||||
mkdir -p temp_package/etc/init.d/
|
||||
mkdir -p temp_package/lib/systemd/system/
|
||||
mkdir -p temp_package/var/log/pandora/
|
||||
|
|
|
@ -32,6 +32,18 @@ use IO::Socket;
|
|||
use Sys::Syslog;
|
||||
use Time::Local;
|
||||
|
||||
my $YAML = 0;
|
||||
# Dynamic load. Avoid unwanted behaviour.
|
||||
eval {
|
||||
eval 'require YAML::Tiny;1' or die('YAML::Tiny lib not found, commands feature won\'t be available');
|
||||
};
|
||||
if ($@) {
|
||||
$YAML = 0;
|
||||
print STDERR $@;
|
||||
} else {
|
||||
$YAML = 1;
|
||||
}
|
||||
|
||||
# Agent XML data
|
||||
my $Xml;
|
||||
|
||||
|
@ -187,6 +199,7 @@ my %DefaultConf = (
|
|||
'custom_id' => '',
|
||||
'url_address' => '',
|
||||
'standby' => 0,
|
||||
'cmd_file' => undef,
|
||||
);
|
||||
my %Conf = %DefaultConf;
|
||||
|
||||
|
@ -284,6 +297,28 @@ sub valid_regexp ($) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Reads a file and returns entire content or undef if error.
|
||||
################################################################################
|
||||
sub read_file {
|
||||
my $path = shift;
|
||||
|
||||
my $_FILE;
|
||||
if( !open($_FILE, "<".$path) ) {
|
||||
print ">> Failed to open $path ".`whoami`."\n";
|
||||
# failed to open, return undef
|
||||
return undef;
|
||||
}
|
||||
|
||||
# Slurp configuration file content.
|
||||
my $content = do { local $/; <$_FILE> };
|
||||
|
||||
# Close file
|
||||
close($_FILE);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Recursively delete files and directories.
|
||||
################################################################################
|
||||
|
@ -682,6 +717,13 @@ sub parse_conf_modules($) {
|
|||
# Macros
|
||||
} elsif ($line =~ /^\s*module_macro(\S+)\s+(.*)\s*$/) {
|
||||
$module->{'macros'}{$1} = $2;
|
||||
# Commands
|
||||
} elsif ($line =~ /^\s*cmd_file\s+(.+)$/) {
|
||||
if (ref ($Conf{'commands'}) ne "HASH") {
|
||||
$Conf{'commands'} = {};
|
||||
}
|
||||
# Initialize empty command hash.
|
||||
$Conf{'commands'}->{$1} = {};
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -1362,6 +1404,185 @@ sub check_collections () {
|
|||
}
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Check for remote commands defined.
|
||||
################################################################################
|
||||
sub prepare_remote_commands {
|
||||
if ($YAML == 0) {
|
||||
log_message(
|
||||
'error',
|
||||
'Cannot use commands without YAML dependency, please install it.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach my $ref (keys %{$Conf{'commands'}}) {
|
||||
my $file_content;
|
||||
my $download = 0;
|
||||
my $rcmd_file = $ConfDir.'/commands/'.$ref.'.rcmd';
|
||||
|
||||
# Check for local .rcmd.done files
|
||||
if (-e $Conf{'temporal'}.'/'.$ref.'.rcmd.done') {
|
||||
# Ignore.
|
||||
delete $Conf{'commands'}->{$ref};
|
||||
next;
|
||||
}
|
||||
|
||||
# Search for local .rcmd file
|
||||
if (-e $rcmd_file) {
|
||||
my $remote_md5_file = $Conf{'temporal'}.'/'.$ref.'.md5';
|
||||
|
||||
$file_content = read_file($rcmd_file);
|
||||
if (recv_file($ref.'.md5', $remote_md5_file) != 0) {
|
||||
# Remote file could not be retrieved, skip.
|
||||
delete $Conf{'commands'}->{$ref};
|
||||
next;
|
||||
}
|
||||
|
||||
my $local_md5 = md5($file_content);
|
||||
my $remote_md5 = md5(read_file($remote_md5_file));
|
||||
|
||||
if ($local_md5 ne $remote_md5) {
|
||||
# Must be downloaded again.
|
||||
$download = 1;
|
||||
}
|
||||
} else {
|
||||
$download = 1;
|
||||
}
|
||||
|
||||
# Search for remote .rcmd file
|
||||
if ($download == 1) {
|
||||
# Download .rcmd file
|
||||
if (recv_file($ref.'.rcmd') != 0) {
|
||||
# Remote file could not be retrieved, skip.
|
||||
delete $Conf{'commands'}->{$ref};
|
||||
next;
|
||||
} else {
|
||||
# Success
|
||||
move($Conf{'temporal'}.'/'.$ref.'.rcmd', $rcmd_file);
|
||||
}
|
||||
}
|
||||
|
||||
# Parse and prepare in memory skel.
|
||||
eval {
|
||||
$Conf{'commands'}->{$ref} = YAML::Tiny->read($rcmd_file);
|
||||
};
|
||||
if ($@) {
|
||||
# Failed.
|
||||
log_message('error', 'Failed to decode command. ' . $@);
|
||||
delete $Conf{'commands'}->{$ref};
|
||||
next;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Command report.
|
||||
################################################################################
|
||||
sub report_command {
|
||||
my ($ref, $err_level) = @_;
|
||||
|
||||
# Retrieve content from .stdout and .stderr
|
||||
my $stdout_file = $Conf{'temporal'}.'/'.$ref.'.stdout';
|
||||
my $stderr_file = $Conf{'temporal'}.'/'.$ref.'.stderr';
|
||||
|
||||
my $return;
|
||||
eval {
|
||||
$return = {
|
||||
'error_level' => $err_level,
|
||||
'stdout' => read_file($stdout_file),
|
||||
'stderr' => read_file($stderr_file),
|
||||
};
|
||||
|
||||
$return->{'name'} = $Conf{'commands'}->{$ref}->[0]->{'name'};
|
||||
};
|
||||
if ($@) {
|
||||
log_message('error', 'Failed to report command output. ' . $@);
|
||||
}
|
||||
|
||||
# Cleanup
|
||||
unlink($stdout_file) if (-e $stdout_file);
|
||||
unlink($stderr_file) if (-e $stderr_file);
|
||||
|
||||
# Mark command as done.
|
||||
open (my $R_FILE, '> '.$ConfDir.'/commands/'.$ref.'.rcmd.done');
|
||||
print $R_FILE $err_level;
|
||||
close($R_FILE);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Executes a block of commands, returns error level, leaves output in
|
||||
# redirection set by $std_files. E.g:
|
||||
# $std_files = ' >> /tmp/stdout 2>> /tmp/stderr
|
||||
################################################################################
|
||||
sub execute_command_block {
|
||||
my ($commands, $std_files) = @_;
|
||||
|
||||
$std_files = '' unless defined ($std_files);
|
||||
return 0 if ref($commands) ne "ARRAY";
|
||||
|
||||
my $err_level;
|
||||
|
||||
foreach my $comm (@{$commands}) {
|
||||
`($comm) $std_files`;
|
||||
$err_level = $?>>8;
|
||||
last unless ($err_level == 0);
|
||||
}
|
||||
|
||||
return $err_level;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Evalate given command.
|
||||
################################################################################
|
||||
sub evaluate_command {
|
||||
my ($ref) = @_;
|
||||
|
||||
# Not found.
|
||||
return unless defined $Conf{'commands'}->{$ref};
|
||||
|
||||
# Already completed.
|
||||
return if (-e $ConfDir.'/commands/'.$ref.'.rcmd.done');
|
||||
|
||||
# [0] because how library works.
|
||||
my $cmd = $Conf{'commands'}->{$ref}->[0];
|
||||
|
||||
my $std_files = ' >> '.$Conf{'temporal'}.'/'.$ref.'.stdout ';
|
||||
$std_files .= ' 2>> '.$Conf{'temporal'}.'/'.$ref.'.stderr ';
|
||||
|
||||
# Check preconditions
|
||||
my $err_level;
|
||||
|
||||
$err_level = execute_command_block(
|
||||
$cmd->{'preconditions'},
|
||||
$std_files
|
||||
);
|
||||
|
||||
# Precondition not satisfied.
|
||||
return report_command($ref, $err_level) unless ($err_level == 0);
|
||||
|
||||
# Main run.
|
||||
$err_level = execute_command_block(
|
||||
$cmd->{'script'},
|
||||
$std_files
|
||||
);
|
||||
|
||||
# Script not success.
|
||||
return report_command($ref, $err_level) unless ($err_level == 0);
|
||||
|
||||
# Check postconditions
|
||||
$err_level = execute_command_block(
|
||||
$cmd->{'postconditions'},
|
||||
$std_files
|
||||
);
|
||||
|
||||
# Return results.
|
||||
return report_command($ref, $err_level);
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Sleep function
|
||||
################################################################################
|
||||
|
@ -2999,6 +3220,25 @@ while (1) {
|
|||
# Check file collections
|
||||
check_collections () unless ($Conf{'debug'} eq '1');
|
||||
|
||||
if ($Conf{'debug'} ne '1') {
|
||||
# Check remote commands
|
||||
prepare_remote_commands ();
|
||||
|
||||
# Cleanup old .rcmd.done files.
|
||||
my %registered = map { $_.'.rcmd.done' => 1 } keys %{$Conf{'commands'}};
|
||||
if(opendir(my $dir, $ConfDir.'/commands/')) {
|
||||
while (my $item = readdir($dir)) {
|
||||
# Skip other files.
|
||||
next if ($item !~ /\.rcmd\.done$/);
|
||||
|
||||
# Clean .rcmd.done file if its command is not referenced in conf.
|
||||
if (!defined($registered{$item})) {
|
||||
unlink ($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Launch broker agents
|
||||
@BrokerPid = ();
|
||||
my @broker_agents = read_config ('broker_agent');
|
||||
|
@ -3128,6 +3368,23 @@ while (1) {
|
|||
}
|
||||
}
|
||||
|
||||
if (ref ($Conf{'commands'}) eq "HASH") {
|
||||
foreach my $command (keys %{$Conf{'commands'}}) {
|
||||
my $result = evaluate_command($command);
|
||||
if (ref($result) eq "HASH") {
|
||||
# Process command result.
|
||||
$Xml .= "<cmd_report>\n";
|
||||
$Xml .= " <cmd_response>\n";
|
||||
$Xml .= " <cmd_name><![CDATA[".$result->{'name'}."]]></cmd_name>\n";
|
||||
$Xml .= " <cmd_errorlevel><![CDATA[".$result->{'error_level'}."]]></cmd_errorlevel>\n";
|
||||
$Xml .= " <cmd_stdout><![CDATA[".$result->{'stdout'}."]]></cmd_stdout>\n";
|
||||
$Xml .= " <cmd_stderr><![CDATA[".$result->{'stderr'}."]]></cmd_sterr>\n";
|
||||
$Xml .= " </cmd_response>\n";
|
||||
$Xml .= "</cmd_report>\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Wait for all the threads
|
||||
$ThreadSem->down ($Conf{'agent_threads'}) if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1);
|
||||
$ThreadSem->up ($Conf{'agent_threads'}) if (defined ($ThreadSem) && $Conf{'agent_threads'} > 1);
|
||||
|
|
|
@ -99,6 +99,11 @@ if [ ! -e /etc/pandora/collections ]; then
|
|||
ln -s /usr/share/pandora_agent/collections /etc/pandora
|
||||
fi
|
||||
|
||||
if [ ! -e /etc/pandora/commands ]; then
|
||||
mkdir -p /usr/share/pandora_agent/commands
|
||||
ln -s /usr/share/pandora_agent/commands /etc/pandora
|
||||
fi
|
||||
|
||||
mkdir -p /var/spool/pandora/data_out
|
||||
if [ ! -d /var/log/pandora ]; then
|
||||
mkdir -p /var/log/pandora
|
||||
|
|
|
@ -90,6 +90,11 @@ fi
|
|||
if [ ! -e /etc/pandora/collections ]; then
|
||||
mkdir /etc/pandora/collections
|
||||
fi
|
||||
|
||||
if [ ! -e /etc/pandora/commands ]; then
|
||||
mkdir /etc/pandora/commands
|
||||
fi
|
||||
|
||||
cp -aRf /usr/share/pandora_agent/pandora_agent_logrotate /etc/logrotate.d/pandora_agent
|
||||
|
||||
# Enable the service on SystemD
|
||||
|
|
|
@ -400,6 +400,11 @@ install () {
|
|||
mkdir -p $PANDORA_BASE$PANDORA_HOME/collections
|
||||
chmod -R 700 $PANDORA_BASE$PANDORA_HOME/collections
|
||||
ln -s $PANDORA_BASE_REAL$PANDORA_HOME/collections $PANDORA_BASE$PANDORA_CFG
|
||||
|
||||
echo "Creating the commands directory in $PANDORA_BASE$PANDORA_HOME/commands..."
|
||||
mkdir -p $PANDORA_BASE$PANDORA_HOME/commands
|
||||
chmod -R 700 $PANDORA_BASE$PANDORA_HOME/commands
|
||||
ln -s $PANDORA_BASE_REAL$PANDORA_HOME/commands $PANDORA_BASE$PANDORA_CFG
|
||||
|
||||
if [ $WITHOUT_TENTACLE_SERVER -eq 0 ]
|
||||
then
|
||||
|
|
|
@ -80,7 +80,9 @@ then
|
|||
mkdir -p temp_package/var/spool/pandora/data_in/netflow
|
||||
chmod 770 temp_package/var/spool/pandora/data_in/netflow
|
||||
mkdir -p temp_package/var/spool/pandora/data_in/trans
|
||||
chmod 770 temp_package/var/spool/pandora/data_in/trans
|
||||
chmod 770 temp_package/var/spool/pandora/data_in/trans
|
||||
mkdir -p temp_package/var/spool/pandora/data_in/commands
|
||||
chmod 770 temp_package/var/spool/pandora/data_in/commands
|
||||
mkdir -p temp_package/var/log/pandora/
|
||||
chmod 754 temp_package/var/log/pandora/
|
||||
mkdir -p temp_package/usr/share/pandora_server/conf/
|
||||
|
|
|
@ -21,7 +21,7 @@ daemon 1
|
|||
# insecure 0
|
||||
|
||||
# Filters (regexp:dir;regexp:dir...)
|
||||
filters .*\.conf:conf;.*\.md5:md5;.*\.zip:collections;.*\.lock:trans
|
||||
filters .*\.conf:conf;.*\.md5:md5;.*\.zip:collections;.*\.lock:trans;.*\.rcmd:commands
|
||||
|
||||
# [-m] Maximum file size allowed by the server in bytes
|
||||
#max_size 2000000
|
||||
|
|
|
@ -54,6 +54,8 @@ mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/spool/pandora/data_in/conf
|
|||
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/spool/pandora/data_in/md5
|
||||
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/spool/pandora/data_in/collections
|
||||
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/spool/pandora/data_in/netflow
|
||||
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/spool/pandora/data_in/trans
|
||||
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/spool/pandora/data_in/commands
|
||||
mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/log/pandora/
|
||||
mkdir -p $RPM_BUILD_ROOT%{prefix}/pandora_server/conf/
|
||||
mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1/
|
||||
|
@ -195,3 +197,5 @@ exit 0
|
|||
%{_localstatedir}/spool/pandora/data_in/collections
|
||||
%{_localstatedir}/spool/pandora/data_in/conf
|
||||
%{_localstatedir}/spool/pandora/data_in/netflow
|
||||
%{_localstatedir}/spool/pandora/data_in/trans
|
||||
%{_localstatedir}/spool/pandora/data_in/commands
|
||||
|
|
|
@ -61,6 +61,7 @@ mkdir -p $RPM_BUILD_ROOT/var/spool/pandora/data_in/md5
|
|||
mkdir -p $RPM_BUILD_ROOT/var/spool/pandora/data_in/collections
|
||||
mkdir -p $RPM_BUILD_ROOT/var/spool/pandora/data_in/netflow
|
||||
mkdir -p $RPM_BUILD_ROOT/var/spool/pandora/data_in/trans
|
||||
mkdir -p $RPM_BUILD_ROOT/var/spool/pandora/data_in/commands
|
||||
mkdir -p $RPM_BUILD_ROOT/var/log/pandora/
|
||||
mkdir -p $RPM_BUILD_ROOT%{prefix}/pandora_server/conf/
|
||||
mkdir -p $RPM_BUILD_ROOT%{prefix}/tentacle/conf/
|
||||
|
@ -198,6 +199,7 @@ rm -Rf /usr/share/man/man1/tentacle_server.1.gz
|
|||
/var/spool/pandora/data_in/netflow
|
||||
/var/spool/pandora/data_in/conf
|
||||
/var/spool/pandora/data_in/trans
|
||||
/var/spool/pandora/data_in/commands
|
||||
|
||||
%defattr(-,pandora,root,750)
|
||||
/etc/pandora
|
||||
|
|
|
@ -315,6 +315,8 @@ install () {
|
|||
chmod 2770 $DESTDIR$PANDORA_SPOOL/data_in/netflow
|
||||
mkdir $DESTDIR$PANDORA_SPOOL/data_in/trans 2> /dev/null
|
||||
chmod 2770 $DESTDIR$PANDORA_SPOOL/data_in/trans
|
||||
mkdir $DESTDIR$PANDORA_SPOOL/data_in/commands 2> /dev/null
|
||||
chmod 2770 $DESTDIR$PANDORA_SPOOL/data_in/commands
|
||||
mkdir -p $DESTDIR$PANDORA_LOG 2> /dev/null
|
||||
chown -R pandora $DESTDIR$PANDORA_LOG 2> /dev/null
|
||||
chmod 2774 $DESTDIR$PANDORA_LOG 2> /dev/null
|
||||
|
|
Loading…
Reference in New Issue