mirror of
https://github.com/Icinga/icingaweb2-module-businessprocess.git
synced 2026-02-14 08:23:20 -05:00
Clean orphaned (missing) nodes (#355)
resolves #222 ## Blocked by: - https://github.com/Icinga/icingaweb2-module-businessprocess/pull/358
This commit is contained in:
commit
7298134f2f
3 changed files with 271 additions and 9 deletions
106
application/clicommands/CleanupCommand.php
Normal file
106
application/clicommands/CleanupCommand.php
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Clicommands;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Application\Modules\Module;
|
||||
use Icinga\Cli\Command;
|
||||
use Icinga\Module\Businessprocess\Modification\NodeRemoveAction;
|
||||
use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport;
|
||||
use Icinga\Module\Businessprocess\State\IcingaDbState;
|
||||
use Icinga\Module\Businessprocess\State\MonitoringState;
|
||||
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
|
||||
|
||||
class CleanupCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var LegacyStorage
|
||||
*/
|
||||
protected $storage;
|
||||
|
||||
protected $defaultActionName = 'cleanup';
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->storage = LegacyStorage::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup all missing monitoring nodes from the specified config name
|
||||
* If no config name is specified, the missing nodes are cleaned from all available configs.
|
||||
* Invalid config files and file names are ignored
|
||||
*
|
||||
* USAGE
|
||||
*
|
||||
* icingacli businessprocess cleanup [<config-name>]
|
||||
*
|
||||
* OPTIONS
|
||||
*
|
||||
* <config-name>
|
||||
*/
|
||||
public function cleanupAction(): void
|
||||
{
|
||||
$configNames = (array) $this->params->shift() ?: $this->storage->listAllProcessNames();
|
||||
$foundMissingNode = false;
|
||||
foreach ($configNames as $configName) {
|
||||
if (! $this->storage->hasProcess($configName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$bp = $this->storage->loadProcess($configName);
|
||||
} catch (Exception $e) {
|
||||
Logger::error(
|
||||
'Failed to scan the %s.conf file for missing nodes. Invalid config found.',
|
||||
$configName
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Module::exists('icingadb')
|
||||
&& (! $bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend())
|
||||
) {
|
||||
IcingaDbState::apply($bp);
|
||||
} else {
|
||||
MonitoringState::apply($bp);
|
||||
}
|
||||
|
||||
$removedNodes = [];
|
||||
foreach (array_keys($bp->getMissingChildren()) as $missingNode) {
|
||||
$node = $bp->getNode($missingNode);
|
||||
$remove = new NodeRemoveAction($node);
|
||||
|
||||
try {
|
||||
if ($remove->appliesTo($bp)) {
|
||||
$remove->applyTo($bp);
|
||||
$removedNodes[] = $node->getName();
|
||||
$this->storage->storeProcess($bp);
|
||||
$bp->clearAppliedChanges();
|
||||
|
||||
$foundMissingNode = true;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Logger::error(sprintf('(%s.conf) %s', $configName, $e->getMessage()));
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($removedNodes)) {
|
||||
echo sprintf(
|
||||
'Removed following %d missing node(s) from %s.conf successfully:',
|
||||
count($removedNodes),
|
||||
$configName
|
||||
);
|
||||
|
||||
echo "\n" . implode("\n", $removedNodes) . "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (! $foundMissingNode) {
|
||||
echo "No missing node found.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,10 @@ use Icinga\Web\Url;
|
|||
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||
use ipl\Html\Html;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\HtmlString;
|
||||
use ipl\Html\TemplateString;
|
||||
use ipl\Web\Widget\Link;
|
||||
|
||||
class ProcessController extends Controller
|
||||
{
|
||||
|
|
@ -114,14 +117,6 @@ class ProcessController extends Controller
|
|||
|
||||
$this->tabs()->extend(new OutputFormat());
|
||||
|
||||
$missing = $bp->getMissingChildren();
|
||||
if (! empty($missing)) {
|
||||
if (($count = count($missing)) > 10) {
|
||||
$missing = array_slice($missing, 0, 10);
|
||||
$missing[] = '...';
|
||||
}
|
||||
$bp->addError('There are %d missing nodes: %s', $count, implode(', ', $missing));
|
||||
}
|
||||
$this->content()->add($this->showHints($bp));
|
||||
$this->content()->add($this->showWarnings($bp));
|
||||
$this->content()->add($this->showErrors($bp));
|
||||
|
|
@ -232,6 +227,12 @@ class ProcessController extends Controller
|
|||
->setParentNode($node)
|
||||
->setSession($this->session())
|
||||
->handleRequest();
|
||||
} elseif ($action === 'cleanup' && $canEdit) {
|
||||
$form = $this->loadForm('CleanupNode')
|
||||
->setSuccessUrl(Url::fromRequest()->without('action'))
|
||||
->setProcess($bp)
|
||||
->setSession($this->session())
|
||||
->handleRequest();
|
||||
} elseif ($action === 'editmonitored' && $canEdit) {
|
||||
$form = $this->loadForm('EditNode')
|
||||
->setSuccessUrl(Url::fromRequest()->without('action'))
|
||||
|
|
@ -323,9 +324,11 @@ class ProcessController extends Controller
|
|||
protected function showHints(BpConfig $bp)
|
||||
{
|
||||
$ul = Html::tag('ul', ['class' => 'error']);
|
||||
$this->prepareMissingNodeLinks($ul);
|
||||
foreach ($bp->getErrors() as $error) {
|
||||
$ul->add(Html::tag('li')->setContent($error));
|
||||
$ul->addHtml(Html::tag('li', $error));
|
||||
}
|
||||
|
||||
if ($bp->hasChanges()) {
|
||||
$li = Html::tag('li')->setSeparator(' ');
|
||||
$li->add(sprintf(
|
||||
|
|
@ -366,6 +369,66 @@ class ProcessController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
protected function prepareMissingNodeLinks(HtmlElement $ul): void
|
||||
{
|
||||
$missing = $this->bp->getMissingChildren();
|
||||
if (! empty($missing)) {
|
||||
$missingLinkedNodes = null;
|
||||
foreach ($this->bp->getImportedNodes() as $process) {
|
||||
if ($process->hasMissingChildren()) {
|
||||
$missingLinkedNodes = array_keys($process->getMissingChildren());
|
||||
$link = Url::fromPath('businessprocess/process/show')
|
||||
->addParams(['config' => $process->getConfigName()]);
|
||||
|
||||
$ul->addHtml(Html::tag(
|
||||
'li',
|
||||
[
|
||||
TemplateString::create(
|
||||
tp(
|
||||
'Linked node %s has one missing child node: {{#link}}Show{{/link}}',
|
||||
'Linked node %s has %d missing child nodes: {{#link}}Show{{/link}}',
|
||||
count($missingLinkedNodes)
|
||||
),
|
||||
$process->getAlias(),
|
||||
count($missingLinkedNodes),
|
||||
['link' => new Link(null, (string) $link)]
|
||||
)
|
||||
]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($missingLinkedNodes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$count = count($missing);
|
||||
if ($count > 10) {
|
||||
$missing = array_slice($missing, 0, 10);
|
||||
$missing[] = '...';
|
||||
}
|
||||
|
||||
$link = Url::fromPath('businessprocess/process/show')
|
||||
->addParams(['config' => $this->bp->getName(), 'action' => 'cleanup']);
|
||||
|
||||
$ul->addHtml(Html::tag(
|
||||
'li',
|
||||
[
|
||||
TemplateString::create(
|
||||
tp(
|
||||
'{{#link}}Cleanup{{/link}} one missing node: %2$s',
|
||||
'{{#link}}Cleanup{{/link}} %d missing nodes: %s',
|
||||
count($missing)
|
||||
),
|
||||
['link' => new Link(null, (string) $link)],
|
||||
$count,
|
||||
implode(', ', $missing)
|
||||
)
|
||||
]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the source code for a process
|
||||
*/
|
||||
|
|
|
|||
93
application/forms/CleanupNodeForm.php
Normal file
93
application/forms/CleanupNodeForm.php
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Businessprocess\Forms;
|
||||
|
||||
use Icinga\Module\Businessprocess\BpConfig;
|
||||
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
|
||||
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
|
||||
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||
use Icinga\Web\Session\SessionNamespace;
|
||||
use ipl\Html\FormattedString;
|
||||
use ipl\Html\Html;
|
||||
use ipl\Sql\Connection as IcingaDbConnection;
|
||||
|
||||
class CleanupNodeForm extends QuickForm
|
||||
{
|
||||
/** @var MonitoringBackend|IcingaDbConnection */
|
||||
protected $backend;
|
||||
|
||||
/** @var BpConfig */
|
||||
protected $bp;
|
||||
|
||||
/** @var SessionNamespace */
|
||||
protected $session;
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$this->addHtml(Html::tag('h2', $this->translate('Cleanup missing nodes')));
|
||||
|
||||
$this->addElement('checkbox', 'cleanup_all', [
|
||||
'class' => 'autosubmit',
|
||||
'label' => $this->translate('Cleanup all missing nodes'),
|
||||
'description' => $this->translate('Remove all missing nodes from config')
|
||||
]);
|
||||
|
||||
if ($this->getSentValue('cleanup_all') !== '1') {
|
||||
$this->addElement('multiselect', 'nodes', [
|
||||
'label' => $this->translate('Select nodes to cleanup'),
|
||||
'required' => true,
|
||||
'size' => 8,
|
||||
'multiOptions' => $this->bp->getMissingChildren()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MonitoringBackend|IcingaDbConnection $backend
|
||||
* @return $this
|
||||
*/
|
||||
public function setBackend($backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param BpConfig $process
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcess(BpConfig $process)
|
||||
{
|
||||
$this->bp = $process;
|
||||
$this->setBackend($process->getBackend());
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SessionNamespace $session
|
||||
* @return $this
|
||||
*/
|
||||
public function setSession(SessionNamespace $session)
|
||||
{
|
||||
$this->session = $session;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
{
|
||||
$changes = ProcessChanges::construct($this->bp, $this->session);
|
||||
|
||||
$nodesToCleanup = $this->getValue('cleanup_all') === '1'
|
||||
? array_keys($this->bp->getMissingChildren())
|
||||
: $this->getValue('nodes');
|
||||
|
||||
foreach ($nodesToCleanup as $nodeName) {
|
||||
$node = $this->bp->getNode($nodeName);
|
||||
$changes->deleteNode($node);
|
||||
}
|
||||
|
||||
unset($changes);
|
||||
|
||||
parent::onSuccess();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue