snaked
view release on metacpan or search on metacpan
#!/usr/bin/perl
#
# snaked: cool cron replacement.
#
#
# petya@kohts.ru
#
#
BEGIN {
# unbuffered output
$| = 1;
use Cwd;
use FindBin;
# without this chroot abs_path (below)
# returns empty string if daemon is called
# from some shell script and current directory
# is a home directory of a user (permissions?)
chroot('/');
$ENV{'MY_BIN'} = "$FindBin::Bin";
$ENV{'MY_LIB'} = Cwd::abs_path("$ENV{'MY_BIN'}/../lib");
if (! -d $ENV{'MY_LIB'}) {
$ENV{'MY_LIB'} = Cwd::abs_path("$ENV{'MY_BIN'}/lib");
}
$ENV{'MY_ETC'} = "/etc/snaked";
$ENV{'MY_ROOT'} = Cwd::abs_path("$ENV{'MY_BIN'}/../../../..");
if (!$ENV{'PS_SNAKED_LIB'}) {
$ENV{'PS_SNAKED_LIB'} = $ENV{'MY_LIB'};
}
};
use strict;
use warnings;
use lib "$ENV{'MY_LIB'}";
use lib "$ENV{'PS_SNAKED_LIB'}";
use snaked;
use Yandex::Tools;
use Yandex::Tools::ProcessList;
package snaked::Daemon;
use Schedule::Cron::Events;
use Time::Local;
use POSIX;
use IO::Handle; # autoflush
use Socket; # socketpair
use Fcntl;
use Time::HiRes;
use File::Path;
my $version = $snaked::VERSION;
my ($daemon_regexp_configured, $daemon_match_cfg, $daemon_match_cfg1, $daemon_match_nocfg, $watchdog_match, $watchdog_match1);
my $current_user = getpwuid($<);
my $current_host = `hostname -f` || "";
my $from_address;
if ($current_user && $current_host) {
$current_host =~ s/[\r\n]//go;
$from_address = $current_user . '@' . $current_host;
}
my $my_path;
my $my_command_line;
my $watchdogs2maintain = 1;
my $use_usleep;
my $have_sleep_external;
if ($^O eq 'linux') {
$use_usleep = 1;
}
else {
my $ret = system("sleep 0");
if ($ret eq 0) {
$have_sleep_external = 1;
}
else {
write_spool("external_sleep_error", "no external sleep: code [$?]; err: [$!]\n", {'mode' => "append"});
}
}
sub clock_adjusted {
my ($clock, $opts) = @_;
$opts->{'start'} = $snaked::Daemon::runtime->{'start_time'} unless $opts->{'start'};
$opts->{'threshold_left'} = -2 unless $opts->{'threshold_left'};
$opts->{'threshold_right'} = 2 unless $opts->{'threshold_right'};
my $elapsed_time_real = $clock->{'real'} - $opts->{'start'}->{'real'};
my $elapsed_time_mono = $clock->{'mono'} - $opts->{'start'}->{'mono'};
my $real_mono_diff = $elapsed_time_mono - $elapsed_time_real;
my $clock_out = localtime($clock->{'real'});
# were there any adjustments (respecting threshold)
if ($real_mono_diff < $opts->{'threshold_left'} ||
$real_mono_diff > $opts->{'threshold_right'} ) {
if ($opts->{'return_adjustment'}) {
return $real_mono_diff;
}
$clock_out .= " (adj. $real_mono_diff: " . localtime($clock->{'real'} + $real_mono_diff) . ")";
}
if ($opts->{'return_adjustment'}) {
return 0;
}
return $clock_out;
}
sub my_usleep {
my ($usec) = @_;
$ENV{'PS_SNAKED_CFG'} = Yandex::Tools::get_cmdline_param('cfg');
if (! -d "$ENV{'PS_SNAKED_CFG'}") {
die "Configuration does not exist: $ENV{'PS_SNAKED_CFG'}\n";
}
}
else {
$ENV{'PS_SNAKED_CFG'} = $ENV{'MY_ETC'};
if (! -d $ENV{'PS_SNAKED_CFG'}) {
$ENV{'PS_SNAKED_CFG'} = ($ENV{'MY_ROOT'} eq "/" ? "" : $ENV{'MY_ROOT'}) .
"/etc/ps-farm/options/ps-snaked";
}
if (! -d $ENV{'PS_SNAKED_CFG'} && -d "/etc/ps-farm/options/ps-snaked") {
$ENV{'PS_SNAKED_CFG'} = "/etc/ps-farm/options/ps-snaked";
}
}
}
if (! -d "$ENV{'PS_SNAKED_CFG'}") {
$ENV{'PS_SNAKED_CFG'} = undef;
}
else {
if (!$daemon_regexp_configured) {
$daemon_match_cfg = qr/^([^\s]+perl[^\s]*[\s]+|)[^\s]+(ps-)?snaked.+(daemon|debug).+cfg.+$ENV{'PS_SNAKED_CFG'}/;
$daemon_match_cfg1 = qr/^([^\s]+perl[^\s]*[\s]+|)[^\s]+(ps-)?snaked.+cfg.+$ENV{'PS_SNAKED_CFG'}.+(daemon|debug)/;
$daemon_match_nocfg = qr/^([^\s]+perl[^\s]*[\s]+|)[^\s]+(ps-)?snaked.+(daemon|debug)/;
$watchdog_match = qr/^([^\s]+perl[^\s]*[\s]+|)[^\s]+(ps-)?snaked.+(watchdog).+cfg.+$ENV{'PS_SNAKED_CFG'}/;
$watchdog_match1 = qr/^([^\s]+perl[^\s]*[\s]+|)[^\s]+(ps-)?snaked.+cfg.+$ENV{'PS_SNAKED_CFG'}.+(watchdog)/;
$daemon_regexp_configured = 1;
}
}
return $ENV{'PS_SNAKED_CFG'};
}
Yandex::Tools::read_cmdline();
get_cfg_path();
Yandex::Tools::ProcessList::set_options({
'daemon_match' => [$daemon_match_cfg, $daemon_match_cfg1],
'daemon_match_startup' => [$daemon_match_nocfg],
});
# commands which might work without actually
# finding configuration on the disk -- what they need
# is the PID which they get from the process table
#
if (Yandex::Tools::defined_cmdline_param('sample-config')) {
my $target_dir = Yandex::Tools::get_cmdline_param('sample-config') || "/etc/snaked";
if (-e $target_dir) {
Yandex::Tools::die("Directory [$target_dir] exists, not going to overwrite.", {'no_log' => 1});
}
File::Path::mkpath($target_dir);
if ($> eq 0) {
Yandex::Tools::write_file_scalar($target_dir . "/log", "/var/log/snaked.log\n");
Yandex::Tools::write_file_scalar($target_dir . "/admin_email", "root\n");
}
else {
Yandex::Tools::write_file_scalar($target_dir . "/log", "/tmp/snaked.log\n");
Yandex::Tools::write_file_scalar($target_dir . "/admin_email", getpwuid($>) . "\n");
}
File::Path::mkpath($target_dir . "/jobs/every_hour");
Yandex::Tools::write_file_scalar($target_dir . "/jobs/every_hour/execution_schedule", "0 * * * *\n");
Yandex::Tools::write_file_scalar($target_dir . "/jobs/every_hour/cmd", "uptime >> /tmp/snaked_every_hour\n");
chmod(0755, $target_dir . "/jobs/every_hour/cmd") || Yandex::Tools::die("Unable to set permissions on [" . $target_dir . "/jobs/every_hour/cmd" . "]", {'no_log' => 1});
File::Path::mkpath($target_dir . "/jobs/every_ten_seconds");
Yandex::Tools::write_file_scalar($target_dir . "/jobs/every_ten_seconds/execution_interval", "10\n");
Yandex::Tools::write_file_scalar($target_dir . "/jobs/every_ten_seconds/cmd", "uptime >> /tmp/snaked_every_ten_seconds\nsleep 2\n");
chmod(0755, $target_dir . "/jobs/every_ten_seconds/cmd") || Yandex::Tools::die("Unable to set permissions on [" . $target_dir . "/jobs/every_ten_seconds/cmd" . "]", {'no_log' => 1});
File::Path::mkpath($target_dir . "/jobs/fast_job");
Yandex::Tools::write_file_scalar($target_dir . "/jobs/fast_job/execution_interval", "1\n");
Yandex::Tools::write_file_scalar($target_dir . "/jobs/fast_job/cmd", "uptime >> /tmp/snaked_fast_job\n");
Yandex::Tools::write_file_scalar($target_dir . "/jobs/fast_job/conflicts", "every_ten_seconds\n");
chmod(0755, $target_dir . "/jobs/fast_job/cmd") || Yandex::Tools::die("Unable to set permissions on [" . $target_dir . "/jobs/fast_job/cmd" . "]", {'no_log' => 1});
print "written sample configuration to: $target_dir\n";
exit(0);
}
elsif (Yandex::Tools::defined_cmdline_param('stop')) {
my $d = Yandex::Tools::ProcessList::get_other_daemon_process();
if ($d) {
print "requesting " . $d->pid() . " [" . $d->cmndline . "] to stop\n";
kill (15, $d->pid);
if (Yandex::Tools::defined_cmdline_param('wait')) {
while (Yandex::Tools::ProcessList::get_other_daemon_process({'refresh_startup_processes' => 1})) {
print ".";
my_usleep(1_000_000);
}
print "\n";
}
}
else {
print "no snaked daemon found for $ENV{'PS_SNAKED_CFG'}\n";
}
exit 0;
}
elsif (Yandex::Tools::defined_cmdline_param('configure')) {
my $d = Yandex::Tools::ProcessList::get_other_daemon_process();
if ($d) {
print "requesting " . $d->pid() . " [" . $d->cmndline . "] to refresh configuration\n";
kill ("HUP", $d->pid)
}
else {
print "no snaked daemon found for $ENV{'PS_SNAKED_CFG'}\n";
}
exit 0;
}
elsif (Yandex::Tools::defined_cmdline_param('restart')) {
my $d = Yandex::Tools::ProcessList::get_other_daemon_process();
if ($d) {
if (!Yandex::Tools::defined_cmdline_param('only-errors')) {
print "requesting " . $d->pid() . " [" . $d->cmndline . "] to restart\n";
}
kill ("USR2", $d->pid);
if (Yandex::Tools::defined_cmdline_param('wait')) {
( run in 2.280 seconds using v1.01-cache-2.11-cpan-524268b4103 )