diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index d52805f..1102ead 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -4,6 +4,8 @@ use Icinga\Application\Config; use Icinga\Module\Masifupgrader\Forms\BackendForm; +use Icinga\Module\Masifupgrader\Forms\IntegrationForm; +use Icinga\Module\Masifupgrader\Forms\ServicesForm; use Icinga\Web\Controller; class ConfigController extends Controller @@ -18,4 +20,25 @@ public function backendAction() $this->view->tabs = $this->Module()->getConfigTabs()->activate('backend'); } + + public function integrationAction() + { + $this->assertPermission('config/modules'); + + $cfg = Config::module('masifupgrader'); + + $this->view->form1 = $form1 = new IntegrationForm(); + $form1->setIniConfig($cfg) + ->handleRequest(); + + if ($cfg->get('integration', 'monitoring', '0')) { + $this->view->form2 = $form2 = new ServicesForm(); + $form2->setIniConfig($cfg) + ->handleRequest(); + } else { + $this->view->form2 = null; + } + + $this->view->tabs = $this->Module()->getConfigTabs()->activate('integration'); + } } diff --git a/application/forms/IntegrationForm.php b/application/forms/IntegrationForm.php new file mode 100644 index 0000000..e93c3a3 --- /dev/null +++ b/application/forms/IntegrationForm.php @@ -0,0 +1,28 @@ +setName('form_config_integration'); + $this->setTitle($this->translate('Monitoring integration')); + $this->setSubmitLabel($this->translate('Save changes')); + } + + public function createElements(array $formData) + { + $this->addElement('checkbox', 'integration_monitoring', [ + 'label' => $this->translate('Monitoring module'), + 'description' => $this->translate('Integrate into the monitoring module (IDO)') + ]); + + if (!Icinga::app()->getModuleManager()->hasEnabled('monitoring')) { + $this->getElement('integration_monitoring')->disabled = true; + } + } +} diff --git a/application/forms/Monitoring/PackagesForm.php b/application/forms/Monitoring/PackagesForm.php new file mode 100644 index 0000000..87e606d --- /dev/null +++ b/application/forms/Monitoring/PackagesForm.php @@ -0,0 +1,205 @@ +tasks === null) { + $rawTasks = $this->fetchAll( + <<agent] + ); + + $this->tasks = []; + + foreach ($rawTasks as list($package, $action, $toVersion)) { + $this->tasks[$package][$action][$toVersion] = null; + } + } + + return $this->tasks; + } + + public function init() + { + $this->setName('form_monitoring_packages'); + $this->setSubmitLabel($this->translate('Approve selection')); + } + + public function createElements(array $formData) + { + foreach ($this->getTasks() as $package => $actions) { + foreach ($actions as $action => $toVersions) { + foreach ($toVersions as $toVersion => $_) { + $checkboxName = implode('_', [bin2hex($package), $action, bin2hex($toVersion)]); + $this->addElement('checkbox', $checkboxName, []); + } + } + } + } + + public function render(Zend_View_Interface $view = null) + { + $this->create(); + + foreach ($this->getElements() as $element) { + if ($element instanceof Zend_Form_Element_Checkbox || $element instanceof Zend_Form_Element_Submit) { + $element->setDecorators([ + 'Zend_Form_Decorator_ViewHelper' => $element->getDecorators()['Zend_Form_Decorator_ViewHelper'] + ]); + } + } + + if ($view === null) { + $view = $this->getView(); + } + + $t1header1 = $this->translate('Package'); + $t1header2 = $this->translate('Action'); + $t1header3 = $this->translate('Target version'); + $invertTrigger = $this->translate('(invert selection)'); + + $result = "
" + . $this->getElement($this->getUidElementName())->render($view) + . $this->getElement($this->getTokenElementName())->render($view) + . "" + . "" + . ""; + + $rows = []; + $currentRow = 0; + + $actionLabels = [ + 'install' => $this->translate('Install'), + 'update' => $this->translate('Update'), + 'configure' => $this->translate('Configure'), + 'remove' => $this->translate('Remove'), + 'purge' => $this->translate('Purge') + ]; + + $actionsOrder = array_flip(array_keys($actionLabels)); + + foreach ($this->getTasks() as $package => $actions) { + $packageRows = 0; + $packageOnRow = $currentRow; + + uksort($actions, function($lhs, $rhs) use($actionsOrder) { + return $actionsOrder[$lhs] - $actionsOrder[$rhs]; + }); + + foreach ($actions as $action => $toVersions) { + $actionOnRow = $currentRow; + + krsort($toVersions, SORT_NATURAL); + + foreach ($toVersions as $toVersion => $_) { + if ($toVersion === '') { + $toVersion = $this->translate('N/A'); + } + + $approve = $this->getElement(implode('_', [bin2hex($package), $action, bin2hex($toVersion)])); + + $rows[] = [ + null, + null, + "" + ]; + + ++$currentRow; + } + + $actionRows = count($toVersions); + $packageRows += $actionRows; + $rows[$actionOnRow][1] = ""; + } + + $rows[$packageOnRow][0] = ""; + } + + foreach ($rows as $row) { + $result .= '' . implode('', $row) . ''; + } + + return "$result
{$view->escape($t1header1)}{$view->escape($t1header2)}{$view->escape($t1header3)} {$view->escape($invertTrigger)}
{$approve->render($view)}{$view->escape($actionLabels[$action])}{$view->escape($package)}
{$this->getElement('btn_submit')->render($view)}
"; + } + + public function onSuccess() + { + $taskFilter = []; + + foreach ($this->getTasks() as $package => $actions) { + foreach ($actions as $action => $toVersions) { + foreach ($toVersions as $toVersion => $_) { + /** @var Zend_Form_Element_Checkbox $checkbox */ + $checkbox = $this->getElement(implode('_', [bin2hex($package), $action, bin2hex($toVersion)])); + + if ($checkbox->isChecked()) { + $taskFilter[$package][$action][$toVersion] = null; + } + } + } + } + + if (empty($taskFilter)) { + return false; + } + + list($packageFilters, $packageFilterParams) = $this->filterTasksByActions('t', 'p2', $taskFilter); + + $filter = "t.approved=0 AND t.agent=(SELECT a.id FROM agent a WHERE a.name=?) AND ($packageFilters)"; + $params = array_merge([$this->agent], $packageFilterParams); + + $this->transaction(function() use($filter, $params) { + $this->execSql("UPDATE task t SET t.approved=1 WHERE $filter", $params); + }); + + return true; + } + + /** + * @param string $agent + * + * @return PackagesForm + */ + public function setAgent($agent) + { + $this->agent = $agent; + return $this; + } +} diff --git a/application/forms/PackagesFormTrait.php b/application/forms/PackagesFormTrait.php new file mode 100644 index 0000000..048caaf --- /dev/null +++ b/application/forms/PackagesFormTrait.php @@ -0,0 +1,58 @@ + $actions) { + $params[] = $package; + $actionFilters = []; + + foreach ($actions as $action => $toVersions) { + $params[] = $action; + + $toVersionHasNull = false; + $toVersionsNotNull = 0; + + foreach ($toVersions as $toVersion => $_) { + if ($toVersion === '') { + $toVersionHasNull = true; + } else { + ++$toVersionsNotNull; + $params[] = $toVersion; + } + } + + $toVersionFilters = []; + + if ($toVersionHasNull) { + $toVersionFilters[] = "$t.to_version IS NULL"; + } + + if ($toVersionsNotNull) { + $toVersionFilters[] = "$t.to_version IN (" . implode(',', array_fill(0, $toVersionsNotNull, '?')) . ')'; + } + + $actionFilters[] = "($t.action=? AND (" . implode(' OR ', $toVersionFilters) . '))'; + } + + $packageFilters[] = "($t.package=(SELECT $p.id FROM package $p WHERE $p.name=?) AND (" . implode(' OR ', $actionFilters) . '))'; + } + + return [implode(' OR ', $packageFilters), $params]; + } +} diff --git a/application/forms/Pending/PackagesForm.php b/application/forms/Pending/PackagesForm.php index 78184e1..048aa45 100644 --- a/application/forms/Pending/PackagesForm.php +++ b/application/forms/Pending/PackagesForm.php @@ -2,7 +2,9 @@ namespace Icinga\Module\Masifupgrader\Forms\Pending; +use Icinga\Module\Masifupgrader\Forms\PackagesFormTrait; use Icinga\Module\Masifupgrader\Web\DbAwareFormTrait; +use Icinga\Module\Masifupgrader\Web\InvertableCheckboxesTrait; use Icinga\Web\Form; use Zend_Form_Element_Checkbox; use Zend_Form_Element_Submit; @@ -11,6 +13,8 @@ class PackagesForm extends Form { use DbAwareFormTrait; + use InvertableCheckboxesTrait; + use PackagesFormTrait; /** * @var array @@ -91,58 +95,6 @@ protected function getAgents($filter = []) return $this->agents; } - /** - * @param string $tasksTableAlias - * @param string $packagesTableAlias - * @param string $filter - * - * @return array - */ - protected function filterTasksByActions($tasksTableAlias, $packagesTableAlias, $filter) - { - $t = $tasksTableAlias; - $p = $packagesTableAlias; - $params = []; - $packageFilters = []; - - foreach ($filter as $package => $actions) { - $params[] = $package; - $actionFilters = []; - - foreach ($actions as $action => $toVersions) { - $params[] = $action; - - $toVersionHasNull = false; - $toVersionsNotNull = 0; - - foreach ($toVersions as $toVersion => $_) { - if ($toVersion === '') { - $toVersionHasNull = true; - } else { - ++$toVersionsNotNull; - $params[] = $toVersion; - } - } - - $toVersionFilters = []; - - if ($toVersionHasNull) { - $toVersionFilters[] = "$t.to_version IS NULL"; - } - - if ($toVersionsNotNull) { - $toVersionFilters[] = "$t.to_version IN (" . implode(',', array_fill(0, $toVersionsNotNull, '?')) . ')'; - } - - $actionFilters[] = "($t.action=? AND (" . implode(' OR ', $toVersionFilters) . '))'; - } - - $packageFilters[] = "($t.package=(SELECT $p.id FROM package $p WHERE $p.name=?) AND (" . implode(' OR ', $actionFilters) . '))'; - } - - return [implode(' OR ', $packageFilters), $params]; - } - public function init() { $this->setName('form_pending_packages'); @@ -212,7 +164,9 @@ public function render(Zend_View_Interface $view = null) . $filterAgents . "" . "" - . ""; + . ""; $rows = []; $currentRow = 0; diff --git a/application/forms/ServicesForm.php b/application/forms/ServicesForm.php new file mode 100644 index 0000000..1828855 --- /dev/null +++ b/application/forms/ServicesForm.php @@ -0,0 +1,34 @@ +setName('form_config_services'); + $this->setTitle($this->translate('Services')); + $this->setSubmitLabel($this->translate('Save changes')); + } + + public function createElements(array $formData) + { + /** @var PDO $pdo */ + $pdo = MonitoringBackend::instance()->getResource()->getDbAdapter()->getConnection(); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $stmt = $pdo->prepare('SELECT DISTINCT name2 FROM icinga_objects WHERE objecttype_id = 2 ORDER BY name2'); + $stmt->execute(); + + foreach ($stmt->fetchAll(PDO::FETCH_COLUMN) as $service) { + $this->addElement('checkbox', "services_$service", [ + 'label' => $this->translate($service), + 'description' => sprintf($this->translate('Integrate into services named "%s"'), $service) + ]); + } + } +} diff --git a/application/views/scripts/config/integration.phtml b/application/views/scripts/config/integration.phtml new file mode 100644 index 0000000..34f1e0e --- /dev/null +++ b/application/views/scripts/config/integration.phtml @@ -0,0 +1,7 @@ +
+ +
+
+ + +
diff --git a/configuration.php b/configuration.php index 87ca233..8d5ebbe 100644 --- a/configuration.php +++ b/configuration.php @@ -8,6 +8,12 @@ 'title' => $this->translate('Database backend') ]); +$this->provideConfigTab('integration', [ + 'url' => 'config/integration', + 'label' => $this->translate('Integration'), + 'title' => $this->translate('Monitoring integration') +]); + $section = $this->menuSection(N_('Masif Upgrader'), [ 'icon' => 'reschedule' ]); diff --git a/library/Masifupgrader/ProvidedHook/Monitoring/DetailviewExtension.php b/library/Masifupgrader/ProvidedHook/Monitoring/DetailviewExtension.php new file mode 100644 index 0000000..e61689f --- /dev/null +++ b/library/Masifupgrader/ProvidedHook/Monitoring/DetailviewExtension.php @@ -0,0 +1,34 @@ +get('integration', 'monitoring', '0') + && Config::module('masifupgrader')->get('services', $object->getName(), '0') + ) { + $this->init(); + + $view = $this->getView(); + + $form = new PackagesForm(); + $form->setDb($this->db)->setAgent($object->getHost()->getName())->handleRequest(); + + return '

' . $view->escape(mt('masifupgrader', 'Masif Upgrader')) . '

' . $form->render($view); + } + + return ''; + } +} diff --git a/library/Masifupgrader/Web/InvertableCheckboxesTrait.php b/library/Masifupgrader/Web/InvertableCheckboxesTrait.php new file mode 100644 index 0000000..f11d741 --- /dev/null +++ b/library/Masifupgrader/Web/InvertableCheckboxesTrait.php @@ -0,0 +1,11 @@ +provideHook('monitoring/DetailviewExtension');
{$view->escape($t1header1)}{$view->escape($t1header2)}{$view->escape($t1header3)} {$view->escape($invertTrigger)}
{$view->escape($t1header3)} {$view->escape($invertTrigger)}