<?php
declare(strict_types=1);
/**
* Contains all callbacks for detached taskmanager tasks.
*/
class TaskmanagerCallback
{
/**
* Add a callback for given task id. This is the only exception in this class,
* as this is not a callback, but a function to define one :)
*
* @param string|array $task Task or Task ID to define callback for
* @param string $callback name of callback function, must be a static method in this class
*/
public static function addCallback($task, string $callback, $args = NULL): void
{
if (!call_user_func_array('method_exists', array('TaskmanagerCallback', $callback))) {
EventLog::warning("addCallback: Invalid callback function: $callback");
return;
}
if (is_array($task) && isset($task['id']))
$task = $task['id'];
if (!is_string($task)) {
EventLog::warning("addCallback: Not a valid task id: $task", print_r(debug_backtrace(), true));
return;
}
$data = array(
'task' => $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)) {
$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);
}
}