ScheduledDowntime: initial implementation

refs #347
This commit is contained in:
Thomas Gelf 2016-10-13 08:33:10 +00:00
parent fb421d3756
commit 2615446572
5 changed files with 469 additions and 0 deletions

View File

@ -0,0 +1,9 @@
<?php
namespace Icinga\Module\Director\Controllers;
use Icinga\Module\Director\Web\Controller\ObjectsController;
class ScheduledDowntimesController extends ObjectsController
{
}

View File

@ -457,6 +457,7 @@ class Db extends DbConnection
'usergroup',
'command',
'timeperiod',
'scheduled_downtime',
'notification',
'apiuser',
'endpoint',

View File

@ -0,0 +1,81 @@
<?php
namespace Icinga\Module\Director\Objects;
use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
class IcingaScheduledDowntime extends IcingaObject
{
protected $table = 'icinga_scheduled_downtime';
protected $defaultProperties = array(
'id' => null,
'zone_id' => null,
'object_name' => null,
'object_type' => null,
'disabled' => 'n',
'display_name' => null,
'author' => null,
'comment' => null,
'fixed' => null,
'duration' => null,
);
protected $supportsImports = true;
protected $supportsRanges = true;
protected $relations = array(
'zone' => 'IcingaZone',
);
protected $booleans = array(
'fixed' => 'fixed',
);
protected $intervalProperties = array(
'duration' => 'duration',
);
/**
* Render update property
*
* Avoid complaints for method names with underscore:
* @codingStandardsIgnoreStart
*
* @return string
*/
public function renderUpdate_method()
{
// @codingStandardsIgnoreEnd
return '';
}
protected function renderObjectHeader()
{
return parent::renderObjectHeader()
. ' import "legacy-timeperiod"' . "\n";
}
public function isActive($now = null)
{
if ($now === null) {
$now = time();
}
foreach ($this->ranges()->getRanges() as $range) {
if ($range->isActive($now)) {
return true;
}
}
// TODO: no range currently means (and renders) "never", Icinga behaves
// different. Figure out whether and how we should support this
return false;
}
protected function prefersGlobalZone()
{
return true;
}
}

View File

@ -0,0 +1,89 @@
<?php
namespace Icinga\Module\Director\Objects;
use Icinga\Module\Director\Data\Db\DbObject;
class IcingaScheduledDowntimeRange extends DbObject
{
protected $keyName = array('scheduled_downtime_id', 'range_key', 'range_type');
protected $table = 'icinga_scheduled_downtime_range';
protected $defaultProperties = array(
'timeperiod_id' => null,
'range_key' => null,
'range_value' => null,
'range_type' => 'include',
'merge_behaviour' => 'set',
);
public function isActive($now = null)
{
if ($now === null) {
$now = time();
}
if (false === ($wday = $this->getWeekDay($this->range_key))) {
// TODO, dates are not yet supported
return false;
}
$wdayName = $this->range_key;
if ((int) strftime('%w', $now) !== $wday) {
return false;
}
$timeRanges = preg_split('/\s*,\s*/', $this->range_value, -1, PREG_SPLIT_NO_EMPTY);
foreach ($timeRanges as $timeRange) {
if ($this->timeRangeIsActive($timeRange, $now)) {
return true;
}
}
return false;
}
protected function timeRangeIsActive($rangeString, $now)
{
if (sscanf($rangeString, '%2d:%2d-%2d:%2d', $hBegin, $mBegin, $hEnd, $mEnd) === 4) {
if ($this->timeFromHourMin($hBegin, $mBegin, $now) <= $now
&& $this->timeFromHourMin($hEnd, $mEnd, $now) >= $now
) {
return true;
}
} else {
// TODO: throw exception?
}
return false;
}
protected function timeFromHourMin($hour, $min, $now)
{
return strtotime(sprintf('%s %02d:%02d:00', date('Y-m-d', $now), $hour, $min));
}
protected function getWeekDay($day)
{
switch ($day) {
case 'sunday':
return 0;
case 'monday':
return 1;
case 'tuesday':
return 2;
case 'wednesday':
return 3;
case 'thursday':
return 4;
case 'friday':
return 5;
case 'saturday':
return 6;
}
return false;
}
}

View File

@ -0,0 +1,289 @@
<?php
namespace Icinga\Module\Director\Objects;
use Icinga\Exception\ProgrammingError;
use Iterator;
use Countable;
use Icinga\Module\Director\IcingaConfig\IcingaConfigRenderer;
use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
class IcingaScheduledDowntimeRanges implements Iterator, Countable, IcingaConfigRenderer
{
protected $storedRanges = array();
protected $ranges = array();
protected $modified = false;
protected $object;
private $position = 0;
protected $idx = array();
public function __construct(IcingaObject $object)
{
$this->object = $object;
}
public function count()
{
return count($this->ranges);
}
public function rewind()
{
$this->position = 0;
}
public function hasBeenModified()
{
return $this->modified;
}
public function current()
{
if (! $this->valid()) {
return null;
}
return $this->ranges[$this->idx[$this->position]];
}
public function key()
{
return $this->idx[$this->position];
}
public function next()
{
++$this->position;
}
public function valid()
{
return array_key_exists($this->position, $this->idx);
}
public function get($key)
{
if (array_key_exists($key, $this->ranges)) {
return $this->ranges[$key];
}
return null;
}
public function getValues()
{
$res = array();
foreach ($this->ranges as $key => $range) {
$res[$key] = $range->range_value;
}
return (object) $res;
}
public function getOriginalValues()
{
$res = array();
foreach ($this->storedRanges as $key => $range) {
$res[$key] = $range->range_value;
}
return (object) $res;
}
public function getRanges()
{
return $this->ranges;
}
protected function modify($range, $value)
{
$this->ranges[$range]->range_key = $value;
}
public function set($ranges)
{
foreach ($ranges as $range => $value) {
$this->setRange($range, $value);
}
$toDelete = array_diff(array_keys($this->ranges), array_keys($ranges));
foreach ($toDelete as $range) {
$this->remove($range);
}
return $this;
}
public function setRange($range, $value)
{
if ($value === null && array_key_exists($range, $this->ranges)) {
$this->remove($range);
return $this;
}
if (array_key_exists($range, $this->ranges)) {
if ($this->ranges[$range]->range_value === $value) {
return $this;
} else {
$this->ranges[$range]->range_value = $value;
$this->modified = true;
}
} else {
$this->ranges[$range] = IcingaTimePeriodRange::create(array(
'timeperiod_id' => $this->object->id,
'range_key' => $range,
'range_value' => $value,
));
$this->modified = true;
}
return $this;
}
/**
* Magic isset check
*
* @return boolean
*/
public function __isset($range)
{
return array_key_exists($range, $this->ranges);
}
public function remove($range)
{
if (array_key_exists($range, $this->ranges)) {
unset($this->ranges[$range]);
}
$this->modified = true;
$this->refreshIndex();
}
public function clear()
{
$this->ranges = array();
$this->modified = true;
$this->refreshIndex();
}
protected function refreshIndex()
{
ksort($this->ranges);
$this->idx = array_keys($this->ranges);
}
protected function getRangeClass()
{
return __NAMESPACE__ . '\\Icinga' .ucfirst($this->object->getShortTableName()) . 'Range';
}
public function listRangesNames()
{
return array_keys($this->ranges);
}
public function getType()
{
return $this->object->getShortTableName();
}
public function getRangeTableName()
{
return $this->object->getTableName() . '_range';
}
protected function loadFromDb()
{
$db = $this->object->getDb();
$connection = $this->object->getConnection();
$table = $this->getRangeTableName();
$query = $db->select()->from(
array('o' => $table)
)->where('o.timeperiod_id = ?', (int) $this->object->id)
->order('o.range_key');
$class = $this->getClass();
$this->ranges = $class::loadAll($connection, $query, 'range_key');
$this->storedRanges = array();
foreach ($this->ranges as $key => $range) {
$this->storedRanges[$key] = clone($range);
}
return $this;
}
public function store()
{
foreach ($this->ranges as $range) {
$range->timeperiod_id = $this->object->id;
$range->store($this->object->getConnection());
}
foreach (array_diff(array_keys($this->storedRanges), array_keys($this->ranges)) as $delete) {
$this->storedRanges[$delete]->delete();
}
$this->storedRanges = $this->ranges;
return true;
}
protected function getClass()
{
return __NAMESPACE__ . '\\IcingaTimePeriodRange';
}
public static function loadForStoredObject(IcingaObject $object)
{
$ranges = new static($object);
return $ranges->loadFromDb();
}
public function toConfigString()
{
if (empty($this->ranges) && $this->object->object_type === 'template') {
return '';
}
$string = " ranges = {\n";
foreach ($this->ranges as $range) {
$string .= sprintf(
" %s\t= %s\n",
c::renderString($range->range_key),
c::renderString($range->range_value)
);
}
return $string . " }\n";
}
public function __toString()
{
try {
return $this->toConfigString();
} catch (Exception $e) {
trigger_error($e);
$previousHandler = set_exception_handler(
function () {
}
);
restore_error_handler();
if ($previousHandler !== null) {
call_user_func($previousHandler, $e);
die();
} else {
die($e->getMessage());
}
}
}
}