$task, 'callback' => $callback, ); if (is_null($args)) { $data['args'] = ''; } else { $data['args'] = serialize($args); } if (Database::exec("INSERT INTO callback (taskid, dateline, cbfunction, args)" . " VALUES (:task, UNIX_TIMESTAMP(), :callback, :args)", $data, true) !== false) { return; } // Most likely the args column is missing - try to add it on-the-fly so the update routine can properly // use it (confmod updates - otherwise the status of modules is not updated properly) Database::exec("ALTER TABLE `callback` ADD `args` TEXT NOT NULL DEFAULT ''", array(), true); Database::exec("INSERT INTO callback (taskid, dateline, cbfunction, args)" . " VALUES (:task, UNIX_TIMESTAMP(), :callback, :args)", $data); } /** * Get all pending callbacks from the callback table. * * @return array list of array(taskid => list of callbacks) */ public static function getPendingCallbacks(): array { $res = Database::simpleQuery("SELECT taskid, cbfunction, args FROM callback", array(), true); if ($res === false) return array(); $retval = array(); foreach ($res as $row) { $retval[$row['taskid']][] = $row; } return $retval; } /** * Handle the given callback. Will delete the entry from the callback * table if appropriate. * * @param array $callback entry from the callback table (cbfunction + taskid + args) * @param ?array $status status of the task as returned by the taskmanager. If NULL it will be queried. */ public static function handleCallback(array $callback, array $status = NULL): void { if (is_null($status)) $status = Taskmanager::status($callback['taskid']); if ($status === false) // No reply from Taskmanager, retry later return; if (Taskmanager::isFailed($status) || Taskmanager::isFinished($status)) { $del = Database::exec("DELETE FROM callback WHERE taskid = :task AND cbfunction = :cb LIMIT 1", array('task' => $callback['taskid'], 'cb' => $callback['cbfunction'])); if ($del === 0) { // No entry deleted, so someone else must have deleted it - race condition, do nothing return; } } if (Taskmanager::isFinished($status)) { Taskmanager::release($status); $func = array('TaskmanagerCallback', preg_replace('/\W/', '', $callback['cbfunction'])); if (!call_user_func_array('method_exists', $func)) { Eventlog::warning("handleCallback: Callback {$callback['cbfunction']} doesn't exist."); } else { if (empty($callback['args'])) call_user_func($func, $status, null); else call_user_func($func, $status, unserialize($callback['args'])); } } } // #################################################################### /** * Result of trying to (re)launch ldadp. */ public static function ldadpStartup(array $task) { if (Taskmanager::isFailed($task)) { if (!isset($task['data']['messages'])) { $task['data']['messages'] = ''; } EventLog::warning("Could not start/stop LDAP-AD-Proxy instances", $task['data']['messages']); } } /** * Result of restoring the server configuration */ public static function dbRestored(array $task) { if (!Taskmanager::isFailed($task)) { EventLog::info('Configuration backup restored.'); } } public static function adConfigCreate(array $task) { if (Taskmanager::isFailed($task)) EventLog::warning("Could not generate Active Directory configuration", $task['data']['error']); } /** * Generating a config module has finished. * * @param array $task task obj * @param array $args has keys 'moduleid' and optionally 'deleteOnError' and 'tmpTgz' */ public static function cbConfModCreated(array $task, array $args) { $mod = Module::get('sysconfig'); if ($mod === false) return; $mod->activate(1, false); if (Taskmanager::isFailed($task)) { ConfigModule::generateFailed($task, $args); } else { ConfigModule::generateSucceeded($args); } } /** * Generating a config.tgz has finished. * * @param array $task task obj * @param array $args has keys 'configid' and optionally 'deleteOnError' */ public static function cbConfTgzCreated(array $task, array $args) { $mod = Module::get('sysconfig'); if ($mod === false) return; $mod->activate(1, false); if (Taskmanager::isFailed($task)) { ConfigTgz::generateFailed($task, $args); } else { ConfigTgz::generateSucceeded($task, $args); } } public static function manualMount(array $task, $args) { if (!isset($task['data']['exitCode'])) return; if ($task['data']['exitCode'] == 0) { // Success - store configuration Property::setVmStoreConfig($args); return; } // If code is 99 then the script failed to even unmount -- don't change anything if ($task['data']['exitCode'] != 99) { // Manual mount failed with non-taskmanager related error - reset storage type to reflect situation $data = Property::getVmStoreConfig(); if (isset($data['storetype'])) { unset($data['storetype']); Property::setVmStoreConfig($data); } } } public static function mlGotList(array $task, $args) { $mod = Module::get('minilinux'); if ($mod === false) return; $mod->activate(1, false); MiniLinux::listDownloadCallback($task, $args); } public static function mlGotLinux(array $task, $args) { $mod = Module::get('minilinux'); if ($mod === false) return; $mod->activate(1, false); MiniLinux::linuxDownloadCallback($task, $args); } public static function rbcConnCheck(array $task, $args) { $mod = Module::get('rebootcontrol'); if ($mod === false) return; $mod->activate(1, false); RebootControl::connectionCheckCallback($task, $args); } public static function ipxeVersionSet(array $task) { $mod = Module::get('serversetup'); if ($mod === false) return; $mod->activate(1, false); IPxeBuilder::setIPxeVersionCallback($task); } public static function ipxeCompileDone(array $task) { $mod = Module::get('serversetup'); if ($mod === false) return; $mod->activate(1, false); IPxeBuilder::compileCompleteCallback($task); } public static function ssUpgradable(array $task): void { $mod = Module::get('systemstatus'); if ($mod === false) return; $mod->activate(1, false); SystemStatus::setUpgradableData($task); } public static function acmeErrors(array $task): void { $mod = Module::get('webinterface'); if ($mod === false) return; $mod->activate(1, false); Acme::callbackErrorCheck($task); } }