diff --git a/.github/workflows/L10n-update.yml b/.github/workflows/L10n-update.yml index 000b5348..46f7c15f 100644 --- a/.github/workflows/L10n-update.yml +++ b/.github/workflows/L10n-update.yml @@ -6,15 +6,6 @@ on: - master jobs: - trigger-update: - name: L10n Update Trigger - runs-on: ubuntu-latest - - steps: - - name: Repository dispatch - uses: peter-evans/repository-dispatch@v3 - with: - token: ${{ secrets.ICINGABOT_TOKEN }} - repository: Icinga/L10n - event-type: update - client-payload: '{"origin": "${{ github.repository }}", "commit": "${{ github.sha }}"}' + update: + uses: icinga/github-actions/.github/workflows/L10n-update.yml@main + secrets: inherit diff --git a/application/controllers/NotificationController.php b/application/controllers/NotificationController.php index 97fa0f4d..cef254ab 100644 --- a/application/controllers/NotificationController.php +++ b/application/controllers/NotificationController.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Controllers; +use Icinga\Exception\NotFoundError; use Icinga\Module\Director\Web\Controller\ObjectController; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaNotification; @@ -80,6 +81,10 @@ class NotificationController extends ObjectController } } + if (! $this->allowsObject($this->object)) { + throw new NotFoundError('No such object available'); + } + return $this->object; } } diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index c0a6182c..4782e5e1 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -49,14 +49,6 @@ class ServiceController extends ObjectController $this->host = $this->getOptionalRelatedObjectFromParams('host', 'host'); $this->set = $this->getOptionalRelatedObjectFromParams('service_set', 'set'); parent::init(); - if ($this->object) { - if ($this->host === null) { - $this->host = $this->loadOptionalRelatedObject($this->object, 'host'); - } - if ($this->set === null) { - $this->set = $this->loadOptionalRelatedObject($this->object, 'service_set'); - } - } $this->addOptionalHostTabs(); $this->addOptionalSetTabs(); } @@ -77,6 +69,20 @@ class ServiceController extends ObjectController return null; } + protected function loadOptionalObject(): void + { + parent::loadOptionalObject(); + + if ($this->object) { + if ($this->host === null) { + $this->host = $this->loadOptionalRelatedObject($this->object, 'host'); + } + if ($this->set === null) { + $this->set = $this->loadOptionalRelatedObject($this->object, 'service_set'); + } + } + } + protected function loadOptionalRelatedObject(IcingaObject $object, $relation) { $key = $object->getUnresolvedRelated($relation); diff --git a/application/controllers/ServicesetController.php b/application/controllers/ServicesetController.php index 684d2fc8..716eb2b2 100644 --- a/application/controllers/ServicesetController.php +++ b/application/controllers/ServicesetController.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Controllers; use Icinga\Data\Filter\Filter; +use Icinga\Exception\NotFoundError; use Icinga\Module\Director\Forms\IcingaServiceSetForm; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaServiceSet; @@ -136,6 +137,10 @@ class ServicesetController extends ObjectController } } + if (! $this->allowsObject($this->object)) { + throw new NotFoundError('No such object available'); + } + return $this->object; } } diff --git a/application/forms/DeployFormsBug7530.php b/application/forms/DeployFormsBug7530.php index b31d3563..0d127f9e 100644 --- a/application/forms/DeployFormsBug7530.php +++ b/application/forms/DeployFormsBug7530.php @@ -13,7 +13,7 @@ trait DeployFormsBug7530 if (parent::hasBeenSubmitted()) { return true; } else { - return \strlen($this->getSentValue('confirm_7530')) > 0; + return strlen($this->getSentValue('confirm_7530', '')) > 0; } } diff --git a/application/forms/IcingaAddServiceForm.php b/application/forms/IcingaAddServiceForm.php index 60ccb6f3..bd9a3771 100644 --- a/application/forms/IcingaAddServiceForm.php +++ b/application/forms/IcingaAddServiceForm.php @@ -30,7 +30,13 @@ class IcingaAddServiceForm extends DirectorObjectForm ); } - $this->addSingleImportElement(); + $this->addSingleImportElement(true); + + if (empty($this->enumServiceTemplates())) { + $this->setSubmitLabel(false); + + return; + } if (! ($imports = $this->getSentOrObjectValue('imports'))) { $this->setSubmitLabel($this->translate('Next')); diff --git a/application/forms/IcingaMultiEditForm.php b/application/forms/IcingaMultiEditForm.php index 4849d467..7f0c0d11 100644 --- a/application/forms/IcingaMultiEditForm.php +++ b/application/forms/IcingaMultiEditForm.php @@ -51,6 +51,7 @@ class IcingaMultiEditForm extends DirectorObjectForm $loader = new IcingaObjectFieldLoader($object); $loader->prepareElements($this); $loader->addFieldsToForm($this); + $this->varNameMap = $loader->getNameMap(); if ($form = $this->relatedForm) { if ($form instanceof DirectorObjectForm) { @@ -237,10 +238,6 @@ class IcingaMultiEditForm extends DirectorObjectForm $this->removeElement($key); $label = $element->getLabel(); - if ($this->isCustomVar($key)) { - $this->varNameMap[$key] = $label; - } - $group = $this->getDisplayGroupForElement($element); $description = $element->getDescription(); diff --git a/doc/02-Installation.md.d/From-Source.md b/doc/02-Installation.md.d/From-Source.md index c8c5d1ea..d4e894f1 100644 --- a/doc/02-Installation.md.d/From-Source.md +++ b/doc/02-Installation.md.d/From-Source.md @@ -41,7 +41,7 @@ and extract it to a folder named `director` in one of your Icinga Web module pat You might want to use a script as follows for this task: ```shell -MODULE_VERSION="1.11.3" +MODULE_VERSION="1.11.5" ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules" REPO_URL="https://github.com/icinga/icingaweb2-module-director" TARGET_DIR="${ICINGAWEB_MODULEPATH}/director" @@ -60,7 +60,7 @@ Simply clone the repository in one of your Icinga web module path directories. You might want to use a script as follows for this task: ```shell -MODULE_VERSION="1.11.3" +MODULE_VERSION="1.11.5" ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules" REPO_URL="https://github.com/icinga/icingaweb2-module-director" TARGET_DIR="${ICINGAWEB_MODULEPATH}/director" diff --git a/doc/82-Changelog.md b/doc/82-Changelog.md index 7ca8c330..e8f392ef 100644 --- a/doc/82-Changelog.md +++ b/doc/82-Changelog.md @@ -4,6 +4,50 @@ Please make sure to always read our [Upgrading](05-Upgrading.md) documentation before switching to a new version. +v1.11.5 +------- + +## Database Schema + +- FIX: Failed schema migration of MySQL to version 188 due Integrity constraint violation ([#2970](https://github.com/Icinga/icingaweb2-module-director/issues/2970)) + +## Deployment + +- Fix: Deprecation notice that sometimes appears on deployment form (no issue) + +### Fixed Issues + +You can find issues related to this release on our [roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/40?closed=1) + +v1.11.4 +------- + +### Security + +- Rest API endpoints accessible to restricted users ([GHSA-3233-ggc5-m3qg](https://github.com/Icinga/icingaweb2-module-director/security/advisories/GHSA-3233-ggc5-m3qg)) + +### UI + +- Fix editing of custom variables for multi-selected objects [#2950](https://github.com/Icinga/icingaweb2-module-director/issues/2950) +- Fix: Check for the existence of service templates to add services [#1249](https://github.com/Icinga/icingaweb2-module-director/issues/1249) + +### Import and Sync + +- Fix erratic job behavior during summer and winter time change (no issue) + +### Integration + +- Fix custom variable renderer for service apply for rules (no issue) +- Fix custom variable renderer for array type data lists [#2960](https://github.com/Icinga/icingaweb2-module-director/issues/2960) + +### Database Schema + +- Fix MySQL 8.4 nonstandard foreign keys deprecation [#2885](https://github.com/Icinga/icingaweb2-module-director/issues/2885) + +### Fixed Issues + +You can find issues related to this release on our [roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/39?closed=1) + v1.11.3 ------- diff --git a/library/Director/Objects/DirectorJob.php b/library/Director/Objects/DirectorJob.php index aadcabc0..a4a9eb61 100644 --- a/library/Director/Objects/DirectorJob.php +++ b/library/Director/Objects/DirectorJob.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Objects; use Icinga\Exception\NotFoundError; +use Icinga\Module\Director\Daemon\DaemonUtil; use Icinga\Module\Director\Daemon\Logger; use Icinga\Module\Director\Data\Db\DbObjectWithSettings; use Icinga\Module\Director\Db; @@ -84,7 +85,8 @@ class DirectorJob extends DbObjectWithSettings implements ExportInterface, Insta public function run() { $job = $this->getInstance(); - $this->set('ts_last_attempt', date('Y-m-d H:i:s')); + $currentTimestamp = DaemonUtil::timestampWithMilliseconds(); + $this->set('ts_last_attempt', $currentTimestamp); try { $job->run(); @@ -92,7 +94,7 @@ class DirectorJob extends DbObjectWithSettings implements ExportInterface, Insta $success = true; } catch (Exception $e) { Logger::error($e->getMessage()); - $this->set('ts_last_error', date('Y-m-d H:i:s')); + $this->set('ts_last_error', $currentTimestamp); $this->set('last_error_message', $e->getMessage()); $this->set('last_attempt_succeeded', 'n'); $success = false; @@ -127,8 +129,8 @@ class DirectorJob extends DbObjectWithSettings implements ExportInterface, Insta } return ( - strtotime($this->get('ts_last_attempt')) + $this->get('run_interval') * 2 - ) < time(); + $this->get('ts_last_attempt') + $this->get('run_interval') * 2 * 1000 + ) < DaemonUtil::timestampWithMilliseconds(); } public function hasBeenDisabled() @@ -145,7 +147,9 @@ class DirectorJob extends DbObjectWithSettings implements ExportInterface, Insta return $this->isWithinTimeperiod(); } - if (strtotime($this->get('ts_last_attempt')) + $this->get('run_interval') < time()) { + if ( + $this->get('ts_last_attempt') + $this->get('run_interval') * 1000 < DaemonUtil::timestampWithMilliseconds() + ) { return $this->isWithinTimeperiod(); } diff --git a/library/Director/ProvidedHook/Icingadb/CustomVarRenderer.php b/library/Director/ProvidedHook/Icingadb/CustomVarRenderer.php index fb307a52..933fb33c 100644 --- a/library/Director/ProvidedHook/Icingadb/CustomVarRenderer.php +++ b/library/Director/ProvidedHook/Icingadb/CustomVarRenderer.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\ProvidedHook\Icingadb; use Icinga\Application\Config; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotFoundError; +use Icinga\Module\Director\CustomVariable\CustomVariableArray; use Icinga\Module\Director\Daemon\Logger; use Icinga\Module\Director\Db; use Icinga\Module\Director\Db\AppliedServiceSetLoader; @@ -113,22 +114,42 @@ class CustomVarRenderer extends CustomVarRendererHook $appliedFilterQuery = IcingaHostAppliedServicesTable::load($directorHostObj)->getQuery(); foreach ($appliedFilterQuery->fetchAll() as $appliedService) { - if ($appliedService->name === $serviceName) { - $query = $db->getDbAdapter()->select()->from('icinga_service') - ->where('object_name = ?', $serviceName) - ->where("object_type = 'apply'") - ->where('assign_filter = ?', $appliedService->assign_filter); + if ($appliedService->apply_for === null) { + $isAppliedService = $appliedService->name === $serviceName; + } else { + /** @var ?CustomVariableArray $hostVar */ + $hostVar = $directorHostObj->vars()->get((substr($appliedService->apply_for, 10))); + if ($hostVar) { + $appliedServiceName = $appliedService->name; + $appliedForServiceLookup = []; + foreach ($hostVar->getValue() as $val) { + $appliedForServiceLookup[$appliedServiceName . $val] = true; + } - $directorAppliedServices = IcingaService::loadAll( - $db, - $query, - 'object_name' - ); - - $directorServiceObj = current($directorAppliedServices); - - break; + $isAppliedService = isset($appliedForServiceLookup[$serviceName]); + } else { + $isAppliedService = false; + } } + + if (! $isAppliedService) { + continue; + } + + $query = $db->getDbAdapter()->select()->from('icinga_service') + ->where('object_name = ?', $appliedService->name) + ->where("object_type = 'apply'") + ->where('assign_filter = ?', $appliedService->assign_filter); + + $directorAppliedServices = IcingaService::loadAll( + $db, + $query, + 'object_name' + ); + + $directorServiceObj = current($directorAppliedServices); + + break; } } elseif ($serviceOrigin[$i] === 'service-set') { $templateResolver = new IcingaTemplateResolver($directorHostObj); @@ -253,7 +274,24 @@ class CustomVarRenderer extends CustomVarRendererHook return '***'; } - if (isset($this->datalistMaps[$key][$value])) { + if (is_array($value)) { + $renderedValue = []; + foreach ($value as $v) { + if (is_string($v) && isset($this->datalistMaps[$key][$v])) { + $renderedValue[] = new HtmlElement( + 'span', + Attributes::create(['title' => $this->datalistMaps[$key][$v] . " [$v]"]), + Text::create($this->datalistMaps[$key][$v]) + ); + } else { + $renderedValue[] = $v; + } + } + + return $renderedValue; + } + + if (is_string($value) && isset($this->datalistMaps[$key][$value])) { return new HtmlElement( 'span', Attributes::create(['title' => $this->datalistMaps[$key][$value] . " [$value]"]), diff --git a/library/Director/ProvidedHook/Monitoring/CustomVarRenderer.php b/library/Director/ProvidedHook/Monitoring/CustomVarRenderer.php index 4eb8d2d0..40d2d006 100644 --- a/library/Director/ProvidedHook/Monitoring/CustomVarRenderer.php +++ b/library/Director/ProvidedHook/Monitoring/CustomVarRenderer.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\ProvidedHook\Monitoring; use Icinga\Application\Config; use Icinga\Exception\ConfigurationError; use Icinga\Exception\NotFoundError; +use Icinga\Module\Director\CustomVariable\CustomVariableArray; use Icinga\Module\Director\Daemon\Logger; use Icinga\Module\Director\Db; use Icinga\Module\Director\Db\AppliedServiceSetLoader; @@ -114,22 +115,42 @@ class CustomVarRenderer extends CustomVarRendererHook $appliedFilterQuery = IcingaHostAppliedServicesTable::load($directorHostObj)->getQuery(); foreach ($appliedFilterQuery->fetchAll() as $appliedService) { - if ($appliedService->name === $serviceName) { - $query = $db->getDbAdapter()->select()->from('icinga_service') - ->where('object_name = ?', $serviceName) - ->where("object_type = 'apply'") - ->where('assign_filter = ?', $appliedService->assign_filter); + if ($appliedService->apply_for === null) { + $isAppliedService = $appliedService->name === $serviceName; + } else { + /** @var ?CustomVariableArray $hostVar */ + $hostVar = $directorHostObj->vars()->get((substr($appliedService->apply_for, 10))); + if ($hostVar) { + $appliedServiceName = $appliedService->name; + $appliedForServiceLookup = []; + foreach ($hostVar->getValue() as $val) { + $appliedForServiceLookup[$appliedServiceName . $val] = true; + } - $directorAppliedServices = IcingaService::loadAll( - $db, - $query, - 'object_name' - ); - - $directorServiceObj = current($directorAppliedServices); - - break; + $isAppliedService = isset($appliedForServiceLookup[$serviceName]); + } else { + $isAppliedService = false; + } } + + if (! $isAppliedService) { + continue; + } + + $query = $db->getDbAdapter()->select()->from('icinga_service') + ->where('object_name = ?', $appliedService->name) + ->where("object_type = 'apply'") + ->where('assign_filter = ?', $appliedService->assign_filter); + + $directorAppliedServices = IcingaService::loadAll( + $db, + $query, + 'object_name' + ); + + $directorServiceObj = current($directorAppliedServices); + + break; } } elseif ($serviceOrigin[$i] === 'service-set') { $templateResolver = new IcingaTemplateResolver($directorHostObj); @@ -254,7 +275,24 @@ class CustomVarRenderer extends CustomVarRendererHook return '***'; } - if (isset($this->datalistMaps[$key][$value])) { + if (is_array($value)) { + $renderedValue = []; + foreach ($value as $v) { + if (is_string($v) && isset($this->datalistMaps[$key][$v])) { + $renderedValue[] = new HtmlElement( + 'span', + Attributes::create(['title' => $this->datalistMaps[$key][$v] . " [$v]"]), + Text::create($this->datalistMaps[$key][$v]) + ); + } else { + $renderedValue[] = $v; + } + } + + return $renderedValue; + } + + if (is_string($value) && isset($this->datalistMaps[$key][$value])) { return new HtmlElement( 'span', Attributes::create(['title' => $this->datalistMaps[$key][$value] . " [$value]"]), diff --git a/library/Director/Restriction/FilterByNameRestriction.php b/library/Director/Restriction/FilterByNameRestriction.php index aef28c4e..d1bea1c4 100644 --- a/library/Director/Restriction/FilterByNameRestriction.php +++ b/library/Director/Restriction/FilterByNameRestriction.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Restriction; use gipfl\IcingaWeb2\Zf1\Db\FilterRenderer; use Icinga\Authentication\Auth; use Icinga\Data\Filter\Filter; +use Icinga\Data\Filter\FilterEqual; use Icinga\Module\Director\Db; use Icinga\Module\Director\Objects\IcingaObject; use Zend_Db_Select as ZfSelect; @@ -30,7 +31,11 @@ class FilterByNameRestriction extends ObjectRestriction protected function setNameForType($type) { - $this->name = "director/{$type}/filter-by-name"; + if ($type === 'service_set') { + $this->name = "director/{$type}/filter-by-name"; + } else { + $this->name = "director/{$type}/apply/filter-by-name"; + } } public function allows(IcingaObject $object) @@ -39,9 +44,9 @@ class FilterByNameRestriction extends ObjectRestriction return true; } - return $this->getFilter()->matches([ + return $this->getFilter()->matches( (object) ['object_name' => $object->getObjectName()] - ]); + ); } public function getFilter() diff --git a/library/Director/Web/Controller/Extension/ObjectRestrictions.php b/library/Director/Web/Controller/Extension/ObjectRestrictions.php index bedb3f18..fa56f023 100644 --- a/library/Director/Web/Controller/Extension/ObjectRestrictions.php +++ b/library/Director/Web/Controller/Extension/ObjectRestrictions.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Web\Controller\Extension; use Icinga\Authentication\Auth; use Icinga\Module\Director\Db; use Icinga\Module\Director\Objects\IcingaObject; +use Icinga\Module\Director\Restriction\FilterByNameRestriction; use Icinga\Module\Director\Restriction\HostgroupRestriction; use Icinga\Module\Director\Restriction\ObjectRestriction; @@ -13,6 +14,9 @@ trait ObjectRestrictions /** @var ObjectRestriction[] */ private $objectRestrictions; + /** @var IcingaObject */ + private $dummyRestrictedObject; + /** * @return ObjectRestriction[] */ @@ -30,13 +34,27 @@ trait ObjectRestrictions */ protected function loadObjectRestrictions(Db $db, Auth $auth) { - return [ - new HostgroupRestriction($db, $auth) - ]; + $objectType = $this->dummyRestrictedObject->getShortTableName(); + if ( + ($objectType === 'service' && $this->dummyRestrictedObject->isApplyRule()) + || $objectType === 'notification' + || $objectType === 'service_set' + || $objectType === 'scheduled_downtime' + ) { + if ($objectType === 'scheduled_downtime') { + $objectType = 'scheduled-downtime'; + } + + return [new FilterByNameRestriction($db, $auth, $objectType)]; + } + + // If the object is host or host group load HostgroupRestriction + return [new HostgroupRestriction($db, $auth)]; } public function allowsObject(IcingaObject $object) { + $this->dummyRestrictedObject = $object; foreach ($this->getObjectRestrictions() as $restriction) { if (! $restriction->allows($object)) { return false; diff --git a/library/Director/Web/Controller/ObjectsController.php b/library/Director/Web/Controller/ObjectsController.php index 5b3c8879..1440ef45 100644 --- a/library/Director/Web/Controller/ObjectsController.php +++ b/library/Director/Web/Controller/ObjectsController.php @@ -17,6 +17,7 @@ use Icinga\Module\Director\Objects\IcingaService; use Icinga\Module\Director\RestApi\IcingaObjectsHandler; use Icinga\Module\Director\Web\ActionBar\ObjectsActionBar; use Icinga\Module\Director\Web\ActionBar\TemplateActionBar; +use Icinga\Module\Director\Web\Controller\Extension\ObjectRestrictions; use Icinga\Module\Director\Web\Form\FormLoader; use Icinga\Module\Director\Web\Table\ApplyRulesTable; use Icinga\Module\Director\Web\Table\ObjectSetTable; @@ -33,6 +34,7 @@ use Ramsey\Uuid\Uuid; abstract class ObjectsController extends ActionController { use BranchHelper; + use ObjectRestrictions; protected $isApified = true; @@ -75,9 +77,13 @@ abstract class ObjectsController extends ActionController $table = $this->getTable(); if ( $request->getControllerName() === 'services' - && $host = $this->params->get('host') + && $hostName = $this->params->get('host') ) { - $host = IcingaHost::load($host, $this->db()); + $host = IcingaHost::load($hostName, $this->db()); + if (! $this->allowsObject($host)) { + throw new NotFoundError(sprintf('Failed to load %s "%s"', $host->getTableName(), $hostName)); + } + $table->getQuery()->where('o.host_id = ?', $host->get('id')); } diff --git a/library/Director/Web/Form/IcingaObjectFieldLoader.php b/library/Director/Web/Form/IcingaObjectFieldLoader.php index 83b1aa6d..cf58b9eb 100644 --- a/library/Director/Web/Form/IcingaObjectFieldLoader.php +++ b/library/Director/Web/Form/IcingaObjectFieldLoader.php @@ -60,6 +60,16 @@ class IcingaObjectFieldLoader return $this; } + /** + * Get element names to variable names map (Example: ['elName' => 'varName']) + * + * @return array + */ + public function getNameMap(): array + { + return $this->nameMap; + } + public function loadFieldsForMultipleObjects($objects) { $fields = array(); diff --git a/library/Director/Web/Table/JobTable.php b/library/Director/Web/Table/JobTable.php index 81ba07b8..c9b3e85e 100644 --- a/library/Director/Web/Table/JobTable.php +++ b/library/Director/Web/Table/JobTable.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Web\Table; use gipfl\IcingaWeb2\Link; use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; +use Icinga\Module\Director\Daemon\DaemonUtil; class JobTable extends ZfQueryBasedTable { @@ -37,11 +38,11 @@ class JobTable extends ZfQueryBasedTable protected function getJobClasses($row) { - if ($row->unixts_last_attempt === null) { + if ($row->ts_last_attempt === null) { return 'pending'; } - if ($row->unixts_last_attempt + $row->run_interval < time()) { + if ($row->ts_last_attempt + $row->run_interval * 1000 < DaemonUtil::timestampWithMilliseconds()) { return 'pending'; } @@ -73,7 +74,6 @@ class JobTable extends ZfQueryBasedTable 'run_interval' => 'j.run_interval', 'last_attempt_succeeded' => 'j.last_attempt_succeeded', 'ts_last_attempt' => 'j.ts_last_attempt', - 'unixts_last_attempt' => 'UNIX_TIMESTAMP(j.ts_last_attempt)', 'ts_last_error' => 'j.ts_last_error', 'last_error_message' => 'j.last_error_message', ] diff --git a/library/Director/Web/Table/ObjectsTable.php b/library/Director/Web/Table/ObjectsTable.php index 4ad11661..00332bdf 100644 --- a/library/Director/Web/Table/ObjectsTable.php +++ b/library/Director/Web/Table/ObjectsTable.php @@ -226,11 +226,14 @@ class ObjectsTable extends ZfQueryBasedTable { /** @var Db $db */ $db = $this->connection(); + $dummyObject = $this->getDummyObject(); + $type = $dummyObject->getShortTableName(); - return [ - new HostgroupRestriction($db, $this->auth), - new FilterByNameRestriction($db, $this->auth, $this->getDummyObject()->getShortTableName()) - ]; + if ($dummyObject->isApplyRule()) { + return [new FilterByNameRestriction($db, $this->auth, $type)]; + } else { + return [new HostgroupRestriction($db, $this->auth)]; + } } /** diff --git a/library/Director/Web/Widget/JobDetails.php b/library/Director/Web/Widget/JobDetails.php index 3a530a25..b794d378 100644 --- a/library/Director/Web/Widget/JobDetails.php +++ b/library/Director/Web/Widget/JobDetails.php @@ -45,7 +45,7 @@ class JobDetails extends HtmlDocument $tsLastAttempt = $job->get('ts_last_attempt'); if ($tsLastAttempt) { - $ts = \strtotime($tsLastAttempt); + $ts = $tsLastAttempt / 1000; $timeAgo = Html::tag('span', [ 'class' => 'time-ago', 'title' => DateFormatter::formatDateTime($ts) diff --git a/module.info b/module.info index 1c448edf..6a3ffe66 100644 --- a/module.info +++ b/module.info @@ -1,5 +1,5 @@ Name: Icinga Director -Version: 1.11.3 +Version: 1.11.5 Depends: reactbundle (>=0.9.0), ipl (>=0.5.0), incubator (>=0.22.0) Description: Director - Config tool for Icinga 2 Icinga Director is a configuration tool that has been designed to make diff --git a/schema/mysql-migrations/upgrade_188.sql b/schema/mysql-migrations/upgrade_188.sql new file mode 100644 index 00000000..d3b916bb --- /dev/null +++ b/schema/mysql-migrations/upgrade_188.sql @@ -0,0 +1,22 @@ +ALTER TABLE director_generated_config + DROP FOREIGN KEY director_generated_config_activity; + +# Delete all entries with duplicate checksum except the first entry +DELETE log1 FROM director_activity_log log1 + INNER JOIN director_activity_log log2 ON log1.checksum = log2.checksum + WHERE log1.id > log2.id; + +ALTER TABLE director_activity_log +DROP INDEX checksum, +ADD UNIQUE INDEX checksum (checksum); + +ALTER TABLE director_generated_config + ADD CONSTRAINT director_generated_config_activity + FOREIGN KEY (last_activity_checksum) + REFERENCES director_activity_log (checksum) + ON DELETE RESTRICT + ON UPDATE RESTRICT; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (188, NOW()); diff --git a/schema/mysql-migrations/upgrade_189.sql b/schema/mysql-migrations/upgrade_189.sql new file mode 100644 index 00000000..4a52fc0d --- /dev/null +++ b/schema/mysql-migrations/upgrade_189.sql @@ -0,0 +1,17 @@ +ALTER TABLE director_job ADD COLUMN ts_last_attempt_tmp BIGINT(20) DEFAULT NULL; +ALTER TABLE director_job ADD COLUMN ts_last_error_tmp BIGINT(20) DEFAULT NULL; + + +UPDATE director_job +SET ts_last_attempt_tmp = UNIX_TIMESTAMP(ts_last_attempt) * 1000, + ts_last_error_tmp = UNIX_TIMESTAMP(ts_last_error) * 1000; + +ALTER TABLE director_job + DROP COLUMN ts_last_attempt, + DROP COLUMN ts_last_error, + CHANGE ts_last_attempt_tmp ts_last_attempt BIGINT(20) DEFAULT NULL, + CHANGE ts_last_error_tmp ts_last_error BIGINT(20) DEFAULT NULL; + +INSERT INTO director_schema_migration +(schema_version, migration_time) +VALUES (189, NOW()); diff --git a/schema/mysql.sql b/schema/mysql.sql index 832ab122..8052ecde 100644 --- a/schema/mysql.sql +++ b/schema/mysql.sql @@ -46,7 +46,7 @@ CREATE TABLE director_activity_log ( INDEX search_idx (object_name), INDEX search_idx2 (object_type(32), object_name(64), change_time), INDEX search_author (author), - INDEX checksum (checksum) + UNIQUE INDEX checksum (checksum) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE director_activity_log_remark ( @@ -114,7 +114,7 @@ CREATE TABLE director_generated_config ( last_activity_checksum VARBINARY(20) NOT NULL, PRIMARY KEY (checksum), CONSTRAINT director_generated_config_activity - FOREIGN KEY activity_checksum (last_activity_checksum) + FOREIGN KEY (last_activity_checksum) REFERENCES director_activity_log (checksum) ON DELETE RESTRICT ON UPDATE RESTRICT @@ -347,8 +347,8 @@ CREATE TABLE director_job ( run_interval INT(10) UNSIGNED NOT NULL, -- seconds timeperiod_id INT(10) UNSIGNED DEFAULT NULL, last_attempt_succeeded ENUM('y', 'n') DEFAULT NULL, - ts_last_attempt TIMESTAMP NULL DEFAULT NULL, - ts_last_error TIMESTAMP NULL DEFAULT NULL, + ts_last_attempt BIGINT(20) NULL DEFAULT NULL, + ts_last_error BIGINT(20) NULL DEFAULT NULL, last_error_message TEXT DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY (job_name), @@ -2446,4 +2446,4 @@ CREATE TABLE branched_icinga_dependency ( INSERT INTO director_schema_migration (schema_version, migration_time) - VALUES (187, NOW()); + VALUES (189, NOW()); diff --git a/schema/pgsql-migrations/upgrade_189.sql b/schema/pgsql-migrations/upgrade_189.sql new file mode 100644 index 00000000..6d6fdadf --- /dev/null +++ b/schema/pgsql-migrations/upgrade_189.sql @@ -0,0 +1,18 @@ +ALTER TABLE director_job ADD COLUMN ts_last_attempt_tmp bigint DEFAULT NULL; +ALTER TABLE director_job ADD COLUMN ts_last_error_tmp bigint DEFAULT NULL; + + +UPDATE director_job +SET ts_last_attempt_tmp = UNIX_TIMESTAMP(ts_last_attempt) * 1000, + ts_last_error_tmp = UNIX_TIMESTAMP(ts_last_error) * 1000; + +ALTER TABLE director_job + DROP COLUMN ts_last_attempt, + DROP COLUMN ts_last_error; + +ALTER TABLE director_job RENAME COLUMN ts_last_attempt_tmp TO ts_last_attempt; +ALTER TABLE director_job RENAME COLUMN ts_last_error_tmp TO ts_last_error; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (189, NOW()); diff --git a/schema/pgsql.sql b/schema/pgsql.sql index 694d8c90..c9f8183d 100644 --- a/schema/pgsql.sql +++ b/schema/pgsql.sql @@ -448,8 +448,8 @@ CREATE TABLE director_job ( run_interval integer NOT NULL, -- seconds timeperiod_id integer DEFAULT NULL, last_attempt_succeeded enum_boolean DEFAULT NULL, - ts_last_attempt timestamp with time zone DEFAULT NULL, - ts_last_error timestamp with time zone DEFAULT NULL, + ts_last_attempt bigint DEFAULT NULL, + ts_last_error bigint DEFAULT NULL, last_error_message text NULL DEFAULT NULL, CONSTRAINT director_job_period FOREIGN KEY (timeperiod_id) @@ -2781,4 +2781,4 @@ CREATE INDEX branched_dependency_search_object_name ON branched_icinga_dependenc INSERT INTO director_schema_migration (schema_version, migration_time) - VALUES (187, NOW()); + VALUES (189, NOW());