diff options
Diffstat (limited to 'modules-available/rebootcontrol/hooks')
3 files changed, 56 insertions, 12 deletions
diff --git a/modules-available/rebootcontrol/hooks/client-update.inc.php b/modules-available/rebootcontrol/hooks/client-update.inc.php new file mode 100644 index 00000000..e934988d --- /dev/null +++ b/modules-available/rebootcontrol/hooks/client-update.inc.php @@ -0,0 +1,25 @@ +<?php + +if ($type === '~poweron') { + $NOW = time(); + $subnet = Request::post('subnet', false, 'string'); + if ($subnet !== false && ($subnet = explode('/', $subnet)) !== false && count($subnet) === 2 + && $subnet[0] === $ip && $subnet[1] >= 8 && $subnet[1] < 32) { + $start = ip2long($ip); + if ($start !== false) { + $maskHost = (int)(2 ** (32 - $subnet[1]) - 1); + $maskNet = ~$maskHost & 0xffffffff; + $end = $start | $maskHost; + $start &= $maskNet; + $netparams = ['start' => sprintf('%u', $start), 'end' => sprintf('%u', $end), 'now' => $NOW]; + $affected = Database::exec('UPDATE reboot_subnet + SET lastseen = :now, seencount = seencount + 1 + WHERE start = :start AND end = :end', $netparams); + if ($affected === 0) { + // New entry + Database::exec('INSERT INTO reboot_subnet (start, end, fixed, isdirect, lastseen, seencount) + VALUES (:start, :end, 0, 0, :now, 1)', $netparams); + } + } + } +} diff --git a/modules-available/rebootcontrol/hooks/config-tgz.inc.php b/modules-available/rebootcontrol/hooks/config-tgz.inc.php index 90e32e8a..c9ce1255 100644 --- a/modules-available/rebootcontrol/hooks/config-tgz.inc.php +++ b/modules-available/rebootcontrol/hooks/config-tgz.inc.php @@ -8,8 +8,10 @@ if (!is_file($tmpfile) || !is_readable($tmpfile) || filemtime($tmpfile) + 86400 } try { $a = new PharData($tmpfile); - $a["/etc/ssh/mgmt/authorized_keys"] = $pubkey; - $a["/etc/ssh/mgmt/authorized_keys"]->chmod(0600); + $a->addFromString("/etc/ssh/mgmt/authorized_keys", $pubkey); + $fi = $a->offsetGet("/etc/ssh/mgmt/authorized_keys"); + /** @var PharFileInfo $fi */ + $fi->chmod(0600); $file = $tmpfile; } catch (Exception $e) { EventLog::failure('Could not include ssh key for reboot-control in config.tgz', (string)$e); diff --git a/modules-available/rebootcontrol/hooks/cron.inc.php b/modules-available/rebootcontrol/hooks/cron.inc.php index e387e055..289426c7 100644 --- a/modules-available/rebootcontrol/hooks/cron.inc.php +++ b/modules-available/rebootcontrol/hooks/cron.inc.php @@ -5,15 +5,18 @@ */ if (in_array((int)date('G'), [6, 7, 9, 12, 15]) && in_array(date('i'), ['00', '01', '02', '03'])) { $res = Database::simpleQuery('SELECT hostid, host, port, username, sshkey, script FROM reboot_jumphost'); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { RebootControl::wakeViaJumpHost($row, '255.255.255.255', [['macaddr' => '00:11:22:33:44:55']]); } } +// CRON for Scheduler +Scheduler::cron(); + /* * Client reachability test -- can be disabled */ -if (mt_rand(1, 2) !== 1 || Property::get(RebootControl::KEY_AUTOSCAN_DISABLED)) +if (Property::get(RebootControl::KEY_AUTOSCAN_DISABLED)) return; class Stuff @@ -21,7 +24,7 @@ class Stuff public static $subnets; } -function destSawPw($destTask, $destMachine, $passwd) +function destSawPw(array $destTask, array $destMachine, string $passwd): bool { return strpos($destTask['data']['result'][$destMachine['machineuuid']]['stdout'], "passwd=$passwd") !== false; } @@ -36,7 +39,7 @@ function spawnDestinationListener($dstid, &$destMachine, &$destTask, &$destDeadl $destDeadline = 0; foreach ($destMachines as $machine) { cron_log("Trying to use {$machine['clientip']} as listener for " . long2ip($machine['bcast'])); - $destTask = RebootControl::runScript([$machine], "echo 'Running-MARK'\nbusybox timeout -t 8 jawol -v -l", 10); + $destTask = RebootControl::runScript([$machine], "echo 'Running-MARK'\nbusybox timeout 8 jawol -v -l -l", 10); Taskmanager::release($destTask); $destDeadline = time() + 10; if (!Taskmanager::isRunning($destTask)) @@ -82,6 +85,11 @@ function testClientToClient($srcid, $dstid) usleep(250000); $destTask = Taskmanager::status($destTask); } + // Wait for destination listener task to finish; we might want to reuse that client, + // and trying to spawn a new listener while the old one is running will fail + for ($to = 0; $to < 30 && Taskmanager::isRunning($destTask); ++$to) { + usleep(250000); + } cron_log($destTask['data']['result'][$destMachine['machineuuid']]['stdout']); // Final moment: did dest see the packets from src? Determine this by looking for the generated password if (destSawPw($destTask, $destMachine, $passwd)) @@ -108,6 +116,11 @@ function testServerToClient($dstid) $task = Taskmanager::waitComplete($task, 2000); $destTask = Taskmanager::status($destTask); } + // Wait for destination listener task to finish; we might want to reuse that client, + // and trying to spawn a new listener while the old one is running will fail + for ($to = 0; $to < 30 && Taskmanager::isRunning($destTask); ++$to) { + usleep(250000); + } cron_log($destTask['data']['result'][$destMachine['machineuuid']]['stdout']); if (destSawPw($destTask, $destMachine, $passwd)) return 1; @@ -127,7 +140,7 @@ function resultToTime($result) $next = 86400 * 7; // a week } else { // Test finished, reachable - $next = 86400 * 30; // a month + $next = 86400 * 14; // two weeks } return time() + round($next * mt_rand(90, 133) / 100); } @@ -137,12 +150,12 @@ function resultToTime($result) */ // First, cleanup: delete orphaned subnets that don't exist anymore, or don't have any clients using our server -$cutoff = strtotime('-180 days'); +$cutoff = strtotime('-720 days'); Database::exec('DELETE FROM reboot_subnet WHERE fixed = 0 AND lastseen < :cutoff', ['cutoff' => $cutoff]); // Get machines running, group by subnet $cutoff = time() - 301; // Really only the ones that didn't miss the most recent update -$res = Database::simpleQuery("SELECT s.subnetid, s.end AS bcast, m.machineuuid, m.clientip, m.macaddr +$res = Database::simpleQuery("SELECT s.subnetid, s.end AS bcast, m.machineuuid, m.clientip, m.macaddr, m.locationid FROM reboot_subnet s INNER JOIN machine m ON ( (m.state = 'IDLE' OR m.state = 'OCCUPIED') @@ -158,12 +171,13 @@ if ($res->rowCount() === 0) return; Stuff::$subnets = []; -while ($row = $res->fetch(PDO::FETCH_ASSOC)) { +foreach ($res as $row) { if (!isset(Stuff::$subnets[$row['subnetid']])) { Stuff::$subnets[$row['subnetid']] = []; } Stuff::$subnets[$row['subnetid']][] = $row; } +unset($res); $task = Taskmanager::submit('DummyTask', []); $task = Taskmanager::waitComplete($task, 4000); @@ -181,7 +195,7 @@ $res = Database::simpleQuery("SELECT subnetid FROM reboot_subnet WHERE subnetid IN (:active) AND nextdirectcheck < UNIX_TIMESTAMP() AND fixed = 0 ORDER BY nextdirectcheck ASC LIMIT 10", ['active' => array_keys(Stuff::$subnets)]); cron_log('Direct checks: ' . $res->rowCount() . ' (' . implode(', ', array_keys(Stuff::$subnets)) . ')'); -while ($row = $res->fetch(PDO::FETCH_ASSOC)) { +foreach ($res as $row) { $dst = (int)$row['subnetid']; cron_log('Direct check for subnetid ' . $dst); $result = testServerToClient($dst); @@ -201,6 +215,9 @@ while ($row = $res->fetch(PDO::FETCH_ASSOC)) { * Try client to client */ +if (!Property::get(RebootControl::KEY_SCAN_CLIENT_TO_CLIENT)) + return; + // Query all possible combos $combos = []; foreach (Stuff::$subnets as $src => $_) { @@ -223,7 +240,7 @@ if (count($combos) > 0) { ORDER BY sxs.nextcheck ASC LIMIT 10", ['combos' => $combos]); cron_log('C2C checks: ' . $res->rowCount()); - while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + foreach ($res as $row) { $src = (int)$row['srcid']; $dst = (int)$row['dstid']; $result = testClientToClient($src, $dst); |