Merge branch 'next'

This commit is contained in:
Thomas Gelf 2017-01-11 18:01:58 +01:00
commit 28fc19be33
146 changed files with 12217 additions and 3444 deletions

3
.gitignore vendored
View file

@ -1 +1,4 @@
.idea/
/debian
/build
/coverage

86
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,86 @@
stages:
- Coding Standards
- Unit-Tests
- Build Packages
variables:
BASE_VERSION: "2.0.0"
VERSION_SUFFIX: "-b${CI_BUILD_ID}-${CI_BUILD_REF_SLUG}"
PSR2 CS Test:
stage: Coding Standards
tags:
- xenial
script:
- phpcs --report-width=auto --report-full --report-gitblame --report-summary -p --standard=PSR2 --extensions=php --encoding=utf-8 -w -s library/Businessprocess/ application/ configuration.php run.php test
Ubuntu Xenial:
stage: Unit-Tests
tags:
- xenial
- businessprocess
script:
- phpunit --testdox --coverage-html=coverage || phpunit --verbose
artifacts:
expire_in: 1 week
name: code-coverage
paths:
- coverage/*
Debian Jessie:
stage: Unit-Tests
tags:
- jessie
- businessprocess
script:
- phpunit --testdox || phpunit --verbose
CentOS 6:
stage: Unit-Tests
tags:
- centos6
- businessprocess
script:
- phpunit --testdox || phpunit --verbose
CentOS 7:
stage: Unit-Tests
tags:
- centos7
- businessprocess
script:
- phpunit --testdox || phpunit --verbose
Xenial Packages:
stage: Build Packages
tags:
- xenial
- businessprocess
script:
- cp -a packaging/debian debian
- dch --no-conf -U -M --empty -v "${BASE_VERSION}${VERSION_SUFFIX}-${CI_BUILD_REF:0:7}" "Automated build triggered by ${GITLAB_USER_ID} <${GITLAB_USER_EMAIL}>"
- cp LICENSE debian/copyright
- dpkg-buildpackage -us -uc
- mkdir build
- mv ../icingaweb2-module-businessprocess*.deb build/
artifacts:
expire_in: 1 week
paths:
- build/*
Jessie Packages:
stage: Build Packages
tags:
- jessie
- businessprocess
script:
- cp -a packaging/debian debian
- dch --no-conf -U -M --empty -v "${BASE_VERSION}${VERSION_SUFFIX}-${CI_BUILD_REF:0:7}" "Automated build triggered by ${GITLAB_USER_ID} <${GITLAB_USER_EMAIL}>"
- cp LICENSE debian/copyright
- dpkg-buildpackage -us -uc
- mkdir build
- mv ../icingaweb2-module-businessprocess*.deb build/
artifacts:
expire_in: 1 week
paths:
- build/*

View file

@ -336,4 +336,4 @@ This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
Public License instead of this License.

View file

@ -2,37 +2,15 @@
namespace Icinga\Module\Businessprocess\Clicommands;
use Icinga\Cli\Command;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\HostNode;
class CheckCommand extends Command
class CheckCommand extends ProcessCommand
{
protected $storage;
protected $hostColors = array(
0 => array('black', 'lightgreen'),
1 => array('black', 'lightred'),
2 => array('black', 'brown'),
99 => array('black', 'lightgray'),
);
protected $serviceColors = array(
0 => array('black', 'lightgreen'),
1 => array('black', 'yellow'),
2 => array('black', 'lightred'),
3 => array('black', 'lightpurple'),
99 => array('black', 'lightgray'),
);
public function init()
public function listActions()
{
$this->storage = new LegacyStorage($this->Config()->getSection('global'));
return array('process');
}
/**
* Check a specific process
* 'check process' is DEPRECATED, please use 'process check' instead
*
* USAGE
*
@ -40,75 +18,6 @@ class CheckCommand extends Command
*/
public function processAction()
{
$name = $this->params->get('config');
if ($name === null) {
$name = $this->getFirstProcessName();
}
$bp = $this->storage->loadProcess($name);
if (null !== ($stateType = $this->params->get('state-type'))) {
if ($stateType === 'soft') {
$bp->useSoftStates();
}
if ($stateType === 'hard') {
$bp->useHardStates();
}
}
$node = $bp->getNode($this->params->shift());
$bp->retrieveStatesFromBackend();
if ($bp->hasErrors()) {
printf(
"Checking Business Process %s failed: %s\n",
$node->getAlias(),
implode("\n", $bp->getErrors())
);
exit(3);
}
printf("Business Process %s: %s\n", $node->getStateName(), $node->getAlias());
if ($this->params->shift('details')) {
echo $this->renderProblemTree($node->getProblemTree(), $this->params->shift('colors'));
}
exit($node->getState());
}
protected function renderProblemTree($tree, $useColors = false, $depth = 0)
{
$output = '';
foreach ($tree as $name => $subtree) {
$node = $subtree['node'];
if ($node instanceof HostNode) {
$colors = $this->hostColors[$node->getState()];
} else {
$colors = $this->serviceColors[$node->getState()];
}
$state = sprintf('[%s]', $node->getStateName());
if ($useColors) {
$state = $this->screen->colorize($state, $colors[0], $colors[1]);
}
$output .= sprintf(
"%s%s %s %s\n",
str_repeat(' ', $depth),
$node instanceof BpNode ? $node->getOperator() : '-',
$state,
$node->getAlias()
);
$output .= $this->renderProblemTree($subtree['children'], $useColors, $depth + 1);
}
return $output;
}
protected function getFirstProcessName()
{
$list = $this->storage->listProcesses();
return key($list);
$this->checkAction();
}
}

View file

@ -0,0 +1,153 @@
<?php
namespace Icinga\Module\Businessprocess\Clicommands;
use Icinga\Cli\Command;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\HostNode;
use Icinga\Module\Businessprocess\Node;
use Icinga\Module\Businessprocess\State\MonitoringState;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
class ProcessCommand extends Command
{
/**
* @var LegacyStorage
*/
protected $storage;
protected $hostColors = array(
0 => array('black', 'lightgreen'),
1 => array('lightgray', 'lightred'),
2 => array('black', 'brown'),
99 => array('black', 'lightgray'),
);
protected $serviceColors = array(
0 => array('black', 'lightgreen'),
1 => array('black', 'yellow'),
2 => array('lightgray', 'lightred'),
3 => array('black', 'lightpurple'),
99 => array('black', 'lightgray'),
);
public function init()
{
$this->storage = new LegacyStorage($this->Config()->getSection('global'));
}
/**
* List all available process
*
* USAGE
*
* icingacli businessprocess list processes [options]
*
* OPTIONS
*
* --no-title Show only the process names and no related title
*/
public function listAction()
{
$noTitle = $this->params->shift('no-title');
foreach ($this->storage->listProcessNames() as $key => $title) {
if ($noTitle) {
echo $key . "\n";
} else {
echo $title . "\n";
}
}
}
/**
* Check a specific process
*
* USAGE
*
* icingacli businessprocess process check <process> [options]
*
* OPTIONS
*
* --config <configname> Name of the config that contains <process>
* --details Show problem details as a tree
* --colors Show colored output
* --state-type <type> Define which state type to look at. Could be
* either soft or hard, overrides an eventually
* configured default
*/
public function checkAction()
{
$name = $this->params->get('config');
if ($name === null) {
$name = $this->getFirstProcessName();
}
$bp = $this->storage->loadProcess($name);
if (null !== ($stateType = $this->params->get('state-type'))) {
if ($stateType === 'soft') {
$bp->useSoftStates();
}
if ($stateType === 'hard') {
$bp->useHardStates();
}
}
/** @var BpNode $node */
$node = $bp->getNode($this->params->shift());
MonitoringState::apply($bp);
if ($bp->hasErrors()) {
printf(
"Checking Business Process %s failed: %s\n",
$node->getAlias(),
implode("\n", $bp->getErrors())
);
exit(3);
}
printf("Business Process %s: %s\n", $node->getStateName(), $node->getAlias());
if ($this->params->shift('details')) {
echo $this->renderProblemTree($node->getProblemTree(), $this->params->shift('colors'));
}
exit($node->getState());
}
protected function renderProblemTree($tree, $useColors = false, $depth = 0)
{
$output = '';
foreach ($tree as $name => $subtree) {
/** @var Node $node */
$node = $subtree['node'];
if ($node instanceof HostNode) {
$colors = $this->hostColors[$node->getState()];
} else {
$colors = $this->serviceColors[$node->getState()];
}
$state = sprintf('[%s]', $node->getStateName());
if ($useColors) {
$state = $this->screen->colorize($state, $colors[0], $colors[1]);
}
$output .= sprintf(
"%s%s %s %s\n",
str_repeat(' ', $depth),
$node instanceof BpNode ? $node->getOperator() : '-',
$state,
$node->getAlias()
);
$output .= $this->renderProblemTree($subtree['children'], $useColors, $depth + 1);
}
return $output;
}
protected function getFirstProcessName()
{
$list = $this->storage->listProcessNames();
return key($list);
}
}

View file

@ -1,30 +1,20 @@
<?php
use Icinga\Module\Businessprocess\Controller;
namespace Icinga\Module\Businessprocess\Controllers;
class Businessprocess_IndexController extends Controller
use Icinga\Module\Businessprocess\Web\Controller;
use Icinga\Module\Businessprocess\Web\Component\Dashboard;
class IndexController extends Controller
{
/**
* Show a welcome page if no process is available
* Show an overview page
*/
public function indexAction()
{
$this->tabs()->add('welcome', array(
'label' => $this->translate('Business Processes'),
'url' => $this->getRequest()->getUrl()
))->activate('welcome');
$configs = $this->storage()->listProcesses();
if (! empty($configs)) {
// Redirect to show the first process if there is any
$this->redirectNow(
'businessprocess/process/show',
array('config' => key($configs))
);
}
// Check back from time to time, maybe someone created a process
$this->setAutorefreshInterval(30);
$this->setTitle($this->translate('Business Process Overview'));
$this->controls()->add($this->overviewTab());
$this->content()->add(Dashboard::create($this->Auth(), $this->storage()));
$this->setAutorefreshInterval(15);
}
}

View file

@ -1,79 +1,60 @@
<?php
use Icinga\Module\Businessprocess\Controller;
namespace Icinga\Module\Businessprocess\Controllers;
use Icinga\Module\Businessprocess\Renderer\Breadcrumb;
use Icinga\Module\Businessprocess\Renderer\TileRenderer;
use Icinga\Module\Businessprocess\Simulation;
use Icinga\Module\Businessprocess\Forms\ProcessForm;
use Icinga\Web\Url;
use Icinga\Module\Businessprocess\State\MonitoringState;
use Icinga\Module\Businessprocess\Web\Controller;
use Icinga\Module\Businessprocess\Web\Url;
/*
config = <file>
process = <node>
*/
class Businessprocess_NodeController extends Controller
class NodeController extends Controller
{
// rename to config
public function editAction()
public function impactAction()
{
$bp = $this->loadModifiedBpConfig();
$node = $bp->getNode($this->getParam('node'));
$detail = Url::fromPath(
'businessprocess/node/edit',
array(
'config' => $this->view->configName,
'node' => $node
)
$this->setAutorefreshInterval(10);
$content = $this->content();
$this->controls()->add(
$this->singleTab($this->translate('Node Impact'))
);
$name = $this->params->get('name');
$this->addTitle($this->translate('Business Impact (%s)'), $name);
$this->view->form = ProcessForm::construct()
->setProcess($bp)
->setSession($this->session())
->setNode($node)
->setRedirectUrl(
sprintf(
'businessprocess/process/show?config=%s&unlocked#!%s',
$bp->getName(),
$detail->getAbsoluteUrl()
)
)
->handleRequest();
foreach ($this->storage()->listProcessNames() as $configName) {
$config = $this->storage()->loadProcess($configName);
$this->view->node = $node;
}
// TODO: Fix issues with children, they do not exist unless resolved :-/
// This is a workaround:
foreach ($config->getRootNodes() as $node) {
$node->getState();
}
foreach ($config->getRootNodes() as $node) {
$node->clearState();
}
public function simulateAction()
{
$bp = $this->loadBpConfig();
$nodename = $this->getParam('node');
$node = $this->view->node = $bp->getNode($nodename);
if (! $config->hasNode($name)) {
continue;
}
$this->view->form = $this->loadForm('simulation')
->setNode($node)
->setSimulation(new Simulation($bp, $this->session()))
->handleRequest();
MonitoringState::apply($config);
$simulation = new Simulation($config, $this->session());
$config->applySimulation($simulation);
if ($this->view->form->succeeded()) {
$this->render('empty');
foreach ($config->getNode($name)->getPaths() as $path) {
$node = array_pop($path);
$renderer = new TileRenderer($config, $config->getNode($node));
$renderer->setUrl(
Url::fromPath(
'businessprocess/process/show',
array('config' => $configName)
)
)->setPath($path);
$bc = Breadcrumb::create($renderer);
$bc->attributes()->set('data-base-target', '_next');
$content->add($bc);
}
}
}
public function addAction()
{
$bp = $this->loadBpConfig();
$redirectUrl = Url::fromPath(
'businessprocess/process/show',
array('config' => $bp->getName())
);
$this->view->form = ProcessForm::construct()
->setProcess($bp)
->setSession($this->session())
->setRedirectUrl($redirectUrl)
->handleRequest();
}
public function deleteAction()
{
}
}

View file

@ -1,30 +1,54 @@
<?php
use Icinga\Module\Businessprocess\Controller;
use Icinga\Module\Businessprocess\ConfigDiff;
namespace Icinga\Module\Businessprocess\Controllers;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\State\MonitoringState;
use Icinga\Module\Businessprocess\Storage\ConfigDiff;
use Icinga\Module\Businessprocess\Html\Element;
use Icinga\Module\Businessprocess\Html\HtmlString;
use Icinga\Module\Businessprocess\Html\HtmlTag;
use Icinga\Module\Businessprocess\Html\Icon;
use Icinga\Module\Businessprocess\Html\Link;
use Icinga\Module\Businessprocess\Node;
use Icinga\Module\Businessprocess\Renderer\Breadcrumb;
use Icinga\Module\Businessprocess\Renderer\Renderer;
use Icinga\Module\Businessprocess\Renderer\TileRenderer;
use Icinga\Module\Businessprocess\Renderer\TreeRenderer;
use Icinga\Module\Businessprocess\Simulation;
use Icinga\Module\Businessprocess\ProcessChanges;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Icinga\Module\Businessprocess\Forms\BpConfigForm;
use Icinga\Module\Businessprocess\Forms\DeleteConfigForm;
use Icinga\Module\Businessprocess\Storage\LegacyConfigRenderer;
use Icinga\Module\Businessprocess\Web\Component\ActionBar;
use Icinga\Module\Businessprocess\Web\Component\RenderedProcessActionBar;
use Icinga\Module\Businessprocess\Web\Component\Tabs;
use Icinga\Module\Businessprocess\Web\Controller;
use Icinga\Module\Businessprocess\Web\Url;
use Icinga\Web\Notification;
use Icinga\Web\Widget\Tabextension\DashboardAction;
class Businessprocess_ProcessController extends Controller
class ProcessController extends Controller
{
/** @var Renderer */
protected $renderer;
/**
* Create a new business process configuration
*/
public function createAction()
{
$this->setTitle($this->translate('Create a new business process'));
$this->tabsForCreate()->activate('create');
$this->assertPermission('businessprocess/create');
$this->view->form = BpConfigForm::construct()
$title = $this->translate('Create a new business process');
$this->setTitle($title);
$this->controls()
->add($this->tabsForCreate()->activate('create'))
->add(HtmlTag::h1($title));
$this->content()->add(
$this->loadForm('bpConfig')
->setStorage($this->storage())
->setRedirectUrl('businessprocess/process/show')
->handleRequest();
->setSuccessUrl('businessprocess/process/show')
->handleRequest()
);
}
/**
@ -32,84 +56,247 @@ class Businessprocess_ProcessController extends Controller
*/
public function uploadAction()
{
$this->setTitle($this->translate('Upload a business process config file'));
$this->tabsForCreate()->activate('upload');
$title = $this->translate('Upload a business process config file');
$this->setTitle($title);
$this->controls()
->add($this->tabsForCreate()->activate('upload'))
->add(HtmlTag::h1($title));
$this->content()->add(
$this->loadForm('BpUpload')
->setStorage($this->storage())
->setSuccessUrl('businessprocess/process/show')
->handleRequest()
);
}
/**
* Show a business process tree
* Show a business process
*/
public function showAction()
{
$this->redirectIfConfigChosen();
$bp = $this->loadModifiedBpConfig();
$node = $this->getNode($bp);
$this->redirectOnConfigSwitch();
MonitoringState::apply($bp);
$this->handleSimulations($bp);
$this->setTitle($this->translate('Business Process "%s"'), $bp->getTitle());
$renderer = $this->prepareRenderer($bp, $node);
if ($this->params->get('unlocked')) {
$bp = $this->loadModifiedBpConfig();
$bp->unlock();
} else {
$bp = $this->loadBpConfig();
$renderer->unlock();
}
$this->setTitle('Business Process "%s"', $bp->getTitle());
$this->tabsForShow()->activate('show');
// Do not lock empty configs
if ($bp->isEmpty() && ! $this->view->compact && $bp->isLocked()) {
if ($bp->isEmpty() && $renderer->isLocked()) {
$this->redirectNow($this->url()->with('unlocked', true));
}
if ($node = $this->params->get('node')) {
// Render a specific node
$this->view->nodeName = $node;
$this->view->bp = $bp->getNode($node);
} else {
// Render a single process
$this->view->bp = $bp;
if ($bp->hasWarnings()) {
$this->view->warnings = $bp->getWarnings();
}
$this->prepareControls($bp, $renderer);
$this->content()->addContent($this->showHints($bp));
$this->content()->addContent($this->showWarnings($bp));
$this->content()->add($renderer);
$this->loadActionForm($bp, $node);
$this->setDynamicAutorefresh();
}
protected function prepareControls($bp, $renderer)
{
$controls = $this->controls();
if ($this->showFullscreen) {
$controls->attributes()->add('class', 'want-fullscreen');
$controls->add(
Link::create(
Icon::create('resize-small'),
$this->url()->without('showFullscreen')->without('view'),
null,
array('style' => 'float: right')
)
);
}
$bp->retrieveStatesFromBackend();
if (! ($this->showFullscreen || $this->view->compact)) {
$controls->add($this->getProcessTabs($bp, $renderer));
}
if (! $this->view->compact) {
$controls->add(Element::create('h1')->setContent($this->view->title));
}
$controls->add(Breadcrumb::create($renderer));
if (! $this->showFullscreen && ! $this->view->compact) {
$controls->add(
new RenderedProcessActionBar($bp, $renderer, $this->Auth(), $this->url())
);
}
}
if ($bp->isLocked()) {
$this->tabs()->extend(new DashboardAction());
protected function getNode(BpConfig $bp)
{
if ($nodeName = $this->params->get('node')) {
return $bp->getNode($nodeName);
} else {
$simulation = new Simulation($bp, $this->session());
if ($this->params->get('dismissSimulations')) {
Notification::success(
sprintf(
$this->translate('%d applied simulation(s) have been dropped'),
$simulation->count()
)
);
$simulation->clear();
$this->redirectNow($this->url()->without('dismissSimulations')->without('unlocked'));
}
return null;
}
}
$bp->applySimulation($simulation);
protected function prepareRenderer($bp, $node)
{
if ($this->renderer === null) {
if ($this->params->get('mode') === 'tree') {
$renderer = new TreeRenderer($bp, $node);
} else {
$renderer = new TileRenderer($bp, $node);
}
$renderer->setUrl($this->url())
->setPath($this->params->getValues('path'));
$this->renderer = $renderer;
}
if ($this->isXhr()) {
$this->setAutorefreshInterval(10);
} else {
return $this->renderer;
}
protected function getProcessTabs(BpConfig $bp, Renderer $renderer)
{
$tabs = $this->singleTab($bp->getTitle());
if ($renderer->isLocked()) {
$tabs->extend(new DashboardAction());
}
return $tabs;
}
protected function handleSimulations(BpConfig $bp)
{
$simulation = new Simulation($bp, $this->session());
if ($this->params->get('dismissSimulations')) {
Notification::success(
sprintf(
$this->translate('%d applied simulation(s) have been dropped'),
$simulation->count()
)
);
$simulation->clear();
$this->redirectNow($this->url()->without('dismissSimulations')->without('unlocked'));
}
$bp->applySimulation($simulation);
}
protected function loadActionForm(BpConfig $bp, Node $node = null)
{
$action = $this->params->get('action');
$form = null;
if ($this->showFullscreen) {
return;
}
if ($action === 'add') {
$form = $this->loadForm('AddNode')
->setProcess($bp)
->setParentNode($node)
->setSession($this->session())
->handleRequest();
} elseif ($action === 'delete') {
$form =$this->loadForm('DeleteNode')
->setProcess($bp)
->setNode($bp->getNode($this->params->get('deletenode')))
->setParentNode($node)
->setSession($this->session())
->handleRequest();
} elseif ($action === 'edit') {
$form =$this->loadForm('Process')
->setProcess($bp)
->setNode($bp->getNode($this->params->get('editnode')))
->setSession($this->session())
->handleRequest();
} elseif ($action === 'simulation') {
$form = $this->loadForm('simulation')
->setNode($bp->getNode($this->params->get('simulationnode')))
->setSimulation(new Simulation($bp, $this->session()))
->handleRequest();
}
if ($form) {
$this->content()->prependContent(HtmlString::create((string) $form));
}
}
protected function setDynamicAutorefresh()
{
if (! $this->isXhr()) {
// This will trigger the very first XHR refresh immediately on page
// load. Please not that this may hammer the server in case we would
// decide to use autorefreshInterval for HTML meta-refreshes also.
$this->setAutorefreshInterval(1);
return;
}
if ($this->params->get('mode') === 'toplevel') {
$this->render('toplevel');
if ($this->params->get('action')) {
$this->setAutorefreshInterval(45);
} else {
$this->setAutorefreshInterval(10);
}
}
/**
* Show a business process from a toplevel perspective
*/
public function toplevelAction()
protected function showWarnings(BpConfig $bp)
{
$this->redirectIfConfigChosen();
if ($bp->hasWarnings()) {
$ul = Element::create('ul', array('class' => 'warning'));
foreach ($bp->getWarnings() as $warning) {
$ul->createElement('li')->addContent($warning);
}
return $ul;
} else {
return null;
}
}
protected function showHints(BpConfig $bp)
{
$ul = Element::create('ul', array('class' => 'error'));
foreach ($bp->getErrors() as $error) {
$ul->createElement('li')->addContent($error);
}
if ($bp->hasChanges()) {
$ul->createElement('li')->setSeparator(' ')->addContent(sprintf(
$this->translate('This process has %d pending change(s).'),
$bp->countChanges()
))->addContent(
Link::create(
$this->translate('Store'),
'businessprocess/process/config',
array('config' => $bp->getName())
)
)->addContent(
Link::create(
$this->translate('Dismiss'),
$this->url()->with('dismissChanges', true),
null
)
);
}
if ($bp->hasSimulations()) {
$ul->createElement('li')->setSeparator(' ')->addContent(sprintf(
$this->translate('This process shows %d simulated state(s).'),
$bp->countSimulations()
))->addContent(Link::create(
$this->translate('Dismiss'),
$this->url()->with('dismissSimulations', true)
));
}
if ($ul->hasContent()) {
return $ul;
} else {
return null;
}
}
/**
@ -117,27 +304,73 @@ class Businessprocess_ProcessController extends Controller
*/
public function sourceAction()
{
$this->tabsForConfig()->activate('source');
$bp = $this->loadModifiedBpConfig();
$this->view->showDiff = $showDiff = (bool) $this->params->get('showDiff', false);
$this->view->source = $bp->toLegacyConfigString();
$this->view->showDiff = (bool) $this->params->get('showDiff', false);
$this->view->source = LegacyConfigRenderer::renderConfig($bp);
if ($this->view->showDiff) {
$this->view->diff = ConfigDiff::create(
$this->storage()->getSource($this->view->configName),
$this->view->source
);
$this->view->title = sprintf(
$title = sprintf(
$this->translate('%s: Source Code Differences'),
$bp->getTitle()
);
} else {
$this->view->title = sprintf(
$title = sprintf(
$this->translate('%s: Source Code'),
$bp->getTitle()
);
}
$actionBar = new ActionBar();
$this->setTitle($title);
$this->controls()
->add($this->tabsForConfig()->activate('source'))
->add(HtmlTag::h1($title))
->add($actionBar);
if ($showDiff) {
$actionBar->add(
Link::create(
$this->translate('Source'),
$this->url()->without('showDiff'),
null,
array(
'class' => 'icon-doc-text',
'title' => $this->translate('Show source code'),
)
)
);
} else {
$actionBar->add(
Link::create(
$this->translate('Diff'),
$this->url()->with('showDiff', true),
null,
array(
'class' => 'icon-flapping',
'title' => $this->translate('Highlight changes'),
)
)
);
}
$actionBar->add(
Link::create(
$this->translate('Download'),
'businessprocess/process/download',
array('config' => $bp->getName()),
array(
'target' => '_blank',
'class' => 'icon-download',
'title' => $this->translate('Download process configuration')
)
)
);
$this->setViewScript('process/source');
}
/**
@ -146,18 +379,17 @@ class Businessprocess_ProcessController extends Controller
public function downloadAction()
{
$bp = $this->loadModifiedBpConfig();
header(
$response = $this->getResponse();
$response->setHeader(
'Content-Disposition',
sprintf(
'Content-Disposition: attachment; filename="%s.conf";',
'attachment; filename="%s.conf";',
$bp->getName()
)
);
header('Content-Type: text/plain');
$response->setHeader('Content-Type', 'text/plain');
echo $bp->toLegacyConfigString();
// Didn't have time to lookup how to correctly disable our renderers
// TODO: no exit :)
echo $this->storage()->render($bp);
$this->doNotRender();
}
@ -166,40 +398,38 @@ class Businessprocess_ProcessController extends Controller
*/
public function configAction()
{
$this->tabsForConfig()->activate('config');
$bp = $this->loadModifiedBpConfig();
$this->setTitle(
$title = sprintf(
$this->translate('%s: Configuration'),
$bp->getTitle()
);
$this->setTitle($title);
$this->controls()
->add($this->tabsForConfig()->activate('config'))
->add(HtmlTag::h1($title));
$url = sprintf(
'businessprocess/process/show?config=%s&unlocked#!%s',
$bp->getName(),
$this->getRequest()->getUrl()
$url = Url::fromPath(
'businessprocess/process/show?unlocked',
array('config' => $bp->getName())
);
$this->content()->add(
$this->loadForm('bpConfig')
->setProcessConfig($bp)
->setStorage($this->storage())
->setSuccessUrl($url)
->handleRequest()
);
$this->view->form = BpConfigForm::construct()
->setProcessConfig($bp)
->setStorage($this->storage())
->setRedirectUrl($url)
->handleRequest();
$this->view->deleteForm = DeleteConfigForm::construct()
->setStorage($this->storage())
->setController($this)
->setBpConfig($bp)
->handleRequest();
}
/**
* Redirect to our URL plus the chosen config if someone switched the
* config in the appropriate dropdown list
*/
protected function redirectIfConfigChosen()
protected function redirectOnConfigSwitch()
{
$request = $this->getRequest();
if ($request->isPost()) {
if ($request->isPost() && $request->getPost('action') === 'switchConfig') {
// We switched the process in the config dropdown list
$params = array(
'config' => $request->getPost('config')
@ -216,6 +446,9 @@ class Businessprocess_ProcessController extends Controller
));
}
/**
* @return Tabs
*/
protected function tabsForCreate()
{
return $this->tabs()->add('create', array(

View file

@ -0,0 +1,397 @@
<?php
namespace Icinga\Module\Businessprocess\Forms;
use Icinga\Module\Businessprocess\BpNode;
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;
class AddNodeForm extends QuickForm
{
/** @var MonitoringBackend */
protected $backend;
/** @var BpConfig */
protected $bp;
/** @var BpNode */
protected $parent;
protected $objectList = array();
protected $processList = array();
/** @var SessionNamespace */
protected $session;
public function setup()
{
$view = $this->getView();
if ($this->hasParentNode()) {
$this->addHtml(
'<h2>' . $view->escape(
sprintf($this->translate('Add a node to %s'), $this->parent->getAlias())
) . '</h2>'
);
} else {
$this->addHtml(
'<h2>' . $this->translate('Add a new root node') . '</h2>'
);
}
$type = $this->selectNodeType();
switch ($type) {
case 'host':
$this->selectHost();
break;
case 'service':
$this->selectService();
break;
case 'process':
$this->selectProcess();
break;
case 'new-process':
$this->addNewProcess();
break;
case null:
$this->setSubmitLabel($this->translate('Next'));
return;
}
}
protected function addNewProcess()
{
$this->addElement('text', 'name', array(
'label' => $this->translate('Name'),
'required' => true,
'description' => $this->translate(
'This is the unique identifier of this process'
),
));
$this->addElement('text', 'alias', array(
'label' => $this->translate('Title'),
'description' => $this->translate(
'Usually this title will be shown for this node. Equals name'
. ' if not given'
),
));
$this->addElement('select', 'operator', array(
'label' => $this->translate('Operator'),
'required' => true,
'multiOptions' => array(
'&' => $this->translate('AND'),
'|' => $this->translate('OR'),
'!' => $this->translate('NOT'),
'<' => $this->translate('DEG'),
'1' => $this->translate('MIN 1'),
'2' => $this->translate('MIN 2'),
'3' => $this->translate('MIN 3'),
'4' => $this->translate('MIN 4'),
'5' => $this->translate('MIN 5'),
'6' => $this->translate('MIN 6'),
'7' => $this->translate('MIN 7'),
'8' => $this->translate('MIN 8'),
'9' => $this->translate('MIN 9'),
)
));
$this->addElement('select', 'display', array(
'label' => $this->translate('Visualization'),
'required' => true,
'description' => $this->translate(
'Where to show this process'
),
'value' => $this->hasParentNode() ? '0' : '1',
'multiOptions' => array(
'1' => $this->translate('Toplevel Process'),
'0' => $this->translate('Subprocess only'),
)
));
$this->addElement('text', 'infoUrl', array(
'label' => $this->translate('Info URL'),
'description' => $this->translate(
'URL pointing to more information about this node'
)
));
}
/**
* @return string|null
*/
protected function selectNodeType()
{
$types = array();
if ($this->hasParentNode()) {
$types['host'] = $this->translate('Host');
$types['service'] = $this->translate('Service');
} elseif (! $this->hasProcesses()) {
$this->addElement('hidden', 'node_type', array(
'ignore' => true,
'decorators' => array('ViewHelper'),
'value' => 'new-process'
));
return 'new-process';
}
if ($this->hasProcesses()) {
$types['process'] = $this->translate('Existing Process');
}
$types['new-process'] = $this->translate('New Process Node');
$this->addElement('select', 'node_type', array(
'label' => $this->translate('Node type'),
'required' => true,
'description' => $this->translate(
'The node type you want to add'
),
'ignore' => true,
'class' => 'autosubmit',
'multiOptions' => $this->optionalEnum($types)
));
return $this->getSentValue('node_type');
}
protected function selectHost()
{
$this->addElement('multiselect', 'children', array(
'label' => $this->translate('Hosts'),
'required' => true,
'size' => 8,
'style' => 'width: 25em',
'multiOptions' => $this->enumHostList(),
'description' => $this->translate(
'Hosts that should be part of this business process node'
)
));
}
protected function selectService()
{
$this->addHostElement();
if ($host = $this->getSentValue('host')) {
$this->addServicesElement($host);
} else {
$this->setSubmitLabel($this->translate('Next'));
}
}
protected function addHostElement()
{
$this->addElement('select', 'host', array(
'label' => $this->translate('Host'),
'required' => true,
'ignore' => true,
'class' => 'autosubmit',
'multiOptions' => $this->optionalEnum($this->enumHostForServiceList()),
));
}
protected function addServicesElement($host)
{
$this->addElement('multiselect', 'children', array(
'label' => $this->translate('Services'),
'required' => true,
'size' => 8,
'style' => 'width: 25em',
'multiOptions' => $this->enumServiceList($host),
'description' => $this->translate(
'Services that should be part of this business process node'
)
));
}
protected function selectProcess()
{
$this->addElement('multiselect', 'children', array(
'label' => $this->translate('Process nodes'),
'required' => true,
'size' => 8,
'style' => 'width: 25em',
'multiOptions' => $this->enumProcesses(),
'description' => $this->translate(
'Other processes that should be part of this business process node'
)
));
}
/**
* @param MonitoringBackend $backend
* @return $this
*/
public function setBackend(MonitoringBackend $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 BpNode|null $node
* @return $this
*/
public function setParentNode(BpNode $node = null)
{
$this->parent = $node;
return $this;
}
/**
* @return bool
*/
public function hasParentNode()
{
return $this->parent !== null;
}
/**
* @param SessionNamespace $session
* @return $this
*/
public function setSession(SessionNamespace $session)
{
$this->session = $session;
return $this;
}
protected function enumHostForServiceList()
{
$names = $this->backend->select()->from('hostStatus', array(
'hostname' => 'host_name',
))->order('host_name')->getQuery()->fetchColumn();
// fetchPairs doesn't seem to work when using the same column with
// different aliases twice
return array_combine((array) $names, (array) $names);
}
protected function enumHostList()
{
$names = $this->backend->select()->from('hostStatus', array(
'hostname' => 'host_name',
))->order('host_name')->getQuery()->fetchColumn();
// fetchPairs doesn't seem to work when using the same column with
// different aliases twice
$res = array();
$suffix = ';Hoststatus';
foreach ($names as $name) {
$res[$name . $suffix] = $name;
}
return $res;
}
protected function enumServiceList($host)
{
$query = $this->backend->select()->from(
'serviceStatus',
array('service' => 'service_description')
)->where('host_name', $host);
$query->order('service_description');
$names = $query->getQuery()->fetchColumn();
$services = array();
foreach ($names as $name) {
$services[$host . ';' . $name] = $name;
}
return $services;
}
protected function hasProcesses()
{
return count($this->enumProcesses()) > 0;
}
protected function enumProcesses()
{
$list = array();
foreach ($this->bp->getNodes() as $node) {
if ($node instanceof BpNode) {
// TODO: Blacklist parents
$list[(string) $node] = (string) $node; // display name?
}
}
natsort($list);
return $list;
}
protected function fetchObjectList()
{
$this->objectList = array();
$hosts = $this->backend->select()->from('hostStatus', array(
'hostname' => 'host_name',
'in_downtime' => 'host_in_downtime',
'ack' => 'host_acknowledged',
'state' => 'host_state'
))->order('host_name')->getQuery()->fetchAll();
$services = $this->backend->select()->from('serviceStatus', array(
'hostname' => 'host_name',
'service' => 'service_description',
'in_downtime' => 'service_in_downtime',
'ack' => 'service_acknowledged',
'state' => 'service_state'
))->order('host_name')->order('service_description')->getQuery()->fetchAll();
foreach ($hosts as $host) {
$this->objectList[$host->hostname] = array(
$host->hostname . ';Hoststatus' => 'Host Status'
);
}
foreach ($services as $service) {
$this->objectList[$service->hostname][
$service->hostname . ';' . $service->service
] = $service->service;
}
return $this;
}
public function onSuccess()
{
$changes = ProcessChanges::construct($this->bp, $this->session);
switch ($this->getValue('node_type')) {
case 'host':
case 'service':
case 'process':
$changes->addChildrenToNode($this->getValue('children'), $this->parent);
break;
case 'new-process':
$properties = $this->getValues();
unset($properties['name']);
$properties['parentName'] = $this->parent->getName();
$changes->createNode($this->getValue('name'), $properties);
break;
}
// Trigger session destruction to make sure it get's stored.
// TODO: figure out why this is necessary, might be an unclean shutdown on redirect
unset($changes);
parent::onSuccess();
}
}

View file

@ -3,18 +3,19 @@
namespace Icinga\Module\Businessprocess\Forms;
use Icinga\Application\Config;
use Icinga\Module\Businessprocess\BusinessProcess;
use Icinga\Module\Businessprocess\Form;
use Icinga\Web\Notification;
use Icinga\Web\Request;
use Icinga\Web\Url;
use Icinga\Authentication\Auth;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Storage\Storage;
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
class BpConfigForm extends Form
class BpConfigForm extends QuickForm
{
/** @var Storage */
protected $storage;
protected $backend;
/** @var BpConfig */
protected $config;
protected $node;
@ -23,47 +24,112 @@ class BpConfigForm extends Form
protected $processList = array();
protected $deleteButtonName;
public function setup()
{
$this->addElement('text', 'name', array(
'label' => $this->translate('Name'),
'label' => $this->translate('Name'),
'required' => true,
'validators' => array(
array(
'validator' => 'StringLength',
'options' => array(
'min' => 2,
'max' => 40
)
),
array(
'validator' => 'Regex',
'options' => array(
'pattern' => '/^[a-zA-Z0-9](?:[a-zA-Z0-9 ._-]*)?[a-zA-Z0-9_]$/'
)
)
),
'description' => $this->translate(
'This is the unique identifier of this process'
),
));
$this->addElement('text', 'title', array(
$this->addElement('text', 'Title', array(
'label' => $this->translate('Title'),
'description' => $this->translate(
'Usually this title will be shown for this process. Equals name'
. ' if not given'
. ' if not given'
),
));
$this->addElement('select', 'backend_name', array(
$this->addElement('textarea', 'Description', array(
'label' => $this->translate('Description'),
'description' => $this->translate(
'A slightly more detailed description for this process, about 100-150 characters long'
),
'rows' => 4,
));
$this->addElement('select', 'Backend', array(
'label' => $this->translate('Backend'),
'description' => $this->translate(
'Icinga Web Monitoring Backend where current object states for'
. ' this process should be retrieved from'
. ' this process should be retrieved from'
),
'multiOptions' => array(
null => $this->translate('Use the configured default backend'),
) + $this->listAvailableBackends()
));
$this->addElement('select', 'state_type', array(
$this->addElement('select', 'Statetype', array(
'label' => $this->translate('State Type'),
'required' => true,
'description' => $this->translate(
'Whether this process should be based on Icinga hard or soft states'
),
'multiOptions' => array(
'hard' => $this->translate('Use HARD states'),
'soft' => $this->translate('Use SOFT states'),
'hard' => $this->translate('Use HARD states'),
)
));
$this->addElement('submit', $this->translate('Store'));
$this->addElement('select', 'AddToMenu', array(
'label' => $this->translate('Add to menu'),
'required' => true,
'description' => $this->translate(
'Whether this process should be linked in the main Icinga Web 2 menu'
),
'multiOptions' => array(
'yes' => $this->translate('Yes'),
'no' => $this->translate('No'),
)
));
if ($this->config === null) {
$this->setSubmitLabel(
$this->translate('Add')
);
} else {
$config = $this->config;
$meta = $config->getMetadata();
foreach ($meta->getProperties() as $k => $v) {
if ($el = $this->getElement($k)) {
$el->setValue($v);
}
}
$this->getElement('name')
->setValue($config->getName())
->setAttrib('readonly', true);
$this->setSubmitLabel(
$this->translate('Store')
);
$label = $this->translate('Delete');
$el = $this->createElement('submit', $label, array(
'data-base-target' => '_main'
))->setLabel($label)->setDecorators(array('ViewHelper'));
$this->deleteButtonName = $el->getName();
$this->addElement($el);
}
}
protected function listAvailableBackends()
@ -81,78 +147,69 @@ class BpConfigForm extends Form
public function setProcessConfig($config)
{
$this->config = $config;
$this->getElement('name')->setValue($config->getName());
$this->getElement('name')->setAttrib('readonly', true);
if ($config->hasTitle()) {
$this->getElement('title')->setValue($config->getTitle());
}
if ($config->hasBackend()) {
$this->getElement('backend_name')->setValue(
$config->getBackend()->getName()
);
}
if ($config->usesSoftStates()) {
$this->getElement('state_type')->setValue('soft');
} else {
$this->getElement('state_type')->setValue('hard');
}
return $this;
}
protected function onRequest()
{
$name = $this->getValue('name');
if ($this->shouldBeDeleted()) {
$this->config->clearAppliedChanges();
$this->storage->deleteProcess($name);
$this->setSuccessUrl('businessprocess');
$this->redirectOnSuccess(sprintf('Process %s has been deleted', $name));
}
}
public function onSuccess()
{
$name = $this->getValue('name');
$title = $this->getValue('title');
$backend = $this->getValue('backend');
$name = $this->getValue('name');
if ($this->config === null) {
// New config
$config = new BusinessProcess();
$config = new BpConfig();
$config->setName($name);
if ($title) {
$config->setTitle($title);
}
if ($backend) {
$config->setBackendName($backend);
}
if ($this->getValue('state_type') === 'soft') {
$config->useSoftStates();
} else {
$config->useHardStates();
}
$this->storage->storeProcess($config);
$config->clearAppliedChanges();
$this->setRedirectUrl(
$this->getRedirectUrl()->setParams(
$config->getMetadata()->set('Owner', Auth::getInstance()->getUser()->getUsername());
$this->setSuccessUrl(
$this->getSuccessUrl()->setParams(
array('config' => $name, 'unlocked' => true)
)
);
$this->setSuccessMessage(sprintf('Process %s has been created', $name));
Notification::success(sprintf('Process %s has been created', $name));
} else {
// Existing config
$config = $this->config;
if ($title) {
$config->setTitle($title);
}
if ($backend) {
$config->setBackendName($backend);
}
if ($this->getValue('state_type') === 'soft') {
$config->useSoftStates();
} else {
$config->useHardStates();
}
$this->storage->storeProcess($config);
$config->clearAppliedChanges();
$this->getRedirectUrl()->setParam('config', $name);
Notification::success(sprintf('Process %s has been stored', $name));
$this->setSuccessMessage(sprintf('Process %s has been stored', $name));
}
$meta = $config->getMetadata();
foreach ($this->getValues() as $key => $value) {
if ($value === null || $value === '') {
continue;
}
if ($meta->hasKey($key)) {
$meta->set($key, $value);
}
}
$this->storage->storeProcess($config);
$config->clearAppliedChanges();
$this->setSuccessUrl('businessprocess/process/show', array('config' => $name));
parent::onSuccess();
}
public function hasDeleteButton()
{
return $this->deleteButtonName !== null;
}
public function shouldBeDeleted()
{
if (! $this->hasDeleteButton()) {
return false;
}
$name = $this->deleteButtonName;
return $this->getSentValue($name) === $this->getElement($name)->getLabel();
}
}

View file

@ -0,0 +1,232 @@
<?php
namespace Icinga\Module\Businessprocess\Forms;
use Icinga\Application\Config;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
use Icinga\Web\Notification;
class BpUploadForm extends QuickForm
{
/** @var LegacyStorage */
protected $storage;
protected $backend;
/** @var BpConfig */
protected $config;
protected $node;
protected $objectList = array();
protected $processList = array();
protected $deleteButtonName;
public function setup()
{
$this->addElement('text', 'name', array(
'label' => $this->translate('Name'),
// 'required' => true,
'description' => $this->translate(
'This is the unique identifier of this process'
),
));
$this->addElement('text', 'title', array(
'label' => $this->translate('Title'),
'description' => $this->translate(
'Usually this title will be shown for this process. Equals name'
. ' if not given'
),
));
$this->addElement('select', 'backend_name', array(
'label' => $this->translate('Backend'),
'description' => $this->translate(
'Icinga Web Monitoring Backend where current object states for'
. ' this process should be retrieved from'
),
'multiOptions' => array(
null => $this->translate('Use the configured default backend'),
) + $this->listAvailableBackends()
));
$this->addElement('select', 'state_type', array(
'label' => $this->translate('State Type'),
'required' => true,
'description' => $this->translate(
'Whether this process should be based on Icinga hard or soft states'
),
'multiOptions' => array(
'hard' => $this->translate('Use HARD states'),
'soft' => $this->translate('Use SOFT states'),
)
));
$this->setAttrib('enctype', 'multipart/form-data');
$tmpdir = sys_get_temp_dir();
$this->addElement('file', 'uploaded_file', array(
'label' => $this->translate('File'),
'destination' => $tmpdir,
'required' => true,
));
/** @var \Zend_Form_Element_File $el */
$el = $this->getElement('uploaded_file');
$el->setValueDisabled(true);
if ($this->config === null) {
$this->setSubmitLabel(
$this->translate('Add')
);
} else {
$config = $this->config;
$this->getElement('name')
->setValue($config->getName())
->setAttrib('readonly', true);
if ($config->hasTitle()) {
$this->getElement('title')->setValue($config->getTitle());
}
if ($config->hasBackend()) {
$this->getElement('backend_name')->setValue(
$config->getBackend()->getName()
);
}
if ($config->usesSoftStates()) {
$this->getElement('state_type')->setValue('soft');
} else {
$this->getElement('state_type')->setValue('hard');
}
$this->setSubmitLabel(
$this->translate('Upload')
);
/*
$label = $this->translate('Delete');
$el = $this->createElement('submit', $label)
->setLabel($label)
->setDecorators(array('ViewHelper'));
$this->deleteButtonName = $el->getName();
$this->addElement($el);
*/
}
}
protected function listAvailableBackends()
{
$keys = array_keys(Config::module('monitoring', 'backends')->toArray());
return array_combine($keys, $keys);
}
public function setStorage(LegacyStorage $storage)
{
$this->storage = $storage;
return $this;
}
public function setProcessConfig(BpConfig $config)
{
$this->config = $config;
return $this;
}
public function onSuccess()
{
$tmpdir = sys_get_temp_dir();
$tmpfile = tempnam($tmpdir, 'bpupload_');
unlink($tmpfile);
$values = $this->getValues();
/** @var \Zend_Form_Element_File $el */
$el = $this->getElement('uploaded_file');
var_dump($el->getFileName());
var_dump($tmpfile);
$el->addFilter('Rename', $tmpfile);
if (!$el->receive()) {
print_r($el->file->getMessages());
}
echo file_get_contents($tmpfile);
unlink($tmpfile);
echo "DONE\n";
exit;
$name = $this->getValue('name');
$title = $this->getValue('title');
$backend = $this->getValue('backend');
/*
onSuccess:
$uploadedData = $form->getValues();
$fullFilePath = $form->file->getFileName();
*/
var_dump($this->getValues());
exit;
if ($this->config === null) {
// New config
$config = new BpConfig();
$config->setName($name);
if ($title) {
$config->setTitle($title);
}
if ($backend) {
$config->setBackendName($backend);
}
if ($this->getValue('state_type') === 'soft') {
$config->useSoftStates();
} else {
$config->useHardStates();
}
$this->storage->storeProcess($config);
$config->clearAppliedChanges();
$this->setSuccessUrl(
$this->getSuccessUrl()->setParams(
array('config' => $name, 'unlocked' => true)
)
);
$this->redirectOnSuccess(sprintf('Process %s has been created', $name));
} else {
$config = $this->config;
if ($title) {
$config->setTitle($title);
}
if ($backend) {
$config->setBackendName($backend);
}
if ($this->getValue('state_type') === 'soft') {
$config->useSoftStates();
} else {
$config->useHardStates();
}
$this->storage->storeProcess($config);
$config->clearAppliedChanges();
$this->getSuccessUrl()->setParam('config', $name);
Notification::success(sprintf('Process %s has been stored', $name));
}
}
public function hasDeleteButton()
{
return $this->deleteButtonName !== null;
}
public function shouldBeDeleted()
{
if (! $this->hasDeleteButton()) {
return false;
}
$name = $this->deleteButtonName;
return $this->getSentValue($name) === $this->getElement($name)->getLabel();
}
}

View file

@ -1,46 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess\Forms;
use Icinga\Module\Businessprocess\BusinessProcess;
use Icinga\Module\Businessprocess\Form;
use Icinga\Web\Notification;
class DeleteConfigForm extends Form
{
protected $storage;
protected $controller;
public function setup()
{
$this->addHidden('name');
$this->addElement('submit', $this->translate('Delete this process'));
}
public function setStorage($storage)
{
$this->storage = $storage;
return $this;
}
public function setController($controller)
{
$this->controller = $controller;
return $this;
}
public function setBpConfig($bp)
{
$this->getElement('name')->setValue($bp->getName());
return $this;
}
public function onSuccess()
{
$name = $this->getValue('name');
$this->storage->deleteProcess($name);
$this->setRedirectUrl('businessprocess');
Notification::success(sprintf('Process %s has been deleted', $name));
}
}

View file

@ -0,0 +1,152 @@
<?php
namespace Icinga\Module\Businessprocess\Forms;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
use Icinga\Module\Businessprocess\Node;
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
use Icinga\Web\Session\SessionNamespace;
class DeleteNodeForm extends QuickForm
{
/** @var MonitoringBackend */
protected $backend;
/** @var BpConfig */
protected $bp;
/** @var Node */
protected $node;
/** @var BpNode */
protected $parentNode;
/** @var SessionNamespace */
protected $session;
public function setup()
{
$node = $this->node;
$view = $this->getView();
$this->addHtml(
'<h2>' . $view->escape(
sprintf($this->translate('Delete "%s"'), $node->getAlias())
) . '</h2>'
);
$biLink = $view->qlink(
$node->getAlias(),
'businessprocess/node/impact',
array('name' => $node->getName()),
array('data-base-target' => '_next')
);
$this->addHtml(
'<p>' . sprintf(
$view->escape(
$this->translate('Unsure? Show business impact of "%s"')
),
$biLink
) . '</p>'
);
if ($this->parentNode) {
$yesMsg = sprintf(
$this->translate('Delete from %s'),
$this->parentNode->getAlias()
);
} else {
$yesMsg = sprintf(
$this->translate('Delete root node "%s"'),
$this->node->getAlias()
);
}
$this->addElement('select', 'confirm', array(
'label' => $this->translate('Are you sure?'),
'required' => true,
'description' => $this->translate(
'Do you really want to delete this node?'
),
'multiOptions' => $this->optionalEnum(array(
'no' => $this->translate('No'),
'yes' => $yesMsg,
'all' => sprintf($this->translate('Delete all occurrences of %s'), $node->getAlias()),
))
));
}
/**
* @param MonitoringBackend $backend
* @return $this
*/
public function setBackend(MonitoringBackend $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 Node $node
* @return $this
*/
public function setNode(Node $node)
{
$this->node = $node;
return $this;
}
/**
* @param BpNode|null $node
* @return $this
*/
public function setParentNode(BpNode $node = null)
{
$this->parentNode = $node;
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);
switch ($this->getValue('confirm')) {
case 'yes':
$changes->deleteNode($this->node, $this->path);
break;
case 'all':
$changes->deleteNode($this->node);
break;
case 'no':
$this->setSuccessMessage($this->translate('Well, maybe next time'));
}
// Trigger session desctruction to make sure it get's stored.
// TODO: figure out why this is necessary, might be an unclean shutdown on redirect
unset($changes);
parent::onSuccess();
}
}

View file

@ -2,42 +2,55 @@
namespace Icinga\Module\Businessprocess\Forms;
use Icinga\Web\Notification;
use Icinga\Web\Request;
use Icinga\Module\Businessprocess\Node;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\Form;
use Icinga\Module\Businessprocess\ProcessChanges;
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\Notification;
use Icinga\Web\Session\SessionNamespace;
class ProcessForm extends Form
class ProcessForm extends QuickForm
{
/** @var MonitoringBackend */
protected $backend;
protected $process;
/** @var BpConfig */
protected $bp;
/** @var BpNode */
protected $node;
protected $objectList = array();
protected $processList = array();
/** @var SessionNamespace */
protected $session;
public function setup()
{
$this->addElement('text', 'name', array(
'label' => $this->translate('Name'),
'required' => true,
'description' => $this->translate(
'This is the unique identifier of this process'
),
));
if ($this->node === null) {
$this->addElement('text', 'name', array(
'label' => $this->translate('Name'),
'required' => true,
'description' => $this->translate(
'This is the unique identifier of this process'
),
));
} else {
$this->addHtml(
'<h2>' . $this->getView()->escape(
sprintf($this->translate('Modify "%s"'), $this->node->getAlias())
) . '</h2>'
);
}
$this->addElement('text', 'alias', array(
'label' => $this->translate('Title'),
'description' => $this->translate(
'Usually this title will be shown for this node. Equals name'
. ' if not given'
. ' if not given'
),
));
@ -67,19 +80,8 @@ class ProcessForm extends Form
'Where to show this process'
),
'multiOptions' => array(
'0' => $this->translate('Subprocess only'),
'1' => $this->translate('Toplevel Process'),
)
));
$this->addElement('multiselect', 'children', array(
'label' => $this->translate('Process components'),
'required' => true,
'size' => 14,
'style' => 'width: 25em;',
'description' => $this->translate(
'Hosts, services or other processes that should be part of this'
. ' business process'
'0' => $this->translate('Subprocess only'),
)
));
@ -90,96 +92,54 @@ class ProcessForm extends Form
)
));
$this->addElement('submit', $this->translate('Store'));
}
public function setBackend($backend)
{
$this->backend = $backend;
$this->fetchObjectList();
$this->fillAvailableChildren();
return $this;
}
protected function fillAvailableChildren()
{
if (empty($this->processList)) {
$children = $this->objectList;
} else {
$children = array(
$this->translate('Other Business Processes') => $this->processList
) + $this->objectList;
}
$this->getElement('children')->setMultiOptions($children);
}
public function setProcess($process)
{
$this->process = $process;
$this->setBackend($process->getBackend());
$this->processList = array();
foreach ($process->getNodes() as $node) {
if ($node instanceof BpNode) {
// TODO: Blacklist parents
$this->processList[(string) $node] = (string) $node; // display name?
if ($node = $this->node) {
if ($node->hasAlias()) {
$this->getElement('alias')->setValue($node->getAlias());
}
$this->getElement('operator')->setValue($node->getOperator());
$this->getElement('display')->setValue($node->getDisplay());
if ($node->hasInfoUrl()) {
$this->getElement('url')->setValue($node->getInfoUrl());
}
}
natsort($this->processList);
$this->fillAvailableChildren();
}
/**
* @param MonitoringBackend $backend
* @return $this
*/
public function setBackend(MonitoringBackend $backend)
{
$this->backend = $backend;
return $this;
}
public function setNode(Node $node)
/**
* @param BpConfig $process
* @return $this
*/
public function setProcess(BpConfig $process)
{
$this->bp = $process;
$this->setBackend($process->getBackend());
return $this;
}
/**
* @param BpNode $node
* @return $this
*/
public function setNode(BpNode $node)
{
$this->node = $node;
$this->setDefaults(array(
'name' => (string) $node,
'alias' => $node->hasAlias() ? $node->getAlias() : '',
'display' => $node->getDisplay(),
'operator' => $node->getOperator(),
'url' => $node->getInfoUrl(),
'children' => array_keys($node->getChildren())
));
$this->getElement('name')->setAttrib('readonly', true);
return $this;
}
protected function fetchObjectList()
{
$this->objectList = array();
$hosts = $this->backend->select()->from('hostStatus', array(
'hostname' => 'host_name',
'in_downtime' => 'host_in_downtime',
'ack' => 'host_acknowledged',
'state' => 'host_state'
))->order('host_name')->getQuery()->fetchAll();
$services = $this->backend->select()->from('serviceStatus', array(
'hostname' => 'host_name',
'service' => 'service_description',
'in_downtime' => 'service_in_downtime',
'ack' => 'service_acknowledged',
'state' => 'service_state'
))->order('host_name')->order('service_description')->getQuery()->fetchAll();
foreach ($hosts as $host) {
$this->objectList[$host->hostname] = array(
$host->hostname . ';Hoststatus' => 'Host Status'
);
}
foreach ($services as $service) {
$this->objectList[$service->hostname][
$service->hostname . ';' . $service->service
] = $service->service;
}
return $this;
}
public function setSession($session)
/**
* @param SessionNamespace $session
* @return $this
*/
public function setSession(SessionNamespace $session)
{
$this->session = $session;
return $this;
@ -187,10 +147,9 @@ class ProcessForm extends Form
public function onSuccess()
{
$changes = ProcessChanges::construct($this->process, $this->session);
$changes = ProcessChanges::construct($this->bp, $this->session);
$modifications = array();
$children = $this->getValue('children');
$alias = $this->getValue('alias');
$operator = $this->getValue('operator');
$display = $this->getValue('display');
@ -201,7 +160,6 @@ class ProcessForm extends Form
if (empty($alias)) {
$alias = null;
}
ksort($children);
// TODO: rename
if ($node = $this->node) {
@ -212,9 +170,6 @@ class ProcessForm extends Form
if ($operator !== $node->getOperator()) {
$modifications['operator'] = $operator;
}
if ($children !== $node->getChildNames()) {
$modifications['childNames'] = $children;
}
if ($url !== $node->getInfoUrl()) {
$modifications['infoUrl'] = $url;
}
@ -225,7 +180,6 @@ class ProcessForm extends Form
$modifications = array(
'display' => $display,
'operator' => $operator,
'childNames' => $children,
'infoUrl' => $url,
'alias' => $alias,
);
@ -241,7 +195,7 @@ class ProcessForm extends Form
Notification::success(
sprintf(
'Process %s has been modified',
$this->process->getName()
$this->bp->getName()
)
);
}

View file

@ -2,56 +2,72 @@
namespace Icinga\Module\Businessprocess\Forms;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
use Icinga\Module\Businessprocess\MonitoredNode;
use Icinga\Module\Businessprocess\Simulation;
use Icinga\Web\Request;
use Icinga\Module\Businessprocess\Web\Form\QuickForm;
class SimulationForm extends QuickForm
{
/** @var MonitoredNode */
protected $node;
/** @var MonitoredNode */
protected $simulatedNode;
/** @var Simulation */
protected $simulation;
public function setup()
{
$states = array(
null => sprintf(
$this->translate('Use current state (%s)'),
$this->translate($this->node->getStateName())
),
'0' => $this->translate('OK'),
'1' => $this->translate('WARNING'),
'2' => $this->translate('CRITICAL'),
'3' => $this->translate('UNKNOWN'),
'99' => $this->translate('PENDING'),
);
$states = $this->enumStateNames();
// TODO: Fetch state from object
if ($this->simulatedNode) {
$states[$this->simulatedNode->getState()] . sprintf(' (%s)', $this->translate('Current simulation'));
$simulatedState = $this->simulatedNode->getState();
$states[$simulatedState] = sprintf(
'%s (%s)',
$this->node->getStateName($simulatedState),
$this->translate('Current simulation')
);
$node = $this->simulatedNode;
$hasSimulation = true;
} else {
$hasSimulation = false;
$node = $this->node;
}
$view = $this->getView();
if ($hasSimulation) {
$title = $this->translate('Modify simulation for %s');
} else {
$title = $this->translate('Add simulation for %s');
}
$this->addHtml(
'<h2>'
. $view->escape(sprintf($title, $node->getAlias()))
. '</h2>'
);
$this->addElement('select', 'state', array(
'label' => $this->translate('State'),
'multiOptions' => $states,
'class' => 'autosubmit',
'value' => $this->simulatedNode ? $node->getState() : null,
));
if (in_array($this->getSentValue('state'), array('0', '99'))) {
return;
}
if ($hasSimulation || ctype_digit($this->getSentValue('state'))) {
$this->addElement('checkbox', 'acknowledged', array(
'label' => $this->translate('Acknowledged'),
'value' => $node->isAcknowledged(),
));
$this->addElement('checkbox', 'acknowledged', array(
'label' => $this->translate('Acknowledged'),
'value' => $node->isAcknowledged(),
));
$this->addElement('checkbox', 'in_downtime', array(
'label' => $this->translate('In downtime'),
'value' => $node->isInDowntime(),
));
$this->addElement('checkbox', 'in_downtime', array(
'label' => $this->translate('In downtime'),
'value' => $node->isInDowntime(),
));
}
$this->setSubmitLabel($this->translate('Apply'));
}
@ -62,14 +78,14 @@ class SimulationForm extends QuickForm
return $this;
}
public function setSimulation($simulation)
public function setSimulation(Simulation $simulation)
{
$this->simulation = $simulation;
$nodeName = (string) $this->node;
if ($simulation->hasNode($nodeName)) {
$name = $this->node->getName();
if ($simulation->hasNode($name)) {
$this->simulatedNode = clone($this->node);
$s = $simulation->getNode($nodeName);
$s = $simulation->getNode($name);
$this->simulatedNode->setState($s->state)
->setAck($s->acknowledged)
->setDowntime($s->in_downtime)
@ -81,7 +97,7 @@ class SimulationForm extends QuickForm
public function onSuccess()
{
$nodeName = (string) $this->node;
$nodeName = $this->node->getName();
if (ctype_digit($this->getValue('state'))) {
$this->notifySuccess($this->translate('Simulation has been set'));
@ -95,5 +111,21 @@ class SimulationForm extends QuickForm
$this->notifySuccess($this->translate('Simulation has been removed'));
}
}
$this->redirectOnSuccess();
}
/**
* @return array
*/
protected function enumStateNames()
{
$states = array(
null => sprintf(
$this->translate('Use current state (%s)'),
$this->translate($this->node->getStateName())
)
) + $this->node->enumStateNames();
return $states;
}
}

View file

@ -1,101 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess\Forms;
use Icinga\Application\Config;
use Icinga\Module\Businessprocess\BusinessProcess;
use Icinga\Web\Form;
use Icinga\Web\Notification;
use Icinga\Web\Request;
class CreateConfigForm extends Form
{
public function setup()
{
$this->addElement('text', 'name', array(
'label' => $this->translate('Name'),
'required' => true,
'description' => $this->translate('This is the unique identifier of this process'),
));
$this->addElement('text', 'title', array(
'label' => $this->translate('Title'),
'description' => $this->translate('Usually this title will be shown for this process. Equals name if not given'),
));
$this->addElement('select', 'backend_name', array(
'label' => $this->translate('Backend'),
'required' => true,
'description' => $this->translate('Icinga Web Monitoring Backend where current object states for this process should be retrieved from'),
'multiOptions' => array(
null => $this->translate('Use current default backend'),
) + $this->listAvailableBackends()
));
$this->addElement('select', 'state_type', array(
'label' => $this->translate('State Type'),
'required' => true,
'description' => $this->translate('Whether this process should be based on Icinga hard or soft states'),
'multiOptions' => array(
'hard' => $this->translate('Use HARD states'),
'soft' => $this->translate('Use SOFT states'),
)
));
$this->addElement('submit', $this->translate('Store'));
}
protected function listAvailableBackends()
{
$keys = array_keys(Config::module('monitoring', 'backends')->toArray());
return array_combine($keys, $keys);
}
public function setBackend($backend)
{
$this->backend = $backend;
return $this;
}
public function setProcessConfig($config)
{
$this->process = $config;
$this->getElement('name')->setValue($config->getName());
if ($config->hasTitle()) {
$this->getElement('title')->setValue($config->getTitle());
}
if ($config->hasBackend()) {
$this->getElement('backend_name')->setValue($config->getBackend()->getName());
}
if ($config->usesSoftStates()) {
$this->getElement('state_type')->setValue('soft');
} else {
$this->getElement('state_type')->setValue('hard');
}
return $this;
}
public function setSession($session)
{
$this->session = $session;
return $this;
}
public function onSuccess()
{
/*
$storage->storeProcess($bp);
$modifications = $this->session->get('modifications', array());
$node = $this->process->getNode($this->getValue('name'));
$node->setChildNames($this->getValue('children'));
$node->setOperator($this->getValue('operator'));
$modifications[$this->process->getName()] = $this->process->toLegacyConfigString();
$this->session->set('modifications', $modifications);
$message = 'Process %s has been modified';
Notification::success(sprintf($message, $this->process->getName()));
*/
}
}

View file

@ -1,135 +1,258 @@
# Icinga Web 2 - Head for multiple monitoring backends.
# Copyright (C) 2015 Icinga Development Team
# Copyright (C) 2016 Icinga Development Team
# This file is distributed under the same license as Businessprocess Module.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Businessprocess Module (2.0.0-beta1)\n"
"Project-Id-Version: Businessprocess Module (2.0.0)\n"
"Report-Msgid-Bugs-To: dev@icinga.org\n"
"POT-Creation-Date: 2015-03-16 06:19+0100\n"
"PO-Revision-Date: 2015-03-16 09:04+0100\n"
"POT-Creation-Date: 2016-12-12 13:32+0100\n"
"PO-Revision-Date: 2016-12-12 13:48+0100\n"
"Last-Translator: Thomas Gelf <thomas@gelf.net>\n"
"Language: de_DE\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.5.4\n"
"Language-Team: \n"
"X-Generator: Poedit 1.8.7.1\n"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:83
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:174
#, php-format
msgid "%d applied simulation(s) have been dropped"
msgstr "%d angewendete Simulation(en) wurde(n) entfernt"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Controller.php:73
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Controller.php:187
#, php-format
msgid "%d pending change(s) have been dropped"
msgstr "%d vorgenommene Änderung(en) wurde(n) verworfen"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:165
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:349
#, php-format
msgid "%s: Configuration"
msgstr "%s: Konfiguration"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:129
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:313
#, php-format
msgid "%s: Source Code"
msgstr "%s: Quellcode"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:124
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:308
#, php-format
msgid "%s: Source Code Differences"
msgstr "%s: Quellcode Unterschiede"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:48
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/ProvidedHook/Director/DataType/BusinessProcess.php:17
msgid "(no process config chosen)"
msgstr "(keine Prozess-Konfiguration gewählt)"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Form/QuickBaseForm.php:113
msgid "- please choose -"
msgstr "- bitte wählen -"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:50
msgid ""
"A slightly more detailed description for this process, about 100-150 "
"characters long"
msgstr ""
"Eine etwas detailliertere Beschreibung dieses Prozesses, etwa 100-150 "
"Zeichen lang"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:53
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:76
msgid "AND"
msgstr "UND"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:42
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:62
msgid "Acknowledged"
msgstr "Bestätigt"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/node/add.phtml:8
msgid "Add new process node"
msgstr "Neuen Knoten hinzufügen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:92
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:86
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TileRenderer.php:91
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TreeRenderer.php:241
msgid "Add"
msgstr "Hinzufügen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:49
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TileRenderer.php:89
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TreeRenderer.php:246
msgid "Add a new business process node"
msgstr "Neuen Business-Prozess hinzufügen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:88
msgid "Add children"
msgstr "Nachfolger hinzufügen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:43
#, php-format
msgid "Add simulation for %s"
msgstr "Simulation für %s hinzufügen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:79
msgid "Add to menu"
msgstr "Zum Menü hinzufügen"
#: /usr/local/icingaweb-modules/businessprocess/configuration.php:50
msgid "Allow to create whole new process configuration (files)"
msgstr "Erlaube das erstellen einer neuen Prozess-Konfiguration (Datei)"
#: /usr/local/icingaweb-modules/businessprocess/configuration.php:54
msgid "Allow to modify process definitions, to add and remove nodes"
msgstr ""
"Erlaubt es Prozessdefinitionen zu modifizieren, sowie Knoten hinzuzufügen "
"und zu entfernen"
#: /usr/local/icingaweb-modules/businessprocess/configuration.php:46
msgid ""
"Allow to see all available processes, regardless of configured restrictions"
msgstr ""
"Erlaubt es, alle verfügbaren Prozesse unabhängig von konfigurierten "
"Restriktionen zu sehen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:96
msgid "Another process"
msgstr "Ein anderer Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:72
msgid "Apply"
msgstr "Anwenden"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/index/index.phtml:8
#, php-format
msgid ""
"As no business process has been defined yet you might want to create a %s or "
"upload an %s."
msgstr ""
"Nachdem noch kein Business-Prozess definiert wurde, möchtest du vermutlich "
"einen %s erstellen oder einen %s hochladen."
#: /usr/local/icingaweb-modules/businessprocess/application/forms/DeleteNodeForm.php:32
msgid "Are you sure?"
msgstr "Bist du sicher?"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:47
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:27
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:56
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:48
msgid "Backend"
msgstr "Backend"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:206
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:384
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Controller.php:128
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Controller.php:139
msgid "Business Process"
msgstr "Business-Prozess"
#: /usr/local/icingaweb-modules/businessprocess/configuration.php:4
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/IndexController.php:13
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:81
#, php-format
msgid "Business Process \"%s\""
msgstr "Businessprozesse \"%s\""
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/IndexController.php:15
msgid "Business Process Overview"
msgstr "Businessprozessübersicht"
#: /usr/local/icingaweb-modules/businessprocess/configuration.php:5
msgid "Business Processes"
msgstr "Business-Prozesse"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:31
msgid "CRITICAL"
msgstr "KRITISCH"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:75
msgid "Config"
msgstr "Konfiguration"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/index/index.phtml:6
msgid "Configure your first business process"
msgstr "Konfiguriere deinen ersten Business-Prozess"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BusinessProcess.php:297
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BusinessProcess.php:316
#, php-format
msgid "Could not retrieve process state: %s"
msgstr "Konnte den Prozess-Status nicht ermitteln: %s"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:214
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:395
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/Dashboard.php:55
msgid "Create"
msgstr "Erstelle"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:21
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/Dashboard.php:56
msgid "Create a new Business Process configuration"
msgstr "Erstelle eine neue Businessprozesskonfiguration"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:37
msgid "Create a new business process"
msgstr "Neuen Business-Prozess erstellen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/DeleteConfigForm.php:18
msgid "Delete this process"
msgstr "Lösche diesen Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:30
msgid "Current simulation"
msgstr "Aktuelle Simulation"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/show.phtml:40
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/show.phtml:51
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:79
msgid "DEG"
msgstr "DEG"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:111
msgid "Delete"
msgstr "Löschen"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TileRenderer/NodeTile.php:159
msgid "Delete this node"
msgstr "Lösche diesen Knoten"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:48
msgid "Description"
msgstr "Beschreibung"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:267
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:279
msgid "Dismiss"
msgstr "Verwerfen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/DeleteNodeForm.php:35
msgid "Do you really want to delete this node"
msgstr "Möchtest du diesen Knoten wirklich löschen"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/source.phtml:6
msgid "Download process configuration"
msgstr "Prozess-Konfiguration herunterladen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:125
msgid "Existing Process"
msgstr "Existierender Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:97
msgid "External process"
msgstr "Externer Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:75
msgid "File"
msgstr "Datei"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Form/QuickForm.php:390
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Form/QuickForm.php:415
msgid "Form has successfully been sent"
msgstr "Das Formular wurde erfolgreich versandt"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/Dashboard.php:47
msgid ""
"From here you can reach all your defined Business Process configurations, "
"create new or modify existing ones"
msgstr ""
"Von hier kannst du alle definierten Businessprozesskonfigurationen "
"erreichen, neue erstellen oder bestehende bearbeiten"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:89
msgid "Fullscreen"
msgstr "Vollbild"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/source.phtml:10
msgid "Highlight changes"
msgstr "Änderungen hervorheben"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:80
msgid ""
"Hosts, services or other processes that should be part of this business "
"process"
msgstr ""
"Hosts, Services oder andere Prozesse welche Teil dieses Business-Prozesses "
"sein sollen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:94
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:135
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:120
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:171
msgid "Host"
msgstr "Host"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:49
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:29
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:121
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:147
msgid "Hosts"
msgstr "Hosts"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:127
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:153
msgid "Hosts that should be part of this business process node"
msgstr "Hosts welche Teil dieses Business-Prozesses sein sollen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:58
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:50
msgid ""
"Icinga Web Monitoring Backend where current object states for this process "
"should be retrieved from"
@ -137,51 +260,65 @@ msgstr ""
"Das Icinga Web Monitoring Backend von welchem die Status-Informationen für "
"diesen Prozess bezogen werden sollen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:46
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:67
msgid "In downtime"
msgstr "In Downtime"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:86
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:81
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:106
msgid "Info URL"
msgstr "Info-URL"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/show.phtml:13
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:61
msgid "Lock"
msgstr "Sperren"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:66
msgid "Lock this process"
msgstr "Sperre diesen Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:50
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:56
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:80
msgid "MIN 1"
msgstr "MIN 1"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:51
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:57
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:81
msgid "MIN 2"
msgstr "MIN 2"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:52
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:58
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:82
msgid "MIN 3"
msgstr "MIN 3"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:53
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:59
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:83
msgid "MIN 4"
msgstr "MIN 4"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:54
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:60
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:84
msgid "MIN 5"
msgstr "MIN 5"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:55
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:61
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:85
msgid "MIN 6"
msgstr "MIN 6"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:56
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:62
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:86
msgid "MIN 7"
msgstr "MIN 7"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:57
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:63
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:87
msgid "MIN 8"
msgstr "MIN 8"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:58
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:64
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:88
msgid "MIN 9"
msgstr "MIN 9"
@ -190,225 +327,359 @@ msgstr "MIN 9"
msgid "Modify process node: %s"
msgstr "Bearbeite Knoten: %s"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BpNode.php:268
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:41
#, php-format
msgid "Modify simulation for %s"
msgstr "Bearbeite die Simulation für %s"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TileRenderer/NodeTile.php:136
msgid "Modify this business process node"
msgstr "Bearbeite diesen Prozessknoten"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TreeRenderer.php:199
msgid "Modify this node"
msgstr "Bearbeite diesen Knoten"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Node.php:350
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:80
msgid "Modify this process"
msgstr "Bearbeite diesen Prozess"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TreeRenderer.php:222
msgid "More information"
msgstr "Weitere Informationen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:31
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:16
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:29
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:55
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:78
msgid "NOT"
msgstr "NICHT"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:32
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:34
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:57
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:32
msgid "Name"
msgstr "Name"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BusinessProcess.php:519
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BpNode.php:276
#, php-format
msgid "Nesting error detected: %s"
msgstr "Verschachtelungsfehler erkannt: %s"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:128
msgid "New Process Node"
msgstr "Neuen Prozess-Knoten hinzufügen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:47
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:164
msgid "Next"
msgstr "Weiter"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:86
#: /usr/local/icingaweb-modules/businessprocess/application/forms/DeleteNodeForm.php:39
msgid "No"
msgstr "Nein"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/Dashboard.php:77
msgid "No Business Process has been defined for you"
msgstr "Es wurde noch kein Business-Prozess für dich definiert"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BusinessProcess.php:693
#, php-format
msgid "No business process nodes for \"%s\" have been defined yet"
msgstr "Es wurden noch keine Business-Prozess Knoten für \"%s\" definiert"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BusinessProcess.php:467
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Controller.php:205
#, php-format
msgid "No such process config: \"%s\""
msgstr "Keine entsprechende Prozesskonfiguration gefunden: \"%s\""
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BusinessProcess.php:575
#, php-format
msgid "Node \"%s\" has been defined twice"
msgstr "Der Knoden \"%s\" wurde doppelt definiert"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:29
msgid "OK"
msgstr "OK"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:131
msgid "Node type"
msgstr "Knotentyp"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:49
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/Dashboard.php:76
msgid "Not available"
msgstr "NIcht verfügbar"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:54
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:77
msgid "OR"
msgstr "ODER"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:45
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:50
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:73
msgid "Operator"
msgstr "Operator"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:109
msgid "Other Business Processes"
msgstr "Andere Business-Prozesse"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:166
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:202
msgid "Other processes that should be part of this business process node"
msgstr "Andere Prozesse welche Teil dieses Business-Prozesses sein sollen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:33
msgid "PENDING"
msgstr "PENDING"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/BusinessProcess.php:538
#, php-format
msgid "Parser waring on %s:%s: %s"
msgstr "Parse-Warnung an %s:%s: %s"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:38
msgid "Plugin output"
msgstr "Plugin-Ausgabe"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:225
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:406
msgid "Process Configuration"
msgstr "Prozess-Konfiguration"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:75
msgid "Process components"
msgstr "Prozess-Komponenten"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:160
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:196
msgid "Process nodes"
msgstr "Prozess-Knoten"
#: /usr/local/icingaweb-modules/businessprocess/configuration.php:3
msgid "Reporting"
msgstr "Reporting"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:95
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:121
msgid "Service"
msgstr "Service"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:146
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:182
msgid "Services"
msgstr "Services"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:152
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:188
msgid "Services that should be part of this business process node"
msgstr "Services welche Teil dieses Business-Prozesses sein sollen"
#: /usr/local/icingaweb-modules/businessprocess/configuration.php:26
msgid "Show all"
msgstr "Alle anzeigen"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/source.phtml:8
msgid "Show source code"
msgstr "Quellcode anzeigen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:86
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TileRenderer/NodeTile.php:151
msgid "Show the business impact of this node by simulating a specific state"
msgstr ""
"Zeige den Business-Impact dieses Knoten durch Simulation eines gewünschten "
"Zustandes"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TileRenderer/NodeTile.php:142
msgid "Show this subtree as a tree"
msgstr "Zeige diesen Teilbaum als eigenen Baum"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Renderer/TreeRenderer.php:212
msgid "Simulate a specific state"
msgstr "Einen bestimmten Zustand simulieren"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:111
msgid "Simulation has been removed"
msgstr "Simulation wurde entfernt"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:89
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:103
msgid "Simulation has been set"
msgstr "Simulation wurde gesended"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:228
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:409
msgid "Source"
msgstr "Quelle"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:26
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:52
msgid "State"
msgstr "Status"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:58
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:36
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:67
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:59
msgid "State Type"
msgstr "Statustyp"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/show.phtml:36
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:68
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:44
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:92
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:261
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:108
msgid "Store"
msgstr "Speichern"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:69
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Form/QuickForm.php:178
msgid "Submit"
msgstr "Absenden"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:76
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:101
msgid "Subprocess only"
msgstr "Nur Sub-Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/upload.phtml:8
msgid "This has not been implemented yet"
msgstr "Das wurde noch nicht implementiert"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:94
msgid "Switch to fullscreen mode"
msgstr "Zum Vollbildmodus wechseln"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:34
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:18
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:32
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:134
msgid "The node type you want to add"
msgstr "Der gewünschte Knotentyp"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:35
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:37
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:60
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:35
msgid "This is the unique identifier of this process"
msgstr "Das ist der eindeutige Identifier dieses Prozesses"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/show.phtml:33
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:257
#, php-format
msgid "This process has %d pending change(s)."
msgstr "Dieser Prozess hat %d ungespeicherte Änderung(en)"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/show.phtml:48
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:276
#, php-format
msgid "This process shows %d simulated state(s)."
msgstr "Dieser Prozess zeigt %d simulierte Zustände"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:39
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:22
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:37
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:28
msgid "Tiles"
msgstr "Kacheln"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:40
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:42
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:65
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:40
msgid "Title"
msgstr "Titel"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:70
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:75
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:100
msgid "Toplevel Process"
msgstr "Toplevel-Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:32
msgid "UNKNOWN"
msgstr "UNBEKANNT"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:37
msgid "Tree"
msgstr "Baum"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:88
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:83
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:108
msgid "URL pointing to more information about this node"
msgstr "URL zu mehr Informationen über diesen Knoten"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/process/show.phtml:10
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:49
msgid "Unlock"
msgstr "Entsperren"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/ActionBar.php:54
msgid "Unlock this process"
msgstr "Entsperre diesen Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:217
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:398
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:111
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/Dashboard.php:64
msgid "Upload"
msgstr "Upload"
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:35
#: /usr/local/icingaweb-modules/businessprocess/application/controllers/ProcessController.php:56
msgid "Upload a business process config file"
msgstr "Lade eine Business-Prozess Konfigurationsdatei hoch"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:64
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:40
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/Dashboard.php:65
msgid "Upload an existing Business Process configuration"
msgstr "Lade eine Business-Prozess Konfigurationsdatei hoch"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:74
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:65
msgid "Use HARD states"
msgstr "HARD-States benutzen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:65
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:41
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:73
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:66
msgid "Use SOFT states"
msgstr "SOFT-States benutzen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:31
msgid "Use current default backend"
msgstr "Aktuelles Standard-Backend benutzen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:124
#, php-format
msgid "Use current state (%s)"
msgstr "Aktuellen Status benutzen (%s)"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:28
msgid "Use current state"
msgstr "Aktuellen Status benutzen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:53
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:62
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:54
msgid "Use the configured default backend"
msgstr "Benutze das konfigurierte Standard-Backend"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:39
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:44
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:67
msgid ""
"Usually this title will be shown for this node. Equals name if not given"
msgstr ""
"Für gewöhnlich wird dieser Titel für diesen Knoten angezeigt. Entspricht dem "
"Namen, wenn nicht angegeben"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:41
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:23
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:42
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:42
msgid ""
"Usually this title will be shown for this process. Equals name if not given"
msgstr ""
"Für gewöhnlich wird dieser Titel für diesen Prozess angezeigt. Entspricht "
"dem Namen, wenn nicht angegeben"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:63
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:69
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:93
msgid "Visualization"
msgstr "Darstellung"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/SimulationForm.php:30
msgid "WARNING"
msgstr "WARNUNG"
#: /usr/local/icingaweb-modules/businessprocess/library/Businessprocess/Web/Component/Dashboard.php:42
msgid "Welcome to your Business Process Overview"
msgstr "Willkommen zur Übersicht deiner Business-Prozesse"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/warnings.phtml:2
msgid "Warnings"
msgstr "Warnungen"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:66
#: /usr/local/icingaweb-modules/businessprocess/application/forms/ProcessForm.php:72
#: /usr/local/icingaweb-modules/businessprocess/application/forms/AddNodeForm.php:96
msgid "Where to show this process"
msgstr "Wo soll dieser Prozess angezeigt werden"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:61
#: /usr/local/icingaweb-modules/businessprocess/application/forms/_CreateConfigForm.php:38
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:70
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpUploadForm.php:62
msgid "Whether this process should be based on Icinga hard or soft states"
msgstr "Ob dieser Prozess auf Icinga's hard- oder soft-states basieren soll"
msgstr "Ob dieser Prozess auf Icinga's Hard- oder Softstates basieren soll"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/index/index.phtml:10
msgid "existing one"
msgstr "einen existierenden"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:82
msgid "Whether this process should be linked in the main Icinga Web 2 menu"
msgstr "Ob dieser Prozess ins Icinga Web 2 Hauptmenü verlinkt werden soll"
#: /usr/local/icingaweb-modules/businessprocess/application/views/scripts/index/index.phtml:9
msgid "new business process"
msgstr "neuen Business-Prozess"
#: /usr/local/icingaweb-modules/businessprocess/application/forms/BpConfigForm.php:85
#: /usr/local/icingaweb-modules/businessprocess/application/forms/DeleteNodeForm.php:40
msgid "Yes"
msgstr "Ja"
#~ msgid "Show"
#~ msgstr "Zeige"
#~ msgid ""
#~ "As no business process has been defined yet you might want to create a %s "
#~ "or upload an %s."
#~ msgstr ""
#~ "Nachdem noch kein Business-Prozess definiert wurde, möchtest du "
#~ "vermutlich einen %s erstellen oder einen %s hochladen."
#~ msgid "CRITICAL"
#~ msgstr "KRITISCH"
#~ msgid "Configure your first business process"
#~ msgstr "Konfiguriere deinen ersten Business-Prozess"
#~ msgid "OK"
#~ msgstr "OK"
#~ msgid "PENDING"
#~ msgstr "PENDING"
#~ msgid "Parser waring on %s:%s: %s"
#~ msgstr "Parse-Warnung an %s:%s: %s"
#~ msgid "Plugin output"
#~ msgstr "Plugin-Ausgabe"
#~ msgid "Reporting"
#~ msgstr "Reporting"
#~ msgid "This has not been implemented yet"
#~ msgstr "Das wurde noch nicht implementiert"
#~ msgid "UNKNOWN"
#~ msgstr "UNBEKANNT"
#~ msgid "Use current default backend"
#~ msgstr "Aktuelles Standard-Backend benutzen"
#~ msgid "WARNING"
#~ msgstr "WARNUNG"
#~ msgid "Warnings"
#~ msgstr "Warnungen"
#~ msgid "min"
#~ msgstr "min"

View file

@ -0,0 +1,15 @@
<?php
// Avoid complaints about missing namespace and invalid class name
// @codingStandardsIgnoreStart
class Zend_View_Helper_FormSimpleNote extends Zend_View_Helper_FormElement
{
// @codingStandardsIgnoreEnd
public function formSimpleNote($name, $value = null)
{
$info = $this->_getInfo($name, $value);
extract($info); // name, value, attribs, options, listsep, disable
return $value;
}
}

View file

@ -1,15 +1,24 @@
<?php
/**
* @deprecated
* @codingStandardsIgnoreStart
*/
class Zend_View_Helper_RenderStateBadges extends Zend_View_Helper_Abstract
{
// @codingStandardsIgnoreEnd
public function renderStateBadges($summary)
{
$html = '';
foreach ($summary as $state => $cnt) {
if ($cnt === 0) continue;
if ($state === 'OK') continue;
if ($state === 'UP') continue;
if ($cnt === 0
|| $state === 'OK'
|| $state === 'UP'
) {
continue;
}
$html .= '<span class="badge badge-' . strtolower($state)
. '" title="' . mt('monitoring', $state) . '">'
. $cnt . '</span>';

View file

@ -0,0 +1,2 @@
<?= $this->controls->render() ?>
<?= $this->content->render() ?>

View file

@ -1,9 +0,0 @@
<?php if ($this->bp->isEditMode()): ?>
<?php if ($this->bp->hasBeenChanged()): ?>
<a href="<?= $this->url()->without('edit') ?>" title="<?= $this->escape('Store modifications') ?>"><?= $this->icon('ok') ?></a>
<?php endif ?>
<a href="<?= $this->url()->without('edit') ?>" title="<?= $this->escape('Dismiss modifications') ?>"><?= $this->icon('cancel') ?></a>
<?php else: ?>
<a href="<?= $this->url()->with('edit', true) ?>" title="<?= $this->escape('Modify this process') ?>"><?= $this->icon('wrench') ?></a>
<?php endif ?>

View file

@ -1,12 +0,0 @@
<div class="controls">
<?= $this->tabs ?>
</div>
<div class="content">
<h1><?= $this->translate('Configure your first business process') ?></h1>
<p><?= sprintf (
$this->translate('As no business process has been defined yet you might want to create a %s or upload an %s.'),
$this->qlink($this->translate('new business process'), 'businessprocess/process/create'),
$this->qlink($this->translate('existing one'), 'businessprocess/process/upload')
) ?></p>
</div>

View file

@ -1,10 +0,0 @@
<?php
use Icinga\Module\Businessprocess\HostNode;
use Icinga\Module\Businessprocess\ServiceNode;
use Icinga\Module\Businessprocess\BpNode;
?><div class="content">
<h1><?= $this->translate('Add new process node') ?></h1>
<?= $this->form ?>
</div>

View file

@ -1,15 +0,0 @@
<?php
use Icinga\Module\Businessprocess\HostNode;
use Icinga\Module\Businessprocess\ServiceNode;
use Icinga\Module\Businessprocess\BpNode;
?><div class="content">
<h1><?= $this->escape(
sprintf(
$this->translate('Modify process node: %s'),
$node
)
) ?></h1>
<?= $this->form ?>
</div>

View file

@ -1 +0,0 @@
__CLOSEME__

View file

@ -1,8 +0,0 @@
<!--<div class="controls">
<?= $this->tabs ?>
</div>-->
<div class="content">
<h1>BI Simulation: <?= $this->escape(preg_replace('/;/', ' - ', $this->node)) ?></h1>
<?= $this->form ?>
</div>

View file

@ -1,16 +0,0 @@
<div class="controls">
<?= $this->tabs ?>
<h1><?= $this->escape($this->title) ?>
<a href="<?= $this->url('businessprocess/process/source', array(
'config' => $this->configName
)) ?>" title="<?= $this->escape('Show configuration source') ?>"><?= $this->icon('doc-text') ?></a>
</h1>
</div>
<div class="content">
<?= $this->form ?>
<div data-base-target="_main">
<?= $this->deleteForm ?>
</div>
</div>

View file

@ -1,9 +0,0 @@
<div class="controls">
<?= $this->tabs ?>
<h1><?= $this->escape($this->title) ?></h1>
</div>
<div class="content">
<?= $this->form ?>
</div>

View file

@ -1,94 +0,0 @@
<?php
$months = array(
'Jänner',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember',
);
?><table style="width: 100%;">
<tr>
<th style="width: 10%;">&nbsp;</th>
<? for ($i = 1; $i <= 12; $i++): ?>
<th style="width: 7.5%; border: 1px solid black;"><?= $months[$i - 1] ?></th>
<? endfor ?>
</tr>
</table>
<div style="overflow: auto">
<table>
<tr>
<? for ($i = 1; $i <= 12; $i++): ?>
<td style="border-right: 1px solid black;"><div style="width: 600px; height: 1px; overflow: hidden;">&nbsp;</div><?= $months[$i - 1] ?></td>
<? endfor ?>
</tr>
</table>
</div>
<div style="overflow: auto; ">
<?php
function stateColor($state)
{
switch($state) {
case 0:
$color = '#0f0';
break;
case 1:
$color = 'orange';
break;
case 2:
$color = '#f00';
break;
default: // und case 3
$color = '#ccc';
}
return $color;
}
$next_color = null;
$color = null;
$start = mktime(0, 0, 0, 0, 0, (int) date('Y'));
$current_offset = $start;
$htm = '';
$cnt = 0;
$last_host = null;
$last_service = null;
foreach ($this->history as $entry) {
if ($entry->hostname !== $last_host || $entry->service !== $last_service) {
echo '<span style="clear: both;" />' . "\n";
}
$cnt++;
if ($cnt > 10000) break;
$duration = $entry->timestamp - $current_offset;
if ($next_color === null) {
$color = stateColor($entry->last_state);
} else {
$color = $next_color;
}
$next_color = stateColor($entry->state);
if ($entry->state == 0) {
$offset = ceil($duration / 3600 / 6);
} else {
$offset = floor($duration / 3600 / 6);
}
echo '<div style="overflow: hidden; height: 10px; float: left; width: ' . $offset . 'px; background-color:' . $color . ';">&nbsp;</div>';
$current_offset += $duration;
$last_host = $entry->hostname;
$last_service = $entry->service;
}
?></div>

View file

@ -1,71 +0,0 @@
<?php
use Icinga\Module\Businessprocess\BusinessProcess;
?>
<?php if (! $this->compact): ?>
<div class="controls">
<?= $this->tabs ?>
<h1><form method="post" action="<?= $this->url()->without('node')->without('unlocked') ?>">
<?= $this->formSelect('config', $this->configName, array('class' => 'autosubmit'), $this->processList) ?>
</form>
<a href="<?= $this->url()->with('mode', 'toplevel')->without('unlocked') ?>" title="<?= $this->escape('Switch to toplevel view') ?>"><?= $this->icon('dashboard') ?></a>
<?php if ($this->bpconfig->isLocked()): ?>
<a href="<?= $this->url()->with('unlocked', true) ?>" title="<?= $this->escape($this->translate('Unlock this process')) ?>"><?= $this->icon('lock') ?></a>
<?php else: ?>
<?php if (! $this->bpconfig->isEmpty()): ?>
<a href="<?= $this->url()->without('unlocked') ?>" style="color: red" title="<?= $this->escape($this->translate('Lock this process')) ?>"><?= $this->icon('lock-open') ?></a>
<?php endif ?>
<a href="<?= $this->url('businessprocess/process/config', array('config' => $this->configName)) ?>" title="<?= $this->escape('Modify this process') ?>" data-base-target="_next"><?= $this->icon('wrench') ?></a>
<?php endif ?>
<a href="<?= $this->url('businessprocess/process/create') ?>" title="<?= $this->escape('Create a new business process configuration') ?>"><?= $this->icon('plus') ?></a>
</h1>
</div>
<?php endif ?>
<div class="content<?= $this->compact ? ' compact' : '' ?>" data-base-target="_next">
<?php if (! $this->bpconfig->isLocked()): ?>
<?= $this->qlink('Add new node', 'businessprocess/node/add', array('config' => $this->configName)) ?>
<?php endif ?>
<?php if ($this->bpconfig->hasErrors() || $this->bpconfig->hasChanges() || $this->bpconfig->hasSimulations()): ?>
<ul class="error">
<?php foreach ($this->bpconfig->getErrors() as $error): ?>
<li><?= $this->escape($error) ?></li>
<?php endforeach ?>
<?php if ($this->bpconfig->hasChanges()): ?>
<li><?= sprintf(
$this->translate('This process has %d pending change(s).'),
$this->bpconfig->countChanges()
) ?> <?= $this->qlink(
$this->translate('Store'),
'businessprocess/process/config',
array('config' => $this->configName)
) ?> <?= $this->qlink(
$this->translate('Dismiss'),
$this->url()->with('dismissChanges', true),
null
) ?></li>
<?php endif ?>
<?php if ($this->bpconfig->hasSimulations()): ?>
<li><?= sprintf(
$this->translate('This process shows %d simulated state(s).'),
$this->bpconfig->countSimulations()
) ?> <?= $this->qlink(
$this->translate('Dismiss'),
$this->url()->with('dismissSimulations', true),
null
) ?></li>
<?php endif ?>
</ul>
<?php endif ?>
<div class="bp">
<?= $this->bp->renderHtml($this) ?>
<?php if (! $this->bpconfig->isLocked()): ?>
<?php if ($this->bp instanceof BusinessProcess): /* do not render when showing subtree */ ?>
<?= $this->bp->renderUnbound($this) ?>
<?php endif ?>
<?php endif ?>
</div>
<?= $this->render('warnings.phtml') ?>
</div>

View file

@ -1,21 +1,9 @@
<div class="controls">
<?= $this->tabs ?>
<h1><?= $this->escape($this->title) ?>
<a href="<?= $this->url('businessprocess/process/download', array(
'config' => $this->configName
)) ?>" target="_self" title="<?= $this->escape($this->translate('Download process configuration')) ?>"><?= $this->icon('download') ?></a>
<?php if ($this->showDiff): ?>
<a href="<?= $this->url()->without('showDiff') ?>" title="<?= $this->escape($this->translate('Show source code')) ?>"><?= $this->icon('doc-text') ?></a>
<?php else: ?>
<a href="<?= $this->url()->with('showDiff', true) ?>" title="<?= $this->escape($this->translate('Highlight changes')) ?>"><?= $this->icon('flapping') ?></a>
<?php endif ?>
</h1>
</div>
<?= $this->controls->render() ?>
<div class="content">
<?php if ($this->showDiff): ?>
<div class="diff">
<?= $this->diff->renderHtml() ?>
<?= $this->diff->render() ?>
</div>
<?php else: ?>
<table class="sourcecode">

View file

@ -1,47 +0,0 @@
<?php
use Icinga\Module\Businessprocess\ImportedNode;
use Icinga\Module\Businessprocess\BpNode;
$count = $this->bp->countChildren();
$howMany = 'normal';
if ($count < 20) {
$howMany = 'few';
} elseif ($count > 50) {
$howMany = 'many';
}
?>
<?php if (! $this->compact): ?>
<div class="controls">
<?= $this->tabs ?>
<h1><form method="post" action="<?= $this->url()->without('node')->without('unlocked') ?>">
<?= $this->formSelect('config', $this->configName, array('class' => 'autosubmit'), $this->processList) ?>
</form>
<a href="<?= $this->url()->without('mode') ?>" title="<?= $this->escape('Switch to tree view') ?>" style="float: right"><?= $this->icon('sitemap') ?></a>
</h1>
</div>
<?php endif ?>
<div class="content<?= $this->compact ? ' compact' : '' ?>" data-base-target="_next">
<div class="toplevel <?= $howMany ?>" data-base-target="_next">
<?php foreach ($this->bp->getChildren() as $name => $node): ?>
<div class="<?= strtolower($node->getStateName()) ?><?= $node->isHandled() ? ' handled' : '' ?>">
<?php if ($node instanceof ImportedNode): ?>
<a href="<?= $this->url('businessprocess/process/show', array('config' => $node->getConfigName(), 'node' => $name)) ?>">
<?php else: ?>
<a href="<?= $this->url('businessprocess/process/show', array('config' => $this->configName, 'node' => $name)) ?>">
<?php endif ?>
<?= $this->escape($node->getAlias()) ?><?php
if ($node instanceof BpNode) {
echo $this->renderStateBadges($node->getStateSummary());
}
?></a>
</div>
<?php endforeach ?>
</div>
<?= $this->render('warnings.phtml') ?>
</div>

View file

@ -1,11 +0,0 @@
<div class="controls">
<?= $this->tabs ?>
<h1><?= $this->escape($this->title) ?></h1>
</div>
<div class="content">
<ul class="error">
<li><?= $this->translate('This has not been implemented yet') ?></li>
</ul>
</div>

View file

@ -1,6 +0,0 @@
<?php if ($this->bp->isSimulationMode()): ?>
<a href="<?= $this->url()->without('simulation') ?>" title="<?= $this->escape('Switch to live mode') ?>"><?= $this->icon('globe') ?></a>
<?php else: ?>
<a href="<?= $this->url()->with('simulation', true) ?>" title="<?= $this->escape('Switch to simulation mode') ?>"><?= $this->icon('magic') ?></a>
<?php endif ?>

View file

@ -1,6 +0,0 @@
<?php if ($this->warnings): ?>
<h2><?= $this->translate('Warnings') ?></h2>
<?php foreach ($this->warnings as $warning): ?>
<?= $this->escape($warning) ?><br />
<?php endforeach ?>
<?php endif ?>

View file

@ -1,7 +1,56 @@
<?php
$section = $this->menuSection(N_('Overview'))
->add($this->translate('Business Processes'))
->setPriority(45)
->setUrl('businessprocess');
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
/** @var \Icinga\Application\Modules\Module $this */
$section = $this->menuSection(N_('Business Processes'), array(
'url' => 'businessprocess',
'icon' => 'sitemap',
'priority' => 46
));
try {
$storage = new LegacyStorage(
$this->getConfig()->getSection('global')
);
$prio = 0;
foreach ($storage->listProcessNames() as $name) {
$prio++;
$meta = $storage->loadMetadata($name);
if ($meta->get('AddToMenu') === 'no') {
continue;
}
if ($prio > 5) {
$section->add(N_('Show all'), array(
'url' => 'businessprocess',
'priority' => $prio
));
break;
}
$section->add($meta->getTitle(), array(
'url' => 'businessprocess/process/show',
'urlParameters' => array('config' => $name),
'priority' => $prio
));
}
} catch (Exception $e) {
// Well... there is not much we could do here
}
$this->providePermission(
'businessprocess/showall',
$this->translate('Allow to see all available processes, regardless of configured restrictions')
);
$this->providePermission(
'businessprocess/create',
$this->translate('Allow to create whole new process configuration (files)')
);
$this->providePermission(
'businessprocess/modify',
$this->translate('Allow to modify process definitions, to add and remove nodes')
);

View file

@ -2,12 +2,14 @@
namespace Icinga\Module\Businessprocess;
use Icinga\Application\Benchmark;
use Icinga\Exception\IcingaException;
use Icinga\Exception\NotFoundError;
use Icinga\Module\Businessprocess\Exception\NestingError;
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
use Icinga\Data\Filter\Filter;
use Exception;
class BusinessProcess
class BpConfig
{
const SOFT_STATE = 0;
@ -27,6 +29,9 @@ class BusinessProcess
*/
protected $backend;
/** @var Metadata */
protected $metadata;
/**
* Business process name
*
@ -76,13 +81,6 @@ class BusinessProcess
*/
protected $root_nodes = array();
/**
* All check names { 'hostA;ping' => true, ... }
*
* @var array
*/
protected $all_checks = array();
/**
* All host names { 'hostA' => true, ... }
*
@ -90,6 +88,11 @@ class BusinessProcess
*/
protected $hosts = array();
/** @var bool Whether catchable errors should be thrown nonetheless */
protected $throwErrors = false;
protected $loopDetection = array();
/**
* Applied state simulation
*
@ -97,25 +100,51 @@ class BusinessProcess
*/
protected $simulation;
/**
* Whether we are in edit mode
*
* @var boolean
*/
protected $editMode = false;
protected $locked = true;
protected $changeCount = 0;
protected $simulationCount = 0;
/** @var ProcessChanges */
protected $appliedChanges;
public function __construct()
{
}
/**
* Retrieve metadata for this configuration
*
* @return Metadata
*/
public function getMetadata()
{
if ($this->metadata === null) {
$this->metadata = new Metadata($this->name);
}
return $this->metadata;
}
/**
* Set metadata
*
* @param Metadata $metadata
*
* @return $this
*/
public function setMetadata(Metadata $metadata)
{
$this->metadata = $metadata;
return $this;
}
/**
* Apply pending process changes
*
* @param ProcessChanges $changes
*
* @return $this
*/
public function applyChanges(ProcessChanges $changes)
{
$cnt = 0;
@ -130,6 +159,13 @@ class BusinessProcess
return $this;
}
/**
* Apply a state simulation
*
* @param Simulation $simulation
*
* @return $this
*/
public function applySimulation(Simulation $simulation)
{
$cnt = 0;
@ -147,28 +183,57 @@ class BusinessProcess
}
$this->simulationCount = $cnt;
return $this;
}
/**
* Number of applied changes
*
* @return int
*/
public function countChanges()
{
return $this->changeCount;
}
/**
* Whether changes have been applied to this configuration
*
* @return int
*/
public function hasChanges()
{
return $this->countChanges() > 0;
}
/**
* @param $name
*
* @return $this
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getHtmlId()
{
return 'businessprocess-' . preg_replace('/[\r\n\t\s]/', '_', $this->getName());
}
public function setTitle($title)
{
$this->title = $title;
@ -177,28 +242,22 @@ class BusinessProcess
public function getTitle()
{
return $this->title ?: $this->getName();
return $this->getMetadata()->getTitle();
}
public function hasTitle()
{
return $this->title !== null;
}
public function setBackendName($name)
{
$this->backendName = $name;
return $this;
return $this->getMetadata()->has('Title');
}
public function getBackendName()
{
return $this->backendName;
return $this->getMetadata()->get('Backend');
}
public function hasBackendName()
{
return $this->backendName !== null;
return $this->getMetadata()->has('Backend');
}
public function setBackend(MonitoringBackend $backend)
@ -210,7 +269,7 @@ class BusinessProcess
public function getBackend()
{
if ($this->backend === null) {
$this->backend = MonitoringBackend::createBackend(
$this->backend = MonitoringBackend::instance(
$this->getBackendName()
);
}
@ -228,22 +287,6 @@ class BusinessProcess
return false;
}
public function isLocked()
{
return $this->locked;
}
public function lock($lock = true)
{
$this->locked = (bool) $lock;
return $this;
}
public function unlock()
{
return $this->lock(false);
}
public function hasSimulations()
{
return $this->countSimulations() > 0;
@ -254,17 +297,6 @@ class BusinessProcess
return $this->simulationCount;
}
public function setEditMode($mode = true)
{
$this->editMode = (bool) $mode;
return $this;
}
public function isEditMode()
{
return $this->editMode;
}
public function clearAppliedChanges()
{
if ($this->appliedChanges !== null) {
@ -292,7 +324,7 @@ class BusinessProcess
public function usesHardStates()
{
$this->state_type === self::HARD_STATE;
return $this->state_type === self::HARD_STATE;
}
public function addRootNode($name)
@ -315,122 +347,38 @@ class BusinessProcess
return array_key_exists($name, $this->root_nodes);
}
public function retrieveStatesFromBackend()
{
try {
$this->reallyRetrieveStatesFromBackend();
} catch (Exception $e) {
$this->error(
$this->translate('Could not retrieve process state: %s'),
$e->getMessage()
);
}
}
public function reallyRetrieveStatesFromBackend()
{
Benchmark::measure('Retrieving states for business process ' . $this->getName());
$backend = $this->getBackend();
// TODO: Split apart, create a dedicated function.
// Separate "parse-logic" from "retrieve-state-logic"
// Allow DB-based backend
// Use IcingaWeb2 Multi-Backend-Support
$check_results = array();
$hostFilter = array_keys($this->hosts);
if ($this->state_type === self::HARD_STATE) {
$hostStateColumn = 'host_hard_state';
$hostStateChangeColumn = 'host_last_hard_state_change';
$serviceStateColumn = 'service_hard_state';
$serviceStateChangeColumn = 'service_last_hard_state_change';
} else {
$hostStateColumn = 'host_state';
$hostStateChangeColumn = 'host_last_state_change';
$serviceStateColumn = 'service_state';
$serviceStateChangeColumn = 'service_last_state_change';
}
$filter = Filter::matchAny();
foreach ($hostFilter as $host) {
$filter->addFilter(Filter::where('host_name', $host));
}
if ($filter->isEmpty()) {
return $this;
}
$hostStatus = $backend->select()->from('hostStatus', array(
'hostname' => 'host_name',
'last_state_change' => $hostStateChangeColumn,
'in_downtime' => 'host_in_downtime',
'ack' => 'host_acknowledged',
'state' => $hostStateColumn
))->applyFilter($filter)->getQuery()->fetchAll();
$serviceStatus = $backend->select()->from('serviceStatus', array(
'hostname' => 'host_name',
'service' => 'service_description',
'last_state_change' => $serviceStateChangeColumn,
'in_downtime' => 'service_in_downtime',
'ack' => 'service_acknowledged',
'state' => $serviceStateColumn
))->applyFilter($filter)->getQuery()->fetchAll();
foreach ($serviceStatus as $row) {
$this->handleDbRow($row);
}
foreach ($hostStatus as $row) {
$this->handleDbRow($row);
}
ksort($this->root_nodes);
Benchmark::measure('Got states for business process ' . $this->getName());
return $this;
}
protected function handleDbRow($row)
{
$key = $row->hostname;
if (property_exists($row, 'service')) {
$key .= ';' . $row->service;
} else {
$key .= ';Hoststatus';
}
// We fetch more states than we need, so skip unknown ones
if (! $this->hasNode($key)) return;
$node = $this->getNode($key);
if ($row->state !== null) {
$node->setState($row->state)->setMissing(false);
}
if ($row->last_state_change !== null) {
$node->setLastStateChange($row->last_state_change);
}
if ((int) $row->in_downtime === 1) {
$node->setDowntime(true);
}
if ((int) $row->ack === 1) {
$node->setAck(true);
}
}
/**
* @return BpNode[]
*/
public function getChildren()
{
return $this->getRootNodes();
}
/**
* @return int
*/
public function countChildren()
{
return count($this->root_nodes);
}
/**
* @return BpNode[]
*/
public function getRootNodes()
{
ksort($this->root_nodes);
return $this->root_nodes;
}
public function listRootNodes()
{
$names = array_keys($this->root_nodes);
sort($names);
return $names;
}
public function getNodes()
{
return $this->nodes;
@ -441,6 +389,11 @@ class BusinessProcess
return array_key_exists($name, $this->nodes);
}
public function hasRootNode($name)
{
return array_key_exists($name, $this->root_nodes);
}
public function createService($host, $service)
{
$node = new ServiceNode(
@ -463,13 +416,53 @@ class BusinessProcess
return $node;
}
public function createImportedNode($config, $name)
public function listInvolvedHostNames()
{
$node = new ImportedNode($this, (object) array('name' => $name, 'configName' => $config));
$this->nodes[$name] = $node;
return array_keys($this->hosts);
}
/**
* Create and attach a new process (BpNode)
*
* @param string $name Process name
* @param string $operator Operator (defaults to &)
*
* @return BpNode
*/
public function createBp($name, $operator = '&')
{
$node = new BpNode($this, (object) array(
'name' => $name,
'operator' => $operator,
'child_names' => array(),
));
$this->addNode($name, $node);
return $node;
}
public function createMissingBp($name)
{
return $this->createBp($name)->setMissing();
}
public function createImportedNode($config, $name = null)
{
$params = (object) array('configName' => $config);
if ($name !== null) {
$params->node = $name;
}
$node = new ImportedNode($this, $params);
$this->nodes[$node->getName()] = $node;
return $node;
}
/**
* @param $name
* @return Node
* @throws Exception
*/
public function getNode($name)
{
if (array_key_exists($name, $this->nodes)) {
@ -482,7 +475,12 @@ class BusinessProcess
if ($pos !== false) {
$host = substr($name, 0, $pos);
$service = substr($name, $pos + 1);
return $this->createService($host, $service);
// TODO: deactivated, this scares me, test it
if ($service === 'Hoststatus') {
return $this->createHost($host);
} else {
return $this->createService($host, $service);
}
}
throw new Exception(
@ -490,13 +488,55 @@ class BusinessProcess
);
}
public function addObjectName($name)
/**
* @param $name
* @return BpNode
*
* @throws NotFoundError
*/
public function getBpNode($name)
{
$this->all_checks[$name] = 1;
if ($this->hasBpNode($name)) {
return $this->nodes[$name];
} else {
throw new NotFoundError('Trying to access a missing business process node "%s"', $name);
}
}
/**
* @param $name
*
* @return bool
*/
public function hasBpNode($name)
{
return array_key_exists($name, $this->nodes)
&& $this->nodes[$name] instanceof BpNode;
}
/**
* Set the state for a specific node
*
* @param string $name Node name
* @param int $state Desired state
*
* @return $this
*/
public function setNodeState($name, $state)
{
$this->getNode($name)->setState($state);
return $this;
}
public function addNode($name, Node $node)
/**
* Add the given node to the given BpNode
*
* @param $name
* @param BpNode $node
*
* @return $this
*/
public function addNode($name, BpNode $node)
{
if (array_key_exists($name, $this->nodes)) {
$this->warn(
@ -523,16 +563,53 @@ class BusinessProcess
return $this;
}
public function listBpNodes()
/**
* Remove all occurrences of a specific node by name
*
* @param $name
*/
public function removeNode($name)
{
unset($this->nodes[$name]);
if (array_key_exists($name, $this->root_nodes)) {
unset($this->root_nodes[$name]);
}
foreach ($this->getBpNodes() as $node) {
if ($node->hasChild($name)) {
$node->removeChild($name);
}
}
}
/**
* Get all business process nodes
*
* @return BpNode[]
*/
public function getBpNodes()
{
$nodes = array();
foreach ($this->nodes as $node) {
if (! $node instanceof BpNode) {
continue;
if ($node instanceof BpNode) {
$nodes[$node->getName()] = $node;
}
}
$name = (string) $node;
return $nodes;
}
/**
* List all business process node names
*
* @return array
*/
public function listBpNodes()
{
$nodes = array();
foreach ($this->getBpNodes() as $name => $node) {
$alias = $node->getAlias();
$nodes[$name] = $name === $alias ? $name : sprintf('%s (%s)', $alias, $node);
}
@ -541,42 +618,57 @@ class BusinessProcess
return $nodes;
}
/**
* All business process nodes defined in this config but not
* assigned to any parent
*
* @return BpNode[]
*/
public function getUnboundNodes()
{
$nodes = array();
foreach ($this->nodes as $node) {
if (! $node instanceof BpNode) {
continue;
}
foreach ($this->getBpNodes() as $name => $node) {
if ($node->hasParents()) {
continue;
}
if ($node->getDisplay() === 0) {
$nodes[(string) $node] = $node;
$nodes[$name] = $node;
}
}
return $nodes;
}
/**
* @return bool
*/
public function hasWarnings()
{
return ! empty($this->warnings);
}
/**
* @return array
*/
public function getWarnings()
{
return $this->warnings;
}
/**
* @return bool
*/
public function hasErrors()
{
return ! empty($this->errors) || $this->isEmpty();
}
/**
* @return array
*/
public function getErrors()
{
$errors = $this->errors;
@ -591,104 +683,103 @@ class BusinessProcess
return $errors;
}
protected function translate($msg)
/**
* Translation helper
*
* @param $msg
*
* @return mixed|string
*/
public function translate($msg)
{
return mt('businessprocess', $msg);
}
/**
* Add a message to our warning stack
*
* @param $msg
*/
protected function warn($msg)
{
$args = func_get_args();
array_shift($args);
if (isset($this->parsing_line_number)) {
$this->warnings[] = sprintf(
$this->translate('Parser waring on %s:%s: %s'),
$this->filename,
$this->parsing_line_number,
vsprintf($msg, $args)
);
} else {
$this->warnings[] = vsprintf($msg, $args);
}
$this->warnings[] = vsprintf($msg, $args);
}
protected function error($msg)
/**
* @param string $msg,...
*
* @return $this
*
* @throws IcingaException
*/
public function addError($msg)
{
$args = func_get_args();
array_shift($args);
$this->errors[] = vsprintf($msg, $args);
$msg = vsprintf($msg, $args);
if ($this->throwErrors) {
throw new IcingaException($msg);
}
$this->errors[] = $msg;
return $this;
}
public function toLegacyConfigString()
/**
* Decide whether errors should be thrown or collected
*
* @param bool $throw
*
* @return $this
*/
public function throwErrors($throw = true)
{
$settings = array();
if ($this->hasTitle()) {
$settings['Title'] = $this->getTitle();
}
// TODO: backendName?
if ($this->backend) {
$settings['Backend'] = $this->backend->getName();
}
$settings['Statetype'] = $this->usesSoftStates() ? 'soft' : 'hard';
if (false) {
$settings['SLA Hosts'] = implode(', ', array());
}
$conf = "### Business Process Config File ###\n#\n";
foreach ($settings as $key => $value) {
$conf .= sprintf("# %-9s : %s\n", $key, $value);
}
$conf .= "#\n###################################\n\n";
$rendered = array();
foreach ($this->getChildren() as $child) {
$conf .= $child->toLegacyConfigString($rendered);
$rendered[(string) $child] = true;
}
foreach ($this->getUnboundNodes() as $node) {
$conf .= $node->toLegacyConfigString($rendered);
$rendered[(string) $node] = true;
}
return $conf . "\n";
$this->throwErrors = $throw;
return $this;
}
/**
* Begin loop detection for the given name
*
* Will throw a NestingError in case this node will be met again below itself
*
* @param $name
*
* @throws NestingError
*/
public function beginLoopDetection($name)
{
// echo "Begin loop $name\n";
if (array_key_exists($name, $this->loopDetection)) {
$loop = array_keys($this->loopDetection);
$loop[] = $name;
$this->loopDetection = array();
throw new NestingError('Loop detected: %s', implode(' -> ', $loop));
}
$this->loopDetection[$name] = true;
}
/**
* Remove the given name from the loop detection stack
*
* @param $name
*/
public function endLoopDetection($name)
{
// echo "End loop $this->name\n";
unset($this->loopDetection[$name]);
}
/**
* Whether this configuration has any Nodes
*
* @return bool
*/
public function isEmpty()
{
return $this->countChildren() === 0;
}
public function renderHtml($view)
{
$html = '';
foreach ($this->getRootNodes() as $name => $node) {
$html .= $node->renderHtml($view);
}
return $html;
}
public function renderUnbound($view)
{
$html = '';
$unbound = $this->getUnboundNodes();
if (empty($unbound)) {
return $html;
}
$parent = new BpNode($this, (object) array(
'name' => '__unbound__',
'operator' => '|',
'child_names' => array_keys($unbound)
));
$parent->getState();
$parent->setMissing()
->setDowntime(false)
->setAck(false)
->setAlias('Unbound nodes');
$html .= $parent->renderHtml($view);
return $html;
}
}

View file

@ -3,7 +3,7 @@
namespace Icinga\Module\Businessprocess;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\ProgrammingError;
use Icinga\Module\Businessprocess\Exception\NestingError;
class BpNode extends Node
{
@ -14,11 +14,16 @@ class BpNode extends Node
protected $url;
protected $info_command;
protected $display = 0;
/** @var Node[] */
protected $children;
protected $child_names = array();
/** @var array */
protected $childNames = array();
protected $alias;
protected $counters;
protected $missing = null;
protected $missingChildren;
protected static $emptyStateSummary = array(
'OK' => 0,
@ -42,7 +47,7 @@ class BpNode extends Node
protected $className = 'process';
public function __construct(BusinessProcess $bp, $object)
public function __construct(BpConfig $bp, $object)
{
$this->bp = $bp;
$this->name = $object->name;
@ -56,7 +61,7 @@ class BpNode extends Node
$this->getState();
$this->counters = self::$emptyStateSummary;
foreach ($this->children as $child) {
foreach ($this->getChildren() as $child) {
if ($child instanceof BpNode) {
$counters = $child->getStateSummary();
foreach ($counters as $k => $v) {
@ -88,6 +93,30 @@ class BpNode extends Node
return false;
}
/**
* @param Node $node
* @return $this
* @throws ConfigurationError
*/
public function addChild(Node $node)
{
if ($this->children === null) {
$this->getChildren();
}
$name = $node->getName();
if (array_key_exists($name, $this->children)) {
throw new ConfigurationError(
'Node "%s" has been defined more than once',
$name
);
}
$this->children[$name] = $node;
$this->childNames[] = $name;
$node->addParent($this);
return $this;
}
public function getProblematicChildren()
{
$problems = array();
@ -103,6 +132,24 @@ class BpNode extends Node
return $problems;
}
public function hasChild($name)
{
return in_array($name, $this->childNames);
}
public function removeChild($name)
{
if (($key = array_search($name, $this->childNames)) !== false) {
unset($this->childNames[$key]);
if (! empty($this->children)) {
unset($this->children[$name]);
}
}
return $this;
}
public function getProblemTree()
{
$tree = array();
@ -135,6 +182,27 @@ class BpNode extends Node
return $this->missing;
}
public function getMissingChildren()
{
if ($this->missingChildren === null) {
$missing = array();
foreach ($this->getChildren() as $child) {
if ($child->isMissing()) {
$missing[(string) $child] = $child;
}
foreach ($child->getMissingChildren() as $m) {
$missing[(string) $m] = $m;
}
}
$this->missingChildren = $missing;
}
return $this->missingChildren;
}
public function getOperator()
{
return $this->operator;
@ -174,7 +242,7 @@ class BpNode extends Node
public function hasInfoUrl()
{
return $this->url !== null;
return ! empty($this->url);
}
public function getInfoUrl()
@ -213,26 +281,60 @@ class BpNode extends Node
return $this;
}
/**
* @return int
*/
public function getState()
{
if ($this->state === null) {
$this->calculateState();
try {
$this->reCalculateState();
} catch (NestingError $e) {
$this->bp->addError(
$this->bp->translate('Nesting error detected: %s'),
$e->getMessage()
);
// Failing nodes are unknown
$this->state = 3;
}
}
return $this->state;
}
public function getHtmlId()
{
return 'businessprocess-' . preg_replace('/[\r\n\t\s]/', '_', (string) $this);
}
protected function invertSortingState($state)
{
return self::$sortStateInversionMap[$state >> self::SHIFT_FLAGS] << self::SHIFT_FLAGS;
}
protected function calculateState()
/**
* @return $this
*/
public function reCalculateState()
{
$bp = $this->bp;
$sort_states = array();
$lastStateChange = 0;
if (!$this->hasChildren()) {
// TODO: delegate this to operators, should mostly fail
$this->state = 3;
$this->setMissing();
return $this;
}
foreach ($this->getChildren() as $child) {
$bp->beginLoopDetection($this->name);
$sort_states[] = $child->getSortingState();
$lastStateChange = max($lastStateChange, $child->getLastStateChange());
$bp->endLoopDetection($this->name);
}
$this->setLastStateChange($lastStateChange);
@ -266,6 +368,21 @@ class BpNode extends Node
}
$this->state = $this->sortStateTostate($sort_state);
return $this;
}
public function checkForLoops()
{
$bp = $this->bp;
foreach ($this->getChildren() as $child) {
$bp->beginLoopDetection($this->name);
if ($child instanceof BpNode) {
$child->checkForLoops();
}
$bp->endLoopDetection($this->name);
}
return $this;
}
public function setDisplay($display)
@ -282,29 +399,51 @@ class BpNode extends Node
public function setChildNames($names)
{
sort($names);
$this->child_names = $names;
$this->childNames = $names;
$this->children = null;
return $this;
}
public function hasChildren($filter = null)
{
return !empty($this->childNames);
}
public function getChildNames()
{
return $this->child_names;
return $this->childNames;
}
public function getChildren($filter = null)
{
if ($this->children === null) {
$this->children = array();
natsort($this->child_names);
foreach ($this->child_names as $name) {
natsort($this->childNames);
foreach ($this->childNames as $name) {
$this->children[$name] = $this->bp->getNode($name);
$this->children[$name]->addParent($this);
}
}
return $this->children;
}
/**
* return BpNode[]
*/
public function getChildBpNodes()
{
$children = array();
foreach ($this->getChildren() as $name => $child) {
if ($child instanceof BpNode) {
$children[$name] = $child;
}
}
return $children;
}
protected function assertNumericOperator()
{
if (! is_numeric($this->operator)) {
@ -312,76 +451,6 @@ class BpNode extends Node
}
}
protected function getActionIcons($view)
{
$icons = array();
if (! $this->bp->isLocked() && $this->name !== '__unbound__') {
$icons[] = $this->actionIcon(
$view,
'wrench',
$view->url('businessprocess/node/edit', array(
'config' => $this->bp->getName(),
'node' => $this->name
)),
mt('businessprocess', 'Modify this node')
);
}
return $icons;
}
public function toLegacyConfigString(& $rendered = array())
{
$cfg = '';
if (array_key_exists($this->name, $rendered)) {
return $cfg;
}
$rendered[$this->name] = true;
$children = array();
foreach ($this->getChildren() as $name => $child) {
$children[] = (string) $child;
if (array_key_exists($name, $rendered)) { continue; }
if ($child instanceof BpNode) {
$cfg .= $child->toLegacyConfigString($rendered) . "\n";
}
}
$eq = '=';
$op = $this->operator;
if (is_numeric($op)) {
$eq = '= ' . $op . ' of:';
$op = '+';
}
$strChildren = implode(' ' . $op . ' ', $children);
if ((count($children) < 2) && $op !== '&') {
$strChildren = $op . ' ' . $strChildren;
}
$cfg .= sprintf(
"%s %s %s\n",
$this->name,
$eq,
$strChildren
);
if ($this->hasAlias() || $this->getDisplay() > 0) {
$prio = $this->getDisplay();
$cfg .= sprintf(
"display %s;%s;%s\n",
$prio,
$this->name,
$this->getAlias()
);
}
if ($this->hasInfoUrl()) {
$cfg .= sprintf(
"info_url;%s;%s\n",
$this->name,
$this->getInfoUrl()
);
}
return $cfg;
}
public function operatorHtml()
{
switch ($this->operator) {

View file

@ -1,40 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess;
use FineDiff;
class ConfigDiff
{
protected $a;
protected $b;
protected $diff;
protected $opcodes;
protected function __construct($a, $b)
{
$this->a = $a;
$this->b = $b;
require_once dirname(__DIR__) . '/vendor/PHP-FineDiff/finediff.php';
$granularity = FineDiff::$paragraphGranularity; // character, word, sentence, paragraph
$this->diff = new FineDiff($a, $b, $granularity);
}
public function renderHtml()
{
return $this->diff->renderDiffToHTML();
}
public function __toString()
{
return $this->renderHtml();
}
public static function create($a, $b)
{
$diff = new static($a, $b);
return $diff;
}
}

View file

@ -1,164 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess;
use Exception;
use Icinga\Application\Icinga;
use Icinga\Module\Businessprocess\BusinessProcess;
use Icinga\Module\Businessprocess\Form\ProcessForm;
use Icinga\Module\Businessprocess\Form\SimulationForm;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Icinga\Module\Monitoring\Backend;
use Icinga\Web\Controller as ModuleController;
use Icinga\Web\Notification;
use Icinga\Module\Businessprocess\Web\Form\FormLoader;
use Icinga\Web\Url;
use Icinga\Web\Widget;
class Controller extends ModuleController
{
protected $config;
protected $backend;
private $storage;
private $url;
public function init()
{
$m = Icinga::app()->getModuleManager();
if (! $m->hasLoaded('monitoring') && $m->hasInstalled('monitoring')) {
$m->loadModule('monitoring');
}
$this->view->errors = array();
$this->view->compact = $this->params->get('view') === 'compact';
}
protected function url()
{
if ($this->url === null) {
$this->url = clone $this->getRequest()->getUrl();
}
return $this->url;
}
protected function tabs()
{
if ($this->view->tabs === null) {
$this->view->tabs = Widget::create('tabs');
}
return $this->view->tabs;
}
protected function session()
{
return $this->Window()->getSessionNamespace('businessprocess');
}
protected function setTitle($title)
{
$args = func_get_args();
array_shift($args);
$this->view->title = vsprintf($title, $args);
}
protected function loadModifiedBpConfig()
{
$bp = $this->loadBpConfig();
$changes = ProcessChanges::construct($bp, $this->session());
if ($this->params->get('dismissChanges')) {
Notification::success(
sprintf(
$this->translate('%d pending change(s) have been dropped'),
$changes->count()
)
);
$changes->clear();
$this->redirectNow($this->url()->without('dismissChanges')->without('unlocked'));
}
$bp->applyChanges($changes);
return $bp;
}
protected function loadBpConfig()
{
$storage = $this->storage();
$this->view->processList = $storage->listProcesses();
// No process found? Go to welcome page
if (empty($this->view->processList)) {
$this->redirectNow('businessprocess');
}
$name = $this->params->get(
'config',
key($this->view->processList)
);
$modifications = $this->session()->get('modifications', array());
if (array_key_exists($name, $modifications)) {
$bp = $storage->loadFromString($name, $modifications[$name]);
} else {
$bp = $storage->loadProcess($name);
}
// allow URL parameter to override configured state type
if (null !== ($stateType = $this->params->get('state_type'))) {
if ($stateType === 'soft') {
$bp->useSoftStates();
}
if ($stateType === 'hard') {
$bp->useHardStates();
}
}
$this->view->bpconfig = $bp;
$this->view->configName = $bp->getName();
return $bp;
}
public function loadForm($name)
{
return FormLoader::load($name, $this->Module());
}
protected function storage()
{
if ($this->storage === null) {
$this->storage = new LegacyStorage(
$this->Config()->getSection('global')
);
}
return $this->storage;
}
protected function loadSlas()
{
$bpconf = $this->bpconf;
if (! isset($bpconf->slahosts)) {
return array();
}
// TODO: This doesn't work right now
$sla_hosts = preg_split('~\s*,s*~', $bpconf->slahosts, -1, PREG_SPLIT_NO_EMPTY);
if (isset($bpconf->sla_year)) {
$start = mktime(0, 0, 0, 1, 1, $bpconf->sla_year);
$end = mktime(23, 59, 59, 1, 0, $bpconf->sla_year + 1);
} else {
$start = mktime(0, 0, 0, 1, 1, (int) date('Y'));
$end = null;
// Bis zum Jahresende hochrechnen:
// $end = mktime(23, 59, 59, 1, 0, (int) date('Y') + 1);
}
return $this->backend
->module('BpAddon')
->getBpSlaValues($sla_hosts, $start, $end);
}
}

View file

@ -3,7 +3,7 @@
namespace Icinga\Module\Businessprocess\Director;
use Icinga\Application\Config;
use Icinga\Module\Director\Web\Hook\ShipConfigFilesHook;
use Icinga\Module\Director\Hook\ShipConfigFilesHook;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
class ShipConfigFiles extends ShipConfigFilesHook

View file

@ -0,0 +1,9 @@
<?php
namespace Icinga\Module\Businessprocess\Exception;
use Icinga\Exception\IcingaException;
class NestingError extends IcingaException
{
}

View file

@ -2,25 +2,26 @@
namespace Icinga\Module\Businessprocess;
use Icinga\Web\Url;
use Icinga\Module\Businessprocess\Html\Link;
use Icinga\Module\Businessprocess\Web\Url;
class HostNode extends Node
class HostNode extends MonitoredNode
{
protected static $sortStateToStateMap = array(
protected $sortStateToStateMap = array(
4 => self::ICINGA_DOWN,
3 => self::ICINGA_UNREACHABLE,
1 => self::ICINGA_PENDING,
0 => self::ICINGA_UP
);
protected static $stateToSortStateMap = array(
protected $stateToSortStateMap = array(
self::ICINGA_PENDING => 1,
self::ICINGA_UNREACHABLE => 3,
self::ICINGA_DOWN => 4,
self::ICINGA_UP => 0,
);
protected static $state_names = array(
protected $stateNames = array(
'UP',
'DOWN',
'UNREACHABLE',
@ -31,7 +32,7 @@ class HostNode extends Node
protected $className = 'host';
public function __construct(BusinessProcess $bp, $object)
public function __construct(BpConfig $bp, $object)
{
$this->name = $object->hostname . ';Hoststatus';
$this->hostname = $object->hostname;
@ -43,46 +44,31 @@ class HostNode extends Node
}
}
public function renderLink($view)
public function getAlias()
{
if ($this->isMissing()) {
return '<span class="missing">' . $view->escape($this->hostname) . '</span>';
}
$params = array(
'host' => $this->getHostname(),
);
if ($this->bp->hasBackendName()) {
$params['backend'] = $this->bp->getBackendName();
}
return $view->qlink($this->hostname, 'monitoring/host/show', $params);
}
protected function getActionIcons($view)
{
$icons = array();
if (! $this->bp->isLocked()) {
$url = Url::fromPath( 'businessprocess/node/simulate', array(
'config' => $this->bp->getName(),
'node' => $this->name
));
$icons[] = $this->actionIcon(
$view,
'magic',
$url,
'Simulation'
);
}
return $icons;
return $this->getHostname();
}
public function getHostname()
{
return $this->hostname;
}
public function getUrl()
{
$params = array(
'host' => $this->getHostname(),
);
if ($this->bp->hasBackendName()) {
$params['backend'] = $this->bp->getBackendName();
}
return Url::fromPath('monitoring/host/show', $params);
}
public function getLink()
{
return Link::create($this->hostname, $this->getUrl());
}
}

View file

@ -0,0 +1,130 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
class Attribute
{
/** @var string */
protected $name;
/** @var string|array */
protected $value;
/**
* Attribute constructor.
*
* @param $name
* @param $value
*/
public function __construct($name, $value)
{
$this->name = $name;
$this->value = $value;
}
/**
* @param $name
* @param $value
* @return static
*/
public static function create($name, $value)
{
return new static($name, $value);
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
/**
* @param string|array $value
* @return $this
*/
public function setValue($value)
{
$this->value = $value;
return $this;
}
/**
* @param string $value
* @return $this
*/
public function addValue($value)
{
if (! is_array($this->value)) {
$this->value = array($this->value);
}
if (is_array($value)) {
$this->value = array_merge($this->value, $value);
} else {
$this->value[] = $value;
}
return $this;
}
/**
* @return string
*/
public function render()
{
return sprintf(
'%s="%s"',
$this->renderName(),
$this->renderValue()
);
}
/**
* @return string
*/
public function renderName()
{
return static::escapeName($this->name);
}
/**
* @return string
*/
public function renderValue()
{
return static::escapeValue($this->value);
}
/**
* @param $name
* @return string
*/
public static function escapeName($name)
{
// TODO: escape
return (string) $name;
}
/**
* @param $value
* @return string
*/
public static function escapeValue($value)
{
// TODO: escape differently
if (is_array($value)) {
return Util::escapeForHtml(implode(' ', $value));
} else {
return Util::escapeForHtml((string) $value);
}
}
}

View file

@ -0,0 +1,195 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
use Icinga\Exception\IcingaException;
use Icinga\Exception\ProgrammingError;
class Attributes
{
/** @var Attribute[] */
protected $attributes = array();
/** @var callable */
protected $callbacks = array();
/**
* Attributes constructor.
* @param Attribute[] $attributes
*/
public function __construct(array $attributes = null)
{
if (empty($attributes)) {
return;
}
foreach ($attributes as $key => $value) {
if ($value instanceof Attribute) {
$this->addAttribute($value);
} elseif (is_string($key)) {
$this->add($key, $value);
} elseif (is_array($value) && count($value) === 2) {
$this->add(array_shift($value), array_shift($value));
}
}
}
/**
* @param Attribute[] $attributes
* @return static
*/
public static function create(array $attributes = null)
{
return new static($attributes);
}
/**
* @param Attributes|array|null $attributes
* @return Attributes
* @throws IcingaException
*/
public static function wantAttributes($attributes)
{
if ($attributes instanceof Attributes) {
return $attributes;
} else {
$self = new static();
if (is_array($attributes)) {
foreach ($attributes as $k => $v) {
$self->add($k, $v);
}
return $self;
} elseif ($attributes !== null) {
throw new IcingaException(
'Attributes, Array or Null expected, got %s',
Util::getPhpTypeName($attributes)
);
}
return $self;
}
}
/**
* @return Attribute[]
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* @param Attribute|string $attribute
* @param string|array $value
* @return $this
*/
public function add($attribute, $value = null)
{
if ($attribute instanceof static) {
foreach ($attribute->getAttributes() as $a) {
$this->add($a);
}
} elseif ($attribute instanceof Attribute) {
$this->addAttribute($attribute);
} elseif (is_array($attribute)) {
foreach ($attribute as $name => $value) {
$this->add($name, $value);
}
} else {
$this->addAttribute(Attribute::create($attribute, $value));
}
return $this;
}
/**
* @param Attribute|string $attribute
* @param string|array $value
* @return $this
*/
public function set($attribute, $value = null)
{
if ($attribute instanceof static) {
foreach ($attribute as $a) {
$this->setAttribute($a);
}
return $this;
} elseif ($attribute instanceof Attribute) {
return $this->setAttribute($attribute);
} else {
return $this->setAttribute(new Attribute($attribute, $value));
}
}
/**
* @param Attribute $attribute
* @return $this
*/
public function addAttribute(Attribute $attribute)
{
$name = $attribute->getName();
if (array_key_exists($name, $this->attributes)) {
$this->attributes[$name]->addValue($attribute->getValue());
} else {
$this->attributes[$name] = $attribute;
}
return $this;
}
/**
* @param Attribute $attribute
* @return $this
*/
public function setAttribute(Attribute $attribute)
{
$name = $attribute->getName();
$this->attributes[$name] = $attribute;
return $this;
}
/**
* Callback must return an instance of Attribute
*
* @param string $name
* @param callable $callback
* @return $this
*/
public function registerCallbackFor($name, $callback)
{
if (! is_callable($callback)) {
throw new ProgrammingError('registerCallBack expects a callable callback');
}
$this->callbacks[$name] = $callback;
return $this;
}
/**
* @inheritdoc
*/
public function render()
{
if (empty($this->attributes) && empty($this->callbacks)) {
return '';
}
$parts = array();
foreach ($this->callbacks as $callback) {
$attribute = call_user_func($callback);
if (! $attribute instanceof Attribute) {
throw new ProgrammingError(
'A registered attribute callback must return an Attribute'
);
}
$parts[] = $attribute->render();
}
foreach ($this->attributes as $attribute) {
$parts[] = $attribute->render();
}
return ' ' . implode(' ', $parts);
}
}

View file

@ -0,0 +1,117 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
use Exception;
abstract class BaseElement extends Html
{
/** @var array You may want to set default attributes when extending this class */
protected $defaultAttributes;
/** @var Attributes */
protected $attributes;
/** @var string */
protected $tag;
/**
* @return Attributes
*/
public function attributes()
{
if ($this->attributes === null) {
$default = $this->getDefaultAttributes();
if (empty($default)) {
$this->attributes = new Attributes();
} else {
$this->attributes = Attributes::wantAttributes($default);
}
}
return $this->attributes;
}
/**
* @param Attributes|array|null $attributes
* @return $this
*/
public function setAttributes($attributes)
{
$this->attributes = Attributes::wantAttributes($attributes);
return $this;
}
/**
* @param Attributes|array|null $attributes
* @return $this
*/
public function addAttributes($attributes)
{
$this->attributes = Attributes::wantAttributes($attributes);
return $this;
}
public function getDefaultAttributes()
{
return $this->defaultAttributes;
}
public function setTag($tag)
{
$this->tag = $tag;
return $this;
}
public function getTag()
{
return $this->tag;
}
/**
* Container constructor.
*
* @param string $tag
* @param Attributes|array $attributes
*
* @return Element
*/
public function createElement($tag, $attributes = null)
{
$element = Element::create($tag, $attributes);
$this->add($element);
return $element;
}
public function renderContent()
{
return parent::render();
}
/**
* @return string
*/
public function render()
{
$tag = $this->getTag();
return sprintf(
'<%s%s>%s</%s>',
$tag,
$this->attributes()->render(),
$this->renderContent(),
$tag
);
}
/**
* Whether the given something can be rendered
*
* @param mixed $any
* @return bool
*/
protected function canBeRendered($any)
{
return is_string($any) || is_int($any) || is_null($any);
}
}

View file

@ -0,0 +1,40 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
class Container extends BaseElement
{
/** @var string */
protected $contentSeparator = "\n";
/** @var string */
protected $tag = 'div';
protected function __construct()
{
}
/**
* @param Renderable|array|string $content
* @param Attributes|array $attributes
* @param string $tag
*
* @return static
*/
public static function create($attributes = null, $content = null, $tag = null)
{
$container = new static();
if ($content !== null) {
$container->setContent($content);
}
if ($attributes !== null) {
$container->setAttributes($attributes);
}
if ($tag !== null) {
$container->setTag($tag);
}
return $container;
}
}

View file

@ -0,0 +1,34 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
class Element extends BaseElement
{
/**
* Container constructor.
*
* @param string $tag
* @param Attributes|array $attributes
*/
public function __construct($tag, $attributes = null)
{
$this->tag = $tag;
if ($attributes !== null) {
$this->attributes = $this->attributes()->add($attributes);
}
}
/**
* Container constructor.
*
* @param string $tag
* @param Attributes|array $attributes
*
* @return static
*/
public static function create($tag, $attributes = null)
{
return new static($tag, $attributes);
}
}

View file

@ -0,0 +1,157 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
use Icinga\Exception\ProgrammingError;
class Html implements Renderable
{
protected $contentSeparator = '';
/**
* @var Renderable[]
*/
private $content = array();
public static function escape($any)
{
return Util::wantHtml($any);
}
/**
* @param Renderable $element
* @return $this
*/
public function add(Renderable $element)
{
$this->content[] = $element;
return $this;
}
/**
* @param Renderable|array|string $content
* @return $this
*/
public function setContent($content)
{
$this->content = array(
static::escape($content)
);
return $this;
}
/**
* @param Renderable|array|string $content
* @return $this
*/
public function addContent($content)
{
$this->content[] = static::escape($content);
return $this;
}
/**
* @param Renderable|array|string $content
* @return $this
*/
public function prependContent($content)
{
array_unshift($this->content, static::escape($content));
return $this;
}
/**
* return Html
*/
public function getContent()
{
if ($this->content === null) {
$this->content = array(new Html());
}
return $this->content;
}
public function hasContent()
{
if ($this->content === null) {
return false;
}
// TODO: unfinished
// return $this->content->isEmpty();
return true;
}
/**
* @param $separator
* @return $this
*/
public function setSeparator($separator)
{
$this->contentSeparator = $separator;
return $this;
}
/**
* @inheritdoc
*/
public function render()
{
$html = array();
foreach ($this->content as $element) {
if (is_string($element)) {
var_dump($this->content);
}
$html[] = $element->render();
}
return implode($this->contentSeparator, $html);
}
protected function translate($msg)
{
// TODO: Not so nice
return mt('businessprocess', $msg);
}
public static function element($name, $attributes = null)
{
// TODO: This might be anything here, add a better check
if (! ctype_alnum($name)) {
throw new ProgrammingError('Invalid element requested');
}
$class = __NAMESPACE__ . '\\' . $name;
/** @var Element $element */
$element = new $class();
if ($attributes !== null) {
$element->setAttributes($attributes);
}
return $element;
}
/**
* @param Exception|string $error
* @return string
*/
protected function renderError($error)
{
return Util::renderError($error);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->render();
} catch (Exception $e) {
return $this->renderError($e);
}
}
}

View file

@ -0,0 +1,8 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
class HtmlString extends Text
{
protected $escaped = true;
}

View file

@ -0,0 +1,28 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
abstract class HtmlTag
{
/**
* @param $content
* @param Attributes|array $attributes
*
* @return Element
*/
public static function h1($content, $attributes = null)
{
return Element::create('h1', $attributes)->setContent($content);
}
/**
* @param $content
* @param Attributes|array $attributes
*
* @return Element
*/
public static function p($content, $attributes = null)
{
return Element::create('p', $attributes)->setContent($content);
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
class Icon extends BaseElement
{
protected $tag = 'i';
protected function __construct()
{
}
/**
* @param string $name
* @param array $attributes
*
* @return static
*/
public static function create($name, array $attributes = null)
{
$icon = new static();
$icon->setAttributes($attributes);
$icon->attributes()->add('class', array('icon', 'icon-' . $name));
return $icon;
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
use Icinga\Module\Businessprocess\Web\Url;
use Icinga\Web\Url as WebUrl;
class Img extends BaseElement
{
protected $tag = 'img';
/** @var Url */
protected $url;
protected $defaultAttributes = array('alt' => '');
protected function __construct()
{
}
/**
* @param Url|string $url
* @param array $urlParams
* @param array $attributes
*
* @return static
*/
public static function create($url, $urlParams = null, array $attributes = null)
{
$img = new static();
$img->setAttributes($attributes);
$img->attributes()->registerCallbackFor('src', array($img, 'getSrcAttribute'));
$img->setUrl($url, $urlParams);
return $img;
}
public function setUrl($url, $urlParams)
{
if ($url instanceof WebUrl) { // Hint: Url is also a WebUrl
if ($urlParams !== null) {
$url->addParams($urlParams);
}
$this->url = $url;
} else {
if ($urlParams === null) {
$this->url = Url::fromPath($url);
} else {
$this->url = Url::fromPath($url, $urlParams);
}
}
$this->url->getParams();
}
/**
* @return Attribute
*/
public function getSrcAttribute()
{
return new Attribute('src', $this->getUrl()->getAbsoluteUrl('&'));
}
/**
* @return Url
*/
public function getUrl()
{
// TODO: What if null? #?
return $this->url;
}
}

View file

@ -0,0 +1,72 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
use Icinga\Module\Businessprocess\Web\Url;
use Icinga\Web\Url as WebUrl;
class Link extends BaseElement
{
protected $tag = 'a';
/** @var Url */
protected $url;
protected function __construct()
{
}
/**
* @param Renderable|array|string $content
* @param Url|string $url
* @param array $urlParams
* @param array $attributes
*
* @return static
*/
public static function create($content, $url, $urlParams = null, array $attributes = null)
{
$link = new static();
$link->setContent($content);
$link->setAttributes($attributes);
$link->attributes()->registerCallbackFor('href', array($link, 'getHrefAttribute'));
$link->setUrl($url, $urlParams);
return $link;
}
public function setUrl($url, $urlParams)
{
if ($url instanceof WebUrl) { // Hint: Url is also a WebUrl
if ($urlParams !== null) {
$url->addParams($urlParams);
}
$this->url = $url;
} else {
if ($urlParams === null) {
$this->url = Url::fromPath($url);
} else {
$this->url = Url::fromPath($url, $urlParams);
}
}
$this->url->getParams();
}
/**
* @return Attribute
*/
public function getHrefAttribute()
{
return new Attribute('href', $this->getUrl()->getAbsoluteUrl('&'));
}
/**
* @return Url
*/
public function getUrl()
{
// TODO: What if null? #?
return $this->url;
}
}

View file

@ -0,0 +1,8 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
interface Renderable
{
public function render();
}

View file

@ -0,0 +1,82 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
class Text implements Renderable
{
/** @var string */
protected $string;
protected $escaped = false;
/**
* Text constructor.
*
* @param $text
*/
public function __construct($string)
{
$this->string = (string) $string;
}
/**
* @return string
*/
public function getText()
{
return $this->string;
}
/**
* @param bool $escaped
* @return $this
*/
public function setEscaped($escaped = true)
{
$this->escaped = $escaped;
return $this;
}
/**
* @param $text
*
* @return static
*/
public static function create($text)
{
return new static($text);
}
/**
* @return string
*/
public function render()
{
if ($this->escaped) {
return $this->string;
} else {
return Util::escapeForHtml($this->string);
}
}
/**
* @param Exception|string $error
* @return string
*/
protected function renderError($error)
{
return Util::renderError($error);
}
/**
* @return string
*/
public function __toString()
{
try {
return $this->render();
} catch (Exception $e) {
return $this->renderError($e);
}
}
}

View file

@ -0,0 +1,130 @@
<?php
namespace Icinga\Module\Businessprocess\Html;
use Exception;
use Icinga\Exception\IcingaException;
class Util
{
/**
* Charset to be used - we only support UTF-8
*/
const CHARSET = 'UTF-8';
/**
* The flags we use for htmlspecialchars depend on our PHP version
*/
protected static $htmlEscapeFlags;
/**
* Escape the given value top be safely used in view scripts
*
* @param string $value The output to be escaped
* @return string
*/
public static function escapeForHtml($value)
{
return htmlspecialchars(
$value,
static::htmlEscapeFlags(),
self::CHARSET,
true
);
}
/**
* @param Exception|string $error
* @return string
*/
public static function renderError($error)
{
if ($error instanceof Exception) {
$file = preg_split('/[\/\\\]/', $error->getFile(), -1, PREG_SPLIT_NO_EMPTY);
$file = array_pop($file);
$msg = sprintf(
'%s (%s:%d)',
$error->getMessage(),
$file,
$error->getLine()
);
} elseif (is_string($error)) {
$msg = $error;
} else {
$msg = 'Got an invalid error'; // TODO: translate?
}
return sprintf(
'ERROR: %s', // TODO: translate?
static::escapeForHtml($msg)
);
}
/**
* @param $any
* @return Renderable
* @throws IcingaException
*/
public static function wantHtml($any)
{
if ($any instanceof Renderable) {
return $any;
} elseif (static::canBeRenderedAsString($any)) {
return new Text($any);
} elseif (is_array($any)) {
$html = new Html();
foreach ($any as $el) {
$html->add(static::wantHtml($el));
}
return $html;
} else {
// TODO: Should we add a dedicated Exception class?
throw new IcingaException(
'String, Html Element or Array of such expected, got "%s"',
Util::getPhpTypeName($any)
);
}
}
public static function canBeRenderedAsString($any)
{
return is_string($any) || is_int($any) || is_null($any);
}
/**
* @param $any
* @return string
*/
public static function getPhpTypeName($any)
{
if (is_object($any)) {
return get_class($any);
} else {
return gettype($any);
}
}
/**
* This defines the flags used when escaping for HTML
*
* - Single quotes are not escaped (ENT_COMPAT)
* - With PHP >= 5.4, invalid characters are replaced with <EFBFBD> (ENT_SUBSTITUTE)
* - With PHP 5.3 they are ignored (ENT_IGNORE, less secure)
* - Uses HTML5 entities for PHP >= 5.4, disallowing &#013;
*
* @return int
*/
protected static function htmlEscapeFlags()
{
if (self::$htmlEscapeFlags === null) {
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
self::$htmlEscapeFlags = ENT_COMPAT | ENT_SUBSTITUTE | ENT_HTML5;
} else {
self::$htmlEscapeFlags = ENT_COMPAT | ENT_IGNORE;
}
}
return self::$htmlEscapeFlags;
}
}

View file

@ -3,25 +3,42 @@
namespace Icinga\Module\Businessprocess;
use Icinga\Application\Config;
use Icinga\Web\Url;
use Icinga\Module\Businessprocess\Html\Link;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Icinga\Module\Businessprocess\Web\Url;
use Exception;
class ImportedNode extends Node
{
/** @var string */
protected $configName;
protected $importedBp;
/** @var string */
protected $nodeName;
protected $importedNode;
/** @var BpNode */
private $node;
protected $className = 'subtree';
public function __construct(BusinessProcess $bp, $object)
/** @var BpConfig */
protected $config;
/**
* @inheritdoc
*/
public function __construct(BpConfig $bp, $object)
{
$this->name = $object->name;
$this->bp = $bp;
$this->configName = $object->configName;
$this->bp = $bp;
$this->name = '@' . $object->configName;
if (property_exists($object, 'node')) {
$this->nodeName = $object->node;
$this->name .= ':' . $object->node;
} else {
$this->useAllRootNodes();
}
if (isset($object->state)) {
$this->setState($object->state);
} else {
@ -29,108 +46,189 @@ class ImportedNode extends Node
}
}
public function hasNode()
{
return $this->nodeName !== null;
}
/**
* @return string
*/
public function getConfigName()
{
return $this->configName;
}
/**
* @inheritdoc
*/
public function getState()
{
if ($this->state === null) {
try {
$this->importedConfig()->retrieveStatesFromBackend();
} catch (Exception $e) {
}
$this->state = $this->importedNode()->getState();
}
return $this->state;
}
/**
* @inheritdoc
*/
public function getAlias()
{
return $this->importedNode()->getAlias();
}
public function isMissing()
public function getUrl()
{
return $this->importedNode()->isMissing();
// TODO: WHY? return $this->getState() === null;
$params = array(
'config' => $this->getConfigName(),
'node' => $this->importedNode()->getName()
);
return Url::fromPath('businessprocess/process/show', $params);
}
/**
* @inheritdoc
*/
public function isMissing()
{
// TODO: WHY? return $this->getState() === null;
return $this->importedNode()->isMissing();
}
/**
* @inheritdoc
*/
public function isInDowntime()
{
if ($this->downtime === null) {
$this->getState();
$this->downtime = $this->importedNode()->isInDowntime();
}
return $this->downtime;
}
/**
* @inheritdoc
*/
public function isAcknowledged()
{
if ($this->ack === null) {
$this->getState();
$this->downtime = $this->importedNode()->isAcknowledged();
}
return $this->ack;
}
/**
* @return BpNode
*/
protected function importedNode()
{
if ($this->importedNode === null) {
$storage = new LegacyStorage(
Config::module('businessprocess')->getSection('global')
);
try {
$this->importedBp = $storage->loadProcess($this->configName);
if ($this->bp->usesSoftStates()) {
$this->importedBp->useSoftStates();
} else {
$this->importedBp->useHardStates();
}
$this->importedBp->retrieveStatesFromBackend();
$this->importedNode = $this->importedBp->getNode($this->name);
} catch (Exception $e) {
$node = new BpNode($this->bp, (object) array(
'name' => $this->name,
'operator' => '&',
'child_names' => array()
));
$node->setState(2);
$node->setMissing(false)
->setDowntime(false)
->setAck(false)
->setAlias($e->getMessage());
$this->importedNode = $node;
}
if ($this->node === null) {
$this->node = $this->loadImportedNode();
}
return $this->importedNode;
return $this->node;
}
protected function getActionIcons($view)
/**
* @return BpNode
*/
protected function loadImportedNode()
{
$icons = array();
try {
$import = $this->importedConfig();
if (! $this->bp->isLocked()) {
return $import->getNode($this->nodeName);
} catch (Exception $e) {
return $this->createFailedNode($e);
}
}
$url = Url::fromPath( 'businessprocess/node/simulate', array(
'config' => $this->bp->getName(),
'node' => $this->name
protected function useAllRootNodes()
{
try {
$bp = $this->importedConfig();
$this->node = new BpNode($bp, (object) array(
'name' => $this->getName(),
'operator' => '&',
'child_names' => $bp->listRootNodes(),
));
} catch (Exception $e) {
$icons[] = $this->actionIcon(
$view,
'magic',
$url,
'Simulation'
);
$this->createFailedNode($e);
}
return $icons;
}
public function renderLink($view)
protected function importedConfig()
{
return $view->qlink($this->getAlias(), 'businessprocess/process/show', array(
'config' => $this->configName,
'process' => $this->name
if ($this->config === null) {
$import = $this->storage()->loadProcess($this->configName);
if ($this->bp->usesSoftStates()) {
$import->useSoftStates();
} else {
$import->useHardStates();
}
$this->config = $import;
}
return $this->config;
}
/**
* @return LegacyStorage
*/
protected function storage()
{
return new LegacyStorage(
Config::module('businessprocess')->getSection('global')
);
}
/**
* @param Exception $e
*
* @return BpNode
*/
protected function createFailedNode(Exception $e)
{
$this->bp->addError($e->getMessage());
$node = new BpNode($this->importedConfig(), (object) array(
'name' => $this->getName(),
'operator' => '&',
'child_names' => array()
));
$node->setState(2);
$node->setMissing(false)
->setDowntime(false)
->setAck(false)
->setAlias($e->getMessage());
return $node;
}
/**
* @inheritdoc
*/
public function getLink()
{
return Link::create(
$this->getAlias(),
'businessprocess/process/show',
array(
'config' => $this->configName,
'process' => $this->name
)
);
}
}

View file

@ -0,0 +1,244 @@
<?php
namespace Icinga\Module\Businessprocess;
use Icinga\Application\Icinga;
use Icinga\Authentication\Auth;
use Icinga\Exception\ProgrammingError;
use Icinga\User;
class Metadata
{
/** @var string Configuration name */
protected $name;
protected $properties = array(
'Title' => null,
'Description' => null,
'Owner' => null,
'AllowedUsers' => null,
'AllowedGroups' => null,
'AllowedRoles' => null,
'AddToMenu' => null,
'Backend' => null,
'Statetype' => null,
// 'SLAHosts' => null
);
public function __construct($name)
{
$this->name = $name;
}
public function getTitle()
{
if ($this->has('Title')) {
return $this->get('Title');
} else {
return $this->name;
}
}
public function getExtendedTitle()
{
$title = $this->getTitle();
if ($title === $this->name) {
return $title;
} else {
return sprintf('%s (%s)', $title, $this->name);
}
}
public function getProperties()
{
return $this->properties;
}
public function hasKey($key)
{
return array_key_exists($key, $this->properties);
}
public function get($key, $default = null)
{
$this->assertKeyExists($key);
if ($this->properties[$key] === null) {
return $default;
}
return $this->properties[$key];
}
public function set($key, $value)
{
$this->assertKeyExists($key);
$this->properties[$key] = $value;
return $this;
}
public function isNull($key)
{
return null === $this->get($key);
}
public function has($key)
{
return null !== $this->get($key);
}
protected function assertKeyExists($key)
{
if (! $this->hasKey($key)) {
throw new ProgrammingError('Trying to access invalid header key: %s', $key);
}
return $this;
}
public function hasRestrictions()
{
return ! (
$this->isNull('AllowedUsers')
&& $this->isNull('AllowedGroups')
&& $this->isNull('AllowedRoles')
);
}
protected function getAuth()
{
return Auth::getInstance();
}
public function canModify(Auth $auth = null)
{
if ($auth === null) {
if (Icinga::app()->isCli()) {
return true;
} else {
$auth = $this->getAuth();
}
}
return $this->canRead($auth) && (
$auth->hasPermission('businessprocess/modify')
|| $this->ownerIs($auth->getUser()->getUsername())
);
}
public function canRead(Auth $auth = null)
{
if ($auth === null) {
if (Icinga::app()->isCli()) {
return true;
} else {
$auth = $this->getAuth();
}
}
if ($auth->hasPermission('businessprocess/showall')) {
return true;
}
if (! $this->hasRestrictions()) {
return true;
}
if (! $auth->isAuthenticated()) {
return false;
}
return $this->userCanRead($auth->getUser());
}
protected function userCanRead(User $user)
{
$username = $user->getUsername();
return $this->ownerIs($username)
|| $this->isInAllowedUserList($username)
|| $this->isMemberOfAllowedGroups($user)
|| $this->hasOneOfTheAllowedRoles($user);
}
public function ownerIs($username)
{
return $this->get('Owner') === $username;
}
public function listAllowedUsers()
{
// TODO: $this->get('AllowedUsers', array());
$list = $this->get('AllowedUsers');
if ($list === null) {
return array();
} else {
return $this->splitCommaSeparated($list);
}
}
public function listAllowedGroups()
{
$list = $this->get('AllowedGroups');
if ($list === null) {
return array();
} else {
return $this->splitCommaSeparated($list);
}
}
public function listAllowedRoles()
{
$list = $this->get('AllowedRoles');
if ($list === null) {
return array();
} else {
return $this->splitCommaSeparated($list);
}
}
public function isInAllowedUserList($username)
{
foreach ($this->listAllowedUsers() as $allowedUser) {
if ($username === $allowedUser) {
return true;
}
}
return false;
}
public function isMemberOfAllowedGroups(User $user)
{
foreach ($this->listAllowedGroups() as $groups) {
foreach ($groups as $group) {
if ($user->isMemberOf($group)) {
return true;
}
}
}
return false;
}
public function hasOneOfTheAllowedRoles(User $user)
{
foreach ($this->listAllowedRoles() as $roles) {
foreach ($roles as $roleName) {
foreach ($user->getRoles() as $role) {
if ($role->getName() === $roleName) {
return true;
}
}
}
}
return false;
}
protected function splitCommaSeparated($string)
{
return preg_split('/\s*,\s*/', $string, -1, PREG_SPLIT_NO_EMPTY);
}
}

View file

@ -0,0 +1,160 @@
<?php
namespace Icinga\Module\Businessprocess\Modification;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Node;
use Icinga\Exception\ProgrammingError;
/**
* Abstract NodeAction class
*
* Every instance of a NodeAction represents a single applied change. Changes are pushed to
* a stack and consumed from there. When persisted, NodeActions are serialized with their name,
* node name and optionally additional properties according preserveProperties. For each property
* that should be preserved, getter and setter methods have to be defined.
*
* @package Icinga\Module\Businessprocess
*/
abstract class NodeAction
{
/** @var string Name of this action (currently create, modify, remove) */
protected $actionName;
/** @var string Name of the node this action applies to */
protected $nodeName;
/** @var array Properties which should be preserved when serializing this action */
protected $preserveProperties = array();
/**
* NodeAction constructor.
*
* @param Node|string $node
*/
public function __construct($node = null)
{
if ($node !== null) {
$this->nodeName = (string) $node;
}
}
/**
* Every NodeAction must be able to apply itself to a BusinessProcess
*
* @param BpConfig $config
* @return mixed
*/
abstract public function applyTo(BpConfig $config);
/**
* Every NodeAction must be able to tell whether it could be applied to a BusinessProcess
*
* @param BpConfig $config
* @return bool
*/
abstract public function appliesTo(BpConfig $config);
/**
* The name of the node this modification applies to
*
* @return string
*/
public function getNodeName()
{
return $this->nodeName;
}
public function hasNode()
{
return $this->nodeName !== null;
}
/**
* Whether this is an instance of a given action name
*
* @param string $actionName
* @return bool
*/
public function is($actionName)
{
return $this->getActionName() === $actionName;
}
/**
* Create an instance of a given actionName for a specific Node
*
* @param string $actionName
* @param string $nodeName
*
* @return static
*/
public static function create($actionName, $nodeName)
{
$className = __NAMESPACE__ . '\\Node' . ucfirst($actionName) . 'Action';
$object = new $className($nodeName);
return $object;
}
/**
* Returns a JSON-encoded serialized NodeAction
*
* @return string
*/
public function serialize()
{
$object = (object) array(
'actionName' => $this->getActionName(),
'nodeName' => $this->getNodeName(),
'properties' => array()
);
foreach ($this->preserveProperties as $key) {
$func = 'get' . ucfirst($key);
$object->properties[$key] = $this->$func();
}
return json_encode($object);
}
/**
* Decodes a JSON-serialized NodeAction and returns an object instance
*
* @param $string
* @return NodeAction
*/
public static function unSerialize($string)
{
$object = json_decode($string);
$action = self::create($object->actionName, $object->nodeName);
foreach ($object->properties as $key => $val) {
$func = 'set' . ucfirst($key);
$action->$func($val);
}
return $action;
}
/**
* Returns the defined action name or determines such from the class name
*
* @return string The action name
*
* @throws ProgrammingError when no such class exists
*/
public function getActionName()
{
if ($this->actionName === null) {
if (! preg_match('/\\\Node(\w+)Action$/', get_class($this), $m)) {
throw new ProgrammingError(
'"%s" is not a NodeAction class',
get_class($this)
);
}
$this->actionName = lcfirst($m[1]);
}
return $this->actionName;
}
}

View file

@ -0,0 +1,80 @@
<?php
namespace Icinga\Module\Businessprocess\Modification;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\BpNode;
class NodeAddChildrenAction extends NodeAction
{
protected $children = array();
protected $preserveProperties = array('children');
/**
* @inheritdoc
*/
public function appliesTo(BpConfig $config)
{
$name = $this->getNodeName();
if (! $config->hasNode($name)) {
return false;
}
return $config->getNode($name) instanceof BpNode;
}
/**
* @inheritdoc
*/
public function applyTo(BpConfig $config)
{
/** @var BpNode $node */
if (! $this->hasNode()) {
// TODO: We end up here when defining "top nodes", but that would probably
// be a different action
return $this;
}
$node = $config->getBpNode($this->getNodeName());
foreach ($this->children as $name) {
if (! $config->hasNode($name)) {
if (strpos($name, ';') !== false) {
list($host, $service) = preg_split('/;/', $name, 2);
if ($service === 'Hoststatus') {
$config->createHost($host);
} else {
$config->createService($host, $service);
}
}
}
$node->addChild($config->getNode($name));
}
return $this;
}
/**
* @param array|string $children
* @return $this
*/
public function setChildren($children)
{
if (is_string($children)) {
$children = array($children);
}
$this->children = $children;
return $this;
}
/**
* @return array
*/
public function getChildren()
{
return $this->children;
}
}

View file

@ -0,0 +1,109 @@
<?php
namespace Icinga\Module\Businessprocess\Modification;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\Node;
class NodeCreateAction extends NodeAction
{
/** @var string */
protected $parentName;
/** @var array */
protected $properties = array();
/** @var array */
protected $preserveProperties = array('parentName', 'properties');
/**
* @param Node $name
*/
public function setParent(Node $name)
{
$this->parentName = (string) $name;
}
/**
* @return bool
*/
public function hasParent()
{
return $this->parentName !== null;
}
/**
* @return string
*/
public function getParentName()
{
return $this->parentName;
}
/**
* @param string $name
*/
public function setParentName($name)
{
$this->parentName = $name;
}
/**
* @return array
*/
public function getProperties()
{
return $this->properties;
}
/**
* @param array $properties
* @return $this
*/
public function setProperties($properties)
{
$this->properties = (array) $properties;
return $this;
}
/**
* @inheritdoc
*/
public function appliesTo(BpConfig $config)
{
return ! $config->hasNode($this->getNodeName());
}
/**
* @inheritdoc
*/
public function applyTo(BpConfig $config)
{
$name = $this->getNodeName();
$properties = array(
'name' => $name,
'operator' => $this->properties['operator'],
);
if (array_key_exists('childNames', $this->properties)) {
$properties['child_names'] = $this->properties['childNames'];
} else {
$properties['child_names'] = array();
}
$node = new BpNode($config, (object) $properties);
foreach ($this->getProperties() as $key => $val) {
if ($key === 'parentName') {
$config->getBpNode($val)->addChild($node);
continue;
}
$func = 'set' . ucfirst($key);
$node->$func($val);
}
$config->addNode($name, $node);
return $node;
}
}

View file

@ -1,6 +1,9 @@
<?php
namespace Icinga\Module\Businessprocess;
namespace Icinga\Module\Businessprocess\Modification;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Node;
class NodeModifyAction extends NodeAction
{
@ -10,11 +13,18 @@ class NodeModifyAction extends NodeAction
protected $preserveProperties = array('formerProperties', 'properties');
// Can be called multiple times
public function setNodeProperties(Node $node, $properties)
/**
* Set properties for a specific node
*
* Can be called multiple times
*
* @param Node $node
* @param array $properties
*
* @return $this
*/
public function setNodeProperties(Node $node, array $properties)
{
$old = array();
foreach (array_keys($properties) as $key) {
$this->properties[$key] = $properties[$key];
@ -30,15 +40,18 @@ class NodeModifyAction extends NodeAction
return $this;
}
public function appliesTo(BusinessProcess $bp)
/**
* @inheritdoc
*/
public function appliesTo(BpConfig $config)
{
$name = $this->getNodeName();
if (! $bp->hasNode($name)) {
if (! $config->hasNode($name)) {
return false;
}
$node = $bp->getNode($name);
$node = $config->getNode($name);
foreach ($this->properties as $key => $val) {
$func = 'get' . ucfirst($key);
@ -50,9 +63,12 @@ class NodeModifyAction extends NodeAction
return true;
}
public function applyTo(BusinessProcess $bp)
/**
* @inheritdoc
*/
public function applyTo(BpConfig $config)
{
$node = $bp->getNode($this->getNodeName());
$node = $config->getNode($this->getNodeName());
foreach ($this->properties as $key => $val) {
$func = 'set' . ucfirst($key);
@ -62,23 +78,37 @@ class NodeModifyAction extends NodeAction
return $this;
}
/**
* @param $properties
* @return $this
*/
public function setProperties($properties)
{
$this->properties = $properties;
return $this;
}
/**
* @param $properties
* @return $this
*/
public function setFormerProperties($properties)
{
$this->formerProperties = $properties;
return $this;
}
/**
* @return array
*/
public function getProperties()
{
return $this->properties;
}
/**
* @return array
*/
public function getFormerProperties()
{
return $this->formerProperties;

View file

@ -0,0 +1,67 @@
<?php
namespace Icinga\Module\Businessprocess\Modification;
use Icinga\Module\Businessprocess\BpConfig;
/**
* NodeRemoveAction
*
* Tracks removed nodes
*
* @package Icinga\Module\Businessprocess
*/
class NodeRemoveAction extends NodeAction
{
protected $preserveProperties = array('parentName');
protected $parentName;
/**
* @param $parentName
* @return $this
*/
public function setParentName($parentName = null)
{
$this->parentName = $parentName;
return $this;
}
/**
* @return mixed
*/
public function getParentName()
{
return $this->parentName;
}
/**
* @inheritdoc
*/
public function appliesTo(BpConfig $config)
{
$parent = $this->getParentName();
if ($parent === null) {
return $config->hasNode($this->getNodeName());
} else {
return $config->hasNode($this->getNodeName()) && $config->hasNode($this->getParentName()) ;
}
}
/**
* @inheritdoc
*/
public function applyTo(BpConfig $config)
{
$parent = $this->getParentName();
if ($parent === null) {
$config->removeNode($this->getNodeName());
} else {
$node = $config->getNode($this->getNodeName());
$node->removeParent($parent);
if (! $node->hasParents()) {
$config->removeNode($this->getNodeName());
}
}
}
}

View file

@ -1,25 +1,41 @@
<?php
namespace Icinga\Module\Businessprocess;
namespace Icinga\Module\Businessprocess\Modification;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Node;
use Icinga\Web\Session\SessionNamespace as Session;
use Icinga\Module\Businessprocess\NodeAction;
class ProcessChanges
{
/** @var NodeAction[] */
protected $changes = array();
/** @var Session */
protected $session;
/** @var bool */
protected $hasBeenModified = false;
/** @var string Session storage key for this processes changes */
protected $sessionKey;
/**
* ProcessChanges constructor.
*
* Direct access is not allowed
*/
private function __construct()
{
}
public static function construct(BusinessProcess $bp, Session $session)
/**
* @param BpConfig $bp
* @param Session $session
*
* @return ProcessChanges
*/
public static function construct(BpConfig $bp, Session $session)
{
$key = 'changes.' . $bp->getName();
$changes = new ProcessChanges();
@ -27,7 +43,7 @@ class ProcessChanges
if ($actions = $session->get($key)) {
foreach ($actions as $string) {
$changes->push(NodeAction::unserialize($string));
$changes->push(NodeAction::unSerialize($string));
}
}
$changes->session = $session;
@ -35,6 +51,12 @@ class ProcessChanges
return $changes;
}
/**
* @param Node $node
* @param $properties
*
* @return $this
*/
public function modifyNode(Node $node, $properties)
{
$action = new NodeModifyAction($node);
@ -42,6 +64,26 @@ class ProcessChanges
return $this->push($action);
}
/**
* @param Node $node
* @param $properties
*
* @return $this
*/
public function addChildrenToNode($children, Node $node = null)
{
$action = new NodeAddChildrenAction($node);
$action->setChildren($children);
return $this->push($action);
}
/**
* @param Node|string $nodeName
* @param array $properties
* @param Node $parent
*
* @return $this
*/
public function createNode($nodeName, $properties, Node $parent = null)
{
$action = new NodeCreateAction($nodeName);
@ -52,11 +94,29 @@ class ProcessChanges
return $this->push($action);
}
public function deleteNode(Node $node)
/**
* @param Node $node
* @param array $path
*
* @return $this
*/
public function deleteNode(Node $node, array $path = null)
{
return $this->push(new NodeDeleteAction($node));
$action = new NodeRemoveAction($node);
if ($path !== null) {
$action->setPath($path);
}
return $this->push($action);
}
/**
* Add a new action to the stack
*
* @param NodeAction $change
*
* @return $this
*/
public function push(NodeAction $change)
{
$this->changes[] = $change;
@ -64,11 +124,21 @@ class ProcessChanges
return $this;
}
/**
* Get all stacked actions
*
* @return NodeAction[]
*/
public function getChanges()
{
return $this->changes;
}
/**
* Forget all changes and remove them from the Session
*
* @return $this
*/
public function clear()
{
$this->hasBeenModified = true;
@ -77,16 +147,31 @@ class ProcessChanges
return $this;
}
/**
* Whether there are no stacked changes
*
* @return bool
*/
public function isEmpty()
{
return $this->count() === 0;
}
/**
* Number of stacked changes
*
* @return bool
*/
public function count()
{
return count($this->changes);
}
/**
* Get the first change on the stack, false if empty
*
* @return NodeAction|boolean
*/
public function shift()
{
if ($this->isEmpty()) {
@ -97,6 +182,11 @@ class ProcessChanges
return array_shift($this->changes);
}
/**
* Get the last change on the stack, false if empty
*
* @return NodeAction|boolean
*/
public function pop()
{
if ($this->isEmpty()) {
@ -107,6 +197,11 @@ class ProcessChanges
return array_pop($this->changes);
}
/**
* The identifier used for this processes changes in our Session storage
*
* @return string
*/
protected function getSessionKey()
{
return $this->sessionKey;
@ -117,6 +212,9 @@ class ProcessChanges
return $this->hasBeenModified;
}
/**
* @return array
*/
public function serialize()
{
$serialized = array();
@ -127,6 +225,9 @@ class ProcessChanges
return $serialized;
}
/**
* Persist to session on destruction
*/
public function __destruct()
{
if (! $this->hasBeenModified()) {

View file

@ -0,0 +1,19 @@
<?php
namespace Icinga\Module\Businessprocess;
use Icinga\Module\Businessprocess\Html\Link;
abstract class MonitoredNode extends Node
{
abstract public function getUrl();
public function getLink()
{
if ($this->isMissing()) {
return Link::create($this->getAlias(), '#');
} else {
return Link::create($this->getAlias(), $this->getUrl());
}
}
}

View file

@ -2,10 +2,8 @@
namespace Icinga\Module\Businessprocess;
use Icinga\Web\Url;
use Icinga\Exception\ProgrammingError;
use Icinga\Data\Filter\Filter;
use Exception;
use Icinga\Module\Businessprocess\Html\Link;
abstract class Node
{
@ -24,7 +22,7 @@ abstract class Node
const ICINGA_UNREACHABLE = 2;
const ICINGA_PENDING = 99;
protected static $sortStateToStateMap = array(
protected $sortStateToStateMap = array(
4 => self::ICINGA_CRITICAL,
3 => self::ICINGA_UNKNOWN,
2 => self::ICINGA_WARNING,
@ -32,7 +30,7 @@ abstract class Node
0 => self::ICINGA_OK
);
protected static $stateToSortStateMap = array(
protected $stateToSortStateMap = array(
self::ICINGA_PENDING => 1,
self::ICINGA_UNKNOWN => 3,
self::ICINGA_CRITICAL => 4,
@ -43,7 +41,7 @@ abstract class Node
/**
* Main business process object
*
* @var BusinessProcess
* @var BpConfig
*/
protected $bp;
@ -96,7 +94,7 @@ abstract class Node
protected $className = 'unknown';
protected static $state_names = array(
protected $stateNames = array(
'OK',
'WARNING',
'CRITICAL',
@ -104,7 +102,7 @@ abstract class Node
99 => 'PENDING'
);
abstract public function __construct(BusinessProcess $bp, $object);
abstract public function __construct(BpConfig $bp, $object);
public function setMissing($missing = true)
{
@ -127,32 +125,38 @@ abstract class Node
return $this->missing;
}
public function hasMissingChildren()
{
return count($this->getMissingChildren()) > 0;
}
public function getMissingChildren()
{
return array();
}
public function hasInfoUrl()
{
return false;
}
public function addChild(Node $node)
{
if (array_key_exists((string) $node, $this->children)) {
throw new Exception(
sprintf(
'Node "%s" has been defined more than once',
$node
)
);
}
$this->childs[(string) $node] = $node;
$node->addParent($this);
return $this;
}
public function setState($state)
{
$this->state = (int) $state;
return $this;
}
/**
* Forget my state
*
* @return $this
*/
public function clearState()
{
$this->state = null;
return $this;
}
public function setAck($ack = true)
{
$this->ack = $ack;
@ -165,9 +169,19 @@ abstract class Node
return $this;
}
public function getStateName()
public function getStateName($state = null)
{
return static::$state_names[ $this->getState() ];
$states = $this->enumStateNames();
if ($state === null) {
return $states[ $this->getState() ];
} else {
return $states[ $state ];
}
}
public function enumStateNames()
{
return $this->stateNames;
}
public function getState()
@ -180,6 +194,7 @@ abstract class Node
)
);
}
return $this->state;
}
@ -238,16 +253,6 @@ abstract class Node
return $this->ack;
}
public function isSimulationMode()
{
return $this->bp->isSimulationMode();
}
public function isEditMode()
{
return $this->bp->isEditMode();
}
public function getChildren($filter = null)
{
return array();
@ -283,158 +288,90 @@ abstract class Node
return count($this->parents) > 0;
}
protected function stateToSortState($state)
public function hasParentName($name)
{
if (array_key_exists($state, static::$stateToSortStateMap)) {
return static::$stateToSortStateMap[$state];
foreach ($this->getParents() as $parent) {
if ($parent->getName() === $name) {
return true;
}
}
throw new ProgrammingError('Got invalid state %s', $sort_state);
return false;
}
public function removeParent($name)
{
$this->parents = array_filter(
$this->parents,
function (BpNode $parent) use ($name) {
return $parent->getName() !== $name;
}
);
}
/**
* @return BpNode[]
*/
public function getParents()
{
return $this->parents;
}
/**
* @return array
*/
public function getPaths()
{
if ($this->bp->hasRootNode($this->getName())) {
return array(array($this->getName()));
}
$paths = array();
foreach ($this->parents as $parent) {
foreach ($parent->getPaths() as $path) {
// $path[] = $this->getName();
$paths[] = $path;
}
}
// TODO! -> for delete etc
return $paths;
}
protected function stateToSortState($state)
{
if (array_key_exists($state, $this->stateToSortStateMap)) {
return $this->stateToSortStateMap[$state];
}
throw new ProgrammingError(
'Got invalid state for node %s: %s',
$this->getName(),
var_export($state, 1) . var_export($this->stateToSortStateMap, 1)
);
}
protected function sortStateTostate($sortState)
{
$sortState = $sortState >> self::SHIFT_FLAGS;
if (array_key_exists($sortState, static::$sortStateToStateMap)) {
return static::$sortStateToStateMap[$sortState];
if (array_key_exists($sortState, $this->sortStateToStateMap)) {
return $this->sortStateToStateMap[$sortState];
}
throw new ProgrammingError('Got invalid sorting state %s', $sort_state);
throw new ProgrammingError('Got invalid sorting state %s', $sortState);
}
protected function renderHtmlForChildren($view)
{
$html = '';
if ($this->hasChildren()) {
foreach ($this->getChildren() as $name => $child) {
$html .= '<tr><td>'
. $child->renderHtml($view)
. '</td></tr>';
}
}
return $html;
}
protected function getId($prefix = '')
{
return md5($prefix . (string) $this);
}
protected function getObjectClassName()
public function getObjectClassName()
{
return $this->className;
}
protected function getStateClassNames()
/**
* @return Link
*/
public function getLink()
{
$state = strtolower($this->getStateName());
if ($this->isMissing()) {
return array('missing');
} elseif ($state === 'ok') {
return array('ok');
} else {
return array('problem', $state);
}
}
public function renderHtml($view, $prefix = '')
{
$id = $this->getId($prefix);
$handled = $this->isAcknowledged() || $this->isInDowntime();
$html = sprintf(
'<table class="bp %s%s%s%s" id="%s"><tbody><tr>',
implode(' ', $this->getStateClassNames()),
$handled ? ' handled' : '',
($this->hasChildren() ? ' operator ' : ' node '),
$this->getObjectClassName(),
$id
);
if ($this->hasChildren()) {
$html .= sprintf(
'<th%s><span class="op">%s</span></th>',
sprintf(' rowspan="%d"', $this->countChildren() + 1),
$this->operatorHtml()
);
}
$title = preg_replace(
'~(</a>)~',
implode('', $this->getIcons($view)) . '$1',
$this->renderLink($view)
);
$title = preg_replace('#</a>#', ' ' . $view->timeSince($this->getLastStateChange()) . '</a>', $title);
$icons = array();
foreach ($this->getActionIcons($view) as $icon) {
$icons[] = $icon;
}
if ($this->hasInfoUrl()) {
$url = $this->getInfoUrl();
$icons[] = $this->actionIcon(
$view,
'help',
$url,
sprintf('%s: %s', mt('businessprocess', 'More information'), $url)
);
}
$title = implode("\n", $icons) . $title;
$html .= sprintf(
'<td>%s</td></tr>',
$title
);
foreach ($this->getChildren() as $name => $child) {
$html .= '<tr><td>' . $child->renderHtml($view, $id . '-') . '</td></tr>';
}
$html .= "</tbody></table>\n";
return $html;
}
protected function getActionIcons($view)
{
return array();
}
protected function actionIcon($view, $icon, $url, $title)
{
if ($url instanceof Url || ! preg_match('~^https?://~', $url)) {
$target = '';
} else {
$target = ' target="_blank"';
}
return sprintf(
' <a href="%s" %stitle="%s" style="float: right" data-base-target="bp-overlay">%s</a>',
$url,
$target,
$view->escape($title),
$view->icon($icon)
);
}
public function renderLink($view)
{
return '<a href="#">' . ($this->hasAlias() ? $this->getAlias() : $this->name) . '</a>';
}
public function getIcons($view)
{
$icons = array();
if ($this->isInDowntime()) {
$icons[] = $view->icon('moon');
}
if ($this->isAcknowledged()) {
$icons[] = $view->icon('ok');
}
return $icons;
return Link::create($this->getAlias(), '#');
}
public function operatorHtml()
@ -442,16 +379,18 @@ abstract class Node
return '&nbsp;';
}
public function toLegacyConfigString(& $rendered = array()) { return '';}
//abstract public function toLegacyConfigString();
public function __toString()
public function getName()
{
return $this->name;
}
public function __toString()
{
return $this->getName();
}
public function __destruct()
{
$this->parents = array();
unset($this->parents);
}
}

View file

@ -1,93 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess;
use Icinga\Exception\ProgrammingError;
abstract class NodeAction
{
const TYPE_CREATE = 'create';
const TYPE_REMOVE = 'remove';
const TYPE_MODIFY = 'modify';
const TYPE_CHILD_ADD = 'childRemove';
const TYPE_CHILD_REMOVE = 'childAdd';
protected $nodeName;
protected $actionName;
protected $preserveProperties = array();
public function __construct($node)
{
$this->nodeName = (string) $node;
}
abstract public function applyTo(BusinessProcess $bp);
public function getNodeName()
{
return $this->nodeName;
}
public function is($actionName)
{
return $this->getActionName() === $actionName;
}
public static function create($actionName, $nodeName)
{
$classname = __NAMESPACE__ . '\\Node' . ucfirst($actionName) . 'Action';
$object = new $classname($nodeName);
return $object;
}
public function serialize()
{
$object = (object) array(
'actionName' => $this->getActionName(),
'nodeName' => $this->getNodeName(),
'properties' => array()
);
foreach ($this->preserveProperties as $key) {
$func = 'get' . ucfirst($key);
$object->properties[$key] = $this->$func();
}
return json_encode($object);
}
public static function unserialize($string)
{
$object = json_decode($string);
$action = self::create($object->actionName, $object->nodeName);
foreach ($object->properties as $key => $val) {
$func = 'set' . ucfirst($key);
$action->$func($val);
}
return $action;
}
public function getActionName()
{
if ($this->actionName === null) {
if (! preg_match('/\\\Node(\w+)Action$/', get_class($this), $m)) {
throw new ProgrammingError(
'"%s" is not a NodeAction class',
get_class($this)
);
}
$this->actionName = lcfirst($m[1]);
}
return $this->actionName;
}
}

View file

@ -1,69 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess;
class NodeCreateAction extends NodeAction
{
protected $parentName;
protected $properties = array();
protected $preserveProperties = array('parentName', 'properties');
public function setParent(Node $name)
{
$this->parentName = $name;
}
public function hasParent()
{
return $this->parentName !== null;
}
public function getParentName()
{
return $this->parentName;
}
public function setParentName($name)
{
$this->parentName = $name;
}
public function getProperties()
{
return $this->properties;
}
public function setProperties($properties)
{
$this->properties = $properties;
return $this;
}
public function appliesTo(BusinessProcess $bp)
{
return ! $bp->hasNode($this->getNodeName());
}
public function applyTo(BusinessProcess $bp)
{
$node = new BpNode($bp, (object) array(
'name' => $this->getNodeName(),
'operator' => $this->properties->operator,
'child_names' => $this->properties->childNames
));
foreach ($this->properties as $key => $val) {
$func = 'set' . ucfirst($key);
$node->$func($val);
}
$bp->addNode($this->getNodeName(), $node);
if ($this->hasParent()) {
$node->addParent($bp->getNode($this->getParentName()));
}
return $node;
}
}

View file

@ -1,16 +0,0 @@
<?php
namespace Icinga\Module\Businessprocess;
class NodeRemoveAction extends NodeAction
{
public function appliesTo(BusinessProcess $bp)
{
return $bp->hasNode($this->getNodeName());
}
public function applyTo(BusinessProcess $bp)
{
$bp->removeNode($this->getNodeName());
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace Icinga\Module\Businessprocess\ProvidedHook\Monitoring;
use Icinga\Module\Monitoring\Hook\HostActionsHook;
use Icinga\Module\Monitoring\Object\Host;
class HostActions extends HostActionsHook
{
public function getActionsForHost(Host $host)
{
$label = mt('businessprocess', 'Business Impact');
return array(
$label => 'businessprocess/node/impact?name='
. rawurlencode($host->getName() . ';Hoststatus')
);
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace Icinga\Module\Businessprocess\ProvidedHook\Monitoring;
use Exception;
use Icinga\Application\Config;
use Icinga\Module\Monitoring\Hook\ServiceActionsHook;
use Icinga\Module\Monitoring\Object\Service;
use Icinga\Web\Url;
class ServiceActions extends ServiceActionsHook
{
public function getActionsForService(Service $service)
{
$label = mt('businessprocess', 'Business Impact');
return array(
$label => sprintf(
'businessprocess/node/impact?name=%s',
rawurlencode(
sprintf('%s;%s', $service->getHost()->getName(), $service->getName())
)
)
);
}
}

View file

@ -0,0 +1,66 @@
<?php
namespace Icinga\Module\Businessprocess\Renderer;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\Html\BaseElement;
use Icinga\Module\Businessprocess\Html\Element;
use Icinga\Module\Businessprocess\Html\Link;
use Icinga\Module\Businessprocess\Renderer\TileRenderer\NodeTile;
class Breadcrumb extends BaseElement
{
protected $tag = 'ul';
protected $defaultAttributes = array(
'class' => 'breadcrumb',
'data-base-target' => '_main'
);
/**
* @param Renderer $renderer
* @return static
*/
public static function create(Renderer $renderer)
{
$bp = $renderer->getBusinessProcess();
$breadcrumb = new static;
$bpUrl = $renderer->getBaseUrl();
if ($bpUrl->getParam('action') === 'delete') {
$bpUrl->remove('action');
}
$breadcrumb->add(Element::create('li')->add(
Link::create($bp->getTitle(), $bpUrl)
));
$path = $renderer->getCurrentPath();
$parts = array();
while ($node = array_pop($path)) {
array_unshift(
$parts,
static::renderNode($bp->getNode($node), $path, $renderer)
);
}
$breadcrumb->addContent($parts);
return $breadcrumb;
}
/**
* @param BpNode $node
* @param array $path
* @param Renderer $renderer
*
* @return NodeTile
*/
protected static function renderNode(BpNode $node, $path, Renderer $renderer)
{
// TODO: something more generic than NodeTile?
$renderer = clone($renderer);
$renderer->lock()->setIsBreadcrumb();
$p = new NodeTile($renderer, (string) $node, $node, $path);
$p->attributes()->add('class', $renderer->getNodeClasses($node));
$p->setTag('li');
return $p;
}
}

View file

@ -0,0 +1,328 @@
<?php
namespace Icinga\Module\Businessprocess\Renderer;
use Icinga\Date\DateFormatter;
use Icinga\Exception\ProgrammingError;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Html\Container;
use Icinga\Module\Businessprocess\Html\Element;
use Icinga\Module\Businessprocess\Html\Html;
use Icinga\Module\Businessprocess\Html\HtmlString;
use Icinga\Module\Businessprocess\Node;
use Icinga\Module\Businessprocess\Web\Url;
abstract class Renderer extends Html
{
/** @var BpConfig */
protected $config;
/** @var BpNode */
protected $parent;
/** @var bool Administrative actions are hidden unless unlocked */
protected $locked = true;
/** @var Url */
protected $url;
/** @var Url */
protected $baseUrl;
/** @var array */
protected $path = array();
/** @var bool */
protected $isBreadcrumb = false;
/**
* Renderer constructor.
*
* @param BpConfig $config
* @param BpNode|null $parent
*/
public function __construct(BpConfig $config, BpNode $parent = null)
{
$this->config = $config;
$this->parent = $parent;
}
/**
* @return BpConfig
*/
public function getBusinessProcess()
{
return $this->config;
}
/**
* Whether this will render all root nodes
*
* @return bool
*/
public function wantsRootNodes()
{
return $this->parent === null;
}
/**
* Whether this will only render parts of given config
*
* @return bool
*/
public function rendersSubNode()
{
return $this->parent !== null;
}
/**
* @return BpNode
*/
public function getParentNode()
{
return $this->parent;
}
/**
* @return BpNode[]
*/
public function getParentNodes()
{
if ($this->wantsRootNodes()) {
return array();
}
return $this->parent->getParents();
}
/**
* @return BpNode[]
*/
public function getChildNodes()
{
if ($this->wantsRootNodes()) {
return $this->config->getRootNodes();
} else {
return $this->parent->getChildren();
}
}
/**
* @return int
*/
public function countChildNodes()
{
if ($this->wantsRootNodes()) {
return $this->config->countChildren();
} else {
return $this->parent->countChildren();
}
}
/**
* @param $summary
* @return Container
*/
public function renderStateBadges($summary)
{
$container = Container::create(
array('class' => 'badges')
)/* ->renderIfEmpty(false) */;
foreach ($summary as $state => $cnt) {
if ($cnt === 0
|| $state === 'OK'
|| $state === 'UP'
) {
continue;
}
$container->addContent(
Element::create(
'span',
array(
'class' => array(
'badge',
'badge-' . strtolower($state)
),
// TODO: We should translate this in this module
'title' => mt('monitoring', $state)
)
)->setContent($cnt)
);
}
return $container;
}
public function getNodeClasses(Node $node)
{
$classes = array(
strtolower($node->getStateName())
);
if ($node->isHandled()) {
$classes[] = 'handled';
}
if ($node instanceof BpNode) {
$classes[] = 'process-node';
} else {
$classes[] = 'monitored-node';
}
return $classes;
}
public function setPath(array $path)
{
$this->path = $path;
return $this;
}
/**
* @return string|null
*/
public function getPath()
{
return $this->path;
}
public function getCurrentPath()
{
$path = $this->getPath();
if ($this->rendersSubNode()) {
$path[] = (string) $this->parent;
}
return $path;
}
/**
* @param Url $url
* @return $this
*/
public function setUrl(Url $url)
{
$this->url = $url->without(array(
'deletenode',
'deleteparent',
'editnode',
'simulationnode'
));
$this->setBaseUrl($url);
return $this;
}
/**
* @param Url $url
* @return $this
*/
public function setBaseUrl(Url $url)
{
$this->baseUrl = $url->without(array('node', 'path'));
return $this;
}
public function getUrl()
{
return $this->url;
}
/**
* @return Url
* @throws ProgrammingError
*/
public function getBaseUrl()
{
if ($this->baseUrl === null) {
throw new ProgrammingError('Renderer has no baseUrl');
}
return clone($this->baseUrl);
}
/**
* @return bool
*/
public function isLocked()
{
return $this->locked;
}
/**
* @return $this
*/
public function lock()
{
$this->locked = true;
return $this;
}
/**
* @return $this
*/
public function unlock()
{
$this->locked = false;
return $this;
}
/**
* TODO: Get rid of this
*
* @return $this
*/
public function setIsBreadcrumb()
{
$this->isBreadcrumb = true;
return $this;
}
public function isBreadcrumb()
{
return $this->isBreadcrumb;
}
public function timeSince($time, $timeOnly = false)
{
if (! $time) {
return HtmlString::create('');
}
return Element::create(
'span',
array(
'class' => array('relative-time', 'time-since'),
'title' => DateFormatter::formatDateTime($time),
)
)->setContent(DateFormatter::timeSince($time, $timeOnly));
}
protected function createUnboundParent(BpConfig $bp)
{
$unbound = $bp->getUnboundNodes();
$parent = new BpNode($bp, (object) array(
'name' => '__unbound__',
'operator' => '|',
'child_names' => array_keys($unbound)
));
$parent->getState();
$parent->setMissing()
->setDowntime(false)
->setAck(false)
->setAlias('Unbound nodes');
return $parent;
}
/**
* Just to be on the safe side
*/
public function __destruct()
{
unset($this->parent);
unset($this->config);
}
}

View file

@ -0,0 +1,113 @@
<?php
namespace Icinga\Module\Businessprocess\Renderer;
use Icinga\Module\Businessprocess\Html\Container;
use Icinga\Module\Businessprocess\Html\Icon;
use Icinga\Module\Businessprocess\Html\Link;
use Icinga\Module\Businessprocess\Renderer\TileRenderer\NodeTile;
class TileRenderer extends Renderer
{
/**
* @inheritdoc
*/
public function render()
{
$bp = $this->config;
$nodesDiv = Container::create(
array(
'class' => array(
'tiles',
$this->howMany()
),
'data-base-target' => '_self',
)
);
$nodes = $this->getChildNodes();
if (! $this->isLocked() && count($nodes) > 8) {
$this->add($this->addNewNode());
}
$path = $this->getCurrentPath();
foreach ($nodes as $name => $node) {
$this->add(new NodeTile($this, $name, $node, $path));
}
if ($this->wantsRootNodes()) {
$unbound = $this->createUnboundParent($bp);
if ($unbound->hasChildren()) {
$name = $unbound->getAlias();
$this->add(new NodeTile($this, $name, $unbound));
}
}
if (! $this->isLocked()) {
$this->add($this->addNewNode());
}
$nodesDiv->addContent($this->getContent());
$this->setContent($nodesDiv);
return parent::render();
}
/**
* A CSS class giving a rough indication of how many nodes we have
*
* This is used to show larger tiles when there are few and smaller
* ones if there are many.
*
* @return string
*/
protected function howMany()
{
$count = $this->countChildNodes();
$howMany = 'normal';
if ($count <= 6) {
$howMany = 'few';
} elseif ($count > 12) {
$howMany = 'many';
}
return $howMany;
}
protected function addNewNode()
{
$div = Container::create(
array('class' => 'addnew')
);
$actions = Container::create(
array(
'class' => 'actions',
'data-base-target' => '_self'
)
);
$link = Link::create(
$this->translate('Add'),
$this->getUrl()->with('action', 'add'),
null,
array(
'title' => $this->translate('Add a new business process node')
)
);
$actions->add(
Link::create(
Icon::create('plus'),
$this->getUrl()->with('action', 'add'),
null,
array(
'title' => $this->translate('Add a new business process node')
)
)
);
return $div->add($actions)->add($link);
}
}

View file

@ -0,0 +1,279 @@
<?php
namespace Icinga\Module\Businessprocess\Renderer\TileRenderer;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\HostNode;
use Icinga\Module\Businessprocess\Html\BaseElement;
use Icinga\Module\Businessprocess\Html\Container;
use Icinga\Module\Businessprocess\Html\HtmlString;
use Icinga\Module\Businessprocess\Html\Icon;
use Icinga\Module\Businessprocess\Html\Link;
use Icinga\Module\Businessprocess\ImportedNode;
use Icinga\Module\Businessprocess\MonitoredNode;
use Icinga\Module\Businessprocess\Node;
use Icinga\Module\Businessprocess\Renderer\Renderer;
use Icinga\Module\Businessprocess\ServiceNode;
class NodeTile extends BaseElement
{
protected $tag = 'div';
protected $renderer;
protected $name;
protected $node;
protected $path;
/**
* @var Container
*/
private $actions;
/**
* NodeTile constructor.
* @param Renderer $renderer
* @param $name
* @param Node $node
* @param null $path
*/
public function __construct(Renderer $renderer, $name, Node $node, $path = null)
{
$this->renderer = $renderer;
$this->name = $name;
$this->node = $node;
$this->path = $path;
}
protected function actions()
{
if ($this->actions === null) {
$this->addActions();
}
return $this->actions;
}
protected function addActions()
{
$this->actions = Container::create(
array(
'class' => 'actions',
'data-base-target' => '_self'
)
);
return $this->add($this->actions);
}
public function render()
{
$renderer = $this->renderer;
$node = $this->node;
$attributes = $this->attributes();
$attributes->add('class', $renderer->getNodeClasses($node));
$attributes->add('id', 'bp-' . (string) $node);
$this->addActions();
$link = $this->getMainNodeLink();
$this->add($link);
if ($node instanceof BpNode) {
if ($renderer->isBreadcrumb()) {
$link->addContent($renderer->renderStateBadges($node->getStateSummary()));
} else {
$this->addContent($renderer->renderStateBadges($node->getStateSummary()));
}
}
if (! $renderer->isBreadcrumb()) {
$this->addDetailsActions();
}
if (! $renderer->isLocked()) {
$this->addActionLinks();
}
return parent::render();
}
protected function getMainNodeUrl(Node $node)
{
if ($node instanceof BpNode) {
return $this->makeBpUrl($node);
} else {
/** @var MonitoredNode $node */
return $node->getUrl();
}
}
protected function buildBaseNodeUrl(Node $node)
{
$path = $this->path;
$name = $this->name; // TODO: ??
$renderer = $this->renderer;
$bp = $renderer->getBusinessProcess();
$params = array(
'config' => $node instanceof ImportedNode ?
$node->getConfigName() :
$bp->getName()
);
if ($name !== null) {
$params['node'] = $name;
}
$url = $renderer->getBaseUrl();
$p = $url->getParams();
$p->mergeValues($params);
if (! empty($path)) {
$p->addValues('path', $path);
}
return $url;
}
protected function makeBpUrl(BpNode $node)
{
return $this->buildBaseNodeUrl($node);
}
protected function makeMonitoredNodeUrl(MonitoredNode $node)
{
$path = $this->path;
$name = $this->name; // TODO: ??
$renderer = $this->renderer;
$bp = $renderer->getBusinessProcess();
$params = array(
'config' => $bp->getName()
);
if ($name !== null) {
$params['node'] = $node->getName();
}
$url = $renderer->getBaseUrl();
$p = $url->getParams();
$p->mergeValues($params);
if (! empty($path)) {
$p->addValues('path', $path);
}
return $url;
}
/**
* @return Link
*/
protected function getMainNodeLink()
{
$node = $this->node;
$url = $this->getMainNodeUrl($node);
if ($node instanceof ServiceNode) {
$link = Link::create(
$node->getAlias(),
$url,
null,
array('data-base-target' => '_next')
);
} elseif ($node instanceof HostNode) {
$link = Link::create(
$node->getHostname(),
$url,
null,
array('data-base-target' => '_next')
);
} else {
$link = Link::create($node->getAlias(), $url);
}
return $link;
}
protected function addDetailsActions()
{
$node = $this->node;
$url = $this->getMainNodeUrl($node);
if ($node instanceof BpNode) {
$this->actions()->add(Link::create(
Icon::create('dashboard'),
$url->with('mode', 'tile'),
null,
array(
'title' => $this->translate('Show tiles for this subtree'),
'data-base-target' => '_next'
)
))->add(Link::create(
Icon::create('sitemap'),
$url->with('mode', 'tree'),
null,
array(
'title' => $this->translate('Show this subtree as a tree'),
'data-base-target' => '_next'
)
));
} else {
// $url = $this->makeMonitoredNodeUrl($node);
if ($node instanceof ServiceNode) {
$this->actions()->add(Link::create(
Icon::create('service'),
$node->getUrl(),
null,
array('data-base-target' => '_next')
));
} elseif ($node instanceof HostNode) {
$this->actions()->add(Link::create(
Icon::create('host'),
$node->getUrl(),
null,
array('data-base-target' => '_next')
));
}
}
}
protected function addActionLinks()
{
$node = $this->node;
$renderer = $this->renderer;
if ($node instanceof BpNode) {
$this->actions()->add(Link::create(
Icon::create('edit'),
$renderer->getUrl()->with('action', 'edit')->with('editnode', $node->getName()),
null,
array('title' => $this->translate('Modify this business process node'))
));
} elseif ($node instanceof MonitoredNode) {
$this->actions()->add(Link::create(
Icon::create('magic'),
$renderer->getUrl()->with('action', 'simulation')
->with('simulationnode', $this->name),
null,
array('title' => $this->translate(
'Show the business impact of this node by simulating a specific state'
))
));
}
$params = array(
'action' => 'delete',
'deletenode' => $node->getName(),
);
$this->actions()->add(Link::create(
Icon::create('cancel'),
$renderer->getUrl()->with($params),
null,
array('title' => $this->translate('Delete this node'))
));
}
}

View file

@ -0,0 +1,250 @@
<?php
namespace Icinga\Module\Businessprocess\Renderer;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Html\Container;
use Icinga\Module\Businessprocess\Html\Element;
use Icinga\Module\Businessprocess\Html\Icon;
use Icinga\Module\Businessprocess\Html\Link;
use Icinga\Module\Businessprocess\Node;
use Icinga\Module\Businessprocess\Web\Url;
class TreeRenderer extends Renderer
{
/**
* @inheritdoc
*/
public function render()
{
$bp = $this->config;
$this->add(Container::create(
array(
'id' => $bp->getHtmlId(),
'class' => 'bp'
),
$this->renderBp($bp)
));
return parent::render();
}
/**
* @param BpConfig $bp
* @return string
*/
public function renderBp(BpConfig $bp)
{
$html = array();
if ($this->wantsRootNodes()) {
$nodes = $bp->getChildren();
} else {
$nodes = $this->parent->getChildren();
}
foreach ($nodes as $name => $node) {
$html[] = $this->renderNode($bp, $node);
}
return $html;
}
/**
* @param Node $node
* @param $path
* @return string
*/
protected function getId(Node $node, $path)
{
return md5(implode(';', $path) . (string) $node);
}
protected function getStateClassNames(Node $node)
{
$state = strtolower($node->getStateName());
if ($node->isMissing()) {
return array('missing');
} elseif ($state === 'ok') {
if ($node->hasMissingChildren()) {
return array('ok', 'missing-children');
} else {
return array('ok');
}
} else {
return array('problem', $state);
}
}
/**
* @param Node $node
* @return Icon[]
*/
public function getNodeIcons(Node $node)
{
$icons = array();
if ($node->isInDowntime()) {
$icons[] = Icon::create('moon');
}
if ($node->isAcknowledged()) {
$icons[] = Icon::create('ok');
}
return $icons;
}
/**
* @param BpConfig $bp
* @param Node $node
* @param array $path
*
* @return string
*/
public function renderNode(BpConfig $bp, Node $node, $path = array())
{
$table = Element::create(
'table',
array(
'id' => $this->getId($node, $path),
'class' => array(
'bp',
$node->getObjectClassName()
)
)
);
$attributes = $table->attributes();
$attributes->add('class', $this->getStateClassNames($node));
if ($node->isHandled()) {
$attributes->add('class', 'handled');
}
if ($node->hasChildren()) {
$attributes->add('class', 'operator');
} else {
$attributes->add('class', 'node');
}
$tbody = $table->createElement('tbody');
$tr = $tbody->createElement('tr');
if ($node->hasChildren()) {
$tr->createElement(
'th',
array(
'rowspan' => $node->countChildren() + 1 + ($this->isLocked() ? 0 : 1)
)
)->createElement(
'span',
array('class' => 'op')
)->setContent($node->operatorHtml());
}
$td = $tr->createElement('td');
if ($node instanceof BpNode && $node->hasInfoUrl()) {
$td->add($this->createInfoAction($node));
}
if (! $this->isLocked()) {
$td->addContent($this->getActionIcons($bp, $node));
}
$link = $node->getLink();
$link->attributes()->set('data-base-target', '_next');
$link->addContent($this->getNodeIcons($node));
if ($node->hasChildren()) {
$link->addContent($this->renderStateBadges($node->getStateSummary()));
}
if ($time = $node->getLastStateChange()) {
$since = $this->timeSince($time)->prependContent(
sprintf(' (%s ', $node->getStateName())
)->addContent(')');
$link->addContent($since);
}
$td->addContent($link);
foreach ($node->getChildren() as $name => $child) {
$tbody->createElement('tr')->createElement('td')->setContent(
$this->renderNode($bp, $child, $this->getCurrentPath())
);
}
if (! $this->isLocked() && $node instanceof BpNode) {
$tbody->createElement('tr')->createElement('td')->setContent(
$this->renderAddNewNode($node)
);
}
return $table;
}
protected function getActionIcons(BpConfig $bp, Node $node)
{
if ($node instanceof BpNode) {
return $this->createEditAction($bp, $node);
} else {
return $this->createSimulationAction($bp, $node);
}
}
protected function createEditAction(BpConfig $bp, BpNode $node)
{
return $this->actionIcon(
'wrench',
Url::fromPath('businessprocess/node/edit', array(
'config' => $bp->getName(),
'node' => $node->getName()
)),
$this->translate('Modify this node')
);
}
protected function createSimulationAction(BpConfig $bp, Node $node)
{
return $this->actionIcon(
'magic',
$this->getUrl()->with(array(
//'config' => $bp->getName(),
'action' => 'simulation',
'simulationnode' => $node->getName()
)),
$this->translate('Simulate a specific state')
);
}
protected function createInfoAction(BpNode $node)
{
$url = $node->getInfoUrl();
return $this->actionIcon(
'help',
$url,
sprintf('%s: %s', $this->translate('More information'), $url)
);
}
protected function actionIcon($icon, $url, $title)
{
return Link::create(
Icon::create($icon),
$url,
null,
array(
'title' => $title,
'style' => 'float: right',
)
);
}
protected function renderAddNewNode($parent)
{
return Link::create(
$this->translate('Add'),
$this->getUrl()->with('action', 'add')->with('node', $parent->getName()),
null,
array(
'class' => 'addnew icon-plus',
'title' => $this->translate('Add a new business process node')
)
);
}
}

View file

@ -2,9 +2,9 @@
namespace Icinga\Module\Businessprocess;
use Icinga\Web\Url;
use Icinga\Module\Businessprocess\Web\Url;
class ServiceNode extends Node
class ServiceNode extends MonitoredNode
{
protected $hostname;
@ -12,7 +12,7 @@ class ServiceNode extends Node
protected $className = 'service';
public function __construct(BusinessProcess $bp, $object)
public function __construct(BpConfig $bp, $object)
{
$this->name = $object->hostname . ';' . $object->service;
$this->hostname = $object->hostname;
@ -25,46 +25,6 @@ class ServiceNode extends Node
}
}
public function renderLink($view)
{
if ($this->isMissing()) {
return '<span class="missing">' . $view->escape($this->getAlias()) . '</span>';
}
$params = array(
'host' => $this->getHostname(),
'service' => $this->getServiceDescription()
);
if ($this->bp->hasBackendName()) {
$params['backend'] = $this->bp->getBackendName();
}
$link = $view->qlink($this->getAlias(), 'monitoring/service/show', $params);
return $link;
}
protected function getActionIcons($view)
{
$icons = array();
if (! $this->bp->isLocked()) {
$url = Url::fromPath( 'businessprocess/node/simulate', array(
'config' => $this->bp->getName(),
'node' => $this->name
));
$icons[] = $this->actionIcon(
$view,
'magic',
$url,
'Simulation'
);
}
return $icons;
}
public function getHostname()
{
return $this->hostname;
@ -79,4 +39,18 @@ class ServiceNode extends Node
{
return $this->hostname . ': ' . $this->service;
}
public function getUrl()
{
$params = array(
'host' => $this->getHostname(),
'service' => $this->getServiceDescription()
);
if ($this->bp->hasBackendName()) {
$params['backend'] = $this->bp->getBackendName();
}
return Url::fromPath('monitoring/service/show', $params);
}
}

View file

@ -2,17 +2,18 @@
namespace Icinga\Module\Businessprocess;
use Icinga\Exception\ProgrammingError;
use Icinga\Web\Session\SessionNamespace;
class Simulation
{
/**
* @var Session
* @var SessionNamespace
*/
protected $session;
/**
* @var BusinessProcess
* @var BpConfig
*/
protected $bp;
@ -21,9 +22,12 @@ class Simulation
*/
protected $key;
/**
* @var
*/
protected $simulations;
public function __construct(BusinessProcess $bp, SessionNamespace $session)
public function __construct(BpConfig $bp, SessionNamespace $session)
{
$this->bp = $bp;
$this->session = $session;

View file

@ -0,0 +1,133 @@
<?php
namespace Icinga\Module\Businessprocess\State;
use Exception;
use Icinga\Application\Benchmark;
use Icinga\Data\Filter\Filter;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
class MonitoringState
{
/** @var BpConfig */
protected $config;
/** @var MonitoringBackend */
protected $backend;
private function __construct(BpConfig $config)
{
$this->config = $config;
$this->backend = $config->getBackend();
}
public static function apply(BpConfig $config)
{
$self = new static($config);
$self->retrieveStatesFromBackend();
return $config;
}
public function retrieveStatesFromBackend()
{
$config = $this->config;
try {
$this->reallyRetrieveStatesFromBackend();
} catch (Exception $e) {
$config->addError(
$config->translate('Could not retrieve process state: %s'),
$e->getMessage()
);
}
}
public function reallyRetrieveStatesFromBackend()
{
$config = $this->config;
Benchmark::measure('Retrieving states for business process ' . $config->getName());
$backend = $this->backend;
$hostFilter = $config->listInvolvedHostNames();
if ($config->usesHardStates()) {
$hostStateColumn = 'host_hard_state';
$hostStateChangeColumn = 'host_last_hard_state_change';
$serviceStateColumn = 'service_hard_state';
$serviceStateChangeColumn = 'service_last_hard_state_change';
} else {
$hostStateColumn = 'host_state';
$hostStateChangeColumn = 'host_last_state_change';
$serviceStateColumn = 'service_state';
$serviceStateChangeColumn = 'service_last_state_change';
}
$filter = Filter::matchAny();
foreach ($hostFilter as $host) {
$filter->addFilter(Filter::where('host_name', $host));
}
if ($filter->isEmpty()) {
return $this;
}
$hostStatus = $backend->select()->from('hostStatus', array(
'hostname' => 'host_name',
'last_state_change' => $hostStateChangeColumn,
'in_downtime' => 'host_in_downtime',
'ack' => 'host_acknowledged',
'state' => $hostStateColumn
))->applyFilter($filter)->getQuery()->fetchAll();
$serviceStatus = $backend->select()->from('serviceStatus', array(
'hostname' => 'host_name',
'service' => 'service_description',
'last_state_change' => $serviceStateChangeColumn,
'in_downtime' => 'service_in_downtime',
'ack' => 'service_acknowledged',
'state' => $serviceStateColumn
))->applyFilter($filter)->getQuery()->fetchAll();
foreach ($serviceStatus as $row) {
$this->handleDbRow($row, $config);
}
foreach ($hostStatus as $row) {
$this->handleDbRow($row, $config);
}
// TODO: Union, single query?
Benchmark::measure('Got states for business process ' . $config->getName());
return $this;
}
protected function handleDbRow($row, BpConfig $config)
{
$key = $row->hostname;
if (property_exists($row, 'service')) {
$key .= ';' . $row->service;
} else {
$key .= ';Hoststatus';
}
// We fetch more states than we need, so skip unknown ones
if (! $config->hasNode($key)) {
return;
}
$node = $config->getNode($key);
if ($row->state !== null) {
$node->setState($row->state)->setMissing(false);
}
if ($row->last_state_change !== null) {
$node->setLastStateChange($row->last_state_change);
}
if ((int) $row->in_downtime === 1) {
$node->setDowntime(true);
}
if ((int) $row->ack === 1) {
$node->setAck(true);
}
}
}

View file

@ -0,0 +1,91 @@
<?php
namespace Icinga\Module\Businessprocess\Storage;
use Diff;
use Diff_Renderer_Html_Inline;
use Diff_Renderer_Html_SideBySide;
use Diff_Renderer_Text_Context;
use Diff_Renderer_Text_Unified;
use Icinga\Module\Businessprocess\Html\Renderable;
class ConfigDiff implements Renderable
{
protected $a;
protected $b;
protected $diff;
protected $opcodes;
protected function __construct($a, $b)
{
$this->requireVendorLib('Diff.php');
if (empty($a)) {
$this->a = array();
} else {
$this->a = explode("\n", (string) $a);
}
if (empty($b)) {
$this->b = array();
} else {
$this->b = explode("\n", (string) $b);
}
$options = array(
'context' => 5,
// 'ignoreWhitespace' => true,
// 'ignoreCase' => true,
);
$this->diff = new Diff($this->a, $this->b, $options);
}
/**
* @return string
*/
public function render()
{
return $this->renderHtmlSideBySide();
}
public function renderHtmlSideBySide()
{
$this->requireVendorLib('Diff/Renderer/Html/SideBySide.php');
$renderer = new Diff_Renderer_Html_SideBySide;
return $this->diff->render($renderer);
}
public function renderHtmlInline()
{
$this->requireVendorLib('Diff/Renderer/Html/Inline.php');
$renderer = new Diff_Renderer_Html_Inline;
return $this->diff->render($renderer);
}
public function renderTextContext()
{
$this->requireVendorLib('Diff/Renderer/Text/Context.php');
$renderer = new Diff_Renderer_Text_Context;
return $this->diff->render($renderer);
}
public function renderTextUnified()
{
$this->requireVendorLib('Diff/Renderer/Text/Unified.php');
$renderer = new Diff_Renderer_Text_Unified;
return $this->diff->render($renderer);
}
protected function requireVendorLib($file)
{
require_once dirname(dirname(__DIR__)) . '/vendor/php-diff/lib/' . $file;
}
public static function create($a, $b)
{
$diff = new static($a, $b);
return $diff;
}
}

View file

@ -0,0 +1,343 @@
<?php
namespace Icinga\Module\Businessprocess\Storage;
use Icinga\Application\Benchmark;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\SystemPermissionException;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\Metadata;
class LegacyConfigParser
{
/** @var int */
protected $currentLineNumber;
/** @var string */
protected $currentFilename;
protected $name;
/** @var BpConfig */
protected $config;
/**
* LegacyConfigParser constructor
*
* @param $name
*/
private function __construct($name)
{
$this->name = $name;
$this->config = new BpConfig();
$this->config->setName($name);
}
/**
* @return BpConfig
*/
public function getParsedConfig()
{
return $this->config;
}
/**
* @param $name
* @param $filename
*
* @return BpConfig
*/
public static function parseFile($name, $filename)
{
Benchmark::measure('Loading business process ' . $name);
$parser = new static($name);
$parser->reallyParseFile($filename);
Benchmark::measure('Business process ' . $name . ' loaded');
return $parser->getParsedConfig();
}
/**
* @param $name
* @param $string
*
* @return BpConfig
*/
public static function parseString($name, $string)
{
Benchmark::measure('Loading BP config from file: ' . $name);
$parser = new static($name);
foreach (preg_split('/\n/', $string) as $line) {
$parser->parseLine($line);
}
Benchmark::measure('Business process ' . $name . ' loaded');
return $parser->getParsedConfig();
}
protected function reallyParseFile($filename)
{
$file = $this->currentFilename = $filename;
$fh = @fopen($file, 'r');
if (! $fh) {
throw new SystemPermissionException('Could not open "%s"', $filename);
}
$config = $this->config;
$config->setMetadata(
$this::readMetadataFromFileHeader($config->getName(), $filename)
);
$this->currentLineNumber = 0;
while ($line = fgets($fh)) {
$this->parseLine($line);
}
fclose($fh);
unset($this->currentLineNumber);
unset($this->currentFilename);
}
public static function readMetadataFromFileHeader($name, $filename)
{
$metadata = new Metadata($name);
$fh = fopen($filename, 'r');
$cnt = 0;
while ($cnt < 15 && false !== ($line = fgets($fh))) {
$cnt++;
static::parseHeaderLine($line, $metadata);
}
fclose($fh);
return $metadata;
}
protected function splitCommaSeparated($string)
{
return preg_split('/\s*,\s*/', $string, -1, PREG_SPLIT_NO_EMPTY);
}
protected function readHeaderString($string, Metadata $metadata)
{
foreach (preg_split('/\n/', $string) as $line) {
$this->parseHeaderLine($line, $metadata);
}
return $metadata;
}
/**
* @return array
*/
protected function emptyHeader()
{
return array(
'Title' => null,
'Description' => null,
'Owner' => null,
'AllowedUsers' => null,
'AllowedGroups' => null,
'AllowedRoles' => null,
'Backend' => null,
'Statetype' => 'soft',
'SLAHosts' => null
);
}
/**
* @param $line
* @param Metadata $metadata
*/
protected static function parseHeaderLine($line, Metadata $metadata)
{
if (preg_match('/^\s*#\s+(.+?)\s*:\s*(.+)$/', $line, $m)) {
if ($metadata->hasKey($m[1])) {
$metadata->set($m[1], $m[2]);
}
}
}
/**
* @param $line
* @param BpConfig $bp
*/
protected function parseDisplay(& $line, BpConfig $bp)
{
list($display, $name, $desc) = preg_split('~\s*;\s*~', substr($line, 8), 3);
$bp->getBpNode($name)->setAlias($desc)->setDisplay($display);
if ($display > 0) {
$bp->addRootNode($name);
}
}
/**
* @param $line
* @param BpConfig $bp
*/
protected function parseExternalInfo(& $line, BpConfig $bp)
{
list($name, $script) = preg_split('~\s*;\s*~', substr($line, 14), 2);
$bp->getBpNode($name)->setInfoCommand($script);
}
protected function parseExtraInfo(& $line, BpConfig $bp)
{
// TODO: Not yet
// list($name, $script) = preg_split('~\s*;\s*~', substr($line, 14), 2);
// $this->getNode($name)->setExtraInfo($script);
}
protected function parseInfoUrl(& $line, BpConfig $bp)
{
list($name, $url) = preg_split('~\s*;\s*~', substr($line, 9), 2);
$bp->getBpNode($name)->setInfoUrl($url);
}
protected function parseExtraLine(& $line, $typeLength, BpConfig $bp)
{
$type = substr($line, 0, $typeLength);
if (substr($type, 0, 7) === 'display') {
$this->parseDisplay($line, $bp);
return true;
}
switch ($type) {
case 'external_info':
$this->parseExternalInfo($line, $bp);
break;
case 'extra_info':
$this->parseExtraInfo($line, $bp);
break;
case 'info_url':
$this->parseInfoUrl($line, $bp);
break;
default:
return false;
}
return true;
}
/**
* Parses a single line
*
* Adds eventual new knowledge to the given Business Process config
*
* @param $line
*
* @throws ConfigurationError
*/
protected function parseLine(& $line)
{
$bp = $this->config;
$line = trim($line);
$this->currentLineNumber++;
// Skip empty or comment-only lines
if (empty($line) || $line[0] === '#') {
return;
}
// Semicolon found in the first 14 cols? Might be a line with extra information
$pos = strpos($line, ';');
if ($pos !== false && $pos < 14) {
if ($this->parseExtraLine($line, $pos, $bp)) {
return;
}
}
list($name, $value) = preg_split('~\s*=\s*~', $line, 2);
if (strpos($name, ';') !== false) {
$this->parseError('No semicolon allowed in varname');
}
$op = '&';
if (preg_match_all('~([\|\+&\!])~', $value, $m)) {
$op = implode('', $m[1]);
for ($i = 1; $i < strlen($op); $i++) {
if ($op[$i] !== $op[$i - 1]) {
$this->parseError('Mixing operators is not allowed');
}
}
}
$op = $op[0];
$op_name = $op;
if ($op === '+') {
if (! preg_match('~^(\d+)(?::(\d+))?\s*of:\s*(.+?)$~', $value, $m)) {
$this->parseError('syntax: <var> = <num> of: <var1> + <var2> [+ <varn>]*');
}
$op_name = $m[1];
// New feature: $minWarn = $m[2];
$value = $m[3];
}
$cmps = preg_split('~\s*\\' . $op . '\s*~', $value, -1, PREG_SPLIT_NO_EMPTY);
$childNames = array();
foreach ($cmps as $val) {
if (strpos($val, ';') !== false) {
if ($bp->hasNode($val)) {
$childNames[] = $val;
continue;
}
list($host, $service) = preg_split('~;~', $val, 2);
if ($service === 'Hoststatus') {
$bp->createHost($host);
} else {
$bp->createService($host, $service);
}
}
if ($val[0] === '@') {
if (strpos($val, ':') === false) {
throw new ConfigurationError(
"I'm unable to import full external configs, a node needs to be provided for '%s'",
$val
);
// TODO: this might work:
// $node = $bp->createImportedNode(substr($val, 1));
} else {
list($config, $nodeName) = preg_split('~:\s*~', substr($val, 1), 2);
$node = $bp->createImportedNode($config, $nodeName);
}
$val = $node->getName();
}
$childNames[] = $val;
}
$node = new BpNode($bp, (object) array(
'name' => $name,
'operator' => $op_name,
'child_names' => $childNames
));
$bp->addNode($name, $node);
}
/**
* @return string
*/
public function getFilename()
{
return $this->currentFilename ?: '[given string]';
}
/**
* @param $msg
* @throws ConfigurationError
*/
protected function parseError($msg)
{
throw new ConfigurationError(
sprintf(
'Parse error on %s:%s: %s',
$this->getFilename(),
$this->currentLineNumber,
$msg
)
);
}
}

View file

@ -0,0 +1,229 @@
<?php
namespace Icinga\Module\Businessprocess\Storage;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\BpConfig;
class LegacyConfigRenderer
{
/** @var array */
protected $renderedNodes;
/**
* LecagyConfigRenderer constructor
*
* @param BpConfig $config
*/
public function __construct(BpConfig $config)
{
$this->config = $config;
}
/**
* @return string
*/
public function render()
{
return $this->renderHeader() . $this->renderNodes();
}
/**
* @param BpConfig $config
* @return mixed
*/
public static function renderConfig(BpConfig $config)
{
$renderer = new static($config);
return $renderer->render();
}
/**
* @return string
*/
public function renderHeader()
{
$str = "### Business Process Config File ###\n#\n";
$meta = $this->config->getMetadata();
foreach ($meta->getProperties() as $key => $value) {
if ($value === null) {
continue;
}
$str .= sprintf("# %-15s : %s\n", $key, $value);
}
$str .= "#\n###################################\n\n";
return $str;
}
/**
* @return string
*/
public function renderNodes()
{
$this->renderedNodes = array();
$config = $this->config;
$str = '';
foreach ($config->getRootNodes() as $node) {
$str .= $this->requireRenderedBpNode($node);
}
foreach ($config->getUnboundNodes() as $name => $node) {
$str .= $this->requireRenderedBpNode($node);
}
return $str . "\n";
}
/**
* Rendered node definition, empty string if already rendered
*
* @param BpNode $node
*
* @return string
*/
protected function requireRenderedBpNode(BpNode $node)
{
$name = $node->getName();
if (array_key_exists($name, $this->renderedNodes)) {
return '';
} else {
$this->renderedNodes[$name] = true;
return $this->renderBpNode($node);
}
}
/**
* @param BpNode $node
* @return string
*/
protected function renderBpNode(BpNode $node)
{
$name = $node->getName();
// Doing this before rendering children allows us to store loops
$cfg = '';
foreach ($node->getChildBpNodes() as $name => $child) {
$cfg .= $this->requireRenderedBpNode($child) . "\n";
}
$cfg .= static::renderSingleBpNode($node);
return $cfg;
}
/**
* @param BpNode $node
* @return string
*/
public static function renderEqualSign(BpNode $node)
{
$op = $node->getOperator();
if (is_numeric($op)) {
return '= ' . $op . ' of:';
} else {
return '=';
}
}
/**
* @param BpNode $node
* @return string
*/
public static function renderOperator(BpNode $node)
{
$op = $node->getOperator();
if (is_numeric($op)) {
return '+';
} else {
return $op;
}
}
/**
* @param BpNode $node
* @return string
*/
public static function renderSingleBpNode(BpNode $node)
{
return static::renderExpression($node)
. static::renderDisplay($node)
. static::renderInfoUrl($node);
}
/**
* @param BpNode $node
* @return string
*/
public static function renderExpression(BpNode $node)
{
return sprintf(
"%s %s %s\n",
$node->getName(),
static::renderEqualSign($node),
static::renderChildNames($node)
);
}
/**
* @param BpNode $node
* @return string
*/
public static function renderChildNames(BpNode $node)
{
$op = static::renderOperator($node);
$children = $node->getChildNames();
$str = implode(' ' . $op . ' ', $children);
if ((count($children) < 2) && $op !== '&') {
return $op . ' ' . $str;
} else {
return $str;
}
}
/**
* @param BpNode $node
* @return string
*/
public static function renderDisplay(BpNode $node)
{
if ($node->hasAlias() || $node->getDisplay() > 0) {
$prio = $node->getDisplay();
return sprintf(
"display %s;%s;%s\n",
$prio,
$node->getName(),
$node->getAlias()
);
} else {
return '';
}
}
/**
* @param BpNode $node
* @return string
*/
public static function renderInfoUrl(BpNode $node)
{
if ($node->hasInfoUrl()) {
return sprintf(
"info_url;%s;%s\n",
$node->getName(),
$node->getInfoUrl()
);
} else {
return '';
}
}
}

View file

@ -2,109 +2,153 @@
namespace Icinga\Module\Businessprocess\Storage;
use Icinga\Application\Icinga;
use Icinga\Data\ConfigObject;
use Icinga\Exception\ConfigurationError;
use Icinga\Module\Businessprocess\BusinessProcess;
use Icinga\Module\Businessprocess\BpNode;
use Icinga\Module\Businessprocess\Storage\Storage;
use DirectoryIterator;
use Icinga\Application\Icinga;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Exception\SystemPermissionException;
use Icinga\Application\Benchmark;
class LegacyStorage extends Storage
{
/** @var string */
protected $configDir;
protected $parsing_line_number;
protected $currentFilename;
public function getConfigDir()
{
if ($this->configDir === null) {
$dir = Icinga::app()
->getModuleManager()
->getModule('businessprocess')
->getConfigDir();
// TODO: This is silly. We need Config::requireDirectory().
if (! is_dir($dir)) {
if (! is_dir(dirname($dir))) {
if (! @mkdir(dirname($dir))) {
throw new SystemPermissionException('Could not create config directory "%s"', dirname($dir));
}
}
if (! mkdir($dir)) {
throw new SystemPermissionException('Could not create config directory "%s"', $dir);
}
}
$dir = $dir . '/processes';
if (! is_dir($dir)) {
if (! mkdir($dir)) {
throw new SystemPermissionException('Could not create config directory "%s"', $dir);
}
}
$this->configDir = $dir;
$this->prepareDefaultConfigDir();
}
return $this->configDir;
}
protected function prepareDefaultConfigDir()
{
$dir = Icinga::app()
->getModuleManager()
->getModule('businessprocess')
->getConfigDir();
// TODO: This is silly. We need Config::requireDirectory().
if (! is_dir($dir)) {
if (! is_dir(dirname($dir))) {
if (! @mkdir(dirname($dir))) {
throw new SystemPermissionException('Could not create config directory "%s"', dirname($dir));
}
}
if (! mkdir($dir)) {
throw new SystemPermissionException('Could not create config directory "%s"', $dir);
}
}
$dir = $dir . '/processes';
if (! is_dir($dir)) {
if (! mkdir($dir)) {
throw new SystemPermissionException('Could not create config directory "%s"', $dir);
}
}
$this->configDir = $dir;
}
/**
* @return array
* @inheritdoc
*/
public function listProcesses()
{
$files = array();
foreach (new DirectoryIterator($this->getConfigDir()) as $file) {
if($file->isDot()) continue;
$filename = $file->getFilename();
if (substr($filename, -5) === '.conf') {
$name = substr($filename, 0, -5);
$header = $this->readHeader($file->getPathname(), $name);
if ($header['Title'] === null) {
$files[$name] = $name;
} else {
$files[$name] = sprintf('%s (%s)', $header['Title'], $name);
}
foreach ($this->listAllProcessNames() as $name) {
$meta = $this->loadMetadata($name);
if (! $meta->canRead()) {
continue;
}
$files[$name] = $meta->getExtendedTitle();
}
natsort($files);
natcasesort($files);
return $files;
}
protected function readHeader($file, $name)
/**
* @inheritdoc
*/
public function listProcessNames()
{
$fh = fopen($file, 'r');
$cnt = 0;
$header = array(
'Title' => null,
'Owner' => null,
'Backend' => null,
'Statetype' => 'soft',
'SLA Hosts' => null
);
while ($cnt < 15 && false !== ($line = fgets($fh))) {
$cnt++;
if (preg_match('/^\s*#\s+(.+?)\s*:\s*(.+)$/', $line, $m)) {
if (array_key_exists($m[1], $header)) {
$header[$m[1]] = $m[2];
}
$files = array();
foreach ($this->listAllProcessNames() as $name) {
$meta = $this->loadMetadata($name);
if (! $meta->canRead()) {
continue;
}
$files[$name] = $name;
}
return $header;
natcasesort($files);
return $files;
}
/**
* @inheritdoc
*/
public function storeProcess(BusinessProcess $process)
public function listAllProcessNames()
{
$files = array();
foreach (new DirectoryIterator($this->getConfigDir()) as $file) {
if ($file->isDot()) {
continue;
}
$filename = $file->getFilename();
if (substr($filename, -5) === '.conf') {
$files[] = substr($filename, 0, -5);
}
}
natcasesort($files);
return $files;
}
/**
* @inheritdoc
*/
public function loadProcess($name)
{
return LegacyConfigParser::parseFile(
$name,
$this->getFilename($name)
);
}
/**
* @inheritdoc
*/
public function storeProcess(BpConfig $process)
{
$filename = $this->getFilename($process->getName());
$content = $process->toLegacyConfigString();
file_put_contents(
$filename,
$content
$this->getFilename($process->getName()),
LegacyConfigRenderer::renderConfig($process)
);
}
/**
* @inheritdoc
*/
public function deleteProcess($name)
{
return @unlink($this->getFilename($name));
}
/**
* @inheritdoc
*/
public function loadMetadata($name)
{
return LegacyConfigParser::readMetadataFromFileHeader(
$name,
$this->getFilename($name)
);
}
@ -118,176 +162,28 @@ class LegacyStorage extends Storage
return $this->getConfigDir() . '/' . $name . '.conf';
}
/**
* @param $name
* @param $string
*
* @return BpConfig
*/
public function loadFromString($name, $string)
{
$bp = new BusinessProcess();
$bp->setName($name);
$this->parseString($string, $bp);
$this->loadHeader($name, $bp);
return $bp;
}
public function deleteProcess($name)
{
unlink($this->getFilename($name));
return LegacyConfigParser::parseString($name, $string);
}
/**
* @return BusinessProcess
* @param $name
* @return bool
*/
public function loadProcess($name)
public function hasProcess($name)
{
Benchmark::measure('Loading business process ' . $name);
$bp = new BusinessProcess();
$bp->setName($name);
$this->parseFile($name, $bp);
$this->loadHeader($name, $bp);
Benchmark::measure('Business process ' . $name . ' loaded');
return $bp;
}
protected function loadHeader($name, $bp)
{
// TODO: do not open twice, this is quick and dirty based on existing code
$file = $this->currentFilename = $this->getFilename($name);
$header = $this->readHeader($file, $name);
$bp->setTitle($header['Title']);
if ($header['Backend']) {
$bp->setBackendName($header['Backend']);
}
if ($header['Statetype'] === 'soft') {
$bp->useSoftStates();
}
}
protected function parseFile($name, $bp)
{
$file = $this->currentFilename = $this->getFilename($name);
$fh = @fopen($file, 'r');
if (! $fh) {
throw new SystemPermissionException('Could not open "%s"', $file);
$file = $this->getFilename($name);
if (! is_file($file)) {
return false;
}
$this->parsing_line_number = 0;
while ($line = fgets($fh)) {
$this->parseLine($line, $bp);
}
fclose($fh);
unset($this->parsing_line_number);
unset($this->currentFilename);
}
protected function parseString($string, $bp)
{
foreach (preg_split('/\n/', $string) as $line) {
$this->parseLine($line, $bp);
}
}
protected function parseLine(& $line, $bp)
{
$line = trim($line);
$this->parsing_line_number++;
if (empty($line)) {
return;
}
if ($line[0] === '#') {
return;
}
// TODO: substr?
if (preg_match('~^display~', $line)) {
list($display, $name, $desc) = preg_split('~\s*;\s*~', substr($line, 8), 3);
$node = $bp->getNode($name)->setAlias($desc)->setDisplay($display);
if ($display > 0) {
$bp->addRootNode($name);
}
return;
}
if (preg_match('~^external_info~', $line)) {
list($name, $script) = preg_split('~\s*;\s*~', substr($line, 14), 2);
$node = $bp->getNode($name)->setInfoCommand($script);
return;
}
// New feature:
// if (preg_match('~^extra_info~', $line)) {
// list($name, $script) = preg_split('~\s*;\s*~', substr($line, 14), 2);
// $node = $this->getNode($name)->setExtraInfo($script);
// }
if (preg_match('~^info_url~', $line)) {
list($name, $url) = preg_split('~\s*;\s*~', substr($line, 9), 2);
$node = $bp->getNode($name)->setInfoUrl($url);
return;
}
list($name, $value) = preg_split('~\s*=\s*~', $line, 2);
if (strpos($name, ';') !== false) {
$this->parseError('No semicolon allowed in varname');
}
$op = '&';
if (preg_match_all('~([\|\+&\!])~', $value, $m)) {
$op = implode('', $m[1]);
for ($i = 1; $i < strlen($op); $i++) {
if ($op[$i] !== $op[$i - 1]) {
$this->parseError('Mixing operators is not allowed');
}
}
}
$op = $op[0];
$op_name = $op;
if ($op === '+') {
if (! preg_match('~^(\d+)\s*of:\s*(.+?)$~', $value, $m)) {
$this->parseError('syntax: <var> = <num> of: <var1> + <var2> [+ <varn>]*');
}
$op_name = $m[1];
$value = $m[2];
}
$cmps = preg_split('~\s*\\' . $op . '\s*~', $value, -1, PREG_SPLIT_NO_EMPTY);
foreach ($cmps as & $val) {
if (strpos($val, ';') !== false) {
if ($bp->hasNode($val)) continue;
list($host, $service) = preg_split('~;~', $val, 2);
if ($service === 'Hoststatus') {
$bp->createHost($host);
} else {
$bp->createService($host, $service);
}
}
if ($val[0] === '@' && strpos($val, ':') !== false) {
list($config, $nodeName) = preg_split('~:\s*~', substr($val, 1), 2);
$bp->createImportedNode($config, $nodeName);
$val = $nodeName;
}
}
$node = new BpNode($bp, (object) array(
'name' => $name,
'operator' => $op_name,
'child_names' => $cmps
));
$bp->addNode($name, $node);
}
protected function parseError($msg)
{
throw new ConfigurationError(
sprintf(
'Parse error on %s:%s: %s',
$this->currentFilename,
$this->parsing_line_number,
$msg
)
);
return $this->loadMetadata($name)->canRead();
}
}

View file

@ -3,12 +3,20 @@
namespace Icinga\Module\Businessprocess\Storage;
use Icinga\Data\ConfigObject;
use Icinga\Module\Businessprocess\BusinessProcess;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Metadata;
abstract class Storage
{
/**
* @var ConfigObject
*/
protected $config;
/**
* Storage constructor.
* @param ConfigObject $config
*/
public function __construct(ConfigObject $config)
{
$this->config = $config;
@ -20,18 +28,65 @@ abstract class Storage
}
/**
* All processes readable by the current user
*
* The returned array has the form <process name> => <nice title>, sorted
* by title
*
* @return array
*/
abstract public function listProcesses();
/**
* @return BusinessProcess
* All process names readable by the current user
*
* The returned array has the form <process name> => <process name> and is
* sorted
*
* @return array
*/
abstract public function listProcessNames();
/**
* All available process names, regardless of eventual restrictions
*
* @return array
*/
abstract public function listAllProcessNames();
/**
* Whether a configuration with the given name exists
*
* @param $name
*
* @return bool
*/
abstract public function hasProcess($name);
/**
* @param $name
* @return BpConfig
*/
abstract public function loadProcess($name);
/**
* Store eventual changes applied to the given configuration
*
* @param BpConfig $config
*
* @return mixed
*/
abstract public function storeProcess(BusinessProcess $name);
abstract public function storeProcess(BpConfig $config);
/**
* @param $name
* @return bool Whether the process has been deleted
*/
abstract public function deleteProcess($name);
/**
* @param string $name
* @return Metadata
*/
abstract public function loadMetadata($name);
}

View file

@ -0,0 +1,76 @@
<?php
namespace Icinga\Module\Businessprocess\Test;
use Icinga\Application\Config;
use Icinga\Application\ApplicationBootstrap;
use Icinga\Application\Icinga;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Icinga\Module\Businessprocess\Web\FakeRequest;
use PHPUnit_Framework_TestCase;
abstract class BaseTestCase extends PHPUnit_Framework_TestCase
{
/** @var ApplicationBootstrap */
private static $app;
/**
* @inheritdoc
*/
public function setUp()
{
$this->app();
FakeRequest::setConfiguredBaseUrl('/icingaweb2/');
}
protected function emptyConfigSection()
{
return Config::module('businessprocess')->getSection('global');
}
/***
* @return BpConfig
*/
protected function makeLoop()
{
return $this->makeInstance()->loadFromString(
'loop',
"a = b\nb = c\nc = a\nd = a"
);
}
/**
* @return LegacyStorage
*/
protected function makeInstance()
{
return new LegacyStorage($this->emptyConfigSection());
}
/**
* @param null $subDir
* @return string
*/
protected function getTestsBaseDir($subDir = null)
{
$dir = dirname(dirname(dirname(__DIR__))) . '/test';
if ($subDir === null) {
return $dir;
} else {
return $dir . '/' . ltrim($subDir, '/');
}
}
/**
* @return ApplicationBootstrap
*/
protected function app()
{
if (self::$app === null) {
self::$app = Icinga::app();
}
return self::$app;
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace Icinga\Module\Businessprocess\Test;
use Icinga\Application\Cli;
class Bootstrap
{
public static function cli($basedir = null)
{
error_reporting(E_ALL | E_STRICT);
if ($basedir === null) {
$basedir = dirname(dirname(dirname(__DIR__)));
}
$testsDir = $basedir . '/test';
require_once 'Icinga/Application/Cli.php';
if (array_key_exists('ICINGAWEB_CONFIGDIR', $_SERVER)) {
$configDir = $_SERVER['ICINGAWEB_CONFIGDIR'];
} else {
$configDir = $testsDir . '/config';
}
Cli::start($testsDir, $configDir)
->getModuleManager()
->loadModule('businessprocess', $basedir);
}
}

View file

@ -0,0 +1,15 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Module\Businessprocess\Html\BaseElement;
class ActionBar extends BaseElement
{
protected $contentSeparator = ' ';
/** @var string */
protected $tag = 'div';
protected $defaultAttributes = array('class' => 'action-bar');
}

View file

@ -0,0 +1,12 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Module\Businessprocess\Html\Container;
class Content extends Container
{
protected $contentSeparator = "\n";
protected $defaultAttributes = array('class' => 'content');
}

View file

@ -0,0 +1,12 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Module\Businessprocess\Html\Container;
class Controls extends Container
{
protected $contentSeparator = "\n";
protected $defaultAttributes = array('class' => 'controls');
}

View file

@ -0,0 +1,108 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Authentication\Auth;
use Icinga\Module\Businessprocess\Html\BaseElement;
use Icinga\Module\Businessprocess\Html\Container;
use Icinga\Module\Businessprocess\Html\HtmlTag;
use Icinga\Module\Businessprocess\Storage\Storage;
class Dashboard extends BaseElement
{
/** @var string */
protected $contentSeparator = "\n";
/** @var string */
protected $tag = 'div';
protected $defaultAttributes = array(
'class' => 'overview-dashboard',
'data-base-target' => '_next'
);
/** @var Auth */
protected $auth;
/** @var Storage */
protected $storage;
/**
* Dashboard constructor.
* @param Auth $auth
* @param Storage $storage
*/
protected function __construct(Auth $auth, Storage $storage)
{
$this->auth = $auth;
$this->storage = $storage;
// TODO: Auth?
$processes = $storage->listProcessNames();
$this->add(
HtmlTag::h1($this->translate('Welcome to your Business Process Overview'))
);
$this->add(
HtmlTag::p(
$this->translate(
'From here you can reach all your defined Business Process'
. ' configurations, create new or modify existing ones'
)
)
);
if ($auth->hasPermission('businessprocess/create')) {
$this->add(
new DashboardAction(
$this->translate('Create'),
$this->translate('Create a new Business Process configuration'),
'plus',
'businessprocess/process/create',
null,
array('class' => 'addnew')
)
)->add(
new DashboardAction(
$this->translate('Upload'),
$this->translate('Upload an existing Business Process configuration'),
'upload',
'businessprocess/process/upload',
null,
array('class' => 'addnew')
)
);
} elseif (empty($processes)) {
$this->addContent(
Container::create()
->add(HtmlTag::h1($this->translate('Not available')))
->add(HtmlTag::p($this->translate('No Business Process has been defined for you')))
);
}
foreach ($processes as $name) {
$meta = $storage->loadMetadata($name);
$title = $meta->get('Title');
if ($title) {
$title = sprintf('%s (%s)', $title, $name);
} else {
$title = $name;
}
$this->add(new DashboardAction(
$title,
$meta->get('Description'),
'sitemap',
'businessprocess/process/show',
array('config' => $name)
));
}
}
/**
* @param Auth $auth
* @param Storage $storage
* @return static
*/
public static function create(Auth $auth, Storage $storage)
{
return new static($auth, $storage);
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Module\Businessprocess\Html\BaseElement;
use Icinga\Module\Businessprocess\Html\Element;
use Icinga\Module\Businessprocess\Html\Icon;
use Icinga\Module\Businessprocess\Html\Link;
class DashboardAction extends BaseElement
{
protected $tag = 'div';
protected $defaultAttributes = array('class' => 'action');
public function __construct($title, $description, $icon, $url, $urlParams = null, $attributes = null)
{
$this->add(
Link::create(
Icon::create($icon),
$url,
$urlParams,
$attributes
)->add(
Element::create('span', array('class' => 'header'))->addContent($title)
)->addContent($description)
);
}
}

View file

@ -0,0 +1,108 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Authentication\Auth;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Html\BaseElement;
use Icinga\Module\Businessprocess\Html\Link;
use Icinga\Module\Businessprocess\Renderer\Renderer;
use Icinga\Module\Businessprocess\Renderer\TreeRenderer;
use Icinga\Module\Businessprocess\Web\Url;
class RenderedProcessActionBar extends ActionBar
{
public function __construct(BpConfig $config, Renderer $renderer, Auth $auth, Url $url)
{
$meta = $config->getMetadata();
if ($renderer instanceof TreeRenderer) {
$this->add(
Link::create(
$this->translate('Tiles'),
$url->with('mode', 'tile'),
null,
array('class' => 'icon-dashboard')
)
);
} else {
$this->add(
Link::create(
$this->translate('Tree'),
$url->with('mode', 'tree'),
null,
array('class' => 'icon-sitemap')
)
);
}
$this->add(
Link::create(
$this->translate('Fullscreen'),
$url->with('showFullscreen', true),
null,
array(
'class' => 'icon-resize-full-alt',
'title' => $this->translate('Switch to fullscreen mode'),
'data-base-target' => '_main',
)
)
);
$hasChanges = $config->hasSimulations() || $config->hasBeenChanged();
if ($renderer->isLocked()) {
$this->add(
Link::create(
$this->translate('Unlock'),
$url->with('unlocked', true),
null,
array(
'class' => 'icon-lock-open',
'title' => $this->translate('Unlock this process'),
)
)
);
} elseif (! $hasChanges) {
$this->add(
Link::create(
$this->translate('Lock'),
$url->without('unlocked')->without('action'),
null,
array(
'class' => 'icon-lock',
'title' => $this->translate('Lock this process'),
)
)
);
}
if ($hasChanges || (! $renderer->isLocked()) && $meta->canModify()) {
$this->add(
Link::create(
$this->translate('Config'),
'businessprocess/process/config',
$this->currentProcessParams($url),
array(
'class' => 'icon-wrench',
'title' => $this->translate('Modify this process'),
'data-base-target' => '_next',
)
)
);
}
}
protected function currentProcessParams($url)
{
$urlParams = $url->getParams();
$params = array();
foreach (array('config', 'node') as $name) {
if ($value = $urlParams->get($name)) {
$params[$name] = $value;
}
}
return $params;
}
}

View file

@ -0,0 +1,10 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Component;
use Icinga\Module\Businessprocess\Html\Renderable;
use Icinga\Web\Widget\Tabs as WebTabs;
class Tabs extends WebTabs implements Renderable
{
}

View file

@ -0,0 +1,266 @@
<?php
namespace Icinga\Module\Businessprocess\Web;
use Icinga\Application\Icinga;
use Icinga\Module\Businessprocess\BpConfig;
use Icinga\Module\Businessprocess\Html\HtmlTag;
use Icinga\Module\Businessprocess\Modification\ProcessChanges;
use Icinga\Module\Businessprocess\Storage\LegacyStorage;
use Icinga\Module\Businessprocess\Storage\Storage;
use Icinga\Module\Businessprocess\Web\Component\ActionBar;
use Icinga\Module\Businessprocess\Web\Component\Controls;
use Icinga\Module\Businessprocess\Web\Component\Content;
use Icinga\Module\Businessprocess\Web\Component\Tabs;
use Icinga\Module\Businessprocess\Web\Form\FormLoader;
use Icinga\Web\Controller as ModuleController;
use Icinga\Web\Notification;
use Icinga\Web\View;
class Controller extends ModuleController
{
/** @var View */
public $view;
/** @var BpConfig */
protected $bp;
/** @var Tabs */
protected $mytabs;
/** @var Storage */
private $storage;
/** @var bool */
protected $showFullscreen;
/** @var Url */
private $url;
public function init()
{
$m = Icinga::app()->getModuleManager();
if (! $m->hasLoaded('monitoring') && $m->hasInstalled('monitoring')) {
$m->loadModule('monitoring');
}
$this->controls();
$this->content();
$this->url();
$this->view->showFullscreen
= $this->showFullscreen
= (bool) $this->_helper->layout()->showFullscreen;
$this->view->compact = $this->params->get('view') === 'compact';
$this->setViewScript('default');
}
/**
* @return Url
*/
protected function url()
{
if ($this->url === null) {
$this->url = Url::fromPath(
$this->getRequest()->getUrl()->getPath()
)->setParams($this->params);
}
return $this->url;
}
/**
* @return ActionBar
*/
protected function actions()
{
if ($this->view->actions === null) {
$this->view->actions = new ActionBar();
}
return $this->view->actions;
}
/**
* @return Controls
*/
protected function controls()
{
if ($this->view->controls === null) {
$this->view->controls = Controls::create();
}
return $this->view->controls;
}
/**
* @return Content
*/
protected function content()
{
if ($this->view->content === null) {
$this->view->content = Content::create();
}
return $this->view->content;
}
/**
* @param $label
* @return Tabs
*/
protected function singleTab($label)
{
return $this->tabs()->add(
'tab',
array(
'label' => $label,
'url' => $this->getRequest()->getUrl()
)
)->activate('tab');
}
/**
* @return Tabs
*/
protected function defaultTab()
{
return $this->singleTab($this->translate('Business Process'));
}
/**
* @return Tabs
*/
protected function overviewTab()
{
return $this->tabs()->add(
'overview',
array(
'label' => $this->translate('Business Process'),
'url' => 'businessprocess'
)
)->activate('overview');
}
/**
* @return Tabs
*/
protected function tabs()
{
// Todo: do not add to view once all of them render controls()
if ($this->mytabs === null) {
$tabs = new Tabs();
//$this->controls()->add($tabs);
$this->mytabs = $tabs;
}
return $this->mytabs;
}
protected function session()
{
return $this->Window()->getSessionNamespace('businessprocess');
}
protected function setViewScript($name)
{
$this->_helper->viewRenderer->setNoController(true);
$this->_helper->viewRenderer->setScriptAction($name);
return $this;
}
protected function setTitle($title)
{
$args = func_get_args();
array_shift($args);
$this->view->title = vsprintf($title, $args);
return $this;
}
protected function addTitle($title)
{
$args = func_get_args();
array_shift($args);
$this->view->title = vsprintf($title, $args);
$this->controls()->add(HtmlTag::h1($this->view->title));
return $this;
}
protected function loadModifiedBpConfig()
{
$bp = $this->loadBpConfig();
$changes = ProcessChanges::construct($bp, $this->session());
if ($this->params->get('dismissChanges')) {
Notification::success(
sprintf(
$this->translate('%d pending change(s) have been dropped'),
$changes->count()
)
);
$changes->clear();
$this->redirectNow($this->url()->without('dismissChanges')->without('unlocked'));
}
$bp->applyChanges($changes);
return $bp;
}
protected function doNotRender()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
return $this;
}
protected function loadBpConfig()
{
$name = $this->params->get('config');
$storage = $this->storage();
if (! $storage->hasProcess($name)) {
$this->httpNotFound(
$this->translate('No such process config: "%s"'),
$name
);
}
$modifications = $this->session()->get('modifications', array());
if (array_key_exists($name, $modifications)) {
$bp = $storage->loadFromString($name, $modifications[$name]);
} else {
$bp = $storage->loadProcess($name);
}
// allow URL parameter to override configured state type
if (null !== ($stateType = $this->params->get('state_type'))) {
if ($stateType === 'soft') {
$bp->useSoftStates();
}
if ($stateType === 'hard') {
$bp->useHardStates();
}
}
$this->view->bpconfig = $this->bp = $bp;
$this->view->configName = $bp->getName();
return $bp;
}
public function loadForm($name)
{
return FormLoader::load($name, $this->Module());
}
/**
* @return LegacyStorage|Storage
*/
protected function storage()
{
if ($this->storage === null) {
$this->storage = new LegacyStorage(
$this->Config()->getSection('global')
);
}
return $this->storage;
}
}

View file

@ -0,0 +1,26 @@
<?php
namespace Icinga\Module\Businessprocess\Web;
use Icinga\Exception\ProgrammingError;
use Icinga\Web\Request;
class FakeRequest extends Request
{
/** @var string */
private static $baseUrl;
public static function setConfiguredBaseUrl($url)
{
self::$baseUrl = $url;
}
public function getBaseUrl($raw = false)
{
if (self::$baseUrl === null) {
throw new ProgrammingError('Cannot determine base URL on CLI if not configured');
} else {
return self::$baseUrl;
}
}
}

View file

@ -0,0 +1,9 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Form\Element;
use Zend_Form_Element_Xhtml;
class FormElement extends Zend_Form_Element_Xhtml
{
}

View file

@ -0,0 +1,22 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Form\Element;
class SimpleNote extends FormElement
{
public $helper = 'formSimpleNote';
/**
* Always ignore this element
* @codingStandardsIgnoreStart
*
* @var boolean
*/
protected $_ignore = true;
// @codingStandardsIgnoreEnd
public function isValid($value, $context = null)
{
return true;
}
}

View file

@ -0,0 +1,167 @@
<?php
namespace Icinga\Module\Businessprocess\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Application\Modules\Module;
use Icinga\Module\Businessprocess\Html\Renderable;
use Zend_Form;
abstract class QuickBaseForm extends Zend_Form implements Renderable
{
/**
* The Icinga module this form belongs to. Usually only set if the
* form is initialized through the FormLoader
*
* @var Module
*/
protected $icingaModule;
protected $icingaModuleName;
private $hintCount = 0;
public function __construct($options = null)
{
$this->callZfConstructor($this->handleOptions($options))
->initializePrefixPaths();
}
protected function callZfConstructor($options = null)
{
parent::__construct($options);
return $this;
}
protected function initializePrefixPaths()
{
$this->addPrefixPathsForBusinessprocess();
if ($this->icingaModule && $this->icingaModuleName !== 'businessprocess') {
$this->addPrefixPathsForModule($this->icingaModule);
}
}
protected function addPrefixPathsForBusinessprocess()
{
$module = Icinga::app()
->getModuleManager()
->loadModule('businessprocess')
->getModule('businessprocess');
$this->addPrefixPathsForModule($module);
}
public function addPrefixPathsForModule(Module $module)
{
$basedir = sprintf(
'%s/%s/Web/Form',
$module->getLibDir(),
ucfirst($module->getName())
);
$this->addPrefixPaths(array(
array(
'prefix' => __NAMESPACE__ . '\\Element\\',
'path' => $basedir . '/Element',
'type' => static::ELEMENT
)
));
return $this;
}
public function addHidden($name, $value = null)
{
$this->addElement('hidden', $name);
$el = $this->getElement($name);
$el->setDecorators(array('ViewHelper'));
if ($value !== null) {
$this->setDefault($name, $value);
$el->setValue($value);
}
return $this;
}
// TODO: Should be an element
public function addHtmlHint($html, $options = array())
{
return $this->addHtml('<div class="hint">' . $html . '</div>', $options);
}
public function addHtml($html, $options = array())
{
if (array_key_exists('name', $options)) {
$name = $options['name'];
unset($options['name']);
} else {
$name = '_HINT' . ++$this->hintCount;
}
$this->addElement('simpleNote', $name, $options);
$this->getElement($name)
->setValue($html)
->setIgnore(true)
->setDecorators(array('ViewHelper'));
return $this;
}
public function optionalEnum($enum, $nullLabel = null)
{
if ($nullLabel === null) {
$nullLabel = $this->translate('- please choose -');
}
return array(null => $nullLabel) + $enum;
}
protected function handleOptions($options = null)
{
if ($options === null) {
return $options;
}
if (array_key_exists('icingaModule', $options)) {
/** @var Module icingaModule */
$this->icingaModule = $options['icingaModule'];
$this->icingaModuleName = $this->icingaModule->getName();
unset($options['icingaModule']);
}
return $options;
}
public function setIcingaModule(Module $module)
{
$this->icingaModule = $module;
return $this;
}
protected function loadForm($name, Module $module = null)
{
if ($module === null) {
$module = $this->icingaModule;
}
return FormLoader::load($name, $module);
}
protected function valueIsEmpty($value)
{
if (is_array($value)) {
return empty($value);
}
return strlen($value) === 0;
}
public function translate($string)
{
if ($this->icingaModuleName === null) {
return t($string);
} else {
return mt($this->icingaModuleName, $string);
}
}
}

Some files were not shown because too many files have changed in this diff Show more