/**
* Small and fast system tasks trigger
*
- * Copyright (C) 2014 Inria (Sylvain Beucler)
+ * Copyright (C) 2014, 2015 Inria (Sylvain Beucler)
*
* This file is part of FusionForge. FusionForge is free software;
* you can redistribute it and/or modify it under the terms of the
//putenv('FUSIONFORGE_NO_DB=true');
require (dirname(__FILE__).'/../common/include/env.inc.php');
-require_once $gfcommon.'include/pre.php';
-require_once $gfcommon.'include/cron_utils.php';
-
-// Locking: for a single script
-// flock() locks are automatically lost on program termination, however
-// that happened (clean, segfault...)
-$lock = null; // global, or auto-closed by PHP and we lose the lock!
-function AcquireReplicationLock($script) {
- // Script lock: http://perl.plover.com/yak/flock/samples/slide006.html
- global $argv, $lock;
- $lock = fopen($script, 'r') or die("Failed to ask lock.\n");
-
- if (!flock($lock, LOCK_EX | LOCK_NB)) {
- die("There's a lock for '$script', exiting\n");
- }
+try {
+ require_once $gfcommon.'include/pre.php';
+} catch (DBException $e) {
+ print "Cannot connect to DB: $e\nWaiting for DB...\n";
}
+require_once $gfcommon.'include/cron_utils.php';
// Invalidate users/groups cache e.g. when a user is added to a group
// Special-case in 'publish-subscribe' mode
function usergroups_sync() {
- global $usergroups_lastsync;
- $res = db_query_params("SELECT MAX(last_modified_date) AS lastmodified FROM nss_usergroups");
- $row = db_fetch_array($res);
- if ($row['lastmodified'] > $usergroups_lastsync) {
- cron_reload_nscd();
- cron_reload_apache();
- $hook_params = array();
- plugin_hook("usergroups_sync", $hook_params);
- $usergroups_lastsync = time();
- }
+ global $usergroups_lastsync;
+ $res = db_query_params("SELECT MAX(last_modified_date) AS lastmodified FROM nss_usergroups");
+ $row = db_fetch_array($res);
+ if ($row['lastmodified'] >= $usergroups_lastsync) {
+ $usergroups_lastsync = time();
+ cron_reload_nscd();
+ cron_regen_apache_auth();
+ cron_reload_apache();
+ $hook_params = array();
+ plugin_hook("usergroups_sync", $hook_params);
+ }
}
-function systask_get_script($plugin_id, $systask_type_id) {
- global $cron_arr;
- global $pm, $plugins;
- if ($plugin_id == null) {
- if (isset($cron_arr[$systask_type_id]))
- return forge_get_config('source_path')
- .'/cronjobs/'.$cron_arr[$systask_type_id];
- } else {
- if (isset($plugins[$plugin_id])) {
- $plugin = $pm->GetPluginObject($plugins[$plugin_id]);
- if (isset($plugin->systask_types[$systask_type_id]))
- return forge_get_config('plugins_path')."/".$plugin->GetName()
- ."/cronjobs/".$plugin->systask_types[$systask_type_id];
- }
+function systask_get_script($plugin_id, $systask_type) {
+ global $cron_arr;
+ if ($plugin_id == null) {
+ if (isset($cron_arr[$systask_type]))
+ return forge_get_config('source_path')
+ .'/cronjobs/'.$cron_arr[$systask_type];
+ } else {
+ global $pm;
+ $plugins = $pm->GetPlugins(); // reload in case a new plugin was installed
+ if (isset($plugins[$plugin_id])) {
+ $plugin = $pm->GetPluginObject($plugins[$plugin_id]);
+ if ($plugin == null) {
+ $pm->LoadPlugin($plugins[$plugin_id]);
+ $plugin = $pm->GetPluginObject($plugins[$plugin_id]);
+ }
+ if (isset($plugin->systask_types[$systask_type]))
+ return forge_get_config('plugins_path')."/".$plugin->GetName()
+ ."/cronjobs/".$plugin->systask_types[$systask_type];
}
- return null;
+ }
+ return null;
}
+function is_group_active_nocache($group_id) {
+ $res = db_query_params("SELECT group_id FROM nss_groups WHERE group_id=$1", array($group_id));
+ return (db_numrows($res) > 0);
+}
$shortopts = 'v'; // enable verbose mode
// Proper daemon
posix_setsid();
chdir('/');
-umask(0);
+//umask(0); // programmers usually expect umask=0022, and this would default mkdir to 0777
+umask(0022);
+$log_path = forge_get_config('log_path');
if (!$verbose) {
// Hack to reopen stdin/stdout/stderr, order is important
// https://andytson.com/blog/2010/05/daemonising-a-php-cli-script-on-a-posix-system/
fclose(STDOUT);
fclose(STDERR);
$ff_stdin = fopen('/dev/null', 'r');
- $ff_stdout = fopen('/dev/null', 'w');
- $ff_stderr = fopen('php://stdout', 'w');
+ //$ff_stdout = fopen('/dev/null', 'w');
+ //$ff_stderr = fopen('php://stdout', 'w');
+ $ff_stdout = fopen("$log_path/systasksd.stdout", 'w');
+ $ff_stderr = fopen("$log_path/systasksd.stderr", 'w');
}
// We could fork & continue in the background too, but then we'd have
// to manage the PID file as well - best leave this to the init script
$pm = plugin_manager_get_object();
-$plugins = $pm->GetPlugins();
usergroups_sync();
while (true) {
- // Deal with pending requests
- $res = db_query_params("SELECT * FROM systasks WHERE status=$1"
- . " ORDER BY systask_id", array('TODO'));
- if (!$res && !db_connection_status())
- db_reconnect();
- while ($arr = db_fetch_array($res)) {
- usergroups_sync();
- $script = systask_get_script($arr['plugin_id'], $arr['systask_type_id']);
- if (!file_exists($script))
- // Not installed on this node, skipping
- continue;
- if (!is_executable($script)) {
- db_query_params("UPDATE systasks SET status=$1, error_message=$2"
- . " WHERE systask_id=$3",
- array('ERROR',
- "Cron job {$arr['plugin_id']}/{$arr['systask_type_id']}"
- . " '$script' not executable.\n",
- $arr['systask_id']));
- continue;
- }
- db_query_params("UPDATE systasks SET status=$1 WHERE systask_id=$2",
- array('WIP', $arr['systask_id']));
- AcquireReplicationLock($script);
- $ret = null;
- if ($verbose) print "Running: $script... ";
- system("$script\n", $ret);
- if ($ret == 0) {
- if ($verbose) print "DONE\n";
- db_query_params("UPDATE systasks SET status=$1 WHERE systask_id=$2",
- array('DONE', $arr['systask_id']));
- } else {
- if ($verbose) print "ERROR\n";
- db_query_params("UPDATE systasks SET status=$1 WHERE systask_id=$2",
- array('ERROR', $arr['systask_id']));
- }
+ // Deal with pending requests
+ $res = db_query_params("SELECT * FROM systasks WHERE status=$1"
+ . " ORDER BY systask_id", array('TODO'));
+ if (!$res && !db_connection_status())
+ db_reconnect();
+ while ($arr = db_fetch_array($res)) {
+ $script = systask_get_script($arr['plugin_id'], $arr['systask_type']);
+ if (!file_exists($script))
+ // Not installed on this node, skipping
+ continue;
+ if (!is_executable($script)) {
+ db_query_params("UPDATE systasks SET status=$1, error_message=$2"
+ . " WHERE systask_id=$3",
+ array('ERROR',
+ "Cron job {$arr['plugin_id']}/{$arr['systask_type']}"
+ . " '$script' not executable.\n",
+ $arr['systask_id']));
+ continue;
}
+ // Concurrency: ensure groups are activated in the system before starting task
+ if (!empty($arr['group_id']) && !is_group_active_nocache($arr['group_id'])) {
+ continue; // wait until project is approved
+ }
usergroups_sync();
- sleep(1);
+ db_query_params("UPDATE systasks SET status=$1, started=now() WHERE systask_id=$2",
+ array('WIP', $arr['systask_id']));
+ cron_acquire_lock($script);
+ $ret = null;
+ if ($verbose) print "Running: $script... ";
+ system("$script\n", $ret);
+ cron_release_lock($script);
+ if ($ret == 0) {
+ if ($verbose) print "DONE\n";
+ db_query_params("UPDATE systasks SET status=$1, stopped=now() WHERE systask_id=$2",
+ array('DONE', $arr['systask_id']));
+ } else {
+ if ($verbose) print "ERROR\n";
+ db_query_params("UPDATE systasks SET status=$1, stopped=now() WHERE systask_id=$2",
+ array('ERROR', $arr['systask_id']));
+ }
+ }
+
+ usergroups_sync();
+
+ sleep(1);
}
// Local Variables: