diff options
author | Christian Hofmaier | 2021-03-16 20:03:58 +0100 |
---|---|---|
committer | Christian Hofmaier | 2021-03-16 20:03:58 +0100 |
commit | 834b95629832fc3735756727b6c7cb1826d0e9d8 (patch) | |
tree | ff465ef0063c59d92f8c77e89f15a2a7a2405977 /modules-available | |
parent | [sysconfig] yes -> true (diff) | |
download | slx-admin-834b95629832fc3735756727b6c7cb1826d0e9d8.tar.gz slx-admin-834b95629832fc3735756727b6c7cb1826d0e9d8.tar.xz slx-admin-834b95629832fc3735756727b6c7cb1826d0e9d8.zip |
[rebootcontrol] Handle scheduler overlaps
- Overlaps < 5 min are ignored, < 15 triggers reboot
- Database: Make 1 line out of 2
Diffstat (limited to 'modules-available')
5 files changed, 102 insertions, 67 deletions
diff --git a/modules-available/locations/pages/details.inc.php b/modules-available/locations/pages/details.inc.php index 2f444157..fd45646b 100644 --- a/modules-available/locations/pages/details.inc.php +++ b/modules-available/locations/pages/details.inc.php @@ -89,25 +89,25 @@ class SubPage array('locationid' => $locationid, 'openingtime' => $openingTimes)); if (Module::isAvailable('rebootcontrol')) { - if ($wol) { + if ($wol || $sd) { $options = array(); + // Sanity checks if ($woloffset > 15) $woloffset = 15; else if ($woloffset < 0) $woloffset = 0; - $options['wol-offset'] = $woloffset; - Scheduler::updateSchedule($locationid, 'wol', $options, $openingTimes); - } else { - Scheduler::deleteSchedule($locationid, 'wol'); - } - if ($sd) { - $options = array(); - // Sanity checks if ($sdoffset > 15) $sdoffset = 15; else if ($sdoffset < 0) $sdoffset = 0; + + // Set options + $options['wol'] = $wol; + $options['wol-offset'] = $woloffset; + $options['sd'] = $sd; $options['sd-offset'] = $sdoffset; - Scheduler::updateSchedule($locationid, 'sd', $options, $openingTimes); + + Scheduler::updateSchedule($locationid, $options, $openingTimes); + } else { - Scheduler::deleteSchedule($locationid, 'sd'); + Scheduler::deleteSchedule($locationid); } } } @@ -423,16 +423,8 @@ class SubPage $rebootcontrol = Module::isAvailable('rebootcontrol'); $data['rebootcontrol'] = $rebootcontrol; if ($rebootcontrol) { - $wol = Database::queryFirst("SELECT options FROM `reboot_scheduler` WHERE locationid = :id AND action = 'wol'", array('id' => $id)); - if ($wol !== false) { - $data['wol'] = true; - $data['wol-options'] = json_decode($wol['options']); - } - $sd = Database::queryFirst("SELECT options FROM `reboot_scheduler` WHERE locationid = :id AND action = 'sd'", array('id' => $id)); - if ($sd !== false) { - $data['sd'] = true; - $data['sd-options'] = json_decode($sd['options']); - } + $res = Database::queryFirst("SELECT * FROM `reboot_scheduler` WHERE locationid = :id", array('id' => $id)); + if ($res !== false) $data['scheduler-options'] = json_decode($res['options']); } echo Render::parse('ajax-opening-location', $data); diff --git a/modules-available/locations/templates/ajax-opening-location.html b/modules-available/locations/templates/ajax-opening-location.html index a2bb357d..b1aea2e2 100644 --- a/modules-available/locations/templates/ajax-opening-location.html +++ b/modules-available/locations/templates/ajax-opening-location.html @@ -128,14 +128,14 @@ <div class="row wol"> <div class="col-sm-4"> <div class="checkbox checkbox-inline"> - <input id="wol-check-{{id}}" name="wol" type="checkbox" {{#wol}}checked{{/wol}}> + <input id="wol-check-{{id}}" name="wol" type="checkbox" {{#scheduler-options.wol}}checked{{/scheduler-options.wol}}> <label for="wol-check-{{id}}">{{lang_wakeonlan}}</label> </div> </div> <div class="col-sm-8"> <div class="input-group"> <input disabled type="number" id="wol-offset-{{id}}" name="wol-offset" class="form-control" - value="{{wol-options.wol-offset}}" placeholder="0" min="0" max="15"> + value="{{scheduler-options.wol-offset}}" placeholder="0" min="0" max="15"> <span class="input-group-addon slx-ga2"> <label for="wol-offset-{{id}}">{{lang_offsetEarly}}</label> </span> @@ -145,14 +145,14 @@ <div class="row shutdown"> <div class="col-sm-4"> <div class="checkbox checkbox-inline"> - <input id="sd-check-{{id}}" name="sd" type="checkbox" {{#sd}}checked{{/sd}}> + <input id="sd-check-{{id}}" name="sd" type="checkbox" {{#scheduler-options.sd}}checked{{/scheduler-options.sd}}> <label for="sd-check-{{id}}">{{lang_shutdown}}</label> </div> </div> <div class="col-sm-8"> <div class="input-group"> <input disabled type="number" id="sd-offset-{{id}}" name="sd-offset" class="form-control" - value="{{sd-options.sd-offset}}" placeholder="0" min="0" max="15"> + value="{{scheduler-options.sd-offset}}" placeholder="0" min="0" max="15"> <span class="input-group-addon slx-ga2"> <label for="sd-offset-{{id}}">{{lang_offsetLate}}</label> </span> diff --git a/modules-available/rebootcontrol/hooks/cron.inc.php b/modules-available/rebootcontrol/hooks/cron.inc.php index 3651c779..9c6cbaaf 100644 --- a/modules-available/rebootcontrol/hooks/cron.inc.php +++ b/modules-available/rebootcontrol/hooks/cron.inc.php @@ -14,10 +14,11 @@ if (in_array((int)date('G'), [6, 7, 9, 12, 15]) && in_array(date('i'), ['00', '0 $now = time(); $res = Database::simpleQuery("SELECT * FROM reboot_scheduler WHERE nextexecution < :now", ['now' => $now]); while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $options = json_decode($row['options'], true); // Calculate next_execution for the event. $location = Database::queryFirst("SELECT openingtime FROM `location` WHERE locationid = :lid", array('lid' => $row['locationid'])); - Scheduler::updateSchedule($row['locationid'], $row['action'], $row['options'], $location['openingtime']); + Scheduler::updateSchedule($row['locationid'], $options, $location['openingtime']); if ($row['nextexecution'] + 1200 < $now) continue; @@ -27,10 +28,9 @@ while ($row = $res->fetch(PDO::FETCH_ASSOC)) { settype($machine['locationid'], 'int'); $machines[] = $machine; } - // Options not yet used. - $options = json_decode($row['options']); if ($row['action'] === 'sd') RebootControl::execute($machines, RebootControl::SHUTDOWN, 0); else if ($row['action'] === 'wol') RebootControl::wakeMachines($machines); + else if ($row['action'] === 'rb') RebootControl::execute($machines, RebootControl::REBOOT, 0); } /* diff --git a/modules-available/rebootcontrol/inc/scheduler.inc.php b/modules-available/rebootcontrol/inc/scheduler.inc.php index 27a22646..0928d20f 100644 --- a/modules-available/rebootcontrol/inc/scheduler.inc.php +++ b/modules-available/rebootcontrol/inc/scheduler.inc.php @@ -3,63 +3,97 @@ class Scheduler { - public static function updateSchedule($locationid, $action, $options, $openingTimes) { + public static function updateSchedule($locationid, $options, $openingTimes) { if ($openingTimes == '') { - self::deleteSchedule($locationid, $action); + self::deleteSchedule($locationid); return false; } - $nextexec = self::calcNextexec($action, $options, $openingTimes); + $nextexec = self::calculateNext($options, $openingTimes); $json_options = json_encode($options); - self::upsert($locationid, $action, $nextexec, $json_options); + if ($nextexec !== false) self::upsert($locationid, $nextexec['action'], $nextexec['time'], $json_options); + else { + // All times are getting ignored because they are within 5 minutes of each other, delete possible db entries. + self::deleteSchedule($locationid); + } return true; } - public static function deleteSchedule($locationid, $action) { + public static function deleteSchedule($locationid) { Database::exec("DELETE FROM `reboot_scheduler` - WHERE locationid = :lid AND action = :act", array( - 'lid' => $locationid, - 'act' => $action - )); + WHERE locationid = :lid", array('lid' => $locationid)); } - private static function calcNextexec($action, $options, $openingTimes) { + private static function calculateNext($options, $openingTimes) { $openingTimes = json_decode($openingTimes, true); - $now = time(); $times = []; + $now = time(); + $openTimes = []; + $closeTimes = []; foreach ($openingTimes as $row) { - // Fetch hour and minutes of opening / closing time. - $hourmin = explode(':', ($action == 'wol' ? $row['openingtime'] : $row['closingtime'])); - // Calculate time based on offset. - $min = ($action == 'wol' ? $hourmin[0] * 60 + $hourmin[1] - $options['wol-offset'] : $hourmin[0] * 60 + $hourmin[1] + $options['sd-offset']); - // Calculate opening / closing time of each day. + if (!$options['wol'] && !$options['sd']) continue; + if ($options['wol']) { + $open = explode(':', $row['openingtime']); + $openTime = $open[0] * 60 + $open[1] - $options['wol-offset']; + } + if ($options['sd']) { + $close = explode(':', $row['closingtime']); + $closeTime = $close[0] * 60 + $close[1] + $options['sd-offset']; + } foreach ($row['days'] as $day) { - $next = strtotime(date('Y-m-d H:i', strtotime($day . ' ' . $min . ' minutes'))); - if ($next < $now) { - $times[] = strtotime(date('Y-m-d H:i', strtotime('next '.$day . ' ' . $min . ' minutes'))); - } else { - $times[] = $next; + if ($options['wol']) { + $nextOpen = strtotime(date('Y-m-d H:i', strtotime($day . ' ' . $openTime . ' minutes'))); + if ($nextOpen < $now) $openTimes[] = strtotime(date('Y-m-d H:i', strtotime('next '.$day . ' ' . $openTime . ' minutes'))); + else $openTimes[] = $nextOpen; + } + if ($options['sd']) { + $nextClose = strtotime(date('Y-m-d H:i', strtotime($day . ' ' . $closeTime . ' minutes'))); + if ($nextClose < $now) $closeTimes[] = strtotime(date('Y-m-d H:i', strtotime('next '.$day . ' ' . $closeTime . ' minutes'))); + else $closeTimes[] = $nextClose; } } } - // Iterate over days, use timestamp with smallest difference to now. - $res = 0; $smallestDiff = 0; - foreach ($times as $time) { - $diff = $time - $now; - if ($res == 0 || $diff < $smallestDiff) { - $smallestDiff = $diff; - $res = $time; + + sort($openTimes); + sort($closeTimes); + $res = array(); + + if ($options['wol'] && !$options['sd']) { + $res['action'] = 'wol'; + $res['time'] = $openTimes[0]; + return $res; + } else if ($options['sd'] && !$options['wol']) { + $res['action'] = 'sd'; + $res['time'] = $closeTimes[0]; + return $res; + } + + for ($i = 0; $i <= sizeof($openTimes); $i++) { + if (abs($openTimes[$i] - $closeTimes[$i]) < 300) { + // If difference is < 5 min, ignore both events. + continue; + } else if (abs($openTimes[$i] - $closeTimes[$i]) < 900) { + // If difference is < 15 min, reboot at the earlier time. + $res['action'] = 'rb'; + $res['time'] = $openTimes[$i] < $closeTimes[$i] ? $openTimes[$i] : $closeTimes[$i]; + } else { + // Use first event. + if ($openTimes[$i] < $closeTimes[$i]) { + $res['action'] = 'wol'; + $res['time'] = $openTimes[$i]; + } else { + $res['action'] = 'sd'; + $res['time'] =$closeTimes[$i]; + } } + return $res; } - return $res; + return false; } - - private static function upsert($locationid, $action, $nextexec, $options) { - $schedule = Database::queryFirst("SELECT locationid, action + $schedule = Database::queryFirst("SELECT locationid FROM `reboot_scheduler` - WHERE locationid = :lid AND action = :act", array( - 'lid' => $locationid, - 'act' => $action + WHERE locationid = :lid", array( + 'lid' => $locationid )); if ($schedule === false) { Database::exec("INSERT INTO `reboot_scheduler` (locationid, action, nextexecution, options) @@ -71,12 +105,12 @@ class Scheduler )); } else { Database::exec("UPDATE `reboot_scheduler` - SET nextexecution = :next, options = :opt - WHERE locationid = :lid AND action = :act", array( + SET action = :act, nextexecution = :next, options = :opt + WHERE locationid = :lid", array( + 'act' => $action, 'next' => $nextexec, 'opt' => $options, - 'lid' => $locationid, - 'act' => $action + 'lid' => $locationid )); } return true; diff --git a/modules-available/rebootcontrol/install.inc.php b/modules-available/rebootcontrol/install.inc.php index 7d4382d0..008d26aa 100644 --- a/modules-available/rebootcontrol/install.inc.php +++ b/modules-available/rebootcontrol/install.inc.php @@ -55,4 +55,13 @@ $output[] = tableAddConstraint('reboot_subnet_x_subnet', 'dstid', 'reboot_subnet $output[] = tableAddConstraint('reboot_scheduler', 'locationid', 'location', 'locationid', 'ON UPDATE CASCADE ON DELETE CASCADE'); +if (tableExists('reboot_scheduler')) { + Database::exec("ALTER TABLE `reboot_scheduler` DROP PRIMARY KEY , ADD PRIMARY KEY (`locationid`)"); +} +if (tableHasColumn('reboot_scheduler', 'action')) { + Database::exec("ALTER TABLE `reboot_scheduler` MODIFY COLUMN `action` ENUM('wol', 'sd', 'rb')"); +} + + + responseFromArray($output);
\ No newline at end of file |