diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:17:48 +0000 |
commit | e6d4dfc040bbe3cb80a2ce65b82493b557f751fc (patch) | |
tree | 40bd6366b01b06f4d96fc8638f23a772263cb5e9 | |
parent | Releasing progress-linux version 1.10.2-2~progress7.99u1. (diff) | |
download | icingaweb2-module-director-e6d4dfc040bbe3cb80a2ce65b82493b557f751fc.tar.xz icingaweb2-module-director-e6d4dfc040bbe3cb80a2ce65b82493b557f751fc.zip |
Merging upstream version 1.11.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
305 files changed, 8131 insertions, 5351 deletions
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..7709e8a --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,219 @@ +name: PHP Tests + +on: + push: + branches: + - master + - release/* + pull_request: + branches: + - master + +jobs: + lint: + name: Static analysis for php ${{ matrix.php }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + os: ['ubuntu-latest'] + + steps: + - name: Checkout code base + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: phpcs + + - name: Setup dependencies + run: | + composer require -n --no-progress overtrue/phplint phpunit/phpunit phpstan/phpstan + sudo git clone --depth 1 https://github.com/Icinga/icingaweb2.git /icingaweb2 + sudo git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git /usr/share/icinga-php/vendor + sudo git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-library.git /usr/share/icinga-php/ipl + sudo git clone --depth 1 https://github.com/Icinga/icingaweb2-module-cube.git /usr/share/icingaweb2-modules/cube + sudo git clone --depth 1 https://github.com/Icinga/icingadb-web.git /usr/share/icingaweb2-modules/icingadb + + - name: Setup Incubator + run: | + sudo git clone --depth 1 https://github.com/Icinga/icingaweb2-module-incubator /usr/share/icingaweb2-modules/incubator + cd /usr/share/icingaweb2-modules/incubator + composer require --no-update \ + "gipfl/calendar": "dev-master as 99.x-dev" \ + "gipfl/cli": "dev-master as 99.x-dev" \ + "gipfl/curl": "dev-master as 99.x-dev" \ + "gipfl/data-type": "dev-master as 99.x-dev" \ + "gipfl/db-migration": "dev-master as 99.x-dev" \ + "gipfl/diff": "dev-master as 99.x-dev" \ + "gipfl/format": "dev-master as 99.x-dev" \ + "gipfl/icinga-bundles": "dev-master as 99.x-dev" \ + "gipfl/icinga-cli-daemon": "dev-master as 99.x-dev" \ + "gipfl/icingaweb2": "dev-master as 99.x-dev" \ + "gipfl/influxdb": "dev-master as 99.x-dev" \ + "gipfl/json": "dev-master as 99.x-dev" \ + "gipfl/linux-health": "dev-master as 99.x-dev" \ + "gipfl/log": "dev-master as 99.x-dev" \ + "gipfl/process": "dev-master as 99.x-dev" \ + "gipfl/protocol-jsonrpc": "dev-master as 99.x-dev" \ + "gipfl/protocol-netstring": "dev-master as 99.x-dev" \ + "gipfl/react-utils": "dev-master as 99.x-dev" \ + "gipfl/simple-daemon": "dev-master as 99.x-dev" \ + "gipfl/socket": "dev-master as 99.x-dev" \ + "gipfl/stream": "dev-master as 99.x-dev" \ + "gipfl/systemd": "dev-master as 99.x-dev" \ + "gipfl/translation": "dev-master as 99.x-dev" \ + "gipfl/web": "dev-master as 99.x-dev" \ + "gipfl/zfdb": "dev-master as 99.x-dev" \ + "gipfl/zfdbstore": "dev-master as 99.x-dev" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config user.name "github-actions[bot]" + bin/make-release.sh snapshot + + - name: PHP Lint + if: ${{ ! cancelled() }} + run: ./vendor/bin/phplint -n --exclude={^vendor/.*} -- . + + - name: PHP CodeSniffer + if: ${{ ! cancelled() }} + run: phpcs + + - name: PHPStan + if: ${{ ! cancelled() }} + run: ./vendor/bin/phpstan analyse + + test: + name: Unit tests with php ${{ matrix.php }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + env: + phpunit-version: 9.5 + + strategy: + fail-fast: false + matrix: + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + os: ['ubuntu-latest'] + include: + - php: '7.2' + phpunit-version: 8.5 + + services: + mysql: + image: mariadb + env: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: director_test + MYSQL_USER: director_test + MYSQL_PASSWORD: director_test + options: >- + --health-cmd "mariadb -s -uroot -proot -e'SHOW DATABASES;' 2> /dev/null | grep director_test > test" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 3306/tcp + + pgsql: + image: postgres + env: + POSTGRES_USER: director_test + POSTGRES_PASSWORD: director_test + POSTGRES_DB: director_test + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432/tcp + + steps: + - name: Checkout code base + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: phpunit:${{ matrix.phpunit-version || env.phpunit-version }} + extensions: mysql, pgsql + + - name: Setup Icinga Web + run: | + git clone --depth 1 https://github.com/Icinga/icingaweb2.git _icingaweb2 + ln -s `pwd` _icingaweb2/modules/director + + - name: Setup Libraries + run: | + composer require --working-dir=_icingaweb2 -n --no-progress mockery/mockery + mkdir _libraries + git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-library.git _libraries/ipl + git clone --depth 1 -b snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git _libraries/vendor + + - name: Setup Incubator + run: | + git clone --depth 1 https://github.com/Icinga/icingaweb2-module-incubator _icingaweb2/modules/incubator + mkdir -p test/config/enabledModules + cd _icingaweb2/modules/incubator + ln -s `pwd` ../../../test/config/enabledModules/incubator + composer require --no-update \ + "gipfl/calendar": "dev-master as 99.x-dev" \ + "gipfl/cli": "dev-master as 99.x-dev" \ + "gipfl/curl": "dev-master as 99.x-dev" \ + "gipfl/data-type": "dev-master as 99.x-dev" \ + "gipfl/db-migration": "dev-master as 99.x-dev" \ + "gipfl/diff": "dev-master as 99.x-dev" \ + "gipfl/format": "dev-master as 99.x-dev" \ + "gipfl/icinga-bundles": "dev-master as 99.x-dev" \ + "gipfl/icinga-cli-daemon": "dev-master as 99.x-dev" \ + "gipfl/icingaweb2": "dev-master as 99.x-dev" \ + "gipfl/influxdb": "dev-master as 99.x-dev" \ + "gipfl/json": "dev-master as 99.x-dev" \ + "gipfl/linux-health": "dev-master as 99.x-dev" \ + "gipfl/log": "dev-master as 99.x-dev" \ + "gipfl/process": "dev-master as 99.x-dev" \ + "gipfl/protocol-jsonrpc": "dev-master as 99.x-dev" \ + "gipfl/protocol-netstring": "dev-master as 99.x-dev" \ + "gipfl/react-utils": "dev-master as 99.x-dev" \ + "gipfl/simple-daemon": "dev-master as 99.x-dev" \ + "gipfl/socket": "dev-master as 99.x-dev" \ + "gipfl/stream": "dev-master as 99.x-dev" \ + "gipfl/systemd": "dev-master as 99.x-dev" \ + "gipfl/translation": "dev-master as 99.x-dev" \ + "gipfl/web": "dev-master as 99.x-dev" \ + "gipfl/zfdb": "dev-master as 99.x-dev" \ + "gipfl/zfdbstore": "dev-master as 99.x-dev" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config user.name "github-actions[bot]" + bin/make-release.sh snapshot + + - name: PHPUnit with MySQL + if: ${{ ! cancelled() }} + env: + ICINGAWEB_LIBDIR: _libraries + ICINGAWEB_CONFIGDIR: test/config + DIRECTOR_TESTDB_RES: Director MySQL TestDB + DIRECTOR_TESTDB: director_test + DIRECTOR_TESTDB_HOST: 127.0.0.1 + DIRECTOR_TESTDB_PORT: ${{ job.services.mysql.ports['3306'] }} + DIRECTOR_TESTDB_USER: director_test + DIRECTOR_TESTDB_PASSWORD: director_test + run: phpunit --verbose --bootstrap _icingaweb2/test/php/bootstrap.php + + - name: PHPUnit with PostgreSQL + if: ${{ ! cancelled() }} + env: + ICINGAWEB_LIBDIR: _libraries + ICINGAWEB_CONFIGDIR: test/config + DIRECTOR_TESTDB_RES: Director PostgreSQL TestDB + DIRECTOR_TESTDB: director_test + DIRECTOR_TESTDB_HOST: 127.0.0.1 + DIRECTOR_TESTDB_PORT: ${{ job.services.pgsql.ports['5432'] }} + DIRECTOR_TESTDB_USER: director_test + DIRECTOR_TESTDB_PASSWORD: director_test + run: phpunit --verbose --bootstrap _icingaweb2/test/php/bootstrap.php diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..9b0d261 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,125 @@ +stages: +- Coding Standards +- Unit-Tests with DB + +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/Director/ library/vendor/ipl/ application/ *.php test + +CentOS 7/MySQL: + stage: Unit-Tests with DB + tags: + - centos7 + - director + variables: + DIRECTOR_TESTDB: "director_test_${CI_BUILD_ID}_${CI_RUNNER_ID}" + DIRECTOR_TESTDB_RES: "Director MySQL TestDB" + before_script: + - mysql -u root -e "CREATE DATABASE $DIRECTOR_TESTDB" + after_script: + - mysql -u root -e "DROP DATABASE $DIRECTOR_TESTDB" + script: + - phpunit --verbose + +CentOS 7/PostgreSQL: + stage: Unit-Tests with DB + tags: + - centos7 + - director + variables: + DIRECTOR_TESTDB: "director_test_${CI_BUILD_ID}_${CI_RUNNER_ID}" + DIRECTOR_TESTDB_RES: "Director PostgreSQL TestDB" + DIRECTOR_TESTDB_USER: "director_${CI_BUILD_ID}_${CI_RUNNER_ID}" + before_script: + - psql postgres -q -c "CREATE DATABASE $DIRECTOR_TESTDB WITH ENCODING 'UTF8';" + - psql $DIRECTOR_TESTDB -q -c "CREATE USER $DIRECTOR_TESTDB_USER WITH PASSWORD 'testing'; GRANT ALL PRIVILEGES ON DATABASE $DIRECTOR_TESTDB TO $DIRECTOR_TESTDB_USER; CREATE EXTENSION pgcrypto;" + after_script: + - psql postgres -c "DROP DATABASE $DIRECTOR_TESTDB" + - psql postgres -c "DROP USER $DIRECTOR_TESTDB_USER" + script: + - phpunit --verbose + +#CentOS 6/MySQL: +# stage: Unit-Tests with DB +# tags: +# - centos6 +# - director +# variables: +# DIRECTOR_TESTDB: "director_test_${CI_BUILD_ID}_${CI_RUNNER_ID}" +# DIRECTOR_TESTDB_RES: "Director MySQL TestDB" +# before_script: +# - mysql -u root -e "CREATE DATABASE $DIRECTOR_TESTDB" +# after_script: +# - mysql -u root -e "DROP DATABASE $DIRECTOR_TESTDB" +# script: +# - phpunit + +Jessie/MySQL: + stage: Unit-Tests with DB + tags: + - jessie + - director + variables: + DIRECTOR_TESTDB: "director_test_${CI_BUILD_ID}_${CI_RUNNER_ID}" + DIRECTOR_TESTDB_RES: "Director MySQL TestDB" + before_script: + - mysql -u root -e "CREATE DATABASE $DIRECTOR_TESTDB" + after_script: + - mysql -u root -e "DROP DATABASE $DIRECTOR_TESTDB" + script: + - phpunit --verbose + +Jessie/PostgreSQL: + stage: Unit-Tests with DB + tags: + - jessie + - director + variables: + DIRECTOR_TESTDB: "director_test_${CI_BUILD_ID}_${CI_RUNNER_ID}" + DIRECTOR_TESTDB_RES: "Director PostgreSQL TestDB" + DIRECTOR_TESTDB_USER: "director_${CI_BUILD_ID}_${CI_RUNNER_ID}" + before_script: + - psql postgres -q -c "CREATE DATABASE $DIRECTOR_TESTDB WITH ENCODING 'UTF8';" + - psql $DIRECTOR_TESTDB -q -c "CREATE USER $DIRECTOR_TESTDB_USER WITH PASSWORD 'testing'; GRANT ALL PRIVILEGES ON DATABASE $DIRECTOR_TESTDB TO $DIRECTOR_TESTDB_USER; CREATE EXTENSION pgcrypto;" + after_script: + - psql postgres -c "DROP DATABASE $DIRECTOR_TESTDB" + - psql postgres -c "DROP USER $DIRECTOR_TESTDB_USER" + script: + - phpunit --verbose + +Xenial/MySQL: + stage: Unit-Tests with DB + tags: + - xenial + - director + variables: + DIRECTOR_TESTDB: "director_test_${CI_BUILD_ID}_${CI_RUNNER_ID}" + DIRECTOR_TESTDB_RES: "Director MySQL TestDB" + before_script: + - mysql -u root -e "CREATE DATABASE $DIRECTOR_TESTDB" + after_script: + - mysql -u root -e "DROP DATABASE $DIRECTOR_TESTDB" + script: + - phpunit --verbose + +Xenial/PostgreSQL: + stage: Unit-Tests with DB + tags: + - ubuntu + - director + variables: + DIRECTOR_TESTDB: "director_test_${CI_BUILD_ID}_${CI_RUNNER_ID}" + DIRECTOR_TESTDB_RES: "Director PostgreSQL TestDB" + DIRECTOR_TESTDB_USER: "director_${CI_BUILD_ID}_${CI_RUNNER_ID}" + before_script: + - psql postgres -q -c "CREATE DATABASE $DIRECTOR_TESTDB WITH ENCODING 'UTF8';" + - psql $DIRECTOR_TESTDB -q -c "CREATE USER $DIRECTOR_TESTDB_USER WITH PASSWORD 'testing'; GRANT ALL PRIVILEGES ON DATABASE $DIRECTOR_TESTDB TO $DIRECTOR_TESTDB_USER; CREATE EXTENSION pgcrypto;" + after_script: + - psql postgres -c "DROP DATABASE $DIRECTOR_TESTDB" + - psql postgres -c "DROP USER $DIRECTOR_TESTDB_USER" + script: + - phpunit --verbose + diff --git a/application/clicommands/KickstartCommand.php b/application/clicommands/KickstartCommand.php index 80aa183..79093e3 100644 --- a/application/clicommands/KickstartCommand.php +++ b/application/clicommands/KickstartCommand.php @@ -29,8 +29,9 @@ class KickstartCommand extends Command * require => Exec['Icinga Director DB migration'], * } * - * Exit code 0 means that a kickstart run is required, code 2 that it is - * not. + * Exit code 0: A kickstart run is required. + * Exit code 1: Kickstart is configured but a run is not required. + * Exit code 2: A kickstart run is not required. */ public function requiredAction() { diff --git a/application/controllers/BasketController.php b/application/controllers/BasketController.php index 8733d16..8d4db03 100644 --- a/application/controllers/BasketController.php +++ b/application/controllers/BasketController.php @@ -9,13 +9,10 @@ use gipfl\IcingaWeb2\Link; use gipfl\Web\Table\NameValueTable; use gipfl\Web\Widget\Hint; use Icinga\Date\DateFormatter; -use Icinga\Module\Director\Core\Json; -use Icinga\Module\Director\Data\Exporter; use Icinga\Module\Director\Db; use Icinga\Module\Director\DirectorObject\Automation\Basket; +use Icinga\Module\Director\DirectorObject\Automation\BasketDiff; use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshot; -use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshotFieldResolver; -use Icinga\Module\Director\DirectorObject\Automation\CompareBasketObject; use Icinga\Module\Director\Forms\AddToBasketForm; use Icinga\Module\Director\Forms\BasketCreateSnapshotForm; use Icinga\Module\Director\Forms\BasketForm; @@ -24,6 +21,7 @@ use Icinga\Module\Director\Forms\RestoreBasketForm; use Icinga\Module\Director\Web\Controller\ActionController; use ipl\Html\Html; use Icinga\Module\Director\Web\Table\BasketSnapshotTable; +use Ramsey\Uuid\Uuid; class BasketController extends ActionController { @@ -127,6 +125,26 @@ class BasketController extends ActionController $this->content()->add($form); } + public function uploadSnapshotAction() + { + $basket = Basket::load($this->params->get('name'), $this->db()); + $this->actions()->add( + Link::create( + $this->translate('back'), + 'director/basket/snapshots', + ['name' => $basket->get('basket_name')], + ['class' => 'icon-left-big'] + ) + ); + $this->basketTabs()->activate('snapshots'); + $this->addTitle($this->translate('Upload a Configuration Basket Snapshot')); + $form = (new BasketUploadForm()) + ->setObject($basket) + ->setDb($this->db()) + ->handleRequest(); + $this->content()->add($form); + } + /** * @throws \Icinga\Exception\NotFoundError */ @@ -147,6 +165,12 @@ class BasketController extends ActionController $basket->get('basket_name') )); $this->basketTabs()->activate('snapshots'); + $this->actions()->add(Link::create( + $this->translate('Upload'), + 'director/basket/upload-snapshot', + ['name' => $basket->get('basket_name')], + ['class' => 'icon-upload'] + )); } if ($basket !== null) { $this->content()->add( @@ -245,12 +269,9 @@ class BasketController extends ActionController $connection = $this->db(); } - $json = $snapshot->getJsonDump(); $this->addSingleTab($this->translate('Snapshot')); - $all = Json::decode($json); - $exporter = new Exporter($this->db()); - $fieldResolver = new BasketSnapshotFieldResolver($all, $connection); - foreach ($all as $type => $objects) { + $diff = new BasketDiff($snapshot, $connection); + foreach ($diff->getBasketObjects() as $type => $objects) { if ($type === 'Datafield') { // TODO: we should now be able to show all fields and link // to a "diff" for the ones that should be created @@ -274,39 +295,33 @@ class BasketController extends ActionController $linkParams['target_db'] = $targetDbName; } try { - $current = BasketSnapshot::instanceByIdentifier($type, $key, $connection); - if ($current === null) { - $table->addNameValueRow( - $key, - Link::create( - Html::tag('strong', ['style' => 'color: green'], $this->translate('new')), + if ($uuid = $object->uuid ?? null) { + $uuid = Uuid::fromString($uuid); + } + if ($diff->hasCurrentInstance($type, $key, $uuid)) { + if ($diff->hasChangedFor($type, $key, $uuid)) { + $link = Link::create( + $this->translate('modified'), 'director/basket/snapshotobject', - $linkParams - ) + $linkParams, + ['class' => 'basket-modified'] + ); + } else { + $link = Html::tag( + 'span', + ['class' => 'basket-unchanged'], + $this->translate('unchanged') + ); + } + } else { + $link = Link::create( + $this->translate('new'), + 'director/basket/snapshotobject', + $linkParams, + ['class' => 'basket-new'] ); - continue; - } - $currentExport = $exporter->export($current); - $fieldResolver->tweakTargetIds($currentExport); - - // Ignore originalId - if (isset($currentExport->originalId)) { - unset($currentExport->originalId); - } - if (isset($object->originalId)) { - unset($object->originalId); } - $hasChanged = ! CompareBasketObject::equals($currentExport, $object); - $table->addNameValueRow( - $key, - $hasChanged - ? Link::create( - Html::tag('strong', ['style' => 'color: orange'], $this->translate('modified')), - 'director/basket/snapshotobject', - $linkParams - ) - : Html::tag('span', ['style' => 'color: green'], $this->translate('unchanged')) - ); + $table->addNameValueRow($key, $link); } catch (Exception $e) { $table->addNameValueRow( $key, @@ -322,7 +337,6 @@ class BasketController extends ActionController $this->content()->add(Html::tag('h2', $type)); $this->content()->add($table); } - $this->content()->add(Html::tag('div', ['style' => 'height: 5em'])); } /** @@ -368,39 +382,28 @@ class BasketController extends ActionController ) */ ]); - $exporter = new Exporter($this->db()); - $json = $snapshot->getJsonDump(); + $this->addSingleTab($this->translate('Snapshot')); - $objects = Json::decode($json); $targetDbName = $this->params->get('target_db'); if ($targetDbName === null) { $connection = $this->db(); } else { $connection = Db::fromResourceName($targetDbName); } - $fieldResolver = new BasketSnapshotFieldResolver($objects, $connection); - $objectFromBasket = $objects->$type->$key; - unset($objectFromBasket->originalId); - CompareBasketObject::normalize($objectFromBasket); - $objectFromBasket = Json::encode($objectFromBasket, JSON_PRETTY_PRINT); - $current = BasketSnapshot::instanceByIdentifier($type, $key, $connection); - if ($current === null) { - $current = ''; - } else { - $exported = $exporter->export($current); - $fieldResolver->tweakTargetIds($exported); - unset($exported->originalId); - CompareBasketObject::normalize($exported); - $current = Json::encode($exported, JSON_PRETTY_PRINT); + $diff = new BasketDiff($snapshot, $connection); + $object = $diff->getBasketObject($type, $key); + if ($uuid = $object->uuid ?? null) { + $uuid = Uuid::fromString($uuid); } - - if ($current === $objectFromBasket) { + $basketJson = $diff->getBasketString($type, $key); + $currentJson = $diff->getCurrentString($type, $key, $uuid); + if ($currentJson === $basketJson) { $this->content()->add([ Hint::ok('Basket equals current object'), - Html::tag('pre', $current) + Html::tag('pre', $currentJson) ]); } else { - $this->content()->add(new InlineDiff(new PhpDiff($current, $objectFromBasket))); + $this->content()->add(new InlineDiff(new PhpDiff($currentJson, $basketJson))); } } diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php index 3f8a105..8a5e702 100644 --- a/application/controllers/ConfigController.php +++ b/application/controllers/ConfigController.php @@ -8,6 +8,7 @@ use gipfl\Web\Widget\Hint; use Icinga\Data\Filter\Filter; use Icinga\Exception\IcingaException; use Icinga\Exception\NotFoundError; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Db\Branch\Branch; use Icinga\Module\Director\Deployment\DeploymentStatus; use Icinga\Module\Director\Forms\DeployConfigForm; @@ -186,7 +187,7 @@ class ConfigController extends ActionController ['class' => 'icon-user', 'data-base-target' => '_self'] )); } - if ($this->hasPermission('director/deploy') && ! $this->getBranch()->isBranch()) { + if ($this->hasPermission(Permission::DEPLOY) && ! $this->getBranch()->isBranch()) { if ($this->db()->hasDeploymentEndpoint()) { $this->actions()->add(DeployConfigForm::load() ->setDb($this->db()) @@ -369,31 +370,33 @@ class ConfigController extends ActionController $configs = $db->enumDeployedConfigs(); foreach (array($leftSum, $rightSum) as $sum) { - if (! array_key_exists($sum, $configs)) { + if ($sum && ! array_key_exists($sum, $configs)) { $configs[$sum] = substr($sum, 0, 7); } } $baseUrl = $this->url()->without(['left', 'right']); - $this->content()->add(Html::tag('form', ['action' => (string) $baseUrl, 'method' => 'GET'], [ - new HtmlString($this->view->formSelect( - 'left', - $leftSum, - ['class' => 'autosubmit', 'style' => 'width: 37%'], - [null => $this->translate('- please choose -')] + $configs - )), - Link::create( - Icon::create('flapping'), - $baseUrl, - ['left' => $rightSum, 'right' => $leftSum] - ), - new HtmlString($this->view->formSelect( - 'right', - $rightSum, - ['class' => 'autosubmit', 'style' => 'width: 37%'], - [null => $this->translate('- please choose -')] + $configs - )), - ])); + $this->content()->add( + Html::tag('form', ['action' => (string) $baseUrl, 'method' => 'GET', 'class' => 'director-form'], [ + new HtmlString($this->view->formSelect( + 'left', + $leftSum, + ['class' => ['autosubmit', 'config-diff']], + [null => $this->translate('- please choose -')] + $configs + )), + Link::create( + Icon::create('flapping'), + $baseUrl, + ['left' => $rightSum, 'right' => $leftSum] + ), + new HtmlString($this->view->formSelect( + 'right', + $rightSum, + ['class' => ['autosubmit', 'config-diff']], + [null => $this->translate('- please choose -')] + $configs + )), + ]) + ); if ($rightSum === null || $leftSum === null || ! strlen($rightSum) || ! strlen($leftSum)) { return; @@ -500,7 +503,7 @@ class ConfigController extends ActionController { $tabs = $this->tabs(); - if ($this->hasPermission('director/deploy') + if ($this->hasPermission(Permission::DEPLOY) && $deploymentId = $this->params->get('deployment_id') ) { $tabs->add('deployment', [ @@ -510,7 +513,7 @@ class ConfigController extends ActionController ]); } - if ($this->hasPermission('director/showconfig')) { + if ($this->hasPermission(Permission::SHOW_CONFIG)) { $tabs->add('config', [ 'label' => $this->translate('Config'), 'url' => 'director/config/files', diff --git a/application/controllers/DataController.php b/application/controllers/DataController.php index ae4bbcf..7480db2 100644 --- a/application/controllers/DataController.php +++ b/application/controllers/DataController.php @@ -216,7 +216,7 @@ class DataController extends ActionController $subTitle = $this->translate('Add a new instance'); } - $this->content()->add(Html::tag('h2', ['style' => 'margin-top: 2em'], $subTitle)); + $this->content()->add(Html::tag('h2', ['class' => 'dictionary-header'], $subTitle)); $form->handleRequest($this->getRequest()); $this->content()->add($form); if ($form->succeeded()) { @@ -326,7 +326,7 @@ class DataController extends ActionController Table::row([ $this->translate('Key / Instance'), $this->translate('Properties') - ], ['style' => 'text-align: left'], 'th') + ], ['class' => 'text-align-left'], 'th') ); foreach ($currentValue as $key => $item) { $table->add(Table::row([ diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php index e107d22..33b5ba5 100644 --- a/application/controllers/HostController.php +++ b/application/controllers/HostController.php @@ -3,7 +3,9 @@ namespace Icinga\Module\Director\Controllers; use gipfl\Web\Widget\Hint; -use Icinga\Module\Director\Monitoring; +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Integration\Icingadb\IcingadbBackend; +use Icinga\Module\Director\Integration\MonitoringModule\Monitoring; use Icinga\Module\Director\Web\Table\ObjectsTableService; use ipl\Html\Html; use gipfl\IcingaWeb2\Link; @@ -31,28 +33,24 @@ class HostController extends ObjectController { protected function checkDirectorPermissions() { - if ($this->isServiceAction() && (new Monitoring())->authCanEditService( - $this->Auth(), - $this->getParam('name'), - $this->getParam('service') - )) { + $host = $this->getHostObject(); + $auth = $this->Auth(); + $backend = $this->backend(); + if ($this->isServiceAction() + && $backend->canModifyService($host->getObjectName(), $this->getParam('service')) + ) { return; } - - if ($this->isServicesReadOnlyAction()) { - $this->assertPermission('director/monitoring/services-ro'); + if ($this->isServicesReadOnlyAction() && $auth->hasPermission($this->getServicesReadOnlyPermission())) { return; } - - if ($this->hasPermission('director/hosts')) { // faster + if ($auth->hasPermission(Permission::HOSTS)) { // faster return; } - - if ($this->canModifyHostViaMonitoringPermissions($this->getParam('name'))) { + if ($backend->canModifyHost($host->getObjectName())) { return; } - - $this->assertPermission('director/hosts'); // complain about default hosts permission + $this->assertPermission(Permission::HOSTS); // complain about default hosts permission } protected function isServicesReadOnlyAction() @@ -76,16 +74,6 @@ class HostController extends ObjectController ]); } - protected function canModifyHostViaMonitoringPermissions($hostname) - { - if ($this->hasPermission('director/monitoring/hosts')) { - $monitoring = new Monitoring(); - return $monitoring->authCanEditHost($this->Auth(), $hostname); - } - - return false; - } - /** * @return HostgroupRestriction */ @@ -150,11 +138,35 @@ class HostController extends ObjectController public function findserviceAction() { + $auth = $this->Auth(); $host = $this->getHostObject(); - $this->redirectNow( - (new ServiceFinder($host, $this->getAuth())) - ->getRedirectionUrl($this->params->get('service')) - ); + $hostName = $host->getObjectName(); + $serviceName = $this->params->get('service'); + $info = ServiceFinder::find($host, $serviceName); + $backend = $this->backend(); + + if ($info && $auth->hasPermission(Permission::HOSTS)) { + $redirectUrl = $info->getUrl(); + } elseif ($info + && (($backend instanceof Monitoring && $auth->hasPermission(Permission::MONITORING_HOSTS)) + || ($backend instanceof IcingadbBackend && $auth->hasPermission(Permission::ICINGADB_HOSTS)) + ) + && $backend->canModifyService($hostName, $serviceName) + ) { + $redirectUrl = $info->getUrl(); + } elseif ($auth->hasPermission($this->getServicesReadOnlyPermission())) { + $redirectUrl = Url::fromPath('director/host/servicesro', [ + 'name' => $hostName, + 'service' => $serviceName + ]); + } else { + $redirectUrl = Url::fromPath('director/host/invalidservice', [ + 'name' => $hostName, + 'service' => $serviceName, + ]); + } + + $this->redirectNow($redirectUrl); } /** @@ -207,8 +219,7 @@ class HostController extends ObjectController $branch = $this->getBranch(); $hostHasBeenCreatedInBranch = $branch->isBranch() && $host->get('id'); $content = $this->content(); - $table = (new ObjectsTableService($this->db())) - ->setAuth($this->Auth()) + $table = (new ObjectsTableService($this->db(), $this->Auth())) ->setHost($host) ->setBranch($branch) ->setTitle($this->translate('Individual Service objects')) @@ -222,8 +233,7 @@ class HostController extends ObjectController $parents = IcingaTemplateRepository::instanceByObject($this->object) ->getTemplatesFor($this->object, true); foreach ($parents as $parent) { - $table = (new ObjectsTableService($this->db())) - ->setAuth($this->Auth()) + $table = (new ObjectsTableService($this->db(), $this->Auth())) ->setBranch($branch) ->setHost($parent) ->setInheritedBy($host) @@ -279,7 +289,7 @@ class HostController extends ObjectController */ public function servicesroAction() { - $this->assertPermission('director/monitoring/services-ro'); + $this->assertPermission($this->getServicesReadOnlyPermission()); $host = $this->getHostObject(); $service = $this->params->getRequired('service'); $db = $this->db(); @@ -289,8 +299,7 @@ class HostController extends ObjectController $this->addTitle($this->translate('Services on %s'), $host->getObjectName()); $content = $this->content(); - $table = (new ObjectsTableService($db)) - ->setAuth($this->Auth()) + $table = (new ObjectsTableService($db, $this->Auth())) ->setHost($host) ->setBranch($branch) ->setReadonly() @@ -305,7 +314,7 @@ class HostController extends ObjectController $parents = IcingaTemplateRepository::instanceByObject($this->object) ->getTemplatesFor($this->object, true); foreach ($parents as $parent) { - $table = (new ObjectsTableService($db)) + $table = (new ObjectsTableService($db, $this->Auth())) ->setReadonly() ->setBranch($branch) ->setHost($parent) @@ -387,6 +396,7 @@ class HostController extends ObjectController ->setHost($host) ->setBranch($this->getBranch()) ->setAffectedHost($affectedHost) + ->removeQueryLimit() ->setTitle($title); if ($roService) { $table->setReadonly()->highlightService($roService); @@ -582,20 +592,19 @@ class HostController extends ObjectController { $host = $this->object; try { - $mon = $this->monitoring(); - if ($host->isObject() - && $mon->isAvailable() - && $mon->hasHost($host->getObjectName()) + $backend = $this->backend(); + if ($host instanceof IcingaHost + && $host->isObject() + && $backend->hasHost($host->getObjectName()) ) { - $this->actions()->add(Link::create( - $this->translate('Show'), - 'monitoring/host/show', - ['host' => $host->getObjectName()], - [ - 'class' => 'icon-globe critical', - 'data-base-target' => '_next' - ] - )); + $this->actions()->add( + Link::create( + $this->translate('Show'), + $backend->getHostUrl($host->getObjectName()), + null, + ['class' => 'icon-globe critical', 'data-base-target' => '_next'] + ) + ); // Intentionally placed here, show it only for deployed Hosts $this->addOptionalInspectLink(); @@ -607,7 +616,7 @@ class HostController extends ObjectController protected function addOptionalInspectLink() { - if (! $this->hasPermission('director/inspect')) { + if (! $this->hasPermission(Permission::INSPECT)) { return; } @@ -627,11 +636,25 @@ class HostController extends ObjectController } /** - * @return IcingaHost + * @return ?IcingaHost */ protected function getHostObject() { - assert($this->object instanceof IcingaHost); + if ($this->object !== null) { + assert($this->object instanceof IcingaHost); + } return $this->object; } + + /** + * Get readOnly permission of the service for the current backend + * + * @return string permission + */ + protected function getServicesReadOnlyPermission(): string + { + return $this->backend() instanceof IcingadbBackend + ? Permission::ICINGADB_SERVICES_RO + : Permission::MONITORING_SERVICES_RO; + } } diff --git a/application/controllers/ImportsourceController.php b/application/controllers/ImportsourceController.php index cbddb9e..f417bf7 100644 --- a/application/controllers/ImportsourceController.php +++ b/application/controllers/ImportsourceController.php @@ -180,9 +180,7 @@ class ImportsourceController extends ActionController 'target' => '_blank', 'class' => 'icon-download', ] - ))->add(Link::create('[..]', '#', null, [ - 'onclick' => 'javascript:$("table.raw-data-table").toggleClass("collapsed");' - ])); + )); try { (new ImportsourceHookTable())->setImportSource($source)->renderTo($this); } catch (Exception $e) { diff --git a/application/controllers/ImportsourcesController.php b/application/controllers/ImportsourcesController.php index 4287292..f0021c5 100644 --- a/application/controllers/ImportsourcesController.php +++ b/application/controllers/ImportsourcesController.php @@ -30,7 +30,7 @@ class ImportsourcesController extends ActionController } $this->addTitle($this->translate('Import source')) - ->setAutoRefreshInterval(10) + ->setAutorefreshInterval(10) ->addAddLink( $this->translate('Add a new Import Source'), 'director/importsource/add' diff --git a/application/controllers/JobsController.php b/application/controllers/JobsController.php index 11e86ed..04c6d34 100644 --- a/application/controllers/JobsController.php +++ b/application/controllers/JobsController.php @@ -11,7 +11,7 @@ class JobsController extends ActionController public function indexAction() { $this->addTitle($this->translate('Jobs')) - ->setAutoRefreshInterval(10) + ->setAutorefreshInterval(10) ->addAddLink($this->translate('Add a new Job'), 'director/job/add') ->tabs(new ImportTabs())->activate('jobs'); diff --git a/application/controllers/SchemaController.php b/application/controllers/SchemaController.php index b0ca24e..961b7b1 100644 --- a/application/controllers/SchemaController.php +++ b/application/controllers/SchemaController.php @@ -62,7 +62,7 @@ class SchemaController extends ActionController return file_get_contents( sprintf( '%s/schema/%s.sql', - $this->Module()->getBasedir(), + $this->Module()->getBaseDir(), $type ) ); diff --git a/application/controllers/SelfServiceController.php b/application/controllers/SelfServiceController.php index 0b3b642..c3c9bb5 100644 --- a/application/controllers/SelfServiceController.php +++ b/application/controllers/SelfServiceController.php @@ -194,7 +194,7 @@ class SelfServiceController extends ActionController } else { throw new ProgrammingError( 'Expected boolean value, got %s', - var_export($value, 1) + var_export($value, true) ); } } @@ -275,7 +275,7 @@ class SelfServiceController extends ActionController // PluginsUrl => framework_plugins_url ]; $username = $settings->get('self-service/icinga_service_user'); - if ($username !== null && strlen($username) > 0) { + if ($username) { $params['icinga_service_user'] = $username; } @@ -404,7 +404,7 @@ class SelfServiceController extends ActionController { foreach ($keys as $key) { $value = $settings->get("self-service/$key"); - if (strlen($value)) { + if ($value) { $params[$key] = $value; } } diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index 3cd54d6..b62f317 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -4,11 +4,10 @@ namespace Icinga\Module\Director\Controllers; use Exception; use Icinga\Exception\NotFoundError; -use Icinga\Module\Director\Data\Db\DbObjectStore; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry; use Icinga\Module\Director\Db\Branch\UuidLookup; use Icinga\Module\Director\Forms\IcingaServiceForm; -use Icinga\Module\Director\Monitoring; use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Web\Controller\ObjectController; use Icinga\Module\Director\Objects\IcingaService; @@ -30,13 +29,14 @@ class ServiceController extends ObjectController protected function checkDirectorPermissions() { - if ($this->hasPermission('director/monitoring/services')) { - $monitoring = new Monitoring(); - if ($monitoring->authCanEditService($this->Auth(), $this->getParam('host'), $this->getParam('name'))) { - return; - } + if ($this->host + && $this->object + && $this->backend()->canModifyService($this->host->getObjectName(), $this->object->getObjectName()) + ) { + return; } - $this->assertPermission('director/hosts'); + + $this->assertPermission(Permission::HOSTS); } public function init() @@ -62,7 +62,7 @@ class ServiceController extends ObjectController protected function getOptionalRelatedObjectFromParams($type, $parameter) { - if ($id = $this->params->get("${parameter}_id")) { + if ($id = $this->params->get("{$parameter}_id")) { $key = (int) $id; } else { $key = $this->params->get($parameter); @@ -80,7 +80,7 @@ class ServiceController extends ObjectController { $key = $object->getUnresolvedRelated($relation); if ($key === null) { - if ($key = $object->get("${relation}_id")) { + if ($key = $object->get("{$relation}_id")) { $key = (int) $key; } else { $key = $object->get($relation); diff --git a/application/controllers/SyncruleController.php b/application/controllers/SyncruleController.php index 928cf2c..e575ad8 100644 --- a/application/controllers/SyncruleController.php +++ b/application/controllers/SyncruleController.php @@ -48,7 +48,7 @@ class SyncruleController extends ActionController */ public function indexAction() { - $this->setAutoRefreshInterval(10); + $this->setAutorefreshInterval(10); $rule = $this->requireSyncRule(); $this->tabs(new SyncRuleTabs($rule))->activate('show'); $ruleName = $rule->get('rule_name'); @@ -94,7 +94,7 @@ class SyncruleController extends ActionController break; case 'in-sync': $c->add(Html::tag('p', null, sprintf( - $this->translate('This Sync Rule was last found to by in Sync at %s.'), + $this->translate('This Sync Rule was last found to be in Sync at %s.'), $rule->get('last_attempt') ))); /* @@ -380,10 +380,7 @@ class SyncruleController extends ActionController protected function firstNames($objects, $max = 50) { $names = []; - $list = new UnorderedList(); - $list->addAttributes([ - 'style' => 'list-style-type: none; marign: 0; padding: 0', - ]); + $list = new UnorderedList([], ['class' => 'unordred-list']); $total = count($objects); $i = 0; PrefetchCache::forget(); @@ -464,7 +461,7 @@ class SyncruleController extends ActionController { $list = new UnorderedList(); foreach ($properties as $property => $cnt) { - $list->addItem("${cnt}x $property"); + $list->addItem("{$cnt}x $property"); } return $list; @@ -517,7 +514,6 @@ class SyncruleController extends ActionController if ($this->showNotInBranch($this->translate('Modifying Sync Rules'))) { return; } - } else { $this->addTitle($this->translate('Add sync rule')); $this->tabs(new SyncRuleTabs())->activate('add'); @@ -609,12 +605,11 @@ class SyncruleController extends ActionController $form = SyncPropertyForm::load()->setDb($db); $this->tabs(new SyncRuleTabs($rule))->activate('property'); $this->actions()->add(new Link( - $this->translate('back'), - 'director/syncrule/property', - ['rule_id' => $ruleId], - ['class' => 'icon-left-big'] - )); - + $this->translate('back'), + 'director/syncrule/property', + ['rule_id' => $ruleId], + ['class' => 'icon-left-big'] + )); if ($id = $this->params->get('id')) { $form->loadObject((int) $id); $this->addTitle( @@ -647,7 +642,7 @@ class SyncruleController extends ActionController */ public function historyAction() { - $this->setAutoRefreshInterval(30); + $this->setAutorefreshInterval(30); $rule = $this->requireSyncRule(); $this->tabs(new SyncRuleTabs($rule))->activate('history'); $this->addTitle($this->translate('Sync history') . ': ' . $rule->get('rule_name')); diff --git a/application/controllers/SyncrulesController.php b/application/controllers/SyncrulesController.php index 1829ebe..1c84ecf 100644 --- a/application/controllers/SyncrulesController.php +++ b/application/controllers/SyncrulesController.php @@ -23,7 +23,7 @@ class SyncrulesController extends ActionController } $this->addTitle($this->translate('Sync rule')) - ->setAutoRefreshInterval(10) + ->setAutorefreshInterval(10) ->addAddLink( $this->translate('Add a new Sync Rule'), 'director/syncrule/add' diff --git a/application/forms/AddToBasketForm.php b/application/forms/AddToBasketForm.php index 44b5357..36091fe 100644 --- a/application/forms/AddToBasketForm.php +++ b/application/forms/AddToBasketForm.php @@ -11,9 +11,6 @@ use Icinga\Module\Director\Web\Form\DirectorForm; class AddToBasketForm extends DirectorForm { - /** @var Basket */ - private $basket; - private $type = '(has not been set)'; private $names = []; @@ -30,7 +27,6 @@ class AddToBasketForm extends DirectorForm 'b' => 'basket_name', ])->order('basket_name')); - $names = []; $basket = null; if ($this->hasBeenSent()) { $basketName = $this->getSentValue('basket'); @@ -38,25 +34,17 @@ class AddToBasketForm extends DirectorForm $basket = Basket::load($basketName, $this->getDb()); } } - $count = 0; - $type = $this->type; + + $names = []; foreach ($this->names as $name) { - if (! empty($names)) { - $names[] = ', '; - } - if ($basket && $basket->hasObject($type, $name)) { - $names[] = Html::tag('span', [ - 'style' => 'text-decoration: line-through' - ], $name); - } else { - $count++; + if (! $basket || ! $basket->hasObject($this->type, $name)) { $names[] = $name; } } - $this->addHtmlHint((new HtmlDocument())->add([ - 'The following objects will be added: ', - $names - ])); + $this->addHtmlHint( + (new HtmlDocument()) + ->add(sprintf('The following objects will be added: %s', implode(", ", $names))) + ); $this->addElement('select', 'basket', [ 'label' => $this->translate('Basket'), 'multiOptions' => $this->optionalEnum($enum), @@ -64,10 +52,10 @@ class AddToBasketForm extends DirectorForm 'class' => 'autosubmit', ]); - if ($count > 0) { + if (! empty($names)) { $this->setSubmitLabel(sprintf( $this->translate('Add %s objects'), - $count + count($names) )); } else { $this->setSubmitLabel($this->translate('Add')); @@ -112,18 +100,18 @@ class AddToBasketForm extends DirectorForm 'Configuration objects have been added to the chosen basket "%s"' ), $basketName)); return parent::onSuccess(); - } else { - $this->addHtmlHint(Hint::error(Html::sprintf($this->translate( - 'Please check your Basket configuration, %s does not support' - . ' single "%s" configuration objects' - ), Link::create( - $basketName, - 'director/basket', - ['name' => $basketName], - ['data-base-target' => '_next'] - ), $type))); - - return false; } + + $this->addHtmlHint(Hint::error(Html::sprintf($this->translate( + 'Please check your Basket configuration, %s does not support' + . ' single "%s" configuration objects' + ), Link::create( + $basketName, + 'director/basket', + ['name' => $basketName], + ['data-base-target' => '_next'] + ), $type))); + + return false; } } diff --git a/application/forms/BasketForm.php b/application/forms/BasketForm.php index 8ff6cca..4ac942c 100644 --- a/application/forms/BasketForm.php +++ b/application/forms/BasketForm.php @@ -52,9 +52,9 @@ class BasketForm extends DirectorObjectForm $types = $this->getAvailableTypes(); $options = [ - 'IGNORE' => $this->translate('Ignore'), - 'ALL' => $this->translate('All of them'), - '[]' => $this->translate('Custom Selection'), + Basket::SELECTION_NONE => $this->translate('Ignore'), + Basket::SELECTION_ALL => $this->translate('All of them'), + Basket::SELECTION_CUSTOM => $this->translate('Custom Selection'), ]; $this->addHtmlHint($this->translate( @@ -92,13 +92,13 @@ class BasketForm extends DirectorObjectForm /** @var Basket $object */ $values = []; foreach ($this->getAvailableTypes() as $type => $label) { - $values[$type] = 'IGNORE'; + $values[$type] = Basket::SELECTION_NONE; } foreach ($object->getChosenObjects() as $type => $selection) { if ($selection === true) { - $values[$type] = 'ALL'; + $values[$type] = Basket::SELECTION_ALL; } elseif (is_array($selection)) { - $values[$type] = '[]'; + $values[$type] = Basket::SELECTION_CUSTOM; } } diff --git a/application/forms/BasketUploadForm.php b/application/forms/BasketUploadForm.php index a88dc06..aa26258 100644 --- a/application/forms/BasketUploadForm.php +++ b/application/forms/BasketUploadForm.php @@ -25,10 +25,12 @@ class BasketUploadForm extends DirectorObjectForm */ public function setup() { - $this->addElement('text', 'basket_name', [ - 'label' => $this->translate('Basket Name'), - 'required' => true, - ]); + if ($this->object === null) { + $this->addElement('text', 'basket_name', [ + 'label' => $this->translate('Basket Name'), + 'required' => true, + ]); + } $this->setAttrib('enctype', 'multipart/form-data'); $this->addElement('file', 'uploaded_file', [ @@ -53,16 +55,6 @@ class BasketUploadForm extends DirectorObjectForm return '\\Icinga\\Module\\Director\\DirectorObject\\Automation\\Basket'; } - protected function setObjectSuccessUrl() - { - /** @var Basket $basket */ - $basket = $this->object(); - $this->setSuccessUrl( - 'director/basket', - ['name' => $basket->get('basket_name')] - ); - } - /** * @return bool * @throws IcingaException @@ -134,13 +126,17 @@ class BasketUploadForm extends DirectorObjectForm $basket->set('owner_type', 'user'); $basket->set('owner_value', $this->getAuth()->getUser()->getUsername()); - $basket->store($this->db); + if ($basket->hasBeenLoadedFromDb()) { + $this->setSuccessUrl('director/basket/snapshots', ['name' => $basket->get('basket_name')]); + } else { + $this->setSuccessUrl('director/basket', ['name' => $basket->get('basket_name')]); + $basket->store($this->db); + } BasketSnapshot::forBasketFromJson( $basket, $this->rawUpload )->store($this->db); - $this->setObjectSuccessUrl(); $this->beforeSuccessfulRedirect(); $this->redirectOnSuccess($this->translate('Basket has been uploaded')); } diff --git a/application/forms/DeploymentLinkForm.php b/application/forms/DeploymentLinkForm.php index f42a627..f5cd368 100644 --- a/application/forms/DeploymentLinkForm.php +++ b/application/forms/DeploymentLinkForm.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Forms; use Icinga\Authentication\Auth; use Icinga\Exception\IcingaException; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Core\DeploymentApiInterface; use Icinga\Module\Director\Db; use Icinga\Module\Director\Deployment\DeploymentInfo; @@ -100,7 +101,7 @@ class DeploymentLinkForm extends DirectorForm protected function canDeploy() { - return $this->auth->hasPermission('director/deploy'); + return $this->auth->hasPermission(Permission::DEPLOY); } public function render(Zend_View_Interface $view = null) diff --git a/application/forms/DirectorDatafieldForm.php b/application/forms/DirectorDatafieldForm.php index a306bd7..ab0dcd8 100644 --- a/application/forms/DirectorDatafieldForm.php +++ b/application/forms/DirectorDatafieldForm.php @@ -140,8 +140,7 @@ class DirectorDatafieldForm extends DirectorObjectForm $this->addElement('text', 'varname', array( 'label' => $this->translate('Field name'), 'description' => $this->translate( - 'The unique name of the field. This will be the name of the custom' - . ' variable in the rendered Icinga configuration.' + 'This will be the name of the custom variable in the rendered Icinga configuration.' ), 'required' => true, )); @@ -166,7 +165,7 @@ class DirectorDatafieldForm extends DirectorObjectForm $this->addElement('select', 'category_id', [ 'label' => $this->translate('Data Field Category'), - 'multiOptions' => $this->optionalEnum($this->enumCategpories()), + 'multiOptions' => $this->optionalEnum($this->enumCategories()), ]); $error = false; @@ -282,7 +281,7 @@ class DirectorDatafieldForm extends DirectorObjectForm protected function enumDataTypes() { $hooks = Hook::all('Director\\DataType'); - $enum = array(null => '- please choose -'); + $enum = [null => $this->translate('- please choose -')]; /** @var DataTypeHook $hook */ foreach ($hooks as $hook) { $enum[get_class($hook)] = $hook->getName(); @@ -291,7 +290,7 @@ class DirectorDatafieldForm extends DirectorObjectForm return $enum; } - protected function enumCategpories() + protected function enumCategories() { $db = $this->getDb()->getDbAdapter(); return $db->fetchPairs( diff --git a/application/forms/IcingaAddServiceForm.php b/application/forms/IcingaAddServiceForm.php index df2302e..60ccb6f 100644 --- a/application/forms/IcingaAddServiceForm.php +++ b/application/forms/IcingaAddServiceForm.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Forms; use gipfl\IcingaWeb2\Link; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Web\Form\DirectorObjectForm; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaService; @@ -82,7 +83,7 @@ class IcingaAddServiceForm extends DirectorObjectForm if ($this->hasBeenSent()) { $this->addError($this->translate('No service has been chosen')); } else { - if ($this->hasPermission('director/admin')) { + if ($this->hasPermission(Permission::ADMIN)) { $html = sprintf( $this->translate('Please define a %s first'), Link::create( diff --git a/application/forms/IcingaCloneObjectForm.php b/application/forms/IcingaCloneObjectForm.php index 6ee99ba..8381eee 100644 --- a/application/forms/IcingaCloneObjectForm.php +++ b/application/forms/IcingaCloneObjectForm.php @@ -5,8 +5,10 @@ namespace Icinga\Module\Director\Forms; use gipfl\Web\Widget\Hint; use Icinga\Exception\IcingaException; use Icinga\Module\Director\Acl; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Data\Db\DbObjectStore; use Icinga\Module\Director\Db\Branch\Branch; +use Icinga\Module\Director\Objects\IcingaCommand; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Objects\IcingaService; @@ -41,7 +43,7 @@ class IcingaCloneObjectForm extends DirectorForm 'value' => $name, )); - if (!$branchOnly && Acl::instance()->hasPermission('director/admin')) { + if (!$branchOnly && Acl::instance()->hasPermission(Permission::ADMIN)) { $this->addElement('select', 'clone_type', array( 'label' => 'Clone type', 'required' => true, @@ -95,7 +97,9 @@ class IcingaCloneObjectForm extends DirectorForm } } - if ($this->object->isTemplate() && $this->object->supportsFields()) { + if (($this->object->isTemplate() || $this->object instanceof IcingaCommand) + && $this->object->supportsFields() + ) { $this->addBoolean('clone_fields', [ 'label' => $this->translate('Clone Template Fields'), 'description' => $this->translate( @@ -132,7 +136,7 @@ class IcingaCloneObjectForm extends DirectorForm $connection = $object->getConnection(); $db = $connection->getDbAdapter(); $newName = $this->getValue('new_object_name'); - $resolve = Acl::instance()->hasPermission('director/admin') + $resolve = Acl::instance()->hasPermission(Permission::ADMIN) && $this->getValue('clone_type') === 'flat'; $msg = sprintf( @@ -189,7 +193,7 @@ class IcingaCloneObjectForm extends DirectorForm $fields = $db->fetchAll( $db->select() ->from($table . '_field') - ->where("${type}_id = ?", $object->get('id')) + ->where("{$type}_id = ?", $object->get('id')) ); } else { $fields = []; @@ -221,7 +225,7 @@ class IcingaCloneObjectForm extends DirectorForm } foreach ($fields as $row) { - $row->{"${type}_id"} = $newId; + $row->{"{$type}_id"} = $newId; $db->insert($table . '_field', (array) $row); } @@ -247,6 +251,7 @@ class IcingaCloneObjectForm extends DirectorForm return $db->fetchPairs( $db->select() ->from('icinga_service_set', ['id', 'object_name']) + ->where('object_type = ?', 'template') ->order('object_name') ); } diff --git a/application/forms/IcingaDependencyForm.php b/application/forms/IcingaDependencyForm.php index ab30844..56597f9 100644 --- a/application/forms/IcingaDependencyForm.php +++ b/application/forms/IcingaDependencyForm.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Forms; use Icinga\Module\Director\Data\Db\DbObject; use Icinga\Module\Director\Web\Form\DirectorObjectForm; use Icinga\Module\Director\Objects\IcingaDependency; +use Zend_Validate_Callback; class IcingaDependencyForm extends DirectorObjectForm { @@ -164,7 +165,7 @@ class IcingaDependencyForm extends DirectorObjectForm ], null); $this->addBoolean('disable_notifications', [ - 'label' => $this->translate('Disable Notificiations'), + 'label' => $this->translate('Disable Notifications'), 'description' => $this->translate( 'Whether to disable notifications when this dependency fails.' . ' Defaults to true.' @@ -192,38 +193,83 @@ class IcingaDependencyForm extends DirectorObjectForm $parentHost = $dependency->get('parent_host'); if ($parentHost === null) { $parentHostVar = $dependency->get('parent_host_var'); - if (\strlen($parentHostVar) > 0) { + if ($parentHostVar !== null && \strlen($parentHostVar) > 0) { $parentHost = '$' . $dependency->get('parent_host_var') . '$'; } } + + $parentHostDescription = $this->translate('Optional. The parent host.'); + $applyTo = $this->getSentOrObjectValue('apply_to'); + $parentHostValidator = new Zend_Validate_Callback(function ($value) use ($applyTo) { + if ($applyTo === 'host' && $this->isCustomVar($value)) { + return explode('.', trim($value, '$'))[0] === 'host'; + } + + return true; + }); + + $parentHostValidator->setMessage( + $this->translate('The parent host cannot be a service custom variable for a host dependency'), + Zend_Validate_Callback::INVALID_VALUE + ); + + if ($applyTo === 'service') { + $additionalDescription = $this->translate( + 'You might want to refer to Host or Service Custom Variables via $host|service.vars.varname$' + ); + } else { + $additionalDescription = $this->translate( + 'You might want to refer to Host Custom Variables via $host.vars.varname$' + ); + } + + $parentHostDescription .= ' ' . $additionalDescription; + $this->addElement('text', 'parent_host', [ - 'label' => $this->translate('Parent Host'), - 'description' => $this->translate( - 'The parent host. You might want to refer Host Custom Variables' - . ' via $host.vars.varname$' - ), - 'class' => "autosubmit director-suggest", + 'label' => $this->translate('Parent Host'), + 'description' => $parentHostDescription, + 'class' => "autosubmit director-suggest", 'data-suggestion-context' => 'hostnames', - 'order' => 10, - 'required' => $this->isObject(), - 'value' => $parentHost + 'order' => 10, + 'required' => $this->isObject(), + 'value' => $parentHost, + 'validators' => [$parentHostValidator] ]); $sentParent = $this->getSentOrObjectValue('parent_host'); if (!empty($sentParent) || $dependency->isApplyRule()) { $parentService = $dependency->get('parent_service'); + if ($parentService === null) { + $parentServiceVar = $dependency->get('parent_service_by_name'); + if ($parentServiceVar) { + $parentService = '$' . $parentServiceVar . '$'; + } + } + + $parentServiceDescription = $this->translate( + 'Optional. The parent service. If omitted this dependency' + . ' object is treated as host dependency.' + ); + + $parentServiceDescription .= ' ' . $additionalDescription; + + $parentServiceValidator = clone $parentHostValidator; + + $parentServiceValidator->setMessage( + $this->translate('The parent service cannot be a service custom variable for a host dependency'), + Zend_Validate_Callback::INVALID_VALUE + ); + $this->addElement('text', 'parent_service', [ - 'label' => $this->translate('Parent Service'), - 'description' => $this->translate( - 'Optional. The parent service. If omitted this dependency' - . ' object is treated as host dependency.' - ), - 'class' => "autosubmit director-suggest", - 'data-suggestion-context' => 'servicenames', - 'data-suggestion-for-host' => $sentParent, - 'order' => 20, - 'value' => $parentService - ]); + 'label' => $this->translate('Parent Service'), + 'description' => $parentServiceDescription, + 'class' => "autosubmit director-suggest", + 'data-suggestion-context' => 'servicenames', + 'data-suggestion-for-host' => $sentParent, + 'order' => 20, + 'value' => $parentService, + 'validators' => [$parentServiceValidator] + ]); } // If configuring Object, allow selection of child host and/or service, @@ -290,11 +336,22 @@ class IcingaDependencyForm extends DirectorObjectForm protected function handleProperties(DbObject $object, &$values) { if ($this->hasBeenSent()) { - if (isset($values['parent_host']) - && $this->isCustomVar($values['parent_host']) - ) { - $values['parent_host_var'] = \trim($values['parent_host'], '$'); - $values['parent_host'] = ''; + if (isset($values['parent_host'])) { + if ($this->isCustomVar($values['parent_host'])) { + $values['parent_host_var'] = \trim($values['parent_host'], '$'); + $values['parent_host'] = ''; + } else { + $values['parent_host_var'] = ''; + } + } + + if (isset($values['parent_service'])) { + if ($this->isCustomVar($values['parent_service'])) { + $values['parent_service_by_name'] = trim($values['parent_service'], '$'); + $values['parent_service'] = ''; + } else { + $values['parent_service_by_name'] = ''; + } } } @@ -303,7 +360,6 @@ class IcingaDependencyForm extends DirectorObjectForm protected function isCustomVar($string) { - return \preg_match('/^\$(?:host)\.vars\..+\$$/', $string); - // Eventually: return \preg_match('/^\$(?:host|service)\.vars\..+\$$/', $string); + return preg_match('/^\$(?:host|service)\.vars\..+\$$/', $string); } } diff --git a/application/forms/IcingaHostForm.php b/application/forms/IcingaHostForm.php index ec71471..ed57251 100644 --- a/application/forms/IcingaHostForm.php +++ b/application/forms/IcingaHostForm.php @@ -3,6 +3,8 @@ namespace Icinga\Module\Director\Forms; use Icinga\Exception\AuthenticationException; +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Auth\Restriction; use Icinga\Module\Director\Repository\IcingaTemplateRepository; use Icinga\Module\Director\Restriction\HostgroupRestriction; use Icinga\Module\Director\Web\Form\DirectorObjectForm; @@ -162,7 +164,7 @@ class IcingaHostForm extends DirectorObjectForm if ($this->hasBeenSent()) { $this->addError($this->translate('No Host template has been chosen')); } else { - if ($this->hasPermission('director/admin')) { + if ($this->hasPermission(Permission::ADMIN)) { $html = sprintf( $this->translate('Please define a %s first'), Link::create( @@ -208,7 +210,7 @@ class IcingaHostForm extends DirectorObjectForm protected function addGroupsElement() { if ($this->hasHostGroupRestriction() - && ! $this->getAuth()->hasPermission('director/groups-for-restricted-hosts') + && ! $this->getAuth()->hasPermission(Permission::GROUPS_FOR_RESTRICTED_HOSTS) ) { return $this; } @@ -262,15 +264,6 @@ class IcingaHostForm extends DirectorObjectForm return $this; } - protected function strikeGroupLinks(BaseHtmlElement $links) - { - /** @var BaseHtmlElement $link */ - foreach ($links->getContent() as $link) { - $link->getAttributes()->add('style', 'text-decoration: strike'); - } - $links->add('aha'); - } - protected function getInheritedGroups() { if ($this->hasObject()) { @@ -295,9 +288,7 @@ class IcingaHostForm extends DirectorObjectForm ); } - return Html::tag('span', [ - 'style' => 'line-height: 2.5em; padding-left: 0.5em' - ], $links); + return Html::tag('span', ['class' => 'host-group-links'], $links); } protected function getAppliedGroups() @@ -311,7 +302,7 @@ class IcingaHostForm extends DirectorObjectForm protected function hasHostGroupRestriction() { - return $this->getAuth()->getRestrictions('director/filter/hostgroups'); + return $this->getAuth()->getRestrictions(Restriction::FILTER_HOSTGROUPS); } /** diff --git a/application/forms/IcingaNotificationForm.php b/application/forms/IcingaNotificationForm.php index 0fca6b8..bf9f75d 100644 --- a/application/forms/IcingaNotificationForm.php +++ b/application/forms/IcingaNotificationForm.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Forms; +use Icinga\Module\Director\DataType\DataTypeDirectorObject; use Icinga\Module\Director\Web\Form\DirectorObjectForm; class IcingaNotificationForm extends DirectorObjectForm @@ -121,20 +122,32 @@ class IcingaNotificationForm extends DirectorObjectForm { $users = $this->enumUsers(); if (empty($users)) { - return $this; - } - - $this->addElement( - 'extensibleSet', - 'users', - array( + $this->addElement('select', 'users', [ + 'label' => $this->translate('Users'), + 'description' => $this->translate('No User object has been created yet'), + 'multiOptions' => $this->optionalEnum([]), + ]); + } else { + $this->addElement('extensibleSet', 'users', [ 'label' => $this->translate('Users'), 'description' => $this->translate( 'Users that should be notified by this notifications' ), 'multiOptions' => $this->optionalEnum($users) + ]); + } + + $this->addElement('select', 'users_var', [ + 'label' => $this->translate('Users Custom Variable'), + 'multiOptions' => $this->enumDirectorObjectFields('user'), + 'description' => $this->translate( + 'If defined, Users from this Custom Variable will be combined with single users chosen below. ' + . ' e.g.: when set to notification_contacts, this notification will pick Users from the Array' + . ' service.vars.notification_contacts and fall back to host.vars.notification_contacts, in' + . ' case the former one does not exist.' + . ' Only Array type DirectorObject Fields for User objects are eligible for this feature.' ) - ); + ]); return $this; } @@ -146,24 +159,59 @@ class IcingaNotificationForm extends DirectorObjectForm { $groups = $this->enumUsergroups(); if (empty($groups)) { - return $this; - } - - $this->addElement( - 'extensibleSet', - 'user_groups', - array( + $this->addElement('select', 'user_groups', [ + 'label' => $this->translate('Users'), + 'description' => $this->translate('No UserGroup object has been created yet'), + 'multiOptions' => $this->optionalEnum([]), + ]); + } else { + $this->addElement('extensibleSet', 'user_groups', [ 'label' => $this->translate('User groups'), 'description' => $this->translate( 'User groups that should be notified by this notifications' ), 'multiOptions' => $this->optionalEnum($groups) + ]); + } + + $this->addElement('select', 'user_groups_var', [ + 'label' => $this->translate('User Groups Custom Variable'), + 'multiOptions' => $this->enumDirectorObjectFields('usergroup'), + 'description' => $this->translate( + 'If defined, User Groups from this Custom Variable will be combined with single Groups chosen below. ' + . ' e.g.: when set to notification_groups, this notification will pick User Groups from the Array' + . ' service.vars.notification_groups and fall back to host.vars.notification_groups, in' + . ' case the former one does not exist.' + . ' Only Array type DirectorObject Fields for User objects are eligible for this feature.' ) - ); + ]); return $this; } + protected function enumDirectorObjectFields($objectType, $dataType = 'array') + { + $db = $this->db->getDbAdapter(); + $query = $db->select() + ->from(['df' => 'director_datafield'], ['k' => 'df.varname', 'v' => 'df.varname']) + ->join( + ['dfs' => 'director_datafield_setting'], + $db->quoteInto('df.id = dfs.datafield_id AND dfs.setting_name = ?', 'icinga_object_type'), + [] + ) + ->join( + ['dft' => 'director_datafield_setting'], + $db->quoteInto('df.id = dft.datafield_id AND dft.setting_name = ?', 'data_type'), + [] + ) + ->where('df.datatype = ?', DataTypeDirectorObject::class) + ->where('dfs.setting_value = ?', $objectType) + ->where('dft.setting_value = ?', $dataType) + ->order('df.varname'); + + return $this->optionalEnum($db->fetchPairs($query)); + } + /** * @return self */ @@ -196,7 +244,7 @@ class IcingaNotificationForm extends DirectorObjectForm array( 'label' => $this->translate('First notification delay'), 'description' => $this->translate( - 'Delay unless the first notification should be sent' + 'Delay until the first notification should be sent' ) . '. ' . $this->getTimeValueInfo() ) ); diff --git a/application/forms/IcingaObjectFieldForm.php b/application/forms/IcingaObjectFieldForm.php index 537c95e..3b503fc 100644 --- a/application/forms/IcingaObjectFieldForm.php +++ b/application/forms/IcingaObjectFieldForm.php @@ -2,6 +2,9 @@ namespace Icinga\Module\Director\Forms; +use Icinga\Module\Director\DataType\DataTypeBoolean; +use Icinga\Module\Director\DataType\DataTypeString; +use Icinga\Module\Director\Field\FormFieldSuggestion; use Icinga\Module\Director\Objects\IcingaCommand; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaObject; @@ -15,6 +18,9 @@ class IcingaObjectFieldForm extends DirectorObjectForm /** @var IcingaObject Please note that $object would conflict with logic in parent class */ protected $icingaObject; + /** @var FormFieldSuggestion */ + protected $fieldSuggestion; + public function setIcingaObject($object) { $this->icingaObject = $object; @@ -36,22 +42,9 @@ class IcingaObjectFieldForm extends DirectorObjectForm . ' a specific set, shown as a dropdown.' ); - // TODO: remove assigned ones! - $existingFields = $this->db->enumDatafields(); - $blacklistedVars = array(); - $suggestedFields = array(); - - foreach ($existingFields as $id => $field) { - if (preg_match('/ \(([^\)]+)\)$/', $field, $m)) { - $blacklistedVars['$' . $m[1] . '$'] = $id; - } - } - // TODO: think about imported existing vars without fields // TODO: extract vars from command line (-> dummy) // TODO: do not suggest chosen ones - $argumentVars = array(); - $argumentVarDescriptions = array(); if ($object instanceof IcingaCommand) { $command = $object; } elseif ($object->hasProperty('check_command_id')) { @@ -60,56 +53,16 @@ class IcingaObjectFieldForm extends DirectorObjectForm $command = null; } - if ($command) { - foreach ($command->arguments() as $arg) { - if ($arg->argument_format === 'string') { - $val = $arg->argument_value; - // TODO: create var::extractMacros or so - - if (preg_match_all('/(\$[a-z0-9_]+\$)/i', $val, $m, PREG_PATTERN_ORDER)) { - foreach ($m[1] as $val) { - if (array_key_exists($val, $blacklistedVars)) { - $id = $blacklistedVars[$val]; - - // Hint: if not set it might already have been - // removed in this loop - if (array_key_exists($id, $existingFields)) { - $suggestedFields[$id] = $existingFields[$id]; - unset($existingFields[$id]); - } - } else { - $argumentVars[$val] = $val; - $argumentVarDescriptions[$val] = $arg->description; - } - } - } - } - } - } - - // Prepare combined fields array - $fields = array(); - if (! empty($suggestedFields)) { - asort($existingFields); - $fields[$this->translate('Suggested fields')] = $suggestedFields; - } - - if (! empty($argumentVars)) { - ksort($argumentVars); - $fields[$this->translate('Argument macros')] = $argumentVars; - } - - if (! empty($existingFields)) { - $fields[$this->translate('Other available fields')] = $existingFields; - } + $suggestions = $this->fieldSuggestion = new FormFieldSuggestion($command, $this->db->enumDatafields()); + $fields = $suggestions->getCommandFields(); - $this->addElement('select', 'datafield_id', array( + $this->addElement('select', 'datafield_id', [ 'label' => 'Field', 'required' => true, 'description' => 'Field to assign', 'class' => 'autosubmit', 'multiOptions' => $this->optionalEnum($fields) - )); + ]); if (empty($fields)) { // TODO: show message depending on permissions @@ -121,67 +74,58 @@ class IcingaObjectFieldForm extends DirectorObjectForm } if (($id = $this->getSentValue('datafield_id')) && ! ctype_digit($id)) { - $this->addElement('text', 'caption', array( + $this->addElement('text', 'caption', [ 'label' => $this->translate('Caption'), 'required' => true, 'ignore' => true, 'value' => trim($id, '$'), - 'description' => $this->translate('The caption which should be displayed') - )); + 'description' => $this->translate( + 'The caption which should be displayed to your users when this field' + . ' is shown' + ) + ]); - $this->addElement('textarea', 'description', array( + $this->addElement('textarea', 'description', [ 'label' => $this->translate('Description'), - 'description' => $this->translate('A description about the field'), + 'description' => $this->translate( + 'An extended description for this field. Will be shown as soon as a' + . ' user puts the focus on this field' + ), 'ignore' => true, - 'value' => array_key_exists($id, $argumentVarDescriptions) ? $argumentVarDescriptions[$id] : null, + 'value' => $command ? $suggestions->getDescription($id) : null, 'rows' => '3', - )); + ]); } - $this->addElement('select', 'is_required', array( + $this->addElement('select', 'is_required', [ 'label' => $this->translate('Mandatory'), 'description' => $this->translate('Whether this field should be mandatory'), 'required' => true, - 'multiOptions' => array( + 'multiOptions' => [ 'n' => $this->translate('Optional'), 'y' => $this->translate('Mandatory'), - ) - )); - - $filterFields = array(); - $prefix = null; - if ($object instanceof IcingaHost) { - $prefix = 'host.vars.'; - } elseif ($object instanceof IcingaService) { - $prefix = 'service.vars.'; - } + ] + ]); - if ($prefix) { - $loader = new IcingaObjectFieldLoader($object); - $fields = $loader->getFields(); - - foreach ($fields as $varName => $field) { - $filterFields[$prefix . $field->varname] = $field->caption; - } - - $this->addFilterElement('var_filter', array( + if ($filterFields = $this->getFilterFields($object)) { + $this->addFilterElement('var_filter', [ 'description' => $this->translate( 'You might want to show this field only when certain conditions are met.' . ' Otherwise it will not be available and values eventually set before' . ' will be cleared once stored' ), 'columns' => $filterFields, - )); + ]); - $this->addDisplayGroup(array($this->getElement('var_filter')), 'field_filter', array( - 'decorators' => array( + $this->addDisplayGroup([$this->getElement('var_filter')], 'field_filter', [ + 'decorators' => [ 'FormElements', - array('HtmlTag', array('tag' => 'dl')), + ['HtmlTag', ['tag' => 'dl']], 'Fieldset', - ), + ], 'order' => 30, 'legend' => $this->translate('Show based on filter') - )); + ]); } $this->setButtons(); @@ -202,18 +146,42 @@ class IcingaObjectFieldForm extends DirectorObjectForm $fieldId = $this->getValue('datafield_id'); if (! ctype_digit($fieldId)) { - $field = DirectorDatafield::create(array( + $field = DirectorDatafield::create([ 'varname' => trim($fieldId, '$'), 'caption' => $this->getValue('caption'), 'description' => $this->getValue('description'), - 'datatype' => 'Icinga\Module\Director\DataType\DataTypeString', - )); + 'datatype' => $this->fieldSuggestion && $this->fieldSuggestion->isBoolean($fieldId) + ? DataTypeBoolean::class + : DataTypeString::class + ]); $field->store($this->getDb()); $this->setElementValue('datafield_id', $field->get('id')); $this->object()->set('datafield_id', $field->get('id')); } $this->object()->set('var_filter', $this->getValue('var_filter')); - return parent::onSuccess(); + parent::onSuccess(); + } + + protected static function getFilterFields(IcingaObject $object): array + { + $filterFields = []; + $prefix = null; + if ($object instanceof IcingaHost) { + $prefix = 'host.vars.'; + } elseif ($object instanceof IcingaService) { + $prefix = 'service.vars.'; + } + + if ($prefix) { + $loader = new IcingaObjectFieldLoader($object); + $fields = $loader->getFields(); + + foreach ($fields as $varName => $field) { + $filterFields[$prefix . $field->get('varname')] = $field->get('caption'); + } + } + + return $filterFields; } } diff --git a/application/forms/IcingaServiceForm.php b/application/forms/IcingaServiceForm.php index f22f9e6..5744d8d 100644 --- a/application/forms/IcingaServiceForm.php +++ b/application/forms/IcingaServiceForm.php @@ -6,8 +6,10 @@ use gipfl\Web\Widget\Hint; use Icinga\Data\Filter\Filter; use Icinga\Exception\IcingaException; use Icinga\Exception\ProgrammingError; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Data\PropertiesFilter\ArrayCustomVariablesFilter; use Icinga\Module\Director\Exception\NestingError; +use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Web\Form\DirectorObjectForm; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaService; @@ -196,14 +198,16 @@ class IcingaServiceForm extends DirectorObjectForm } /** - * @param IcingaService $service - * @return IcingaService + * Hint: could be moved elsewhere + * + * @param IcingaService $object + * @return IcingaObject|IcingaService|IcingaServiceSet * @throws \Icinga\Exception\NotFoundError */ - protected function getFirstParent(IcingaService $service) + protected static function getFirstParent(IcingaObject $object) { - /** @var IcingaService[] $objects */ - $objects = $service->imports()->getObjects(); + /** @var IcingaObject[] $objects */ + $objects = $object->imports()->getObjects(); if (empty($objects)) { throw new RuntimeException('Something went wrong, got no parent'); } @@ -300,7 +304,7 @@ class IcingaServiceForm extends DirectorObjectForm if ($this->set) { return $this->object; } else { - return $this->getFirstParent($this->object); + return self::getFirstParent($this->object); } } @@ -355,7 +359,7 @@ class IcingaServiceForm extends DirectorObjectForm $objectType = 'template'; } $this->addHidden('object_type', $objectType); - $forceCommandElements = $this->hasPermission('director/admin'); + $forceCommandElements = $this->hasPermission(Permission::ADMIN); $this->addNameElement() ->addHostObjectElement() @@ -550,7 +554,7 @@ class IcingaServiceForm extends DirectorObjectForm ->addGroupsElement() ->groupMainProperties(); - if ($this->hasPermission('director/admin')) { + if ($this->hasPermission(Permission::ADMIN)) { $this->addCheckCommandElements(true) ->addCheckExecutionElements(true) ->addExtraInfoElements(); @@ -721,8 +725,7 @@ class IcingaServiceForm extends DirectorObjectForm protected function enumHosts() { $db = $this->db->getDbAdapter(); - $table = new ObjectsTableHost($this->db); - $table->setAuth($this->getAuth()); + $table = new ObjectsTableHost($this->db, $this->getAuth()); if ($this->branch && $this->branch->isBranch()) { $table->setBranchUuid($this->branch->getUuid()); } diff --git a/application/forms/IcingaServiceSetForm.php b/application/forms/IcingaServiceSetForm.php index 21508d5..38b848a 100644 --- a/application/forms/IcingaServiceSetForm.php +++ b/application/forms/IcingaServiceSetForm.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Forms; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Web\Form\DirectorObjectForm; @@ -113,7 +114,7 @@ class IcingaServiceSetForm extends DirectorObjectForm protected function addAssignmentElements() { - if (! $this->hasPermission('director/service_set/apply')) { + if (! $this->hasPermission(Permission::SERVICE_SET_APPLY)) { return $this; } diff --git a/application/forms/IcingaTemplateChoiceForm.php b/application/forms/IcingaTemplateChoiceForm.php index 31fe610..27af5d2 100644 --- a/application/forms/IcingaTemplateChoiceForm.php +++ b/application/forms/IcingaTemplateChoiceForm.php @@ -19,7 +19,7 @@ class IcingaTemplateChoiceForm extends DirectorObjectForm { if ($name !== null) { /** @var IcingaTemplateChoice $class - cheating IDE */ - $class = $this->getObjectClassName(); + $class = $this->getObjectClassname(); $this->setObject($class::load($name, $this->getDb())); } @@ -133,7 +133,7 @@ class IcingaTemplateChoiceForm extends DirectorObjectForm /** @var IcingaTemplateChoice $object */ $object = $this->object(); $this->setSuccessUrl( - 'director/templatechoice/' . $object->getObjectshortTableName(), + 'director/templatechoice/' . $object->getObjectShortTableName(), $object->getUrlParams() ); } diff --git a/application/forms/ImportRowModifierForm.php b/application/forms/ImportRowModifierForm.php index 9e53bd9..7033f4c 100644 --- a/application/forms/ImportRowModifierForm.php +++ b/application/forms/ImportRowModifierForm.php @@ -64,6 +64,41 @@ class ImportRowModifierForm extends DirectorObjectForm $error = $e->getMessage(); $mods = $this->optionalEnum([]); } + $this->addElement('YesNo', 'use_filter', [ + 'label' => $this->translate('Set based on filter'), + 'ignore' => true, + 'class' => 'autosubmit', + 'required' => true, + ]); + + if ($this->hasBeenSent()) { + $useFilter = $this->getSentValue('use_filter'); + if ($useFilter === null) { + $this->setElementValue('use_filter', $useFilter = 'n'); + } + } elseif ($object = $this->getObject()) { + $expression = $object->get('filter_expression'); + $useFilter = ($expression === null || strlen($expression) === 0) ? 'n' : 'y'; + $this->setElementValue('use_filter', $useFilter); + } else { + $this->setElementValue('use_filter', $useFilter = 'n'); + } + + if ($useFilter === 'y') { + $this->addElement('text', 'filter_expression', [ + 'label' => $this->translate('Filter Expression'), + 'description' => $this->translate( + 'This allows to filter for specific parts within the given source expression.' + . ' You are allowed to refer all imported columns. Examples: host=www* would' + . ' set this property only for rows imported with a host property starting' + . ' with "www". Complex example: host=www*&!(address=127.*|address6=::1).' + . ' Please note, that CIDR notation based matches are also supported: ' + . ' address=192.0.2.128/25| address=2001:db8::/32| address=::ffff:192.0.2.0/96' + ), + 'required' => true, + // TODO: validate filter + ]); + } $this->addElement('select', 'provider_class', [ 'label' => $this->translate('Modifier'), diff --git a/application/forms/RemoveLinkForm.php b/application/forms/RemoveLinkForm.php index 6f0c7cc..fb43db0 100644 --- a/application/forms/RemoveLinkForm.php +++ b/application/forms/RemoveLinkForm.php @@ -17,10 +17,7 @@ class RemoveLinkForm extends DirectorForm { // Required to detect the right instance $this->formName = 'RemoveSet' . sha1(json_encode($params)); - parent::__construct([ - 'style' => 'float: right', - 'data-base-target' => '_self' - ]); + parent::__construct(['data-base-target' => '_self']); $this->label = $label; $this->title = $title; foreach ($params as $name => $value) { @@ -38,7 +35,7 @@ class RemoveLinkForm extends DirectorForm public function setup() { - $this->setAttrib('class', 'inline'); + $this->addAttribs(['class' => ['inline', 'remove-link-form']]); $this->addHtml(Icon::create('cancel')); $this->addSubmitButton($this->label, [ 'class' => 'link-button', diff --git a/application/forms/SyncCheckForm.php b/application/forms/SyncCheckForm.php index 8fb3bd0..b180d3d 100644 --- a/application/forms/SyncCheckForm.php +++ b/application/forms/SyncCheckForm.php @@ -55,7 +55,7 @@ class SyncCheckForm extends DirectorForm } elseif ($sum['modify'] > 1) { } */ - $html = '<pre>' . print_r($sum, 1) . '</pre>'; + $html = '<pre>' . print_r($sum, true) . '</pre>'; $this->addHtml($html); } elseif ($this->rule->get('sync_state') === 'in-sync') { diff --git a/application/locale/de_DE/LC_MESSAGES/director.mo b/application/locale/de_DE/LC_MESSAGES/director.mo Binary files differindex 3cf12af..fb9e2fd 100644 --- a/application/locale/de_DE/LC_MESSAGES/director.mo +++ b/application/locale/de_DE/LC_MESSAGES/director.mo diff --git a/application/locale/de_DE/LC_MESSAGES/director.po b/application/locale/de_DE/LC_MESSAGES/director.po index ec2fb2a..0ee94ed 100644 --- a/application/locale/de_DE/LC_MESSAGES/director.po +++ b/application/locale/de_DE/LC_MESSAGES/director.po @@ -1,378 +1,379 @@ # Director - Config tool for Icinga 2. -# Copyright (C) 2022 TEAM NAME +# Copyright (C) 2023 Icinga # This file is distributed under the same license as Director Module. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -# +# +#, fuzzy msgid "" msgstr "" "Project-Id-Version: Director Module (master)\n" -"Report-Msgid-Bugs-To: https://github.com/Icinga/icingaweb2-module-director/issues\n" -"POT-Creation-Date: 2022-09-21 07:17+0000\n" -"PO-Revision-Date: 2022-09-21 09:21+0200\n" +"Report-Msgid-Bugs-To: ISSUE TRACKER\n" +"POT-Creation-Date: 2023-09-21 08:58+0000\n" +"PO-Revision-Date: 2023-09-21 10:53+0200\n" "Last-Translator: Thomas Gelf <thomas@gelf.net>\n" -"Language-Team: \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-Poedit-Basepath: .\n" -"X-Generator: Poedit 3.0.1\n" "X-Poedit-SearchPath-0: .\n" -#: library/Director/Web/Form/DirectorObjectForm.php:615 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:618 #, php-format msgid " (inherited from \"%s\")" msgstr " (geerbt von \"%s\")" -#: library/Director/Web/Table/TemplatesTable.php:64 +#: ../../../../library/Director/Web/Table/TemplatesTable.php:64 msgid " - not in use -" msgstr " - unbenutzt -" -#: library/Director/Web/Table/DatafieldCategoryTable.php:48 -#: library/Director/Web/Table/DatafieldTable.php:52 +#: ../../../../library/Director/Web/Table/DatafieldTable.php:54 +#: ../../../../library/Director/Web/Table/DatafieldCategoryTable.php:48 msgid "# Used" msgstr "# Benutzt" -#: library/Director/Web/Table/DatafieldTable.php:53 +#: ../../../../library/Director/Web/Table/DatafieldTable.php:55 msgid "# Vars" msgstr "# Vars" -#: library/Director/Web/Table/CustomvarTable.php:29 +#: ../../../../library/Director/Web/Table/CustomvarTable.php:29 #, php-format msgid "%d / %d" msgstr "%d / %d" -#: library/Director/Resolver/CommandUsage.php:51 +#: ../../../../library/Director/Resolver/CommandUsage.php:51 #, php-format msgid "%d Host Template(s)" msgstr "%d Host-Vorlagen" -#: library/Director/Resolver/CommandUsage.php:50 +#: ../../../../library/Director/Resolver/CommandUsage.php:50 #, php-format msgid "%d Host(s)" msgstr "%d Host(s)" -#: library/Director/Resolver/CommandUsage.php:61 +#: ../../../../library/Director/Resolver/CommandUsage.php:61 #, php-format msgid "%d Notification Apply Rule(s)" msgstr "%d Benachrichtigungs-Apply-Regeln" -#: library/Director/Resolver/CommandUsage.php:60 +#: ../../../../library/Director/Resolver/CommandUsage.php:60 #, php-format msgid "%d Notification Template(s)" msgstr "%d Benachrichtigungsvorlagen" -#: library/Director/Resolver/CommandUsage.php:59 +#: ../../../../library/Director/Resolver/CommandUsage.php:59 #, php-format msgid "%d Notification(s)" msgstr "%d Benachrichtigung(en)" -#: library/Director/Resolver/CommandUsage.php:56 +#: ../../../../library/Director/Resolver/CommandUsage.php:56 #, php-format msgid "%d Service Apply Rule(s)" msgstr "%d Service Apply-Regel(n)" -#: library/Director/Resolver/CommandUsage.php:55 +#: ../../../../library/Director/Resolver/CommandUsage.php:55 #, php-format msgid "%d Service Template(s)" msgstr "%d Service-Vorlage(n)" -#: library/Director/Resolver/CommandUsage.php:54 +#: ../../../../library/Director/Resolver/CommandUsage.php:54 #, php-format msgid "%d Service(s)" msgstr "%d Service(s)" -#: library/Director/Dashboard/Dashlet/Dashlet.php:170 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:170 #, php-format msgid "%d apply rules have been defined" msgstr "%d Apply-Regeln wurden definiert" -#: library/Director/Db/Branch/BranchModificationInspection.php:68 -#: library/Director/Web/Table/SyncRunTable.php:49 -#: library/Director/Web/Widget/SyncRunDetails.php:77 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:68 +#: ../../../../library/Director/Web/Table/SyncRunTable.php:49 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:77 #, php-format msgid "%d created" msgstr "%d erstellt" -#: library/Director/Db/Branch/BranchModificationInspection.php:71 -#: library/Director/Web/Table/SyncRunTable.php:61 -#: library/Director/Web/Widget/SyncRunDetails.php:89 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:71 +#: ../../../../library/Director/Web/Table/SyncRunTable.php:61 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:89 #, php-format msgid "%d deleted" msgstr "%d gelöscht" -#: library/Director/Web/Widget/DeploymentInfo.php:110 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:111 #, php-format msgid "%d files" msgstr "%d Dateien" -#: library/Director/Web/Widget/DeployedConfigInfoHeader.php:93 +#: ../../../../library/Director/Web/Widget/DeployedConfigInfoHeader.php:93 #, php-format msgid "%d files rendered in %0.2fs" msgstr "%d Dateien in %0.2fs erstellt" -#: library/Director/Dashboard/Dashlet/Dashlet.php:212 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:212 #, php-format msgid "%d have been externally defined and will not be deployed" msgstr "%d wurden extern definiert und werden nicht ausgerollt" -#: library/Director/Db/Branch/BranchModificationInspection.php:74 -#: library/Director/Web/Table/SyncRunTable.php:55 -#: library/Director/Web/Widget/SyncRunDetails.php:83 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:74 +#: ../../../../library/Director/Web/Table/SyncRunTable.php:55 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:83 #, php-format msgid "%d modified" msgstr "%d geändert" -#: application/controllers/SyncruleController.php:353 +#: ../../../../application/controllers/SyncruleController.php:353 #, php-format msgid "%d object(s) will be created" msgstr "%d Objekt(e) werden erstellt" -#: application/controllers/SyncruleController.php:334 +#: ../../../../application/controllers/SyncruleController.php:334 #, php-format msgid "%d object(s) will be deleted" msgstr "%d Objekt(e) werden gelöscht" -#: application/controllers/SyncruleController.php:343 +#: ../../../../application/controllers/SyncruleController.php:343 #, php-format msgid "%d object(s) will be modified" msgstr "%d Objekt(e) werden verändert" -#: application/controllers/InspectController.php:76 +#: ../../../../application/controllers/InspectController.php:76 #, php-format msgid "%d objects found" msgstr "%d Objekte gefunden" -#: library/Director/Dashboard/Dashlet/Dashlet.php:195 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:195 #, php-format msgid "%d objects have been defined" msgstr "%d Objekte wurden definiert" -#: application/forms/IcingaMultiEditForm.php:93 +#: ../../../../application/forms/IcingaMultiEditForm.php:93 #, php-format msgid "%d objects have been modified" msgstr "%d Objekte wurden verändert" -#: library/Director/Web/Widget/DeploymentInfo.php:119 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:120 #, php-format msgid "%d objects, %d templates, %d apply rules" msgstr "%d Objekte, %d Vorlagen, %d Apply-Regeln" -#: library/Director/Dashboard/Dashlet/Dashlet.php:204 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:204 #, php-format msgid "%d of them are templates" msgstr "%d davon sind Vorlagen" -#: library/Director/Dashboard/Dashlet/Dashlet.php:152 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:152 #, php-format msgid "%d templates have been defined" msgstr "%d Vorlagen wurden definiert" -#: library/Director/Web/Widget/ActivityLogInfo.php:581 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:581 #, php-format msgid "%s \"%s\" has been created" msgstr "%s \"%s\" wurde erstellt" -#: library/Director/Web/Widget/ActivityLogInfo.php:584 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:584 #, php-format msgid "%s \"%s\" has been deleted" msgstr "%s \"%s\" wurde gelöscht" -#: application/forms/IcingaImportObjectForm.php:36 +#: ../../../../application/forms/IcingaImportObjectForm.php:36 #, php-format msgid "%s \"%s\" has been imported\"" msgstr "%s \"%s\" wurde importiert\"" -#: library/Director/Web/Widget/ActivityLogInfo.php:587 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:587 #, php-format msgid "%s \"%s\" has been modified" msgstr "%s \"%s\" wurde geändert" -#: library/Director/Web/Table/IcingaHostAppliedServicesTable.php:107 +#: ../../../../library/Director/Web/Table/IcingaHostAppliedServicesTable.php:107 #, php-format msgid "%s %s(%s)" msgstr "%s %s(%s)" -#: library/Director/Web/Table/ObjectSetTable.php:61 +#: ../../../../library/Director/Web/Table/ObjectSetTable.php:66 #, php-format msgid "%s (%d members)" msgstr "%s (%d Mitglieder)" -#: application/controllers/HostController.php:248 -#: application/controllers/HostController.php:328 +#: ../../../../application/controllers/HostController.php:235 +#: ../../../../application/controllers/HostController.php:315 #, php-format msgid "%s (Applied Service set)" msgstr "%s (zugewiesenes Service-Set)" -#: application/controllers/HostController.php:384 +#: ../../../../application/controllers/HostController.php:369 #, php-format msgid "%s (Service set)" msgstr "%s (Service-Set)" -#: application/forms/SettingsForm.php:189 -#: application/forms/SelfServiceSettingsForm.php:256 +#: ../../../../application/forms/SettingsForm.php:189 +#: ../../../../application/forms/SelfServiceSettingsForm.php:256 #, php-format msgid "%s (default)" msgstr "%s (default)" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:312 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:312 #, php-format msgid "%s (inherited from %s)" msgstr "%s (geerbt von %s)" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:307 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:307 #, php-format msgid "%s (inherited)" msgstr "%s (geerbt)" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:325 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:325 #, php-format msgid "%s (not an Array!)" msgstr "%s (kein Array)" -#: library/Director/Web/Controller/TemplateController.php:72 +#: ../../../../library/Director/Web/Controller/TemplateController.php:73 #, php-format msgid "%s Templates" msgstr "%s Vorlagen" -#: application/forms/IcingaCommandArgumentForm.php:137 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:137 #, php-format msgid "%s argument \"%s\" has been removed" msgstr "Das %s-Argument \"%s\" wurde entfernt" -#: library/Director/Web/Controller/TemplateController.php:37 +#: ../../../../library/Director/Web/Controller/TemplateController.php:38 #, php-format msgid "%s based on %s" msgstr "%s basierend auf %s" -#: library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:114 +#: ../../../../library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:114 #, php-format msgid "%s config changes are available in your configuration branch" msgstr "" "%s Konfigurationsänderungen sind in diesem Konfigurationszweig verfügbar" -#: library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:129 +#: ../../../../library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:129 #, php-format msgid "%s config changes happend since the last deployed configuration" msgstr "" "%s Konfigurationsänderungen seit der letzten ausgerollten Konfiguration" -#: application/forms/IcingaServiceForm.php:286 +#: ../../../../application/forms/IcingaServiceForm.php:290 #, php-format msgid "%s has been deactivated on %s" msgstr "%s wurde auf %s deaktiviert" -#: application/controllers/DataController.php:354 +#: ../../../../application/controllers/DataController.php:354 #, php-format msgid "%s instances" msgstr "%s Instanzen" -#: application/forms/IcingaServiceForm.php:322 +#: ../../../../application/forms/IcingaServiceForm.php:326 #, php-format msgid "%s is no longer deactivated on %s" msgstr "%s ist auf %s nicht mehr deaktiviert" -#: library/Director/Web/Widget/NotInBranchedHint.php:18 +#: ../../../../library/Director/Web/Widget/NotInBranchedHint.php:18 #, php-format msgid "%s is not available while being in a Configuration Branch: %s" msgstr "%s ist beim Arbeiten in einem Konfigurationszweig nicht verfügbar: %s" -#: library/Director/Web/Widget/SyncRunDetails.php:49 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:49 #, php-format msgid "%s objects have been modified" msgstr "%s Objekte wurden verändert" -#: application/controllers/DataController.php:359 +#: ../../../../application/controllers/DataController.php:359 #, php-format msgid "%s on %s" msgstr "%s auf %s" -#: application/controllers/HostController.php:542 +#: ../../../../application/controllers/HostController.php:520 #, php-format msgid "%s on %s (from set: %s)" msgstr "%s auf %s (aus dem Set \"%s\")" -#: library/Director/Dashboard/Dashlet/Dashlet.php:227 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:227 #, php-format msgid "%s related group objects have been created" msgstr "%s verwandte Gruppenobjekte wurden erstellt" -#: library/Director/Web/Controller/TemplateController.php:75 +#: ../../../../library/Director/Web/Controller/TemplateController.php:76 #, php-format msgid "%s templates based on %s" msgstr "%s Vorlagen basierend auf %s" -#: library/Director/Web/Widget/HealthCheckPluginOutput.php:46 +#: ../../../../library/Director/Web/Widget/HealthCheckPluginOutput.php:46 #, php-format msgid "%s: %d" msgstr "%s: %d" -#: application/controllers/BasketController.php:195 +#: ../../../../application/controllers/BasketController.php:219 #, php-format msgid "%s: %s (Snapshot)" msgstr "%s: %s (Snapshot)" -#: application/controllers/ImportsourceController.php:310 +#: ../../../../application/controllers/ImportsourceController.php:310 #, php-format msgid "%s: Property Modifier" msgstr "%s: Eigenschaftsmodifikatoren" -#: application/controllers/BasketController.php:146 +#: ../../../../application/controllers/BasketController.php:164 #, php-format msgid "%s: Snapshots" msgstr "%s: Snapshots" -#: application/controllers/ImportsourceController.php:280 +#: ../../../../application/controllers/ImportsourceController.php:280 #, php-format msgid "%s: add Property Modifier" msgstr "%s: Eigenschaftsmodifikator hinzufügen" -#: library/Director/Db/Housekeeping.php:54 +#: ../../../../library/Director/Db/Housekeeping.php:54 msgid "(Host) group resolve cache" msgstr "Gruppenmitgliedschaftscache (Hosts)" -#: application/controllers/ServiceController.php:187 +#: ../../../../application/controllers/ServiceController.php:187 #, php-format msgid "(on %s)" msgstr "(auf %s)" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:243 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:243 msgid "- add more -" msgstr "- mehr hinzuzufügen -" -#: library/Director/Web/Form/DirectorObjectForm.php:1090 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1093 msgid "- click to add more -" msgstr "- Hier klicken um mehr hinzuzufügen -" -#: application/forms/SelfServiceSettingsForm.php:79 +#: ../../../../application/forms/SelfServiceSettingsForm.php:79 msgid "- no automatic installation -" msgstr "- keine automatische Installation -" -#: library/Director/DataType/DataTypeDirectorObject.php:45 -#: library/Director/DataType/DataTypeSqlQuery.php:37 -#: library/Director/Job/ImportJob.php:118 -#: library/Director/Job/SyncJob.php:124 -#: library/Director/Web/Form/QuickBaseForm.php:119 -#: application/views/helpers/FormDataFilter.php:465 -#: application/forms/SettingsForm.php:193 -#: application/forms/SelfServiceSettingsForm.php:252 -#: application/controllers/ConfigController.php:383 -#: application/controllers/ConfigController.php:394 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:45 +#: ../../../../library/Director/DataType/DataTypeSqlQuery.php:37 +#: ../../../../library/Director/Job/ImportJob.php:118 +#: ../../../../library/Director/Job/SyncJob.php:124 +#: ../../../../library/Director/Web/Form/QuickBaseForm.php:119 +#: ../../../../application/views/helpers/FormDataFilter.php:465 +#: ../../../../application/forms/SettingsForm.php:193 +#: ../../../../application/forms/SelfServiceSettingsForm.php:252 +#: ../../../../application/forms/DirectorDatafieldForm.php:284 +#: ../../../../application/controllers/ConfigController.php:384 +#: ../../../../application/controllers/ConfigController.php:395 msgid "- please choose -" msgstr "- bitte wählen -" -#: application/controllers/SyncruleController.php:455 +#: ../../../../application/controllers/SyncruleController.php:455 #, php-format msgid "...and %d more" msgstr "...und %d weitere" -#: library/Director/Web/Controller/ObjectController.php:730 -#: application/controllers/ConfigController.php:452 +#: ../../../../library/Director/Web/Controller/ObjectController.php:741 +#: ../../../../application/controllers/ConfigController.php:453 msgid "...and the modifications below are already in the main branch:" msgstr "...und folgende Änderungen befinden sich bereits im Hauptzweig:" -#: application/controllers/BasketsController.php:34 +#: ../../../../application/controllers/BasketsController.php:34 msgid "" "A Configuration Basket references specific Configuration Objects or all " "objects of a specific type. It has been designed to share Templates, Import/" @@ -385,7 +386,7 @@ msgstr "" "teilen. Dies ist kein Werkzeug welches sich um einzelne Hosts oder Services " "kümmert." -#: library/Director/Import/ImportSourceLdap.php:64 +#: ../../../../library/Director/Import/ImportSourceLdap.php:64 msgid "" "A custom LDAP filter to use in addition to the object class. This allows for " "a lot of flexibility but requires LDAP filter skills. Simple filters might " @@ -396,7 +397,7 @@ msgstr "" "Kenntnisse über LDAP Filter. Einfache Filter können wie folgt aussehen: " "operatingsystem=*server*" -#: application/forms/SyncPropertyForm.php:215 +#: ../../../../application/forms/SyncPropertyForm.php:215 msgid "" "A custom string. Might contain source columns, please use placeholders of " "the form ${columnName} in such case. Structured data sources can be " @@ -406,15 +407,11 @@ msgstr "" "Platzhalter in der Form ${columnName} genutzt werden. Strukturierte Daten " "können mittels ${columnName.sub.key} addressiert werden" -#: application/forms/IcingaObjectFieldForm.php:134 -msgid "A description about the field" -msgstr "Eine Beschreibung des Feldes" - -#: application/forms/IcingaTemplateChoiceForm.php:59 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:59 msgid "A detailled description explaining what this choice is all about" msgstr "Eine detaillierte Beschreibung zum Sinn und Zweck dieser Auswahl" -#: application/forms/IcingaServiceSetForm.php:104 +#: ../../../../application/forms/IcingaServiceSetForm.php:105 msgid "" "A meaningful description explaining your users what to expect when assigning " "this set of services" @@ -423,26 +420,26 @@ msgstr "" "wenn dieses Service-Set zugewiesen wird" # Geschlecht kann hier leider nicht bestimmt werden -ThW -#: library/Director/Web/Form/DirectorObjectForm.php:662 -#: application/forms/IcingaTimePeriodRangeForm.php:85 -#: application/forms/IcingaScheduledDowntimeRangeForm.php:90 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:665 +#: ../../../../application/forms/IcingaTimePeriodRangeForm.php:85 +#: ../../../../application/forms/IcingaScheduledDowntimeRangeForm.php:90 #, php-format msgid "A new %s has successfully been created" msgstr "Ein neuer %s wurde erfolgreich erstellt" -#: application/forms/IcingaGenerateApiKeyForm.php:39 +#: ../../../../application/forms/IcingaGenerateApiKeyForm.php:39 #, php-format msgid "A new Self Service API key for %s has been generated" msgstr "Ein neuer Selbstbedienungs-API-Schlüssel für %s wurde erstellt" -#: application/forms/ImportRowModifierForm.php:72 +#: ../../../../application/forms/ImportRowModifierForm.php:107 msgid "" "A property modifier allows you to modify a specific property at import time" msgstr "" "Ein Eigenschaftsmodifikator erlaubt das Verändern bestimmter Eigenschaften " "während des Imports" -#: application/forms/ImportSourceForm.php:17 +#: ../../../../application/forms/ImportSourceForm.php:17 msgid "" "A short name identifying this import source. Use something meaningful, like " "\"Hosts from Puppet\", \"Users from Active Directory\" or similar" @@ -451,7 +448,7 @@ msgstr "" "Bezeichnungen wie \"Hosts aus Puppet\" oder \"Benutzer aus LDAP\" bieten " "sich an" -#: application/forms/DirectorJobForm.php:74 +#: ../../../../application/forms/DirectorJobForm.php:74 msgid "" "A short name identifying this job. Use something meaningful, like \"Import " "Puppet Hosts\"" @@ -459,11 +456,11 @@ msgstr "" "Eine kurzer Name um diesen Auftrag zu bezeichnen. Sprechende Bezeichnungen " "wie \"Puppet Hosts importieren\" bieten sich an" -#: application/forms/IcingaServiceSetForm.php:30 +#: ../../../../application/forms/IcingaServiceSetForm.php:31 msgid "A short name identifying this set of services" msgstr "Eine kurzer Name um dieses Service-Set zu bezeichnen" -#: library/Director/Web/SelfService.php:234 +#: ../../../../library/Director/Web/SelfService.php:221 #, php-format msgid "" "A ticket for this agent could not have been requested from your deployment " @@ -472,7 +469,7 @@ msgstr "" "Für diesen Agenten konnte kein Ticket vom Deployment-Endpoint angefordert " "werden: %s" -#: library/Director/Dashboard/Dashlet/DeploymentDashlet.php:95 +#: ../../../../library/Director/Dashboard/Dashlet/DeploymentDashlet.php:96 #, php-format msgid "" "A total of %d config changes happened since your last deployed config has " @@ -480,293 +477,293 @@ msgid "" msgstr "" "Insgesamt wurde die Konfiguration %d mal seit dem letzten Ausrollen geändert" -#: application/forms/IcingaHostSelfServiceForm.php:49 +#: ../../../../application/forms/IcingaHostSelfServiceForm.php:49 msgid "API Key" msgstr "API-Schlüssel" -#: library/Director/Db/Branch/BranchModificationInspection.php:34 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:34 msgid "API Users" msgstr "API Benutzer" -#: application/forms/IcingaEndpointForm.php:46 -#: application/forms/KickstartForm.php:155 +#: ../../../../application/forms/IcingaEndpointForm.php:46 +#: ../../../../application/forms/KickstartForm.php:155 msgid "API user" msgstr "API Benutzer" -#: library/Director/Web/Form/DirectorObjectForm.php:1434 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1437 msgid "Accept passive checks" msgstr "Passive Checkergebnisse akzeptieren" -#: application/forms/IcingaHostForm.php:93 +#: ../../../../application/forms/IcingaHostForm.php:95 msgid "Accepts config" msgstr "Akzeptiert Konfiguration" # Aktuell wird es so in anderen Modulen übersetzt. -ThW -#: library/Director/IcingaConfig/TypeFilterSet.php:28 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:28 msgid "Acknowledgement" msgstr "Bestätigung" -#: library/Director/Web/Table/ConfigFileDiffTable.php:81 -#: library/Director/Web/Widget/ActivityLogInfo.php:514 -#: library/Director/Web/Widget/ActivityLogInfo.php:525 -#: application/controllers/BranchController.php:62 +#: ../../../../library/Director/Web/Table/ConfigFileDiffTable.php:81 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:514 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:525 +#: ../../../../application/controllers/BranchController.php:61 msgid "Action" msgstr "Aktion" -#: library/Director/Web/Form/DirectorObjectForm.php:1547 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1550 msgid "Action URL" msgstr "Aktions-URL" -#: library/Director/Web/Table/QuickTable.php:281 -#: library/Director/Web/Widget/DeployedConfigInfoHeader.php:72 -#: library/Director/Web/Widget/ActivityLogInfo.php:555 +#: ../../../../library/Director/Web/Table/QuickTable.php:281 +#: ../../../../library/Director/Web/Widget/DeployedConfigInfoHeader.php:72 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:555 msgid "Actions" msgstr "Aktionen" -#: application/forms/SettingsForm.php:175 +#: ../../../../application/forms/SettingsForm.php:175 msgid "Activation Tool" msgstr "Aktivierungswerkzeug" -#: application/forms/SettingsForm.php:154 +#: ../../../../application/forms/SettingsForm.php:154 msgid "Active-Passive" msgstr "Aktiv-Passiv" -#: library/Director/Web/Widget/SyncRunDetails.php:30 -#: application/controllers/BranchController.php:48 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:30 +#: ../../../../application/controllers/BranchController.php:47 msgid "Activity" msgstr "Aktivität" -#: library/Director/Dashboard/Dashlet/ActivityLogDashlet.php:11 -#: library/Director/Web/Tabs/InfraTabs.php:29 -#: application/controllers/ConfigController.php:160 +#: ../../../../library/Director/Dashboard/Dashlet/ActivityLogDashlet.php:13 +#: ../../../../library/Director/Web/Tabs/InfraTabs.php:30 +#: ../../../../application/controllers/ConfigController.php:161 msgid "Activity Log" msgstr "Aktivitätslog" -#: library/Director/Web/Controller/ObjectController.php:304 +#: ../../../../library/Director/Web/Controller/ObjectController.php:307 #, php-format msgid "Activity Log: %s" msgstr "Aktivitätslog: %s" -#: configuration.php:173 +#: ../../../../configuration.php:141 msgid "Activity log" msgstr "Aktivitätslog" -#: library/Director/Web/ActionBar/TemplateActionBar.php:19 -#: library/Director/Web/ActionBar/ChoicesActionBar.php:16 -#: library/Director/Web/ActionBar/ObjectsActionBar.php:16 -#: library/Director/Web/Form/DirectorObjectForm.php:504 -#: library/Director/Web/Controller/ActionController.php:166 -#: library/Director/Web/Controller/ObjectsController.php:315 -#: library/Director/Web/Controller/ObjectsController.php:356 -#: application/forms/AddToBasketForm.php:73 -#: application/controllers/DataController.php:34 -#: application/controllers/DataController.php:77 -#: application/controllers/DataController.php:95 -#: application/controllers/DataController.php:171 +#: ../../../../library/Director/Web/ActionBar/TemplateActionBar.php:19 +#: ../../../../library/Director/Web/ActionBar/ChoicesActionBar.php:16 +#: ../../../../library/Director/Web/ActionBar/ObjectsActionBar.php:16 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:505 +#: ../../../../library/Director/Web/Controller/ActionController.php:166 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:315 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:356 +#: ../../../../application/forms/AddToBasketForm.php:73 +#: ../../../../application/controllers/DataController.php:34 +#: ../../../../application/controllers/DataController.php:77 +#: ../../../../application/controllers/DataController.php:95 +#: ../../../../application/controllers/DataController.php:171 msgid "Add" msgstr "Hinzufügen" -#: library/Director/Web/Tabs/ObjectTabs.php:51 -#: library/Director/Web/Controller/ObjectController.php:104 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:52 +#: ../../../../library/Director/Web/Controller/ObjectController.php:106 #, php-format msgid "Add %s" msgstr "%s hinzufügen" -#: application/forms/AddToBasketForm.php:69 +#: ../../../../application/forms/AddToBasketForm.php:69 #, php-format msgid "Add %s objects" msgstr "%s Objekte hinzufügen" -#: library/Director/Web/Controller/ObjectController.php:446 +#: ../../../../library/Director/Web/Controller/ObjectController.php:449 #, php-format msgid "Add %s: %s" msgstr "%s hinzufügen: %s" -#: application/controllers/HostsController.php:40 -#: application/controllers/HostsController.php:79 +#: ../../../../application/controllers/HostsController.php:40 +#: ../../../../application/controllers/HostsController.php:79 msgid "Add Service" msgstr "Service hinzufügen" -#: application/controllers/HostsController.php:45 -#: application/controllers/HostsController.php:110 +#: ../../../../application/controllers/HostsController.php:45 +#: ../../../../application/controllers/HostsController.php:110 msgid "Add Service Set" msgstr "Service-Set hinzufügen" -#: application/controllers/HostsController.php:127 +#: ../../../../application/controllers/HostsController.php:127 #, php-format msgid "Add Service Set to %d hosts" msgstr "Füge Service-Set zu %d Hosts hinzu" -#: application/controllers/HostController.php:121 +#: ../../../../application/controllers/HostController.php:105 #, php-format msgid "Add Service Set to %s" msgstr "Service-Set zu %s hinzufügen" -#: application/controllers/HostController.php:107 +#: ../../../../application/controllers/HostController.php:91 #, php-format msgid "Add Service to %s" msgstr "Service zu %s hinzufügen" -#: application/controllers/DatafieldController.php:33 +#: ../../../../application/controllers/DatafieldController.php:33 msgid "Add a new Data Field" msgstr "Einen neues Datenfeld hinzufügen" -#: application/controllers/DatafieldcategoryController.php:39 +#: ../../../../application/controllers/DatafieldcategoryController.php:39 msgid "Add a new Data Field Category" msgstr "Eine neue Datenfeldkategorie hinzufügen" -#: application/controllers/DataController.php:64 +#: ../../../../application/controllers/DataController.php:64 msgid "Add a new Data List" msgstr "Datenliste hinzufügen" -#: application/controllers/ImportsourcesController.php:35 +#: ../../../../application/controllers/ImportsourcesController.php:35 msgid "Add a new Import Source" msgstr "Importquelle hinzufügen" -#: application/controllers/JobsController.php:15 -#: application/controllers/JobController.php:35 +#: ../../../../application/controllers/JobsController.php:15 +#: ../../../../application/controllers/JobController.php:35 msgid "Add a new Job" msgstr "Job hinzufügen" -#: application/controllers/SyncrulesController.php:28 +#: ../../../../application/controllers/SyncrulesController.php:28 msgid "Add a new Sync Rule" msgstr "Synchronisationsregel hinzufügen" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:514 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:514 msgid "Add a new entry" msgstr "Einen neuen Eintrag hinzufügen" -#: application/controllers/DataController.php:216 +#: ../../../../application/controllers/DataController.php:216 msgid "Add a new instance" msgstr "Neue Instanz hinzufügen" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:271 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:271 msgid "Add a new one..." msgstr "Einen Neuen hinzufügen..." -#: application/controllers/ServicesetController.php:51 +#: ../../../../application/controllers/ServicesetController.php:51 #, php-format msgid "Add a service set to \"%s\"" msgstr "Füge ein Service-Set zu \"%s\" hinzu" -#: application/controllers/ServiceController.php:118 +#: ../../../../application/controllers/ServiceController.php:118 #, php-format msgid "Add a service to \"%s\"" msgstr "Füge einen Service zu \"%s\" hinzu" -#: application/views/helpers/FormDataFilter.php:516 +#: ../../../../application/views/helpers/FormDataFilter.php:516 msgid "Add another filter" msgstr "Weiteren Filter hinzufügen" -#: application/controllers/BasketController.php:85 +#: ../../../../application/controllers/BasketController.php:83 msgid "Add chosen objects to a Configuration Basket" msgstr "Gewählte Objekte zu einem Konfigurationsbasket hinzufügen" -#: application/forms/DirectorDatalistEntryForm.php:60 +#: ../../../../application/forms/DirectorDatalistEntryForm.php:60 msgid "Add data list entry" msgstr "Datenlisteneintrag hinzufügen" -#: application/controllers/ImportsourceController.php:108 +#: ../../../../application/controllers/ImportsourceController.php:108 msgid "Add import source" msgstr "Importquelle hinzufügen" -#: library/Director/Web/Controller/ObjectController.php:452 +#: ../../../../library/Director/Web/Controller/ObjectController.php:455 #, php-format msgid "Add new Icinga %s" msgstr "Neuen Icinga %s hinzufügen" -#: library/Director/Web/Controller/ObjectController.php:435 +#: ../../../../library/Director/Web/Controller/ObjectController.php:438 #, php-format msgid "Add new Icinga %s template" msgstr "Neue Icinga %s Vorlage hinzufügen" -#: application/controllers/ImportsourceController.php:253 +#: ../../../../application/controllers/ImportsourceController.php:253 msgid "Add property modifier" msgstr "Eigenschaftsmodifikator hinzufügen" -#: application/controllers/HostController.php:139 -#: application/controllers/ServicesetController.php:68 +#: ../../../../application/controllers/HostController.php:123 +#: ../../../../application/controllers/ServicesetController.php:68 msgid "Add service" msgstr "Service hinzufügen" -#: application/controllers/HostController.php:144 +#: ../../../../application/controllers/HostController.php:128 msgid "Add service set" msgstr "Service-Set hinzufügen" -#: application/controllers/HostsController.php:96 +#: ../../../../application/controllers/HostsController.php:96 #, php-format msgid "Add service to %d hosts" msgstr "Füge einen Service zu %d Hosts hinzu" -#: application/controllers/SyncruleController.php:580 +#: ../../../../application/controllers/SyncruleController.php:579 msgid "Add sync property rule" msgstr "Regel für Synchronisationseigenschaft hinzufügen" -#: application/controllers/SyncruleController.php:630 +#: ../../../../application/controllers/SyncruleController.php:628 #, php-format msgid "Add sync property: %s" msgstr "Synchronisationseigenschaft hinzufügen: %s" -#: application/controllers/SyncruleController.php:522 +#: ../../../../application/controllers/SyncruleController.php:521 msgid "Add sync rule" msgstr "Synchronisationsregel hinzufügen" -#: library/Director/Web/Controller/ObjectController.php:417 -#: library/Director/Web/Controller/TemplateController.php:129 -#: application/controllers/HostsController.php:70 -#: application/controllers/ServicesController.php:36 -#: application/controllers/BasketController.php:84 -#: application/controllers/ImportsourceController.php:67 -#: application/controllers/JobController.php:89 -#: application/controllers/SyncruleController.php:673 -#: application/controllers/DataController.php:370 +#: ../../../../library/Director/Web/Controller/TemplateController.php:130 +#: ../../../../library/Director/Web/Controller/ObjectController.php:420 +#: ../../../../application/controllers/HostsController.php:70 +#: ../../../../application/controllers/ServicesController.php:36 +#: ../../../../application/controllers/BasketController.php:82 +#: ../../../../application/controllers/ImportsourceController.php:67 +#: ../../../../application/controllers/JobController.php:89 +#: ../../../../application/controllers/SyncruleController.php:671 +#: ../../../../application/controllers/DataController.php:370 msgid "Add to Basket" msgstr "Zu Basket hinzufügen" -#: configuration.php:61 +#: ../../../../configuration.php:54 msgid "" "Additional (monitoring module) object filter to further restrict write access" msgstr "" "Zusätzliche (Monitoring-Modul-spezifische) Objekt-Filter, um den " "Schreibzugriff weiter einzuschränken" -#: library/Director/Import/ImportSourceRestApi.php:151 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:151 msgid "Additional headers for the HTTP request." msgstr "Zusätzliche HTTP-Header für diesen Request" -#: library/Director/Web/Form/DirectorObjectForm.php:1533 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1536 msgid "Additional notes for this object" msgstr "Weitere Notizen zu diesem Objekt" -#: library/Director/Web/Form/DirectorObjectForm.php:1586 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1589 msgid "Additional properties" msgstr "Weitere Eigenschaften" -#: library/Director/Web/Tabs/ObjectTabs.php:145 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:142 msgid "Agent" msgstr "Agent" -#: application/forms/SelfServiceSettingsForm.php:154 +#: ../../../../application/forms/SelfServiceSettingsForm.php:154 msgid "Agent Version" msgstr "Agenten-Version" -#: library/Director/PropertyModifier/PropertyModifierSimpleGroupBy.php:60 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSimpleGroupBy.php:60 msgid "Aggregation Columns" msgstr "Aggregationsspalten" -#: application/forms/IcingaHostSelfServiceForm.php:31 +#: ../../../../application/forms/IcingaHostSelfServiceForm.php:31 msgid "Alias" msgstr "Alias" -#: library/Director/Import/ImportSourceDirectorObject.php:80 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:80 msgid "All Object Types" msgstr "Alle Objekttypen" -#: application/controllers/ConfigController.php:173 +#: ../../../../application/controllers/ConfigController.php:174 msgid "All changes" msgstr "Alle Änderungen" -#: application/forms/SettingsForm.php:78 +#: ../../../../application/forms/SettingsForm.php:78 msgid "" "All changes are tracked in the Director database. In addition you might also " "want to send an audit log through the Icinga Web 2 logging mechanism. That " @@ -780,78 +777,79 @@ msgstr "" "entweder an Syslog oder die konfigurierte Logdatei geschickt. Dafür muss " "Icinga Web 2 mindestens mit dem \"Info\" Level loggen." -#: application/forms/SyncPropertyForm.php:309 +#: ../../../../application/forms/SyncPropertyForm.php:309 msgid "All custom variables (vars)" msgstr "Alle benutzerdefinierten Variablen (vars)" -#: application/forms/BasketForm.php:56 +#: ../../../../application/forms/BasketForm.php:56 msgid "All of them" msgstr "All diese" -#: application/forms/IcingaServiceForm.php:766 +#: ../../../../application/forms/IcingaServiceForm.php:770 #, php-format msgid "All overrides have been removed from \"%s\"" msgstr "Alle überschriebenen Eigenschaften wurden von \"%s\" entfernt" -#: library/Director/Web/Controller/ObjectsController.php:307 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:307 #, php-format msgid "All your %s Apply Rules" msgstr "Alle %s Apply Regeln" -#: library/Director/Web/Controller/ObjectsController.php:252 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:252 #, php-format msgid "All your %s Templates" msgstr "Alle %s Templates" -#: application/forms/SelfServiceSettingsForm.php:187 +#: ../../../../application/forms/SelfServiceSettingsForm.php:187 msgid "Allow Updates" msgstr "Updates erlauben" -#: library/Director/DataType/DataTypeDatalist.php:153 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:153 msgid "Allow for values not on the list" msgstr "Erlaube Werte die nicht au f der Liste stehen" -#: configuration.php:39 +#: ../../../../configuration.php:47 msgid "Allow readonly users to see where a Service came from" msgstr "Erlaube Nur-Lesen-Benutzern zu sehen woher ein Service kommt" -#: configuration.php:10 +#: ../../../../configuration.php:14 msgid "Allow to access the director API" msgstr "Zugriff auf die Director API erlauben" -#: configuration.php:11 +#: ../../../../configuration.php:15 msgid "Allow to access the full audit log" msgstr "Zugriff auf das volle Audit-Log erlauben" -#: configuration.php:21 +#: ../../../../configuration.php:29 msgid "Allow to configure hosts" msgstr "Erlauben, Hosts zu konfigurieren" -#: configuration.php:26 configuration.php:29 +#: ../../../../configuration.php:31 +#: ../../../../configuration.php:38 msgid "Allow to configure notifications (unrestricted)" msgstr "Erlaube (unbeschränkt) Benachrichtigungen zu konfigurieren" -#: configuration.php:23 +#: ../../../../configuration.php:34 msgid "Allow to configure service sets" msgstr "Erlauben, Service-Sets zu konfigurieren" -#: configuration.php:22 +#: ../../../../configuration.php:33 msgid "Allow to configure services" msgstr "Erlauben, Services zu konfigurieren" -#: configuration.php:25 +#: ../../../../configuration.php:36 msgid "Allow to configure users" msgstr "Erlauben, Benutzer zu konfigurieren" -#: configuration.php:24 +#: ../../../../configuration.php:35 msgid "Allow to define Service Set Apply Rules" msgstr "Erlaube Definieren von Service-Set Apply-Regeln" -#: configuration.php:20 +#: ../../../../configuration.php:16 msgid "Allow to deploy configuration" msgstr "Das Ausrollen von Konfigurationen erlauben" -#: configuration.php:34 +#: ../../../../configuration.php:18 msgid "" "Allow to inspect objects through the Icinga 2 API (could contain sensitive " "information)" @@ -859,35 +857,35 @@ msgstr "" "Untersuchen von Objekten über die API von Icinga 2 erlauben (könnte sensible " "Daten enthalten)" -#: configuration.php:14 +#: ../../../../configuration.php:21 msgid "Allow to show configuration (could contain sensitive information)" msgstr "Anzeigen der Konfiguration erlauben (könnte sensible Daten enthalten)" -#: configuration.php:18 +#: ../../../../configuration.php:24 msgid "Allow to show the full executed SQL queries in some places" msgstr "" "Erlaube das Anzeigen der vollständigen ausgeführten SQL-Statements an " "einigen Stellen" -#: application/forms/DirectorDatalistEntryForm.php:48 +#: ../../../../application/forms/DirectorDatalistEntryForm.php:48 msgid "" "Allow to use this entry only to users with one of these Icinga Web 2 roles" msgstr "" "Erlaube es ausschließlich Benutzern mit einer dieser Icinga Web 2 Rollen, " "diesen Eintrag zu nutzen" -#: configuration.php:49 +#: ../../../../configuration.php:13 msgid "Allow unrestricted access to Icinga Director" msgstr "Unbeschränkten Zugriff auf die Director API erlauben" -#: configuration.php:43 +#: ../../../../configuration.php:41 msgid "" "Allow users to modify Hosts they are allowed to see in the monitoring module" msgstr "" "Erlaube Benutzern, Hosts zu bearbeiten, welche sie im Monitoring-Modul sehen " "dürfen" -#: configuration.php:47 +#: ../../../../configuration.php:44 msgid "" "Allow users to modify Service they are allowed to see in the monitoring " "module" @@ -895,37 +893,37 @@ msgstr "" "Erlaube Benutzern, Services zu bearbeiten, welche sie im Monitoring-Modul " "sehen dürfen" -#: configuration.php:67 +#: ../../../../configuration.php:27 msgid "Allow users with Hostgroup restrictions to access the Groups field" msgstr "" "Mache Benutzern mit Hostgruppenbeschränkung das Feld \"Gruppen\" zugänglich" -#: application/forms/IcingaTemplateChoiceForm.php:85 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:85 msgid "Allowed maximum" msgstr "Erlaubtes Maximum" -#: application/forms/DirectorDatalistEntryForm.php:44 +#: ../../../../application/forms/DirectorDatalistEntryForm.php:44 msgid "Allowed roles" msgstr "Erlaubte Rollen" -#: application/forms/IcingaCloneObjectForm.php:102 +#: ../../../../application/forms/IcingaCloneObjectForm.php:106 msgid "Also clone fields provided by this Template" msgstr "Klone auch Felder welche durch diese Vorlage bereitgestellt werden" -#: application/forms/IcingaCloneObjectForm.php:70 +#: ../../../../application/forms/IcingaCloneObjectForm.php:72 msgid "Also clone single Service Sets defined for this Host" msgstr "Klone auch Service-Sets welche für diesen Host definiert wurden" -#: application/forms/IcingaCloneObjectForm.php:61 +#: ../../../../application/forms/IcingaCloneObjectForm.php:63 msgid "Also clone single Services defined for this Host" msgstr "Klone auch Einzelservices welche für diesen Host definiert wurden" -#: library/Director/Import/ImportSourceRestApi.php:211 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:211 msgid "Also deeper keys can be specific by a dot-notation:" msgstr "" "Auch tieferliegende Schlüssel können via Punkt-Notation erreicht werden:" -#: application/forms/SelfServiceSettingsForm.php:204 +#: ../../../../application/forms/SelfServiceSettingsForm.php:204 msgid "" "Also install NSClient++. It can be used through the Icinga Agent and comes " "with a bunch of additional Check Plugins" @@ -933,20 +931,20 @@ msgstr "" "Installiere auch NSClient++. Dieser kann über den installierten Icinga Agent " "genutzt werden und bringt eine Reihe zusätzlicher Check-Plugins" -#: application/forms/DirectorDatafieldForm.php:109 +#: ../../../../application/forms/DirectorDatafieldForm.php:109 #, php-format msgid "Also rename all \"%s\" custom variables to \"%s\" on %d objects?" msgstr "" "Auch alle benutzerdefinierten \"%s\" Variablen nach \"%s\" auf %d Objekten " "umbenennen?" -#: application/forms/DirectorDatafieldForm.php:66 +#: ../../../../application/forms/DirectorDatafieldForm.php:66 #, php-format msgid "Also wipe all \"%s\" custom variables from %d objects?" msgstr "" "Außerdem alle \"%s\" benutzerdefinierten Variablen von %d Objekten entfernen?" -#: application/forms/IcingaHostForm.php:355 +#: ../../../../application/forms/IcingaHostForm.php:357 msgid "" "Alternative name for this host. Might be a host alias or and kind of string " "helping your users to identify this host" @@ -954,7 +952,7 @@ msgstr "" "Alternativer Name für diesen Host. Kann ein Alias oder jede Zeichenkette " "sein, die Benutzern hilft, diesen Host zu identifizieren" -#: application/forms/IcingaUserForm.php:135 +#: ../../../../application/forms/IcingaUserForm.php:135 msgid "" "Alternative name for this user. In case your object name is a username, this " "could be the full name of the corresponding person" @@ -963,11 +961,11 @@ msgstr "" "Benutzername ist, könnte hier der vollständige Name der betreffenden Person " "hinterlegt werden" -#: library/Director/Web/Form/DirectorObjectForm.php:1567 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1570 msgid "Alternative text to be shown in case above icon is missing" msgstr "Alternativer Text der angezeigt werden soll, falls obiges Icon fehlt" -#: application/forms/IcingaCommandArgumentForm.php:91 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:91 msgid "" "An Icinga DSL expression that returns a boolean value, e.g.: var cmd = " "bool(macro(\"$cmd$\")); return cmd ..." @@ -975,7 +973,7 @@ msgstr "" "Ein Icinga DSL Ausdruck welcher einen booleschen Wert liefert, z.B.: var cmd " "= bool(macro(\"$cmd$\")); return cmd ..." -#: application/forms/IcingaCommandArgumentForm.php:52 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:52 msgid "" "An Icinga DSL expression, e.g.: var cmd = macro(\"$cmd$\"); return " "typeof(command) == String ..." @@ -983,7 +981,7 @@ msgstr "" "Ein Icinga DSL Ausdruck, z.B.: var cmd = macro(\"$cmd$\"); return " "typeof(command) == String ..." -#: library/Director/Web/Form/DirectorObjectForm.php:1549 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1552 msgid "" "An URL leading to additional actions for this object. Often used with Icinga " "Classic, rarely with Icinga Web 2 as it provides far better possibilities to " @@ -993,11 +991,11 @@ msgstr "" "Classic, jedoch selten mit Icinga Web 2 genutzt, da dieses viel bessere " "Möglichkeiten zur Integration von Addons bietet" -#: library/Director/Web/Form/DirectorObjectForm.php:1542 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1545 msgid "An URL pointing to additional notes for this object" msgstr "Eine URL zu Notizen für dieses Objekt" -#: library/Director/Web/Form/DirectorObjectForm.php:1558 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1561 msgid "" "An URL pointing to an icon for this object. Try \"tux.png\" for icons " "relative to public/img/icons or \"cloud\" (no extension) for items from the " @@ -1007,14 +1005,14 @@ msgstr "" "public/img/icons oder \"cloud\" (ohne Erweiterung) für Objekte aus dem " "Icinga Icon-Fundus" -#: library/Director/Web/Form/DirectorObjectForm.php:1314 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1317 msgid "" "An alternative display name for this group. If you wonder how this could be " "helpful just leave it blank" msgstr "" "Ein alternativer Anzeigename für diese Gruppe. Kann leer gelassen werden" -#: application/forms/ImportRowModifierForm.php:54 +#: ../../../../application/forms/ImportRowModifierForm.php:54 msgid "" "An extended description for this Import Row Modifier. This should explain " "it's purpose and why it has been put in place at all." @@ -1022,7 +1020,7 @@ msgstr "" "Eine erweiterte Beschreibung für diesen Eigenschaftsmodifikator. Diese soll " "seine Aufgabe sowie seinen Sinn und Zweck beschreiben." -#: application/forms/ImportSourceForm.php:26 +#: ../../../../application/forms/ImportSourceForm.php:26 msgid "" "An extended description for this Import Source. This should explain what " "kind of data you're going to import from this source." @@ -1030,7 +1028,7 @@ msgstr "" "Eine erweiterte Beschreibung für diese Import-Quelle. Diese sollte " "erläutern, welche Art von Daten von dieser Quelle bereitgestellt werden." -#: application/forms/SyncRuleForm.php:38 +#: ../../../../application/forms/SyncRuleForm.php:38 msgid "" "An extended description for this Sync Rule. This should explain what this " "Rule is going to accomplish." @@ -1038,7 +1036,8 @@ msgstr "" "Eine erweiterte Beschreibung für diese Synchronisationsregel. Sollte " "erläutern was diese Regel bezwecken will." -#: application/forms/DirectorDatafieldForm.php:161 +#: ../../../../application/forms/DirectorDatafieldForm.php:160 +#: ../../../../application/forms/IcingaObjectFieldForm.php:96 msgid "" "An extended description for this field. Will be shown as soon as a user puts " "the focus on this field" @@ -1046,7 +1045,7 @@ msgstr "" "Eine ausführliche Beschreibung dieses Felds. Wird angezeigt, sobald ein " "Benutzer den Fokus auf dieses Feld legt" -#: library/Director/Import/ImportSourceLdap.php:58 +#: ../../../../library/Director/Import/ImportSourceLdap.php:58 msgid "" "An object class to search for. Might be \"user\", \"group\", \"computer\" or " "similar" @@ -1054,7 +1053,7 @@ msgstr "" "Die Objektklasse, nach der gesucht werden soll. z.B. \"user\", \"group\", " "\"computer\" oder Ähnliches" -#: library/Director/PropertyModifier/PropertyModifierGetPropertyFromOtherImportSource.php:35 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetPropertyFromOtherImportSource.php:35 msgid "" "Another Import Source. We're going to look up the row with the key matching " "the value in the chosen column" @@ -1062,192 +1061,192 @@ msgstr "" "Eine andere Import-Quelle. Wir suchen dort eine Zeile mit einem Schlüssel, " "der dem Wert in der gewählten Spalte entspricht" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:20 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:20 msgid "Any first (leftmost) component" msgstr "Beliebige erste (linkeste) Komponente" -#: library/Director/Web/SelfService.php:70 -#: library/Director/Web/SelfService.php:111 +#: ../../../../library/Director/Web/SelfService.php:70 +#: ../../../../library/Director/Web/SelfService.php:111 msgid "Api Key:" msgstr "API-Schlüssel:" -#: library/Director/Web/Controller/TemplateController.php:54 +#: ../../../../library/Director/Web/Controller/TemplateController.php:55 #, php-format msgid "Applied %s" msgstr "Angewendete(r) %s" -#: application/forms/IcingaHostForm.php:231 +#: ../../../../application/forms/IcingaHostForm.php:233 msgid "Applied groups" msgstr "Angewendete Gruppen" -#: application/controllers/HostController.php:417 +#: ../../../../application/controllers/HostController.php:402 #, php-format msgid "Applied service: %s" msgstr "Zugewiesener Service: %s" -#: application/controllers/HostController.php:261 -#: application/controllers/HostController.php:345 +#: ../../../../application/controllers/HostController.php:248 +#: ../../../../application/controllers/HostController.php:331 msgid "Applied services" msgstr "Zugewiesene Services" -#: library/Director/Web/Tabs/ObjectsTabs.php:49 +#: ../../../../library/Director/Web/Tabs/ObjectsTabs.php:51 msgid "Apply" msgstr "Anwenden" -#: application/controllers/ServiceController.php:123 +#: ../../../../application/controllers/ServiceController.php:123 #, php-format msgid "Apply \"%s\"" msgstr "Apply \"%s\"" -#: application/forms/ApplyMigrationsForm.php:25 +#: ../../../../application/forms/ApplyMigrationsForm.php:25 #, php-format msgid "Apply %d pending schema migrations" msgstr "%d Schema-Migrations-Scripte anwenden" -#: application/forms/IcingaServiceForm.php:623 +#: ../../../../application/forms/IcingaServiceForm.php:627 msgid "Apply For" msgstr "Anwenden auf" -#: library/Director/Web/Controller/TemplateController.php:169 +#: ../../../../library/Director/Web/Controller/TemplateController.php:170 msgid "Apply Rule" msgstr "Apply-Regel" -#: library/Director/Web/Table/ApplyRulesTable.php:165 +#: ../../../../library/Director/Web/Table/ApplyRulesTable.php:165 msgid "Apply Rule rendering preview" msgstr "Rendering-Vorschau für diese Apply-Regel" -#: library/Director/Import/ImportSourceDirectorObject.php:84 -#: library/Director/Web/Table/DependencyTemplateUsageTable.php:11 -#: library/Director/Web/Table/NotificationTemplateUsageTable.php:11 -#: library/Director/Web/Table/ServiceTemplateUsageTable.php:12 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:84 +#: ../../../../library/Director/Web/Table/DependencyTemplateUsageTable.php:11 +#: ../../../../library/Director/Web/Table/NotificationTemplateUsageTable.php:11 +#: ../../../../library/Director/Web/Table/ServiceTemplateUsageTable.php:12 msgid "Apply Rules" msgstr "Apply-Regeln" -#: application/forms/ApplyMigrationsForm.php:20 +#: ../../../../application/forms/ApplyMigrationsForm.php:20 msgid "Apply a pending schema migration" msgstr "Ein ausstehende Schema-Migration durchführen" -#: library/Director/Job/SyncJob.php:92 +#: ../../../../library/Director/Job/SyncJob.php:92 msgid "Apply changes" msgstr "Änderungen anwenden" -#: library/Director/Dashboard/Dashlet/NotificationApplyDashlet.php:19 +#: ../../../../library/Director/Dashboard/Dashlet/NotificationApplyDashlet.php:21 msgid "Apply notifications with specific properties according to given rules." msgstr "" "Benachrichtigungen mit bestimmten Eigenschaften anhand von gegebenen Regeln " "anwenden" -#: library/Director/Web/Form/DirectorObjectForm.php:1123 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1126 msgid "Apply rule" msgstr "Apply Regel" -#: library/Director/Web/Table/ApplyRulesTable.php:172 +#: ../../../../library/Director/Web/Table/ApplyRulesTable.php:172 msgid "Apply rule history" msgstr "Apply-Regel Historie" -#: application/forms/KickstartForm.php:38 +#: ../../../../application/forms/KickstartForm.php:38 msgid "Apply schema migrations" msgstr "Schema-Migrations-Scripte anwenden" -#: application/forms/IcingaNotificationForm.php:81 -#: application/forms/IcingaDependencyForm.php:93 -#: application/forms/IcingaScheduledDowntimeForm.php:82 +#: ../../../../application/forms/IcingaNotificationForm.php:82 +#: ../../../../application/forms/IcingaDependencyForm.php:93 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:82 msgid "Apply to" msgstr "Anwenden auf" -#: application/controllers/ServiceController.php:224 +#: ../../../../application/controllers/ServiceController.php:224 #, php-format msgid "Apply: %s" msgstr "Apply: %s" -#: library/Director/Web/Table/BranchedIcingaCommandArgumentTable.php:46 -#: library/Director/Web/Table/IcingaCommandArgumentTable.php:49 +#: ../../../../library/Director/Web/Table/BranchedIcingaCommandArgumentTable.php:46 +#: ../../../../library/Director/Web/Table/IcingaCommandArgumentTable.php:49 msgid "Argument" msgstr "Argument" -#: application/forms/IcingaObjectFieldForm.php:99 +#: ../../../../library/Director/Field/FormFieldSuggestion.php:82 msgid "Argument macros" msgstr "Argument Makros" -#: application/forms/IcingaCommandArgumentForm.php:25 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:25 msgid "Argument name" msgstr "Argumentname" -#: application/forms/SyncPropertyForm.php:315 +#: ../../../../application/forms/SyncPropertyForm.php:315 msgid "Arguments" msgstr "Argumente" -#: library/Director/DataType/DataTypeDirectorObject.php:80 -#: library/Director/DataType/DataTypeSqlQuery.php:77 -#: library/Director/DataType/DataTypeDatalist.php:133 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:80 +#: ../../../../library/Director/DataType/DataTypeSqlQuery.php:77 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:133 msgid "Array" msgstr "Array" -#: library/Director/Web/Form/DirectorObjectForm.php:1619 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1622 msgid "Assign where" msgstr "Zuweisen wo" -#: application/forms/IcingaTemplateChoiceForm.php:95 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:95 msgid "Associated Template" msgstr "Zugehörige Vorlage" -#: library/Director/Web/Widget/ActivityLogInfo.php:506 -#: application/forms/IcingaScheduledDowntimeForm.php:31 -#: application/controllers/BranchController.php:60 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:506 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:31 +#: ../../../../application/controllers/BranchController.php:59 msgid "Author" msgstr "Autor" -#: library/Director/DataType/DataTypeDatalist.php:151 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:151 msgid "Autocomplete" msgstr "Automatische Vervollständigung" -#: library/Director/Dashboard/AutomationDashboard.php:15 +#: ../../../../library/Director/Dashboard/AutomationDashboard.php:15 msgid "Automate all tasks" msgstr "Automatisiere alle Aufgaben" -#: configuration.php:169 +#: ../../../../configuration.php:137 msgid "Automation" msgstr "Automatisierung" -#: application/forms/IcingaTemplateChoiceForm.php:64 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:64 msgid "Available choices" msgstr "Verfügbare Auswahlmöglichkeiten" -#: library/Director/Web/Controller/TemplateController.php:95 -#: application/controllers/BasketController.php:54 -#: application/controllers/DataController.php:165 +#: ../../../../library/Director/Web/Controller/TemplateController.php:96 +#: ../../../../application/controllers/BasketController.php:52 +#: ../../../../application/controllers/DataController.php:165 msgid "Back" msgstr "Zurück" -#: library/Director/Web/Table/BasketTable.php:31 -#: application/forms/AddToBasketForm.php:61 -#: application/controllers/BasketController.php:36 +#: ../../../../library/Director/Web/Table/BasketTable.php:31 +#: ../../../../application/forms/AddToBasketForm.php:61 +#: ../../../../application/controllers/BasketController.php:34 msgid "Basket" msgstr "Basket" -#: application/forms/BasketForm.php:38 +#: ../../../../application/forms/BasketForm.php:38 msgid "Basket Definitions" msgstr "Basket-Definitionen" -#: application/forms/BasketUploadForm.php:29 -#: application/forms/BasketForm.php:48 +#: ../../../../application/forms/BasketForm.php:48 +#: ../../../../application/forms/BasketUploadForm.php:30 msgid "Basket Name" msgstr "Basket-Name" -#: application/controllers/BasketController.php:142 +#: ../../../../application/controllers/BasketController.php:160 msgid "Basket Snapshots" msgstr "Basket-Snapshots" -#: application/forms/BasketUploadForm.php:145 +#: ../../../../application/forms/BasketUploadForm.php:141 msgid "Basket has been uploaded" msgstr "Basket wurde hochgeladen" -#: application/controllers/BasketsController.php:17 -#: application/controllers/BasketController.php:78 +#: ../../../../application/controllers/BasketsController.php:17 +#: ../../../../application/controllers/BasketController.php:76 msgid "Baskets" msgstr "Baskets" -#: application/forms/SyncRuleForm.php:103 +#: ../../../../application/forms/SyncRuleForm.php:103 msgid "" "Be careful: this is usually NOT what you want, as it makes Sync \"blind\" " "for objects matching this filter. This means that \"Purge\" will not work as " @@ -1260,86 +1259,86 @@ msgstr "" "Whitelist\"-Eigenschaftsmodifikator ist für gewöhnlich was man stattdessen " "nutzen möchte." -#: library/Director/PropertyModifier/PropertyModifierTrim.php:20 +#: ../../../../library/Director/PropertyModifier/PropertyModifierTrim.php:20 msgid "Beginning and Ending" msgstr "Anfang und Ende" -#: library/Director/PropertyModifier/PropertyModifierTrim.php:21 +#: ../../../../library/Director/PropertyModifier/PropertyModifierTrim.php:21 msgid "Beginning only" msgstr "Nur den Anfang" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:79 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:79 msgid "Binary" msgstr "Binary" -#: application/controllers/BranchController.php:49 +#: ../../../../application/controllers/BranchController.php:48 msgid "Branch Activity" msgstr "Aktivität in diesem Zweig" -#: library/Director/DataType/DataTypeDictionary.php:36 +#: ../../../../library/Director/DataType/DataTypeDictionary.php:36 msgid "Can be managed once this object has been created" msgstr "Kann verwaltet werden, sobald dieses Objekt erstellt wurde" -#: library/Director/Db/Branch/MergeErrorModificationForMissingObject.php:10 +#: ../../../../library/Director/Db/Branch/MergeErrorModificationForMissingObject.php:10 #, php-format msgid "Cannot apply modification for %s %s, object does not exist" msgstr "" "Änderung für %s %s kann nicht angewandt werden, das Objekt existiert nicht" -#: library/Director/Db/Branch/MergeErrorDeleteMissingObject.php:10 +#: ../../../../library/Director/Db/Branch/MergeErrorDeleteMissingObject.php:10 #, php-format msgid "Cannot delete %s %s, it does not exist" msgstr "%s %s kann nicht gelöscht werden, es existiert nicht" -#: library/Director/Db/Branch/MergeErrorRecreateOnMerge.php:10 +#: ../../../../library/Director/Db/Branch/MergeErrorRecreateOnMerge.php:10 #, php-format msgid "Cannot recreate %s %s" msgstr "%s %s kann nicht erneut erstellt werden" -#: application/forms/DirectorDatafieldForm.php:150 -#: application/forms/IcingaObjectFieldForm.php:125 +#: ../../../../application/forms/DirectorDatafieldForm.php:149 +#: ../../../../application/forms/IcingaObjectFieldForm.php:83 msgid "Caption" msgstr "Beschriftung" -#: library/Director/Dashboard/Dashlet/DatafieldCategoryDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/DatafieldCategoryDashlet.php:19 msgid "Categories bring structure to your Data Fields" msgstr "Kategorien bringen Struktur in konfigurierte Datenfelder" -#: library/Director/Web/Table/DatafieldTable.php:51 +#: ../../../../library/Director/Web/Table/DatafieldTable.php:53 msgid "Category" msgstr "Kategorie" -#: library/Director/Web/Table/DatafieldCategoryTable.php:47 +#: ../../../../library/Director/Web/Table/DatafieldCategoryTable.php:47 msgid "Category Name" msgstr "Kategoriename" -#: application/forms/DirectorDatafieldCategoryForm.php:23 +#: ../../../../application/forms/DirectorDatafieldCategoryForm.php:23 msgid "Category name" msgstr "Kategoriename" -#: application/forms/IcingaMultiEditForm.php:270 +#: ../../../../application/forms/IcingaMultiEditForm.php:270 #, php-format msgid "Changing this value affects %d object(s): %s" msgstr "Diesen Wert zu ändern beeinflusst %d Objekt(e): %s" -#: library/Director/PropertyModifier/PropertyModifierTrim.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierTrim.php:28 msgid "Character Mask" msgstr "Zeichenmaske" -#: library/Director/Import/ImportSourceCoreApi.php:57 +#: ../../../../library/Director/Import/ImportSourceCoreApi.php:57 msgid "Check Commands" msgstr "Check-Kommando" -#: library/Director/Web/Form/DirectorObjectForm.php:1335 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1338 msgid "Check command" msgstr "Check-Kommando" -#: library/Director/Web/Form/DirectorObjectForm.php:1336 -#: application/forms/IcingaNotificationForm.php:263 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1339 +#: ../../../../application/forms/IcingaNotificationForm.php:311 msgid "Check command definition" msgstr "Check-Kommandodefinition" -#: library/Director/Web/Form/DirectorObjectForm.php:1404 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1407 msgid "" "Check command timeout in seconds. Overrides the CheckCommand's timeout " "attribute" @@ -1347,57 +1346,57 @@ msgstr "" "Timeout für das Check-Kommando in Sekunden. Überschreibt die Timeout-" "Konfiguration des Kommandos" -#: library/Director/Web/Form/DirectorObjectForm.php:336 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:337 msgid "Check execution" msgstr "Check-Ausführung" -#: application/forms/ImportCheckForm.php:23 -#: application/forms/SyncCheckForm.php:24 +#: ../../../../application/forms/ImportCheckForm.php:23 +#: ../../../../application/forms/SyncCheckForm.php:24 msgid "Check for changes" msgstr "Auf Änderungen prüfen" -#: library/Director/Web/Form/DirectorObjectForm.php:1371 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1374 msgid "Check interval" msgstr "Check-Intervall" -#: library/Director/Web/Form/DirectorObjectForm.php:1416 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1419 msgid "Check period" msgstr "Checkzeitraum" -#: library/Director/Web/Form/DirectorObjectForm.php:1402 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1405 msgid "Check timeout" msgstr "Check-Timeout" -#: application/forms/ImportCheckForm.php:45 +#: ../../../../application/forms/ImportCheckForm.php:45 msgid "Checking this Import Source failed" msgstr "Überprüfen dieser Importquelle fehlgeschlagen" -#: application/forms/SyncCheckForm.php:66 +#: ../../../../application/forms/SyncCheckForm.php:66 msgid "Checking this sync rule failed" msgstr "Überprüfen dieser Synchronisationsregel fehlgeschlagen" -#: library/Director/Web/Widget/ActivityLogInfo.php:550 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:550 msgid "Checksum" msgstr "Prüfsumme" -#: application/forms/IcingaDependencyForm.php:233 +#: ../../../../application/forms/IcingaDependencyForm.php:233 msgid "Child Host" msgstr "Kind-Host" -#: application/forms/IcingaDependencyForm.php:246 +#: ../../../../application/forms/IcingaDependencyForm.php:246 msgid "Child Service" msgstr "Kind-Service" -#: application/forms/IcingaTemplateChoiceForm.php:48 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:48 msgid "Choice name" msgstr "Auswahlname" -#: library/Director/Dashboard/Dashlet/ChoicesDashlet.php:11 -#: library/Director/Web/Tabs/ObjectsTabs.php:74 +#: ../../../../library/Director/Dashboard/Dashlet/ChoicesDashlet.php:13 +#: ../../../../library/Director/Web/Tabs/ObjectsTabs.php:76 msgid "Choices" msgstr "Auswahl" -#: application/forms/BasketForm.php:82 +#: ../../../../application/forms/BasketForm.php:82 msgid "" "Choose \"All\" to always add all of them, \"Ignore\" to not care about a " "specific Type at all and opt for \"Custom Selection\" in case you want to " @@ -1408,35 +1407,35 @@ msgstr "" "\"Benutzerdefinierte Auswahl\" wenn nur bestimmte Objekte manuell gewählt " "werden sollen." -#: application/forms/IcingaTemplateChoiceForm.php:97 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:97 msgid "Choose Choice Associated Template" msgstr "Wähle eine der Auswahl zugehörige Vorlage" -#: application/controllers/IndexController.php:53 +#: ../../../../application/controllers/IndexController.php:53 msgid "Choose DB Resource" msgstr "Datenbankressource wählen" -#: application/forms/IcingaHostForm.php:188 +#: ../../../../application/forms/IcingaHostForm.php:190 msgid "Choose a Host Template" msgstr "Wähle eine Service-Vorlage" -#: application/forms/IcingaAddServiceForm.php:105 +#: ../../../../application/forms/IcingaAddServiceForm.php:106 msgid "Choose a service template" msgstr "Wähle eine Service-Vorlage" -#: application/forms/SyncRuleForm.php:46 +#: ../../../../application/forms/SyncRuleForm.php:46 msgid "Choose an object type" msgstr "Einen Objekttyp auswählen" -#: application/forms/BasketUploadForm.php:35 +#: ../../../../application/forms/BasketUploadForm.php:37 msgid "Choose file" msgstr "Datei wählen" -#: application/forms/IcingaServiceForm.php:601 +#: ../../../../application/forms/IcingaServiceForm.php:605 msgid "Choose the host this single service should be assigned to" msgstr "Host wählen, dem dieser einzelne Service zugewiesen werden soll" -#: application/forms/IcingaTemplateChoiceForm.php:75 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:75 msgid "" "Choosing this many options will be mandatory for this Choice. Setting this " "to zero will leave this Choice optional, setting it to one results in a " @@ -1449,79 +1448,79 @@ msgstr "" "man mehrere Optionen erzwingen, die Auswahl wandelt sich dann in ein " "Mehrfach-Auswahlfeld." -#: application/forms/IcingaZoneForm.php:37 +#: ../../../../application/forms/IcingaZoneForm.php:37 msgid "Chose an (optional) parent zone" msgstr "Eine (optionale) Elternzone auswählen" -#: library/Director/Web/Widget/Documentation.php:38 +#: ../../../../library/Director/Web/Widget/Documentation.php:38 #, php-format msgid "Click to read our documentation: %s" msgstr "Anklicken um unsere Dokumentation zu lesen: %s" -#: library/Director/Web/ActionBar/AutomationObjectActionBar.php:44 -#: library/Director/Web/Form/CloneImportSourceForm.php:35 -#: library/Director/Web/Form/CloneSyncRuleForm.php:35 -#: library/Director/Web/Controller/ObjectController.php:381 -#: application/controllers/ImportsourceController.php:148 -#: application/controllers/SyncruleController.php:548 +#: ../../../../library/Director/Web/ActionBar/AutomationObjectActionBar.php:44 +#: ../../../../library/Director/Web/Form/CloneImportSourceForm.php:37 +#: ../../../../library/Director/Web/Form/CloneSyncRuleForm.php:37 +#: ../../../../library/Director/Web/Controller/ObjectController.php:384 +#: ../../../../application/controllers/ImportsourceController.php:148 +#: ../../../../application/controllers/SyncruleController.php:547 msgid "Clone" msgstr "Klonen" -#: application/forms/IcingaCloneObjectForm.php:108 +#: ../../../../application/forms/IcingaCloneObjectForm.php:112 #, php-format msgid "Clone \"%s\"" msgstr "Klone \"%s\"" -#: application/forms/IcingaCloneObjectForm.php:68 +#: ../../../../application/forms/IcingaCloneObjectForm.php:70 msgid "Clone Service Sets" msgstr "Klone Service-Set" -#: application/forms/IcingaCloneObjectForm.php:59 +#: ../../../../application/forms/IcingaCloneObjectForm.php:61 msgid "Clone Services" msgstr "Klone Services" -#: application/forms/IcingaCloneObjectForm.php:100 +#: ../../../../application/forms/IcingaCloneObjectForm.php:104 msgid "Clone Template Fields" msgstr "Vorlagen-Felder klonen" -#: application/forms/IcingaCloneObjectForm.php:49 +#: ../../../../application/forms/IcingaCloneObjectForm.php:51 msgid "Clone the object as is, preserving imports" msgstr "Objekt vollständig unter Erhalt der Vererbung klonen" -#: application/forms/IcingaCloneObjectForm.php:89 +#: ../../../../application/forms/IcingaCloneObjectForm.php:91 msgid "Clone this service to the very same or to another Host" msgstr "Klone diesen Service zum selben oder einem anderen Host" -#: application/forms/IcingaCloneObjectForm.php:80 +#: ../../../../application/forms/IcingaCloneObjectForm.php:82 msgid "Clone this service to the very same or to another Service Set" msgstr "Klone diesen Service" -#: library/Director/Web/Controller/ObjectController.php:214 +#: ../../../../library/Director/Web/Controller/ObjectController.php:217 #, php-format msgid "Clone: %s" msgstr "Klone %s" -#: library/Director/Web/Controller/ObjectController.php:221 +#: ../../../../library/Director/Web/Controller/ObjectController.php:224 msgid "Cloning Apply Rules" msgstr "Apply-Regeln klonen" -#: application/controllers/ImportsourceController.php:149 +#: ../../../../application/controllers/ImportsourceController.php:149 msgid "Cloning Import Sources" msgstr "Importquellen klonen" -#: application/controllers/SyncruleController.php:559 +#: ../../../../application/controllers/SyncruleController.php:558 msgid "Cloning Sync Rules" msgstr "Synchronisationsregeln klonen" -#: library/Director/Web/Controller/ObjectController.php:217 +#: ../../../../library/Director/Web/Controller/ObjectController.php:220 msgid "Cloning Templates" msgstr "Vorlagen Klonen" -#: library/Director/Web/Form/DirectorObjectForm.php:1162 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1165 msgid "Cluster Zone" msgstr "Cluster Zone" -#: library/Director/Dashboard/Dashlet/ChoicesDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/ChoicesDashlet.php:19 msgid "" "Combine multiple templates into meaningful Choices, making life easier for " "your users" @@ -1529,7 +1528,7 @@ msgstr "" "Kombiniere mehrere Vorlagen zu sprechenden Wahlmöglichkeiten, um die " "Benutzung zu vereinfachen" -#: library/Director/PropertyModifier/PropertyModifierSimpleGroupBy.php:62 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSimpleGroupBy.php:62 msgid "" "Comma-separated list of columns that should be aggregated (transformed into " "an Array). For all other columns only the first value will be kept." @@ -1538,373 +1537,373 @@ msgstr "" "verwandelt) werden sollen. Für alle anderen Spalten wird lediglich der erste " "Wert beibehalten." -#: library/Director/TranslationDummy.php:16 -#: application/forms/IcingaCommandForm.php:58 -#: application/forms/SyncRuleForm.php:20 +#: ../../../../library/Director/TranslationDummy.php:16 +#: ../../../../application/forms/IcingaCommandForm.php:58 +#: ../../../../application/forms/SyncRuleForm.php:20 msgid "Command" msgstr "Kommando" -#: application/forms/BasketForm.php:17 +#: ../../../../application/forms/BasketForm.php:17 msgid "Command Definitions" msgstr "Kommandodefinitionen" -#: application/forms/BasketForm.php:19 +#: ../../../../application/forms/BasketForm.php:19 msgid "Command Template" msgstr "Kommando-Vorlage" -#: library/Director/Dashboard/Dashlet/CommandTemplatesDashlet.php:19 +#: ../../../../library/Director/Dashboard/Dashlet/CommandTemplatesDashlet.php:19 msgid "Command Templates" msgstr "Kommando-Vorlagen" -#: application/controllers/CommandController.php:92 +#: ../../../../application/controllers/CommandController.php:92 #, php-format msgid "Command arguments: %s" msgstr "Kommandoargumente: %s" -#: application/forms/IcingaHostForm.php:114 +#: ../../../../application/forms/IcingaHostForm.php:116 msgid "Command endpoint" msgstr "Kommandoendpunkt" -#: application/forms/IcingaCommandForm.php:47 +#: ../../../../application/forms/IcingaCommandForm.php:47 msgid "Command name" msgstr "Kommandoname" -#: application/forms/IcingaCommandForm.php:17 +#: ../../../../application/forms/IcingaCommandForm.php:17 msgid "Command type" msgstr "Kommandotyp" -#: configuration.php:161 -#: library/Director/Dashboard/Dashlet/CommandObjectDashlet.php:13 -#: library/Director/Dashboard/Dashlet/CheckCommandsDashlet.php:19 -#: library/Director/Db/Branch/BranchModificationInspection.php:37 -#: library/Director/Web/Table/CustomvarVariantsTable.php:57 +#: ../../../../configuration.php:129 +#: ../../../../library/Director/Dashboard/Dashlet/CheckCommandsDashlet.php:21 +#: ../../../../library/Director/Dashboard/Dashlet/CommandObjectDashlet.php:15 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:37 +#: ../../../../library/Director/Web/Table/CustomvarVariantsTable.php:57 msgid "Commands" msgstr "Kommandos" -#: application/forms/IcingaScheduledDowntimeForm.php:39 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:39 msgid "Comment" msgstr "Kommentar" -#: application/controllers/BasketController.php:345 +#: ../../../../application/controllers/BasketController.php:356 #, php-format msgid "Comparing %s \"%s\" from Snapshot \"%s\" to current config" msgstr "" "Vergleiche %s \"%s\" aus dem Snapshot \"%s\" mit der aktuellen Konfiguration" -#: application/forms/IcingaCommandArgumentForm.php:89 -#: application/forms/IcingaCommandArgumentForm.php:98 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:89 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:98 msgid "Condition (set_if)" msgstr "Bedingung (set_if)" -#: application/forms/IcingaCommandArgumentForm.php:75 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:75 msgid "Condition format" msgstr "Bedingungsformat" -#: library/Director/Web/Table/CoreApiFieldsTable.php:85 -#: library/Director/Web/Widget/DeploymentInfo.php:60 -#: application/controllers/JobController.php:112 -#: application/controllers/ConfigController.php:277 -#: application/controllers/ConfigController.php:515 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:85 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:61 +#: ../../../../application/controllers/JobController.php:112 +#: ../../../../application/controllers/ConfigController.php:278 +#: ../../../../application/controllers/ConfigController.php:516 msgid "Config" msgstr "Konfiguration" -#: library/Director/Dashboard/Dashlet/DeploymentDashlet.php:18 +#: ../../../../library/Director/Dashboard/Dashlet/DeploymentDashlet.php:19 msgid "Config Deployment" msgstr "Ausrollen der Konfiguration" -#: application/forms/DeployConfigForm.php:100 -#: application/forms/DeploymentLinkForm.php:165 -#: application/controllers/ConfigController.php:490 +#: ../../../../application/forms/DeployConfigForm.php:100 +#: ../../../../application/forms/DeploymentLinkForm.php:166 +#: ../../../../application/controllers/ConfigController.php:491 msgid "Config deployment failed" msgstr "Ausrollen der Konfiguration fehlgeschlagen" -#: application/controllers/ConfigController.php:364 -#: application/controllers/ConfigController.php:365 +#: ../../../../application/controllers/ConfigController.php:365 +#: ../../../../application/controllers/ConfigController.php:366 msgid "Config diff" msgstr "Konfigurationsunterschied" -#: application/controllers/ConfigController.php:323 -#: application/controllers/ConfigController.php:425 +#: ../../../../application/controllers/ConfigController.php:324 +#: ../../../../application/controllers/ConfigController.php:426 #, php-format msgid "Config file \"%s\"" msgstr "Konfigurationsdatei \"%s\"" -#: application/forms/DeployConfigForm.php:76 -#: application/forms/DeployConfigForm.php:95 -#: application/forms/DeploymentLinkForm.php:152 -#: application/controllers/ConfigController.php:470 +#: ../../../../application/forms/DeployConfigForm.php:76 +#: ../../../../application/forms/DeployConfigForm.php:95 +#: ../../../../application/forms/DeploymentLinkForm.php:153 +#: ../../../../application/controllers/ConfigController.php:471 msgid "Config has been submitted, validation is going on" msgstr "Konfiguration wurde übergeben, Überprüfung ist im Gange" -#: application/forms/DeployFormsBug7530.php:87 +#: ../../../../application/forms/DeployFormsBug7530.php:87 msgid "Config has not been deployed" msgstr "Konfiguration wurde nicht ausgerollt" -#: library/Director/Web/ObjectPreview.php:41 +#: ../../../../library/Director/Web/ObjectPreview.php:41 #, php-format msgid "Config preview: %s" msgstr "Konfigurationsvorschau: %s" -#: library/Director/ProvidedHook/Monitoring/ServiceActions.php:65 -#: library/Director/Web/Widget/DeploymentInfo.php:82 +#: ../../../../library/Director/ProvidedHook/Monitoring/ServiceActions.php:63 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:83 msgid "Configuration" msgstr "Konfiguration" -#: application/controllers/HostController.php:285 +#: ../../../../application/controllers/HostController.php:272 msgid "Configuration (read-only)" msgstr "Konfiguration (nur lesen)" -#: library/Director/Dashboard/Dashlet/BasketDashlet.php:11 -#: application/controllers/BasketsController.php:32 +#: ../../../../library/Director/Dashboard/Dashlet/BasketDashlet.php:13 +#: ../../../../application/controllers/BasketsController.php:32 msgid "Configuration Baskets" msgstr "Konfigurationsbaskets" -#: application/forms/SettingsForm.php:121 +#: ../../../../application/forms/SettingsForm.php:121 msgid "Configuration format" msgstr "Konfigurationsformat" -#: application/forms/KickstartForm.php:309 +#: ../../../../application/forms/KickstartForm.php:309 msgid "Configuration has been stored" msgstr "Konfiguration wurde gespeichert" -#: application/forms/AddToBasketForm.php:112 +#: ../../../../application/forms/AddToBasketForm.php:112 #, php-format msgid "Configuration objects have been added to the chosen basket \"%s\"" msgstr "Konfigurationsobjekte wurden zum gewählten Basket \"%s\" hinzugefügt" -#: library/Director/Web/SelfService.php:192 +#: ../../../../library/Director/Web/SelfService.php:179 msgid "Configure this Agent via Self Service API" msgstr "Konfiguriere diesen Agent über die Selbstbedienungs-API" -#: application/controllers/BasketController.php:231 +#: ../../../../application/controllers/BasketController.php:255 msgid "Content Checksum" msgstr "Prüfsumme (Inhalt)" -#: application/controllers/BasketsController.php:20 +#: ../../../../application/controllers/BasketsController.php:20 msgid "Create" msgstr "Erstellen" -#: application/controllers/BasketController.php:104 +#: ../../../../application/controllers/BasketController.php:102 msgid "Create Basket" msgstr "Basket erstellen" -#: application/controllers/IndexController.php:46 +#: ../../../../application/controllers/IndexController.php:46 msgid "Create Schema" msgstr "Schema erstellen" -#: application/forms/BasketCreateSnapshotForm.php:23 +#: ../../../../application/forms/BasketCreateSnapshotForm.php:23 msgid "Create Snapshot" msgstr "Snapshot erstellen" -#: library/Director/Web/Controller/ObjectsController.php:320 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:320 #, php-format msgid "Create a new %s Apply Rule" msgstr "Erstelle eine neue %s Apply-Regel" -#: library/Director/Web/Controller/ObjectsController.php:361 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:361 #, php-format msgid "Create a new %s Set" msgstr "Erstelle ein neues %s-Set" -#: library/Director/Web/Controller/TemplateController.php:157 +#: ../../../../library/Director/Web/Controller/TemplateController.php:158 #, php-format msgid "Create a new %s inheriting from this one" msgstr "Neuen und von diesem erbenden %s erstellen" -#: library/Director/Web/Controller/TemplateController.php:147 -#: library/Director/Web/Controller/TemplateController.php:167 +#: ../../../../library/Director/Web/Controller/TemplateController.php:148 +#: ../../../../library/Director/Web/Controller/TemplateController.php:168 #, php-format msgid "Create a new %s inheriting from this template" msgstr "Einen neuen von dieser Vorlage erbenden %s erstellen" -#: application/controllers/BasketController.php:105 +#: ../../../../application/controllers/BasketController.php:103 msgid "Create a new Configuration Basket" msgstr "Erstelle einen neuen Konfigurationsbasket" -#: library/Director/Web/ActionBar/TemplateActionBar.php:23 -#: library/Director/Web/Controller/ObjectController.php:147 +#: ../../../../library/Director/Web/ActionBar/TemplateActionBar.php:23 +#: ../../../../library/Director/Web/Controller/ObjectController.php:148 msgid "Create a new Template" msgstr "Neue Vorlage erstellen" -#: library/Director/Web/ActionBar/ObjectsActionBar.php:20 +#: ../../../../library/Director/Web/ActionBar/ObjectsActionBar.php:20 msgid "Create a new object" msgstr "Neues Objekt erstellen" -#: library/Director/Web/ActionBar/ChoicesActionBar.php:20 +#: ../../../../library/Director/Web/ActionBar/ChoicesActionBar.php:20 msgid "Create a new template choice" msgstr "Neue Template-Auswahl erstellen" -#: application/forms/KickstartForm.php:37 +#: ../../../../application/forms/KickstartForm.php:37 msgid "Create database schema" msgstr "Datenbankschema erstellen" -#: application/forms/ApplyMigrationsForm.php:31 +#: ../../../../application/forms/ApplyMigrationsForm.php:31 msgid "Create schema" msgstr "Datenbankschema erstellen" -#: application/controllers/BasketController.php:230 +#: ../../../../application/controllers/BasketController.php:254 msgid "Created" msgstr "Erstellt" -#: application/controllers/ImportsourceController.php:109 +#: ../../../../application/controllers/ImportsourceController.php:109 msgid "Creating Import Sources" msgstr "Importquellen erstellen" -#: application/controllers/JobController.php:36 +#: ../../../../application/controllers/JobController.php:36 msgid "Creating Jobs" msgstr "Aufträge erstellen" -#: application/controllers/SyncruleController.php:524 +#: ../../../../application/controllers/SyncruleController.php:523 msgid "Creating Sync Rules" msgstr "Synchronisationsregeln erstellen" -#: library/Director/Web/Controller/ObjectController.php:146 +#: ../../../../library/Director/Web/Controller/ObjectController.php:147 msgid "Creating Templates" msgstr "Vorlagen erstellen" -#: library/Director/IcingaConfig/StateFilterSet.php:26 +#: ../../../../library/Director/IcingaConfig/StateFilterSet.php:26 msgid "Critical" msgstr "Kritisch" -#: library/Director/Web/Controller/TemplateController.php:186 +#: ../../../../library/Director/Web/Controller/TemplateController.php:187 msgid "Current Template Usage" msgstr "Aktuelle Nutzung dieser Vorlage" -#: application/forms/IcingaHostForm.php:104 +#: ../../../../application/forms/IcingaHostForm.php:106 msgid "Custom Endpoint Name" msgstr "Individueller Endpunktname" -#: application/forms/BasketForm.php:57 +#: ../../../../application/forms/BasketForm.php:57 msgid "Custom Selection" msgstr "Benutzerdefinierte Auswahl" -#: application/controllers/CustomvarController.php:13 +#: ../../../../application/controllers/CustomvarController.php:13 msgid "Custom Variable" msgstr "Benutzerdefinierte Variable" -#: application/controllers/CustomvarController.php:14 +#: ../../../../application/controllers/CustomvarController.php:14 #, php-format msgid "Custom Variable variants: %s" msgstr "Varianten der benutzerdefinierten Variable: %s" -#: library/Director/Web/Tabs/DataTabs.php:30 +#: ../../../../library/Director/Web/Tabs/DataTabs.php:30 msgid "Custom Variables" msgstr "Benutzerdefinierte Variablen" -#: application/controllers/DataController.php:110 +#: ../../../../application/controllers/DataController.php:110 msgid "Custom Vars - Overview" msgstr "Benutzerdefinierte Variablen - Übersicht" -#: application/forms/SyncPropertyForm.php:180 +#: ../../../../application/forms/SyncPropertyForm.php:180 msgid "Custom expression" msgstr "Benutzerdefinierter Ausdruck" -#: library/Director/Web/Controller/ObjectController.php:250 +#: ../../../../library/Director/Web/Controller/ObjectController.php:253 #, php-format msgid "Custom fields: %s" msgstr "Benutzerdefinierte Felder: \"%s\"" -#: library/Director/IcingaConfig/TypeFilterSet.php:25 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:25 msgid "Custom notification" msgstr "Benutzerdefinierte Benachrichtigung" -#: library/Director/Web/Form/IcingaObjectFieldLoader.php:266 -#: application/forms/IcingaServiceForm.php:464 +#: ../../../../library/Director/Web/Form/IcingaObjectFieldLoader.php:266 +#: ../../../../application/forms/IcingaServiceForm.php:468 msgid "Custom properties" msgstr "Benutzerdefinierte Eigenschaften" -#: application/forms/SyncPropertyForm.php:67 +#: ../../../../application/forms/SyncPropertyForm.php:67 msgid "Custom variable" msgstr "Benutzerdefinierte Variable" -#: application/forms/SyncPropertyForm.php:308 +#: ../../../../application/forms/SyncPropertyForm.php:308 msgid "Custom variable (vars.)" msgstr "Benutzerdefinierte Variable (vars.)" -#: library/Director/Objects/IcingaService.php:756 -#: library/Director/Objects/IcingaHost.php:164 -#: application/controllers/SuggestController.php:253 -#: application/controllers/SuggestController.php:263 +#: ../../../../library/Director/Objects/IcingaHost.php:163 +#: ../../../../library/Director/Objects/IcingaService.php:669 +#: ../../../../application/controllers/SuggestController.php:253 +#: ../../../../application/controllers/SuggestController.php:263 msgid "Custom variables" msgstr "Benutzerdefinierte Variablen" -#: library/Director/Dashboard/Dashlet/CustomvarDashlet.php:11 +#: ../../../../library/Director/Dashboard/Dashlet/CustomvarDashlet.php:13 msgid "CustomVar Overview" msgstr "Benutzerdefinierte Variable - Übersicht" -#: library/Director/Import/ImportSourceSql.php:41 +#: ../../../../library/Director/Import/ImportSourceSql.php:41 msgid "DB Query" msgstr "Datenbank-Abfrage" -#: application/forms/KickstartForm.php:222 +#: ../../../../application/forms/KickstartForm.php:222 msgid "DB Resource" msgstr "Datenbankressource" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:15 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:15 msgid "DN component" msgstr "DN Komponente" -#: library/Director/PropertyModifier/PropertyModifierDnsRecords.php:25 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDnsRecords.php:25 msgid "DNS record type" msgstr "DNS-Record-Typ" -#: library/Director/Web/Tabs/MainTabs.php:34 +#: ../../../../library/Director/Web/Tabs/MainTabs.php:35 msgid "Daemon" msgstr "Dienst" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:40 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:40 #, php-format msgid "Daemon has been stopped %s, was running with PID %s as %s@%s" msgstr "Dienst wurde %s gestoppt, lief zuvor mit PID %s als %s@%s" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:62 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:62 #, php-format msgid "Daemon is running with PID %s as %s@%s, last refresh happened %s" msgstr "" "Dienst läuft mit PID %s als %s@%s, die letzte Aktualisierung fand %s statt" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:51 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:51 #, php-format msgid "" "Daemon keep-alive is outdated, was last seen running with PID %s as %s@%s %s" msgstr "" "Daemon keep-alive is outdated, was last seen running with PID %s as %s@%s %s" -#: library/Director/Dashboard/Dashlet/DatafieldCategoryDashlet.php:11 -#: application/controllers/DataController.php:93 +#: ../../../../library/Director/Dashboard/Dashlet/DatafieldCategoryDashlet.php:13 +#: ../../../../application/controllers/DataController.php:93 msgid "Data Field Categories" msgstr "Datenfeldkategorien" -#: application/forms/DirectorDatafieldForm.php:168 +#: ../../../../application/forms/DirectorDatafieldForm.php:167 msgid "Data Field Category" msgstr "Datenfeldkategorie" -#: application/controllers/DataController.php:75 +#: ../../../../application/controllers/DataController.php:75 msgid "Data Fields" msgstr "Datenfelder" -#: application/controllers/DataController.php:65 +#: ../../../../application/controllers/DataController.php:65 msgid "Data List" msgstr "Datenliste" -#: application/forms/SyncRuleForm.php:19 +#: ../../../../application/forms/SyncRuleForm.php:19 msgid "Data List Entry" msgstr "Datenlisteneintrag" -#: application/controllers/DataController.php:59 +#: ../../../../application/controllers/DataController.php:59 #, php-format msgid "Data List: %s" msgstr "Datenliste: %s" -#: application/forms/BasketForm.php:34 +#: ../../../../application/forms/BasketForm.php:34 msgid "Data Lists" msgstr "Datenlisten" -#: library/Director/Web/Tabs/DataTabs.php:24 +#: ../../../../library/Director/Web/Tabs/DataTabs.php:24 msgid "Data field categories" msgstr "Datenfeldkategorien" -#: application/forms/DirectorDatafieldCategoryForm.php:17 +#: ../../../../application/forms/DirectorDatafieldCategoryForm.php:17 msgid "" "Data field categories allow to structure Data Fields. Fields with a category " "will be shown grouped by category." @@ -1912,11 +1911,11 @@ msgstr "" "Datenfeldkategorien erlauben es, Datenfelder zu strukturieren. Felder mit " "einer Kategorie werden nach Kategorie gruppiert angezeigt." -#: library/Director/Web/Tabs/DataTabs.php:21 +#: ../../../../library/Director/Web/Tabs/DataTabs.php:21 msgid "Data fields" msgstr "Datenfelder" -#: application/forms/DirectorDatafieldForm.php:133 +#: ../../../../application/forms/DirectorDatafieldForm.php:133 msgid "" "Data fields allow you to customize input controls for Icinga custom " "variables. Once you defined them here, you can provide them through your " @@ -1929,21 +1928,21 @@ msgstr "" "granuläre Kontrolle darüber, welche Eigenschaften in welche Weise " "konfigurierbar sein sollen." -#: library/Director/Dashboard/Dashlet/DatafieldDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/DatafieldDashlet.php:19 msgid "Data fields make sure that configuration fits your rules" msgstr "" "Datenfelder sorgen dafür, dass die Konfiguration in vorgegebene Regeln passt" -#: application/forms/DirectorDatalistForm.php:24 +#: ../../../../application/forms/DirectorDatalistForm.php:24 msgid "Data list" msgstr "Datenliste" -#: library/Director/Web/Tabs/DataTabs.php:27 -#: application/controllers/DataController.php:32 +#: ../../../../library/Director/Web/Tabs/DataTabs.php:27 +#: ../../../../application/controllers/DataController.php:32 msgid "Data lists" msgstr "Datenlisten" -#: application/forms/DirectorDatalistForm.php:15 +#: ../../../../application/forms/DirectorDatalistForm.php:15 msgid "" "Data lists are mainly used as data providers for custom variables presented " "as dropdown boxes boxes. You can manually manage their entries here in " @@ -1958,31 +1957,31 @@ msgstr "" "Letzteres erlaubt das Synchronisieren der verfügbaren Auswahlmöglichkeiten " "mit externen Datenquellen" -#: application/forms/DirectorDatafieldForm.php:181 +#: ../../../../application/forms/DirectorDatafieldForm.php:180 msgid "Data type" msgstr "Datentyp" -#: application/forms/KickstartForm.php:272 +#: ../../../../application/forms/KickstartForm.php:272 msgid "Database backend" msgstr "Datenbankbackend" -#: library/Director/Web/Widget/ActivityLogInfo.php:507 -#: application/controllers/BranchController.php:61 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:507 +#: ../../../../application/controllers/BranchController.php:60 msgid "Date" msgstr "Datum" -#: library/Director/Web/Table/IcingaTimePeriodRangeTable.php:45 -#: library/Director/Web/Table/IcingaScheduledDowntimeRangeTable.php:51 -#: application/forms/IcingaTimePeriodRangeForm.php:21 -#: application/forms/IcingaScheduledDowntimeRangeForm.php:22 +#: ../../../../library/Director/Web/Table/IcingaTimePeriodRangeTable.php:45 +#: ../../../../library/Director/Web/Table/IcingaScheduledDowntimeRangeTable.php:51 +#: ../../../../application/forms/IcingaTimePeriodRangeForm.php:21 +#: ../../../../application/forms/IcingaScheduledDowntimeRangeForm.php:22 msgid "Day(s)" msgstr "Tag(e)" -#: application/forms/IcingaServiceForm.php:173 +#: ../../../../application/forms/IcingaServiceForm.php:175 msgid "Deactivate" msgstr "Deaktivieren" -#: application/forms/SettingsForm.php:130 +#: ../../../../application/forms/SettingsForm.php:130 msgid "" "Default configuration format. Please note that v1.x is for special " "transitional projects only and completely unsupported. There are no plans to " @@ -1993,11 +1992,15 @@ msgstr "" "unterstützt wird. Es gibt keine Pläne aus dem Director ein " "Konfigurationswerkzeug für Icinga 1.x zu machen" -#: application/forms/SettingsForm.php:32 +#: ../../../../application/forms/SettingsForm.php:32 msgid "Default global zone" msgstr "Globale Standard-Zone" -#: library/Director/Dashboard/CommandsDashboard.php:23 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMap.php:45 +msgid "Default value" +msgstr "Standardwert" + +#: ../../../../library/Director/Dashboard/CommandsDashboard.php:23 msgid "" "Define Check-, Notification- or Event-Commands. Command definitions are the " "glue between your Host- and Service-Checks and the Check plugins on your " @@ -2008,11 +2011,11 @@ msgstr "" "Checks und den Check-Plugins auf dem Monitoring- (oder dem überwachten) " "System" -#: library/Director/Dashboard/Dashlet/DatafieldDashlet.php:11 +#: ../../../../library/Director/Dashboard/Dashlet/DatafieldDashlet.php:13 msgid "Define Data Fields" msgstr "Datenfelder definieren" -#: library/Director/Dashboard/Dashlet/HostGroupsDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/HostGroupsDashlet.php:19 msgid "" "Define Host Groups to give your configuration more structure. They are " "useful for Dashboards, Notifications or Restrictions" @@ -2021,7 +2024,7 @@ msgstr "" "Nützlich sind diese auch für Dashboards, Benachrichtigungen oder " "Berechtigungen" -#: application/forms/SelfServiceSettingsForm.php:116 +#: ../../../../application/forms/SelfServiceSettingsForm.php:116 msgid "" "Define a download Url or local directory from which the a specific Icinga 2 " "Agent MSI Installer package should be fetched. Please ensure to only define " @@ -2039,20 +2042,20 @@ msgstr "" "MSI-Installer-Name wie folgt erstellt: Icinga2-v[InstallAgentVersion]-" "[OSArchitecture].msi (volles Beispiel: Icinga2-v2.6.3-x86_64.msi)" -#: library/Director/Dashboard/Dashlet/ImportSourceDashlet.php:29 +#: ../../../../library/Director/Dashboard/Dashlet/ImportSourceDashlet.php:30 msgid "Define and manage imports from various data sources" msgstr "Definiert und verwaltet Importe von diversen Datenquellen" -#: library/Director/Dashboard/TimeperiodsDashboard.php:14 +#: ../../../../library/Director/Dashboard/TimeperiodsDashboard.php:14 msgid "Define custom Time Periods" msgstr "Benutzerdefinierte Zeiträume festlegen" -#: library/Director/Dashboard/Dashlet/SyncDashlet.php:29 +#: ../../../../library/Director/Dashboard/Dashlet/SyncDashlet.php:30 msgid "Define how imported data should be synchronized with Icinga" msgstr "" "Definieren, wie importierte Daten mit Icinga synchronisiert werden sollen" -#: application/forms/SyncRuleForm.php:54 +#: ../../../../application/forms/SyncRuleForm.php:54 msgid "" "Define what should happen when an object with a matching key already exists. " "You could merge its properties (import source wins), replace it completely " @@ -2065,16 +2068,16 @@ msgstr "" "durch das importierte Objekt ersetzt oder ignoriert (hilfreich für einmalige " "Importe) werden." -#: library/Director/Dashboard/ObjectsDashboard.php:15 +#: ../../../../library/Director/Dashboard/ObjectsDashboard.php:15 msgid "Define whatever you want to be monitored" msgstr "Angeben, was überwacht werden soll" -#: library/Director/Web/Form/DirectorObjectForm.php:1393 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1396 msgid "Defines after how many check attempts a new hard state is reached" msgstr "" "Legt fest, nach wie vielen Versuchen ein neuer Hard State erreicht wird" -#: library/Director/Dashboard/Dashlet/UserGroupsDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/UserGroupsDashlet.php:19 msgid "" "Defining Notifications for User Groups instead of single Users gives more " "flexibility" @@ -2082,7 +2085,7 @@ msgstr "" "Für Benutzergruppen anstelle einzelner Benutzer definierte " "Benachrichtigungen geben mehr Flexibilität" -#: library/Director/Dashboard/Dashlet/ServiceGroupsDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceGroupsDashlet.php:19 msgid "" "Defining Service Groups get more structure. Great for Dashboards. " "Notifications and Permissions might be based on groups." @@ -2090,108 +2093,108 @@ msgstr "" "Definiere Service-Gruppen für mehr Struktur. Nützlich für Dashboards. " "Benachrichtigungen und Berechtigungen können auf Gruppen basieren." -#: application/forms/IcingaNotificationForm.php:199 -msgid "Delay unless the first notification should be sent" +#: ../../../../application/forms/IcingaNotificationForm.php:247 +msgid "Delay until the first notification should be sent" msgstr "Verzögerung bis die erste Benachrichtigung verschickt werden soll" -#: library/Director/Web/Form/DirectorObjectForm.php:925 -#: application/forms/IcingaObjectFieldForm.php:193 -#: application/forms/SyncRuleForm.php:87 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:928 +#: ../../../../application/forms/SyncRuleForm.php:87 +#: ../../../../application/forms/IcingaObjectFieldForm.php:142 msgid "Delete" msgstr "Löschen" -#: library/Director/PropertyModifier/PropertyModifierSplit.php:13 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSplit.php:13 msgid "Delimiter" msgstr "Trenner" -#: library/Director/Dashboard/Dashlet/DependencyObjectDashlet.php:13 -#: library/Director/Db/Branch/BranchModificationInspection.php:47 -#: application/forms/BasketForm.php:33 +#: ../../../../library/Director/Dashboard/Dashlet/DependencyObjectDashlet.php:13 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:47 +#: ../../../../application/forms/BasketForm.php:33 msgid "Dependencies" msgstr "Abhängigkeiten" -#: application/forms/SyncRuleForm.php:24 +#: ../../../../application/forms/SyncRuleForm.php:24 msgid "Dependency" msgstr "Abhängigkeit" -#: application/forms/DeploymentLinkForm.php:94 +#: ../../../../application/forms/DeploymentLinkForm.php:95 msgid "Deploy" msgstr "Ausrollen" -#: application/forms/DeployConfigForm.php:37 +#: ../../../../application/forms/DeployConfigForm.php:37 #, php-format msgid "Deploy %d pending changes" msgstr "%d ausstehende Änderungen ausrollen" -#: library/Director/Dashboard/DeploymentDashboard.php:15 +#: ../../../../library/Director/Dashboard/DeploymentDashboard.php:15 msgid "Deploy configuration to your Icinga nodes" msgstr "Konfiguration auf Icinga Knoten ausrollen" -#: library/Director/Job/ConfigJob.php:45 +#: ../../../../library/Director/Job/ConfigJob.php:45 msgid "Deploy modified config" msgstr "Veränderte Konfiguration ausrollen" -#: library/Director/Web/Widget/DeploymentInfo.php:54 -#: application/controllers/ConfigController.php:270 -#: application/controllers/ConfigController.php:507 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:55 +#: ../../../../application/controllers/ConfigController.php:271 +#: ../../../../application/controllers/ConfigController.php:508 msgid "Deployment" msgstr "Deployment" -#: application/forms/SettingsForm.php:165 +#: ../../../../application/forms/SettingsForm.php:165 msgid "Deployment Path" msgstr "Deployment-Pfad" -#: application/controllers/DeploymentController.php:22 +#: ../../../../application/controllers/DeploymentController.php:22 msgid "Deployment details" msgstr "Deployment-Details" -#: application/forms/SettingsForm.php:150 +#: ../../../../application/forms/SettingsForm.php:150 msgid "Deployment mode" msgstr "Ausrollmodus" -#: application/forms/SettingsForm.php:159 +#: ../../../../application/forms/SettingsForm.php:159 msgid "Deployment mode for Icinga 1 configuration" msgstr "Ausrollmodus für Icinga 1 Konfiguration" -#: library/Director/Web/Widget/DeploymentInfo.php:77 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:78 msgid "Deployment time" msgstr "Deployment-Zeit" -#: configuration.php:178 -#: library/Director/Web/Tabs/InfraTabs.php:36 -#: application/controllers/ConfigController.php:57 +#: ../../../../configuration.php:146 +#: ../../../../library/Director/Web/Tabs/InfraTabs.php:37 +#: ../../../../application/controllers/ConfigController.php:58 msgid "Deployments" msgstr "Deployments" -#: library/Director/Web/Table/CoreApiFieldsTable.php:87 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:87 msgid "Deprecated" msgstr "Abgekündigt" -#: application/forms/IcingaCommandArgumentForm.php:31 -#: application/forms/ImportSourceForm.php:24 -#: application/forms/DirectorDatafieldCategoryForm.php:31 -#: application/forms/DirectorDatafieldForm.php:159 -#: application/forms/IcingaServiceSetForm.php:102 -#: application/forms/IcingaObjectFieldForm.php:133 -#: application/forms/SyncRuleForm.php:36 -#: application/forms/ImportRowModifierForm.php:52 -#: application/forms/IcingaTemplateChoiceForm.php:56 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:31 +#: ../../../../application/forms/ImportSourceForm.php:24 +#: ../../../../application/forms/DirectorDatafieldCategoryForm.php:31 +#: ../../../../application/forms/IcingaServiceSetForm.php:103 +#: ../../../../application/forms/ImportRowModifierForm.php:52 +#: ../../../../application/forms/DirectorDatafieldForm.php:158 +#: ../../../../application/forms/SyncRuleForm.php:36 +#: ../../../../application/forms/IcingaObjectFieldForm.php:94 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:56 msgid "Description" msgstr "Beschreibung" -#: application/forms/IcingaCommandArgumentForm.php:32 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:32 msgid "Description of the argument" msgstr "Beschreibung des Arguments" -#: library/Director/Web/Table/SyncpropertyTable.php:63 +#: ../../../../library/Director/Web/Table/SyncpropertyTable.php:63 msgid "Destination" msgstr "Ziel" -#: application/forms/SyncPropertyForm.php:48 +#: ../../../../application/forms/SyncPropertyForm.php:48 msgid "Destination Field" msgstr "Zielfeld" -#: application/controllers/HealthController.php:25 +#: ../../../../application/controllers/HealthController.php:25 msgid "" "Did you know that you can run this entire Health Check (or just some " "sections) as an Icinga Check on a regular base?" @@ -2199,167 +2202,167 @@ msgstr "" "Wussten Sie, dass sich dieser Health-Check (oder auch nur Abschnitte daraus) " "als regelmäßiger Icinga-Check ausführen lässt?" -#: library/Director/Web/Widget/ActivityLogInfo.php:367 -#: application/controllers/ConfigController.php:426 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:367 +#: ../../../../application/controllers/ConfigController.php:427 msgid "Diff" msgstr "Diff" -#: library/Director/Web/Widget/DeployedConfigInfoHeader.php:84 +#: ../../../../library/Director/Web/Widget/DeployedConfigInfoHeader.php:84 msgid "Diff with other config" msgstr "Mit anderer Konfiguration vergleichen" -#: library/Director/Web/Table/TemplateUsageTable.php:55 +#: ../../../../library/Director/Web/Table/TemplateUsageTable.php:55 msgid "Direct" msgstr "Direkt" -#: application/controllers/DaemonController.php:20 -#: application/controllers/DaemonController.php:22 +#: ../../../../application/controllers/DaemonController.php:20 +#: ../../../../application/controllers/DaemonController.php:22 msgid "Director Background Daemon" msgstr "Director Hintergrunddienst" -#: application/controllers/HealthController.php:17 +#: ../../../../application/controllers/HealthController.php:17 msgid "Director Health" msgstr "Director-Health" -#: application/controllers/KickstartController.php:16 +#: ../../../../application/controllers/KickstartController.php:16 msgid "Director Kickstart Wizard" msgstr "Director Kickstart-Assistent" -#: library/Director/Import/ImportSourceDirectorObject.php:69 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:69 msgid "Director Object" msgstr "Director-Objekt" -#: library/Director/Dashboard/Dashlet/SettingsDashlet.php:11 +#: ../../../../library/Director/Dashboard/Dashlet/SettingsDashlet.php:13 msgid "Director Settings" msgstr "Director-Einstellungen" -#: library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:81 +#: ../../../../library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:81 msgid "Director database schema has not been created yet" msgstr "Datenbankschema für Director wurde noch nicht erstellt" -#: application/forms/SyncRuleForm.php:88 +#: ../../../../application/forms/SyncRuleForm.php:88 msgid "Disable" msgstr "Deaktivien" -#: application/forms/IcingaDependencyForm.php:159 +#: ../../../../application/forms/IcingaDependencyForm.php:159 msgid "Disable Checks" msgstr "Checks deaktivieren" -#: application/forms/IcingaDependencyForm.php:167 -msgid "Disable Notificiations" +#: ../../../../application/forms/IcingaDependencyForm.php:167 +msgid "Disable Notifications" msgstr "Benachrichtigungen deaktivieren" -#: application/forms/SettingsForm.php:54 +#: ../../../../application/forms/SettingsForm.php:54 msgid "Disable all Jobs" msgstr "Alle Aufträge deaktivieren" -#: library/Director/Web/Form/DirectorObjectForm.php:1296 -#: application/forms/DirectorJobForm.php:37 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1299 +#: ../../../../application/forms/DirectorJobForm.php:37 msgid "Disabled" msgstr "Deaktiviert" -#: application/forms/IcingaCommandForm.php:79 +#: ../../../../application/forms/IcingaCommandForm.php:79 msgid "Disabled by default, and should only be used in rare cases." msgstr "" "Standardmäßig deaktiviert, sollte nur in seltenen Fällen benutzt werden." -#: library/Director/Web/Form/DirectorObjectForm.php:1297 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1300 msgid "Disabled objects will not be deployed" msgstr "Deaktivierte Objekte werden nicht ausgerollt" -#: library/Director/Web/Form/DirectorObjectForm.php:1312 -#: application/forms/IcingaTimePeriodForm.php:20 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1315 +#: ../../../../application/forms/IcingaTimePeriodForm.php:20 msgid "Display Name" msgstr "Anzeigename" -#: application/forms/IcingaUserForm.php:133 -#: application/forms/IcingaHostForm.php:352 +#: ../../../../application/forms/IcingaUserForm.php:133 +#: ../../../../application/forms/IcingaHostForm.php:354 msgid "Display name" msgstr "Anzeigename" -#: library/Director/Web/Table/CustomvarTable.php:42 +#: ../../../../library/Director/Web/Table/CustomvarTable.php:42 msgid "Distinct Commands" msgstr "Unterschiedliche Kommandos" -#: library/Director/Dashboard/DataDashboard.php:16 +#: ../../../../library/Director/Dashboard/DataDashboard.php:16 msgid "Do more with custom data" msgstr "Mehr mit benutzerdefinierten Daten anfangen" -#: application/forms/SelfServiceSettingsForm.php:36 +#: ../../../../application/forms/SelfServiceSettingsForm.php:36 msgid "Do not transform at all" msgstr "Überhaupt nicht umwandeln" -#: library/Director/Web/SelfService.php:177 +#: ../../../../library/Director/Web/SelfService.php:164 msgid "Documentation" msgstr "Dokumentation" -#: application/forms/SelfServiceSettingsForm.php:50 +#: ../../../../application/forms/SelfServiceSettingsForm.php:50 msgid "Don't care, my host settings are fine" msgstr "Keine Sorge, meine Host-Einstellungen sind in Ordnung" -#: library/Director/IcingaConfig/StateFilterSet.php:21 +#: ../../../../library/Director/IcingaConfig/StateFilterSet.php:21 msgid "Down" msgstr "Down" -#: library/Director/Web/SelfService.php:249 -#: library/Director/Web/SelfService.php:262 -#: application/controllers/SchemaController.php:80 -#: application/controllers/BasketController.php:214 +#: ../../../../library/Director/Web/SelfService.php:236 +#: ../../../../library/Director/Web/SelfService.php:249 +#: ../../../../application/controllers/SchemaController.php:80 +#: ../../../../application/controllers/BasketController.php:238 msgid "Download" msgstr "Download" -#: application/controllers/ImportsourceController.php:176 +#: ../../../../application/controllers/ImportsourceController.php:176 msgid "Download JSON" msgstr "JSON herunterladen" -#: library/Director/Web/Widget/AdditionalTableActions.php:59 +#: ../../../../library/Director/Web/Widget/AdditionalTableActions.php:60 msgid "Download as JSON" msgstr "Als JSON herunterladen" -#: application/forms/SelfServiceSettingsForm.php:83 +#: ../../../../application/forms/SelfServiceSettingsForm.php:83 msgid "Download from a custom url" msgstr "Von einer benutzerdefinierten URL laden" -#: application/forms/SelfServiceSettingsForm.php:82 +#: ../../../../application/forms/SelfServiceSettingsForm.php:82 msgid "Download from packages.icinga.com" msgstr "Von packages.icinga.com herunterladen" -#: library/Director/IcingaConfig/TypeFilterSet.php:30 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:30 msgid "Downtime ends" msgstr "Downtime endet" -#: application/forms/IcingaScheduledDowntimeForm.php:21 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:21 msgid "Downtime name" msgstr "Downtime-Name" -#: library/Director/IcingaConfig/TypeFilterSet.php:31 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:31 msgid "Downtime removed" msgstr "Downtime entfernt" -#: library/Director/IcingaConfig/TypeFilterSet.php:29 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:29 msgid "Downtime starts" msgstr "Downtime startet" -#: application/forms/IcingaForgetApiKeyForm.php:22 +#: ../../../../application/forms/IcingaForgetApiKeyForm.php:22 msgid "Drop Self Service API key" msgstr "Selbstbedienungs-API-Schlüssel verwerfen" -#: library/Director/PropertyModifier/PropertyModifierArrayToRow.php:23 -#: library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:30 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:30 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayToRow.php:23 msgid "Drop the current row" msgstr "Die aktuelle Zeile verwerfen" -#: library/Director/DataType/DataTypeDatalist.php:150 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:150 msgid "Dropdown (list values only)" msgstr "Aufklappmenü (nur Listeneinträge)" -#: library/Director/Web/Widget/DeploymentInfo.php:83 -#: library/Director/Web/Widget/SyncRunDetails.php:29 -#: application/forms/IcingaScheduledDowntimeForm.php:56 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:84 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:29 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:56 msgid "Duration" msgstr "Dauer" -#: library/Director/PropertyModifier/PropertyModifierListToObject.php:18 +#: ../../../../library/Director/PropertyModifier/PropertyModifierListToObject.php:18 msgid "" "Each Array in the list must contain this property. It's value will be used " "as the key/object property name for the row." @@ -2367,39 +2370,39 @@ msgstr "" "Jedes Array in der Liste enthält diese Eigenschaft. Dessen Wert wird als " "Schlüssel/Objektbezeichner für die Zeile benutzt." -#: application/controllers/DatafieldcategoryController.php:37 +#: ../../../../application/controllers/DatafieldcategoryController.php:37 msgid "Edit a Category" msgstr "Kategorie bearbeiten" -#: application/controllers/DatafieldController.php:31 +#: ../../../../application/controllers/DatafieldController.php:31 msgid "Edit a Field" msgstr "Ein Feld bearbeiten" -#: application/controllers/DataController.php:397 +#: ../../../../application/controllers/DataController.php:397 msgid "Edit list" msgstr "Liste bearbeiten" -#: library/Director/DataType/DataTypeDatalist.php:144 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:144 msgid "Element behavior" msgstr "Verhalten des Elements" -#: application/forms/IcingaUserForm.php:36 +#: ../../../../application/forms/IcingaUserForm.php:36 msgid "Email" msgstr "E-Mail" -#: application/forms/SettingsForm.php:69 +#: ../../../../application/forms/SettingsForm.php:69 msgid "Enable audit log" msgstr "Revisionslog aktivieren" -#: library/Director/Web/Form/DirectorObjectForm.php:1446 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1449 msgid "Enable event handler" msgstr "Eventhandler aktivieren" -#: library/Director/Web/Form/DirectorObjectForm.php:1458 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1461 msgid "Enable flap detection" msgstr "Flap-Erkennung aktivieren" -#: application/forms/SettingsForm.php:111 +#: ../../../../application/forms/SettingsForm.php:111 msgid "" "Enabled the feature for custom endpoint names, where you can choose a " "different name for the generated endpoint object. This uses some Icinga " @@ -2412,49 +2415,49 @@ msgstr "" "benutzerdefinierte Variable eingesetzt. Bitte NICHT aktivieren, wenn " "abweichende Endpunktnamen nicht wirklich erforderlich sind!" -#: library/Director/PropertyModifier/PropertyModifierTrim.php:22 +#: ../../../../library/Director/PropertyModifier/PropertyModifierTrim.php:22 msgid "Ending only" msgstr "Nur das Ende" -#: library/Director/Import/ImportSourceDirectorObject.php:72 -#: library/Director/Web/Table/ObjectsTableEndpoint.php:19 -#: application/forms/IcingaEndpointForm.php:24 -#: application/forms/SyncRuleForm.php:25 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:72 +#: ../../../../library/Director/Web/Table/ObjectsTableEndpoint.php:19 +#: ../../../../application/forms/IcingaEndpointForm.php:24 +#: ../../../../application/forms/SyncRuleForm.php:25 msgid "Endpoint" msgstr "Endpunkt" -#: application/forms/KickstartForm.php:121 +#: ../../../../application/forms/KickstartForm.php:121 msgid "Endpoint Name" msgstr "Name des Endpunkts" -#: application/forms/IcingaEndpointForm.php:31 +#: ../../../../application/forms/IcingaEndpointForm.php:31 msgid "Endpoint address" msgstr "Adresse des Endpunkts" -#: library/Director/Web/Widget/InspectPackages.php:46 +#: ../../../../library/Director/Web/Widget/InspectPackages.php:46 msgid "Endpoint in your Root Zone" msgstr "Endpunkte in Rootzone" -#: application/forms/IcingaEndpointForm.php:18 +#: ../../../../application/forms/IcingaEndpointForm.php:18 msgid "Endpoint template name" msgstr "Name der Endpunktsvorlage" -#: library/Director/Dashboard/Dashlet/EndpointObjectDashlet.php:17 -#: library/Director/Db/Branch/BranchModificationInspection.php:35 -#: library/Director/Import/ImportSourceCoreApi.php:59 +#: ../../../../library/Director/Dashboard/Dashlet/EndpointObjectDashlet.php:18 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:35 +#: ../../../../library/Director/Import/ImportSourceCoreApi.php:59 msgid "Endpoints" msgstr "Endpunkte" -#: application/controllers/PhperrorController.php:15 -#: application/controllers/PhperrorController.php:34 +#: ../../../../application/controllers/PhperrorController.php:15 +#: ../../../../application/controllers/PhperrorController.php:34 msgid "Error" msgstr "Fehler" -#: application/forms/IcingaHostForm.php:86 +#: ../../../../application/forms/IcingaHostForm.php:88 msgid "Establish connection" msgstr "Verbindung herstellen" -#: application/forms/IcingaServiceForm.php:627 +#: ../../../../application/forms/IcingaServiceForm.php:631 msgid "" "Evaluates the apply for rule for all objects with the custom attribute " "specified. E.g selecting \"host.vars.custom_attr\" will generate \"for " @@ -2468,83 +2471,85 @@ msgstr "" "Dabei ist \"config\" dann als \"$config$\" zugänglich. HINWEIS: nur " "benutzerdefinierte Eigenschaften vom Typ \"Array\" sind wählbar." -#: library/Director/Web/Form/DirectorObjectForm.php:1350 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1353 msgid "Event command" msgstr "Event-Kommando" -#: library/Director/Web/Form/DirectorObjectForm.php:1351 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1354 msgid "Event command definition" msgstr "Event-Kommandodefinition" -#: library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:23 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:23 msgid "" "Every Dictionary entry has a key, its value will be provided in this column" msgstr "" +"Jeder Dictionary-Eintrag hat einen Schlüssel, sein Wert wird in dieser " +"Spalte bereitgestellt" -#: application/forms/IcingaScheduledDowntimeForm.php:41 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:41 msgid "Every related downtime will show this comment" msgstr "Jede zugehörige Downtime wird diesen Kommentar anzeigen" -#: application/forms/IcingaTimePeriodForm.php:70 +#: ../../../../application/forms/IcingaTimePeriodForm.php:70 msgid "Exclude other time periods from this." msgstr "Andere Zeiträume von diesem ausschließen." -#: application/forms/IcingaTimePeriodForm.php:67 +#: ../../../../application/forms/IcingaTimePeriodForm.php:67 msgid "Exclude period" msgstr "Zeitraum ausschließen" -#: library/Director/Web/Form/DirectorObjectForm.php:1428 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1431 msgid "Execute active checks" msgstr "Aktive Checks ausführen" -#: application/forms/DirectorJobForm.php:48 +#: ../../../../application/forms/DirectorJobForm.php:48 msgid "Execution interval for this job, in seconds" msgstr "Ausführungsintervall dieses Auftrags, in Sekunden" -#: application/forms/SyncPropertyForm.php:251 +#: ../../../../application/forms/SyncPropertyForm.php:251 msgid "Existing Data Lists" msgstr "Vorhandene Datenlisten" -#: application/forms/SyncPropertyForm.php:236 +#: ../../../../application/forms/SyncPropertyForm.php:236 msgid "Existing templates" msgstr "Vorhandene Vorlagen" -#: application/controllers/BranchController.php:46 +#: ../../../../application/controllers/BranchController.php:45 msgid "Expected Modification" msgstr "Erwartete Änderungen" -#: application/forms/SyncPropertyForm.php:179 +#: ../../../../application/forms/SyncPropertyForm.php:179 msgid "Expert mode" msgstr "Expertenmodus" -#: library/Director/DataType/DataTypeDatalist.php:154 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:154 msgid "Extend the list with new values" msgstr "Erweitere die Liste mit neuen Werten" -#: library/Director/Web/Tabs/ObjectsTabs.php:35 +#: ../../../../library/Director/Web/Tabs/ObjectsTabs.php:36 msgid "External" msgstr "Extern" -#: application/forms/BasketForm.php:18 +#: ../../../../application/forms/BasketForm.php:18 msgid "External Command Definitions" msgstr "Externe Kommandodefinitionen" -#: library/Director/Dashboard/Dashlet/ExternalCheckCommandsDashlet.php:19 +#: ../../../../library/Director/Dashboard/Dashlet/ExternalCheckCommandsDashlet.php:19 msgid "External Commands" msgstr "Externe Kommandos" -#: library/Director/Dashboard/Dashlet/ExternalCheckCommandsDashlet.php:12 +#: ../../../../library/Director/Dashboard/Dashlet/ExternalCheckCommandsDashlet.php:12 msgid "" "External Commands have been defined in your local Icinga 2 Configuration." msgstr "" "Externe Kommandos wurden in der lokalen Icinga-2-Konfiguration definiert." -#: library/Director/Dashboard/Dashlet/ExternalNotificationCommandsDashlet.php:19 +#: ../../../../library/Director/Dashboard/Dashlet/ExternalNotificationCommandsDashlet.php:19 msgid "External Notification Commands" msgstr "Externe Benachrichtigungskommandos" -#: library/Director/Dashboard/Dashlet/CommandTemplatesDashlet.php:12 -#: library/Director/Dashboard/Dashlet/ExternalNotificationCommandsDashlet.php:12 +#: ../../../../library/Director/Dashboard/Dashlet/CommandTemplatesDashlet.php:12 +#: ../../../../library/Director/Dashboard/Dashlet/ExternalNotificationCommandsDashlet.php:12 msgid "" "External Notification Commands have been defined in your local Icinga 2 " "Configuration." @@ -2552,83 +2557,84 @@ msgstr "" "Externe Benachrichtigungskommandos wurden in der lokalen Icinga-2-" "Konfiguration definiert." -#: library/Director/Import/ImportSourceDirectorObject.php:83 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:83 msgid "External Objects" msgstr "Externe Objekte" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:75 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:75 msgid "FQDN" msgstr "FQDN" -#: library/Director/Web/Widget/DeploymentInfo.php:141 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:142 msgid "Failed" msgstr "Fehlgeschlagen" -#: application/forms/IcingaImportObjectForm.php:42 +#: ../../../../application/forms/IcingaImportObjectForm.php:42 #, php-format msgid "Failed to import %s \"%s\"" msgstr "Import von %s fehlgeschlagen \"%s\"" -#: application/forms/SettingsForm.php:109 +#: ../../../../application/forms/SettingsForm.php:109 msgid "Feature: Custom Endpoint Name" msgstr "Feature: Individueller Endpunktname" -#: application/forms/IcingaObjectFieldForm.php:196 +#: ../../../../application/forms/IcingaObjectFieldForm.php:145 msgid "Field has been removed" msgstr "Feld wurde entfernt" -#: library/Director/Web/Table/IcingaObjectDatafieldTable.php:50 -#: library/Director/Web/Table/DatafieldTable.php:50 -#: application/forms/DirectorDatafieldForm.php:141 +#: ../../../../library/Director/Web/Table/IcingaObjectDatafieldTable.php:50 +#: ../../../../library/Director/Web/Table/DatafieldTable.php:52 +#: ../../../../application/forms/DirectorDatafieldForm.php:141 msgid "Field name" msgstr "Feldname" -#: application/forms/DirectorDatafieldForm.php:182 +#: ../../../../application/forms/DirectorDatafieldForm.php:181 msgid "Field type" msgstr "Feldtyp" -#: library/Director/Web/Tabs/ObjectTabs.php:103 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:100 msgid "Fields" msgstr "Felder" -#: library/Director/Web/Table/GeneratedConfigFileTable.php:84 -#: library/Director/Web/Table/ConfigFileDiffTable.php:82 +#: ../../../../library/Director/Web/Table/GeneratedConfigFileTable.php:84 +#: ../../../../library/Director/Web/Table/ConfigFileDiffTable.php:82 msgid "File" msgstr "Datei" -#: library/Director/Web/Widget/InspectPackages.php:54 +#: ../../../../library/Director/Web/Widget/InspectPackages.php:54 #, php-format msgid "File Content: %s" msgstr "Dateiinhalt: %s" -#: library/Director/Web/Widget/InspectPackages.php:52 +#: ../../../../library/Director/Web/Widget/InspectPackages.php:52 #, php-format msgid "Files in Stage: %s" msgstr "Dateien im Stage: %s" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:44 -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:54 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:44 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:54 msgid "Filter" msgstr "Filter" -#: application/forms/SyncPropertyForm.php:103 -#: application/forms/SyncRuleForm.php:95 +#: ../../../../application/forms/ImportRowModifierForm.php:89 +#: ../../../../application/forms/SyncPropertyForm.php:103 +#: ../../../../application/forms/SyncRuleForm.php:95 msgid "Filter Expression" msgstr "Filterausdruck" -#: configuration.php:80 +#: ../../../../configuration.php:57 msgid "Filter available notification apply rules" msgstr "Verfügbare Benachrichtigungs-Apply-Regeln filtern" -#: configuration.php:87 +#: ../../../../configuration.php:60 msgid "Filter available scheduled downtime rules" msgstr "Verfügbare Geplante-Downtime-Regeln filtern" -#: configuration.php:73 +#: ../../../../configuration.php:63 msgid "Filter available service apply rules" msgstr "Verfügbare Service-Apply-Regeln filtern" -#: configuration.php:94 +#: ../../../../configuration.php:66 msgid "" "Filter available service set templates. Use asterisks (*) as wildcards, like " "in DB* or *net*" @@ -2636,103 +2642,103 @@ msgstr "" "Verfügbare Service-Set-Vorlagen filtern. Benutze Sternchen (*) als " "Platzhalter, wie in DB* oder *net*" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:29 -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:29 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:27 msgid "Filter method" msgstr "Filter-Methode" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:33 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:33 msgid "First Element" msgstr "Erstes Element" -#: application/forms/IcingaNotificationForm.php:197 +#: ../../../../application/forms/IcingaNotificationForm.php:245 msgid "First notification delay" msgstr "Verzögerung der ersten Benachrichtigung" -#: application/forms/IcingaScheduledDowntimeForm.php:47 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:47 msgid "Fixed" msgstr "Fix" -#: library/Director/IcingaConfig/TypeFilterSet.php:33 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:33 msgid "Flapping" msgstr "Flapping" -#: library/Director/IcingaConfig/TypeFilterSet.php:35 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:35 msgid "Flapping ends" msgstr "Flapping endet" -#: library/Director/Web/Form/DirectorObjectForm.php:1479 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1482 msgid "" "Flapping lower bound in percent for a service to be considered not flapping" msgstr "" "Untere Flapping-Grenze in Prozent um einen Service nicht als Flapping " "einzuordnen" -#: library/Director/IcingaConfig/TypeFilterSet.php:34 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:34 msgid "Flapping starts" msgstr "Flapping beginnt" -#: library/Director/Web/Form/DirectorObjectForm.php:1466 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1469 msgid "Flapping threshold (high)" msgstr "Flapping Schwellewert (hoch)" -#: library/Director/Web/Form/DirectorObjectForm.php:1477 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1480 msgid "Flapping threshold (low)" msgstr "Flapping Schwellwert (niedrig)" -#: library/Director/Web/Form/DirectorObjectForm.php:1468 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1471 msgid "Flapping upper bound in percent for a service to be considered flapping" msgstr "" "Obere Flapping-Grenze in Prozent um einen Service als Flapping einzuordnen" -#: application/forms/IcingaCloneObjectForm.php:50 +#: ../../../../application/forms/IcingaCloneObjectForm.php:52 msgid "Flatten all inherited properties, strip imports" msgstr "Alle vererbten Eigenschaften flach machen, Importierte entfernen" -#: application/forms/SelfServiceSettingsForm.php:100 +#: ../../../../application/forms/SelfServiceSettingsForm.php:100 msgid "Flush API directory" msgstr "API-Verzeichnis leeren" -#: library/Director/Web/SelfService.php:245 +#: ../../../../library/Director/Web/SelfService.php:232 msgid "For manual configuration" msgstr "Manuelle Konfiguration" -#: library/Director/Job/ConfigJob.php:31 +#: ../../../../library/Director/Job/ConfigJob.php:31 msgid "Force rendering" msgstr "Erstellen erzwingen" -#: library/Director/Objects/DirectorDatafield.php:237 +#: ../../../../library/Director/Objects/DirectorDatafield.php:204 #, php-format msgid "Form element could not be created, %s is missing" msgstr "Formularelement konnte nicht erstellt werden, %s ist nicht vorhanden" -#: library/Director/Web/Form/QuickForm.php:524 -#: library/Director/Web/Form/QuickForm.php:551 +#: ../../../../library/Director/Web/Form/QuickForm.php:524 +#: ../../../../library/Director/Web/Form/QuickForm.php:551 msgid "Form has successfully been sent" msgstr "Formular wurde erfolgreich abgeschickt" -#: application/forms/IcingaServiceVarForm.php:32 -#: application/forms/IcingaHostVarForm.php:32 +#: ../../../../application/forms/IcingaServiceVarForm.php:32 +#: ../../../../application/forms/IcingaHostVarForm.php:32 msgid "Format" msgstr "Format" -#: library/Director/Web/Widget/ActivityLogInfo.php:393 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:393 msgid "Former object" msgstr "Vorheriges Objekt" -#: application/forms/SelfServiceSettingsForm.php:24 +#: ../../../../application/forms/SelfServiceSettingsForm.php:24 msgid "Fully qualified domain name (FQDN)" msgstr "Voll qualifizierter Domain-Name (FQDN)" -#: application/forms/IcingaGenerateApiKeyForm.php:24 +#: ../../../../application/forms/IcingaGenerateApiKeyForm.php:24 msgid "Generate Self Service API key" msgstr "Selbstservice-API-Schlüssel generieren" -#: library/Director/Web/SelfService.php:114 +#: ../../../../library/Director/Web/SelfService.php:114 msgid "Generate a new key" msgstr "Neuen Schlüssel generieren" -#: library/Director/Web/SelfService.php:132 +#: ../../../../library/Director/Web/SelfService.php:132 msgid "" "Generated Host keys will continue to work, but you'll no longer be able to " "register new Hosts with this key" @@ -2740,79 +2746,79 @@ msgstr "" "Generierte Host-Schlüssel werden weiterhin funktionieren, aber es wird nicht " "mehr möglich sein neue Hosts mit diesem Schlüssel zu registrieren" -#: application/controllers/ConfigController.php:281 +#: ../../../../application/controllers/ConfigController.php:282 msgid "Generated config" msgstr "Erzeugte Konfiguration" -#: library/Director/Dashboard/AlertsDashboard.php:17 +#: ../../../../library/Director/Dashboard/AlertsDashboard.php:17 msgid "Get alerts when something goes wrong" msgstr "Werde alarmiert, wenn etwas schief läuft" -#: library/Director/Dashboard/Dashlet/CustomvarDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/CustomvarDashlet.php:19 msgid "Get an overview of used CustomVars and their variants" msgstr "Eine Übersicht über benutzerdefinierte Variablen und deren Varianten" -#: library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:27 msgid "Get host by address (Reverse DNS lookup)" msgstr "Host über Adresse ermitteln (Reverse DNS Lookup)" -#: library/Director/PropertyModifier/PropertyModifierGetHostByName.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByName.php:27 msgid "Get host by name (DNS lookup)" msgstr "Adresse für Hostname ermitteln (DNS Lookup)" -#: application/controllers/ConfigController.php:241 +#: ../../../../application/controllers/ConfigController.php:242 msgid "Global Director Settings" msgstr "Globale Director-Einstellungen" -#: library/Director/Web/SelfService.php:101 +#: ../../../../library/Director/Web/SelfService.php:101 msgid "Global Self Service Setting" msgstr "Globale Selbstbedienungs-Einstellungen" -#: application/forms/SelfServiceSettingsForm.php:57 +#: ../../../../application/forms/SelfServiceSettingsForm.php:57 msgid "Global Zones" msgstr "Globale Zonen" -#: application/forms/IcingaZoneForm.php:22 +#: ../../../../application/forms/IcingaZoneForm.php:22 msgid "Global zone" msgstr "Globale Zone" -#: library/Director/PropertyModifier/PropertyModifierJoin.php:13 +#: ../../../../library/Director/PropertyModifier/PropertyModifierJoin.php:13 msgid "Glue" msgstr "Kleben" -#: library/Director/Web/ActionBar/DirectorBaseActionBar.php:40 +#: ../../../../library/Director/Web/ActionBar/DirectorBaseActionBar.php:40 #, php-format msgid "Go back to \"%s\" Dashboard" msgstr "Zurück zum \"%s\" Dashboard" -#: library/Director/Job/ConfigJob.php:57 +#: ../../../../library/Director/Job/ConfigJob.php:57 msgid "Grace period" msgstr "Gnadenfrist" -#: library/Director/Web/Table/GroupMemberTable.php:72 +#: ../../../../library/Director/Web/Table/GroupMemberTable.php:72 msgid "Group" msgstr "Gruppe" -#: library/Director/PropertyModifier/PropertyModifierSimpleGroupBy.php:14 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSimpleGroupBy.php:14 msgid "Group by a column, aggregate others" msgstr "Gruppiere nach einer Spalte, aggregiere andere" -#: application/forms/IcingaHostForm.php:248 +#: ../../../../application/forms/IcingaHostForm.php:250 msgid "" "Group has been inherited, but will be overridden by locally assigned group(s)" msgstr "" "Die Gruppe wurde geerbt, wird aber von lokal gesetzten Gruppen überschrieben" -#: application/forms/SyncPropertyForm.php:318 +#: ../../../../application/forms/SyncPropertyForm.php:318 msgid "Group membership" msgstr "Gruppenmitgliedschaft" -#: library/Director/Web/Controller/ObjectController.php:329 +#: ../../../../library/Director/Web/Controller/ObjectController.php:332 #, php-format msgid "Group membership: %s" msgstr "Gruppenmitgliedschaft: %s" -#: library/Director/Dashboard/Dashlet/ServiceSetsDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceSetsDashlet.php:19 msgid "" "Grouping your Services into Sets allow you to quickly assign services often " "used together in a single operation all at once" @@ -2820,112 +2826,112 @@ msgstr "" "Das Bündel von Services in Sets erlaubt es, Services welche häufig gemeinsam " "benutzt werden in einem Einzelschritt zuzuweisen" -#: library/Director/Web/Tabs/ObjectsTabs.php:65 -#: application/forms/IcingaUserForm.php:109 -#: application/forms/IcingaHostForm.php:217 -#: application/forms/IcingaServiceForm.php:649 +#: ../../../../library/Director/Web/Tabs/ObjectsTabs.php:67 +#: ../../../../application/forms/IcingaUserForm.php:109 +#: ../../../../application/forms/IcingaServiceForm.php:653 +#: ../../../../application/forms/IcingaHostForm.php:219 msgid "Groups" msgstr "Gruppen" -#: library/Director/Import/ImportSourceRestApi.php:134 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:134 msgid "HTTP (this is plaintext!)" msgstr "HTTP (das ist Klartext)" -#: library/Director/Import/ImportSourceRestApi.php:149 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:149 msgid "HTTP Header" msgstr "HTTP-Header" -#: library/Director/Import/ImportSourceRestApi.php:250 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:250 msgid "HTTP proxy" msgstr "HTTP-Proxy" -#: library/Director/Import/ImportSourceRestApi.php:133 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:133 msgid "HTTPS (strongly recommended)" msgstr "HTTPS (dringend empfohlen)" -#: library/Director/Web/Tabs/MainTabs.php:31 +#: ../../../../library/Director/Web/Tabs/MainTabs.php:32 msgid "Health" msgstr "Health" -#: library/Director/Dashboard/Dashlet/SingleServicesDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/SingleServicesDashlet.php:19 msgid "Here you can find all single services directly attached to single hosts" msgstr "" "Hier finden sich alle Einzel-Services welche einzelnen Hosts zugewiesen " "wurden" -#: library/Director/DataType/DataTypeString.php:27 -#: library/Director/Web/Table/CoreApiFieldsTable.php:89 +#: ../../../../library/Director/DataType/DataTypeString.php:27 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:89 msgid "Hidden" msgstr "Versteckt" -#: library/Director/Web/Widget/AdditionalTableActions.php:70 +#: ../../../../library/Director/Web/Widget/AdditionalTableActions.php:71 msgid "Hide SQL" msgstr "SQL verbergeb" -#: application/controllers/HealthController.php:23 +#: ../../../../application/controllers/HealthController.php:23 msgid "Hint: Check Plugin" msgstr "Hinweis: Check-Plugin" -#: application/forms/IcingaServiceForm.php:166 +#: ../../../../application/forms/IcingaServiceForm.php:168 msgid "Hints regarding this service" msgstr "Hinweise zu diesem Service" -#: library/Director/Web/Tabs/ImportsourceTabs.php:45 -#: library/Director/Web/Tabs/SyncRuleTabs.php:43 -#: library/Director/Web/Tabs/ObjectTabs.php:95 +#: ../../../../library/Director/Web/Tabs/ImportsourceTabs.php:45 +#: ../../../../library/Director/Web/Tabs/SyncRuleTabs.php:43 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:92 msgid "History" msgstr "Historie" -#: library/Director/TranslationDummy.php:13 -#: library/Director/Import/ImportSourceDirectorObject.php:71 -#: library/Director/Web/Table/ObjectsTableService.php:106 -#: library/Director/Web/Table/ObjectsTableEndpoint.php:20 -#: application/forms/IcingaHostVarForm.php:15 -#: application/forms/IcingaServiceForm.php:597 -#: application/forms/SyncRuleForm.php:12 -#: application/controllers/ServiceController.php:280 +#: ../../../../library/Director/TranslationDummy.php:13 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:71 +#: ../../../../library/Director/Web/Table/ObjectsTableService.php:106 +#: ../../../../library/Director/Web/Table/ObjectsTableEndpoint.php:20 +#: ../../../../application/forms/IcingaHostVarForm.php:15 +#: ../../../../application/forms/IcingaServiceForm.php:601 +#: ../../../../application/forms/SyncRuleForm.php:12 +#: ../../../../application/controllers/ServiceController.php:280 msgid "Host" msgstr "Host" -#: library/Director/Objects/IcingaService.php:769 -#: application/controllers/SuggestController.php:262 +#: ../../../../library/Director/Objects/IcingaService.php:682 +#: ../../../../application/controllers/SuggestController.php:262 msgid "Host Custom variables" msgstr "Benutzerdefinierte Host-Variablen" -#: application/forms/SyncRuleForm.php:13 -#: application/forms/BasketForm.php:20 +#: ../../../../application/forms/BasketForm.php:20 +#: ../../../../application/forms/SyncRuleForm.php:13 msgid "Host Group" msgstr "Hostgruppe" -#: library/Director/Dashboard/Dashlet/HostGroupsDashlet.php:11 +#: ../../../../library/Director/Dashboard/Dashlet/HostGroupsDashlet.php:13 msgid "Host Groups" msgstr "Hostgruppen" -#: application/forms/SelfServiceSettingsForm.php:19 +#: ../../../../application/forms/SelfServiceSettingsForm.php:19 msgid "Host Name" msgstr "Hostname" -#: application/forms/IcingaHostForm.php:169 -#: application/forms/IcingaHostForm.php:186 +#: ../../../../application/forms/IcingaHostForm.php:171 +#: ../../../../application/forms/IcingaHostForm.php:188 msgid "Host Template" msgstr "Host-Vorlage" -#: application/forms/BasketForm.php:21 +#: ../../../../application/forms/BasketForm.php:21 msgid "Host Template Choice" msgstr "Auswahlmöglichkeit für Hostvorlagen" -#: library/Director/Dashboard/Dashlet/HostTemplatesDashlet.php:11 -#: application/forms/BasketForm.php:22 +#: ../../../../library/Director/Dashboard/Dashlet/HostTemplatesDashlet.php:13 +#: ../../../../application/forms/BasketForm.php:22 msgid "Host Templates" msgstr "Host-Vorlagen" -#: application/forms/IcingaHostForm.php:327 -#: application/forms/IcingaHostSelfServiceForm.php:35 +#: ../../../../application/forms/IcingaHostSelfServiceForm.php:35 +#: ../../../../application/forms/IcingaHostForm.php:329 msgid "Host address" msgstr "Hostadresse" -#: application/forms/IcingaHostForm.php:329 -#: application/forms/IcingaHostSelfServiceForm.php:37 +#: ../../../../application/forms/IcingaHostSelfServiceForm.php:37 +#: ../../../../application/forms/IcingaHostForm.php:331 msgid "" "Host address. Usually an IPv4 address, but may be any kind of address your " "check plugin is able to deal with" @@ -2933,51 +2939,51 @@ msgstr "" "Hostadresse. Üblicherweise eine IPv4 Adresse, kann jedoch jede Art von " "Adresse sein, mit der das Plugin umgehen kann" -#: configuration.php:99 +#: ../../../../configuration.php:70 msgid "Host configs" msgstr "Host-Konfigurationen" -#: library/Director/DataType/DataTypeDirectorObject.php:57 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:57 msgid "Host groups" msgstr "Hostgruppen" -#: application/forms/IcingaHostSelfServiceForm.php:25 +#: ../../../../application/forms/IcingaHostSelfServiceForm.php:25 msgid "Host name" msgstr "Hostname" -#: application/forms/SelfServiceSettingsForm.php:25 +#: ../../../../application/forms/SelfServiceSettingsForm.php:25 msgid "Host name (local part, without domain)" msgstr "Hostname (lokaler Teil, ohne Domain)" -#: library/Director/Dashboard/Dashlet/HostObjectDashlet.php:13 +#: ../../../../library/Director/Dashboard/Dashlet/HostObjectDashlet.php:15 msgid "Host objects" msgstr "Hostobjekte" -#: library/Director/Objects/IcingaService.php:768 -#: library/Director/Objects/IcingaHost.php:163 -#: application/controllers/SuggestController.php:252 -#: application/controllers/SuggestController.php:261 +#: ../../../../library/Director/Objects/IcingaHost.php:162 +#: ../../../../library/Director/Objects/IcingaService.php:681 +#: ../../../../application/controllers/SuggestController.php:252 +#: ../../../../application/controllers/SuggestController.php:261 msgid "Host properties" msgstr "Hosteigenschaften" -#: application/controllers/TemplatechoiceController.php:20 +#: ../../../../application/controllers/TemplatechoiceController.php:20 msgid "Host template choice" msgstr "Auswahlmöglichkeit für Hostvorlagen" -#: application/controllers/TemplatechoicesController.php:19 +#: ../../../../application/controllers/TemplatechoicesController.php:19 msgid "Host template choices" msgstr "Auswahlmöglichkeiten für Hostvorlagen" -#: application/forms/IcingaHostGroupForm.php:14 +#: ../../../../application/forms/IcingaHostGroupForm.php:14 msgid "Hostgroup" msgstr "Hostgruppe" -#: library/Director/Db/Branch/BranchModificationInspection.php:39 -#: library/Director/Import/ImportSourceCoreApi.php:61 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:39 +#: ../../../../library/Director/Import/ImportSourceCoreApi.php:61 msgid "Hostgroups" msgstr "Hostgruppen" -#: application/forms/IcingaHostForm.php:220 +#: ../../../../application/forms/IcingaHostForm.php:222 msgid "" "Hostgroups that should be directly assigned to this node. Hostgroups can be " "useful for various reasons. You might assign service checks based on " @@ -2993,38 +2999,38 @@ msgstr "" "direkt einzelnen Hosts oder Hostvorlagen zugeordnet werden. Auch über Apply " "Regeln können Hostgruppen zugewiesen werden" -#: library/Director/Web/Table/IcingaServiceSetHostTable.php:38 -#: library/Director/Web/Table/IcingaHostsMatchingFilterTable.php:48 -#: application/forms/IcingaHostForm.php:39 +#: ../../../../library/Director/Web/Table/IcingaServiceSetHostTable.php:38 +#: ../../../../library/Director/Web/Table/IcingaHostsMatchingFilterTable.php:48 +#: ../../../../application/forms/IcingaHostForm.php:41 msgid "Hostname" msgstr "Hostname" -#: library/Director/Import/ImportSourceRestApi.php:262 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:262 msgid "Hostname, IP or <host>:<port>" msgstr "Hostname, IP oder <host>:<port>" -#: configuration.php:153 -#: library/Director/Dashboard/Dashlet/HostsDashlet.php:11 -#: library/Director/IcingaConfig/StateFilterSet.php:19 -#: library/Director/DataType/DataTypeDirectorObject.php:56 -#: library/Director/DataType/DataTypeDictionary.php:59 -#: library/Director/Db/Branch/BranchModificationInspection.php:38 -#: library/Director/Import/ImportSourceCoreApi.php:60 -#: library/Director/Web/Table/CustomvarVariantsTable.php:58 -#: library/Director/Web/Table/CustomvarTable.php:43 -#: application/forms/IcingaNotificationForm.php:89 -#: application/forms/IcingaServiceForm.php:711 -#: application/forms/IcingaDependencyForm.php:100 -#: application/forms/IcingaScheduledDowntimeForm.php:89 +#: ../../../../configuration.php:121 +#: ../../../../library/Director/Dashboard/Dashlet/HostsDashlet.php:13 +#: ../../../../library/Director/IcingaConfig/StateFilterSet.php:19 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:56 +#: ../../../../library/Director/DataType/DataTypeDictionary.php:59 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:38 +#: ../../../../library/Director/Import/ImportSourceCoreApi.php:60 +#: ../../../../library/Director/Web/Table/CustomvarVariantsTable.php:58 +#: ../../../../library/Director/Web/Table/CustomvarTable.php:43 +#: ../../../../application/forms/IcingaNotificationForm.php:90 +#: ../../../../application/forms/IcingaServiceForm.php:715 +#: ../../../../application/forms/IcingaDependencyForm.php:100 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:89 msgid "Hosts" msgstr "Hosts" -#: application/controllers/ServicesetController.php:85 +#: ../../../../application/controllers/ServicesetController.php:85 #, php-format msgid "Hosts using this set: %s" msgstr "Hosts welche dieses Set benutzen: %s" -#: application/forms/IcingaScheduledDowntimeForm.php:58 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:58 msgid "" "How long the downtime lasts. Only has an effect for flexible (non-fixed) " "downtimes. Time in seconds, supported suffixes include ms (milliseconds), s " @@ -3036,19 +3042,19 @@ msgstr "" "(Millisekunden), s (Sekunden), m (Minuten), h (Stunden) and d (Tage). Um " "\"90 Minuten\" auszudrücken könnte man 1h 30m schreiben" -#: application/forms/DeployFormsBug7530.php:114 +#: ../../../../application/forms/DeployFormsBug7530.php:114 msgid "I know what I'm doing, deploy anyway" msgstr "Ich weiß was ich tue, bitte dennoch ausrollen" -#: application/forms/DeployFormsBug7530.php:115 +#: ../../../../application/forms/DeployFormsBug7530.php:115 msgid "I know, please don't bother me again" msgstr "Ich weiß, und möchte damit nicht mehr belästigt werden" -#: application/forms/IcingaEndpointForm.php:32 +#: ../../../../application/forms/IcingaEndpointForm.php:32 msgid "IP address / hostname of remote node" msgstr "IP Adresse / Hostname des entfernten Knoten" -#: application/forms/KickstartForm.php:133 +#: ../../../../application/forms/KickstartForm.php:133 msgid "" "IP address / hostname of your Icinga node. Please note that this information " "will only be used for the very first connection to your Icinga instance. The " @@ -3064,71 +3070,66 @@ msgstr "" "host-Eigenschaft entweder eine IP Adresse oder einen auflösbaren Hostname " "enthält. Der Director muss diesen Endpunkt erreichen können" -#: application/forms/IcingaHostForm.php:335 -#: application/forms/IcingaHostSelfServiceForm.php:43 +#: ../../../../application/forms/IcingaHostSelfServiceForm.php:43 +#: ../../../../application/forms/IcingaHostForm.php:337 msgid "IPv6 address" msgstr "IPv6 Adresse" -#: library/Director/Web/Controller/ObjectsController.php:350 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:350 #, php-format msgid "Icinga %s Sets" msgstr "Icinga %s-Sets" -#: application/controllers/InspectController.php:38 +#: ../../../../application/controllers/InspectController.php:38 #, php-format msgid "Icinga 2 - Objects: %s" msgstr "Icinga-2-Objekte: %s" -#: application/controllers/InspectController.php:144 +#: ../../../../application/controllers/InspectController.php:144 msgid "Icinga 2 API - Status" msgstr "Icinga 2 API - Status" -#: library/Director/Web/SelfService.php:216 +#: ../../../../library/Director/Web/SelfService.php:203 msgid "Icinga 2 Client documentation" msgstr "Icinga 2 Client-Dokumentation" -#: library/Director/Web/SelfService.php:158 -#: library/Director/Web/SelfService.php:164 -msgid "Icinga 2 Powershell Module" -msgstr "Icinga 2 Powershell Modul" - -#: application/forms/IcingaHostForm.php:147 -#: application/forms/IcingaServiceForm.php:697 +#: ../../../../application/forms/IcingaServiceForm.php:701 +#: ../../../../application/forms/IcingaHostForm.php:149 msgid "Icinga Agent and zone settings" msgstr "Icinga Agenten- und Zoneneinstellungen" -#: library/Director/Dashboard/Dashlet/ApiUserObjectDashlet.php:13 +#: ../../../../library/Director/Dashboard/Dashlet/ApiUserObjectDashlet.php:15 msgid "Icinga Api users" msgstr "Icinga API Benutzer" -#: application/forms/IcingaCommandArgumentForm.php:39 -#: application/forms/IcingaCommandArgumentForm.php:78 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:39 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:78 msgid "Icinga DSL" msgstr "Icinga-DSL" -#: configuration.php:118 +#: ../../../../configuration.php:89 msgid "Icinga Director" msgstr "Icinga-Director" -#: application/controllers/DashboardController.php:45 +#: ../../../../application/controllers/DashboardController.php:45 msgid "Icinga Director - Main Dashboard" msgstr "Icinga Director - Übersichtsdashboard" -#: application/controllers/DaemonController.php:46 +#: ../../../../application/controllers/DaemonController.php:46 msgid "Icinga Director Background Daemon" msgstr "Icinga Director Hintergrunddienst" -#: library/Director/Dashboard/DirectorDashboard.php:15 +#: ../../../../library/Director/Dashboard/DirectorDashboard.php:15 msgid "Icinga Director Configuration" msgstr "Icinga Director Konfiguration" -#: application/controllers/IndexController.php:45 -#: application/controllers/IndexController.php:52 +#: ../../../../application/controllers/IndexController.php:45 +#: ../../../../application/controllers/IndexController.php:52 #, php-format msgid "Icinga Director Setup: %s" msgstr "Icinga Director Setup: %s" -#: application/forms/SettingsForm.php:35 +#: ../../../../application/forms/SettingsForm.php:35 msgid "" "Icinga Director decides to deploy objects like CheckCommands to a global " "zone. This defaults to \"director-global\" but might be adjusted to a custom " @@ -3138,7 +3139,7 @@ msgstr "" "auszubringen. Der Standard dafür ist \"director-global\", es kann aber auch " "eine benutzerdefinierte Zone verwendet werden" -#: application/controllers/PhperrorController.php:40 +#: ../../../../application/controllers/PhperrorController.php:40 msgid "" "Icinga Director depends on the following modules, please install/upgrade as " "required" @@ -3146,7 +3147,7 @@ msgstr "" "Der Icinga Director benötigt folgende Module, bitte wie angegeben " "installieren und/oder aktualisieren" -#: library/Director/Dashboard/Dashlet/SelfServiceDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/SelfServiceDashlet.php:19 msgid "" "Icinga Director offers a Self Service API, allowing new Icinga nodes to " "register themselves" @@ -3154,19 +3155,19 @@ msgstr "" "Der Icinga Director stellt eine Selbstbedienungs-API bereit, über welche " "sich neue Icinga-Knoten selbst registrieren können" -#: application/forms/KickstartForm.php:131 +#: ../../../../application/forms/KickstartForm.php:131 msgid "Icinga Host" msgstr "Icinga-Host" -#: library/Director/Dashboard/Dashlet/InfrastructureDashlet.php:11 +#: ../../../../library/Director/Dashboard/Dashlet/InfrastructureDashlet.php:13 msgid "Icinga Infrastructure" msgstr "Icinga-Infrastruktur" -#: application/forms/SettingsForm.php:43 +#: ../../../../application/forms/SettingsForm.php:43 msgid "Icinga Package Name" msgstr "Icinga Package Name" -#: library/Director/Web/Form/DirectorObjectForm.php:1164 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1167 msgid "" "Icinga cluster zone. Allows to manually override Directors decisions of " "where to deploy your config to. You should consider not doing so unless you " @@ -3176,16 +3177,16 @@ msgstr "" "wohin der Director die Konfiguration ausrollt. Sollte nicht ohne " "ausreichendes Wissen um den Icinga-Cluster-Stack verändert werden" -#: library/Director/Web/SelfService.php:145 -#: library/Director/Web/SelfService.php:151 +#: ../../../../library/Director/Web/SelfService.php:145 +#: ../../../../library/Director/Web/SelfService.php:151 msgid "Icinga for Windows" msgstr "Icinga für Windows" -#: application/forms/IcingaHostGroupForm.php:16 +#: ../../../../application/forms/IcingaHostGroupForm.php:16 msgid "Icinga object name for this host group" msgstr "Icinga-Objektname für diese Hostgruppe" -#: application/forms/IcingaHostForm.php:46 +#: ../../../../application/forms/IcingaHostForm.php:48 msgid "" "Icinga object name for this host. This is usually a fully qualified host " "name but it could basically be any kind of string. To make things easier for " @@ -3197,19 +3198,19 @@ msgstr "" "sprechende Namen für Vorlagen verwendet werden. z.B. ist \"Standard Linux " "Server\" leichter verständlich als \"generic-host\"" -#: application/forms/IcingaServiceGroupForm.php:16 +#: ../../../../application/forms/IcingaServiceGroupForm.php:16 msgid "Icinga object name for this service group" msgstr "Icinga-Objektname für diese Servicegruppe" -#: application/forms/IcingaUserGroupForm.php:19 +#: ../../../../application/forms/IcingaUserGroupForm.php:19 msgid "Icinga object name for this user group" msgstr "Icinga-Objektname für diese Benutzergruppe" -#: application/forms/SettingsForm.php:126 +#: ../../../../application/forms/SettingsForm.php:126 msgid "Icinga v1.x" msgstr "Icinga v1.x" -#: application/forms/SettingsForm.php:100 +#: ../../../../application/forms/SettingsForm.php:100 msgid "" "Icinga v2.11.0 breaks some configurations, the Director will warn you before " "every deployment in case your config is affected. This setting allows to " @@ -3219,97 +3220,131 @@ msgstr "" "warnt vor jedem Deployment falls die auszurollende Konfiguration betroffen " "ist. Diese Einstellung erlaubt es diese Warnung zu verbergen." -#: application/forms/SettingsForm.php:125 +#: ../../../../application/forms/SettingsForm.php:125 msgid "Icinga v2.x" msgstr "Icinga v2.x" -#: application/forms/IcingaHostForm.php:77 +#: ../../../../application/forms/IcingaHostForm.php:79 msgid "Icinga2 Agent" msgstr "Icinga-2-Agent" -#: library/Director/Web/Form/DirectorObjectForm.php:1556 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1559 msgid "Icon image" msgstr "Icon Bild" -#: library/Director/Web/Form/DirectorObjectForm.php:1565 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1568 msgid "Icon image alt" msgstr "Icon Bild alternativ" -#: library/Director/Web/Table/CoreApiFieldsTable.php:81 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:81 msgid "Id" msgstr "ID" -#: application/forms/IcingaCommandForm.php:52 +#: ../../../../application/forms/IcingaCommandForm.php:52 msgid "Identifier for the Icinga command you are going to create" msgstr "Bezeichner für das Icinga-Kommando, das erstellt werden soll" -#: application/forms/IcingaCommandForm.php:78 +#: ../../../../application/forms/IcingaNotificationForm.php:181 +msgid "" +"If defined, User Groups from this Custom Variable will be combined with " +"single Groups chosen below. e.g.: when set to notification_groups, this " +"notification will pick User Groups from the Array service.vars." +"notification_groups and fall back to host.vars.notification_groups, in case " +"the former one does not exist. Only Array type DirectorObject Fields for " +"User objects are eligible for this feature." +msgstr "" +"Wenn diese benutzerdefinierte Variable vorhanden ist, werden Benutzergruppen " +"aus selbiger mit nachfolgend ausgewählten Einzelgruppen kombiniert. " +"Beispiel: wird hier notification_groups gewählt, wird diese Benachrichtigung " +"Benutzergruppen aus dem Array service. vars.notification_groups verwenden, " +"und auf host.vars.notification_groups zurückfallen, falls ersteres nicht " +"existiert. Lediglich Felder vom Array-Typ DirectorObject sind für dieses " +"Feature auswählbar." + +#: ../../../../application/forms/IcingaNotificationForm.php:144 +msgid "" +"If defined, Users from this Custom Variable will be combined with single " +"users chosen below. e.g.: when set to notification_contacts, this " +"notification will pick Users from the Array service.vars." +"notification_contacts and fall back to host.vars.notification_contacts, in " +"case the former one does not exist. Only Array type DirectorObject Fields " +"for User objects are eligible for this feature." +msgstr "" +"Wenn diese benutzerdefinierte Variable vorhanden ist, werden Benutzer aus " +"selbiger mit nachfolgend ausgewählten Einzelbenutzern kombiniert. Beispiel: " +"wird hier notification_contacts gewählt, wird diese Benachrichtigung " +"Benutzergruppen aus dem Array service. vars.notification_contacts verwenden, " +"und auf host.vars.notification_contacts zurückfallen, falls ersteres nicht " +"existiert. Lediglich Felder vom Array-Typ DirectorObject sind für dieses " +"Feature auswählbar." + +#: ../../../../application/forms/IcingaCommandForm.php:78 msgid "If enabled you can not define arguments." msgstr "Wenn aktiviert können keine Argumente definiert werden." -#: application/forms/SyncRuleForm.php:64 -#: application/forms/BasketForm.php:55 +#: ../../../../application/forms/BasketForm.php:55 +#: ../../../../application/forms/SyncRuleForm.php:64 msgid "Ignore" msgstr "Ignorieren" -#: application/forms/SettingsForm.php:91 +#: ../../../../application/forms/SettingsForm.php:91 msgid "Ignore Bug #7530" msgstr "Bug #7530 ignorieren" -#: application/forms/IcingaDependencyForm.php:175 +#: ../../../../application/forms/IcingaDependencyForm.php:175 msgid "Ignore Soft States" msgstr "Soft-States ignorieren" -#: library/Director/PropertyModifier/PropertyModifierGetPropertyFromOtherImportSource.php:33 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetPropertyFromOtherImportSource.php:33 msgid "Import Source" msgstr "Importquelle" -#: application/forms/BasketForm.php:35 +#: ../../../../application/forms/BasketForm.php:35 msgid "Import Sources" msgstr "Importquellen" -#: library/Director/Dashboard/Dashlet/ImportSourceDashlet.php:14 +#: ../../../../library/Director/Dashboard/Dashlet/ImportSourceDashlet.php:15 msgid "Import data sources" msgstr "Import-Datenquellen" -#: application/forms/IcingaImportObjectForm.php:26 +#: ../../../../application/forms/IcingaImportObjectForm.php:26 #, php-format msgid "Import external \"%s\"" msgstr "Externe \"%s\" importieren" -#: application/controllers/ImportrunController.php:14 -#: application/controllers/ImportrunController.php:15 +#: ../../../../application/controllers/ImportrunController.php:14 +#: ../../../../application/controllers/ImportrunController.php:15 msgid "Import run" msgstr "Importlauf" -#: application/controllers/ImportsourceController.php:266 +#: ../../../../application/controllers/ImportsourceController.php:266 #, php-format msgid "Import run history: %s" msgstr "Importlaufhistorie: %s" -#: library/Director/Job/ImportJob.php:80 -#: library/Director/Web/Tabs/ImportsourceTabs.php:37 -#: library/Director/Web/Tabs/ImportTabs.php:20 -#: application/controllers/ImportsourcesController.php:32 +#: ../../../../library/Director/Job/ImportJob.php:80 +#: ../../../../library/Director/Web/Tabs/ImportsourceTabs.php:37 +#: ../../../../library/Director/Web/Tabs/ImportTabs.php:20 +#: ../../../../application/controllers/ImportsourcesController.php:32 msgid "Import source" msgstr "Importquelle" -#: application/forms/ImportSourceForm.php:15 +#: ../../../../application/forms/ImportSourceForm.php:15 msgid "Import source name" msgstr "Name der Importquelle" -#: application/controllers/ImportsourceController.php:170 +#: ../../../../application/controllers/ImportsourceController.php:170 #, php-format msgid "Import source preview: %s" msgstr "Vorschau der Importquelle: %s" -#: application/controllers/ImportsourceController.php:92 -#: application/controllers/ImportsourceController.php:135 +#: ../../../../application/controllers/ImportsourceController.php:92 +#: ../../../../application/controllers/ImportsourceController.php:135 #, php-format msgid "Import source: %s" msgstr "Importquelle: %s" -#: library/Director/Web/Form/DirectorObjectForm.php:1270 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1273 msgid "" "Importable templates, add as many as you want. Please note that order " "matters when importing properties from multiple templates: last one wins" @@ -3318,15 +3353,15 @@ msgstr "" "Reihenfolge wichtig ist, wenn Eigenschaften von mehreren Vorlagen geerbt " "werden: Der letzte Eintrag gewinnt" -#: application/forms/ImportRunForm.php:33 +#: ../../../../application/forms/ImportRunForm.php:33 msgid "Imported new data from this Import Source" msgstr "Neue Daten von dieser Import-Datenquelle importiert" -#: library/Director/Web/Table/ImportrunTable.php:32 +#: ../../../../library/Director/Web/Table/ImportrunTable.php:32 msgid "Imported rows" msgstr "Importierte Reihen" -#: application/forms/IcingaImportObjectForm.php:16 +#: ../../../../application/forms/IcingaImportObjectForm.php:16 msgid "" "Importing an object means that its type will change from \"external\" to " "\"object\". That way it will make part of the next deployment. So in case " @@ -3341,11 +3376,11 @@ msgstr "" "Konfiguration entfernt werden. Sollte ein Konflikt auftreten, geschieht " "nichts weiter, als dass die Konfiguration nicht ausgerollt werden kann." -#: library/Director/Web/Form/DirectorObjectForm.php:1268 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1271 msgid "Imports" msgstr "Importe" -#: application/controllers/SelfServiceController.php:110 +#: ../../../../application/controllers/SelfServiceController.php:110 msgid "" "In case an Icinga Admin provided you with a self service API token, this is " "where you can register new hosts" @@ -3353,7 +3388,7 @@ msgstr "" "Wenn ein Icinga-Administrator einen Selbstbedienungs-API-" "Schlüsselbereitstellt, können hier neue Hosts registriert werden" -#: application/forms/SelfServiceSettingsForm.php:189 +#: ../../../../application/forms/SelfServiceSettingsForm.php:189 msgid "" "In case the Icinga 2 Agent is already installed on the system, this " "parameter will allow you to configure if you wish to upgrade / downgrade to " @@ -3363,7 +3398,7 @@ msgstr "" "dieser Parameter festzulegen, ob auch Up- und Downgrades zu der spezifierten " "Icinga 2 Version gewünscht sind." -#: application/forms/SelfServiceSettingsForm.php:156 +#: ../../../../application/forms/SelfServiceSettingsForm.php:156 msgid "" "In case the Icinga 2 Agent should be automatically installed, this has to be " "a string value like: 2.6.3" @@ -3371,7 +3406,7 @@ msgstr "" "Falls der Icinga-2-Agent automatisch installiert werden soll, muss dies in " "String der Form 2.6.3 sein" -#: application/forms/SelfServiceSettingsForm.php:102 +#: ../../../../application/forms/SelfServiceSettingsForm.php:102 msgid "" "In case the Icinga Agent will accept configuration from the parent Icinga 2 " "system, it will possibly write data to /var/lib/icinga2/api/*. By setting " @@ -3383,17 +3418,12 @@ msgstr "" "schreiben. Wird dieser Schalter auf Ja gesetzt, wird jeglicher Inhalt dieses " "Verzeichnisses vor einem eventuellen Restart des Icinga-2-Agenten geleert" -#: library/Director/Web/SelfService.php:147 +#: ../../../../library/Director/Web/SelfService.php:147 #, php-format msgid "In case you're using %s, please run this Script:" msgstr "Falls %s benutzt wird, bitte dieses Script ausführen:" -#: library/Director/Web/SelfService.php:160 -#, php-format -msgid "In case you're using the legacy %s, please run:" -msgstr "Falls das vorherige %s benutzt wird, bitte dieses Script ausführen:" - -#: library/Director/Import/ImportSourceRestApi.php:246 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:246 msgid "" "In case your API is only reachable through a proxy, please choose it's " "protocol right here" @@ -3401,100 +3431,100 @@ msgstr "" "Wenn die API nur über einen Proxy zugänglich ist, bitte hier dessen " "Protokoll auswählen" -#: library/Director/Import/ImportSourceRestApi.php:270 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:270 msgid "In case your proxy requires authentication, please configure this here" msgstr "" "Falls der Proxy eine Authentifizierung verlangt, kann diese hier " "konfiguriert werden" -#: application/forms/IcingaTimePeriodForm.php:62 +#: ../../../../application/forms/IcingaTimePeriodForm.php:62 msgid "Include other time periods into this." msgstr "Andere Zeiträume in diesen einbinden." -#: application/forms/IcingaTimePeriodForm.php:59 +#: ../../../../application/forms/IcingaTimePeriodForm.php:59 msgid "Include period" msgstr "Zeitraum einbinden" -#: library/Director/Web/Table/TemplateUsageTable.php:56 +#: ../../../../library/Director/Web/Table/TemplateUsageTable.php:56 msgid "Indirect" msgstr "Indirekt" -#: application/controllers/HostController.php:214 -#: application/controllers/HostController.php:295 +#: ../../../../application/controllers/HostController.php:198 +#: ../../../../application/controllers/HostController.php:282 msgid "Individual Service objects" msgstr "Individuelle Service-Objekte" -#: library/Director/Web/Tabs/InfraTabs.php:43 +#: ../../../../library/Director/Web/Tabs/InfraTabs.php:44 msgid "Infrastructure" msgstr "Infrastruktur" -#: application/forms/SyncPropertyForm.php:312 +#: ../../../../application/forms/SyncPropertyForm.php:312 msgid "Inheritance (import)" msgstr "Vererbung (Import)" -#: library/Director/Web/SelfService.php:195 +#: ../../../../library/Director/Web/SelfService.php:182 msgid "Inherited Template Api Key:" msgstr "Vom Template geerbter API-Schlüssel:" -#: application/controllers/HostController.php:232 +#: ../../../../application/controllers/HostController.php:219 #, php-format msgid "Inherited from %s" msgstr "Geerbt von %s" -#: application/forms/IcingaHostForm.php:256 +#: ../../../../application/forms/IcingaHostForm.php:258 msgid "Inherited groups" msgstr "Geerbte Gruppen" -#: application/controllers/HostController.php:461 +#: ../../../../application/controllers/HostController.php:446 #, php-format msgid "Inherited service: %s" msgstr "Geerbter Service: %s" -#: library/Director/ProvidedHook/Monitoring/HostActions.php:36 -#: library/Director/ProvidedHook/Monitoring/ServiceActions.php:43 -#: library/Director/Web/Tabs/ObjectTabs.php:132 -#: application/controllers/HostController.php:621 +#: ../../../../library/Director/ProvidedHook/Monitoring/HostActions.php:37 +#: ../../../../library/Director/ProvidedHook/Monitoring/ServiceActions.php:44 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:129 +#: ../../../../application/controllers/HostController.php:592 msgid "Inspect" msgstr "Inspizieren" -#: application/controllers/InspectController.php:63 +#: ../../../../application/controllers/InspectController.php:63 msgid "Inspect - object list" msgstr "Inspizieren - Objektliste" -#: application/controllers/InspectController.php:170 +#: ../../../../application/controllers/InspectController.php:170 msgid "Inspect File Content" msgstr "Dateiinhalt inspizieren" -#: application/controllers/InspectController.php:168 +#: ../../../../application/controllers/InspectController.php:168 msgid "Inspect Packages" msgstr "Pakete Inspizieren" -#: application/forms/SelfServiceSettingsForm.php:202 +#: ../../../../application/forms/SelfServiceSettingsForm.php:202 msgid "Install NSClient++" msgstr "NSClient++ installieren" -#: application/forms/SelfServiceSettingsForm.php:72 +#: ../../../../application/forms/SelfServiceSettingsForm.php:72 msgid "Installation Source" msgstr "Installationsquelle" -#: library/Director/Web/Table/Dependency/DependencyInfoTable.php:39 +#: ../../../../library/Director/Web/Table/Dependency/DependencyInfoTable.php:39 msgid "Installed" msgstr "Installiert" -#: application/forms/SelfServiceSettingsForm.php:165 +#: ../../../../application/forms/SelfServiceSettingsForm.php:165 msgid "Installer Hashes" msgstr "Prüfsummen für den Installer" -#: application/forms/IcingaCommandForm.php:25 +#: ../../../../application/forms/IcingaCommandForm.php:25 msgid "Internal commands" msgstr "Interne Kommandos" -#: application/controllers/SyncruleController.php:140 +#: ../../../../application/controllers/SyncruleController.php:140 #, php-format msgid "It has been renamed since then, its former name was %s" msgstr "Es wurde seither umbenannt. Sein bisheriger Name war %s" -#: library/Director/Web/SelfService.php:72 +#: ../../../../library/Director/Web/SelfService.php:72 msgid "" "It is not a good idea to do so as long as your Agent still has a valid Self " "Service API key!" @@ -3502,7 +3532,7 @@ msgstr "" "Dies ist keine gute Idee solange der Agent noch über einen gültigen " "Selbstbedienungs-API-Schlüssel verfügt!" -#: application/forms/IcingaTemplateChoiceForm.php:87 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:87 msgid "" "It will not be allowed to choose more than this many options. Setting it to " "one (1) will result in a drop-down box, a higher number will turn this into " @@ -3512,7 +3542,7 @@ msgstr "" "vorgegeben wird. Setzt man sie auf Eins (1) erhält man ein Dropdown-Feld, " "eine höhere Nummer verwandelt diese in ein Mehrfach-Auswahlfeld." -#: library/Director/Web/Widget/ImportSourceDetails.php:35 +#: ../../../../library/Director/Web/Widget/ImportSourceDetails.php:35 msgid "" "It's currently unknown whether we are in sync with this Import Source. You " "should either check for changes or trigger a new Import Run." @@ -3521,7 +3551,7 @@ msgstr "" "ist. Es sollte auf Änderungen geprüft oder ein neuer Importlauf angestoßen " "werden." -#: application/controllers/SyncruleController.php:91 +#: ../../../../application/controllers/SyncruleController.php:91 msgid "" "It's currently unknown whether we are in sync with this rule. You should " "either check for changes or trigger a new Sync Run." @@ -3529,153 +3559,157 @@ msgstr "" "Aktuell ist unbekannt, ob die Konfiguration mit dieser Regel synchron ist. " "Es sollte auf Änderungen geprüft oder ein neuer Importlauf angestoßen werden." -#: application/forms/BasketUploadForm.php:130 -#: application/forms/BasketForm.php:126 +#: ../../../../application/forms/BasketForm.php:126 +#: ../../../../application/forms/BasketUploadForm.php:122 msgid "It's not allowed to store an empty basket" msgstr "Das Speichern eines leeren Baskets ist nicht erlaubt" -#: application/controllers/JobController.php:108 +#: ../../../../application/controllers/JobController.php:108 msgid "Job" msgstr "Auftrag" -#: application/forms/BasketForm.php:37 +#: ../../../../application/forms/BasketForm.php:37 msgid "Job Definitions" msgstr "Job-Definitionen" -#: application/forms/DirectorJobForm.php:17 +#: ../../../../application/forms/DirectorJobForm.php:17 msgid "Job Type" msgstr "Auftragstyp" -#: library/Director/Web/Table/JobTable.php:60 -#: application/forms/DirectorJobForm.php:72 +#: ../../../../library/Director/Web/Table/JobTable.php:60 +#: ../../../../application/forms/DirectorJobForm.php:72 msgid "Job name" msgstr "Auftragsname" -#: application/controllers/JobController.php:26 -#: application/controllers/JobController.php:57 +#: ../../../../application/controllers/JobController.php:26 +#: ../../../../application/controllers/JobController.php:57 #, php-format msgid "Job: %s" msgstr "Auftrag: %s" -#: library/Director/Dashboard/Dashlet/JobDashlet.php:14 -#: library/Director/Web/Tabs/ImportTabs.php:26 -#: application/controllers/JobsController.php:13 +#: ../../../../library/Director/Dashboard/Dashlet/JobDashlet.php:15 +#: ../../../../library/Director/Web/Tabs/ImportTabs.php:26 +#: ../../../../application/controllers/JobsController.php:13 msgid "Jobs" msgstr "Aufträge" -#: library/Director/Web/Table/BranchActivityTable.php:70 -#: library/Director/Web/Table/ActivityLogTable.php:220 +#: ../../../../library/Director/Web/Table/ActivityLogTable.php:221 +#: ../../../../library/Director/Web/Table/BranchActivityTable.php:71 msgid "Jump to this object" msgstr "Zu diesem Objekt springen" -#: library/Director/Web/SelfService.php:267 +#: ../../../../library/Director/Web/SelfService.php:255 msgid "Just download and run this script on your Linux Client Machine:" msgstr "" "Einfach dieses Skript herunterladen und auf dem Linux Client-Rechner " "ausführen:" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:57 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:57 msgid "Keep matching elements" msgstr "Übereinstimmende Elemente behalten" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:73 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:73 msgid "Keep only matching rows" msgstr "Behalte nur passende Zeilen" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:31 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:31 msgid "Keep the DN as is" msgstr "DN unverändert behalten" -#: library/Director/PropertyModifier/PropertyModifierJsonDecode.php:26 +#: ../../../../library/Director/PropertyModifier/PropertyModifierJsonDecode.php:26 msgid "Keep the JSON string as is" msgstr "JSON-String beibehalten" -#: library/Director/PropertyModifier/PropertyModifierListToObject.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierListToObject.php:27 msgid "Keep the first row with that key" msgstr "Behalte die erste Zeile mit diesem Schlüssel" -#: library/Director/PropertyModifier/PropertyModifierListToObject.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:33 +msgid "Keep the given string" +msgstr "Bestehenden String behalten" + +#: ../../../../library/Director/PropertyModifier/PropertyModifierListToObject.php:28 msgid "Keep the last row with that key" msgstr "Behalte die letzte Zeile mit diesem Schlüssel" -#: library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:18 -#: library/Director/PropertyModifier/PropertyModifierGetHostByName.php:18 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:18 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByName.php:18 msgid "Keep the property (hostname) as is" msgstr "Die Eigenschaft (hostname) behalten, wie sie ist" -#: library/Director/PropertyModifier/PropertyModifierParseURL.php:40 -#: library/Director/PropertyModifier/PropertyModifierDnsRecords.php:35 +#: ../../../../library/Director/PropertyModifier/PropertyModifierParseURL.php:40 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDnsRecords.php:35 msgid "Keep the property as is" msgstr "Die Eigenschaft beibehalten" -#: library/Director/PropertyModifier/PropertyModifierArrayToRow.php:25 -#: library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:32 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:32 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayToRow.php:25 msgid "Keep the row, set the column value to null" msgstr "Behalte die Zeile so wie sie ist, setze den Spaltenwert auf null" -#: library/Director/Web/Table/DatalistEntryTable.php:54 -#: application/forms/DirectorDatalistEntryForm.php:21 +#: ../../../../library/Director/Web/Table/DatalistEntryTable.php:54 +#: ../../../../application/forms/DirectorDatalistEntryForm.php:21 msgid "Key" msgstr "Schlüssel" -#: application/controllers/DataController.php:327 +#: ../../../../application/controllers/DataController.php:327 msgid "Key / Instance" msgstr "Schlüssel / Instanz" -#: library/Director/PropertyModifier/PropertyModifierListToObject.php:15 +#: ../../../../library/Director/PropertyModifier/PropertyModifierListToObject.php:15 msgid "Key Property" msgstr "Schlüsseleigenschaft" -#: library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:21 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:21 msgid "Key Property Name" msgstr "Schlüsseleigenschaft" -#: application/forms/ImportSourceForm.php:87 +#: ../../../../application/forms/ImportSourceForm.php:87 msgid "Key column name" msgstr "Schlüsselspaltenname" -#: application/controllers/KickstartController.php:15 -#: application/controllers/KickstartController.php:17 +#: ../../../../application/controllers/KickstartController.php:15 +#: ../../../../application/controllers/KickstartController.php:17 msgid "Kickstart" msgstr "Kickstart" -#: library/Director/Dashboard/Dashlet/KickstartDashlet.php:11 -#: application/forms/KickstartForm.php:292 +#: ../../../../library/Director/Dashboard/Dashlet/KickstartDashlet.php:13 +#: ../../../../application/forms/KickstartForm.php:292 msgid "Kickstart Wizard" msgstr "Kickstart Assistent" -#: library/Director/Import/ImportSourceLdap.php:50 +#: ../../../../library/Director/Import/ImportSourceLdap.php:50 msgid "LDAP Search Base" msgstr "LDAP Suchbasis" -#: library/Director/Web/Table/DatalistEntryTable.php:55 -#: library/Director/Web/Table/IcingaObjectDatafieldTable.php:49 -#: library/Director/Web/Table/DatafieldTable.php:49 -#: application/forms/DirectorDatalistEntryForm.php:30 +#: ../../../../library/Director/Web/Table/DatalistEntryTable.php:55 +#: ../../../../library/Director/Web/Table/IcingaObjectDatafieldTable.php:49 +#: ../../../../library/Director/Web/Table/DatafieldTable.php:51 +#: ../../../../application/forms/DirectorDatalistEntryForm.php:30 msgid "Label" msgstr "Bezeichnung" -#: library/Director/Web/Widget/IcingaObjectInspection.php:58 +#: ../../../../library/Director/Web/Widget/IcingaObjectInspection.php:58 msgid "Last Check Result" msgstr "Letztes Check-Ergebnis" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:34 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:34 msgid "Last Element" msgstr "Letztes Element" -#: application/forms/IcingaNotificationForm.php:208 +#: ../../../../application/forms/IcingaNotificationForm.php:256 msgid "Last notification" msgstr "Letzte Benachrichtigung" -#: library/Director/Web/Widget/DeployedConfigInfoHeader.php:77 +#: ../../../../library/Director/Web/Widget/DeployedConfigInfoHeader.php:77 msgid "Last related activity" msgstr "Zuletzt verwendete Konfiguration" -#: application/controllers/SyncruleController.php:136 +#: ../../../../application/controllers/SyncruleController.php:136 msgid "Last sync run details" msgstr "Details des letzten Imports" -#: application/forms/IcingaCommandArgumentForm.php:69 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:69 msgid "" "Leave empty for non-positional arguments. Can be a positive or negative " "number and influences argument ordering" @@ -3683,7 +3717,7 @@ msgstr "" "Leer lassen für Argumente, deren Position egal ist. Kann eine positive oder " "negative Zahl sein und beeinflusst die Reihenfolge der Argumente" -#: application/forms/DirectorDatafieldForm.php:44 +#: ../../../../application/forms/DirectorDatafieldForm.php:44 msgid "" "Leaving custom variables in place while removing the related field is " "perfectly legal and might be a desired operation. This way you can no longer " @@ -3700,7 +3734,7 @@ msgstr "" "demselben Namen zu einem späteren Zeitpunkt wieder hinzufügt, wird alles " "wieder funktionieren wie zuvor" -#: application/forms/DirectorDatafieldForm.php:87 +#: ../../../../application/forms/DirectorDatafieldForm.php:87 msgid "" "Leaving custom variables in place while renaming the related field is " "perfectly legal and might be a desired operation. This way you can no longer " @@ -3717,54 +3751,55 @@ msgstr "" "demselben Namen zu einem späteren Zeitpunkt wieder hinzufügt, wird alles " "wieder funktionieren wie zuvor" -#: library/Director/PropertyModifier/PropertyModifierMap.php:35 -#: library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:45 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMap.php:37 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:45 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSetValue.php:34 msgid "Let the import fail" msgstr "Import fehlschlagen lassen" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:55 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:55 msgid "Let the whole Import Run fail" msgstr "Den ganzen Importlauf fehlschlagen lassen" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:32 -#: library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:19 -#: library/Director/PropertyModifier/PropertyModifierListToObject.php:26 -#: library/Director/PropertyModifier/PropertyModifierParseURL.php:41 -#: library/Director/PropertyModifier/PropertyModifierJsonDecode.php:27 -#: library/Director/PropertyModifier/PropertyModifierArrayToRow.php:24 -#: library/Director/PropertyModifier/PropertyModifierDnsRecords.php:36 -#: library/Director/PropertyModifier/PropertyModifierGetHostByName.php:19 -#: library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:31 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:32 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:31 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:19 +#: ../../../../library/Director/PropertyModifier/PropertyModifierListToObject.php:26 +#: ../../../../library/Director/PropertyModifier/PropertyModifierParseURL.php:41 +#: ../../../../library/Director/PropertyModifier/PropertyModifierJsonDecode.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayToRow.php:24 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDnsRecords.php:36 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByName.php:19 msgid "Let the whole import run fail" msgstr "Den ganzen Importlauf fehlschlagen lassen" -#: configuration.php:54 +#: ../../../../configuration.php:51 msgid "Limit access to the given comma-separated list of hostgroups" msgstr "" "Den Zugriff auf diese Kommagetrennte Liste von Host-Gruppen beschränken" -#: library/Director/Web/SelfService.php:260 +#: ../../../../library/Director/Web/SelfService.php:247 msgid "Linux commandline" msgstr "Linux Kommandozeile" -#: application/controllers/DataController.php:125 +#: ../../../../application/controllers/DataController.php:125 msgid "List Entries" msgstr "Listeneinträge" -#: application/controllers/DataController.php:401 +#: ../../../../application/controllers/DataController.php:401 msgid "List entries" msgstr "Listeneinträge" -#: library/Director/Web/Table/DatalistTable.php:31 -#: application/forms/DirectorDatalistForm.php:13 +#: ../../../../library/Director/Web/Table/DatalistTable.php:31 +#: ../../../../application/forms/DirectorDatalistForm.php:13 msgid "List name" msgstr "Listenname" -#: library/Director/Import/ImportSourceRestApi.php:213 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:213 msgid "Literal dots in a key name can be written in the escape notation:" msgstr "Punkte im Schlüsselbezeichner können bei Bedarf verschont werden:" -#: application/forms/SettingsForm.php:167 +#: ../../../../application/forms/SettingsForm.php:167 msgid "" "Local directory to deploy Icinga 1.x configuration. Must be writable by " "icingaweb2. (e.g. /etc/icinga/director)" @@ -3773,16 +3808,16 @@ msgstr "" "werden soll. Muss von icingaweb2 beschreibbar sein (z.B. /etc/icinga/" "director)" -#: application/forms/IcingaEndpointForm.php:41 +#: ../../../../application/forms/IcingaEndpointForm.php:41 msgid "Log Duration" msgstr "Behaltefrist des Logs" -#: library/Director/Web/Form/DirectorObjectForm.php:576 -#: application/forms/IcingaAddServiceForm.php:67 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:579 +#: ../../../../application/forms/IcingaAddServiceForm.php:68 msgid "Main properties" msgstr "Haupteigenschaften" -#: library/Director/Dashboard/Dashlet/CheckCommandsDashlet.php:12 +#: ../../../../library/Director/Dashboard/Dashlet/CheckCommandsDashlet.php:14 msgid "" "Manage definitions for your Commands that should be executed as Check " "Plugins, Notifications or based on Events" @@ -3790,7 +3825,7 @@ msgstr "" "Definitionen für Kommandos verwalten, welche als Check-Plugins " "Benachrichtigungen oder Event-basiert ausgeführt werden sollen" -#: library/Director/Dashboard/Dashlet/HostTemplatesDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/HostTemplatesDashlet.php:19 msgid "" "Manage your Host Templates. Use Fields to make it easy for your users to get " "them customized." @@ -3798,28 +3833,28 @@ msgstr "" "Host-Vorlagen verwalten. Verwende Felder um Benutzern deren Anpassung zu " "erleichtern." -#: library/Director/Dashboard/Dashlet/InfrastructureDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/InfrastructureDashlet.php:19 msgid "" "Manage your Icinga 2 infrastructure: Masters, Zones, Satellites and more" msgstr "Icinga 2 Infrastruktur verwalten: Master, Zonen, Satelliten und mehr" -#: library/Director/Dashboard/CommandsDashboard.php:17 +#: ../../../../library/Director/Dashboard/CommandsDashboard.php:17 msgid "Manage your Icinga Commands" msgstr "Icinga Kommandos verwalten" -#: library/Director/Dashboard/HostsDashboard.php:16 +#: ../../../../library/Director/Dashboard/HostsDashboard.php:16 msgid "Manage your Icinga Hosts" msgstr "Icinga Hosts verwalten" -#: library/Director/Dashboard/InfrastructureDashboard.php:24 +#: ../../../../library/Director/Dashboard/InfrastructureDashboard.php:24 msgid "Manage your Icinga Infrastructure" msgstr "Icinga 2 Infrastruktur verwalten" -#: library/Director/Dashboard/ServicesDashboard.php:18 +#: ../../../../library/Director/Dashboard/ServicesDashboard.php:18 msgid "Manage your Icinga Service Checks" msgstr "Icinga Service Checks verwalten" -#: library/Director/Dashboard/Dashlet/ServiceTemplatesDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceTemplatesDashlet.php:19 msgid "" "Manage your Service Templates. Use Fields to make it easy for your users to " "get them customized." @@ -3827,56 +3862,56 @@ msgstr "" "Service-Vorlagen verwalten. Verwende Felder um Benutzern deren Anpassung zu " "erleichtern." -#: library/Director/Web/Controller/ObjectController.php:254 +#: ../../../../library/Director/Web/Controller/ObjectController.php:257 msgid "Managing Fields" msgstr "Datenfelder verwalten" -#: library/Director/Web/Table/IcingaObjectDatafieldTable.php:51 -#: application/forms/IcingaObjectFieldForm.php:142 -#: application/forms/IcingaObjectFieldForm.php:147 +#: ../../../../library/Director/Web/Table/IcingaObjectDatafieldTable.php:51 +#: ../../../../application/forms/IcingaObjectFieldForm.php:106 +#: ../../../../application/forms/IcingaObjectFieldForm.php:111 msgid "Mandatory" msgstr "Pflicht" -#: application/forms/SettingsForm.php:155 +#: ../../../../application/forms/SettingsForm.php:155 msgid "Master-less" msgstr "Masterlos" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:35 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:35 msgid "Match NULL value columns" msgstr "Triff auf Spalten NULL-Werten zu" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:34 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:34 msgid "Match boolean FALSE" msgstr "Triff auf boolesches FALSE zu" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:33 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:33 msgid "Match boolean TRUE" msgstr "Triff auf boolesches TRUE zu" -#: library/Director/Web/Form/DirectorObjectForm.php:1391 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1394 msgid "Max check attempts" msgstr "Maximale Checkwiederholungen" -#: library/Director/Web/Table/GroupMemberTable.php:73 -#: library/Director/Web/Table/GroupMemberTable.php:78 +#: ../../../../library/Director/Web/Table/GroupMemberTable.php:73 +#: ../../../../library/Director/Web/Table/GroupMemberTable.php:78 msgid "Member" msgstr "Mitglied" -#: library/Director/Web/Tabs/ObjectTabs.php:114 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:111 msgid "Members" msgstr "Mitglieder" -#: library/Director/Web/Controller/ObjectController.php:615 -#: application/forms/SyncRuleForm.php:62 +#: ../../../../library/Director/Web/Controller/ObjectController.php:626 +#: ../../../../application/forms/SyncRuleForm.php:62 msgid "Merge" msgstr "Zusammenführen" -#: application/forms/SyncPropertyForm.php:117 +#: ../../../../application/forms/SyncPropertyForm.php:117 msgid "Merge Policy" msgstr "Zusammenführungsrichtlinie" -#: application/forms/IcingaTimePeriodRangeForm.php:23 -#: application/forms/IcingaScheduledDowntimeRangeForm.php:24 +#: ../../../../application/forms/IcingaTimePeriodRangeForm.php:23 +#: ../../../../application/forms/IcingaScheduledDowntimeRangeForm.php:24 msgid "" "Might be monday, tuesday or 2016-01-28 - have a look at the documentation " "for more examples" @@ -3884,294 +3919,302 @@ msgstr "" "Mögliche Werte sind z.B. monday, tuesday oder 2016-01-28 - Mehr Beispiele " "finden sich in der Dokumentation" -#: application/forms/IcingaTemplateChoiceForm.php:73 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:73 msgid "Minimum required" msgstr "Erforderliches Minimum" -#: application/controllers/BranchController.php:112 +#: ../../../../application/controllers/BranchController.php:125 msgid "Modification" msgstr "Änderung" -#: application/forms/ImportRowModifierForm.php:69 +#: ../../../../application/forms/ImportRowModifierForm.php:104 msgid "Modifier" msgstr "Modifikator" -#: library/Director/Web/Tabs/ImportsourceTabs.php:41 +#: ../../../../library/Director/Web/Tabs/ImportsourceTabs.php:41 msgid "Modifiers" msgstr "Modifikatoren" -#: library/Director/ProvidedHook/Monitoring/HostActions.php:55 -#: library/Director/ProvidedHook/Monitoring/ServiceActions.php:56 -#: library/Director/ProvidedHook/Monitoring/ServiceActions.php:62 -#: library/Director/Web/ActionBar/AutomationObjectActionBar.php:38 -#: library/Director/Web/Tabs/SyncRuleTabs.php:37 -#: library/Director/Web/Controller/TemplateController.php:121 -#: application/controllers/ImportsourceController.php:126 -#: application/controllers/SyncruleController.php:553 +#: ../../../../library/Director/ProvidedHook/Monitoring/HostActions.php:54 +#: ../../../../library/Director/ProvidedHook/Monitoring/ServiceActions.php:57 +#: ../../../../library/Director/ProvidedHook/Monitoring/ServiceActions.php:60 +#: ../../../../library/Director/Web/ActionBar/AutomationObjectActionBar.php:38 +#: ../../../../library/Director/Web/Tabs/SyncRuleTabs.php:37 +#: ../../../../library/Director/Web/Controller/TemplateController.php:122 +#: ../../../../application/controllers/ImportsourceController.php:126 +#: ../../../../application/controllers/SyncruleController.php:552 msgid "Modify" msgstr "Ändere" -#: library/Director/ProvidedHook/CubeLinks.php:52 -#: library/Director/ProvidedHook/IcingaDbCubeLinks.php:53 +#: ../../../../library/Director/ProvidedHook/CubeLinks.php:52 +#: ../../../../library/Director/ProvidedHook/IcingaDbCubeLinks.php:53 #, php-format msgid "Modify %d hosts" msgstr "%d Hosts verändern" -#: library/Director/Web/Controller/ObjectsController.php:215 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:215 #, php-format msgid "Modify %d objects" msgstr "%d Objekte bearbeiten" -#: application/controllers/DatafieldController.php:28 -#: application/controllers/DatafieldcategoryController.php:34 +#: ../../../../application/controllers/DatafieldController.php:28 +#: ../../../../application/controllers/DatafieldcategoryController.php:34 #, php-format msgid "Modify %s" msgstr "Ändere %s" -#: library/Director/ProvidedHook/CubeLinks.php:35 -#: library/Director/ProvidedHook/IcingaDbCubeLinks.php:30 +#: ../../../../library/Director/ProvidedHook/CubeLinks.php:35 +#: ../../../../library/Director/ProvidedHook/IcingaDbCubeLinks.php:30 msgid "Modify a host" msgstr "Ändere einen Host" -#: application/forms/DirectorDatalistEntryForm.php:61 +#: ../../../../application/forms/DirectorDatalistEntryForm.php:61 msgid "Modify data list entry" msgstr "Datenlisteneintrag verändern" -#: application/controllers/DataController.php:214 +#: ../../../../application/controllers/DataController.php:214 #, php-format msgid "Modify instance: %s" msgstr "Instanz ändern: %s" -#: library/Director/Web/Table/ApplyRulesTable.php:158 +#: ../../../../library/Director/Web/Table/ApplyRulesTable.php:158 msgid "Modify this Apply Rule" msgstr "Diese Apply-Regeln ändern" -#: library/Director/Web/Controller/ObjectController.php:180 +#: ../../../../library/Director/Web/Controller/ObjectController.php:183 msgid "Modifying Apply Rules" msgstr "Apply-Regeln ändern" -#: application/controllers/ImportsourceController.php:127 -#: application/controllers/ImportsourceController.php:285 -#: application/controllers/ImportsourceController.php:315 +#: ../../../../application/controllers/ImportsourceController.php:127 +#: ../../../../application/controllers/ImportsourceController.php:285 +#: ../../../../application/controllers/ImportsourceController.php:315 msgid "Modifying Import Sources" msgstr "Importquellen ändern" -#: application/controllers/JobController.php:59 +#: ../../../../application/controllers/JobController.php:59 msgid "Modifying Jobs" msgstr "Aufträge ändern" -#: application/controllers/SyncruleController.php:517 -#: application/controllers/SyncruleController.php:625 -#: application/controllers/SyncruleController.php:633 +#: ../../../../application/controllers/SyncruleController.php:517 +#: ../../../../application/controllers/SyncruleController.php:623 +#: ../../../../application/controllers/SyncruleController.php:631 msgid "Modifying Sync Rules" msgstr "Synchronisationsregeln ändern" -#: application/controllers/TemplatechoiceController.php:36 +#: ../../../../application/controllers/TemplatechoiceController.php:36 msgid "Modifying Template Choices" msgstr "Auswahlmöglichkeit für Vorlagen abändern" -#: library/Director/Web/Controller/ObjectController.php:176 -#: application/controllers/ServiceController.php:147 +#: ../../../../library/Director/Web/Controller/ObjectController.php:179 +#: ../../../../application/controllers/ServiceController.php:147 msgid "Modifying Templates" msgstr "Vorlagen ändern" -#: library/Director/Web/Table/Dependency/DependencyInfoTable.php:37 +#: ../../../../library/Director/Web/Table/Dependency/DependencyInfoTable.php:37 msgid "Module name" msgstr "Modulname" -#: library/Director/Dashboard/Dashlet/ServiceObjectDashlet.php:15 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceObjectDashlet.php:17 msgid "Monitored Services" msgstr "Überwachte Services" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:544 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:544 msgid "Move down" msgstr "Nach unten bewegen" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:534 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:534 msgid "Move up" msgstr "Nach oben bewegen" -#: library/Director/Web/Controller/ObjectsController.php:213 +#: ../../../../library/Director/Web/Controller/ObjectsController.php:213 msgid "Multiple objects" msgstr "Mehrere Objekte" -#: application/forms/SelfServiceSettingsForm.php:51 +#: ../../../../application/forms/SelfServiceSettingsForm.php:51 msgid "My Agents should use DNS to look up Endpoint names" msgstr "Meine Agents sollen DNS benutzen, um Endpoint-Namen nachzuschlagen" -#: application/controllers/ConfigController.php:181 +#: ../../../../application/controllers/ConfigController.php:182 msgid "My changes" msgstr "Meine Änderungen" -#: application/controllers/SchemaController.php:16 +#: ../../../../application/controllers/SchemaController.php:16 msgid "MySQL schema" msgstr "MySQL Schema" -#: library/Director/Web/Table/ChoicesTable.php:41 -#: library/Director/Web/Table/CoreApiObjectsTable.php:57 -#: library/Director/Web/Table/CoreApiPrototypesTable.php:40 -#: library/Director/Web/Table/CoreApiFieldsTable.php:79 -#: library/Director/Web/Table/ObjectSetTable.php:45 -#: application/forms/IcingaServiceVarForm.php:22 -#: application/forms/IcingaHostForm.php:38 -#: application/forms/IcingaHostVarForm.php:22 -#: application/forms/IcingaTimePeriodForm.php:15 -#: application/forms/IcingaCommandForm.php:46 -#: application/forms/IcingaServiceForm.php:575 -#: application/forms/IcingaDependencyForm.php:74 -#: application/forms/IcingaApiUserForm.php:14 -#: application/forms/IcingaAddServiceForm.php:143 -#: application/forms/IcingaServiceDictionaryMemberForm.php:22 +#: ../../../../library/Director/Web/Table/CoreApiObjectsTable.php:57 +#: ../../../../library/Director/Web/Table/CoreApiPrototypesTable.php:40 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:79 +#: ../../../../library/Director/Web/Table/ChoicesTable.php:41 +#: ../../../../library/Director/Web/Table/ObjectSetTable.php:50 +#: ../../../../application/forms/IcingaServiceVarForm.php:22 +#: ../../../../application/forms/IcingaHostVarForm.php:22 +#: ../../../../application/forms/IcingaTimePeriodForm.php:15 +#: ../../../../application/forms/IcingaCommandForm.php:46 +#: ../../../../application/forms/IcingaServiceForm.php:579 +#: ../../../../application/forms/IcingaHostForm.php:40 +#: ../../../../application/forms/IcingaApiUserForm.php:14 +#: ../../../../application/forms/IcingaServiceDictionaryMemberForm.php:22 +#: ../../../../application/forms/IcingaAddServiceForm.php:144 +#: ../../../../application/forms/IcingaDependencyForm.php:74 msgid "Name" msgstr "Name" -#: application/forms/IcingaDependencyForm.php:76 +#: ../../../../application/forms/IcingaDependencyForm.php:76 msgid "Name for the Icinga dependency you are going to create" msgstr "Name der Icinga-Abhängigkeit, die erstellt werden soll" -#: application/forms/IcingaEndpointForm.php:20 +#: ../../../../application/forms/IcingaEndpointForm.php:20 msgid "Name for the Icinga endpoint template you are going to create" msgstr "Name der Icinga-Endpunkt-Vorlage, die erstellt werden soll" -#: application/forms/IcingaEndpointForm.php:26 +#: ../../../../application/forms/IcingaEndpointForm.php:26 msgid "Name for the Icinga endpoint you are going to create" msgstr "Name des Icinga-Endpunkt, der erstellt werden soll" -#: application/forms/IcingaNotificationForm.php:21 +#: ../../../../application/forms/IcingaNotificationForm.php:22 msgid "Name for the Icinga notification template you are going to create" msgstr "Name der Icinga-Benachrichtigungs-Vorlage, die erstellt werden soll" -#: application/forms/IcingaNotificationForm.php:27 +#: ../../../../application/forms/IcingaNotificationForm.php:28 msgid "Name for the Icinga notification you are going to create" msgstr "Name der Icinga-Benachrichtigung, die erstellt werden soll" -#: application/forms/IcingaServiceForm.php:578 -#: application/forms/IcingaAddServiceForm.php:146 +#: ../../../../application/forms/IcingaServiceForm.php:582 +#: ../../../../application/forms/IcingaAddServiceForm.php:147 msgid "Name for the Icinga service you are going to create" msgstr "Name des Icinga-Service, der erstellt werden soll" -#: application/forms/IcingaUserForm.php:30 +#: ../../../../application/forms/IcingaUserForm.php:30 msgid "Name for the Icinga user object you are going to create" msgstr "Name für das Icinga-Benutzerobjekt, das Sie erstellen möchten" -#: application/forms/IcingaUserForm.php:24 +#: ../../../../application/forms/IcingaUserForm.php:24 msgid "Name for the Icinga user template you are going to create" msgstr "Name für die Icinga-Benutzervorlage, die Sie erstellen möchten" -#: application/forms/IcingaZoneForm.php:17 +#: ../../../../application/forms/IcingaZoneForm.php:17 msgid "Name for the Icinga zone you are going to create" msgstr "Name der Icinga-Zone, die erstellt werden soll" -#: application/forms/IcingaServiceDictionaryMemberForm.php:25 +#: ../../../../application/forms/IcingaServiceDictionaryMemberForm.php:25 msgid "Name for the instance you are going to create" msgstr "Name der Instanz, die erstellt werden soll" -#: application/forms/IcingaCloneObjectForm.php:151 +#: ../../../../application/forms/IcingaCloneObjectForm.php:155 msgid "Name needs to be changed when cloning a Template" msgstr "Beim Klonen einer Vorlage muss der Name geändert werden" -#: library/Director/Web/Table/CoreApiFieldsTable.php:90 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:90 msgid "Nav" msgstr "Nav" -#: application/controllers/DatafieldcategoryController.php:40 +#: ../../../../application/controllers/DatafieldcategoryController.php:40 msgid "New Category" msgstr "Neue Kategorie" -#: application/controllers/DatafieldController.php:34 +#: ../../../../application/controllers/DatafieldController.php:34 msgid "New Field" msgstr "Neues Feld" -#: application/controllers/JobController.php:34 +#: ../../../../application/controllers/JobController.php:34 msgid "New Job" msgstr "Neuer Job" -#: library/Director/Web/Tabs/ImportsourceTabs.php:54 +#: ../../../../library/Director/Web/Tabs/ImportsourceTabs.php:54 msgid "New import source" msgstr "Neue Importquelle" -#: library/Director/Web/Form/CloneImportSourceForm.php:31 -#: library/Director/Web/Form/CloneSyncRuleForm.php:31 -#: application/forms/IcingaCloneObjectForm.php:39 +#: ../../../../library/Director/Web/Form/CloneImportSourceForm.php:33 +#: ../../../../library/Director/Web/Form/CloneSyncRuleForm.php:33 +#: ../../../../application/forms/IcingaCloneObjectForm.php:41 msgid "New name" msgstr "Neuer Name" -#: library/Director/Web/Widget/ActivityLogInfo.php:379 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:379 msgid "New object" msgstr "Neues Objekt" -#: application/forms/IcingaHostForm.php:31 -#: application/forms/IcingaAddServiceForm.php:35 +#: ../../../../application/forms/IcingaHostForm.php:33 +#: ../../../../application/forms/IcingaAddServiceForm.php:36 msgid "Next" msgstr "Weiter" -#: library/Director/Job/ImportJob.php:102 -#: library/Director/Job/ConfigJob.php:40 -#: library/Director/Job/ConfigJob.php:52 -#: library/Director/Job/SyncJob.php:102 -#: library/Director/PropertyModifier/PropertyModifierUpperCaseFirst.php:26 -#: application/forms/IcingaZoneForm.php:29 -#: application/forms/SettingsForm.php:58 -#: application/forms/SettingsForm.php:73 -#: application/forms/SettingsForm.php:95 -#: application/forms/SelfServiceSettingsForm.php:240 +#: ../../../../library/Director/Job/ImportJob.php:102 +#: ../../../../library/Director/Job/ConfigJob.php:40 +#: ../../../../library/Director/Job/ConfigJob.php:52 +#: ../../../../library/Director/Job/SyncJob.php:102 +#: ../../../../library/Director/PropertyModifier/PropertyModifierUpperCaseFirst.php:26 +#: ../../../../application/forms/IcingaZoneForm.php:29 +#: ../../../../application/forms/SettingsForm.php:58 +#: ../../../../application/forms/SettingsForm.php:73 +#: ../../../../application/forms/SettingsForm.php:95 +#: ../../../../application/forms/SelfServiceSettingsForm.php:240 msgid "No" msgstr "Nein" -#: application/controllers/DataController.php:184 +#: ../../../../application/controllers/DataController.php:184 #, php-format msgid "No %s have been created yet" msgstr "Bisher wurden keine %s erstellt" -#: library/Director/Util.php:167 +#: ../../../../library/Director/Util.php:167 #, php-format msgid "No %s resource available" msgstr "Keine %s Ressource verfügbar" -#: library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:101 +#: ../../../../library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:101 msgid "No API user configured, you might run the kickstart helper" msgstr "" "Kein API Benutzer konfiguriert. Der kickstart helper sollte ausgeführt werden" -#: application/forms/IcingaHostForm.php:175 +#: ../../../../application/forms/IcingaHostForm.php:177 msgid "No Host Template has been provided yet" msgstr "Es wurde noch keine passende Host-Vorlage bereitgestellt" -#: application/forms/IcingaHostForm.php:163 +#: ../../../../application/forms/IcingaHostForm.php:165 msgid "No Host template has been chosen" msgstr "Keine Host-Vorlage wurde ausgewählt" -#: application/forms/IcingaAddServiceForm.php:95 +#: ../../../../application/forms/IcingaAddServiceForm.php:96 msgid "No Service Templates have been provided yet" msgstr "Es wurde noch keine passende Vorlage bereitgestellt" -#: library/Director/Web/Form/DirectorObjectForm.php:670 -#: application/forms/IcingaCommandArgumentForm.php:181 -#: application/forms/IcingaTimePeriodRangeForm.php:94 -#: application/forms/IcingaServiceForm.php:777 -#: application/forms/IcingaScheduledDowntimeRangeForm.php:99 +#: ../../../../application/forms/IcingaNotificationForm.php:127 +msgid "No User object has been created yet" +msgstr "Kein Benutzer-Objekt wurde bisher definiert" + +#: ../../../../application/forms/IcingaNotificationForm.php:164 +msgid "No UserGroup object has been created yet" +msgstr "Keine Benutzergruppe wurde bisher definiert" + +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:673 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:181 +#: ../../../../application/forms/IcingaTimePeriodRangeForm.php:94 +#: ../../../../application/forms/IcingaServiceForm.php:781 +#: ../../../../application/forms/IcingaScheduledDowntimeRangeForm.php:99 msgid "No action taken, object has not been modified" msgstr "Keine Aktion durchgeführt, das Objekt wurde nicht verändert" -#: library/Director/Dashboard/Dashlet/Dashlet.php:162 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:162 msgid "No apply rule has been defined yet" msgstr "Bisher wurde kein Apply-Regel definiert" -#: library/Director/Web/Widget/SyncRunDetails.php:43 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:43 msgid "No changes have been made" msgstr "Keine Änderungen wurden gemacht" -#: application/controllers/DashboardController.php:73 +#: ../../../../application/controllers/DashboardController.php:73 msgid "No dashboard available, you might have not enough permissions" msgstr "" "Kein Dashboard verfügbar, eventuell wurden nicht genügend Zugriffsrechte " "gewährt" -#: library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:70 +#: ../../../../library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:70 msgid "No database has been configured for Icinga Director" msgstr "Keine Datenbank für den Icinga-Director wurde konfiguriert" -#: application/forms/KickstartForm.php:215 +#: ../../../../application/forms/KickstartForm.php:215 msgid "" "No database resource has been configured yet. Please choose a resource to " "complete your config" @@ -4179,65 +4222,65 @@ msgstr "" "Es wurde bisher keine Datenbankressource konfiguriert. Bitte eine Ressource " "auswählen, um die Konfiguration zu vervollständigen" -#: application/forms/KickstartForm.php:56 +#: ../../../../application/forms/KickstartForm.php:56 msgid "No database schema has been created yet" msgstr "Kein Datenbankschema wurde bisher erstellt" -#: application/forms/AddToBasketForm.php:105 +#: ../../../../application/forms/AddToBasketForm.php:105 msgid "No object has been chosen" msgstr "Keine Objekt wurde ausgewählt" -#: library/Director/Dashboard/Dashlet/Dashlet.php:180 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:180 msgid "No object has been defined yet" msgstr "Kein Objekt wurde bisher definiert" -#: application/forms/IcingaMultiEditForm.php:88 +#: ../../../../application/forms/IcingaMultiEditForm.php:88 msgid "No object has been modified" msgstr "Kein Objekt wurde verändert" -#: library/Director/Web/Form/DirectorObjectForm.php:1245 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1248 msgid "No related template has been provided yet" msgstr "Es wurde noch keine passende Vorlage bereitgestellt" -#: application/forms/IcingaAddServiceForm.php:83 +#: ../../../../application/forms/IcingaAddServiceForm.php:84 msgid "No service has been chosen" msgstr "Keine Service wurde ausgewählt" -#: application/controllers/HostController.php:167 +#: ../../../../application/controllers/HostController.php:151 #, php-format msgid "No such service: %s" msgstr "Kein solcher Service: %s" -#: library/Director/Web/Form/DirectorObjectForm.php:1240 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1243 msgid "No template has been chosen" msgstr "Keine Vorlage wurde ausgewählt" -#: library/Director/Dashboard/Dashlet/Dashlet.php:144 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:144 msgid "No template has been defined yet" msgstr "Es wurde noch keine Vorlage definiert" -#: application/forms/IcingaServiceForm.php:625 +#: ../../../../application/forms/IcingaServiceForm.php:629 msgid "None" msgstr "Keine" -#: library/Director/Dashboard/Dashlet/EndpointObjectDashlet.php:57 +#: ../../../../library/Director/Dashboard/Dashlet/EndpointObjectDashlet.php:58 msgid "None could be used for deployments right now" msgstr "Keines kann momentan zum Ausrollen verwendet werden" -#: library/Director/Web/Form/DirectorObjectForm.php:1531 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1534 msgid "Notes" msgstr "Notizen" -#: library/Director/Web/Form/DirectorObjectForm.php:1540 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1543 msgid "Notes URL" msgstr "Notizen-URL" -#: application/forms/SyncRunForm.php:60 +#: ../../../../application/forms/SyncRunForm.php:60 msgid "Nothing changed, rule is in sync" msgstr "Keine Änderung, Regel ist synchron" -#: application/forms/ImportCheckForm.php:38 -#: application/forms/ImportRunForm.php:38 +#: ../../../../application/forms/ImportCheckForm.php:38 +#: ../../../../application/forms/ImportRunForm.php:38 msgid "" "Nothing to do, data provided by this Import Source didn't change since the " "last import run" @@ -4245,40 +4288,40 @@ msgstr "" "Keine Aktion nötig. Die Daten von dieser Importquelle haben sich seit dem " "letzten Lauf nicht geändert" -#: application/forms/RestoreObjectForm.php:76 +#: ../../../../application/forms/RestoreObjectForm.php:76 msgid "Nothing to do, restore would not modify the current object" msgstr "" "Nichts zu tun, eine Wiederherstellung würde das aktuelle Objekt nicht ändern" -#: application/forms/SyncRunForm.php:64 +#: ../../../../application/forms/SyncRunForm.php:64 msgid "Nothing to do, rule is in sync" msgstr "Nichts zu tun, Regel ist synchron" -#: application/forms/SyncCheckForm.php:63 +#: ../../../../application/forms/SyncCheckForm.php:63 msgid "Nothing would change, this rule is still in sync" msgstr "Es würde sich nichts ändern, diese Regel ist noch synchron" -#: library/Director/TranslationDummy.php:18 -#: application/forms/IcingaNotificationForm.php:25 -#: application/forms/SyncRuleForm.php:22 +#: ../../../../library/Director/TranslationDummy.php:18 +#: ../../../../application/forms/IcingaNotificationForm.php:26 +#: ../../../../application/forms/SyncRuleForm.php:22 msgid "Notification" msgstr "Benachrichtigung" -#: library/Director/DataType/DataTypeDirectorObject.php:58 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:58 msgid "Notification Apply Rules" msgstr "Benachrichtigungs-Apply-Regeln" -#: library/Director/Web/Controller/TemplateController.php:57 +#: ../../../../library/Director/Web/Controller/TemplateController.php:58 #, php-format msgid "Notification Apply Rules based on %s" msgstr "Benachrichtigungs-Apply-Regeln basierend auf %s" -#: library/Director/Dashboard/Dashlet/NotificationCommandsDashlet.php:19 -#: library/Director/Import/ImportSourceCoreApi.php:58 +#: ../../../../library/Director/Dashboard/Dashlet/NotificationCommandsDashlet.php:19 +#: ../../../../library/Director/Import/ImportSourceCoreApi.php:58 msgid "Notification Commands" msgstr "Benachrichtigungskommandos" -#: library/Director/Dashboard/Dashlet/NotificationCommandsDashlet.php:12 +#: ../../../../library/Director/Dashboard/Dashlet/NotificationCommandsDashlet.php:12 msgid "" "Notification Commands allow you to trigger any action you want when a " "notification takes place" @@ -4286,41 +4329,41 @@ msgstr "" "Benachrichtigungs-Kommandos erlauben das Ausführen beliebiger Aktionen wenn " "eine Benachrichtigung stattfinden soll" -#: application/forms/IcingaNotificationForm.php:19 +#: ../../../../application/forms/IcingaNotificationForm.php:20 msgid "Notification Template" msgstr "Benachrichtigungsvorlage" -#: application/forms/BasketForm.php:30 +#: ../../../../application/forms/BasketForm.php:30 msgid "Notification Templates" msgstr "Benachrichtigungsvorlagen" -#: application/forms/IcingaNotificationForm.php:262 +#: ../../../../application/forms/IcingaNotificationForm.php:310 msgid "Notification command" msgstr "Benachrichtigungskommando" -#: application/forms/IcingaNotificationForm.php:176 +#: ../../../../application/forms/IcingaNotificationForm.php:224 msgid "Notification interval" msgstr "Benachrichtigungsintervall" -#: application/controllers/TemplatechoicesController.php:29 +#: ../../../../application/controllers/TemplatechoicesController.php:29 msgid "Notification template choices" msgstr "Auswahlmöglichkeiten für Benachrichtigungsvorlagen" -#: library/Director/Dashboard/Dashlet/NotificationTemplateDashlet.php:13 +#: ../../../../library/Director/Dashboard/Dashlet/NotificationTemplateDashlet.php:15 msgid "Notification templates" msgstr "Benachrichtigungsvorlagen" -#: configuration.php:165 -#: library/Director/Dashboard/Dashlet/NotificationApplyDashlet.php:13 -#: library/Director/Dashboard/Dashlet/NotificationsDashlet.php:13 -#: library/Director/Db/Branch/BranchModificationInspection.php:46 -#: library/Director/Web/Table/CustomvarVariantsTable.php:61 -#: library/Director/Web/Table/CustomvarTable.php:46 -#: application/forms/BasketForm.php:31 +#: ../../../../configuration.php:133 +#: ../../../../library/Director/Dashboard/Dashlet/NotificationApplyDashlet.php:15 +#: ../../../../library/Director/Dashboard/Dashlet/NotificationsDashlet.php:15 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:46 +#: ../../../../library/Director/Web/Table/CustomvarVariantsTable.php:61 +#: ../../../../library/Director/Web/Table/CustomvarTable.php:46 +#: ../../../../application/forms/BasketForm.php:31 msgid "Notifications" msgstr "Benachrichtigungen" -#: library/Director/Dashboard/NotificationsDashboard.php:20 +#: ../../../../library/Director/Dashboard/NotificationsDashboard.php:20 msgid "" "Notifications are sent when a host or service reaches a non-ok hard state or " "recovers from such. One might also want to send them for special events like " @@ -4354,72 +4397,72 @@ msgstr "" "sich natürlich auch an externe Serviceanbieter auslagern. Die Möglichkeiten " "sind endlos, nachdem man beliebig viele eigene Kommandos anbinden kann" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:43 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:43 msgid "Numeric position or key name" msgstr "Numerische Position oder Schlüsselbezeichner" -#: library/Director/IcingaConfig/StateFilterSet.php:24 +#: ../../../../library/Director/IcingaConfig/StateFilterSet.php:24 msgid "OK" msgstr "Ok" -#: library/Director/DataType/DataTypeDirectorObject.php:67 -#: library/Director/Web/Form/DirectorObjectForm.php:1114 -#: library/Director/Web/Form/DirectorObjectForm.php:1119 -#: library/Director/Web/Controller/TemplateController.php:149 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:67 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1117 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1122 +#: ../../../../library/Director/Web/Controller/TemplateController.php:150 msgid "Object" msgstr "Objekt" -#: application/controllers/InspectController.php:102 +#: ../../../../application/controllers/InspectController.php:102 msgid "Object Inspection" msgstr "Objekt-Inspektion" -#: library/Director/Import/ImportSourceDirectorObject.php:78 -#: application/forms/SyncRuleForm.php:45 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:78 +#: ../../../../application/forms/SyncRuleForm.php:45 msgid "Object Type" msgstr "Objekttyp" -#: library/Director/Import/ImportSourceLdap.php:56 +#: ../../../../library/Director/Import/ImportSourceLdap.php:56 msgid "Object class" msgstr "Objektklasse" -#: library/Director/Dashboard/Dashlet/DependencyObjectDashlet.php:18 +#: ../../../../library/Director/Dashboard/Dashlet/DependencyObjectDashlet.php:18 msgid "Object dependency relationships." msgstr "Objekt-Abhängigkeiten." -#: application/forms/RestoreObjectForm.php:80 +#: ../../../../application/forms/RestoreObjectForm.php:80 msgid "Object has been re-created" msgstr "Objekt wurde wiederhergestellt" -#: application/forms/RestoreObjectForm.php:72 +#: ../../../../application/forms/RestoreObjectForm.php:72 msgid "Object has been restored" msgstr "Objekt wurde wiederhergestellt" -#: application/forms/SyncPropertyForm.php:359 +#: ../../../../application/forms/SyncPropertyForm.php:359 msgid "Object properties" msgstr "Objekteigenschaften" -#: library/Director/Web/Table/SyncruleTable.php:46 -#: library/Director/Web/Form/DirectorObjectForm.php:1127 +#: ../../../../library/Director/Web/Table/SyncruleTable.php:46 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1130 msgid "Object type" msgstr "Objekttyp" -#: application/controllers/InspectController.php:65 +#: ../../../../application/controllers/InspectController.php:65 #, php-format msgid "Object type \"%s\"" msgstr "Objekttyp \"%s\"" -#: library/Director/Web/Table/GeneratedConfigFileTable.php:85 +#: ../../../../library/Director/Web/Table/GeneratedConfigFileTable.php:85 msgid "Object/Tpl/Apply" msgstr "Objekt/Vorlage/Apply" -#: library/Director/Import/ImportSourceDirectorObject.php:81 -#: library/Director/Web/Table/HostTemplateUsageTable.php:11 -#: library/Director/Web/Table/TemplateUsageTable.php:24 -#: library/Director/Web/Table/ServiceTemplateUsageTable.php:11 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:81 +#: ../../../../library/Director/Web/Table/TemplateUsageTable.php:24 +#: ../../../../library/Director/Web/Table/HostTemplateUsageTable.php:11 +#: ../../../../library/Director/Web/Table/ServiceTemplateUsageTable.php:11 msgid "Objects" msgstr "Objekte" -#: library/Director/Import/ImportSourceRestApi.php:209 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:209 msgid "" "Often the expected result is provided in a property like \"objects\". Please " "specify this if required." @@ -4427,35 +4470,35 @@ msgstr "" "Häufig wird das zu erwartende Ergebnis in einer Eigenschaft wie \"objects\" " "zurückgeliefert. Bitte angeben falls erforderlich." -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:27 -#: library/Director/PropertyModifier/PropertyModifierParseURL.php:34 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierParseURL.php:34 msgid "On failure" msgstr "Bei Fehler" -#: library/Director/Dashboard/Dashlet/Dashlet.php:166 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:166 msgid "One apply rule has been defined" msgstr "Eine Apply-Regel wurde definiert" -#: library/Director/Dashboard/Dashlet/Dashlet.php:188 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:188 msgid "One external object has been defined, it will not be deployed" msgstr "Ein externes Objekt wurde erstellt, es wird nicht ausgerollt" -#: library/Director/Dashboard/Dashlet/Dashlet.php:191 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:191 msgid "One object has been defined" msgstr "Ein Objekt wurde definiert" -#: library/Director/Web/Widget/SyncRunDetails.php:46 -#: application/forms/IcingaMultiEditForm.php:90 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:46 +#: ../../../../application/forms/IcingaMultiEditForm.php:90 msgid "One object has been modified" msgstr "Ein Objekt wurde verändert" -#: library/Director/PropertyModifier/PropertyModifierSplit.php:16 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSplit.php:16 msgid "One or more characters that should be used to split this string" msgstr "" "Ein oder mehrere Zeichen, die zum Trennen der Zeichenkette genutzt werden " "sollen" -#: library/Director/PropertyModifier/PropertyModifierJoin.php:16 +#: ../../../../library/Director/PropertyModifier/PropertyModifierJoin.php:16 msgid "" "One or more characters that will be used to glue an input array to a string. " "Can be left empty" @@ -4463,18 +4506,18 @@ msgstr "" "Ein oder mehrere Zeichen, die verwendet werden, um einen Eingabearray an " "eine Zeichenkette zu heften. Kann leer bleiben" -#: application/forms/IcingaTimePeriodRangeForm.php:30 -#: application/forms/IcingaScheduledDowntimeRangeForm.php:31 +#: ../../../../application/forms/IcingaTimePeriodRangeForm.php:30 +#: ../../../../application/forms/IcingaScheduledDowntimeRangeForm.php:31 msgid "One or more time periods, e.g. 00:00-24:00 or 00:00-09:00,17:00-24:00" msgstr "" "Einer oder mehrere Zeiträume, z.B. 00:00-24:00 oder 00:00-09:00,17:00-24:00" -#: library/Director/Dashboard/Dashlet/Dashlet.php:148 -#: library/Director/Dashboard/Dashlet/Dashlet.php:185 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:148 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:185 msgid "One template has been defined" msgstr "Eine Vorlage wurde definiert" -#: application/forms/IcingaCommandArgumentForm.php:100 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:100 msgid "" "Only set this parameter if the argument value resolves to a numeric value. " "String values are not supported" @@ -4482,11 +4525,11 @@ msgstr "" "Nur setzen, wenn der Wert des Arguments numereisch ist. Zeichenketten als " "Wert werden nicht unterstützt" -#: application/forms/IcingaObjectFieldForm.php:146 +#: ../../../../application/forms/IcingaObjectFieldForm.php:110 msgid "Optional" msgstr "Optional" -#: application/forms/IcingaCommandForm.php:71 +#: ../../../../application/forms/IcingaCommandForm.php:71 msgid "" "Optional command timeout. Allowed values are seconds or durations postfixed " "with a specific unit (e.g. 1m or also 3m 30s)." @@ -4494,7 +4537,7 @@ msgstr "" "Optionaler Kommando-Timeout. Erlaubt sind Werte in Sekunden oder Werte mit " "nachgestellter Zeiteinheit. z.B. 1m oder auch 3m 30s." -#: application/forms/IcingaDependencyForm.php:248 +#: ../../../../application/forms/IcingaDependencyForm.php:248 msgid "" "Optional. The child service. If omitted this dependency object is treated as " "host dependency." @@ -4502,7 +4545,7 @@ msgstr "" "Optional. Der Kind-Service. Falls leer wird dieses Objekt als Host-" "Abhängigkeit behandelt." -#: application/forms/IcingaDependencyForm.php:218 +#: ../../../../application/forms/IcingaDependencyForm.php:218 msgid "" "Optional. The parent service. If omitted this dependency object is treated " "as host dependency." @@ -4510,38 +4553,38 @@ msgstr "" "Optional. Der Eltern-Service. Falls leer wird dieses Objekt als Host-" "Abhängigkeit behandelt." -#: application/forms/IcingaObjectFieldForm.php:103 +#: ../../../../library/Director/Field/FormFieldSuggestion.php:90 msgid "Other available fields" msgstr "Andere verfügbare Felder" -#: application/forms/SyncPropertyForm.php:274 +#: ../../../../application/forms/SyncPropertyForm.php:274 msgid "Other sources" msgstr "Andere Quellen" -#: application/forms/IcingaServiceForm.php:160 -#: application/forms/IcingaServiceForm.php:435 -#: application/forms/IcingaServiceForm.php:467 +#: ../../../../application/forms/IcingaServiceForm.php:162 +#: ../../../../application/forms/IcingaServiceForm.php:439 +#: ../../../../application/forms/IcingaServiceForm.php:471 msgid "Override vars" msgstr "Variablen überschreiben" -#: library/Director/Web/ActionBar/AutomationObjectActionBar.php:32 -#: library/Director/Web/Tabs/MainTabs.php:26 +#: ../../../../library/Director/Web/ActionBar/AutomationObjectActionBar.php:32 +#: ../../../../library/Director/Web/Tabs/MainTabs.php:27 msgid "Overview" msgstr "Überblick" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:81 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:81 msgid "PHP Binary" msgstr "PHP Binary" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:84 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:84 msgid "PHP Integer" msgstr "PHP Integer" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:83 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:83 msgid "PHP Version" msgstr "PHP-Version" -#: application/controllers/PhperrorController.php:19 +#: ../../../../application/controllers/PhperrorController.php:19 #, php-format msgid "" "PHP version 5.4.x is required for Director >= 1.4.0, you're running %s. " @@ -4550,56 +4593,56 @@ msgstr "" "PHP Version 5.4.x ist für den Director >= 1.4.0 erforderlich, hier läuft %s. " "Bitte entweder PHP upgraden oder den Icinga Director downgraden" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:73 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:73 msgid "PID" msgstr "PID" -#: library/Director/Web/Tabs/ObjectTabs.php:137 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:134 msgid "Packages" msgstr "Pakete" -#: library/Director/Web/Widget/InspectPackages.php:48 +#: ../../../../library/Director/Web/Widget/InspectPackages.php:48 #, php-format msgid "Packages on Endpoint: %s" msgstr "Pakete auf Endpunkt: %s" -#: application/forms/IcingaUserForm.php:41 +#: ../../../../application/forms/IcingaUserForm.php:41 msgid "Pager" msgstr "Pager" -#: application/forms/IcingaDependencyForm.php:200 +#: ../../../../application/forms/IcingaDependencyForm.php:200 msgid "Parent Host" msgstr "Eltern-Host" -#: application/forms/IcingaDependencyForm.php:216 +#: ../../../../application/forms/IcingaDependencyForm.php:216 msgid "Parent Service" msgstr "Eltern-Service" -#: application/forms/IcingaZoneForm.php:36 +#: ../../../../application/forms/IcingaZoneForm.php:36 msgid "Parent Zone" msgstr "Übergeordnete Zone" -#: library/Director/Import/ImportSourceRestApi.php:233 -#: application/forms/IcingaApiUserForm.php:19 -#: application/forms/KickstartForm.php:163 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:233 +#: ../../../../application/forms/IcingaApiUserForm.php:19 +#: ../../../../application/forms/KickstartForm.php:163 msgid "Password" msgstr "Passwort" -#: library/Director/PropertyModifier/PropertyModifierRegexSplit.php:13 -#: library/Director/PropertyModifier/PropertyModifierCombine.php:14 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexSplit.php:13 +#: ../../../../library/Director/PropertyModifier/PropertyModifierCombine.php:14 msgid "Pattern" msgstr "Muster" -#: application/forms/ApplyMigrationsForm.php:39 +#: ../../../../application/forms/ApplyMigrationsForm.php:39 msgid "Pending database schema migrations have successfully been applied" msgstr "" "Ausstehende Datenbankschemamigrationsskripte wurden erfolgreich angewandt" -#: library/Director/Util.php:169 +#: ../../../../library/Director/Util.php:169 msgid "Please ask an administrator to grant you access to resources" msgstr "Zugriff auf Ressourcen kann durch Administrator gewährt werden" -#: application/forms/AddToBasketForm.php:117 +#: ../../../../application/forms/AddToBasketForm.php:117 #, php-format msgid "" "Please check your Basket configuration, %s does not support single \"%s\" " @@ -4608,16 +4651,16 @@ msgstr "" "Bitte Basketkonfiguration überprüfen, %s unterstützt keine einzelnen " "Konfigurationsobjekte vom Typ \"%s\"" -#: library/Director/PropertyModifier/PropertyModifierMap.php:19 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMap.php:20 msgid "Please choose a data list that can be used for map lookups" msgstr "Eine Datenliste auswählen, die für Map lookups verwendet wird" -#: library/Director/DataType/DataTypeDirectorObject.php:69 -#: library/Director/DataType/DataTypeDictionary.php:66 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:69 +#: ../../../../library/Director/DataType/DataTypeDictionary.php:66 msgid "Please choose a specific Icinga object type" msgstr "Bitte einen bestimmten Icinga-Objekttyp auswählen" -#: library/Director/Job/ImportJob.php:82 +#: ../../../../library/Director/Job/ImportJob.php:82 msgid "" "Please choose your import source that should be executed. You could create " "different schedules for different sources or also opt for running all of " @@ -4627,7 +4670,7 @@ msgstr "" "verschiedene Zeitpläne für verschiedene Quellen erstellt oder alle " "gleichzeitig ausgeführt werden." -#: library/Director/Job/SyncJob.php:82 +#: ../../../../library/Director/Job/SyncJob.php:82 msgid "" "Please choose your synchronization rule that should be executed. You could " "create different schedules for different rules or also opt for running all " @@ -4637,33 +4680,33 @@ msgstr "" "verschiedene Zeitpläne für verschiedene Regeln erstellt oder alle " "gleichzeitig ausgeführt werden." -#: library/Director/Import/ImportSourceSql.php:55 +#: ../../../../library/Director/Import/ImportSourceSql.php:55 msgid "Please click \"Store\" once again to determine query columns" msgstr "" "Bitte klicke \"Speicher\" erneut um die von der Abfrage bereitgestellten " "Spalten zu ermitteln" -#: application/forms/KickstartForm.php:234 +#: ../../../../application/forms/KickstartForm.php:234 #, php-format msgid "Please click %s to create new DB resources" msgstr "%s klicken, um neue Datenbankressourcen zu erstellen" -#: library/Director/Util.php:159 +#: ../../../../library/Director/Util.php:159 #, php-format msgid "Please click %s to create new resources" msgstr "%s klicken, um neue Ressourcen zu erstellen" -#: application/forms/IcingaHostForm.php:167 -#: application/forms/IcingaAddServiceForm.php:87 +#: ../../../../application/forms/IcingaHostForm.php:169 +#: ../../../../application/forms/IcingaAddServiceForm.php:88 #, php-format msgid "Please define a %s first" msgstr "Bitte zuerst eine %s definieren" -#: library/Director/Web/Form/DirectorObjectForm.php:1243 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1246 msgid "Please define a related template first" msgstr "Bitte zuerst eine entsprechende Vorlage definieren" -#: application/forms/KickstartForm.php:472 +#: ../../../../application/forms/KickstartForm.php:472 msgid "" "Please make sure that your database exists and your user has been granted " "enough permissions" @@ -4671,7 +4714,7 @@ msgstr "" "Überprüfen, ob die Datenbank existiert und der Benutzer ausreichende " "Berechtigungen hat" -#: application/controllers/ImportsourceController.php:98 +#: ../../../../application/controllers/ImportsourceController.php:98 #, php-format msgid "" "Please note that importing data will take place in your main Branch. " @@ -4683,7 +4726,7 @@ msgstr "" "anderen Konfigurationszweig befindet. Für die volle Funktionalität bitte %s " "deaktivieren" -#: application/forms/SettingsForm.php:23 +#: ../../../../application/forms/SettingsForm.php:23 msgid "" "Please only change those settings in case you are really sure that you are " "required to do so. Usually the defaults chosen by the Icinga Director should " @@ -4693,18 +4736,18 @@ msgstr "" "nötig erachtet wird. Für gewöhnlich sollten die vom Icinga Director " "gewählten Standardwerte für Umgebungen jeglicher Art passend sein." -#: application/forms/SyncRuleForm.php:31 +#: ../../../../application/forms/SyncRuleForm.php:31 msgid "Please provide a rule name" msgstr "Bitte einen Regelnamen angeben" -#: library/Director/PropertyModifier/PropertyModifierSubstring.php:17 -#: library/Director/PropertyModifier/PropertyModifierSubstring.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSubstring.php:17 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSubstring.php:27 #, php-format msgid "Please see %s for detailled instructions of how start and end work" msgstr "" "Siehe %s für eine detaillierte Anleitung, wie Beginn und Ende funktionieren" -#: application/forms/ImportRowModifierForm.php:32 +#: ../../../../application/forms/ImportRowModifierForm.php:32 msgid "" "Please start typing for a list of suggestions. Dots allow you to access " "nested properties: column.some.key. Such nested properties cannot be " @@ -4717,7 +4760,7 @@ msgstr "" "verändert werden, dafür lässt sich der modifizierte Wert aber in eine neue " "\"Zieleigenschaft\" schreiben" -#: application/forms/IcingaCommandForm.php:35 +#: ../../../../application/forms/IcingaCommandForm.php:35 msgid "" "Plugin Check commands are what you need when running checks agains your " "infrastructure. Notification commands will be used when it comes to notify " @@ -4731,284 +4774,300 @@ msgstr "" "für Selbstheilungsmechanismen verwendet, wie das Neustarten von Services " "oder das Neustarten von Systemen beim Überschreiten bestimmter Schwellwerte" -#: application/forms/IcingaCommandForm.php:20 +#: ../../../../application/forms/IcingaCommandForm.php:20 msgid "Plugin commands" msgstr "Plugin-Kommandos" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:50 -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:65 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:50 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:65 msgid "Policy" msgstr "Richtlinie" -#: application/forms/IcingaEndpointForm.php:36 -#: application/forms/KickstartForm.php:145 +#: ../../../../application/forms/IcingaEndpointForm.php:36 +#: ../../../../application/forms/KickstartForm.php:145 msgid "Port" msgstr "Port" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:41 -#: application/forms/IcingaCommandArgumentForm.php:67 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:41 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:67 msgid "Position" msgstr "Position" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:30 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:30 msgid "Position Type" msgstr "Positionstyp" -#: application/controllers/SchemaController.php:17 +#: ../../../../application/controllers/SchemaController.php:17 msgid "PostgreSQL schema" msgstr "PostgreSQL Schema" -#: application/forms/IcingaTimePeriodForm.php:76 +#: ../../../../application/forms/IcingaTimePeriodForm.php:76 msgid "Prefer includes" msgstr "Includes bevorzugen" -#: library/Director/Dashboard/BranchesDashboard.php:24 +#: ../../../../library/Director/Dashboard/BranchesDashboard.php:34 msgid "Prepare your configuration in a safe Environment" msgstr "Bereite Konfiguration in einer geschützten Umgebung vor" -#: library/Director/Dashboard/Dashlet/BasketDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/BasketDashlet.php:19 msgid "Preserve specific configuration objects in a specific state" msgstr "" "Bestimmte Konfigurationsobjekte in einem bestimmten Zustand aufbewahren" -#: library/Director/Web/Tabs/ImportsourceTabs.php:49 -#: library/Director/Web/Tabs/SyncRuleTabs.php:33 -#: library/Director/Web/Tabs/ObjectTabs.php:86 +#: ../../../../library/Director/Web/Tabs/ImportsourceTabs.php:49 +#: ../../../../library/Director/Web/Tabs/SyncRuleTabs.php:33 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:83 msgid "Preview" msgstr "Vorschau" -#: library/Director/IcingaConfig/TypeFilterSet.php:23 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:23 msgid "Problem" msgstr "Problem" -#: library/Director/IcingaConfig/TypeFilterSet.php:27 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:27 msgid "Problem handling" msgstr "Problembehandlung" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:94 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:94 msgid "Process List" msgstr "Prozessliste" -#: library/Director/Web/Form/DirectorObjectForm.php:1452 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1455 msgid "Process performance data" msgstr "Performancedaten verarbeiten" -#: library/Director/Import/ImportSourceLdap.php:70 -#: library/Director/Web/Tabs/SyncRuleTabs.php:39 -#: application/controllers/DataController.php:328 +#: ../../../../library/Director/Import/ImportSourceLdap.php:70 +#: ../../../../library/Director/Web/Tabs/SyncRuleTabs.php:39 +#: ../../../../application/controllers/DataController.php:328 msgid "Properties" msgstr "Eigenschaften" -#: library/Director/PropertyModifier/PropertyModifierGetPropertyFromOtherImportSource.php:61 -#: library/Director/Web/Table/PropertymodifierTable.php:129 -#: library/Director/Web/Table/PropertymodifierTable.php:132 -#: application/forms/ImportRowModifierForm.php:30 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetPropertyFromOtherImportSource.php:61 +#: ../../../../library/Director/Web/Table/PropertymodifierTable.php:129 +#: ../../../../library/Director/Web/Table/PropertymodifierTable.php:132 +#: ../../../../application/forms/ImportRowModifierForm.php:30 msgid "Property" msgstr "Eigenschaft" -#: application/controllers/ImportsourceController.php:251 +#: ../../../../application/controllers/ImportsourceController.php:251 #, php-format msgid "Property modifiers: %s" msgstr "Eigenschaftsmodifikatoren: %s" -#: library/Director/Web/Table/CoreApiFieldsTable.php:88 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:88 msgid "Protected" msgstr "Geschützt" -#: library/Director/Import/ImportSourceRestApi.php:128 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:128 msgid "Protocol" msgstr "Protokoll" -#: application/controllers/InspectController.php:89 +#: ../../../../application/controllers/InspectController.php:89 msgid "Prototypes (methods)" msgstr "Prototypen (Methoden)" -#: library/Director/Dashboard/Dashlet/DatalistDashlet.php:11 +#: ../../../../library/Director/Dashboard/Dashlet/DatalistDashlet.php:13 msgid "Provide Data Lists" msgstr "Datenlisten bereitstellen" -#: library/Director/Dashboard/Dashlet/DatalistDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/DatalistDashlet.php:19 msgid "Provide data lists to make life easier for your users" msgstr "Datenlisten erleichtern Anwendern die Arbeit" -#: library/Director/Dashboard/Dashlet/TimeperiodTemplateDashlet.php:18 +#: ../../../../library/Director/Dashboard/Dashlet/TimeperiodTemplateDashlet.php:20 msgid "Provide templates for your TimePeriod objects." msgstr "Vorlagen für Benachrichtigungen bereitstellen." -#: library/Director/Dashboard/Dashlet/UserTemplateDashlet.php:18 +#: ../../../../library/Director/Dashboard/Dashlet/UserTemplateDashlet.php:20 msgid "Provide templates for your User objects." msgstr "Vorlagen für Benutzer-Objekte bereitstellen." -#: library/Director/Dashboard/Dashlet/NotificationTemplateDashlet.php:18 +#: ../../../../library/Director/Dashboard/Dashlet/NotificationTemplateDashlet.php:20 msgid "Provide templates for your notifications." msgstr "Vorlagen für Benachrichtigungen bereitstellen." -#: library/Director/Import/ImportSourceRestApi.php:244 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:244 msgid "Proxy" msgstr "Proxy" -#: library/Director/Import/ImportSourceRestApi.php:260 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:260 msgid "Proxy Address" msgstr "Proxyadresse" -#: library/Director/Import/ImportSourceRestApi.php:278 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:278 msgid "Proxy Password" msgstr "Proxykennwort" -#: library/Director/Import/ImportSourceRestApi.php:268 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:268 msgid "Proxy Username" msgstr "Proxybenutzer" -#: application/forms/SyncRuleForm.php:70 +#: ../../../../application/forms/SyncRuleForm.php:70 msgid "Purge" msgstr "Bereinigen" -#: application/forms/SyncRuleForm.php:82 +#: ../../../../application/forms/SyncRuleForm.php:82 msgid "Purge Action" msgstr "Aktion beim Bereinigen" -#: library/Director/Web/Tabs/ObjectTabs.php:122 +#: ../../../../library/Director/Import/ImportSourceLab.php:44 +msgid "RAW JSON data" +msgstr "Rohe JSON-Daten" + +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:119 msgid "Ranges" msgstr "Bereiche" -#: application/forms/DeployConfigForm.php:32 +#: ../../../../application/forms/DeployConfigForm.php:32 msgid "Re-deploy now" msgstr "Jetzt erneut ausrollen" -#: application/forms/IcingaServiceForm.php:141 +#: ../../../../application/forms/IcingaServiceForm.php:143 msgid "Reactivate" msgstr "Reaktivieren" -#: library/Director/IcingaConfig/TypeFilterSet.php:24 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:24 msgid "Recovery" msgstr "Erholung" -#: application/forms/IcingaGenerateApiKeyForm.php:22 +#: ../../../../application/forms/IcingaGenerateApiKeyForm.php:22 msgid "Regenerate Self Service API key" msgstr "Selbstbedienungs-API-Schlüssel neu generieren" -#: application/forms/IcingaHostSelfServiceForm.php:56 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:13 +msgid "Regex pattern" +msgstr "Regex-Muster" + +#: ../../../../application/forms/IcingaHostSelfServiceForm.php:56 msgid "Register" msgstr "Registrieren" -#: library/Director/Web/SelfService.php:62 +#: ../../../../library/Director/Web/SelfService.php:62 msgid "Registered Agent" msgstr "Registrierter Agent" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:34 -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:32 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:34 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:32 msgid "Regular Expression" msgstr "Regulärer Ausdruck" -#: library/Director/PropertyModifier/PropertyModifierRegexSplit.php:16 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:41 +msgid "Regular expression based replacement" +msgstr "Ersatz, basierend auf dem regulären Ausdruck" + +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexSplit.php:16 msgid "Regular expression pattern to split the string (e.g. /\\s+/ or /[,;]/)" msgstr "" "Regulärer Ausdruck anhand dessen eine String aufgeteilt werden soll (z.B. /" "\\s+/ oder /[,;]/)" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:58 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:58 msgid "Reject matching elements" msgstr "Übereinstimmende Elemente ablehnen" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:17 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:17 msgid "Reject or keep rows based on property value" msgstr "Die ganze Zeile abhängig vom Eigenschaftswert abweisen" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:72 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:72 msgid "Reject the whole row" msgstr "Verwerfe die ganze Zeile" -#: application/forms/IcingaDependencyForm.php:268 +#: ../../../../application/forms/IcingaDependencyForm.php:268 msgid "Related Objects" msgstr "Verwandte Objekte" -#: library/Director/Web/Widget/ActivityLogInfo.php:532 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:532 msgid "Remark" msgstr "Anmerkung" -#: library/Director/Web/Table/IcingaServiceSetServiceTable.php:225 +#: ../../../../library/Director/Web/Table/IcingaServiceSetServiceTable.php:238 msgid "Remove" msgstr "Entfernen" -#: library/Director/Web/Table/IcingaServiceSetServiceTable.php:227 +#: ../../../../library/Director/Web/Table/IcingaServiceSetServiceTable.php:240 #, php-format msgid "Remove \"%s\" from this host" msgstr "\"%s\" von diesem Host entfernen" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:524 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:524 msgid "Remove this entry" msgstr "Diesen Eintrag entfernen" -#: application/views/helpers/FormDataFilter.php:507 +#: ../../../../application/views/helpers/FormDataFilter.php:507 msgid "Remove this part of your filter" msgstr "Diesen Teil des Filters entfernen" -#: application/forms/DirectorDatafieldForm.php:96 +#: ../../../../application/forms/DirectorDatafieldForm.php:96 msgid "Rename related vars" msgstr "Zugehörige Variablen umbenennen" -#: application/forms/IcingaCommandForm.php:86 +#: ../../../../application/forms/IcingaCommandForm.php:86 msgid "Render as string" msgstr "Als String rendern" -#: application/controllers/ConfigController.php:72 +#: ../../../../application/controllers/ConfigController.php:73 msgid "Render config" msgstr "Konfiguration erstellen" -#: application/forms/IcingaCommandForm.php:77 +#: ../../../../application/forms/IcingaCommandForm.php:77 msgid "Render the command as a plain string instead of an array." msgstr "Rendere das Kommando als reinen String und nicht als Array." -#: application/controllers/ConfigController.php:310 +#: ../../../../application/controllers/ConfigController.php:311 msgid "Rendered file" msgstr "Erzeugte Datei" -#: library/Director/Web/Widget/DeploymentInfo.php:97 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:98 #, php-format msgid "Rendered in %0.2fs, deployed in %0.2fs" msgstr "Erstellt in %0.2fs, ausgerollt in %0.2fs" -#: library/Director/Web/Widget/ActivityLogInfo.php:539 -#: library/Director/Web/Widget/ActivityLogInfo.php:544 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:539 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:544 msgid "Rendering" msgstr "Erstellen" -#: application/forms/IcingaCommandArgumentForm.php:107 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:107 msgid "Repeat key" msgstr "Schlüssel wiederholen" -#: application/forms/SyncRuleForm.php:63 +#: ../../../../application/forms/SyncRuleForm.php:63 msgid "Replace" msgstr "Ersetzen" -#: library/Director/Web/Table/CoreApiFieldsTable.php:86 -#: library/Director/Web/Table/Dependency/DependencyInfoTable.php:38 -#: application/forms/IcingaCommandArgumentForm.php:124 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:21 +msgid "Replacement" +msgstr "Ersatz" + +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:86 +#: ../../../../library/Director/Web/Table/Dependency/DependencyInfoTable.php:38 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:124 msgid "Required" msgstr "Benötigt" -#: library/Director/Import/ImportSourceDirectorObject.php:90 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:90 msgid "Resolved" msgstr "Aufgelöst" -#: application/forms/RestoreBasketForm.php:58 -#: application/controllers/BasketController.php:208 +#: ../../../../application/forms/RestoreBasketForm.php:58 +#: ../../../../application/controllers/BasketController.php:232 msgid "Restore" msgstr "Wiederherstellen" -#: application/forms/RestoreObjectForm.php:17 +#: ../../../../application/forms/RestoreObjectForm.php:17 msgid "Restore former object" msgstr "Vorheriges Objekt wiederherstellen" -#: application/forms/RestoreBasketForm.php:52 +#: ../../../../application/forms/RestoreBasketForm.php:52 msgid "Restore to this target Director DB" msgstr "In dieser Director-Ziel-DB wiederherstellen" -#: library/Director/Web/Form/DirectorObjectForm.php:1380 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1383 msgid "Retry interval" msgstr "Wiederholungsintervall" -#: library/Director/Web/Form/DirectorObjectForm.php:1382 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1385 msgid "" "Retry interval, will be applied after a state change unless the next hard " "state is reached" @@ -5016,49 +5075,53 @@ msgstr "" "Wiederholungsintervall, wird nach einem Statuswechsel verwendet, bis der " "nächste Hard Status erreicht wurde" -#: library/Director/PropertyModifier/PropertyModifierMap.php:34 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMap.php:36 +msgid "Return custom default value" +msgstr "Benutzerdefinierten Wert zurückgeben" + +#: ../../../../library/Director/PropertyModifier/PropertyModifierMap.php:35 msgid "Return lookup key unmodified" msgstr "Suchschlüssel unverändert zurück geben" -#: library/Director/Web/Widget/InspectPackages.php:69 +#: ../../../../library/Director/Web/Widget/InspectPackages.php:69 msgid "Root Zone" msgstr "Rootzone" -#: library/Director/Web/Table/SyncruleTable.php:45 -#: application/forms/SyncRuleForm.php:30 +#: ../../../../library/Director/Web/Table/SyncruleTable.php:45 +#: ../../../../application/forms/SyncRuleForm.php:30 msgid "Rule name" msgstr "Regelname" -#: library/Director/Job/ImportJob.php:119 +#: ../../../../library/Director/Job/ImportJob.php:119 msgid "Run all imports at once" msgstr "Alle Importe gleichzeitig ausführen" -#: library/Director/Job/SyncJob.php:125 +#: ../../../../library/Director/Job/SyncJob.php:125 msgid "Run all rules at once" msgstr "Alle Regeln gleichzeitig ausführen" -#: library/Director/Job/ImportJob.php:92 -#: application/forms/KickstartForm.php:189 +#: ../../../../library/Director/Job/ImportJob.php:92 +#: ../../../../application/forms/KickstartForm.php:189 msgid "Run import" msgstr "Import ausführen" -#: application/forms/DirectorJobForm.php:46 +#: ../../../../application/forms/DirectorJobForm.php:46 msgid "Run interval" msgstr "Laufintervall" -#: application/forms/IcingaServiceForm.php:678 +#: ../../../../application/forms/IcingaServiceForm.php:682 msgid "Run on agent" msgstr "Auf Agent ausführen" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:76 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:76 msgid "Running with systemd" msgstr "Läuft mit systemd" -#: library/Director/Import/ImportSourceRestApi.php:251 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:251 msgid "SOCKS5 proxy" msgstr "SOCKS5 Proxy" -#: library/Director/Dashboard/Dashlet/JobDashlet.php:29 +#: ../../../../library/Director/Dashboard/Dashlet/JobDashlet.php:30 msgid "" "Schedule and automate Import, Syncronization, Config Deployment, " "Housekeeping and more" @@ -5066,12 +5129,12 @@ msgstr "" "Import, Synchronisation, Ausrollen der Konfiguration, Bereinigung und mehr " "planen und automatisieren" -#: library/Director/Dashboard/NotificationsDashboard.php:14 -#: library/Director/Dashboard/UsersDashboard.php:15 +#: ../../../../library/Director/Dashboard/NotificationsDashboard.php:14 +#: ../../../../library/Director/Dashboard/UsersDashboard.php:15 msgid "Schedule your notifications" msgstr "Benachrichtigungen planen" -#: library/Director/Dashboard/Dashlet/NotificationsDashlet.php:19 +#: ../../../../library/Director/Dashboard/Dashlet/NotificationsDashlet.php:21 msgid "" "Schedule your notifications. Define who should be notified, when, and for " "which kind of problem" @@ -5079,16 +5142,16 @@ msgstr "" "Benachrichtigungen planen. Wer soll wann benachrichtigt werden, wofür, und " "für welche Art von Problemen" -#: application/forms/SyncRuleForm.php:23 +#: ../../../../application/forms/SyncRuleForm.php:23 msgid "Scheduled Downtime" msgstr "Geplante Downtime" -#: library/Director/Dashboard/Dashlet/ScheduledDowntimeApplyDashlet.php:13 -#: library/Director/Db/Branch/BranchModificationInspection.php:48 +#: ../../../../library/Director/Dashboard/Dashlet/ScheduledDowntimeApplyDashlet.php:15 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:48 msgid "Scheduled Downtimes" msgstr "Geplante Downtimes" -#: application/forms/SettingsForm.php:177 +#: ../../../../application/forms/SettingsForm.php:177 msgid "" "Script or tool to call when activating a new configuration stage. (e.g. " "sudo /usr/local/bin/icinga-director-activate) (name of the stage will be the " @@ -5098,99 +5161,99 @@ msgstr "" "ausgeführt werden soll. (z.B. sudo /usr/local/bin/icinga-director-activate) " "(der Name der Konfiguration wird dem Skript als Argument mitgegeben)" -#: application/controllers/SettingsController.php:43 -#: application/controllers/SelfServiceController.php:107 +#: ../../../../application/controllers/SettingsController.php:43 +#: ../../../../application/controllers/SelfServiceController.php:107 msgid "Self Service" msgstr "Selbstbedienung" -#: application/controllers/SelfServiceController.php:108 +#: ../../../../application/controllers/SelfServiceController.php:108 msgid "Self Service - Host Registration" msgstr "Selbstbedienung - Host-Registrierung" -#: library/Director/Dashboard/Dashlet/SelfServiceDashlet.php:11 -#: library/Director/Web/SelfService.php:180 +#: ../../../../library/Director/Dashboard/Dashlet/SelfServiceDashlet.php:13 +#: ../../../../library/Director/Web/SelfService.php:167 msgid "Self Service API" msgstr "Selbstbedienungs-API" -#: application/controllers/SettingsController.php:44 +#: ../../../../application/controllers/SettingsController.php:44 msgid "Self Service API - Global Settings" msgstr "Selbstbedienungs-API - Globale Einstellungen" -#: application/forms/SelfServiceSettingsForm.php:298 +#: ../../../../application/forms/SelfServiceSettingsForm.php:298 msgid "Self Service Settings have been stored" msgstr "Selbstbedienungseinstellungen wurden gespeichert" -#: library/Director/Web/Form/DirectorObjectForm.php:1440 -#: application/forms/IcingaUserForm.php:89 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1443 +#: ../../../../application/forms/IcingaUserForm.php:89 msgid "Send notifications" msgstr "Benachrichtigungen senden" -#: library/Director/Web/Widget/DeploymentInfo.php:78 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:79 msgid "Sent to" msgstr "Senden an" -#: library/Director/TranslationDummy.php:14 -#: application/forms/IcingaServiceVarForm.php:15 -#: application/forms/IcingaAddServiceForm.php:104 -#: application/forms/SyncRuleForm.php:14 +#: ../../../../library/Director/TranslationDummy.php:14 +#: ../../../../application/forms/IcingaServiceVarForm.php:15 +#: ../../../../application/forms/SyncRuleForm.php:14 +#: ../../../../application/forms/IcingaAddServiceForm.php:105 msgid "Service" msgstr "Service" -#: library/Director/Dashboard/Dashlet/ServiceApplyRulesDashlet.php:11 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceApplyRulesDashlet.php:13 msgid "Service Apply Rules" msgstr "Service Apply-Regeln" -#: application/forms/SyncRuleForm.php:15 +#: ../../../../application/forms/SyncRuleForm.php:15 msgid "Service Group" msgstr "Servicegruppe" -#: library/Director/Dashboard/Dashlet/ServiceGroupsDashlet.php:11 -#: application/forms/BasketForm.php:23 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceGroupsDashlet.php:13 +#: ../../../../application/forms/BasketForm.php:23 msgid "Service Groups" msgstr "Servicegruppen" -#: library/Director/Web/Table/ObjectsTableService.php:107 +#: ../../../../library/Director/Web/Table/ObjectsTableService.php:107 msgid "Service Name" msgstr "Servicename" -#: library/Director/DataType/DataTypeDirectorObject.php:61 -#: application/forms/SyncRuleForm.php:16 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:61 +#: ../../../../application/forms/SyncRuleForm.php:16 msgid "Service Set" msgstr "Service-Set" -#: application/forms/RemoveLinkForm.php:55 +#: ../../../../application/forms/RemoveLinkForm.php:55 msgid "Service Set has been removed" msgstr "Service-Set wurde entfernt" -#: library/Director/Dashboard/Dashlet/ServiceSetsDashlet.php:11 -#: library/Director/Web/Table/CustomvarVariantsTable.php:60 -#: library/Director/Web/Table/CustomvarTable.php:45 -#: application/forms/BasketForm.php:26 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceSetsDashlet.php:13 +#: ../../../../library/Director/Web/Table/CustomvarVariantsTable.php:60 +#: ../../../../library/Director/Web/Table/CustomvarTable.php:45 +#: ../../../../application/forms/BasketForm.php:26 msgid "Service Sets" msgstr "Service-Sets" -#: application/forms/IcingaAddServiceForm.php:89 +#: ../../../../application/forms/IcingaAddServiceForm.php:90 msgid "Service Template" msgstr "Service-Vorlage" -#: application/forms/BasketForm.php:24 +#: ../../../../application/forms/BasketForm.php:24 msgid "Service Template Choice" msgstr "Auswahlmöglichkeit für Service-Vorlagen" -#: library/Director/Dashboard/Dashlet/ServiceTemplatesDashlet.php:11 -#: application/forms/BasketForm.php:25 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceTemplatesDashlet.php:13 +#: ../../../../application/forms/BasketForm.php:25 msgid "Service Templates" msgstr "Service-Vorlagen" -#: application/forms/SelfServiceSettingsForm.php:179 +#: ../../../../application/forms/SelfServiceSettingsForm.php:179 msgid "Service User" msgstr "Dienst-Benutzeraccount" -#: library/Director/DataType/DataTypeDirectorObject.php:60 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:60 msgid "Service groups" msgstr "Servicegruppen" -#: application/forms/IcingaServiceForm.php:653 +#: ../../../../application/forms/IcingaServiceForm.php:657 msgid "" "Service groups that should be directly assigned to this service. " "Servicegroups can be useful for various reasons. They are helpful to " @@ -5204,116 +5267,128 @@ msgstr "" "Dashboards oder zum Umsetzen von Einschränkungen. Servicegruppen können " "direkt einem einzelnen Service zugeordnet werden oder Service-Vorlagen." -#: library/Director/Web/Table/IcingaHostAppliedForServiceTable.php:102 +#: ../../../../library/Director/Web/Table/IcingaHostAppliedForServiceTable.php:102 msgid "Service name" msgstr "Servicename" -#: library/Director/Objects/IcingaService.php:755 -#: application/controllers/SuggestController.php:260 +#: ../../../../library/Director/Objects/IcingaService.php:668 +#: ../../../../application/controllers/SuggestController.php:260 msgid "Service properties" msgstr "Service-Eigenschaften" -#: application/forms/IcingaServiceSetForm.php:87 -#: application/forms/IcingaAddServiceSetForm.php:86 +#: ../../../../application/forms/IcingaServiceSetForm.php:88 +#: ../../../../application/forms/IcingaAddServiceSetForm.php:86 msgid "Service set" msgstr "Service-Set" -#: application/forms/IcingaServiceSetForm.php:28 +#: ../../../../application/forms/IcingaServiceSetForm.php:29 msgid "Service set name" msgstr "Service-Set Name" -#: application/controllers/TemplatechoiceController.php:25 +#: ../../../../application/controllers/TemplatechoiceController.php:25 msgid "Service template choice" msgstr "Auswahlmöglichkeite für Service-Vorlagen" -#: application/controllers/TemplatechoicesController.php:24 +#: ../../../../application/controllers/TemplatechoicesController.php:24 msgid "Service template choices" msgstr "Auswahlmöglichkeiten für Service-Vorlagen" -#: application/controllers/ServiceController.php:301 +#: ../../../../application/controllers/ServiceController.php:301 msgid "ServiceSet" msgstr "Service-Set" -#: application/forms/IcingaServiceGroupForm.php:14 +#: ../../../../application/forms/IcingaServiceGroupForm.php:14 msgid "Servicegroup" msgstr "Servicegruppe" -#: library/Director/Db/Branch/BranchModificationInspection.php:41 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:41 msgid "Servicegroups" msgstr "Servicegruppen" -#: library/Director/Web/Table/IcingaAppliedServiceTable.php:32 -#: library/Director/Web/Table/ObjectsTableService.php:103 -#: library/Director/Web/Table/IcingaServiceSetServiceTable.php:168 +#: ../../../../library/Director/Web/Table/IcingaServiceSetServiceTable.php:168 +#: ../../../../library/Director/Web/Table/IcingaAppliedServiceTable.php:32 +#: ../../../../library/Director/Web/Table/ObjectsTableService.php:103 msgid "Servicename" msgstr "Servicename" -#: configuration.php:157 -#: library/Director/IcingaConfig/StateFilterSet.php:23 -#: library/Director/DataType/DataTypeDirectorObject.php:59 -#: library/Director/DataType/DataTypeDictionary.php:60 -#: library/Director/Db/Branch/BranchModificationInspection.php:40 -#: library/Director/Web/Table/CustomvarVariantsTable.php:59 -#: library/Director/Web/Table/CustomvarTable.php:44 -#: library/Director/Web/Tabs/ObjectTabs.php:75 -#: application/forms/IcingaNotificationForm.php:90 -#: application/forms/IcingaDependencyForm.php:101 -#: application/forms/IcingaScheduledDowntimeForm.php:90 -#: application/controllers/ServiceController.php:284 -#: application/controllers/ServiceController.php:305 +#: ../../../../configuration.php:125 +#: ../../../../library/Director/IcingaConfig/StateFilterSet.php:23 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:59 +#: ../../../../library/Director/DataType/DataTypeDictionary.php:60 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:40 +#: ../../../../library/Director/Web/Table/CustomvarVariantsTable.php:59 +#: ../../../../library/Director/Web/Table/CustomvarTable.php:44 +#: ../../../../library/Director/Web/Tabs/ObjectTabs.php:74 +#: ../../../../application/forms/IcingaNotificationForm.php:91 +#: ../../../../application/forms/IcingaDependencyForm.php:101 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:90 +#: ../../../../application/controllers/ServiceController.php:284 +#: ../../../../application/controllers/ServiceController.php:305 msgid "Services" msgstr "Services" -#: application/controllers/ServicesetController.php:64 +#: ../../../../application/controllers/ServicesetController.php:64 #, php-format msgid "Services in this set: %s" msgstr "Services in diesem Set: %s" -#: application/controllers/HostController.php:286 +#: ../../../../application/controllers/HostController.php:273 #, php-format msgid "Services on %s" msgstr "Services auf %s" -#: application/controllers/HostController.php:206 +#: ../../../../application/controllers/HostController.php:190 #, php-format msgid "Services: %s" msgstr "Services: %s" -#: library/Director/Db/Branch/BranchModificationInspection.php:42 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:42 msgid "Servicesets" msgstr "Service-Sets" -#: application/forms/SyncPropertyForm.php:84 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSetValue.php:13 +msgid "Set a specific value" +msgstr "Spezifischen Wert setzen" + +#: ../../../../application/forms/ImportRowModifierForm.php:68 +#: ../../../../application/forms/SyncPropertyForm.php:84 msgid "Set based on filter" msgstr "Basierend auf Filter setzen" -#: library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:44 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:44 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSetValue.php:33 msgid "Set false" msgstr "Auf \"false\" setzen" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:30 -#: library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:17 -#: library/Director/PropertyModifier/PropertyModifierParseURL.php:39 -#: library/Director/PropertyModifier/PropertyModifierJsonDecode.php:25 -#: library/Director/PropertyModifier/PropertyModifierDnsRecords.php:34 -#: library/Director/PropertyModifier/PropertyModifierGetHostByName.php:17 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:30 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:17 +#: ../../../../library/Director/PropertyModifier/PropertyModifierParseURL.php:39 +#: ../../../../library/Director/PropertyModifier/PropertyModifierJsonDecode.php:25 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDnsRecords.php:34 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByName.php:17 msgid "Set no value (null)" msgstr "Keinen Wert setzen (null)" -#: library/Director/PropertyModifier/PropertyModifierMap.php:33 -#: library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:42 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMap.php:34 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:42 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSetValue.php:31 msgid "Set null" msgstr "Auf \"null\" setzen" -#: library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:43 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:34 +msgid "Set the value to NULL" +msgstr "Setze den Wert auf NULL" + +#: ../../../../library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:43 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSetValue.php:32 msgid "Set true" msgstr "Auf \"true\" setzen" -#: library/Director/Web/Tabs/ObjectsTabs.php:81 +#: ../../../../library/Director/Web/Tabs/ObjectsTabs.php:83 msgid "Sets" msgstr "Sets" -#: application/forms/IcingaHostForm.php:116 +#: ../../../../application/forms/IcingaHostForm.php:118 msgid "" "Setting a command endpoint allows you to force host checks to be executed by " "a specific endpoint. Please carefully study the related Icinga documentation " @@ -5323,75 +5398,75 @@ msgstr "" "einem bestimmten Endpoint. Bitte nicht verwenden, ohne die entsprechende " "Icinga-Dokumentation gelesen zu haben" -#: library/Director/Web/SelfService.php:97 -#: application/controllers/ConfigController.php:240 +#: ../../../../library/Director/Web/SelfService.php:97 +#: ../../../../application/controllers/ConfigController.php:241 msgid "Settings" msgstr "Einstellungen" -#: application/forms/SettingsForm.php:230 +#: ../../../../application/forms/SettingsForm.php:230 msgid "Settings have been stored" msgstr "Einstellungen wurden gespeichert" -#: library/Director/Web/SelfService.php:90 +#: ../../../../library/Director/Web/SelfService.php:90 msgid "Share this Template for Self Service API" msgstr "Für die Selbstbedienungs-API freigeben" -#: library/Director/Web/SelfService.php:88 +#: ../../../../library/Director/Web/SelfService.php:88 msgid "Shared for Self Service API" msgstr "Für die Selbstbedienungs-API freigegeben" -#: library/Director/PropertyModifier/PropertyModifierUpperCaseFirst.php:21 +#: ../../../../library/Director/PropertyModifier/PropertyModifierUpperCaseFirst.php:21 msgid "Should all the other characters be lowercased first?" msgstr "" "Sollen alle anderen Zeichen zuvor in Kleinbuchstaben umgewandelt werden?" -#: application/controllers/HostController.php:597 +#: ../../../../application/controllers/HostController.php:570 msgid "Show" msgstr "Zeigen" -#: application/controllers/BasketController.php:202 +#: ../../../../application/controllers/BasketController.php:226 msgid "Show Basket" msgstr "Basket anzeigen" -#: application/forms/DeployFormsBug7530.php:101 +#: ../../../../application/forms/DeployFormsBug7530.php:101 #, php-format msgid "Show Issue %s on GitHub" msgstr "Issue %s auf GitHub anzeigen" -#: library/Director/Web/Widget/AdditionalTableActions.php:75 +#: ../../../../library/Director/Web/Widget/AdditionalTableActions.php:76 msgid "Show SQL" msgstr "SQL anzeigen" -#: library/Director/Web/Table/ApplyRulesTable.php:151 +#: ../../../../library/Director/Web/Table/ApplyRulesTable.php:151 msgid "Show affected Objects" msgstr "Betroffene Objekte zeigen" -#: library/Director/Web/Widget/SyncRunDetails.php:97 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:97 msgid "Show all actions" msgstr "Alle Aktionen anzeigen" -#: library/Director/Web/Form/IplElement/ExtensibleSetElement.php:501 +#: ../../../../library/Director/Web/Form/IplElement/ExtensibleSetElement.php:501 msgid "Show available options" msgstr "Verfügbare Optionen anzeigen" -#: application/forms/IcingaObjectFieldForm.php:183 +#: ../../../../application/forms/IcingaObjectFieldForm.php:132 msgid "Show based on filter" msgstr "Basierend auf Filter zeigen" -#: library/Director/Web/Table/BranchActivityTable.php:86 -#: library/Director/Web/Table/ActivityLogTable.php:230 +#: ../../../../library/Director/Web/Table/ActivityLogTable.php:231 +#: ../../../../library/Director/Web/Table/BranchActivityTable.php:87 msgid "Show details related to this change" msgstr "Details zu dieser Änderung zeigen" -#: library/Director/Web/ObjectPreview.php:52 +#: ../../../../library/Director/Web/ObjectPreview.php:52 msgid "Show normal" msgstr "Normal anzeigen" -#: library/Director/Web/ObjectPreview.php:61 +#: ../../../../library/Director/Web/ObjectPreview.php:61 msgid "Show resolved" msgstr "Aufgelöst anzeigen" -#: library/Director/Web/Widget/BranchedObjectsHint.php:23 +#: ../../../../library/Director/Web/Widget/BranchedObjectsHint.php:28 #, php-format msgid "" "Showing a branched view, with potential changes being visible only in this %s" @@ -5399,228 +5474,228 @@ msgstr "" "Zeige eine abgezweigte Ansicht, mit potentiell nur in diesem %s sichtbaren " "Änderungen" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:33 -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:31 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:33 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:31 msgid "Simple match with wildcards (*)" msgstr "Einfache Suche mit Platzhaltern (*)" -#: application/controllers/BasketController.php:343 +#: ../../../../application/controllers/BasketController.php:354 msgid "Single Object Diff" msgstr "Einfacher Objekt-Diff" -#: library/Director/Dashboard/Dashlet/SingleServicesDashlet.php:11 +#: ../../../../library/Director/Dashboard/Dashlet/SingleServicesDashlet.php:13 msgid "Single Services" msgstr "Einzelne Services" -#: library/Director/Web/Table/GeneratedConfigFileTable.php:86 +#: ../../../../library/Director/Web/Table/GeneratedConfigFileTable.php:86 msgid "Size" msgstr "Größe" -#: application/forms/IcingaCommandArgumentForm.php:115 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:115 msgid "Skip key" msgstr "Schlüssel überspringen" -#: library/Director/PropertyModifier/PropertyModifierSkipDuplicates.php:13 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSkipDuplicates.php:13 msgid "Skip row if this value appears more than once" msgstr "Zeile überspringen wenn dieser Wert mehr als einmal vorkommt" -#: application/controllers/BasketController.php:249 -#: application/controllers/BasketController.php:373 +#: ../../../../application/controllers/BasketController.php:272 +#: ../../../../application/controllers/BasketController.php:383 msgid "Snapshot" msgstr "Snapshot" -#: library/Director/Web/Table/BasketTable.php:32 -#: application/controllers/BasketController.php:40 -#: application/controllers/BasketController.php:143 +#: ../../../../library/Director/Web/Table/BasketTable.php:32 +#: ../../../../application/controllers/BasketController.php:38 +#: ../../../../application/controllers/BasketController.php:161 msgid "Snapshots" msgstr "Snapshots" -#: library/Director/Import/ImportSourceRestApi.php:194 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:194 msgid "Something like https://api.example.com/rest/v2/objects" msgstr "So etwas wie https://api.example.com/rest/v2/objects" -#: application/forms/SyncPropertyForm.php:183 +#: ../../../../application/forms/SyncPropertyForm.php:183 msgid "Source Column" msgstr "Quellspalte" -#: application/forms/SyncPropertyForm.php:213 +#: ../../../../application/forms/SyncPropertyForm.php:213 msgid "Source Expression" msgstr "Quellausdruck" -#: application/forms/SyncPropertyForm.php:38 +#: ../../../../application/forms/SyncPropertyForm.php:38 msgid "Source Name" msgstr "Quellenname" -#: application/forms/SelfServiceSettingsForm.php:114 +#: ../../../../application/forms/SelfServiceSettingsForm.php:114 msgid "Source Path" msgstr "Quellpfad" -#: application/forms/ImportSourceForm.php:33 +#: ../../../../application/forms/ImportSourceForm.php:33 msgid "Source Type" msgstr "Quellentyp" -#: application/forms/SyncPropertyForm.php:160 +#: ../../../../application/forms/SyncPropertyForm.php:160 msgid "Source columns" msgstr "Quellspalten" -#: library/Director/Web/Table/SyncpropertyTable.php:62 +#: ../../../../library/Director/Web/Table/SyncpropertyTable.php:62 msgid "Source field" msgstr "Quellenfeld" -#: library/Director/Web/Table/ImportrunTable.php:30 -#: library/Director/Web/Table/ImportsourceTable.php:18 -#: library/Director/Web/Table/SyncpropertyTable.php:61 +#: ../../../../library/Director/Web/Table/ImportrunTable.php:30 +#: ../../../../library/Director/Web/Table/ImportsourceTable.php:18 +#: ../../../../library/Director/Web/Table/SyncpropertyTable.php:61 msgid "Source name" msgstr "Quellenname" -#: application/forms/SyncPropertyForm.php:356 +#: ../../../../application/forms/SyncPropertyForm.php:356 msgid "Special properties" msgstr "Spezielle Eigenschaften" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:36 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:36 msgid "Specific Element (by key name)" msgstr "Spezifisches Element (nach Schlüsselname)" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:35 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:35 msgid "Specific Element (by position)" msgstr "Spezifisches Element (nach Position)" -#: library/Director/Import/ImportSourceRestApi.php:152 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:152 msgid "" "Specify headers in text format \"Header: Value\", each header on a new line." msgstr "" "Header im Textformat angeben \"Header: Wert\", jeden Header auf einer Zeile." -#: library/Director/PropertyModifier/PropertyModifierTrim.php:30 +#: ../../../../library/Director/PropertyModifier/PropertyModifierTrim.php:30 msgid "" -"Specify the characters that trim should remove.Default is: \" " -"\\t\\n\\r\\0\\x0B\"" +"Specify the characters that trim should remove.Default is: \" \\t\\n\\r" +"\\0\\x0B\"" msgstr "" -"Zeichen welche von Trim entfernt werden sollen. Standard: \" " -"\\t\\n\\r\\0\\x0B\"" +"Zeichen welche von Trim entfernt werden sollen. Standard: \" \\t\\n\\r" +"\\0\\x0B\"" -#: library/Director/Web/Widget/DeploymentInfo.php:87 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:88 msgid "Stage name" msgstr "Phasenname" -#: library/Director/Web/Widget/InspectPackages.php:50 +#: ../../../../library/Director/Web/Widget/InspectPackages.php:50 #, php-format msgid "Stages in Package: %s" msgstr "Phasen in Paket: %s" -#: library/Director/Web/Widget/SyncRunDetails.php:28 +#: ../../../../library/Director/Web/Widget/SyncRunDetails.php:28 msgid "Start time" msgstr "Startzeit" -#: library/Director/Web/Widget/DeploymentInfo.php:88 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:89 msgid "Startup" msgstr "Start" -#: library/Director/Web/Widget/DeploymentInfo.php:162 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:163 msgid "Startup Log" msgstr "Start-Log" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:72 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:72 msgid "Startup Time" msgstr "Startzeit" -#: library/Director/Web/Table/CoreApiFieldsTable.php:84 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:84 msgid "State" msgstr "Zustand" -#: library/Director/Web/Form/DirectorObjectForm.php:1688 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1691 msgid "State and transition type filters" msgstr "Status- und Übergangstypen-Filter" -#: library/Director/IcingaConfig/TypeFilterSet.php:22 +#: ../../../../library/Director/IcingaConfig/TypeFilterSet.php:22 msgid "State changes" msgstr "Zustandsänderungen" -#: library/Director/Web/Form/DirectorObjectForm.php:1663 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1666 msgid "States" msgstr "Zustände" -#: library/Director/Web/Widget/DeployedConfigInfoHeader.php:91 +#: ../../../../library/Director/Web/Widget/DeployedConfigInfoHeader.php:91 msgid "Statistics" msgstr "Statistiken" -#: application/controllers/InspectController.php:42 -#: application/controllers/InspectController.php:143 +#: ../../../../application/controllers/InspectController.php:42 +#: ../../../../application/controllers/InspectController.php:143 msgid "Status" msgstr "Zustand" -#: library/Director/Web/SelfService.php:127 +#: ../../../../library/Director/Web/SelfService.php:127 msgid "Stop sharing this Template" msgstr "Diese Vorlage nicht mehr bereitstellen" -#: library/Director/Web/Form/DirectorObjectForm.php:508 -#: application/forms/SettingsForm.php:139 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:509 +#: ../../../../application/forms/SettingsForm.php:139 msgid "Store" msgstr "Speichern" -#: application/forms/KickstartForm.php:36 +#: ../../../../application/forms/KickstartForm.php:36 msgid "Store configuration" msgstr "Konfiguration speichern" -#: library/Director/DataType/DataTypeDatalist.php:152 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:152 msgid "Strict, list values only" msgstr "Strikt, nur Listeneinträge" -#: library/Director/DataType/DataTypeDirectorObject.php:79 -#: library/Director/DataType/DataTypeSqlQuery.php:76 -#: library/Director/DataType/DataTypeDatalist.php:132 -#: application/forms/IcingaCommandArgumentForm.php:38 -#: application/forms/IcingaCommandArgumentForm.php:77 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:79 +#: ../../../../library/Director/DataType/DataTypeSqlQuery.php:76 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:132 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:38 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:77 msgid "String" msgstr "Zeichenkette" -#: application/views/helpers/FormDataFilter.php:534 +#: ../../../../application/views/helpers/FormDataFilter.php:534 msgid "Strip this operator, preserve child nodes" msgstr "Diesen Operator entfernen, Kind-Knoten beibehalten" -#: library/Director/Web/Form/QuickForm.php:221 +#: ../../../../library/Director/Web/Form/QuickForm.php:221 msgid "Submit" msgstr "Absenden" -#: library/Director/Web/Widget/DeploymentInfo.php:139 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:140 msgid "Succeeded" msgstr "Gelungen" -#: application/forms/IcingaObjectFieldForm.php:94 +#: ../../../../library/Director/Field/FormFieldSuggestion.php:78 msgid "Suggested fields" msgstr "Vorgeschlagene Felder" -#: library/Director/Web/ActionBar/TemplateActionBar.php:37 +#: ../../../../library/Director/Web/ActionBar/TemplateActionBar.php:37 msgid "Switch to Table view" msgstr "Zur Tabellenansicht wechseln" -#: library/Director/Web/ActionBar/TemplateActionBar.php:36 +#: ../../../../library/Director/Web/ActionBar/TemplateActionBar.php:36 msgid "Switch to Tree view" msgstr "Zur Baumansicht wechseln" -#: application/controllers/SyncruleController.php:621 +#: ../../../../application/controllers/SyncruleController.php:619 #, php-format msgid "Sync \"%s\": %s" msgstr "\"%s\": \"%s\" synchronisieren" -#: application/controllers/BranchController.php:45 -#: application/controllers/SyncruleController.php:203 +#: ../../../../application/controllers/BranchController.php:44 +#: ../../../../application/controllers/SyncruleController.php:203 msgid "Sync Preview" msgstr "Synchronisationsvorschau" -#: application/controllers/SyncruleController.php:155 +#: ../../../../application/controllers/SyncruleController.php:155 msgid "Sync Properties" msgstr "Synchronisationseigenschaften" -#: application/forms/BasketForm.php:36 +#: ../../../../application/forms/BasketForm.php:36 msgid "Sync Rules" msgstr "Synchronisationsregeln" -#: application/controllers/SyncruleController.php:653 +#: ../../../../application/controllers/SyncruleController.php:651 msgid "Sync history" msgstr "Synchronisationshistorie" -#: application/forms/SyncRuleForm.php:98 +#: ../../../../application/forms/SyncRuleForm.php:98 #, php-format msgid "" "Sync only part of your imported objects with this rule. Icinga Web 2 filter " @@ -5629,139 +5704,139 @@ msgstr "" "Nur einen Teil der importierten Objekte mit dieser Regel synchronisieren. " "Die Icinga Web 2 Filter Syntax kann verwendet werden. z.B: %s" -#: application/controllers/SyncruleController.php:585 +#: ../../../../application/controllers/SyncruleController.php:584 msgid "Sync properties" msgstr "Synchronisationseigenschaften" -#: library/Director/Web/Tabs/SyncRuleTabs.php:29 -#: library/Director/Web/Tabs/SyncRuleTabs.php:50 -#: library/Director/Web/Tabs/ImportTabs.php:23 -#: application/controllers/SyncrulesController.php:25 -#: application/controllers/SyncruleController.php:544 +#: ../../../../library/Director/Web/Tabs/SyncRuleTabs.php:29 +#: ../../../../library/Director/Web/Tabs/SyncRuleTabs.php:50 +#: ../../../../library/Director/Web/Tabs/ImportTabs.php:23 +#: ../../../../application/controllers/SyncrulesController.php:25 +#: ../../../../application/controllers/SyncruleController.php:543 msgid "Sync rule" msgstr "Synchronisationsregel" -#: application/controllers/SyncruleController.php:55 -#: application/controllers/SyncruleController.php:509 +#: ../../../../application/controllers/SyncruleController.php:55 +#: ../../../../application/controllers/SyncruleController.php:509 #, php-format msgid "Sync rule: %s" msgstr "Synchronisationsregel: %s" -#: application/forms/SyncRunForm.php:35 +#: ../../../../application/forms/SyncRunForm.php:35 #, php-format msgid "Sync to Branch: %s" msgstr "" "In Branch s\n" "ynchronisieren: %s" -#: application/controllers/SyncruleController.php:63 +#: ../../../../application/controllers/SyncruleController.php:63 msgid "Synchronization failed" msgstr "Synchronisation fehlgeschlagen" -#: library/Director/Job/SyncJob.php:80 +#: ../../../../library/Director/Job/SyncJob.php:80 msgid "Synchronization rule" msgstr "Synchronisationsregel" -#: library/Director/Dashboard/Dashlet/SyncDashlet.php:14 +#: ../../../../library/Director/Dashboard/Dashlet/SyncDashlet.php:15 msgid "Synchronize" msgstr "Synchronisieren" -#: application/controllers/SyncruleController.php:128 +#: ../../../../application/controllers/SyncruleController.php:128 #, php-format msgid "Synchronizing '%s'" msgstr "'%s' synchronisieren" -#: library/Director/Web/ActionBar/TemplateActionBar.php:30 +#: ../../../../library/Director/Web/ActionBar/TemplateActionBar.php:30 msgid "Table" msgstr "Tabelle" -#: application/forms/RestoreBasketForm.php:51 +#: ../../../../application/forms/RestoreBasketForm.php:51 msgid "Target DB" msgstr "Ziel-DB" -#: application/forms/IcingaCloneObjectForm.php:87 +#: ../../../../application/forms/IcingaCloneObjectForm.php:89 msgid "Target Host" msgstr "Zielhost" -#: application/forms/IcingaCloneObjectForm.php:78 +#: ../../../../application/forms/IcingaCloneObjectForm.php:80 msgid "Target Service Set" msgstr "Ziel-Service-Set" -#: library/Director/DataType/DataTypeDirectorObject.php:77 -#: library/Director/DataType/DataTypeSqlQuery.php:74 -#: library/Director/DataType/DataTypeDatalist.php:130 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:77 +#: ../../../../library/Director/DataType/DataTypeSqlQuery.php:74 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:130 msgid "Target data type" msgstr "Zieldatentyp" -#: application/forms/ImportRowModifierForm.php:42 +#: ../../../../application/forms/ImportRowModifierForm.php:42 msgid "Target property" msgstr "Zieleigenschaft" -#: library/Director/DataType/DataTypeDictionary.php:86 -#: library/Director/Web/Form/DirectorObjectForm.php:1111 -#: library/Director/Web/Form/DirectorObjectForm.php:1115 -#: library/Director/Web/Controller/TemplateController.php:159 +#: ../../../../library/Director/DataType/DataTypeDictionary.php:86 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1114 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1118 +#: ../../../../library/Director/Web/Controller/TemplateController.php:160 msgid "Template" msgstr "Vorlage" -#: library/Director/DataType/DataTypeDictionary.php:64 +#: ../../../../library/Director/DataType/DataTypeDictionary.php:64 msgid "Template (Object) Type" msgstr "Vorlagentyp (Objekt)" -#: library/Director/Web/Table/TemplatesTable.php:52 +#: ../../../../library/Director/Web/Table/TemplatesTable.php:52 msgid "Template Name" msgstr "Vorlagenname" -#: application/forms/IcingaScheduledDowntimeForm.php:16 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:16 msgid "Template name" msgstr "Vorlagenname" -#: library/Director/Web/Controller/ObjectController.php:348 -#: library/Director/Web/Controller/TemplateController.php:116 +#: ../../../../library/Director/Web/Controller/TemplateController.php:117 +#: ../../../../library/Director/Web/Controller/ObjectController.php:351 #, php-format msgid "Template: %s" msgstr "Vorlage: %s" -#: library/Director/Import/ImportSourceDirectorObject.php:82 -#: library/Director/Web/Tree/TemplateTreeRenderer.php:43 -#: library/Director/Web/Table/DependencyTemplateUsageTable.php:10 -#: library/Director/Web/Table/NotificationTemplateUsageTable.php:10 -#: library/Director/Web/Table/HostTemplateUsageTable.php:10 -#: library/Director/Web/Table/TemplateUsageTable.php:23 -#: library/Director/Web/Table/ServiceTemplateUsageTable.php:10 -#: library/Director/Web/Tabs/ObjectsTabs.php:58 -#: application/forms/IcingaServiceForm.php:710 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:82 +#: ../../../../library/Director/Web/Tree/TemplateTreeRenderer.php:43 +#: ../../../../library/Director/Web/Table/DependencyTemplateUsageTable.php:10 +#: ../../../../library/Director/Web/Table/TemplateUsageTable.php:23 +#: ../../../../library/Director/Web/Table/NotificationTemplateUsageTable.php:10 +#: ../../../../library/Director/Web/Table/HostTemplateUsageTable.php:10 +#: ../../../../library/Director/Web/Table/ServiceTemplateUsageTable.php:10 +#: ../../../../library/Director/Web/Tabs/ObjectsTabs.php:60 +#: ../../../../application/forms/IcingaServiceForm.php:714 msgid "Templates" msgstr "Vorlagen" -#: application/forms/IcingaCloneObjectForm.php:32 +#: ../../../../application/forms/IcingaCloneObjectForm.php:34 msgid "Templates cannot be cloned in Configuration Branches" msgstr "Vorlagen können in Konfigurationszweigen nicht geklont werden" -#: application/forms/DeployFormsBug7530.php:116 +#: ../../../../application/forms/DeployFormsBug7530.php:116 msgid "Thanks, I'll verify this and come back later" msgstr "Danke, ich überprüfe das und komme wieder" -#: library/Director/Job/ImportJob.php:67 +#: ../../../../library/Director/Job/ImportJob.php:67 msgid "The \"Import\" job allows to run import actions at regular intervals" msgstr "" "Der \"Import\" Auftrag erlaubt das Ausführen von Importen in regelmäßigen " "Abständen" -#: library/Director/Job/SyncJob.php:65 +#: ../../../../library/Director/Job/SyncJob.php:65 msgid "The \"Sync\" job allows to run sync actions at regular intervals" msgstr "" "Der \"Sync\" Auftrag erlaubt das Ausführen von Synchronisationen in " "regelmäßigen Abständen" -#: library/Director/Web/Form/DirectorObjectForm.php:661 -#: application/forms/IcingaTimePeriodRangeForm.php:84 -#: application/forms/IcingaScheduledDowntimeRangeForm.php:89 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:664 +#: ../../../../application/forms/IcingaTimePeriodRangeForm.php:84 +#: ../../../../application/forms/IcingaScheduledDowntimeRangeForm.php:89 #, php-format msgid "The %s has successfully been stored" msgstr "%s wurde erfolgreich gespeichert" -#: library/Director/Job/ConfigJob.php:71 +#: ../../../../library/Director/Job/ConfigJob.php:71 msgid "" "The Config job allows you to generate and eventually deploy your Icinga 2 " "configuration" @@ -5769,11 +5844,11 @@ msgstr "" "Der Auftrag \"Konfiguration\" erlaubt das Erstellen und eventuelle Ausrollen " "der Icinga 2 Konfiguration" -#: application/forms/IcingaUserForm.php:37 +#: ../../../../application/forms/IcingaUserForm.php:37 msgid "The Email address of the user." msgstr "Die E-Mail-Adresse des Benutzers." -#: library/Director/Job/HousekeepingJob.php:21 +#: ../../../../library/Director/Job/HousekeepingJob.php:21 msgid "" "The Housekeeping job provides various task that keep your Director database " "fast and clean" @@ -5781,7 +5856,7 @@ msgstr "" "Der \"Bereinigen\" Auftrag bietet verschiedene Aktionen, die die Director-" "Datenbank schnell und sauber halten" -#: application/controllers/DaemonController.php:39 +#: ../../../../application/controllers/DaemonController.php:39 #, php-format msgid "" "The Icinga Director Background Daemon is not running. Please check our %s in " @@ -5790,7 +5865,7 @@ msgstr "" "Der Icinga Director Hintergrunddienst läuft nicht. Um eine Schritt-für-" "Schritt-Anleitung hierzu anzuzeigen bitte unsere %s zu Rate ziehen." -#: application/controllers/SettingsController.php:38 +#: ../../../../application/controllers/SettingsController.php:38 msgid "" "The Icinga Director Self Service API allows your Hosts to register " "themselves. This allows them to get their Icinga Agent configured, installed " @@ -5800,7 +5875,7 @@ msgstr "" "registrieren. Auf diese Weise wird deren Icinga-Agent konfiguriert, " "installiert und automatisch aktualisiert." -#: application/forms/SettingsForm.php:45 +#: ../../../../application/forms/SettingsForm.php:45 msgid "" "The Icinga Package name Director uses to deploy it's configuration. This " "defaults to \"director\" and should not be changed unless you really know " @@ -5810,7 +5885,7 @@ msgstr "" "Konfiguration benutzt. Für gewöhnlich ist das \"director\" und sollte nur " "geändert werden, wenn die Auswirkung dieser Anpassung bewusst ist" -#: library/Director/Import/ImportSourceLdap.php:72 +#: ../../../../library/Director/Import/ImportSourceLdap.php:72 msgid "" "The LDAP properties that should be fetched. This is required to be a comma-" "separated list like: \"cn, dnshostname, operatingsystem, sAMAccountName\"" @@ -5818,35 +5893,32 @@ msgstr "" "Die LDAP Eigenschaften, die geholt werden sollen. Muss eine Komma-separierte " "Liste sein, wie \"cn, dnshostname, operatingsystem, sAMAccountName\"" -#: application/forms/IcingaForgetApiKeyForm.php:31 +#: ../../../../application/forms/IcingaForgetApiKeyForm.php:31 #, php-format msgid "The Self Service API key for %s has been dropped" msgstr "Der Selbstbedienungs-API-Schlüssel für %s wurde verworfen" -#: application/forms/IcingaAddServiceSetForm.php:116 +#: ../../../../application/forms/IcingaAddServiceSetForm.php:116 #, php-format msgid "The Service Set \"%s\" has been added to %d hosts" msgstr "Das Service-Set \"%s\" wurde zu %d Hosts hinzugefügt" -#: application/forms/IcingaCommandArgumentForm.php:173 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:173 #, php-format msgid "The argument %s has successfully been stored" msgstr "Das Argument %s wurde erfolgreich gespeichert" -#: application/forms/IcingaObjectFieldForm.php:129 -msgid "The caption which should be displayed" -msgstr "Die Beschriftung, die angezeigt werden soll" - -#: application/forms/DirectorDatafieldForm.php:153 +#: ../../../../application/forms/DirectorDatafieldForm.php:152 +#: ../../../../application/forms/IcingaObjectFieldForm.php:88 msgid "" "The caption which should be displayed to your users when this field is shown" msgstr "Die Beschriftung welche Benutzern zu diesem Feld angezeigt werden soll" -#: application/forms/IcingaDependencyForm.php:234 +#: ../../../../application/forms/IcingaDependencyForm.php:234 msgid "The child host." msgstr "Der Kind-Host." -#: application/forms/IcingaCommandForm.php:61 +#: ../../../../application/forms/IcingaCommandForm.php:61 msgid "" "The command Icinga should run. Absolute paths are accepted as provided, " "relative paths are prefixed with \"PluginDir + \", similar Constant prefixes " @@ -5861,65 +5933,65 @@ msgstr "" "bedeutet, das aktuell keine Leerzeichen in Plugin-Namen und Pfaden " "unterstützt werden." -#: application/forms/KickstartForm.php:165 +#: ../../../../application/forms/KickstartForm.php:165 msgid "The corresponding password" msgstr "Das entsprechende Passwort" -#: library/Director/PropertyModifier/PropertyModifierStripDomain.php:14 +#: ../../../../library/Director/PropertyModifier/PropertyModifierStripDomain.php:14 msgid "The domain name you want to be stripped" msgstr "Der Domänenname, der entfernt werden soll" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:18 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:18 msgid "The first (leftmost) CN" msgstr "Der erste (linkeste) CN" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:19 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:19 msgid "The first (leftmost) OU" msgstr "Die erste (linkeste) OU" -#: library/Director/Web/Controller/ObjectController.php:718 -#: application/controllers/ConfigController.php:443 +#: ../../../../library/Director/Web/Controller/ObjectController.php:729 +#: ../../../../application/controllers/ConfigController.php:444 #, php-format msgid "The following modifications are visible in this %s only..." msgstr "Die folgenden Änderungen sind nur in diesem %s sichtbar..." -#: application/forms/IcingaServiceForm.php:767 +#: ../../../../application/forms/IcingaServiceForm.php:771 #, php-format msgid "The given properties have been stored for \"%s\"" msgstr "Die übergebenen Eigenschaften wurden für \"%s\" gespeichert" -#: library/Director/Web/Form/DirectorObjectForm.php:1666 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1669 msgid "The host/service states you want to get notifications for" msgstr "" "Die Host/Service Status, für die Benachrichtigungen versandt werden sollen" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:21 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:21 msgid "The last (rightmost) OU" msgstr "Die letzte (rechteste) OU" -#: library/Director/Web/Widget/JobDetails.php:60 +#: ../../../../library/Director/Web/Widget/JobDetails.php:60 #, php-format msgid "The last attempt failed %s: %s" msgstr "Der letzte Versuch schlug %s fehl: %s" -#: library/Director/Web/Widget/JobDetails.php:55 +#: ../../../../library/Director/Web/Widget/JobDetails.php:55 #, php-format msgid "The last attempt succeeded %s" msgstr "Der letzte Versuch war %s erfolgreich" -#: library/Director/Dashboard/Dashlet/DeploymentDashlet.php:83 +#: ../../../../library/Director/Dashboard/Dashlet/DeploymentDashlet.php:84 msgid "The last deployment did not succeed" msgstr "Das letzte Ausrollen war nicht erfolgreich" -#: library/Director/Dashboard/Dashlet/DeploymentDashlet.php:85 +#: ../../../../library/Director/Dashboard/Dashlet/DeploymentDashlet.php:86 msgid "The last deployment is currently pending" msgstr "Das Ausrollen der Konfiguration ist im Gange" -#: application/forms/IcingaEndpointForm.php:42 +#: ../../../../application/forms/IcingaEndpointForm.php:42 msgid "The log duration time." msgstr "Die Dauer der Aufzeichnungen." -#: application/forms/IcingaUserForm.php:160 +#: ../../../../application/forms/IcingaUserForm.php:160 msgid "" "The name of a time period which determines when notifications to this User " "should be triggered. Not set by default." @@ -5927,8 +5999,8 @@ msgstr "" "Der Name des Zeitraumes, der angibt, wann Benachrichtigungen für diesen " "Benutzer ausgelöst werden sollen. Kein Default-Wert." -#: application/forms/IcingaNotificationForm.php:242 -#: application/forms/IcingaDependencyForm.php:143 +#: ../../../../application/forms/IcingaNotificationForm.php:290 +#: ../../../../application/forms/IcingaDependencyForm.php:143 msgid "" "The name of a time period which determines when this notification should be " "triggered. Not set by default." @@ -5936,7 +6008,7 @@ msgstr "" "Der Name des Zeitraumes, der angibt, wann diese Benachrichtigung ausgelöst " "werden soll. Kein Default-Wert." -#: library/Director/Web/Form/DirectorObjectForm.php:1418 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1421 msgid "" "The name of a time period which determines when this object should be " "monitored. Not limited by default." @@ -5944,7 +6016,7 @@ msgstr "" "Der Name des Zeitraumes, der angibt, wann dieses Objekt überwacht wird. " "Standardmäßig nicht eingeschränkt." -#: application/forms/DirectorJobForm.php:62 +#: ../../../../application/forms/DirectorJobForm.php:62 msgid "" "The name of a time period within this job should be active. Supports only " "simple time periods (weekday and multiple time definitions)" @@ -5952,15 +6024,15 @@ msgstr "" "Der Name des Zeitraums innerhalb derer dieser Auftrag aktiv sein soll. " "Erlaubt nur einfache Zeiträume (Wochentag und mehrere Zeitangaben)" -#: application/forms/IcingaHostVarForm.php:16 +#: ../../../../application/forms/IcingaHostVarForm.php:16 msgid "The name of the host" msgstr "Der Name des Hosts" -#: application/forms/IcingaServiceVarForm.php:16 +#: ../../../../application/forms/IcingaServiceVarForm.php:16 msgid "The name of the service" msgstr "Der Name des Service" -#: application/forms/IcingaNotificationForm.php:178 +#: ../../../../application/forms/IcingaNotificationForm.php:226 msgid "" "The notification interval (in seconds). This interval is used for active " "notifications. Defaults to 30 minutes. If set to 0, re-notifications are " @@ -5970,7 +6042,7 @@ msgstr "" "aktive Benachrichtigungen verwendet. Default-Wert ist 30 Minuten. Wird er " "auf 0 gesetzt, sind Benachrichtungswiederholungen deaktiviert." -#: library/Director/PropertyModifier/PropertyModifierBitmask.php:16 +#: ../../../../library/Director/PropertyModifier/PropertyModifierBitmask.php:16 msgid "" "The numeric bitmask you want to apply. In case you have a hexadecimal or " "binary mask please transform it to a decimal number first. The result of " @@ -5982,11 +6054,11 @@ msgstr "" "Ergebnis ist ein boolescher Wert welcher angibt, ob die Maske auf den " "numerischen Wert in der Quellspalte zutrifft" -#: application/forms/IcingaUserForm.php:42 +#: ../../../../application/forms/IcingaUserForm.php:42 msgid "The pager address of the user." msgstr "Die Pageradresse des Benutzers." -#: application/forms/IcingaDependencyForm.php:202 +#: ../../../../application/forms/IcingaDependencyForm.php:202 msgid "" "The parent host. You might want to refer Host Custom Variables via $host." "vars.varname$" @@ -5994,7 +6066,7 @@ msgstr "" "Der Elternhost. Benutzerdefinierte Hosteigenschaften lassen sich via $host." "vars.varname$ referenzieren" -#: library/Director/PropertyModifier/PropertyModifierRegexReplace.php:15 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:15 msgid "" "The pattern you want to search for. This can be a regular expression like /" "^www\\d+\\./" @@ -6002,11 +6074,11 @@ msgstr "" "Das Muster, nach dem gesucht werden soll. Kann ein regulärer Ausdruck wie /" "^www\\d+\\./ sein" -#: application/forms/IcingaEndpointForm.php:37 +#: ../../../../application/forms/IcingaEndpointForm.php:37 msgid "The port of the endpoint." msgstr "Der Port des Endpunkts." -#: application/forms/KickstartForm.php:148 +#: ../../../../application/forms/KickstartForm.php:148 msgid "" "The port you are going to use. The default port 5665 will be used if none is " "set" @@ -6014,48 +6086,48 @@ msgstr "" "Der Port, der genutzt werden soll. Wird kein Wert gesetzt, gilt der Default-" "Wert 5665" -#: library/Director/PropertyModifier/PropertyModifierGetPropertyFromOtherImportSource.php:64 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetPropertyFromOtherImportSource.php:64 msgid "The property to get from the row we found in the chosen Import Source" msgstr "" "Die Eigenschaft welche wir aus der Zeile die wir in der gewählten " "Importquelle gefunden haben extrahieren wollen" -#: application/forms/IcingaAddServiceForm.php:176 +#: ../../../../application/forms/IcingaAddServiceForm.php:177 #, php-format msgid "The service \"%s\" has been added to %d hosts" msgstr "Der Service \"%s\" wurde zu %d Hosts hinzugefügt" -#: application/forms/IcingaAddServiceSetForm.php:88 +#: ../../../../application/forms/IcingaAddServiceSetForm.php:88 msgid "The service Set that should be assigned" msgstr "Das Service-Set welches zugewiesen werden soll" -#: application/forms/IcingaServiceSetForm.php:89 +#: ../../../../application/forms/IcingaServiceSetForm.php:90 msgid "The service set that should be assigned to this host" msgstr "Das Service-Set welches diesem Host zugewiesen werden soll" -#: library/Director/Web/Form/DirectorObjectForm.php:1676 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1679 msgid "The state transition types you want to get notifications for" msgstr "" "Die Arten von Statusänderungen, für die Benachrichtigungen verschickt werden " "sollen" -#: library/Director/PropertyModifier/PropertyModifierRegexReplace.php:23 -msgid "The string that should be used as a preplacement" +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:23 +msgid "The string that should be used as a replacement" msgstr "Die Zeichenkette, die als Ersatz genutzt werden soll" -#: library/Director/PropertyModifier/PropertyModifierReplace.php:14 +#: ../../../../library/Director/PropertyModifier/PropertyModifierReplace.php:14 msgid "The string you want to search for" msgstr "Die Zeichenkette, nach der gesucht werden soll" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:56 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:56 msgid "" -"The string/pattern you want to search for, use regular expression like /" -"^www\\d+\\./" +"The string/pattern you want to search for, use regular expression like /^www" +"\\d+\\./" msgstr "" "Das Muster, nach dem gesucht werden soll. Kann ein regulärer Ausdruck wie /" "^www\\d+\\./ sein" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:46 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:46 msgid "" "The string/pattern you want to search for, use wildcard matches like www.* " "or *linux*" @@ -6063,7 +6135,7 @@ msgstr "" "Das Muster, nach dem gesucht werden soll, Platzhalter wie www.* oder *linux* " "sind möglich" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:41 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:41 msgid "" "The string/pattern you want to search for. Depends on the chosen method, use " "www.* or *linux* for wildcard matches and expression like /^www\\d+\\./ in " @@ -6074,79 +6146,70 @@ msgstr "" "Suchen und Ausdrücken wie /^www\\d+\\./ falls Reguläre Ausdrücke bevorzugt " "wurden" -#: application/forms/DirectorDatafieldCategoryForm.php:25 +#: ../../../../application/forms/DirectorDatafieldCategoryForm.php:25 msgid "" "The unique name of the category used for grouping your custom Data Fields." msgstr "" "Der eindeutige Kategoriebezeichner welcher zum Gruppieren der " "benutzerdefinierten Felder benutzt werden soll." -#: application/forms/DirectorDatafieldForm.php:143 -msgid "" -"The unique name of the field. This will be the name of the custom variable " -"in the rendered Icinga configuration." -msgstr "" -"Der eindeutige Bezeichner dieses Feldes. Dieser wird als Name der " -"benutzerdefinierten Eigenschaft in der gerenderten Icinga-Konfiguration " -"benutzt." - -#: application/forms/SelfServiceSettingsForm.php:181 +#: ../../../../application/forms/SelfServiceSettingsForm.php:181 msgid "The user that should run the Icinga 2 service on Windows." msgstr "" "Der Benutzeraccount unter welchem der Icinga-2-Dienst unter Windows laufen " "soll." -#: application/forms/DirectorDatafieldForm.php:74 +#: ../../../../application/forms/DirectorDatafieldForm.php:74 #, php-format msgid "" -"There are %d objects with a related property. Should I also remove the " -"\"%s\" property from them?" +"There are %d objects with a related property. Should I also remove the \"%s" +"\" property from them?" msgstr "" "Es gibt %d Objekte mit einer entsprechenden Eigenschaft. Soll der Wert für " "\"%s\" von all diesen entfernt werden?" -#: application/forms/DirectorDatafieldForm.php:118 +#: ../../../../application/forms/DirectorDatafieldForm.php:118 #, php-format msgid "" -"There are %d objects with a related property. Should I also rename the " -"\"%s\" property to \"%s\" on them?" +"There are %d objects with a related property. Should I also rename the \"%s" +"\" property to \"%s\" on them?" msgstr "" "Es gibt %d Objekte mit einer entsprechenden Eigenschaft. Soll auf all diesen " "die Variable \"%s\" nach \"%s\" umbenannt werden?" -#: application/forms/DeploymentLinkForm.php:66 +#: ../../../../application/forms/DeploymentLinkForm.php:67 #, php-format msgid "There are %d pending changes" msgstr "Es gibt %d noch nicht ausgerollte Änderungen" -#: application/forms/DeploymentLinkForm.php:79 +#: ../../../../application/forms/DeploymentLinkForm.php:80 #, php-format msgid "There are %d pending changes, %d of them applied to this object" msgstr "" "Es sind %d Änderungen ausständig, wovon %d auf dieses Objekt angewendet " "werden" -#: library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:90 +#: ../../../../library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php:90 #, php-format msgid "There are %d pending database migrations" msgstr "Es sind %d Datenbankmigrationen ausständig" -#: application/forms/IcingaObjectFieldForm.php:117 +#: ../../../../application/forms/IcingaObjectFieldForm.php:75 msgid "" "There are no data fields available. Please ask an administrator to create " "such" msgstr "" "Es sind keine Datenfelder verfügbar. Ein Administrator kann welche anlegen" -#: library/Director/Dashboard/Dashlet/DeploymentDashlet.php:91 +#: ../../../../library/Director/Dashboard/Dashlet/DeploymentDashlet.php:92 msgid "There are no pending changes" msgstr "Es gibt keine anstehenden Änderungen" -#: application/forms/DeployConfigForm.php:34 +#: ../../../../application/forms/DeployConfigForm.php:34 msgid "There are no pending changes. Deploy anyway" msgstr "Es gibt keine anstehenden Änderungen. Dennoch ausrollen" -#: library/Director/Web/Widget/ImportSourceDetails.php:52 +#: ../../../../library/Director/Web/Widget/ImportSourceDetails.php:52 msgid "" "There are pending changes for this Import Source. You should trigger a new " "Import Run." @@ -6154,7 +6217,7 @@ msgstr "" "Es gibt ausstehende Änderungen für diese Importquelle. Ein neuer Importlauf " "sollte angestoßen werden." -#: application/controllers/SyncruleController.php:108 +#: ../../../../application/controllers/SyncruleController.php:108 msgid "" "There are pending changes for this Sync Rule. You should trigger a new Sync " "Run." @@ -6162,18 +6225,18 @@ msgstr "" "Es gibt ausstehende Änderungen für diese Synchronisationsregel. Ein neuer " "Synchronisationslauf sollte angestoßen werden." -#: application/forms/KickstartForm.php:66 +#: ../../../../application/forms/KickstartForm.php:66 msgid "There are pending database migrations" msgstr "Es sind Datenbankmigrationen ausständig" -#: application/forms/DeploymentLinkForm.php:71 +#: ../../../../application/forms/DeploymentLinkForm.php:72 msgid "" "There has been a single change to this object, nothing else has been modified" msgstr "" "An diesem Objekt wurde eine einzelne Änderung vorgenommen. Nichts Anderes " "wurde verändert" -#: application/forms/DeploymentLinkForm.php:74 +#: ../../../../application/forms/DeploymentLinkForm.php:75 #, php-format msgid "" "There have been %d changes to this object, nothing else has been modified" @@ -6181,15 +6244,15 @@ msgstr "" "An diesem Objekt wurden %d Änderungen vorgenommen, nichts anderes wurde " "verändert" -#: application/forms/DeploymentLinkForm.php:63 +#: ../../../../application/forms/DeploymentLinkForm.php:64 msgid "There is a single pending change" msgstr "Es gibt eine einzelne ausstehende Änderung" -#: application/forms/DirectorJobForm.php:21 +#: ../../../../application/forms/DirectorJobForm.php:21 msgid "These are different available job types" msgstr "Verschiedene verfügbare Auftragstypen" -#: application/forms/ImportSourceForm.php:37 +#: ../../../../application/forms/ImportSourceForm.php:37 msgid "" "These are different data providers fetching data from various sources. You " "didn't find what you're looking for? Import sources are implemented as a " @@ -6201,69 +6264,69 @@ msgstr "" "geschriebenes) Icinga Web 2 Modul diese Funktionalität nachrüsten, da " "Importquellen als Hook in Director realisiert werden" -#: application/controllers/CommandController.php:76 +#: ../../../../application/controllers/CommandController.php:76 #, php-format msgid "This Command is currently being used by %s" msgstr "Dieses Kommando wird gegenwärtig von %s benutzt" -#: application/controllers/CommandController.php:82 +#: ../../../../application/controllers/CommandController.php:82 msgid "This Command is currently not in use" msgstr "Dieses Kommando wird gegenwärtig nicht benutzt" -#: library/Director/Web/Form/DirectorObjectForm.php:951 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:954 #, php-format msgid "This Command is still in use by %d other objects" msgstr "Dieses Kommando wird von %d anderen Objekten benutzt" -#: library/Director/Web/Widget/ImportSourceDetails.php:59 +#: ../../../../library/Director/Web/Widget/ImportSourceDetails.php:59 #, php-format msgid "This Import Source failed when last checked at %s: %s" msgstr "Diese Importquelle schlug bei der letzten Prüfung um %s fehl: %s" -#: library/Director/Web/Widget/ImportSourceDetails.php:67 +#: ../../../../library/Director/Web/Widget/ImportSourceDetails.php:67 #, php-format msgid "This Import Source has an invalid state: %s" msgstr "Diese Importquelle hat einen ungültigen Zustand: %s" -#: application/forms/ImportCheckForm.php:33 +#: ../../../../application/forms/ImportCheckForm.php:33 msgid "This Import Source provides modified data" msgstr "Diese Importquelle stellt veränderte Daten zur Verfügung" -#: library/Director/Web/Widget/ImportSourceDetails.php:42 +#: ../../../../library/Director/Web/Widget/ImportSourceDetails.php:42 #, php-format msgid "This Import Source was last found to be in sync at %s." msgstr "Diese Importquelle war zuletzt um %s syncron." -#: application/forms/IcingaServiceForm.php:136 +#: ../../../../application/forms/IcingaServiceForm.php:138 msgid "This Service has been deactivated on this host" msgstr "Dieser Service wurde auf diesem Host deaktiviert" -#: application/controllers/SyncruleController.php:115 +#: ../../../../application/controllers/SyncruleController.php:115 #, php-format msgid "This Sync Rule failed when last checked at %s: %s" msgstr "" "Diese Synchronisationsregel schlug bei der letzten Prüfung um %s fehl: %s" -#: application/controllers/SyncruleController.php:85 +#: ../../../../application/controllers/SyncruleController.php:85 msgid "This Sync Rule has never been run before." msgstr "Diese Synchronisationsregel wurde noch nie ausgeführt." -#: application/controllers/SyncruleController.php:258 +#: ../../../../application/controllers/SyncruleController.php:258 msgid "This Sync Rule is in sync and would currently not apply any changes" msgstr "" "Diese Sync-Regel ist synchron und würde aktuell keine Änderungen verursachen" -#: application/controllers/SyncruleController.php:97 +#: ../../../../application/controllers/SyncruleController.php:97 #, php-format -msgid "This Sync Rule was last found to by in Sync at %s." +msgid "This Sync Rule was last found to be in Sync at %s." msgstr "Diese Synchronisationsregel war zuletzt synchron um %s." -#: application/forms/SyncPropertyForm.php:105 +#: ../../../../application/forms/SyncPropertyForm.php:105 msgid "" "This allows to filter for specific parts within the given source expression. " "You are allowed to refer all imported columns. Examples: host=www* would set " -"this property only for rows imported with a host property starting with " -"\"www\". Complex example: host=www*&!(address=127.*|address6=::1)" +"this property only for rows imported with a host property starting with \"www" +"\". Complex example: host=www*&!(address=127.*|address6=::1)" msgstr "" "Erlaubt das Filtern nach bestimmten Teilen innerhalb des angegebenen " "Quellausdrucks. Alle importierten Spalten können angegeben werden. " @@ -6271,22 +6334,39 @@ msgstr "" "setzen, bei denen die Host Eigenschaft mit \"www\" beginnt. Komplexes " "Beispiel: host=www*&!(address=127.*|address6=::1)" -#: library/Director/DataType/DataTypeDatalist.php:147 +#: ../../../../application/forms/ImportRowModifierForm.php:91 +msgid "" +"This allows to filter for specific parts within the given source expression. " +"You are allowed to refer all imported columns. Examples: host=www* would set " +"this property only for rows imported with a host property starting with \"www" +"\". Complex example: host=www*&!(address=127.*|address6=::1). Please note, " +"that CIDR notation based matches are also supported: " +"address=192.0.2.128/25| address=2001:db8::/32| address=::ffff:192.0.2.0/96" +msgstr "" +"Erlaubt das Filtern nach bestimmten Teilen innerhalb des angegebenen " +"Quellausdrucks. Alle importierten Spalten können angegeben werden. " +"Beispiele: host=www* würde diese Eigenschaft nur für importierte Zeilen " +"setzen, bei denen die Host Eigenschaft mit \"www\" beginnt. Komplexes " +"Beispiel: host=www*&!(address=127.*|address6=::1). Bitte beachten, dass auch " +"Muster in CIDR-Notation unterstützt werden: address=192.0.2.128/25| " +"address=2001:db8::/32| address=::ffff:192.0.2.0/96" + +#: ../../../../library/Director/DataType/DataTypeDatalist.php:147 msgid "This allows to show either a drop-down list or an auto-completion" msgstr "" "Dies erlaubt es, entweder eine Ausklappmenü oder ein Feld mit automatischer " "Vervollständigung anzuzeigen" -#: application/forms/DirectorJobForm.php:39 +#: ../../../../application/forms/DirectorJobForm.php:39 msgid "This allows to temporarily disable this job" msgstr "Erlaubt das vorübergehende Deaktivieren dieses Auftrags" -#: application/forms/IcingaHostGroupForm.php:30 -#: application/forms/IcingaNotificationForm.php:106 -#: application/forms/IcingaServiceGroupForm.php:30 -#: application/forms/IcingaServiceForm.php:476 -#: application/forms/IcingaDependencyForm.php:115 -#: application/forms/IcingaScheduledDowntimeForm.php:115 +#: ../../../../application/forms/IcingaNotificationForm.php:107 +#: ../../../../application/forms/IcingaHostGroupForm.php:30 +#: ../../../../application/forms/IcingaServiceGroupForm.php:30 +#: ../../../../application/forms/IcingaServiceForm.php:480 +#: ../../../../application/forms/IcingaDependencyForm.php:115 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:115 msgid "" "This allows you to configure an assignment filter. Please feel free to " "combine as many nested operators as you want. The \"contains\" operator is " @@ -6299,7 +6379,7 @@ msgstr "" "Teilstrings zu vergleichen bitte Jokerzeichen (wildcards) benutzen, wie in *." "example.com" -#: application/forms/IcingaServiceSetForm.php:123 +#: ../../../../application/forms/IcingaServiceSetForm.php:124 msgid "" "This allows you to configure an assignment filter. Please feel free to " "combine as many nested operators as you want. You might also want to skip " @@ -6316,31 +6396,31 @@ msgstr "" "Arrays zulässig. Um Teilstrings zu vergleichen bitte Jokerzeichen " "(wildcards) benutzen, wie in *.example.com" -#: library/Director/Job/ConfigJob.php:47 +#: ../../../../library/Director/Job/ConfigJob.php:47 msgid "This allows you to immediately deploy a modified configuration" msgstr "Dies erlaubt das sofortige Ausrollen einer veränderten Konfiguration" -#: library/Director/ProvidedHook/CubeLinks.php:37 -#: library/Director/ProvidedHook/IcingaDbCubeLinks.php:32 +#: ../../../../library/Director/ProvidedHook/CubeLinks.php:37 +#: ../../../../library/Director/ProvidedHook/IcingaDbCubeLinks.php:32 #, php-format msgid "This allows you to modify properties for \"%s\"" msgstr "Erlaubt das Ändern der Eigenschaften von \"%s\"" -#: library/Director/ProvidedHook/CubeLinks.php:54 -#: library/Director/ProvidedHook/IcingaDbCubeLinks.php:55 +#: ../../../../library/Director/ProvidedHook/CubeLinks.php:54 +#: ../../../../library/Director/ProvidedHook/IcingaDbCubeLinks.php:55 msgid "This allows you to modify properties for all chosen hosts at once" msgstr "" "Hiermit lassen sich Eigenschaften für alle gewählten Hosts auf einmal ändern" -#: application/controllers/BasketController.php:64 +#: ../../../../application/controllers/BasketController.php:62 msgid "This basket is empty" msgstr "Dieser Basket ist leer" -#: application/forms/KickstartForm.php:230 +#: ../../../../application/forms/KickstartForm.php:230 msgid "This has to be a MySQL or PostgreSQL database" msgstr "Muss eine MySQL oder PostgeSQL Datenbank sein" -#: library/Director/Web/SelfService.php:65 +#: ../../../../library/Director/Web/SelfService.php:65 msgid "" "This host has been registered via the Icinga Director Self Service API. In " "case you re-installed the host or somehow lost it's secret key, you might " @@ -6352,11 +6432,11 @@ msgstr "" "ging, kann es erwünscht sein, den aktuellen Schlüssel zu verwerfen. Das " "würde es erlauben, denselben Host neu zu registrieren." -#: application/controllers/InspectController.php:71 +#: ../../../../application/controllers/InspectController.php:71 msgid "This is an abstract object type." msgstr "Das ist ein abstrakter Objekttyp." -#: application/forms/SelfServiceSettingsForm.php:45 +#: ../../../../application/forms/SelfServiceSettingsForm.php:45 msgid "" "This is only important in case your master/satellite nodes do not have IP " "addresses as their \"host\" property. The Agent can be told to issue related " @@ -6366,12 +6446,12 @@ msgstr "" "Eigenschaft gesetzt haben. Dem Agent kann angewiesen werden, eigenständig " "entsprechende DNS-Lookups eigenständig vorzunehmen" -#: library/Director/Web/Controller/TemplateController.php:179 +#: ../../../../library/Director/Web/Controller/TemplateController.php:180 #, php-format msgid "This is the \"%s\" %s Template. Based on this, you might want to:" msgstr "Das ist die \"%s\" %s Vorlage. Basierend auf diese, kann man:" -#: application/forms/KickstartForm.php:123 +#: ../../../../application/forms/KickstartForm.php:123 msgid "" "This is the name of the Endpoint object (and certificate name) you created " "for your ApiListener object. In case you are unsure what this means please " @@ -6381,7 +6461,7 @@ msgstr "" "Objekt erstellt wurde. Bei Unklarheit, was damit gemeint ist, sollte die " "Dokumentation erneut zu Rate gezogen werden" -#: library/Director/Dashboard/Dashlet/HostsDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/HostsDashlet.php:19 msgid "" "This is where you add all your servers, containers, network or sensor " "devices - and much more. Every subject worth to be monitored" @@ -6389,7 +6469,7 @@ msgstr "" "Hier werden alle Server, Container, Netzwerk- oder Sensor-Geräte und vieles " "mehr hinzugefügt. Jede Komponente die es wert ist, überwacht zu werden" -#: library/Director/Dashboard/HostsDashboard.php:22 +#: ../../../../library/Director/Dashboard/HostsDashboard.php:22 msgid "" "This is where you manage your Icinga 2 Host Checks. Host templates are your " "main building blocks. You can bundle them to \"choices\", allowing (or " @@ -6400,7 +6480,7 @@ msgstr "" "werden, um es eigenen Benutzern zu erlauben, aus einem definierten Set von " "Vorlagen zu wählen - oder dies gar zu erzwingen." -#: library/Director/Dashboard/ServicesDashboard.php:24 +#: ../../../../library/Director/Dashboard/ServicesDashboard.php:24 msgid "" "This is where you manage your Icinga 2 Service Checks. Service Templates are " "your base building blocks, Service Sets allow you to assign multiple " @@ -6414,7 +6494,7 @@ msgstr "" "Eigenschaften zuzuweisen. Und die Liste aller Einzel-Services erlaubt es, " "einzelne oder mehrere zugleich zu bearbeiten oder zu löschen." -#: library/Director/Dashboard/UsersDashboard.php:21 +#: ../../../../library/Director/Dashboard/UsersDashboard.php:21 msgid "" "This is where you manage your Icinga 2 User (Contact) objects. Try to keep " "your User objects simply by movin complexity to your templates. Bundle your " @@ -6432,7 +6512,7 @@ msgstr "" "Import-Funktion und entsprechende Synchronisationsregeln lässt sich nahezu " "alles automatisieren!" -#: library/Director/Dashboard/InfrastructureDashboard.php:39 +#: ../../../../library/Director/Dashboard/InfrastructureDashboard.php:39 msgid "" "This is where you manage your Icinga 2 infrastructure. When adding a new " "Icinga Master or Satellite please re-run the Kickstart Helper once." @@ -6440,27 +6520,27 @@ msgstr "" "Hier wird die Icinga 2 Infrastruktur verwaltet. Den Kickstart-Helper beim " "Hinzufügen von neuen Icinga Mastern oder Satelliten bitte erneut ausführen." -#: library/Director/Web/Table/ObjectsTableEndpoint.php:47 +#: ../../../../library/Director/Web/Table/ObjectsTableEndpoint.php:47 msgid "This is your Config master and will receive our Deployments" msgstr "" "Dies ist der Konfigurations-Master zu welchem sämtliche Konfiguration " "ausgerollt wird" -#: library/Director/Web/Widget/JobDetails.php:66 +#: ../../../../library/Director/Web/Widget/JobDetails.php:66 msgid "This job has not been executed yet" msgstr "Dieser Auftrag wurde bisher nicht ausgeführt" -#: library/Director/Web/Widget/JobDetails.php:36 +#: ../../../../library/Director/Web/Widget/JobDetails.php:36 #, php-format msgid "This job runs every %ds and is currently pending" -msgstr "Dieser Auftrag läuft alle %d und ist aktuell ausständig" +msgstr "Dieser Auftrag läuft alle %ds und ist aktuell ausständig" -#: library/Director/Web/Widget/JobDetails.php:40 +#: ../../../../library/Director/Web/Widget/JobDetails.php:40 #, php-format msgid "This job runs every %ds." -msgstr "Dieser Auftrag läuft alle %d." +msgstr "Dieser Auftrag läuft alle %ds." -#: library/Director/Web/Widget/JobDetails.php:27 +#: ../../../../library/Director/Web/Widget/JobDetails.php:27 #, php-format msgid "" "This job would run every %ds. It has been disabled and will therefore not be " @@ -6469,7 +6549,8 @@ msgstr "" "Dieser Auftrag würde alle %d ausgeführt. Er ist deaktiviert und wird deshalb " "nicht wie geplant ausgeführt" -#: library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:33 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMakeBoolean.php:33 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSetValue.php:22 msgid "" "This modifier transforms 0/\"0\"/false/\"false\"/\"n\"/\"no\" to false and " "1, \"1\", true, \"true\", \"y\" and \"yes\" to true, both in a case " @@ -6484,7 +6565,7 @@ msgstr "" "aber true oder false als Fallback nutzen. Alternativ kann man auch den " "komplette Importvorgang aufgrund ungültiger Daten fehlschlagen lassen" -#: application/forms/ImportSourceForm.php:89 +#: ../../../../application/forms/ImportSourceForm.php:89 msgid "" "This must be a column containing unique values like hostnames. Unless " "otherwise specified this will then be used as the object_name for the " @@ -6507,44 +6588,40 @@ msgstr "" "\"Kombinieren\", falls die gegebenen Datenquelle keine solche Spalte " "bereitstellen kann" -#: application/forms/IcingaScheduledDowntimeForm.php:33 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:33 msgid "This name will show up as the author for ever related downtime comment" msgstr "" "Der Name wird als Autor für sämtliche zugehörigen Downtime-Kommentare " "aufscheinen" -#: library/Director/Web/Widget/BranchedObjectHint.php:57 +#: ../../../../library/Director/Web/Widget/BranchedObjectHint.php:69 #, php-format msgid "This object has been created in %s" msgstr "Dieses Objekt wurde in %s erstellt" -#: library/Director/Web/Widget/ActivityLogInfo.php:545 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:545 msgid "This object has been disabled" msgstr "Dieses Objekt wurde deaktiviert" -#: library/Director/Web/Widget/ActivityLogInfo.php:540 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:540 msgid "This object has been enabled" msgstr "Dieses Objekt wurde aktiviert" -#: library/Director/Web/Widget/BranchedObjectHint.php:62 +#: ../../../../library/Director/Web/Widget/BranchedObjectHint.php:74 #, php-format msgid "This object has modifications visible only in %s" msgstr "Dieses Objekt hat Änderungen, welche nur in %s sichtbar sind" -#: library/Director/Web/Widget/BranchedObjectHint.php:34 +#: ../../../../library/Director/Web/Widget/BranchedObjectHint.php:45 #, php-format -msgid "" -"This object will be created in %s. It will not be part of any deployment " -"unless being merged" -msgstr "" -"Das Objekt wird in %s erstellt. Es sind nicht Teil eines eventuellen " -"Deployments, solange die Änderungen nicht zusammengeführt werden" +msgid "This object will be created in %s." +msgstr "Dieses Objekt wird in %s erstellt" -#: library/Director/Web/ObjectPreview.php:75 +#: ../../../../library/Director/Web/ObjectPreview.php:75 msgid "This object will not be deployed as it has been disabled" msgstr "Das Objekt wird nicht ausgerollt, da es deaktiviert wurde" -#: library/Director/PropertyModifier/PropertyModifierCombine.php:17 +#: ../../../../library/Director/PropertyModifier/PropertyModifierCombine.php:17 msgid "" "This pattern will be evaluated, and variables like ${some_column} will be " "filled accordingly. A typical use-case is generating unique service " @@ -6558,13 +6635,13 @@ msgstr "" "einen solchen nicht bereitstellt. Die gewählte \"Eigenschaft\" hat hier " "keine Auswirkung und wird ignoriert." -#: application/controllers/SyncruleController.php:219 +#: ../../../../application/controllers/SyncruleController.php:219 #, php-format msgid "This preview has been generated %s, please click %s to regenerate it" msgstr "" "Dieser Vorschau wurde %s generiert, zwecks Aktualisierung bitte %s klicken" -#: library/Director/Web/SelfService.php:256 +#: ../../../../library/Director/Web/SelfService.php:243 msgid "" "This requires the Icinga Agent to be installed. It generates and signs it's " "certificate and it also generates a minimal icinga2.conf to get your agent " @@ -6574,7 +6651,7 @@ msgstr "" "sein Zertifikat und erstellt eine minimale icinga2.conf mit welcher der " "Agent zu den ihm übergeordneten Systemen verbunden wird" -#: application/forms/IcingaServiceForm.php:403 +#: ../../../../application/forms/IcingaServiceForm.php:407 #, php-format msgid "" "This service belongs to the %s Service Set. Still, you might want to " @@ -6583,7 +6660,7 @@ msgstr "" "Dieser Service gehört zum Service Set %s. Dennoch können die folgenden " "Eigenschaften nur für diesen speziellen Host geändert werden." -#: application/forms/IcingaServiceForm.php:443 +#: ../../../../application/forms/IcingaServiceForm.php:447 #, php-format msgid "" "This service belongs to the service set \"%s\". Still, you might want to " @@ -6592,7 +6669,7 @@ msgstr "" "Dieser Service gehört zum Set \"%s\". Dennoch können die folgenden " "Eigenschaften nur für diesen speziellen Host geändert werden." -#: application/forms/IcingaServiceForm.php:384 +#: ../../../../application/forms/IcingaServiceForm.php:388 msgid "" "This service has been generated in an automated way, but still allows you to " "override the following properties in a safe way." @@ -6600,7 +6677,7 @@ msgstr "" "Dieser Service wurde durch einen Automatismus erstellt, erlaubt es aber " "dennoch die folgenden Eigenschaften auf sichere Weise zu überschreiben." -#: application/forms/IcingaServiceForm.php:390 +#: ../../../../application/forms/IcingaServiceForm.php:394 #, php-format msgid "" "This service has been generated using the %s apply rule, assigned where %s" @@ -6608,7 +6685,7 @@ msgstr "" "Dieser Service wurde durch die Apply-Regel %s erstellt, und wird zugewiesen " "wo %s" -#: application/forms/IcingaServiceForm.php:415 +#: ../../../../application/forms/IcingaServiceForm.php:419 #, php-format msgid "" "This service has been inherited from %s. Still, you might want to change the " @@ -6617,12 +6694,12 @@ msgstr "" "Dieser Service wurde von %s geerbt. Dennoch können die folgenden " "Eigenschaften nur für diesen speziellen Host geändert werden." -#: library/Director/Web/Table/IcingaServiceSetServiceTable.php:216 +#: ../../../../library/Director/Web/Table/IcingaServiceSetServiceTable.php:229 #, php-format msgid "This set has been inherited from %s" msgstr "Dieses Set wurde von %s geerbt" -#: library/Director/Dashboard/Dashlet/KickstartDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/KickstartDashlet.php:19 msgid "" "This synchronizes Icinga Director to your Icinga 2 infrastructure. A new run " "should be triggered on infrastructure changes" @@ -6630,91 +6707,123 @@ msgstr "" "Synchronisiert den Icinga Director mit der Icinga 2 Infrastruktur. Bei " "Änderungen an derselben sollte ein neuer Lauf angestoßen werden" -#: library/Director/Web/Table/TemplateUsageTable.php:103 +#: ../../../../library/Director/Web/Table/TemplateUsageTable.php:104 msgid "This template is not in use" msgstr "Diese Vorlage ist nicht in Verwendung" -#: library/Director/Web/Form/DirectorObjectForm.php:941 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:944 #, php-format msgid "This template is still in use by %d other objects" msgstr "Diese Vorlage ist noch in Verwendung durch %d andere Objekte" -#: application/forms/IcingaTemplateChoiceForm.php:51 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMap.php:48 +msgid "" +"This value will be evaluated, and variables like ${some_column} will be " +"filled accordingly. A typical use-case is generating unique service " +"identifiers via ${host}!${service} in case your data source doesn't allow " +"you to ship such. The chosen \"property\" has no effect here and will be " +"ignored." +msgstr "" +"Dieses Muster wird ausgewertet, und Variablen wie ${eine_spalte} werden " +"entsprechend befüllt. Ein typischer Anwendungsfall ist das Erstellen von " +"eindeutigen Service-Bezeichnern via ${host}!${service} falls die Datenquelle " +"einen solchen nicht bereitstellt. Die gewählte \"Eigenschaft\" hat hier " +"keine Auswirkung und wird ignoriert." + +#: ../../../../library/Director/Web/Widget/BranchedObjectHint.php:25 +msgid "This will be part of the next deployment" +msgstr "Das wird Teil des nächsten Deployments" + +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:51 msgid "This will be shown as a label for the given choice" msgstr "Dies wird als Bezeichner für diese Auswahlmöglichkeit angezeigt werden" -#: application/forms/DirectorDatalistEntryForm.php:33 +#: ../../../../application/forms/DirectorDatafieldForm.php:143 +msgid "" +"This will be the name of the custom variable in the rendered Icinga " +"configuration." +msgstr "" +"Dies wird als Name der benutzerdefinierten Eigenschaft in der gerenderten " +"Icinga-Konfiguration benutzt." + +#: ../../../../application/forms/DirectorDatalistEntryForm.php:33 msgid "This will be the visible caption for this entry" msgstr "Die sichtbare Bezeichnung für diesen Eintrag" -#: library/Director/Web/SelfService.php:116 +#: ../../../../library/Director/Web/SelfService.php:116 msgid "This will invalidate the former key" msgstr "Das macht den vorherigen Schlüssel ungültig" -#: library/Director/Web/SelfService.php:246 +#: ../../../../library/Director/Web/Widget/BranchedObjectHint.php:32 +msgid "This will not be part of any deployment, unless being merged" +msgstr "" +"Dies wird nicht Teil eines eventuellen Deployments, solange die Änderungen " +"nicht zusammengeführt werden" + +#: ../../../../library/Director/Web/SelfService.php:233 msgid "Ticket" msgstr "Ticket" -#: application/forms/SyncRuleForm.php:21 +#: ../../../../application/forms/SyncRuleForm.php:21 msgid "Time Period" msgstr "Zeitraum" -#: application/forms/BasketForm.php:32 +#: ../../../../application/forms/BasketForm.php:32 msgid "Time Periods" msgstr "Zeiträume" -#: application/forms/IcingaUserForm.php:158 -#: application/forms/IcingaNotificationForm.php:240 -#: application/forms/DirectorJobForm.php:60 -#: application/forms/IcingaDependencyForm.php:141 +#: ../../../../application/forms/IcingaUserForm.php:158 +#: ../../../../application/forms/IcingaNotificationForm.php:288 +#: ../../../../application/forms/DirectorJobForm.php:60 +#: ../../../../application/forms/IcingaDependencyForm.php:141 msgid "Time period" msgstr "Zeitraum" -#: application/controllers/TimeperiodController.php:17 -#: application/controllers/ScheduledDowntimeController.php:24 +#: ../../../../application/controllers/TimeperiodController.php:17 +#: ../../../../application/controllers/ScheduledDowntimeController.php:24 msgid "Time period ranges" msgstr "Zeiträume" -#: application/forms/IcingaScheduledDowntimeRangeForm.php:56 +#: ../../../../application/forms/IcingaScheduledDowntimeRangeForm.php:56 #, php-format msgid "Time range \"%s\" has been removed from %s" msgstr "Der Zeitraum \"%s\" wurden von \"%s\" entfernt" -#: application/forms/SyncPropertyForm.php:321 +#: ../../../../application/forms/SyncPropertyForm.php:321 msgid "Time ranges" msgstr "Zeiträume" -#: application/forms/IcingaCommandForm.php:69 +#: ../../../../application/forms/IcingaCommandForm.php:69 msgid "Timeout" msgstr "Timeout" -#: library/Director/Dashboard/Dashlet/TimeperiodTemplateDashlet.php:13 +#: ../../../../library/Director/Dashboard/Dashlet/TimeperiodTemplateDashlet.php:15 msgid "Timeperiod Templates" msgstr "Zeitraumvorlage" -#: library/Director/Dashboard/Dashlet/TimeperiodObjectDashlet.php:16 -#: library/Director/Dashboard/Dashlet/TimeperiodsDashlet.php:13 -#: library/Director/Db/Branch/BranchModificationInspection.php:45 -#: library/Director/Web/Table/IcingaTimePeriodRangeTable.php:46 -#: library/Director/Web/Table/IcingaScheduledDowntimeRangeTable.php:52 -#: application/forms/IcingaScheduledDowntimeRangeForm.php:29 +#: ../../../../library/Director/Dashboard/Dashlet/TimeperiodObjectDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/TimeperiodsDashlet.php:15 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:45 +#: ../../../../library/Director/Web/Table/IcingaTimePeriodRangeTable.php:46 +#: ../../../../library/Director/Web/Table/IcingaScheduledDowntimeRangeTable.php:52 +#: ../../../../application/forms/IcingaScheduledDowntimeRangeForm.php:29 msgid "Timeperiods" msgstr "Zeiträume" -#: application/forms/IcingaTimePeriodRangeForm.php:28 +#: ../../../../application/forms/IcingaTimePeriodRangeForm.php:28 msgid "Timerperiods" msgstr "Zeiträume" -#: library/Director/Web/Table/ImportrunTable.php:31 +#: ../../../../library/Director/Web/Table/ImportrunTable.php:31 msgid "Timestamp" msgstr "Zeitstempel" -#: library/Director/DataType/DataTypeDictionary.php:28 +#: ../../../../library/Director/DataType/DataTypeDictionary.php:28 msgid "To be managed on objects only" msgstr "Kann nur auf Objekten verwaltet werden" -#: application/forms/SelfServiceSettingsForm.php:59 -#: application/forms/SelfServiceSettingsForm.php:167 +#: ../../../../application/forms/SelfServiceSettingsForm.php:59 +#: ../../../../application/forms/SelfServiceSettingsForm.php:167 msgid "" "To ensure downloaded packages are build by the Icinga Team and not " "compromised by third parties, you will be able to provide an array of SHA1 " @@ -6730,87 +6839,91 @@ msgstr "" "keinem davon entspricht, wird das Powershell-Modul sich weigern mit Update " "oder Installation des Agenten fortzufahren" -#: library/Director/Web/SelfService.php:221 +#: ../../../../library/Director/Field/FormFieldSuggestion.php:86 +msgid "Toggles (boolean arguments)" +msgstr "Schalter (boolsche Argumente)" + +#: ../../../../library/Director/Web/SelfService.php:208 msgid "Top Down" msgstr "Top Down" -#: library/Director/Web/Table/TemplateUsageTable.php:57 +#: ../../../../library/Director/Web/Table/TemplateUsageTable.php:57 msgid "Total" msgstr "Gesamt" -#: application/forms/SelfServiceSettingsForm.php:31 +#: ../../../../application/forms/SelfServiceSettingsForm.php:31 msgid "Transform Host Name" msgstr "Hostname transformieren" -#: application/forms/SelfServiceSettingsForm.php:43 +#: ../../../../application/forms/SelfServiceSettingsForm.php:43 msgid "Transform Parent Host to IP" msgstr "Elternhost in IP umwandeln" -#: application/forms/SelfServiceSettingsForm.php:37 +#: ../../../../application/forms/SelfServiceSettingsForm.php:37 msgid "Transform to lowercase" msgstr "In Kleinbuchstaben umwandeln" -#: application/forms/SelfServiceSettingsForm.php:38 +#: ../../../../application/forms/SelfServiceSettingsForm.php:38 msgid "Transform to uppercase" msgstr "In Großbuchstaben umwandeln" -#: library/Director/Web/Form/DirectorObjectForm.php:1673 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1676 msgid "Transition types" msgstr "Änderungsstypen" -#: library/Director/Web/ActionBar/TemplateActionBar.php:30 +#: ../../../../library/Director/Web/ActionBar/TemplateActionBar.php:30 msgid "Tree" msgstr "Baum" -#: application/forms/ImportRunForm.php:23 +#: ../../../../application/forms/ImportRunForm.php:23 msgid "Trigger Import Run" msgstr "Importlauf anstoßen" -#: application/forms/SyncRunForm.php:37 +#: ../../../../application/forms/SyncRunForm.php:37 msgid "Trigger this Sync" msgstr "Diese Synchronisation anstoßen" -#: application/forms/ImportRunForm.php:45 +#: ../../../../application/forms/ImportRunForm.php:45 msgid "Triggering this Import Source failed" msgstr "Anstoßen dieser Importquelle schlug fehl" -#: library/Director/PropertyModifier/PropertyModifierTrim.php:16 +#: ../../../../library/Director/PropertyModifier/PropertyModifierTrim.php:16 msgid "Trim Method" msgstr "Trim-Methode" -#: library/Director/Dashboard/Dashlet/SettingsDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/SettingsDashlet.php:19 msgid "Tweak some global Director settings" msgstr "Einige globale Director-Einstellungen anpassen" -#: library/Director/Web/Table/CoreApiFieldsTable.php:80 -#: library/Director/Web/Table/ObjectsTableEndpoint.php:22 +#: ../../../../library/Director/Web/Table/CoreApiFieldsTable.php:80 +#: ../../../../library/Director/Web/Table/ObjectsTableEndpoint.php:22 msgid "Type" msgstr "Typ" -#: application/controllers/InspectController.php:82 +#: ../../../../application/controllers/InspectController.php:82 msgid "Type attributes" msgstr "Typ-Attribute" -#: library/Director/PropertyModifier/PropertyModifierParseURL.php:27 -#: library/Director/PropertyModifier/PropertyModifierParseURL.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierParseURL.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierParseURL.php:28 msgid "URL component" msgstr "URL- Komponente" -#: library/Director/PropertyModifier/PropertyModifierUuidBinToHex.php:12 +#: ../../../../library/Director/PropertyModifier/PropertyModifierUuidBinToHex.php:12 msgid "UUID: from binary to hex" msgstr "UUID: binär in hexadezimal umwandeln" -#: application/forms/DeployFormsBug7530.php:72 +#: ../../../../application/forms/DeployFormsBug7530.php:72 msgid "Unable to detect your Icinga 2 Core version" msgstr "Die Icinga 2 Core-Version konnte nicht ermittelt werden" -#: library/Director/DataType/DataTypeSqlQuery.php:27 -#: application/forms/SyncPropertyForm.php:168 +#: ../../../../library/Director/DataType/DataTypeSqlQuery.php:27 +#: ../../../../application/forms/SyncPropertyForm.php:168 #, php-format msgid "Unable to fetch data: %s" msgstr "Daten konnten nicht geholt werden: %s" -#: application/forms/IcingaHostForm.php:383 +#: ../../../../application/forms/IcingaHostForm.php:385 msgid "" "Unable to store a host with the given properties because of insufficient " "permissions" @@ -6818,7 +6931,7 @@ msgstr "" "Ein Host konnte aufgrund unzureichender Berechtigungen nicht mit den " "gegebenen Eigenschaften abgespeichert werden" -#: application/forms/KickstartForm.php:316 +#: ../../../../application/forms/KickstartForm.php:316 #, php-format msgid "" "Unable to store the configuration to \"%s\". Please check file permissions " @@ -6828,11 +6941,11 @@ msgstr "" "Dateisystemberechtigungen prüfen oder den unten angegebenen Inhalt manuell " "speichern" -#: library/Director/Db/Housekeeping.php:49 +#: ../../../../library/Director/Db/Housekeeping.php:49 msgid "Undeployed configurations" msgstr "Nicht ausgerollte Konfigurationen" -#: application/forms/IcingaNotificationForm.php:221 +#: ../../../../application/forms/IcingaNotificationForm.php:269 msgid "" "Unit is seconds unless a suffix is given. Supported suffixes include ms " "(milliseconds), s (seconds), m (minutes), h (hours) and d (days)." @@ -6842,86 +6955,91 @@ msgstr "" "(Millisekunden), s (Sekunden), m (Minuten), h (Stunden) and d (Tage). Um " "\"90 Minuten\" auszudrücken könnte man 1h 30m schreiben." -#: library/Director/IcingaConfig/StateFilterSet.php:27 +#: ../../../../library/Director/IcingaConfig/StateFilterSet.php:27 msgid "Unknown" msgstr "Unbekannt" -#: library/Director/Web/Widget/DeploymentInfo.php:136 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:137 msgid "Unknown, failed to collect related information" msgstr "Unbekannt, entsprechende Information konnte nicht gesammelt werden" -#: library/Director/Web/Widget/DeploymentInfo.php:134 +#: ../../../../library/Director/Web/Widget/DeploymentInfo.php:135 msgid "Unknown, still waiting for config check outcome" msgstr "Unbekannt, warte auf Ergebnis der Konfigurationsprüfung" -#: library/Director/Db/Housekeeping.php:53 +#: ../../../../library/Director/Db/Housekeeping.php:53 msgid "Unlinked imported properties" msgstr "Nicht-verknüpfte importierte Eigenschaften" -#: library/Director/Db/Housekeeping.php:51 +#: ../../../../library/Director/Db/Housekeeping.php:51 msgid "Unlinked imported row sets" msgstr "Nicht-verknüpfte importierte Zeilensets" -#: library/Director/Db/Housekeeping.php:52 +#: ../../../../library/Director/Db/Housekeeping.php:52 msgid "Unlinked imported rows" msgstr "Nicht-verknüpfte importierte Zeilen" -#: application/controllers/PhperrorController.php:22 -#: application/controllers/PhperrorController.php:37 +#: ../../../../application/controllers/PhperrorController.php:22 +#: ../../../../application/controllers/PhperrorController.php:37 msgid "Unsatisfied dependencies" msgstr "Unerfüllte Abhängigkeiten" -#: library/Director/Db/Housekeeping.php:50 +#: ../../../../library/Director/Db/Housekeeping.php:50 msgid "Unused rendered files" msgstr "Nicht verwendete, generierte Dateien" -#: library/Director/IcingaConfig/StateFilterSet.php:20 +#: ../../../../library/Director/IcingaConfig/StateFilterSet.php:20 msgid "Up" msgstr "Up" -#: application/forms/IcingaTimePeriodForm.php:25 +#: ../../../../application/forms/IcingaTimePeriodForm.php:25 msgid "Update Method" msgstr "Aktualisierungsmethode" -#: application/forms/SyncRuleForm.php:52 +#: ../../../../application/forms/SyncRuleForm.php:52 msgid "Update Policy" msgstr "Aktualisierungsrichtlinie" -#: application/forms/SyncRuleForm.php:65 +#: ../../../../application/forms/SyncRuleForm.php:65 msgid "Update only" msgstr "Nur aktualisieren" -#: application/forms/DeployFormsBug7530.php:109 +#: ../../../../application/forms/DeployFormsBug7530.php:109 msgid "Upgrading Icinga 2 - Confic Sync: Zones in Zones" msgstr "Upgrading Icinga 2 - Confic Sync: Zones in Zones" -#: application/forms/DeployFormsBug7530.php:111 +#: ../../../../application/forms/DeployFormsBug7530.php:111 msgid "Upgrading documentation" msgstr "Upgrading-Dokumentation" -#: application/forms/BasketUploadForm.php:43 -#: application/controllers/BasketsController.php:26 +#: ../../../../application/forms/BasketUploadForm.php:45 +#: ../../../../application/controllers/BasketsController.php:26 +#: ../../../../application/controllers/BasketController.php:169 msgid "Upload" msgstr "Hochladen" -#: application/controllers/BasketController.php:122 +#: ../../../../application/controllers/BasketController.php:120 msgid "Upload a Basket" msgstr "Basket hochladen" -#: application/controllers/BasketController.php:123 +#: ../../../../application/controllers/BasketController.php:121 msgid "Upload a Configuration Basket" msgstr "Konfigurationsbasket hochladen" -#: library/Director/Web/Controller/ObjectController.php:367 +#: ../../../../application/controllers/BasketController.php:140 +msgid "Upload a Configuration Basket Snapshot" +msgstr "Schnappschuss eines Konfigurationsbaskets hochladen" + +#: ../../../../library/Director/Web/Controller/ObjectController.php:370 msgid "Usage" msgstr "Benutzung" -#: library/Director/Web/Widget/AdditionalTableActions.php:101 +#: ../../../../library/Director/Web/Widget/AdditionalTableActions.php:102 #, php-format msgid "Usage (%s)" msgstr "Benutzung (%s)" -#: application/forms/IcingaHostForm.php:106 +#: ../../../../application/forms/IcingaHostForm.php:108 msgid "" "Use a different name for the generated endpoint object than the host name " "and add a custom variable to allow services setting the correct command " @@ -6931,43 +7049,47 @@ msgstr "" "Endpunktobjekt und füge eine benutzerdefinierte Variable hinzu, welche es " "Services erlaubt, den korrekten Commandendpunkt zu setzen." -#: application/forms/SelfServiceSettingsForm.php:84 +#: ../../../../application/forms/SelfServiceSettingsForm.php:84 msgid "Use a local file or network share" msgstr "Benutze eine lokales Verzeichnis oder eine Netzwerkfreigabe" -#: library/Director/PropertyModifier/PropertyModifierUpperCaseFirst.php:18 +#: ../../../../library/Director/PropertyModifier/PropertyModifierUpperCaseFirst.php:18 msgid "Use lowercase first" msgstr "Erst in Kleinbuchstaben umwandeln" -#: application/forms/SyncPropertyForm.php:273 +#: ../../../../application/forms/SyncPropertyForm.php:273 msgid "Used sources" msgstr "Verwendete Quellen" -#: library/Director/TranslationDummy.php:17 -#: application/forms/SyncRuleForm.php:17 +#: ../../../../library/Director/TranslationDummy.php:17 +#: ../../../../application/forms/SyncRuleForm.php:17 msgid "User" msgstr "Benutzer" -#: application/forms/SyncRuleForm.php:18 +#: ../../../../application/forms/SyncRuleForm.php:18 msgid "User Group" msgstr "Benutzergruppe" -#: library/Director/Dashboard/Dashlet/UserGroupsDashlet.php:11 -#: application/forms/BasketForm.php:27 +#: ../../../../library/Director/Dashboard/Dashlet/UserGroupsDashlet.php:13 +#: ../../../../application/forms/BasketForm.php:27 msgid "User Groups" msgstr "Benutzergruppen" -#: library/Director/Dashboard/Dashlet/UserTemplateDashlet.php:13 -#: application/forms/BasketForm.php:28 +#: ../../../../application/forms/IcingaNotificationForm.php:178 +msgid "User Groups Custom Variable" +msgstr "Variable für Benutzergruppen" + +#: ../../../../library/Director/Dashboard/Dashlet/UserTemplateDashlet.php:15 +#: ../../../../application/forms/BasketForm.php:28 msgid "User Templates" msgstr "Benutzervorlagen" -#: library/Director/DataType/DataTypeDirectorObject.php:63 -#: application/forms/IcingaNotificationForm.php:156 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:63 +#: ../../../../application/forms/IcingaNotificationForm.php:169 msgid "User groups" msgstr "Benutzergruppen" -#: application/forms/IcingaUserForm.php:113 +#: ../../../../application/forms/IcingaUserForm.php:113 msgid "" "User groups that should be directly assigned to this user. Groups can be " "useful for various reasons. You might prefer to send notifications to groups " @@ -6977,54 +7099,60 @@ msgstr "" "Gruppen können für verschiedene Aufgaben verwendet werden. Eventuell ist es " "besser, Benachrichtigungen an Gruppen statt an einzelne Benutzer zu schicken" -#: application/forms/IcingaNotificationForm.php:158 +#: ../../../../application/forms/IcingaNotificationForm.php:171 msgid "User groups that should be notified by this notifications" msgstr "" "Benutzergruppen, die durch diese Benachrichtigungen verständigt werden sollen" -#: application/forms/IcingaUserForm.php:194 +#: ../../../../application/forms/IcingaUserForm.php:194 msgid "User properties" msgstr "Benutzereigenschaften" -#: application/forms/IcingaUserForm.php:22 +#: ../../../../application/forms/IcingaUserForm.php:22 msgid "User template name" msgstr "Benutzervorlagenname" -#: application/forms/IcingaUserGroupForm.php:17 +#: ../../../../application/forms/IcingaUserGroupForm.php:17 msgid "Usergroup" msgstr "Benutzergruppe" -#: library/Director/Db/Branch/BranchModificationInspection.php:44 -#: library/Director/Import/ImportSourceCoreApi.php:63 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:44 +#: ../../../../library/Director/Import/ImportSourceCoreApi.php:63 msgid "Usergroups" msgstr "Benutzergruppen" -#: library/Director/Import/ImportSourceRestApi.php:226 -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:74 -#: application/forms/IcingaUserForm.php:28 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:226 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:74 +#: ../../../../application/forms/IcingaUserForm.php:28 msgid "Username" msgstr "Benutzername" -#: library/Director/DataType/DataTypeDirectorObject.php:62 -#: library/Director/Db/Branch/BranchModificationInspection.php:43 -#: library/Director/Import/ImportSourceCoreApi.php:62 -#: library/Director/Web/Table/CustomvarVariantsTable.php:62 -#: library/Director/Web/Table/CustomvarTable.php:47 -#: application/forms/IcingaNotificationForm.php:131 -#: application/forms/BasketForm.php:29 +#: ../../../../library/Director/DataType/DataTypeDirectorObject.php:62 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:43 +#: ../../../../library/Director/Import/ImportSourceCoreApi.php:62 +#: ../../../../library/Director/Web/Table/CustomvarVariantsTable.php:62 +#: ../../../../library/Director/Web/Table/CustomvarTable.php:47 +#: ../../../../application/forms/IcingaNotificationForm.php:126 +#: ../../../../application/forms/IcingaNotificationForm.php:132 +#: ../../../../application/forms/IcingaNotificationForm.php:163 +#: ../../../../application/forms/BasketForm.php:29 msgid "Users" msgstr "Benutzer" -#: library/Director/Dashboard/Dashlet/UserObjectDashlet.php:16 -#: library/Director/Dashboard/Dashlet/UsersDashlet.php:13 +#: ../../../../library/Director/Dashboard/Dashlet/UserObjectDashlet.php:13 +#: ../../../../library/Director/Dashboard/Dashlet/UsersDashlet.php:15 msgid "Users / Contacts" msgstr "Benutzer / Kontakte" -#: application/forms/IcingaNotificationForm.php:133 +#: ../../../../application/forms/IcingaNotificationForm.php:141 +msgid "Users Custom Variable" +msgstr "Variable für Benutzer" + +#: ../../../../application/forms/IcingaNotificationForm.php:134 msgid "Users that should be notified by this notifications" msgstr "Benutzer, die durch diese Benachrichtigungen verständigt werden sollen" -#: library/Director/Dashboard/Dashlet/ServiceApplyRulesDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/ServiceApplyRulesDashlet.php:19 msgid "" "Using Apply Rules a Service can be applied to multiple hosts at once, based " "on filters dealing with any combination of their properties" @@ -7033,55 +7161,55 @@ msgstr "" "werden, und zwar basierend auf Filtern welche einzelne oder mehrere " "Eigenschaften derselben kombinieren" -#: application/forms/IcingaHostForm.php:336 -#: application/forms/IcingaHostSelfServiceForm.php:44 +#: ../../../../application/forms/IcingaHostSelfServiceForm.php:44 +#: ../../../../application/forms/IcingaHostForm.php:338 msgid "Usually your hosts main IPv6 address" msgstr "Üblicherweise die Haupt-IPv6-Adresse des Hosts" -#: library/Director/Web/Table/BranchedIcingaCommandArgumentTable.php:47 -#: library/Director/Web/Table/IcingaCommandArgumentTable.php:50 -#: application/forms/IcingaServiceVarForm.php:27 -#: application/forms/IcingaCommandArgumentForm.php:50 -#: application/forms/IcingaCommandArgumentForm.php:59 -#: application/forms/CustomvarForm.php:21 -#: application/forms/IcingaHostVarForm.php:27 +#: ../../../../library/Director/Web/Table/BranchedIcingaCommandArgumentTable.php:47 +#: ../../../../library/Director/Web/Table/IcingaCommandArgumentTable.php:50 +#: ../../../../application/forms/IcingaServiceVarForm.php:27 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:50 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:59 +#: ../../../../application/forms/CustomvarForm.php:21 +#: ../../../../application/forms/IcingaHostVarForm.php:27 msgid "Value" msgstr "Wert" -#: application/forms/IcingaCommandArgumentForm.php:36 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:36 msgid "Value type" msgstr "Werttyp" -#: library/Director/Web/Table/CustomvarVariantsTable.php:56 +#: ../../../../library/Director/Web/Table/CustomvarVariantsTable.php:56 msgid "Variable Value" msgstr "Variablenwert" -#: library/Director/Web/Table/CustomvarTable.php:41 -#: application/forms/CustomvarForm.php:16 +#: ../../../../library/Director/Web/Table/CustomvarTable.php:41 +#: ../../../../application/forms/CustomvarForm.php:16 msgid "Variable name" msgstr "Variablenname" -#: library/Director/Import/ImportSourceRestApi.php:176 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:176 msgid "Verify Host" msgstr "Host überprüfen" -#: library/Director/Import/ImportSourceRestApi.php:169 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:169 msgid "Verify Peer" msgstr "Peer überprüfen" -#: library/Director/DataType/DataTypeString.php:24 +#: ../../../../library/Director/DataType/DataTypeString.php:24 msgid "Visibility" msgstr "Sichtbarkeit" -#: library/Director/DataType/DataTypeString.php:26 +#: ../../../../library/Director/DataType/DataTypeString.php:26 msgid "Visible" msgstr "Sichtbar" -#: library/Director/Web/Form/DirectorObjectForm.php:1486 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1489 msgid "Volatile" msgstr "Sprunghaft (Volatile)" -#: application/forms/IcingaCommandForm.php:80 +#: ../../../../application/forms/IcingaCommandForm.php:80 msgid "" "WARNING, this can allow shell script injection via custom variables used in " "command." @@ -7089,13 +7217,13 @@ msgstr "" "VORSICHT, hiermit schafft man die Möglichkeit über benutzerdefinierte " "Variablen Shell-Code in Kommandos zu injizieren." -#: library/Director/Dashboard/InfrastructureDashboard.php:50 +#: ../../../../library/Director/Dashboard/InfrastructureDashboard.php:50 #, php-format msgid "Want to connect to your Icinga Agents? Have a look at our %s!" msgstr "" "Sollen Icinga Agents verbunden werden? Riskieren einen Blick in unsere %s!" -#: library/Director/Dashboard/TimeperiodsDashboard.php:20 +#: ../../../../library/Director/Dashboard/TimeperiodsDashboard.php:20 msgid "" "Want to define to execute specific checks only withing specific time " "periods? Get mobile notifications only out of office hours, but mail " @@ -7107,11 +7235,11 @@ msgstr "" "Alarmierung via E-Mail rund um die Uhr? Zeiträume erlauben es, diese und " "ähnliche Anforderungen zu erfüllen." -#: library/Director/IcingaConfig/StateFilterSet.php:25 +#: ../../../../library/Director/IcingaConfig/StateFilterSet.php:25 msgid "Warning" msgstr "Warnung" -#: application/forms/DeployFormsBug7530.php:94 +#: ../../../../application/forms/DeployFormsBug7530.php:94 #, php-format msgid "" "Warning: you're running Icinga v2.11.0 and our configuration looks like you " @@ -7123,7 +7251,7 @@ msgstr "" "Lösung. Das GitHub-Issue und unsere %s enthalten weiterführende " "Informationen." -#: library/Director/Web/Form/DirectorObjectForm.php:1129 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1132 msgid "" "What kind of object this should be. Templates allow full access to any " "property, they are your building blocks for \"real\" objects. External " @@ -7140,7 +7268,7 @@ msgstr "" "erlauben das Zuweisen von Services, Benachrichtigungen und Gruppen an andere " "Objekte." -#: library/Director/PropertyModifier/PropertyModifierMap.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierMap.php:29 msgid "" "What should happen if the lookup key does not exist in the data list? You " "could return a null value, keep the unmodified imported value or interrupt " @@ -7150,24 +7278,24 @@ msgstr "" "befindet? Es kann ein null Wert zurückgegeben werden, der importierte Wert " "unverändert übernommen oder der Importvorgang unterbrochen werden" -#: library/Director/PropertyModifier/PropertyModifierSplit.php:24 -#: library/Director/PropertyModifier/PropertyModifierRegexSplit.php:24 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexSplit.php:24 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSplit.php:24 msgid "What should happen when the given string is empty?" msgstr "Was soll passieren wenn der übergebene String leer ist?" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:66 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:66 msgid "What should happen when the result array is empty?" msgstr "Was soll passieren wenn das resultierende Array leer ist?" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:51 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:51 msgid "What should happen when the specified element is not available?" msgstr "Was soll passieren wenn das spezifizierte Element nicht verfügbar ist?" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:53 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:53 msgid "What should happen with matching elements?" msgstr "Was soll mit passenden Elementen passieren?" -#: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:68 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php:68 msgid "" "What should happen with the row, when this property matches the given " "expression?" @@ -7175,54 +7303,58 @@ msgstr "" "Was soll mit der Zeile passieren, wenn der gegebene Ausdruck auf diese " "Eigenschaft zutrifft?" -#: library/Director/PropertyModifier/PropertyModifierDnsRecords.php:32 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:29 +msgid "What should happen, if the given pattern doesn't match" +msgstr "Was soll passieren, wenn das Muster nicht zutrifft?" + +#: ../../../../library/Director/PropertyModifier/PropertyModifierDnsRecords.php:32 msgid "What should we do if the DNS lookup fails?" msgstr "Was soll geschehen, wenn die (DNS) Auflösung fehlschlägt?" -#: library/Director/PropertyModifier/PropertyModifierParseURL.php:36 +#: ../../../../library/Director/PropertyModifier/PropertyModifierParseURL.php:36 msgid "" "What should we do if the URL could not get parsed or component not found?" msgstr "" "Was soll mit der URL geschehen, wenn sie nicht geparsed werden kann oder " "aber Komponenten davon nicht gefunden werden?" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:28 msgid "What should we do if the desired part does not exist?" msgstr "Was soll geschehen, wenn der gewünschte Teil nicht existiert?" -#: library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:15 -#: library/Director/PropertyModifier/PropertyModifierGetHostByName.php:15 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByAddr.php:15 +#: ../../../../library/Director/PropertyModifier/PropertyModifierGetHostByName.php:15 msgid "What should we do if the host (DNS) lookup fails?" msgstr "Was soll geschehen, wenn die (DNS) Auflösung fehlschlägt?" -#: library/Director/PropertyModifier/PropertyModifierArrayToRow.php:21 -#: library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayToRow.php:21 msgid "What should we do in case the given value is empty?" msgstr "Was soll passieren wenn der übergebene Wert leer ist?" -#: library/Director/PropertyModifier/PropertyModifierJsonDecode.php:22 +#: ../../../../library/Director/PropertyModifier/PropertyModifierJsonDecode.php:22 msgid "What should we do in case we are unable to decode the given string?" msgstr "" "Was soll geschehen, wenn sich der übergebene String nicht dekodieren lässt?" -#: library/Director/PropertyModifier/PropertyModifierListToObject.php:24 +#: ../../../../library/Director/PropertyModifier/PropertyModifierListToObject.php:24 msgid "What should we do, if the same key occurs twice?" msgstr "Was soll geschehen, wenn derselbe Schlüssel zweimal auftaucht?" -#: library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:16 +#: ../../../../library/Director/PropertyModifier/PropertyModifierExtractFromDN.php:16 msgid "What should we extract from the DN?" msgstr "Was soll aus dem DN extrahiert werden?" -#: application/forms/BasketForm.php:61 +#: ../../../../application/forms/BasketForm.php:61 msgid "" "What should we place into this Basket every time we create new snapshot?" msgstr "Was sollen wir beim Erstellen eines Snapshots in diesen Basket geben?" -#: application/forms/SelfServiceSettingsForm.php:21 +#: ../../../../application/forms/SelfServiceSettingsForm.php:21 msgid "What to use as your Icinga 2 Agent's Host Name" msgstr "Was soll als Hostname für den Icinga-2-Agent genutzt werden?" -#: library/Director/Job/ConfigJob.php:59 +#: ../../../../library/Director/Job/ConfigJob.php:59 msgid "" "When deploying configuration, wait at least this amount of seconds unless " "the next deployment should take place" @@ -7230,22 +7362,26 @@ msgstr "" "Beim Ausrollen einer Konfiguration mindestens diese Anzahl an Sekunden " "warten, bevor das nächste Ausrollen durchgeführt wird" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:63 -#: library/Director/PropertyModifier/PropertyModifierSplit.php:21 -#: library/Director/PropertyModifier/PropertyModifierRegexSplit.php:21 -#: library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:63 +#: ../../../../library/Director/PropertyModifier/PropertyModifierDictionaryToRow.php:27 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexSplit.php:21 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSplit.php:21 msgid "When empty" msgstr "Falls leer" -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:48 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:48 msgid "When not available" msgstr "Wenn nicht verfügbar" -#: application/forms/IcingaNotificationForm.php:210 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexReplace.php:27 +msgid "When not matched" +msgstr "Wenn nicht zugetroffen" + +#: ../../../../application/forms/IcingaNotificationForm.php:258 msgid "When the last notification should be sent" msgstr "Wann die letzte Nachricht versenderwerden" -#: library/Director/Dashboard/InfrastructureDashboard.php:44 +#: ../../../../library/Director/Dashboard/InfrastructureDashboard.php:44 msgid "" "When you feel the desire to manually create Zone or Endpoint objects please " "rethink this twice. Doing so is mostly the wrong way, might lead to a dead " @@ -7255,11 +7391,11 @@ msgstr "" "zweimal überdenken. Das ist meistens der falsche Weg, kann in Sackgassen " "führen und damit eine Menge Arbeit beim manuellen Aufräumen verursachen." -#: library/Director/PropertyModifier/PropertyModifierTrim.php:17 +#: ../../../../library/Director/PropertyModifier/PropertyModifierTrim.php:17 msgid "Where to trim the string(s)" msgstr "Wo String(s) gestutzt werden soll" -#: application/forms/IcingaScheduledDowntimeForm.php:104 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:104 msgid "" "Whether Downtimes should also explicitly be scheduled for all Services " "belonging to affected Hosts" @@ -7267,15 +7403,15 @@ msgstr "" "Ob Downtimes zudem explizit auch für alle zu den betroffenen Hosts gehörigen " "Services eingeplant werden sollen" -#: application/forms/SettingsForm.php:63 +#: ../../../../application/forms/SettingsForm.php:63 msgid "Whether all configured Jobs should be disabled" msgstr "Ob alle konfigurierten Jobs deaktiviert werden sollen" -#: library/Director/Web/Form/DirectorObjectForm.php:1459 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1462 msgid "Whether flap detection is enabled on this object" msgstr "Ob die Flapping-Erkennung für dieses Objekt aktiviert werden soll" -#: library/Director/Job/ConfigJob.php:33 +#: ../../../../library/Director/Job/ConfigJob.php:33 msgid "" "Whether rendering should be forced. If not enforced, this job re-renders the " "configuration only when there have been activities since the last rendered " @@ -7285,12 +7421,12 @@ msgstr "" "Konfiguration nur erstellt, falls seit dem letzten Erstellen Aktivitäten " "durchgeführt wurden" -#: application/forms/IcingaHostForm.php:94 +#: ../../../../application/forms/IcingaHostForm.php:96 msgid "Whether the agent is configured to accept config" msgstr "" "Ja, falls der Agent so konfiguriert ist, dass er Konfiguration akzeptiert" -#: application/forms/IcingaCommandArgumentForm.php:42 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:42 msgid "" "Whether the argument value is a string (allowing macros like $host$) or an " "Icinga DSL lambda function (will be enclosed with {{ ... }}" @@ -7298,7 +7434,7 @@ msgstr "" "Ist der Wert des Arguments eine Zeichenkette (erlaubt Makros wie $host$) " "oder eine Icinga-DSL-Lambda-Funktion? (wird in {{ ... }} eingeschlossen" -#: application/forms/IcingaServiceForm.php:680 +#: ../../../../application/forms/IcingaServiceForm.php:684 msgid "" "Whether the check commmand for this service should be executed on the Icinga " "agent" @@ -7306,7 +7442,7 @@ msgstr "" "Ob das Kommando für diesen Service auf dem Icinga-Agent ausgeführt werden " "soll" -#: application/forms/IcingaCommandArgumentForm.php:117 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:117 msgid "" "Whether the parameter name should not be passed to the command. Per default, " "the parameter name (e.g. -H) will be appended, so no need to explicitly set " @@ -7316,14 +7452,14 @@ msgstr "" "wird dieser (z.B. -H) hinzugefügt, es ist also nicht erforderlich dies " "explizit auf \"Nein\" zu setzen." -#: application/forms/IcingaHostForm.php:88 +#: ../../../../application/forms/IcingaHostForm.php:90 msgid "" "Whether the parent (master) node should actively try to connect to this agent" msgstr "" "Soll der (Master) Knoten aktiv versuchen, sich zu diesem Agenten zu " "verbinden?" -#: application/forms/IcingaCommandArgumentForm.php:81 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:81 msgid "" "Whether the set_if parameter is a string (allowing macros like $host$) or an " "Icinga DSL lambda function (will be enclosed with {{ ... }}" @@ -7331,20 +7467,20 @@ msgstr "" "Ist der set_if Parameter eine Zeichenkette (erlaubt Makros wie $host$) oder " "eine Icinga-DSL-Lambda-Funktion? (wird in {{ ... }} eingeschlossen" -#: application/forms/IcingaCommandArgumentForm.php:126 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:126 msgid "Whether this argument should be required" msgstr "Soll dieses Argument erforderlich sein?" -#: library/Director/Web/Form/DirectorObjectForm.php:1487 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1490 msgid "Whether this check is volatile." msgstr "Ist dieser Check sprunghaft (volatile)?" -#: application/forms/IcingaDependencyForm.php:95 -#: application/forms/IcingaScheduledDowntimeForm.php:84 +#: ../../../../application/forms/IcingaDependencyForm.php:95 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:84 msgid "Whether this dependency should affect hosts or services" msgstr "Soll diese Abhängigkeit Hosts oder Services betreffen" -#: application/forms/IcingaScheduledDowntimeForm.php:49 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:49 msgid "" "Whether this downtime is fixed or flexible. If unsure please check the " "related documentation: https://icinga.com/docs/icinga2/latest/doc/08-" @@ -7354,19 +7490,19 @@ msgstr "" "Dokumentation zu Rate ziehen: https://icinga.com/docs/icinga2/latest/doc/08-" "advanced-topics/#downtimes" -#: application/forms/IcingaObjectFieldForm.php:143 +#: ../../../../application/forms/IcingaObjectFieldForm.php:107 msgid "Whether this field should be mandatory" msgstr "Soll dieses Feld Pflicht sein?" -#: application/forms/IcingaHostForm.php:79 +#: ../../../../application/forms/IcingaHostForm.php:81 msgid "Whether this host has the Icinga 2 Agent installed" msgstr "Hat dieser Host den Icinga-2-Agent installiert?" -#: application/forms/IcingaNotificationForm.php:83 +#: ../../../../application/forms/IcingaNotificationForm.php:84 msgid "Whether this notification should affect hosts or services" msgstr "Soll diese Benachrichtigung Hosts oder Services betreffen" -#: application/forms/IcingaCommandArgumentForm.php:109 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:109 msgid "" "Whether this parameter should be repeated when multiple values (read: array) " "are given" @@ -7374,7 +7510,7 @@ msgstr "" "Soll dieser Parameter wiederholt werden, wenn mehrere Werte (in einem Array) " "angegeben werden" -#: library/Director/DataType/DataTypeDatalist.php:136 +#: ../../../../library/Director/DataType/DataTypeDatalist.php:136 msgid "" "Whether this should be a String or an Array in the generated Icinga " "configuration. In case you opt for Array, Director users will be able to " @@ -7384,7 +7520,7 @@ msgstr "" "sein soll. Wird Array gewählt, können Director-Benutzer mehrere Elemente aus " "einer Liste wählen" -#: application/forms/IcingaZoneForm.php:24 +#: ../../../../application/forms/IcingaZoneForm.php:24 msgid "" "Whether this zone should be available everywhere. Please note that it rarely " "leads to the desired result when you try to distribute global zones in " @@ -7393,30 +7529,30 @@ msgstr "" "Soll diese Zone überall verfügbar sein? Beachte, dass es selten zielführend " "ist, globale Zonen in verteilten Umgebungen zu verteilen" -#: library/Director/Web/Form/DirectorObjectForm.php:1435 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1438 msgid "Whether to accept passive check results for this object" msgstr "Sollen passive Checkergebnisse für dieses Objekt akzeptiert werden?" -#: library/Director/Web/Form/DirectorObjectForm.php:1429 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1432 msgid "Whether to actively check this object" msgstr "Soll dieses Objekt aktiv geprüft werden?" -#: application/forms/SelfServiceSettingsForm.php:33 +#: ../../../../application/forms/SelfServiceSettingsForm.php:33 msgid "Whether to adjust your host name" msgstr "Ob der Hostname angepasst werden soll" -#: application/forms/SyncRuleForm.php:84 +#: ../../../../application/forms/SyncRuleForm.php:84 msgid "Whether to delete or to disable objects subject to purge" msgstr "Ob zu bereinigende Objekte deaktiviert oder gelöscht werden sollen" -#: application/forms/IcingaDependencyForm.php:161 +#: ../../../../application/forms/IcingaDependencyForm.php:161 msgid "" "Whether to disable checks when this dependency fails. Defaults to false." msgstr "" "Ob Checks deaktiviert werden sollen, wenn diese Abhängigkeit fehlschlägt. " "Standardmäßig ist dies nicht der Fall." -#: application/forms/IcingaDependencyForm.php:169 +#: ../../../../application/forms/IcingaDependencyForm.php:169 msgid "" "Whether to disable notifications when this dependency fails. Defaults to " "true." @@ -7424,11 +7560,11 @@ msgstr "" "Sollen Benachrichtigungen deaktiviert werden, wenn diese Abhängigkeit " "fehlschlägt. Standard-Einstellung ist Ja." -#: library/Director/Web/Form/DirectorObjectForm.php:1447 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1450 msgid "Whether to enable event handlers this object" msgstr "Sollen Event-Handler für dieses Objekt aktiviert werden?" -#: application/forms/IcingaDependencyForm.php:177 +#: ../../../../application/forms/IcingaDependencyForm.php:177 msgid "" "Whether to ignore soft states for the reachability calculation. Defaults to " "true." @@ -7436,17 +7572,17 @@ msgstr "" "Ob Soft-States für die Berechnung der Erreichbarkeit berücksichtigt werden " "sollen. Dies ist standardmäßig der Fall." -#: application/forms/IcingaTimePeriodForm.php:77 +#: ../../../../application/forms/IcingaTimePeriodForm.php:77 msgid "Whether to prefer timeperiods includes or excludes. Default to true." msgstr "" "Ob das Einbinden oder Ausschließen von Zeiträumen bevorzugt werden soll. " "Standard-Einstellung ist Ja." -#: library/Director/Web/Form/DirectorObjectForm.php:1453 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1456 msgid "Whether to process performance data provided by this object" msgstr "Sollen Performancedaten von diesem Objekt verarbeitet werden?" -#: application/forms/SyncRuleForm.php:72 +#: ../../../../application/forms/SyncRuleForm.php:72 msgid "" "Whether to purge existing objects. This means that objects of the same type " "will be removed from Director in case they no longer exist at your import " @@ -7456,20 +7592,20 @@ msgstr "" "desselben Typs aus dem Director entfernt werden, falls sie in der " "Importquelle nicht mehr vorhanden sein sollten." -#: library/Director/Web/Form/DirectorObjectForm.php:1441 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1444 msgid "Whether to send notifications for this object" msgstr "Sollen Benachrichtigungen für dieses Objekt verschickt werden?" -#: application/forms/IcingaUserForm.php:90 +#: ../../../../application/forms/IcingaUserForm.php:90 msgid "Whether to send notifications for this user" msgstr "Sollen Benachrichtigungen für diesen Benutzer verschickt werden?" -#: library/Director/Import/ImportSourceRestApi.php:130 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:130 msgid "Whether to use encryption when talking to the REST API" msgstr "" "Ob für die Verbindung zu dieser REST-API Verschlüsselung benutzt werden soll" -#: library/Director/Import/ImportSourceRestApi.php:171 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:171 msgid "" "Whether we should check that our peer's certificate has been signed by a " "trusted CA. This is strongly recommended." @@ -7478,12 +7614,12 @@ msgstr "" "vertrauenswürdigen Zertifizierungsstelle signiert wurde. Das wird " "strengstens empfohlen." -#: library/Director/Import/ImportSourceRestApi.php:178 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:178 msgid "Whether we should check that the certificate matches theconfigured host" msgstr "" "Ob geprüft werden soll, dass die Zertifikate zum konfigurierten Host passen" -#: application/forms/SyncPropertyForm.php:119 +#: ../../../../application/forms/SyncPropertyForm.php:119 msgid "" "Whether you want to merge or replace the destination field. Makes no " "difference for strings" @@ -7491,7 +7627,7 @@ msgstr "" "Soll das Zielfeld zusammengeführt oder ersetzt werden? Macht keinen " "Unterschied für Zeichenketten" -#: application/forms/DirectorDatalistEntryForm.php:24 +#: ../../../../application/forms/DirectorDatalistEntryForm.php:24 msgid "" "Will be stored as a custom variable value when this entry is chosen from the " "list" @@ -7499,53 +7635,53 @@ msgstr "" "Wird als benutzerdefinierte Variable gespeichert, wenn dieser Eintrag aus " "der Liste gewählt wird" -#: library/Director/Import/ImportSourceRestApi.php:228 +#: ../../../../library/Director/Import/ImportSourceRestApi.php:228 msgid "Will be used to authenticate against your REST API" msgstr "Wird für die Authentifizierung gegen die REST-API benutzt" -#: library/Director/Web/SelfService.php:247 +#: ../../../../library/Director/Web/SelfService.php:234 msgid "Windows Kickstart Script" msgstr "Kickstart-Skript für Windows" -#: application/forms/DirectorDatafieldForm.php:53 +#: ../../../../application/forms/DirectorDatafieldForm.php:53 msgid "Wipe related vars" msgstr "Zugehörige Eigenschaften leeren" -#: application/forms/IcingaScheduledDowntimeForm.php:102 +#: ../../../../application/forms/IcingaScheduledDowntimeForm.php:102 msgid "With Services" msgstr "Mit Services" -#: library/Director/Dashboard/Dashlet/ActivityLogDashlet.php:17 +#: ../../../../library/Director/Dashboard/Dashlet/ActivityLogDashlet.php:19 msgid "Wondering about what changed why? Track your changes!" msgstr "Hier kann nachvollzogen werden, was weshalb verändert wurde." -#: library/Director/Dashboard/InfrastructureDashboard.php:35 +#: ../../../../library/Director/Dashboard/InfrastructureDashboard.php:35 msgid "Working with Agents and Config Zones" msgstr "Mit Agenten und Konfigurationszonen arbeiten" -#: application/views/helpers/FormDataFilter.php:525 +#: ../../../../application/views/helpers/FormDataFilter.php:525 msgid "Wrap this expression into an operator" msgstr "Diesen Ausdruck in einen Operator packen" -#: application/forms/IcingaDeleteObjectForm.php:17 +#: ../../../../application/forms/IcingaDeleteObjectForm.php:17 #, php-format msgid "YES, please delete \"%s\"" msgstr "JA, bitte \"%s\" löschen" -#: library/Director/Job/ImportJob.php:101 -#: library/Director/Job/ConfigJob.php:39 -#: library/Director/Job/ConfigJob.php:51 -#: library/Director/Job/SyncJob.php:101 -#: library/Director/PropertyModifier/PropertyModifierUpperCaseFirst.php:25 -#: application/forms/IcingaZoneForm.php:30 -#: application/forms/SettingsForm.php:59 -#: application/forms/SettingsForm.php:74 -#: application/forms/SettingsForm.php:96 -#: application/forms/SelfServiceSettingsForm.php:239 +#: ../../../../library/Director/Job/ImportJob.php:101 +#: ../../../../library/Director/Job/ConfigJob.php:39 +#: ../../../../library/Director/Job/ConfigJob.php:51 +#: ../../../../library/Director/Job/SyncJob.php:101 +#: ../../../../library/Director/PropertyModifier/PropertyModifierUpperCaseFirst.php:25 +#: ../../../../application/forms/IcingaZoneForm.php:30 +#: ../../../../application/forms/SettingsForm.php:59 +#: ../../../../application/forms/SettingsForm.php:74 +#: ../../../../application/forms/SettingsForm.php:96 +#: ../../../../application/forms/SelfServiceSettingsForm.php:239 msgid "Yes" msgstr "Ja" -#: application/controllers/BasketsController.php:41 +#: ../../../../application/controllers/BasketsController.php:41 msgid "" "You can create Basket snapshots at any time, this will persist a serialized " "representation of all involved objects at that moment in time. Snapshots can " @@ -7557,7 +7693,7 @@ msgstr "" "persistiert. Snapshots können exportiert, importiert, geteilt und " "wiederhergestellt werden - zur selben oder einer anderen Director-Instanz." -#: library/Director/Web/SelfService.php:129 +#: ../../../../library/Director/Web/SelfService.php:129 msgid "" "You can stop sharing a Template at any time. This will immediately " "invalidate the former key." @@ -7565,8 +7701,8 @@ msgstr "" "Die Freigabe einer Vorlage kann jederzeit widerrufen werden. Das macht den " "vorherigen Schlüssel sofort ungültig." -#: library/Director/Job/ImportJob.php:94 -#: library/Director/Job/SyncJob.php:94 +#: ../../../../library/Director/Job/ImportJob.php:94 +#: ../../../../library/Director/Job/SyncJob.php:94 msgid "" "You could immediately apply eventual changes or just learn about them. In " "case you do not want them to be applied immediately, defining a job still " @@ -7577,7 +7713,7 @@ msgstr "" "nicht sofort angewandt werden, ist es immer noch sinnvoll, einen Auftrag zu " "erstellen. Verfügbare Änderungen werden in der Director-GUI angezeigt." -#: application/forms/SelfServiceSettingsForm.php:74 +#: ../../../../application/forms/SelfServiceSettingsForm.php:74 msgid "" "You might want to let the generated Powershell script install the Icinga 2 " "Agent in an automated way. If so, please choose where your Windows nodes " @@ -7587,7 +7723,7 @@ msgstr "" "Agenten automatisch installiert. Falls das gewünscht ist gilt es hier zu " "wühlen, von wo sich die Windows-Knoten den Agenten-Installer besorgen sollen" -#: application/forms/IcingaObjectFieldForm.php:169 +#: ../../../../application/forms/IcingaObjectFieldForm.php:118 msgid "" "You might want to show this field only when certain conditions are met. " "Otherwise it will not be available and values eventually set before will be " @@ -7597,7 +7733,7 @@ msgstr "" "anzuzeigen. Treffen diese nicht zu wird es nicht angezeigt, eventuell " "zugehörige Eigenschaften werden beim Speichern dann auch wieder entfernt." -#: application/forms/ImportRowModifierForm.php:44 +#: ../../../../application/forms/ImportRowModifierForm.php:44 msgid "" "You might want to write the modified value to another (new) property. This " "property name can be defined here, the original property would remain " @@ -7610,19 +7746,31 @@ msgstr "" "lediglich der ursprüngliche Wert an Ort und Stelle geändert werden soll, " "dieses Feld bitte leer lassen" -#: application/controllers/SyncruleController.php:153 +#: ../../../../application/controllers/SyncruleController.php:153 #, php-format msgid "You must define some %s before you can run this Sync Rule" msgstr "" "Bevor dieses Synchronisationsregel ausgeführt werden kann, müssen %s " "definiert werden" -#: library/Director/Dashboard/BranchesDashboard.php:19 +#: ../../../../library/Director/Web/Widget/BranchedObjectsHint.php:21 +msgid "" +"You're currently in the master branch, your changes will make part of the " +"next Deployment" +msgstr "" +"Befindet man sich im master-Branch, werden durchgeführte Änderungen Teil des " +"nächsten Deployments" + +#: ../../../../library/Director/Dashboard/BranchesDashboard.php:21 #, php-format msgid "You're currently working in a Configuration Branch: %s" msgstr "Gegenwärtig wird in einem Konfigurationszweig gearbeitet: %s" -#: application/controllers/IndexController.php:35 +#: ../../../../library/Director/Dashboard/BranchesDashboard.php:28 +msgid "You're currently working in the main Configuration Branch" +msgstr "Gegenwärtig wird im Hauptkonfigurationszweig gearbeitet" + +#: ../../../../application/controllers/IndexController.php:35 #, php-format msgid "" "Your DB schema (migration #%d) is newer than your code base. Downgrading " @@ -7632,27 +7780,23 @@ msgstr "" "Quellcode. Ein Downgrade des Icinga Directors wird nicht unterstützt und " "kann zu unerwarteten Problemen führen." -#: application/forms/KickstartForm.php:157 +#: ../../../../application/forms/KickstartForm.php:157 msgid "Your Icinga 2 API username" msgstr "Der Icinga-2-API Benutzername" -#: library/Director/Import/ImportSourceLdap.php:52 +#: ../../../../library/Director/Import/ImportSourceLdap.php:52 msgid "" "Your LDAP search base. Often something like OU=Users,OU=HQ,DC=your," "DC=company,DC=tld" msgstr "" "Die LDAP Suchbasis. Meist etwas wie OU=Users,OU=HQ,DC=your,DC=company,DC=tld" -#: library/Director/Web/Widget/BranchedObjectHint.php:42 +#: ../../../../library/Director/Web/Widget/BranchedObjectHint.php:52 #, php-format -msgid "" -"Your changes will be stored in %s. The'll not be part of any deployment " -"unless being merged" -msgstr "" -"Änderungen werden in %s gespeichert. Sie sind nicht Teil eines eventuellen " -"Deployments, solange sie nicht zusammengeführt werden" +msgid "Your changes are going to be stored in %s." +msgstr "Die Änderungen werden in %s gespeichert werden." -#: application/forms/KickstartForm.php:98 +#: ../../../../application/forms/KickstartForm.php:98 msgid "" "Your configuration looks good. Still, you might want to re-run this " "kickstart wizard to (re-)import modified or new manually defined Command " @@ -7663,13 +7807,13 @@ msgstr "" "Kommandodefinitionen oder neue ITL-Kommandos nach einem Icinga-2-Core-" "Upgrade (neu) zu importieren." -#: application/forms/KickstartForm.php:76 +#: ../../../../application/forms/KickstartForm.php:76 #, php-format msgid "Your database looks good, you are ready to %s" msgstr "" "Datenbank sieht gut aus. Icinga Director sollte jetzt fertig für %s sein." -#: application/forms/KickstartForm.php:110 +#: ../../../../application/forms/KickstartForm.php:110 msgid "" "Your installation of Icinga Director has not yet been prepared for " "deployments. This kickstart wizard will assist you with setting up the " @@ -7679,240 +7823,267 @@ msgstr "" "Konfiguration vorbereitet. Dieser Kickstart-Assistent hilft bei der " "Einrichtung der Verbindung zum Icinga 2 Server." -#: library/Director/Web/Form/DirectorObjectForm.php:1372 +#: ../../../../library/Director/Web/Form/DirectorObjectForm.php:1375 msgid "Your regular check interval" msgstr "Der übliche Check-Intervall" -#: library/Director/PropertyModifier/PropertyModifierReplace.php:20 -#: library/Director/PropertyModifier/PropertyModifierReplaceNull.php:20 +#: ../../../../library/Director/PropertyModifier/PropertyModifierReplaceNull.php:20 +#: ../../../../library/Director/PropertyModifier/PropertyModifierReplace.php:20 msgid "Your replacement string" msgstr "Die Ersatzzeichenkette" -#: application/forms/IcingaTemplateChoiceForm.php:67 +#: ../../../../application/forms/IcingaTemplateChoiceForm.php:67 msgid "Your users will be allowed to choose among those templates" msgstr "Benutzern wird erlaubt, zwischen diesen Vorlagen zu wählen" -#: library/Director/TranslationDummy.php:15 -#: library/Director/Import/ImportSourceDirectorObject.php:73 -#: library/Director/Web/Table/ObjectsTableEndpoint.php:21 -#: application/forms/SyncRuleForm.php:26 +#: ../../../../library/Director/TranslationDummy.php:15 +#: ../../../../library/Director/Import/ImportSourceDirectorObject.php:73 +#: ../../../../library/Director/Web/Table/ObjectsTableEndpoint.php:21 +#: ../../../../application/forms/SyncRuleForm.php:26 msgid "Zone" msgstr "Zone" -#: application/forms/IcingaZoneForm.php:14 +#: ../../../../application/forms/IcingaZoneForm.php:14 msgid "Zone name" msgstr "Zonenname" -#: application/forms/IcingaUserForm.php:76 -#: application/forms/IcingaNotificationForm.php:65 -#: application/forms/IcingaCommandForm.php:110 -#: application/forms/IcingaUserGroupForm.php:42 -#: application/forms/IcingaDependencyForm.php:61 +#: ../../../../application/forms/IcingaUserForm.php:76 +#: ../../../../application/forms/IcingaNotificationForm.php:66 +#: ../../../../application/forms/IcingaCommandForm.php:110 +#: ../../../../application/forms/IcingaUserGroupForm.php:42 +#: ../../../../application/forms/IcingaDependencyForm.php:61 msgid "Zone settings" msgstr "Zoneneinstellungen" -#: library/Director/Dashboard/Dashlet/ZoneObjectDashlet.php:13 -#: library/Director/Db/Branch/BranchModificationInspection.php:36 -#: library/Director/Import/ImportSourceCoreApi.php:64 +#: ../../../../library/Director/Dashboard/Dashlet/ZoneObjectDashlet.php:15 +#: ../../../../library/Director/Db/Branch/BranchModificationInspection.php:36 +#: ../../../../library/Director/Import/ImportSourceCoreApi.php:64 msgid "Zones" msgstr "Zonen" -#: application/forms/SyncPropertyForm.php:348 +#: ../../../../application/forms/SyncPropertyForm.php:348 msgid "a list" msgstr "eine Liste" -#: library/Director/Web/Widget/InspectPackages.php:122 +#: ../../../../library/Director/Web/Widget/InspectPackages.php:122 msgid "active" msgstr "aktiv" -#: library/Director/Web/Widget/AdditionalTableActions.php:87 +#: ../../../../library/Director/Web/Widget/AdditionalTableActions.php:88 msgid "all" msgstr "alle" -#: library/Director/Web/ActionBar/DirectorBaseActionBar.php:35 -#: library/Director/Web/Controller/ObjectController.php:278 -#: library/Director/Web/Controller/ObjectController.php:638 -#: library/Director/Web/Controller/ActionController.php:182 -#: application/controllers/ServiceController.php:156 -#: application/controllers/ServiceController.php:216 -#: application/controllers/HostController.php:564 -#: application/controllers/BasketController.php:98 -#: application/controllers/BasketController.php:116 -#: application/controllers/BasketController.php:357 -#: application/controllers/ImportsourceController.php:366 -#: application/controllers/SyncruleController.php:612 -#: application/controllers/DataController.php:138 +#: ../../../../library/Director/Web/ActionBar/DirectorBaseActionBar.php:35 +#: ../../../../library/Director/Web/Controller/ActionController.php:182 +#: ../../../../library/Director/Web/Controller/ObjectController.php:281 +#: ../../../../library/Director/Web/Controller/ObjectController.php:649 +#: ../../../../application/controllers/ServiceController.php:156 +#: ../../../../application/controllers/ServiceController.php:216 +#: ../../../../application/controllers/HostController.php:542 +#: ../../../../application/controllers/BasketController.php:96 +#: ../../../../application/controllers/BasketController.php:114 +#: ../../../../application/controllers/BasketController.php:133 +#: ../../../../application/controllers/BasketController.php:368 +#: ../../../../application/controllers/ImportsourceController.php:366 +#: ../../../../application/controllers/SyncruleController.php:611 +#: ../../../../application/controllers/DataController.php:138 msgid "back" msgstr "Zurück" -#: library/Director/Web/Widget/BranchedObjectsHint.php:24 -#: library/Director/Web/Controller/ObjectController.php:722 -#: application/controllers/ConfigController.php:447 +#: ../../../../library/Director/Web/Widget/BranchedObjectsHint.php:29 +#: ../../../../library/Director/Web/Controller/ObjectController.php:733 +#: ../../../../application/controllers/ConfigController.php:448 msgid "configuration branch" msgstr "Konfigurationszweig" -#: application/locale/translateMe.php:11 +#: ../../../../application/locale/translateMe.php:11 msgid "critical" msgstr "Kritisch" -#: library/Director/Web/Table/Dependency/DependencyInfoTable.php:57 +#: ../../../../library/Director/Web/Table/Dependency/DependencyInfoTable.php:57 msgid "disabled" msgstr "deaktiviert" -#: library/Director/Dashboard/InfrastructureDashboard.php:32 -#: application/controllers/DaemonController.php:43 +#: ../../../../library/Director/Dashboard/InfrastructureDashboard.php:32 +#: ../../../../application/controllers/DaemonController.php:43 msgid "documentation" msgstr "Dokumentation" -#: application/locale/translateMe.php:6 +#: ../../../../application/locale/translateMe.php:6 msgid "down" msgstr "Down" -#: application/forms/IcingaCommandArgumentForm.php:27 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:27 msgid "e.g. -H or --hostname, empty means \"skip_key\"" msgstr "z.B. -H oder --hostname, leer bedeutet \"skip_key\"" -#: application/forms/IcingaCommandArgumentForm.php:61 +#: ../../../../application/forms/IcingaCommandArgumentForm.php:61 msgid "e.g. 5%, $host.name$, $lower$%:$upper$%" msgstr "z.B. 5%, $host.name$, $lower$%:$upper$%" -#: application/forms/SyncPropertyForm.php:165 +#: ../../../../application/forms/SyncPropertyForm.php:165 msgid "failed to fetch" msgstr "Abholen fehlgeschlagen" -#: library/Director/Util.php:161 -#: library/Director/Web/Form/ClickHereForm.php:17 -#: application/forms/KickstartForm.php:236 +#: ../../../../library/Director/Util.php:161 +#: ../../../../library/Director/Web/Form/ClickHereForm.php:17 +#: ../../../../application/forms/KickstartForm.php:236 msgid "here" msgstr "hier" -#: application/forms/IcingaHostVarForm.php:23 +#: ../../../../application/forms/IcingaHostVarForm.php:23 msgid "host var name" msgstr "host var name" -#: application/forms/IcingaHostVarForm.php:28 +#: ../../../../application/forms/IcingaHostVarForm.php:28 msgid "host var value" msgstr "host var value" -#: library/Director/Web/Table/Dependency/DependencyInfoTable.php:60 +#: ../../../../library/Director/Web/Table/Dependency/DependencyInfoTable.php:60 msgid "missing" msgstr "fehlend" -#: application/controllers/BasketController.php:304 +#: ../../../../application/controllers/BasketController.php:304 msgid "modified" msgstr "geändert" -#: library/Director/Web/Table/Dependency/DependencyInfoTable.php:65 +#: ../../../../library/Director/Web/Table/Dependency/DependencyInfoTable.php:65 msgid "more" msgstr "mehr" -#: application/controllers/BasketController.php:282 +#: ../../../../application/controllers/BasketController.php:314 msgid "new" msgstr "neu" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:78 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:78 msgid "no" msgstr "nein" -#: library/Director/Dashboard/Dashlet/Dashlet.php:222 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:222 msgid "no related group exists" msgstr "keine verwandte Gruppe existiert" -#: application/locale/translateMe.php:9 +#: ../../../../application/locale/translateMe.php:9 msgid "ok" msgstr "ok" -#: library/Director/Web/Widget/ActivityLogInfo.php:316 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:316 msgid "on host" msgstr "auf dem Host" -#: library/Director/Web/Widget/ActivityLogInfo.php:298 +#: ../../../../library/Director/Web/Widget/ActivityLogInfo.php:298 msgid "on service set" msgstr "am Service-Set" -#: library/Director/Dashboard/Dashlet/Dashlet.php:224 +#: ../../../../library/Director/Dashboard/Dashlet/Dashlet.php:224 msgid "one related group exists" msgstr "eine verwandte Gruppe existiert" -#: application/locale/translateMe.php:8 +#: ../../../../application/locale/translateMe.php:8 msgid "pending" msgstr "ausstehend" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:71 -#: library/Director/PropertyModifier/PropertyModifierSplit.php:29 -#: library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:56 -#: library/Director/PropertyModifier/PropertyModifierRegexSplit.php:29 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:71 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayElementByPosition.php:56 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexSplit.php:29 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSplit.php:29 msgid "return NULL" msgstr "NULL zurückgeben" -#: library/Director/PropertyModifier/PropertyModifierArrayFilter.php:70 -#: library/Director/PropertyModifier/PropertyModifierSplit.php:28 -#: library/Director/PropertyModifier/PropertyModifierRegexSplit.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierArrayFilter.php:70 +#: ../../../../library/Director/PropertyModifier/PropertyModifierRegexSplit.php:28 +#: ../../../../library/Director/PropertyModifier/PropertyModifierSplit.php:28 msgid "return an empty array" msgstr "ein leeres Array zurückliefern" -#: application/forms/IcingaServiceVarForm.php:23 +#: ../../../../application/forms/IcingaServiceVarForm.php:23 msgid "service var name" msgstr "service var name" -#: application/forms/IcingaServiceVarForm.php:28 +#: ../../../../application/forms/IcingaServiceVarForm.php:28 msgid "service var value" msgstr "service var value" -#: application/forms/KickstartForm.php:78 +#: ../../../../application/forms/KickstartForm.php:78 msgid "start working with the Icinga Director" msgstr "die Arbeit mit dem Icinga Director zu beginnen" -#: library/Director/Web/Widget/BranchedObjectHint.php:27 +#: ../../../../library/Director/Web/Widget/BranchedObjectHint.php:24 +msgid "the main configuration branch" +msgstr "der Hauptkonfigurationszweig" + +#: ../../../../library/Director/Web/Widget/BranchedObjectHint.php:36 msgid "this configuration branch" msgstr "diesem Konfigurationszweig" -#: application/controllers/BasketController.php:308 +#: ../../../../application/controllers/BasketController.php:310 msgid "unchanged" msgstr "unverändert" -#: application/locale/translateMe.php:12 +#: ../../../../application/locale/translateMe.php:12 msgid "unknown" msgstr "Unbekannt" -#: application/locale/translateMe.php:7 +#: ../../../../application/locale/translateMe.php:7 msgid "unreachable" msgstr "unreachable" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:89 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:89 msgid "unsupported" msgstr "nicht unterstützt" -#: library/Director/Web/Widget/AdditionalTableActions.php:89 +#: ../../../../library/Director/Web/Widget/AdditionalTableActions.php:90 msgid "unused" msgstr "unbenutzt" -#: application/locale/translateMe.php:5 +#: ../../../../application/locale/translateMe.php:5 msgid "up" msgstr "up" -#: library/Director/Web/Widget/AdditionalTableActions.php:88 +#: ../../../../library/Director/Web/Widget/AdditionalTableActions.php:89 msgid "used" msgstr "benutzt" -#: application/forms/IcingaServiceVarForm.php:33 -#: application/forms/IcingaHostVarForm.php:33 +#: ../../../../application/forms/IcingaServiceVarForm.php:33 +#: ../../../../application/forms/IcingaHostVarForm.php:33 msgid "value format" msgstr "Wertformat" -#: library/Director/Web/Table/GroupMemberTable.php:74 -#: library/Director/Web/Table/GroupMemberTable.php:79 +#: ../../../../library/Director/Web/Table/GroupMemberTable.php:74 +#: ../../../../library/Director/Web/Table/GroupMemberTable.php:79 msgid "via" msgstr "via" -#: application/locale/translateMe.php:10 +#: ../../../../application/locale/translateMe.php:10 msgid "warning" msgstr "warning" -#: library/Director/Web/Widget/BackgroundDaemonDetails.php:77 +#: ../../../../library/Director/Web/Widget/BackgroundDaemonDetails.php:77 msgid "yes" msgstr "ja" +#~ msgid "A description about the field" +#~ msgstr "Eine Beschreibung des Feldes" + +#~ msgid "Icinga 2 Powershell Module" +#~ msgstr "Icinga 2 Powershell Modul" + +#, php-format +#~ msgid "In case you're using the legacy %s, please run:" +#~ msgstr "" +#~ "Falls das vorherige %s benutzt wird, bitte dieses Script ausführen:" + +#~ msgid "The caption which should be displayed" +#~ msgstr "Die Beschriftung, die angezeigt werden soll" + +#, php-format +#~ msgid "" +#~ "Your changes will be stored in %s. The'll not be part of any deployment " +#~ "unless being merged" +#~ msgstr "" +#~ "Änderungen werden in %s gespeichert. Sie sind nicht Teil eines " +#~ "eventuellen Deployments, solange sie nicht zusammengeführt werden" + #~ msgid "Create a new Service Set" #~ msgstr "Ein neues Service-Set erstellen" diff --git a/application/locale/it_IT/LC_MESSAGES/director.po b/application/locale/it_IT/LC_MESSAGES/director.po index c4f6d2d..2e97485 100644 --- a/application/locale/it_IT/LC_MESSAGES/director.po +++ b/application/locale/it_IT/LC_MESSAGES/director.po @@ -1839,7 +1839,7 @@ msgstr "" "essere basate sui gruppi." #: application/forms/IcingaNotificationForm.php:199 -msgid "Delay unless the first notification should be sent" +msgid "Delay until the first notification should be sent" msgstr "Ritarda prima di spedire la prima notifica" #: application/forms/IcingaObjectFieldForm.php:193 @@ -1979,7 +1979,7 @@ msgid "Disable Checks" msgstr "Disattivare i Checks" #: application/forms/IcingaDependencyForm.php:167 -msgid "Disable Notificiations" +msgid "Disable Notifications" msgstr "Disattivare le notifiche" #: application/forms/SettingsForm.php:54 diff --git a/application/locale/ja_JP/LC_MESSAGES/director.po b/application/locale/ja_JP/LC_MESSAGES/director.po index d1bec38..63064d9 100644 --- a/application/locale/ja_JP/LC_MESSAGES/director.po +++ b/application/locale/ja_JP/LC_MESSAGES/director.po @@ -1665,7 +1665,7 @@ msgstr "サービスグループを定義すると、より構造がわかりま "最適です。 通知と許可はグループに基づいている場合があります。" #: ../../../../modules/director/application/forms/IcingaNotificationForm.php:196 -msgid "Delay unless the first notification should be sent" +msgid "Delay until the first notification should be sent" msgstr "最初の通知時間" #: ../../../../modules/director/application/forms/IcingaObjectFieldForm.php:185 @@ -1791,7 +1791,7 @@ msgstr "監視を無効化" # smori #: ../../../../modules/director/application/forms/IcingaDependencyForm.php:164 -msgid "Disable Notificiations" +msgid "Disable Notifications" msgstr "通知を無効化" #: ../../../../modules/director/application/forms/SettingsForm.php:54 diff --git a/application/views/helpers/FormDataFilter.php b/application/views/helpers/FormDataFilter.php index d8bc508..a62b906 100644 --- a/application/views/helpers/FormDataFilter.php +++ b/application/views/helpers/FormDataFilter.php @@ -44,14 +44,16 @@ class Zend_View_Helper_FormDataFilter extends Zend_View_Helper_FormElement { $info = $this->_getInfo($name, $value, $attribs); extract($info); // id, name, value, attribs, options, listsep, disable - if (array_key_exists('columns', $attribs)) { - $this->setColumns($attribs['columns']); - unset($attribs['columns']); - } + if ($attribs) { + if (array_key_exists('columns', $attribs)) { + $this->setColumns($attribs['columns']); + unset($attribs['columns']); + } - if (array_key_exists('suggestionContext', $attribs)) { - $this->setSuggestionContext($attribs['suggestionContext']); - unset($attribs['suggestionContext']); + if (array_key_exists('suggestionContext', $attribs)) { + $this->setSuggestionContext($attribs['suggestionContext']); + unset($attribs['suggestionContext']); + } } // TODO: check for columns in attribs, preserve & remove them from the @@ -217,7 +219,7 @@ class Zend_View_Helper_FormDataFilter extends Zend_View_Helper_FormElement } elseif (substr($col, $prefixLen, 5) === 'vars.') { $var = substr($col, $prefixLen + 5); - return $this->text($filter, "DataListValues!${var}"); + return $this->text($filter, "DataListValues!{$var}"); } } @@ -236,7 +238,7 @@ class Zend_View_Helper_FormDataFilter extends Zend_View_Helper_FormElement $filter->getExpression(), [ 'class' => 'director-suggest', - 'data-suggestion-context' => "${type}groupnames", + 'data-suggestion-context' => "{$type}groupnames", ] ); } diff --git a/application/views/helpers/FormStoredPassword.php b/application/views/helpers/FormStoredPassword.php index e25a1dc..b746ed4 100644 --- a/application/views/helpers/FormStoredPassword.php +++ b/application/views/helpers/FormStoredPassword.php @@ -8,8 +8,8 @@ use ipl\Html\HtmlDocument; * * We're rendering the following fields: * - * - ${name}[_value]: - * - ${name}[_sent]: + * - {$name}[_value]: + * - {$name}[_sent]: * * Avoid complaints about class names: * @codingStandardsIgnoreStart @@ -26,14 +26,14 @@ class Zend_View_Helper_FormStoredPassword extends Zend_View_Helper_FormElement $res = new HtmlDocument(); $el = Html::tag('input', [ 'type' => 'password', - 'name' => "${name}[_value]", + 'name' => "{$name}[_value]", 'id' => $id, ]); $res->add($el); $res->add(Html::tag('input', [ 'type' => 'hidden', - 'name' => "${name}[_sent]", + 'name' => "{$name}[_sent]", 'value' => 'y' ])); diff --git a/configuration.php b/configuration.php index 4536d5d..f812f3c 100644 --- a/configuration.php +++ b/configuration.php @@ -1,100 +1,99 @@ <?php use Icinga\Application\Icinga; +use Icinga\Application\Modules\Module; +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Auth\Restriction; use Icinga\Web\Window; -/** @var \Icinga\Application\Modules\Module $this */ +/** @var Module $this */ if ($this->getConfig()->get('frontend', 'disabled', 'no') === 'yes') { return; } -$this->providePermission('director/api', $this->translate('Allow to access the director API')); -$this->providePermission('director/audit', $this->translate('Allow to access the full audit log')); -$this->providePermission( - 'director/showconfig', - $this->translate('Allow to show configuration (could contain sensitive information)') -); -$this->providePermission( - 'director/showsql', - $this->translate('Allow to show the full executed SQL queries in some places') -); -$this->providePermission('director/deploy', $this->translate('Allow to deploy configuration')); -$this->providePermission('director/hosts', $this->translate('Allow to configure hosts')); -$this->providePermission('director/services', $this->translate('Allow to configure services')); -$this->providePermission('director/servicesets', $this->translate('Allow to configure service sets')); -$this->providePermission('director/service_set/apply', $this->translate('Allow to define Service Set Apply Rules')); -$this->providePermission('director/users', $this->translate('Allow to configure users')); -$this->providePermission('director/notifications', $this->translate('Allow to configure notifications (unrestricted)')); -$this->providePermission( - 'director/scheduled-downtimes', - $this->translate('Allow to configure notifications (unrestricted)') -); -$this->providePermission( - 'director/inspect', - $this->translate( - 'Allow to inspect objects through the Icinga 2 API (could contain sensitive information)' - ) -); -$this->providePermission( - 'director/monitoring/services-ro', - $this->translate('Allow readonly users to see where a Service came from') -); -$this->providePermission( - 'director/monitoring/hosts', - $this->translate('Allow users to modify Hosts they are allowed to see in the monitoring module') -); -$this->providePermission( - 'director/monitoring/services', - $this->translate('Allow users to modify Service they are allowed to see in the monitoring module') -); -$this->providePermission('director/*', $this->translate('Allow unrestricted access to Icinga Director')); -$this->provideRestriction( - 'director/filter/hostgroups', - $this->translate( - 'Limit access to the given comma-separated list of hostgroups' - ) -); +$monitoringExists = Module::exists('monitoring'); +$icingadbExists = Module::exists('icingadb'); -$this->provideRestriction( - 'director/monitoring/rw-object-filter', - $this->translate( - 'Additional (monitoring module) object filter to further restrict write access' - ) -); +$this->providePermission(Permission::ALL_PERMISSIONS, $this->translate('Allow unrestricted access to Icinga Director')); +$this->providePermission(Permission::API, $this->translate('Allow to access the director API')); +$this->providePermission(Permission::AUDIT, $this->translate('Allow to access the full audit log')); +$this->providePermission(Permission::DEPLOY, $this->translate('Allow to deploy configuration')); +$this->providePermission(Permission::INSPECT, $this->translate( + 'Allow to inspect objects through the Icinga 2 API (could contain sensitive information)' +)); +$this->providePermission(Permission::SHOW_CONFIG, $this->translate( + 'Allow to show configuration (could contain sensitive information)' +)); +$this->providePermission(Permission::SHOW_SQL, $this->translate( + 'Allow to show the full executed SQL queries in some places' +)); +$this->providePermission(Permission::GROUPS_FOR_RESTRICTED_HOSTS, $this->translate( + 'Allow users with Hostgroup restrictions to access the Groups field' +)); +$this->providePermission(Permission::HOSTS, $this->translate('Allow to configure hosts')); +$this->providePermission(Permission::NOTIFICATIONS, $this->translate( + 'Allow to configure notifications (unrestricted)' +)); +$this->providePermission(Permission::SERVICES, $this->translate('Allow to configure services')); +$this->providePermission(Permission::SERVICE_SETS, $this->translate('Allow to configure service sets')); +$this->providePermission(Permission::SERVICE_SET_APPLY, $this->translate('Allow to define Service Set Apply Rules')); +$this->providePermission(Permission::USERS, $this->translate('Allow to configure users')); +$this->providePermission(Permission::SCHEDULED_DOWNTIMES, $this->translate( + 'Allow to configure notifications (unrestricted)' +)); -$this->providePermission( - 'director/groups-for-restricted-hosts', - $this->translate('Allow users with Hostgroup restrictions to access the Groups field') -); +if ($monitoringExists) { + $this->providePermission(Permission::MONITORING_HOSTS, $this->translate( + 'Allow users to modify Hosts they are allowed to see in the monitoring module' + )); + $this->providePermission(Permission::MONITORING_SERVICES, $this->translate( + 'Allow users to modify Service they are allowed to see in the monitoring module' + )); + $this->providePermission(Permission::MONITORING_SERVICES_RO, $this->translate( + 'Allow readonly users to see where a Service came from' + )); +} -$this->provideRestriction( - 'director/service/apply/filter-by-name', - $this->translate( - 'Filter available service apply rules' - ) -); +if ($icingadbExists) { + $this->providePermission(Permission::ICINGADB_HOSTS, $this->translate( + 'Allow users to modify Hosts they are allowed to see in Icinga DB Web' + )); + $this->providePermission(Permission::ICINGADB_SERVICES, $this->translate( + 'Allow users to modify Service they are allowed to see in Icinga DB Web' + )); + $this->providePermission(Permission::ICINGADB_SERVICES_RO, $this->translate( + 'Allow readonly users to see where a Service came from' + )); +} -$this->provideRestriction( - 'director/notification/apply/filter-by-name', - $this->translate( - 'Filter available notification apply rules' - ) -); +if ($monitoringExists) { + $this->provideRestriction(Restriction::MONITORING_RW_OBJECT_FILTER, $this->translate( + 'Additional (monitoring module) object filter to further restrict write access' + )); +} -$this->provideRestriction( - 'director/scheduled-downtime/apply/filter-by-name', - $this->translate( - 'Filter available scheduled downtime rules' - ) -); +if ($icingadbExists) { + $this->provideRestriction(Restriction::ICINGADB_RW_OBJECT_FILTER, $this->translate( + 'Additional (Icinga DB Web) object filter to further restrict write access' + )); +} -$this->provideRestriction( - 'director/service_set/filter-by-name', - $this->translate( - 'Filter available service set templates. Use asterisks (*) as wildcards,' - . ' like in DB* or *net*' - ) -); +$this->provideRestriction(Restriction::FILTER_HOSTGROUPS, $this->translate( + 'Limit access to the given comma-separated list of hostgroups' +)); +$this->provideRestriction(Restriction::NOTIFICATION_APPLY_FILTER_BY_NAME, $this->translate( + 'Filter available notification apply rules' +)); +$this->provideRestriction(Restriction::SCHEDULED_DOWNTIME_APPLY_FILTER_BY_NAME, $this->translate( + 'Filter available scheduled downtime rules' +)); +$this->provideRestriction(Restriction::SERVICE_APPLY_FILTER_BY_NAME, $this->translate( + 'Filter available service apply rules' +)); +$this->provideRestriction(Restriction::SERVICE_SET_FILTER_BY_NAME, $this->translate( + 'Filter available service set templates. Use asterisks (*) as wildcards,' + . ' like in DB* or *net*' +)); $this->provideSearchUrl($this->translate('Host configs'), 'director/hosts?limit=10', 60); @@ -111,10 +110,10 @@ $this->provideRestriction( ); */ -$this->provideConfigTab('config', array( +$this->provideConfigTab('config', [ 'title' => 'Configuration', 'url' => 'settings' -)); +]); $mainTitle = N_('Icinga Director'); try { @@ -141,41 +140,38 @@ try { $mainTitle .= ' (?!)'; } -$section = $this->menuSection( - $mainTitle -)->setUrl('director')->setPriority(60)->setIcon( - 'cubes' -)->setRenderer(array( - 'SummaryNavigationItemRenderer', - 'state' => 'critical' -)); - +// Hint: director/admin and director/deployments are intentionally +$section = $this->menuSection($mainTitle) + ->setUrl('director') + ->setPriority(60) + ->setIcon('cubes') + ->setRenderer(['SummaryNavigationItemRenderer', 'state' => 'critical']); $section->add(N_('Hosts')) ->setUrl('director/dashboard?name=hosts') - ->setPermission('director/hosts') + ->setPermission(Permission::HOSTS) ->setPriority(30); $section->add(N_('Services')) ->setUrl('director/dashboard?name=services') - ->setPermission('director/services') + ->setPermission(Permission::SERVICES) ->setPriority(40); $section->add(N_('Commands')) ->setUrl('director/dashboard?name=commands') - ->setPermission('director/admin') + ->setPermission(Permission::ADMIN) ->setPriority(50); $section->add(N_('Notifications')) ->setUrl('director/dashboard?name=notifications') - ->setPermission('director/notifications') + ->setPermission(Permission::NOTIFICATIONS) ->setPriority(70); $section->add(N_('Automation')) ->setUrl('director/importsources') - ->setPermission('director/admin') + ->setPermission(Permission::ADMIN) ->setPriority(901); $section->add(N_('Activity log')) ->setUrl('director/config/activities') ->setPriority(902) - ->setPermission('director/audit') + ->setPermission(Permission::AUDIT) ->setRenderer('ConfigHealthItemRenderer'); $section->add(N_('Deployments')) ->setUrl('director/config/deployments') ->setPriority(902) - ->setPermission('director/deployments'); + ->setPermission(Permission::DEPLOYMENTS); diff --git a/doc/02-Installation.md.d/From-Source.md b/doc/02-Installation.md.d/From-Source.md index ea17233..8875152 100644 --- a/doc/02-Installation.md.d/From-Source.md +++ b/doc/02-Installation.md.d/From-Source.md @@ -20,7 +20,7 @@ Make sure you use `director` as the module name. The following requirements must * [Icinga Web](https://github.com/Icinga/icingaweb2) (≥2.8.0). All versions since 2.2 should also work fine, but might show smaller UI bugs and are not actively tested * The following Icinga modules must be installed and enabled: - * [incubator](https://github.com/Icinga/icingaweb2-module-incubator) (≥0.18.0) + * [incubator](https://github.com/Icinga/icingaweb2-module-incubator) (≥0.21.0) * If you are using Icinga Web <2.9.0, the following modules are also required * [ipl](https://github.com/Icinga/icingaweb2-module-ipl) (≥0.5.0) * [reactbundle](https://github.com/Icinga/icingaweb2-module-reactbundle) (≥0.9.0) @@ -41,7 +41,7 @@ and extract it to a folder named `director` in one of your Icinga Web module pat You might want to use a script as follows for this task: ```shell -MODULE_VERSION="1.10.2" +MODULE_VERSION="1.11.1" ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules" REPO_URL="https://github.com/icinga/icingaweb2-module-director" TARGET_DIR="${ICINGAWEB_MODULEPATH}/director" @@ -60,7 +60,7 @@ Simply clone the repository in one of your Icinga web module path directories. You might want to use a script as follows for this task: ```shell -MODULE_VERSION="1.10.2" +MODULE_VERSION="1.11.1" ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules" REPO_URL="https://github.com/icinga/icingaweb2-module-director" TARGET_DIR="${ICINGAWEB_MODULEPATH}/director" diff --git a/doc/05-Upgrading.md b/doc/05-Upgrading.md index 63630b6..a4fe56c 100644 --- a/doc/05-Upgrading.md +++ b/doc/05-Upgrading.md @@ -15,6 +15,7 @@ you will be told so in your frontend. Please read more about: * [Database Backup](#backup-first) +* [Upgrading to 1.11.x](#upgrade-to-1.11.x) * [Upgrading to 1.10.x](#upgrade-to-1.10.x) * [Upgrading to 1.9.x](#upgrade-to-1.9.x) * [Upgrading to 1.8.x](#upgrade-to-1.8.x) @@ -41,7 +42,14 @@ use the tools provided by your database backend, like `mysqldump` or `pg_dump`. Restoring from a backup is trivial, and Director will always be able to apply pending database migrations to an imported old database snapshot. -<a name="upgrade-to-1.9.x"></a>Upgrading to 1.10.x +<a name="upgrade-to-1.11.x"></a>Upgrading to 1.11.x +-------------------------------------------------- + +Before upgrading, please upgrade the [incubator module](https://github.com/Icinga/icingaweb2-module-incubator) +to (at least) v0.21.0. As always, you'll be prompted to apply pending Database +Migrations. + +<a name="upgrade-to-1.10.x"></a>Upgrading to 1.10.x -------------------------------------------------- Please check module dependencies, we raised some of them. In case you're missing diff --git a/doc/70-REST-API.md b/doc/70-REST-API.md index dd5d266..6e7770d 100644 --- a/doc/70-REST-API.md +++ b/doc/70-REST-API.md @@ -164,7 +164,7 @@ Enabling `allowOverrides` allows you to let Director figure out, whether your modified Custom Variables need to be applied to a specific individual Service, or whether setting Overrides at Host level is the way to go. - POST director/service?name=Uptime&host=hostname.example.com&allowOverrices + POST director/service?name=Uptime&host=hostname.example.com&allowOverrides ```json { "vars.uptime_warning": 300 } @@ -257,7 +257,7 @@ You can of course also use the API to trigger specific actions. Deploying the co More ---- -Currently we do not handle Last-Modified und ETag headers. This would involve some work, but could be a cool feature. Let us know your ideas! +Currently, we do not handle Last-Modified und ETag headers. This would involve some work, but could be a cool feature. Let us know your ideas! Sample scenario @@ -560,8 +560,8 @@ Another possibility is to pass a list of checksums to fetch the status of specific deployments and (activity log) activities. Following, you can see an example of how to do it: - GET director/config/deployment-status?config_checksums=617b9cbad9e141cfc3f4cb636ec684bd60073be2, - 617b9cbad9e141cfc3f4cb636ec684bd60073be1&activity_log_checksums=617b9cbad9e141cfc3f4cb636ec684bd60073be1, + GET director/config/deployment-status?configs=617b9cbad9e141cfc3f4cb636ec684bd60073be2, + 617b9cbad9e141cfc3f4cb636ec684bd60073be1&activitiess=617b9cbad9e141cfc3f4cb636ec684bd60073be1, 028b3a19ca7457f5fc9dbb5e4ea527eaf61616a2 ```json diff --git a/doc/82-Changelog.md b/doc/82-Changelog.md index 5867b41..08a6632 100644 --- a/doc/82-Changelog.md +++ b/doc/82-Changelog.md @@ -4,6 +4,166 @@ Please make sure to always read our [Upgrading](05-Upgrading.md) documentation before switching to a new version. +v1.11.1 +------- + +### UI +* FIX: Data fields are now suggested for service templates without a check command (#2815, #2826) +* FIX: Unsetting a parent host or service of a dependency is now correctly stored (no issue) +* FIX: The activity log now avoids a bug in PHP introduced with version 8.1.25 (#2828) + +### Internals +* FIX: UserGroup creation failed since v1.10.0 (#2784) +* FIX: Hostgroup names consisting only of digits are now correctly handled (#2821) +* FIX: Improved compatibility with PHP 8.1 and 8.2 (#2819, #2827) +* FIX: The parent host or service of a dependency can now be reliably referenced by custom variable (#2289) +* FIX: Services in service sets are now fully restored once a removed set is restored (#1065) + +### Integrations +* FIX: Icinga DB integration now works even if the monitoring module is not available (#2635) +* FIX: Conformity with the content security policy introduced with Icinga Web v2.12 (#2845) + +### Fixed issues +* You can find issues and feature requests related to this release on our + [roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/35?closed=1) + +v1.11.0 +------- + +Icinga Director v1.11 ships a nice new feature, which has been requested by +many users: it is now possible to let Notification rules pick User and/or User +Groups from Host and Service custom variables. + +![Notification User Vars](screenshot/director/82_changelog/v1.11.0/82-1.11.0-05-notification_user-var.png) + +Behind the scenes, some Icinga DSL assures that Icinga behaves as expected: + +![Notification User Vars rendered](screenshot/director/82_changelog/v1.11.0/82-1.11.0-06-notification_user-var_rendered.png) + +The IcingaDB module is now supported. This release also ships a fallback template +for Icinga for Windows 1.11 (and Icinga 2.14). To improve security for those +relying on default settings, all Host templates are per default rendered to all +non-global zones in a redundant way, instead of being rendered to the main global +zone. + +For those who want to store Secrets in their Host template definitions, this now +hinders them from reaching your Agent Endpoints. In addition to this, with this +release you now have more control over target Zones for services belonging to +Service Sets. Also, some issues related to permissions and restrictions have been +addressed. + +Various little Import and Sync issues have been addressed, automated Service +Template import has been fixed. In addition to some minor Property modifier +improvements, they can now be applied in a conditional way. Such filter rules +also support CIDR notation. Most prominent use-case: as vSphereDB now ships ALL +guest IP addresses, you can pick specific addresses for specific use-cases / +host properties based on their network range: + +![CIDR-based filters](screenshot/director/82_changelog/v1.11.0/82-1.11.0-01-cidr_based_filters.png) + +This release now officially supports PHP 8.2, addresses issues when integrating +with the IcingaDB web module, and some dark-mode glitches. Search functionality +has been improved, Preview Diff shows more details, editing multiple single +Services with the very same name has been fixed, and the interactive Startup log +renderer now wraps log lines in a nice way: + +![Wrap Startup Log lines](screenshot/director/82_changelog/v1.11.0/82-1.11.0-02-wrap_startup_log_lines.png) + +Performance has greatly been improved for those, who trigger a lot of single API +requests, instead of relying on Import/Sync mechanism. Our template usage overview +now also summarizes and links objects used in Services belonging to Service Sets: + +![Template Usage overview](screenshot/director/82_changelog/v1.11.0/82-1.11.0-03-template_usage.png) + +Commands can now be cloned with their field definitions, and custom variables +from set_if flags make now part of the "suggested fields" list. + +In addition to major refactoring and technical improvements related to our +configuration baskets, it's now also possible to upload additional snapshots for +existing baskets: + +![Basket Snapshot upload](screenshot/director/82_changelog/v1.11.0/82-1.11.0-04-upload_basket_snapshot.png) + +Speaking of baskets, they have been reworked in a way giving especially Icinga +Partners and Plugin authors more control over related objects. As UUIDs are now +supported in Baskets too, it is for example possible to rename an object with a +new Basket Snapshot. + +### Breaking Changes +* Module and system dependencies have been raised, [Upgrading](05-Upgrading.md) + and [Installation](02-Installation.md) documentations contain related details + +### UI +* FEATURE: allow to clone commands with fields (#2264) +* FEATURE: Data Fields are now sorted in a case-insensitive way (#2358) +* FEATURE: Data Field search is now case-insensitive (#2359) +* FEATURE: Deployment Log now breaks lines (#2677) +* FEATURE: Sort Template trees by name (#2691) +* FEATURE: Branch and Sync diff/preview now shows related host for services (#2736) +* FEATURE: Show more details for assign filter parsing errors (#2667) +* FEATURE: Fields from set_if are now being proposed (#514) +* FEATURE: Template usage table now shows Set members (#2378) +* FIX: do not fail for (some) Service Dependencies (#2669, #1142) +* FIX: Service Sets can now be searched by Service name in branches too (#2738) +* FIX: Template usage table had no header (#2780) +* FIX: Strikethrough for deactivated services in applied Service Set (#2746, #2766) +* FIX: editing multi-selected services with the same name has been fixed (#2798, 2801, #2599) +* FIX: Service Sets table with PostgreSQL (#2799) +* FIX: Dark mode for some clone forms (#2670) + +### Icinga Configuration +* FEATURE: render fallback template for IfW 1.11 for Icinga < 2.14 (#2776) +* FEATURE: render host templates to all non-global zones per default (#2410) +* FEATURE: notifications can pick user(groups) from host/service vars (#462) +* FIX: render Set Services to individual zones where required (#1589, #2356) +* FIX: special characters like & and | caused trouble in filters (#2667) + +### Import and Sync +* FEATURE: regular expression based modifier allows explicit NULL on no match (#2705) +* FEATURE: property modifiers can now be applied based on filters (#2756) +* FEATURE: CIDR notation (network ranges) is supported in such filters (#2757) +* FEATURE: trigger group membership resolution on group sync conditionally (#2812) +* FIX: synchronizing Service (and -Set) Templates has been fixed (#2745, #2217) +* FIX: null properties with Sync policy "ignore" are now being ignored (#2657) +* FIX: Import Source shows available columns for Core API Import (#2763) +* FIX: JSON-decode now explicitly fails for non-string inputs (#2810) + +### Integrations +* FIX: don't throw an error, when editing a Service via IcingaDB link (#2533, #2563) + +# Configuration Baskets +* FEATURE: it's now possible to upload snapshots for existing baskets (#1952) +* FIX: basket now shows where to expect changes for lists from snapshots (#2791) +* FIX: Icinga DSL parts for Commands are now restored from Baskets (#2811) + +### REST API +* FIX: Commands give 204 w/o ghost changes for same properties (#2660) + +### Permissions and Restrictions +* FIX: monitoring-related permission checks have been refactored (#2712) +* FIX: Hostgroup-Filters have not been applied to Overview tables (#2775) +* FIX: error editing Hosts with hostgroup restriction in place (#2164, #2809) + +### Configuration Branches +* FEATURE: with this release, directorbranches v1.3 supports a "default branch" (#2688) +* FEATURE: users with default branches get warnings in the main branch (#2689) +* FIX: create a branched set, add services, modify them (#2710) + +### Health Check +* FIX: complaint about overdue jobs was not correct (#2680, #2681) + +### Internals +* FEATURE: support PHP 8.2 (#2777, #2792) +* FEATURE: Unit Tests are now being triggered as GitHub workflows (no issue) +* FIX: group membership is no longer resolved when not needed (#2048) +* FIX: require Auth object for all object tables (#2808) +* FIX: group membership is no longer resolved when not needed (#2048) + +### Fixed issues +* You can find issues and feature requests related to this release on our + [roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/33?closed=1) + + v1.10.2 ------- diff --git a/doc/93-Testing.md b/doc/93-Testing.md index 7d2f8fb..7bdf4df 100644 --- a/doc/93-Testing.md +++ b/doc/93-Testing.md @@ -12,16 +12,12 @@ there is probably already someone running them from time to time. So, just lean back with full trust in our development toolchain and spend your time elsewhere ;-) Cheers! -### Tests on Travis-CI +### Tests on GitHub When pushing to [GitHub](https://github.com/Icinga/icingaweb2-module-director/) -or sending pull requests, Unit-Tests are automatically triggered on -[Travis-CI](https://travis-ci.org/Icinga/icingaweb2-module-director): +or sending pull requests, Unit-Tests are automatically triggered. -[![Build Status](https://travis-ci.org/Icinga/icingaweb2-module-director.svg?branch=master)](https://travis-ci.org/Icinga/icingaweb2-module-director) - -We run our tests against MySQL and PostgreSQL, with PHP versions ranging from -5.3 to 7.1, including nightly builds. +![Build Status](https://github.com/Icinga/icingaweb2-module-director/workflows/PHP%20Tests/badge.svg?branch=master) ### Tests for supported Platforms diff --git a/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-01-cidr_based_filters.png b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-01-cidr_based_filters.png Binary files differnew file mode 100644 index 0000000..7f612a9 --- /dev/null +++ b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-01-cidr_based_filters.png diff --git a/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-02-wrap_startup_log_lines.png b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-02-wrap_startup_log_lines.png Binary files differnew file mode 100644 index 0000000..35e714a --- /dev/null +++ b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-02-wrap_startup_log_lines.png diff --git a/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-03-template_usage.png b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-03-template_usage.png Binary files differnew file mode 100644 index 0000000..59b1040 --- /dev/null +++ b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-03-template_usage.png diff --git a/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-04-upload_basket_snapshot.png b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-04-upload_basket_snapshot.png Binary files differnew file mode 100644 index 0000000..87ec640 --- /dev/null +++ b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-04-upload_basket_snapshot.png diff --git a/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-05-notification_user-var.png b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-05-notification_user-var.png Binary files differnew file mode 100644 index 0000000..31fa5ea --- /dev/null +++ b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-05-notification_user-var.png diff --git a/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-06-notification_user-var_rendered.png b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-06-notification_user-var_rendered.png Binary files differnew file mode 100644 index 0000000..0a72cde --- /dev/null +++ b/doc/screenshot/director/82_changelog/v1.11.0/82-1.11.0-06-notification_user-var_rendered.png diff --git a/library/Director/Acl.php b/library/Director/Acl.php index 4aa2bd2..44c23f5 100644 --- a/library/Director/Acl.php +++ b/library/Director/Acl.php @@ -56,7 +56,7 @@ class Acl public function listRoleNames() { return array_map( - array($this, 'getNameForRole'), + [$this, 'getNameForRole'], $this->getUser()->getRoles() ); } diff --git a/library/Director/Auth/MonitoringRestriction.php b/library/Director/Auth/MonitoringRestriction.php new file mode 100644 index 0000000..1fb6013 --- /dev/null +++ b/library/Director/Auth/MonitoringRestriction.php @@ -0,0 +1,36 @@ +<?php + +namespace Icinga\Module\Director\Auth; + +use Icinga\Authentication\Auth; +use Icinga\Data\Filter\Filter; + +class MonitoringRestriction +{ + public static function getObjectsFilter(Auth $auth): Filter + { + $restriction = Filter::matchAny(); + $restriction->setAllowedFilterColumns([ + 'host_name', + 'hostgroup_name', + 'instance_name', + 'service_description', + 'servicegroup_name', + function ($c) { + return preg_match('/^_(?:host|service)_/i', $c); + } + ]); + foreach ($auth->getRestrictions(Restriction::MONITORING_RW_OBJECT_FILTER) as $filter) { + if ($filter === '*') { + return Filter::matchAll(); + } + $restriction->addFilter(Filter::fromQueryString($filter)); + } + + if ($restriction->isEmpty()) { + return Filter::matchAll(); + } + + return $restriction; + } +} diff --git a/library/Director/Auth/Permission.php b/library/Director/Auth/Permission.php new file mode 100644 index 0000000..c29d789 --- /dev/null +++ b/library/Director/Auth/Permission.php @@ -0,0 +1,31 @@ +<?php + +namespace Icinga\Module\Director\Auth; + +class Permission +{ + public const ALL_PERMISSIONS = 'director/*'; + public const ADMIN = 'director/admin'; // internal, assign ALL_PERMISSONS + public const API = 'director/api'; + public const AUDIT = 'director/audit'; + public const DEPLOY = 'director/deploy'; + public const DEPLOYMENTS = 'director/deployments'; // internal, assign ALL_PERMISSONS + public const GROUPS_FOR_RESTRICTED_HOSTS = 'director/groups-for-restricted-hosts'; + public const HOSTS = 'director/hosts'; + public const HOST_GROUPS = 'director/hostgroups'; // internal, assign ALL_PERMISSIONS + public const INSPECT = 'director/inspect'; + public const MONITORING_SERVICES_RO = 'director/monitoring/services-ro'; + public const MONITORING_SERVICES = 'director/monitoring/services'; + public const MONITORING_HOSTS = 'director/monitoring/hosts'; + public const ICINGADB_SERVICES_RO = 'director/icingadb/services-ro'; + public const ICINGADB_SERVICES = 'director/icingadb/services'; + public const ICINGADB_HOSTS = 'director/icingadb/hosts'; + public const NOTIFICATIONS = 'director/notifications'; + public const SCHEDULED_DOWNTIMES = 'director/scheduled-downtimes'; + public const SERVICES = 'director/services'; + public const SERVICE_SETS = 'director/servicesets'; + public const SERVICE_SET_APPLY = 'director/service_set/apply'; + public const SHOW_CONFIG = 'director/showconfig'; + public const SHOW_SQL = 'director/showsql'; + public const USERS = 'director/users'; +} diff --git a/library/Director/Auth/Restriction.php b/library/Director/Auth/Restriction.php new file mode 100644 index 0000000..3394dcc --- /dev/null +++ b/library/Director/Auth/Restriction.php @@ -0,0 +1,17 @@ +<?php + +namespace Icinga\Module\Director\Auth; + +class Restriction +{ + public const MONITORING_RW_OBJECT_FILTER = 'director/monitoring/rw-object-filter'; + public const ICINGADB_RW_OBJECT_FILTER = 'director/icingadb/rw-object-filter'; + public const FILTER_HOSTGROUPS = 'director/filter/hostgroups'; + + // Hint: by-name-Filters are being fetched with variable names, like "director/$type/apply/filter-by-name" + public const NOTIFICATION_APPLY_FILTER_BY_NAME = 'director/notification/apply/filter-by-name'; + public const SCHEDULED_DOWNTIME_APPLY_FILTER_BY_NAME = 'director/scheduled-downtime/apply/filter-by-name'; + public const SERVICE_APPLY_FILTER_BY_NAME = 'director/service/apply/filter-by-name'; + public const SERVICE_SET_FILTER_BY_NAME = 'director/service_set/filter-by-name'; + const DB_RESOURCE = 'director/db_resource'; +} diff --git a/library/Director/Cli/Command.php b/library/Director/Cli/Command.php index 69d61b1..7268913 100644 --- a/library/Director/Cli/Command.php +++ b/library/Director/Cli/Command.php @@ -82,9 +82,9 @@ class Command extends CliCommand { MemoryLimit::raiseTo('1024M'); - ini_set('max_execution_time', 0); + ini_set('max_execution_time', '0'); if (version_compare(PHP_VERSION, '7.0.0') < 0) { - ini_set('zend.enable_gc', 0); + ini_set('zend.enable_gc', '0'); } return $this; diff --git a/library/Director/Cli/ObjectCommand.php b/library/Director/Cli/ObjectCommand.php index ca68213..ed99c14 100644 --- a/library/Director/Cli/ObjectCommand.php +++ b/library/Director/Cli/ObjectCommand.php @@ -428,7 +428,7 @@ class ObjectCommand extends Command } $stdin = file_get_contents('php://stdin'); - if (strlen($stdin) === 0) { + if (! $stdin) { return null; } diff --git a/library/Director/Core/CoreApi.php b/library/Director/Core/CoreApi.php index ea10916..73588c2 100644 --- a/library/Director/Core/CoreApi.php +++ b/library/Director/Core/CoreApi.php @@ -569,7 +569,7 @@ constants 'icon_image_alt' => 'icon_image_alt', ]; - if (version_compare($this->getVersion(), '2.8.0', '>=')) { + if (version_compare($this->getVersion() ?? '', '2.8.0', '>=')) { $params['flapping_threshold_high'] = 'flapping_threshold_high'; $params['flapping_threshold_low'] = 'flapping_threshold_low'; } @@ -622,7 +622,7 @@ constants { IcingaCommand::setPluginDir($this->getConstant('PluginDir')); - $objects = $this->getDirectorObjects('Command', "${type}Commands", [ + $objects = $this->getDirectorObjects('Command', "{$type}Commands", [ 'arguments' => 'arguments', // 'env' => 'env', 'timeout' => 'timeout', diff --git a/library/Director/Core/LegacyDeploymentApi.php b/library/Director/Core/LegacyDeploymentApi.php index 7287c4a..0ab77e0 100644 --- a/library/Director/Core/LegacyDeploymentApi.php +++ b/library/Director/Core/LegacyDeploymentApi.php @@ -128,6 +128,10 @@ class LegacyDeploymentApi implements DeploymentApiInterface if (file_exists($path)) { if (is_link($path)) { $linkTarget = readlink($path); + if (! $linkTarget) { + throw new IcingaException('Failed to read symlink'); + } + $linkTargetDir = dirname($linkTarget); $linkTargetName = basename($linkTarget); @@ -165,7 +169,7 @@ class LegacyDeploymentApi implements DeploymentApiInterface $this->assertDeploymentPath(); $dh = @opendir($this->deploymentPath); - if ($dh === null) { + if ($dh === false) { throw new IcingaException('Can not list contents of %s', $this->deploymentPath); } @@ -279,7 +283,7 @@ class LegacyDeploymentApi implements DeploymentApiInterface $this->mkdir(dirname($fullPath), true); $fh = @fopen($fullPath, 'w'); - if ($fh === null) { + if ($fh === false) { throw new IcingaException('Could not open file "%s" for writing.', $fullPath); } chmod($fullPath, $this->file_mode); @@ -334,7 +338,7 @@ class LegacyDeploymentApi implements DeploymentApiInterface protected function listDirectoryContents($path, $depth = 0) { $dh = @opendir($path); - if ($dh === null) { + if ($dh === false) { throw new IcingaException('Can not list contents of %s', $path); } diff --git a/library/Director/Core/RestApiClient.php b/library/Director/Core/RestApiClient.php index b0854ff..19f6b68 100644 --- a/library/Director/Core/RestApiClient.php +++ b/library/Director/Core/RestApiClient.php @@ -206,14 +206,14 @@ class RestApiClient } /** - * @return resource + * @throws RuntimeException */ protected function curl() { if ($this->curl === null) { $this->curl = curl_init(sprintf('https://%s:%d', $this->peer, $this->port)); if (! $this->curl) { - throw new RuntimeException('CURL INIT ERROR: ' . curl_error($this->curl)); + throw new RuntimeException('CURL INIT FAILED'); } } @@ -260,13 +260,11 @@ class RestApiClient public function disconnect() { - if ($this->curl !== null) { - if (is_resource($this->curl)) { - @curl_close($this->curl); - } - - $this->curl = null; + if ($this->curl) { + @curl_close($this->curl); } + + $this->curl = null; } public function __destruct() diff --git a/library/Director/Core/RestApiResponse.php b/library/Director/Core/RestApiResponse.php index 523ed35..43516f7 100644 --- a/library/Director/Core/RestApiResponse.php +++ b/library/Director/Core/RestApiResponse.php @@ -113,7 +113,7 @@ class RestApiResponse throw new IcingaException('API request failed: ' . $result->status); } } else { - throw new IcingaException('API request failed: ' . var_export($result, 1)); + throw new IcingaException('API request failed: ' . var_export($result, true)); } } diff --git a/library/Director/CustomVariable/CustomVariable.php b/library/Director/CustomVariable/CustomVariable.php index 98eda84..4b5dd3e 100644 --- a/library/Director/CustomVariable/CustomVariable.php +++ b/library/Director/CustomVariable/CustomVariable.php @@ -236,7 +236,7 @@ abstract class CustomVariable implements IcingaConfigRenderer // TODO: check for specific class/stdClass/interface? return new CustomVariableDictionary($key, $value); } else { - throw new LogicException(sprintf('WTF (%s): %s', $key, var_export($value, 1))); + throw new LogicException(sprintf('WTF (%s): %s', $key, var_export($value, true))); } } diff --git a/library/Director/CustomVariable/CustomVariableBoolean.php b/library/Director/CustomVariable/CustomVariableBoolean.php index 9953fae..750f1d6 100644 --- a/library/Director/CustomVariable/CustomVariableBoolean.php +++ b/library/Director/CustomVariable/CustomVariableBoolean.php @@ -31,7 +31,7 @@ class CustomVariableBoolean extends CustomVariable if (! is_bool($value)) { throw new ProgrammingError( 'Expected a boolean, got %s', - var_export($value, 1) + var_export($value, true) ); } diff --git a/library/Director/CustomVariable/CustomVariableNull.php b/library/Director/CustomVariable/CustomVariableNull.php index f87ccfa..83e07f0 100644 --- a/library/Director/CustomVariable/CustomVariableNull.php +++ b/library/Director/CustomVariable/CustomVariableNull.php @@ -31,7 +31,7 @@ class CustomVariableNull extends CustomVariable if (! is_null($value)) { throw new ProgrammingError( 'Null can only be null, got %s', - var_export($value, 1) + var_export($value, true) ); } diff --git a/library/Director/CustomVariable/CustomVariableNumber.php b/library/Director/CustomVariable/CustomVariableNumber.php index 62838a9..7b0c3e9 100644 --- a/library/Director/CustomVariable/CustomVariableNumber.php +++ b/library/Director/CustomVariable/CustomVariableNumber.php @@ -47,7 +47,7 @@ class CustomVariableNumber extends CustomVariable if (! is_int($value) && ! is_float($value)) { throw new ProgrammingError( 'Expected a number, got %s', - var_export($value, 1) + var_export($value, true) ); } diff --git a/library/Director/CustomVariable/CustomVariables.php b/library/Director/CustomVariable/CustomVariables.php index cdcc4bd..01227c5 100644 --- a/library/Director/CustomVariable/CustomVariables.php +++ b/library/Director/CustomVariable/CustomVariables.php @@ -414,10 +414,15 @@ class CustomVariables implements Iterator, Countable, IcingaConfigRenderer protected function renderKeyName($key) { + return 'vars' . self::renderKeySuffix($key); + } + + public static function renderKeySuffix($key) + { if (preg_match('/^[a-z][a-z0-9_]*$/i', $key)) { - return 'vars.' . c::escapeIfReserved($key); + return '.' . c::escapeIfReserved($key); } else { - return 'vars[' . c::renderString($key) . ']'; + return '[' . c::renderString($key) . ']'; } } diff --git a/library/Director/Daemon/BackgroundDaemon.php b/library/Director/Daemon/BackgroundDaemon.php index 34cc28b..2d8a29c 100644 --- a/library/Director/Daemon/BackgroundDaemon.php +++ b/library/Director/Daemon/BackgroundDaemon.php @@ -104,7 +104,7 @@ class BackgroundDaemon try { $uuid = \bin2hex(Uuid::uuid4()->getBytes()); } catch (Exception $e) { - $uuid = 'deadc0de' . \substr(\md5(\getmypid()), 0, 24); + $uuid = 'deadc0de' . substr(md5((string) getmypid()), 0, 24); } } $processDetails = new DaemonProcessDetails($uuid); diff --git a/library/Director/Dashboard/BranchesDashboard.php b/library/Director/Dashboard/BranchesDashboard.php index fe8b385..faeb8bf 100644 --- a/library/Director/Dashboard/BranchesDashboard.php +++ b/library/Director/Dashboard/BranchesDashboard.php @@ -4,8 +4,10 @@ namespace Icinga\Module\Director\Dashboard; use gipfl\Web\Widget\Hint; use Icinga\Application\Hook; +use Icinga\Authentication\Auth; use Icinga\Module\Director\Db\Branch\Branch; use Icinga\Module\Director\Db\Branch\BranchStore; +use Icinga\Module\Director\Db\Branch\PreferredBranchSupport; use Icinga\Module\Director\Hook\BranchSupportHook; use ipl\Html\Html; @@ -19,6 +21,14 @@ class BranchesDashboard extends Dashboard $this->translate('You\'re currently working in a Configuration Branch: %s'), Branch::requireHook()->linkToBranch($branch, $this->getAuth(), $branch->getName()) ))); + } else { + if (($implementation = Branch::optionalHook()) && $implementation instanceof PreferredBranchSupport) { + if ($implementation->hasPreferredBranch(Auth::getInstance())) { + $this->prepend(Hint::warning( + $this->translate('You\'re currently working in the main Configuration Branch') + )); + } + } } return $this->translate('Prepare your configuration in a safe Environment'); diff --git a/library/Director/Dashboard/Dashboard.php b/library/Director/Dashboard/Dashboard.php index de8970c..3f1fc38 100644 --- a/library/Director/Dashboard/Dashboard.php +++ b/library/Director/Dashboard/Dashboard.php @@ -149,6 +149,7 @@ abstract class Dashboard extends HtmlDocument ]); } + #[\ReturnTypeWillChange] public function count() { return count($this->dashlets()); diff --git a/library/Director/Dashboard/Dashlet/ActivityLogDashlet.php b/library/Director/Dashboard/Dashlet/ActivityLogDashlet.php index 9794986..7a9745b 100644 --- a/library/Director/Dashboard/Dashlet/ActivityLogDashlet.php +++ b/library/Director/Dashboard/Dashlet/ActivityLogDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class ActivityLogDashlet extends Dashlet { protected $icon = 'book'; @@ -30,6 +32,6 @@ class ActivityLogDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/audit'); + return [Permission::AUDIT]; } } diff --git a/library/Director/Dashboard/Dashlet/ApiUserObjectDashlet.php b/library/Director/Dashboard/Dashlet/ApiUserObjectDashlet.php index 419859d..238059a 100644 --- a/library/Director/Dashboard/Dashlet/ApiUserObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/ApiUserObjectDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class ApiUserObjectDashlet extends Dashlet { protected $icon = 'lock-open-alt'; - protected $requiredStats = array('apiuser'); + protected $requiredStats = ['apiuser']; public function getTitle() { @@ -20,6 +22,6 @@ class ApiUserObjectDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/BasketDashlet.php b/library/Director/Dashboard/Dashlet/BasketDashlet.php index 10f2b81..8ac26ed 100644 --- a/library/Director/Dashboard/Dashlet/BasketDashlet.php +++ b/library/Director/Dashboard/Dashlet/BasketDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class BasketDashlet extends Dashlet { protected $icon = 'tag'; @@ -25,6 +27,6 @@ class BasketDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/CheckCommandsDashlet.php b/library/Director/Dashboard/Dashlet/CheckCommandsDashlet.php index 65d8c8c..458c700 100644 --- a/library/Director/Dashboard/Dashlet/CheckCommandsDashlet.php +++ b/library/Director/Dashboard/Dashlet/CheckCommandsDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class CheckCommandsDashlet extends Dashlet { protected $icon = 'wrench'; @@ -21,7 +23,7 @@ class CheckCommandsDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/ChoicesDashlet.php b/library/Director/Dashboard/Dashlet/ChoicesDashlet.php index efdbba5..105ebb9 100644 --- a/library/Director/Dashboard/Dashlet/ChoicesDashlet.php +++ b/library/Director/Dashboard/Dashlet/ChoicesDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + abstract class ChoicesDashlet extends Dashlet { protected $icon = 'flapping'; @@ -36,6 +38,6 @@ abstract class ChoicesDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/CommandObjectDashlet.php b/library/Director/Dashboard/Dashlet/CommandObjectDashlet.php index 083172e..18a4731 100644 --- a/library/Director/Dashboard/Dashlet/CommandObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/CommandObjectDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class CommandObjectDashlet extends Dashlet { protected $icon = 'wrench'; - protected $requiredStats = array('command'); + protected $requiredStats = ['command']; public function getTitle() { @@ -20,6 +22,6 @@ class CommandObjectDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/CustomvarDashlet.php b/library/Director/Dashboard/Dashlet/CustomvarDashlet.php index 919c06b..a2acd54 100644 --- a/library/Director/Dashboard/Dashlet/CustomvarDashlet.php +++ b/library/Director/Dashboard/Dashlet/CustomvarDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class CustomvarDashlet extends Dashlet { protected $icon = 'keyboard'; @@ -25,6 +27,6 @@ class CustomvarDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/DatafieldCategoryDashlet.php b/library/Director/Dashboard/Dashlet/DatafieldCategoryDashlet.php index 6efb4ca..eb1cefc 100644 --- a/library/Director/Dashboard/Dashlet/DatafieldCategoryDashlet.php +++ b/library/Director/Dashboard/Dashlet/DatafieldCategoryDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class DatafieldCategoryDashlet extends Dashlet { protected $icon = 'th-list'; @@ -25,6 +27,6 @@ class DatafieldCategoryDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/DatafieldDashlet.php b/library/Director/Dashboard/Dashlet/DatafieldDashlet.php index 03f2d8d..a381a3f 100644 --- a/library/Director/Dashboard/Dashlet/DatafieldDashlet.php +++ b/library/Director/Dashboard/Dashlet/DatafieldDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class DatafieldDashlet extends Dashlet { protected $icon = 'edit'; @@ -25,6 +27,6 @@ class DatafieldDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/DatalistDashlet.php b/library/Director/Dashboard/Dashlet/DatalistDashlet.php index bdf179f..fe82e4b 100644 --- a/library/Director/Dashboard/Dashlet/DatalistDashlet.php +++ b/library/Director/Dashboard/Dashlet/DatalistDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class DatalistDashlet extends Dashlet { protected $icon = 'sort-name-up'; @@ -25,6 +27,6 @@ class DatalistDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/DependencyObjectDashlet.php b/library/Director/Dashboard/Dashlet/DependencyObjectDashlet.php index 47a18aa..b6455fe 100644 --- a/library/Director/Dashboard/Dashlet/DependencyObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/DependencyObjectDashlet.php @@ -6,7 +6,7 @@ class DependencyObjectDashlet extends Dashlet { protected $icon = 'sitemap'; - protected $requiredStats = array('dependency'); + protected $requiredStats = ['dependency']; public function getTitle() { diff --git a/library/Director/Dashboard/Dashlet/DeploymentDashlet.php b/library/Director/Dashboard/Dashlet/DeploymentDashlet.php index 7a52793..83b4cea 100644 --- a/library/Director/Dashboard/Dashlet/DeploymentDashlet.php +++ b/library/Director/Dashboard/Dashlet/DeploymentDashlet.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; use Exception; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Objects\DirectorDeploymentLog; class DeploymentDashlet extends Dashlet @@ -109,6 +110,6 @@ class DeploymentDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/deploy'); + return [Permission::DEPLOY]; } } diff --git a/library/Director/Dashboard/Dashlet/EndpointObjectDashlet.php b/library/Director/Dashboard/Dashlet/EndpointObjectDashlet.php index 9dd9467..97ae746 100644 --- a/library/Director/Dashboard/Dashlet/EndpointObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/EndpointObjectDashlet.php @@ -3,12 +3,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; use Exception; +use Icinga\Module\Director\Auth\Permission; class EndpointObjectDashlet extends Dashlet { protected $icon = 'cloud'; - protected $requiredStats = array('endpoint'); + protected $requiredStats = ['endpoint']; protected $hasDeploymentEndpoint; @@ -24,7 +25,7 @@ class EndpointObjectDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } protected function hasDeploymentEndpoint() diff --git a/library/Director/Dashboard/Dashlet/HostGroupsDashlet.php b/library/Director/Dashboard/Dashlet/HostGroupsDashlet.php index 5d3b25f..249d4d6 100644 --- a/library/Director/Dashboard/Dashlet/HostGroupsDashlet.php +++ b/library/Director/Dashboard/Dashlet/HostGroupsDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class HostGroupsDashlet extends Dashlet { protected $icon = 'tags'; @@ -26,6 +28,6 @@ class HostGroupsDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/hostgroups'); + return [Permission::HOST_GROUPS]; } } diff --git a/library/Director/Dashboard/Dashlet/HostObjectDashlet.php b/library/Director/Dashboard/Dashlet/HostObjectDashlet.php index 10cff94..e77f75b 100644 --- a/library/Director/Dashboard/Dashlet/HostObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/HostObjectDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class HostObjectDashlet extends Dashlet { protected $icon = 'host'; - protected $requiredStats = array('host', 'hostgroup'); + protected $requiredStats = ['host', 'hostgroup']; public function getTitle() { @@ -15,7 +17,7 @@ class HostObjectDashlet extends Dashlet public function listRequiredPermissions() { - return ['director/hosts']; + return [Permission::HOSTS]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/HostTemplatesDashlet.php b/library/Director/Dashboard/Dashlet/HostTemplatesDashlet.php index 09bed17..eb4092a 100644 --- a/library/Director/Dashboard/Dashlet/HostTemplatesDashlet.php +++ b/library/Director/Dashboard/Dashlet/HostTemplatesDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class HostTemplatesDashlet extends Dashlet { protected $icon = 'cubes'; @@ -26,6 +28,6 @@ class HostTemplatesDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/HostsDashlet.php b/library/Director/Dashboard/Dashlet/HostsDashlet.php index 39c1421..55bebbd 100644 --- a/library/Director/Dashboard/Dashlet/HostsDashlet.php +++ b/library/Director/Dashboard/Dashlet/HostsDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class HostsDashlet extends Dashlet { protected $icon = 'host'; @@ -27,6 +29,6 @@ class HostsDashlet extends Dashlet public function listRequiredPermissions() { - return ['director/hosts']; + return [Permission::HOSTS]; } } diff --git a/library/Director/Dashboard/Dashlet/ImportSourceDashlet.php b/library/Director/Dashboard/Dashlet/ImportSourceDashlet.php index 302c1ed..aa34613 100644 --- a/library/Director/Dashboard/Dashlet/ImportSourceDashlet.php +++ b/library/Director/Dashboard/Dashlet/ImportSourceDashlet.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; use Exception; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Objects\ImportSource; class ImportSourceDashlet extends Dashlet @@ -60,6 +61,6 @@ class ImportSourceDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/InfrastructureDashlet.php b/library/Director/Dashboard/Dashlet/InfrastructureDashlet.php index 328df72..e1d5908 100644 --- a/library/Director/Dashboard/Dashlet/InfrastructureDashlet.php +++ b/library/Director/Dashboard/Dashlet/InfrastructureDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class InfrastructureDashlet extends Dashlet { protected $icon = 'cloud'; @@ -25,6 +27,6 @@ class InfrastructureDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/JobDashlet.php b/library/Director/Dashboard/Dashlet/JobDashlet.php index d7452e0..af5429d 100644 --- a/library/Director/Dashboard/Dashlet/JobDashlet.php +++ b/library/Director/Dashboard/Dashlet/JobDashlet.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; use Exception; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Objects\DirectorJob; class JobDashlet extends Dashlet @@ -60,6 +61,6 @@ class JobDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/KickstartDashlet.php b/library/Director/Dashboard/Dashlet/KickstartDashlet.php index 09801f5..eb74371 100644 --- a/library/Director/Dashboard/Dashlet/KickstartDashlet.php +++ b/library/Director/Dashboard/Dashlet/KickstartDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class KickstartDashlet extends Dashlet { protected $icon = 'gauge'; @@ -26,6 +28,6 @@ class KickstartDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/NotificationApplyDashlet.php b/library/Director/Dashboard/Dashlet/NotificationApplyDashlet.php index e0b0443..d0dbb01 100644 --- a/library/Director/Dashboard/Dashlet/NotificationApplyDashlet.php +++ b/library/Director/Dashboard/Dashlet/NotificationApplyDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class NotificationApplyDashlet extends Dashlet { protected $icon = 'bell'; @@ -27,7 +29,7 @@ class NotificationApplyDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/notifications'); + return [Permission::NOTIFICATIONS]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/NotificationTemplateDashlet.php b/library/Director/Dashboard/Dashlet/NotificationTemplateDashlet.php index a58b5d0..6f1fe64 100644 --- a/library/Director/Dashboard/Dashlet/NotificationTemplateDashlet.php +++ b/library/Director/Dashboard/Dashlet/NotificationTemplateDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class NotificationTemplateDashlet extends Dashlet { protected $icon = 'cubes'; - protected $requiredStats = array('notification'); + protected $requiredStats = ['notification']; public function getTitle() { @@ -21,7 +23,7 @@ class NotificationTemplateDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/NotificationsDashlet.php b/library/Director/Dashboard/Dashlet/NotificationsDashlet.php index 85610f0..a0b1e43 100644 --- a/library/Director/Dashboard/Dashlet/NotificationsDashlet.php +++ b/library/Director/Dashboard/Dashlet/NotificationsDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class NotificationsDashlet extends Dashlet { protected $icon = 'bell'; - protected $requiredStats = array('notification'); + protected $requiredStats = ['notification']; public function getTitle() { @@ -23,7 +25,7 @@ class NotificationsDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/notifications'); + return [Permission::NOTIFICATIONS]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/ScheduledDowntimeApplyDashlet.php b/library/Director/Dashboard/Dashlet/ScheduledDowntimeApplyDashlet.php index 45bcfa2..c9fbb68 100644 --- a/library/Director/Dashboard/Dashlet/ScheduledDowntimeApplyDashlet.php +++ b/library/Director/Dashboard/Dashlet/ScheduledDowntimeApplyDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class ScheduledDowntimeApplyDashlet extends Dashlet { protected $icon = 'plug'; @@ -15,7 +17,7 @@ class ScheduledDowntimeApplyDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/scheduled-downtimes'); + return [Permission::SCHEDULED_DOWNTIMES]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/SelfServiceDashlet.php b/library/Director/Dashboard/Dashlet/SelfServiceDashlet.php index 32b1cfa..b3d15fc 100644 --- a/library/Director/Dashboard/Dashlet/SelfServiceDashlet.php +++ b/library/Director/Dashboard/Dashlet/SelfServiceDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class SelfServiceDashlet extends Dashlet { protected $icon = 'chat'; @@ -26,6 +28,6 @@ class SelfServiceDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/ServiceApplyRulesDashlet.php b/library/Director/Dashboard/Dashlet/ServiceApplyRulesDashlet.php index b4bee04..487be02 100644 --- a/library/Director/Dashboard/Dashlet/ServiceApplyRulesDashlet.php +++ b/library/Director/Dashboard/Dashlet/ServiceApplyRulesDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class ServiceApplyRulesDashlet extends Dashlet { protected $icon = 'resize-full-alt'; @@ -26,6 +28,6 @@ class ServiceApplyRulesDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/ServiceGroupsDashlet.php b/library/Director/Dashboard/Dashlet/ServiceGroupsDashlet.php index ad47768..44162a9 100644 --- a/library/Director/Dashboard/Dashlet/ServiceGroupsDashlet.php +++ b/library/Director/Dashboard/Dashlet/ServiceGroupsDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class ServiceGroupsDashlet extends Dashlet { protected $icon = 'tags'; @@ -26,6 +28,6 @@ class ServiceGroupsDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/ServiceObjectDashlet.php b/library/Director/Dashboard/Dashlet/ServiceObjectDashlet.php index 01fb800..087590b 100644 --- a/library/Director/Dashboard/Dashlet/ServiceObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/ServiceObjectDashlet.php @@ -3,6 +3,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; use Icinga\Module\Director\Acl; +use Icinga\Module\Director\Auth\Permission; +use RuntimeException; class ServiceObjectDashlet extends Dashlet { @@ -22,13 +24,13 @@ class ServiceObjectDashlet extends Dashlet public function listRequiredPermissions() { - return ['director/services']; + throw new RuntimeException('This method should not be accessed, isAllowed() has been implemented'); } public function isAllowed() { $acl = Acl::instance(); - return $acl->hasPermission('director/services') - || $acl->hasPermission('director/service_sets'); + return $acl->hasPermission(Permission::SERVICES) + || $acl->hasPermission(Permission::SERVICE_SETS); } } diff --git a/library/Director/Dashboard/Dashlet/ServiceSetsDashlet.php b/library/Director/Dashboard/Dashlet/ServiceSetsDashlet.php index f971d42..c8db0e9 100644 --- a/library/Director/Dashboard/Dashlet/ServiceSetsDashlet.php +++ b/library/Director/Dashboard/Dashlet/ServiceSetsDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class ServiceSetsDashlet extends Dashlet { protected $icon = 'services'; @@ -26,6 +28,6 @@ class ServiceSetsDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/servicesets'); + return [Permission::SERVICE_SETS]; } } diff --git a/library/Director/Dashboard/Dashlet/ServiceTemplatesDashlet.php b/library/Director/Dashboard/Dashlet/ServiceTemplatesDashlet.php index 62d1b41..c2131d6 100644 --- a/library/Director/Dashboard/Dashlet/ServiceTemplatesDashlet.php +++ b/library/Director/Dashboard/Dashlet/ServiceTemplatesDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class ServiceTemplatesDashlet extends Dashlet { protected $icon = 'cubes'; @@ -26,6 +28,6 @@ class ServiceTemplatesDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/SettingsDashlet.php b/library/Director/Dashboard/Dashlet/SettingsDashlet.php index 716e565..0a3d680 100644 --- a/library/Director/Dashboard/Dashlet/SettingsDashlet.php +++ b/library/Director/Dashboard/Dashlet/SettingsDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class SettingsDashlet extends Dashlet { protected $icon = 'edit'; @@ -25,6 +27,6 @@ class SettingsDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/SingleServicesDashlet.php b/library/Director/Dashboard/Dashlet/SingleServicesDashlet.php index 297b3f8..a7d648a 100644 --- a/library/Director/Dashboard/Dashlet/SingleServicesDashlet.php +++ b/library/Director/Dashboard/Dashlet/SingleServicesDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class SingleServicesDashlet extends Dashlet { protected $icon = 'service'; @@ -26,6 +28,6 @@ class SingleServicesDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/services'); + return [Permission::SERVICES]; } } diff --git a/library/Director/Dashboard/Dashlet/SyncDashlet.php b/library/Director/Dashboard/Dashlet/SyncDashlet.php index 4ac689a..d212bc2 100644 --- a/library/Director/Dashboard/Dashlet/SyncDashlet.php +++ b/library/Director/Dashboard/Dashlet/SyncDashlet.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; use Exception; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Objects\SyncRule; class SyncDashlet extends Dashlet @@ -60,6 +61,6 @@ class SyncDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/TimeperiodObjectDashlet.php b/library/Director/Dashboard/Dashlet/TimeperiodObjectDashlet.php index ba4c1db..2aa4c9b 100644 --- a/library/Director/Dashboard/Dashlet/TimeperiodObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/TimeperiodObjectDashlet.php @@ -4,12 +4,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; use DirectoryIterator; use Icinga\Exception\ProgrammingError; +use Icinga\Module\Director\Auth\Permission; class TimeperiodObjectDashlet extends Dashlet { protected $icon = 'calendar'; - protected $requiredStats = array('timeperiod'); + protected $requiredStats = ['timeperiod']; public function getTitle() { @@ -23,6 +24,6 @@ class TimeperiodObjectDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/TimeperiodTemplateDashlet.php b/library/Director/Dashboard/Dashlet/TimeperiodTemplateDashlet.php index 26339e4..7aa3201 100644 --- a/library/Director/Dashboard/Dashlet/TimeperiodTemplateDashlet.php +++ b/library/Director/Dashboard/Dashlet/TimeperiodTemplateDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class TimeperiodTemplateDashlet extends Dashlet { protected $icon = 'cubes'; - protected $requiredStats = array('timeperiod'); + protected $requiredStats = ['timeperiod']; public function getTitle() { @@ -21,7 +23,7 @@ class TimeperiodTemplateDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/TimeperiodsDashlet.php b/library/Director/Dashboard/Dashlet/TimeperiodsDashlet.php index 5a54bec..827cc12 100644 --- a/library/Director/Dashboard/Dashlet/TimeperiodsDashlet.php +++ b/library/Director/Dashboard/Dashlet/TimeperiodsDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class TimeperiodsDashlet extends Dashlet { protected $icon = 'calendar'; - protected $requiredStats = array('timeperiod'); + protected $requiredStats = ['timeperiod']; public function getTitle() { @@ -20,6 +22,6 @@ class TimeperiodsDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/UserGroupsDashlet.php b/library/Director/Dashboard/Dashlet/UserGroupsDashlet.php index 3fba4ba..792e140 100644 --- a/library/Director/Dashboard/Dashlet/UserGroupsDashlet.php +++ b/library/Director/Dashboard/Dashlet/UserGroupsDashlet.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class UserGroupsDashlet extends Dashlet { protected $icon = 'tags'; @@ -26,6 +28,6 @@ class UserGroupsDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Dashboard/Dashlet/UserObjectDashlet.php b/library/Director/Dashboard/Dashlet/UserObjectDashlet.php index 463b84c..7e4f511 100644 --- a/library/Director/Dashboard/Dashlet/UserObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/UserObjectDashlet.php @@ -2,14 +2,11 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; -use DirectoryIterator; -use Icinga\Exception\ProgrammingError; - class UserObjectDashlet extends Dashlet { protected $icon = 'users'; - protected $requiredStats = array('user', 'usergroup'); + protected $requiredStats = ['user', 'usergroup']; public function getTitle() { diff --git a/library/Director/Dashboard/Dashlet/UserTemplateDashlet.php b/library/Director/Dashboard/Dashlet/UserTemplateDashlet.php index 291ab05..c00215d 100644 --- a/library/Director/Dashboard/Dashlet/UserTemplateDashlet.php +++ b/library/Director/Dashboard/Dashlet/UserTemplateDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class UserTemplateDashlet extends Dashlet { protected $icon = 'cubes'; - protected $requiredStats = array('user'); + protected $requiredStats = ['user']; public function getTitle() { @@ -21,7 +23,7 @@ class UserTemplateDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/UsersDashlet.php b/library/Director/Dashboard/Dashlet/UsersDashlet.php index 43ddc26..4f0c7d7 100644 --- a/library/Director/Dashboard/Dashlet/UsersDashlet.php +++ b/library/Director/Dashboard/Dashlet/UsersDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class UsersDashlet extends Dashlet { protected $icon = 'users'; - protected $requiredStats = array('user', 'usergroup'); + protected $requiredStats = ['user', 'usergroup']; public function getTitle() { @@ -15,7 +17,7 @@ class UsersDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/users'); + return [Permission::USERS]; } public function getUrl() diff --git a/library/Director/Dashboard/Dashlet/ZoneObjectDashlet.php b/library/Director/Dashboard/Dashlet/ZoneObjectDashlet.php index ee789f2..f2ff8c8 100644 --- a/library/Director/Dashboard/Dashlet/ZoneObjectDashlet.php +++ b/library/Director/Dashboard/Dashlet/ZoneObjectDashlet.php @@ -2,11 +2,13 @@ namespace Icinga\Module\Director\Dashboard\Dashlet; +use Icinga\Module\Director\Auth\Permission; + class ZoneObjectDashlet extends Dashlet { protected $icon = 'globe'; - protected $requiredStats = array('zone'); + protected $requiredStats = ['zone']; public function getTitle() { @@ -20,6 +22,6 @@ class ZoneObjectDashlet extends Dashlet public function listRequiredPermissions() { - return array('director/admin'); + return [Permission::ADMIN]; } } diff --git a/library/Director/Data/AssignFilterHelper.php b/library/Director/Data/AssignFilterHelper.php index b0253cf..7448c51 100644 --- a/library/Director/Data/AssignFilterHelper.php +++ b/library/Director/Data/AssignFilterHelper.php @@ -135,7 +135,7 @@ class AssignFilterHelper $parts = array(); foreach (preg_split('~\*~', $expression) as $part) { - $parts[] = preg_quote($part); + $parts[] = preg_quote($part, '/'); } // match() is case insensitive $pattern = '/^' . implode('.*', $parts) . '$/i'; diff --git a/library/Director/Data/Db/DbDataFormatter.php b/library/Director/Data/Db/DbDataFormatter.php index d6e4eeb..91fc776 100644 --- a/library/Director/Data/Db/DbDataFormatter.php +++ b/library/Director/Data/Db/DbDataFormatter.php @@ -6,7 +6,7 @@ use InvalidArgumentException; class DbDataFormatter { - public static function normalizeBoolean($value) + public static function normalizeBoolean($value): ?string { if ($value === 'y' || $value === '1' || $value === true || $value === 1) { return 'y'; @@ -20,7 +20,19 @@ class DbDataFormatter throw new InvalidArgumentException(sprintf( 'Got invalid boolean: %s', - var_export($value, 1) + var_export($value, true) )); } + + public static function booleanForDbValue($value): ?bool + { + if ($value === 'y') { + return true; + } + if ($value === 'n') { + return false; + } + + return $value; // let this fail elsewhere, if not null + } } diff --git a/library/Director/Data/Db/DbObject.php b/library/Director/Data/Db/DbObject.php index 6ecae8b..114b61b 100644 --- a/library/Director/Data/Db/DbObject.php +++ b/library/Director/Data/Db/DbObject.php @@ -80,6 +80,9 @@ abstract class DbObject protected $binaryProperties = []; + /* key/value!! */ + protected $booleans = []; + /** * Filled with object instances when prefetchAll is used */ @@ -346,6 +349,16 @@ abstract class DbObject return $this->$func($value); } + if ($this->getUuidColumn() === $key) { + if (strlen($value) > 16) { + $value = Uuid::fromString($value)->getBytes(); + } + } + + if ($this->propertyIsBoolean($key)) { + $value = DbDataFormatter::normalizeBoolean($value); + } + if (! $this->hasProperty($key)) { throw new InvalidArgumentException(sprintf( 'Trying to set invalid key "%s"', @@ -372,7 +385,10 @@ abstract class DbObject return $this; } if ($key === 'id' || substr($key, -3) === '_id') { - if ((int) $value === (int) $this->properties[$key]) { + if ($value !== null + && $this->properties[$key] !== null + && (int) $value === (int) $this->properties[$key] + ) { return $this; } } @@ -553,7 +569,7 @@ abstract class DbObject /** * Unique key name * - * @return string + * @return string|array */ public function getKeyName() { @@ -706,8 +722,7 @@ abstract class DbObject */ protected function loadFromDb() { - $select = $this->db->select()->from($this->table)->where($this->createWhere()); - $properties = $this->db->fetchRow($select); + $properties = $this->db->fetchRow($this->prepareObjectQuery()); if (empty($properties)) { if (is_array($this->getKeyName())) { @@ -728,6 +743,11 @@ abstract class DbObject return $this->setDbProperties($properties); } + public function prepareObjectQuery() + { + return $this->db->select()->from($this->table)->where($this->createWhere()); + } + /** * @param object|array $row * @param Db $db @@ -878,6 +898,11 @@ abstract class DbObject return in_array($column, $this->binaryProperties) || $this->getUuidColumn() === $column; } + public function propertyIsBoolean($property) + { + return array_key_exists($property, $this->booleans); + } + /** * Store object to database * @@ -959,7 +984,7 @@ abstract class DbObject $this->table, $this->getLogId(), $e->getMessage(), - var_export($this->getProperties(), 1) // TODO: Remove properties + var_export($this->getProperties(), true) // TODO: Remove properties )); } @@ -1027,7 +1052,7 @@ abstract class DbObject if ($this->hasUuidColumn() && $this->properties[$this->uuidColumn] !== null) { return $this->db->quoteInto( sprintf('%s = ?', $this->getUuidColumn()), - $this->connection->quoteBinary($this->getUniqueId()->getBytes()) + $this->connection->quoteBinary($this->getOriginalProperty($this->uuidColumn)) ); } if ($id = $this->getAutoincId()) { @@ -1302,6 +1327,40 @@ abstract class DbObject } /** + * @param $id + * @param DbConnection $connection + * @return static + */ + public static function loadOptional($id, DbConnection $connection): ?DbObject + { + if ($prefetched = static::getPrefetched($id)) { + return $prefetched; + } + /** @var DbObject $obj */ + $obj = new static(); + + if (self::$dbObjectStore !== null && $obj->hasUuidColumn()) { + $table = $obj->getTableName(); + assert($connection instanceof Db); + $uuid = UuidLookup::findUuidForKey($id, $table, $connection, self::$dbObjectStore->getBranch()); + if ($uuid) { + return self::$dbObjectStore->load($table, $uuid); + } + + return null; + } + + $obj->setConnection($connection)->setKey($id); + $properties = $connection->getDbAdapter()->fetchRow($obj->prepareObjectQuery()); + if (empty($properties)) { + return null; + } + + $obj->setDbProperties($properties); + return $obj; + } + + /** * @param DbConnection $connection * @param \Zend_Db_Select $query * @param string|null $keyColumn @@ -1436,7 +1495,7 @@ abstract class DbObject )); } - public static function loadWithUniqueId(UuidInterface $uuid, DbConnection $connection) + public static function loadWithUniqueId(UuidInterface $uuid, DbConnection $connection): ?DbObject { $db = $connection->getDbAdapter(); $obj = new static; diff --git a/library/Director/Data/Db/ServiceSetQueryBuilder.php b/library/Director/Data/Db/ServiceSetQueryBuilder.php index 7841d1e..597fe0e 100644 --- a/library/Director/Data/Db/ServiceSetQueryBuilder.php +++ b/library/Director/Data/Db/ServiceSetQueryBuilder.php @@ -27,6 +27,8 @@ class ServiceSetQueryBuilder /** @var \Zend_Db_Adapter_Abstract */ protected $db; + protected $searchColumns = []; + /** * @param ?UuidInterface $uuid */ diff --git a/library/Director/Data/Exporter.php b/library/Director/Data/Exporter.php index a2e3191..1a3cfcb 100644 --- a/library/Director/Data/Exporter.php +++ b/library/Director/Data/Exporter.php @@ -2,10 +2,14 @@ namespace Icinga\Module\Director\Data; +use gipfl\Json\JsonString; use gipfl\ZfDb\Adapter\Adapter; +use Icinga\Authentication\Auth; +use Icinga\Module\Director\Data\Db\DbDataFormatter; use Icinga\Module\Director\Data\Db\DbObject; use Icinga\Module\Director\Data\Db\DbObjectWithSettings; use Icinga\Module\Director\Db; +use Icinga\Module\Director\DirectorObject\Automation\Basket; use Icinga\Module\Director\Objects\DirectorDatafield; use Icinga\Module\Director\Objects\DirectorDatalist; use Icinga\Module\Director\Objects\DirectorDatalistEntry; @@ -18,6 +22,7 @@ use Icinga\Module\Director\Objects\IcingaTemplateChoice; use Icinga\Module\Director\Objects\ImportSource; use Icinga\Module\Director\Objects\InstantiatedViaHook; use Icinga\Module\Director\Objects\SyncRule; +use Ramsey\Uuid\Uuid; use RuntimeException; class Exporter @@ -68,6 +73,11 @@ class Exporter $props = $chosen; } + if ($column = $object->getUuidColumn()) { + if ($uuid = $object->get($column)) { + $props[$column] = Uuid::fromBytes($uuid)->toString(); + } + } ksort($props); return (object) $props; @@ -152,10 +162,10 @@ class Exporter throw new RuntimeException('Not yet'); } $props['services'] = []; - foreach ($object->getServiceObjects() as $serviceObject) { - $props['services'][$serviceObject->getObjectName()] = $this->export($serviceObject); + foreach ($object->getServices() as $serviceObject) { + $props['services'][] = $this->export($serviceObject); } - ksort($props['services']); + usort($props['services'], [$this, 'sortByName']); } elseif ($object instanceof IcingaHost) { if ($this->exportHostServices) { $services = []; @@ -168,10 +178,15 @@ class Exporter } } + protected function sortByName($left, $right) + { + return $left->object_name < $right->object_name ? '-1' : '1'; + } + public function serviceLoader() { if ($this->serviceLoader === null) { - $this->serviceLoader = new HostServiceLoader($this->connection); + $this->serviceLoader = new HostServiceLoader($this->connection, Auth::getInstance()); $this->serviceLoader->resolveObjects($this->resolveObjects); } @@ -241,6 +256,12 @@ class Exporter protected function exportDbObject(DbObject $object) { $props = $object->getProperties(); + foreach ($props as $key => &$value) { + if ($object->propertyIsBoolean($key)) { + $value = DbDataFormatter::booleanForDbValue($value); + } + } + unset($value); if ($object instanceof DbObjectWithSettings) { if ($object instanceof InstantiatedViaHook) { $props['settings'] = (object) $object->getInstance()->exportSettings(); @@ -248,6 +269,11 @@ class Exporter $props['settings'] = (object) $object->getSettings(); // Already sorted } } + if ($object instanceof Basket) { + if (isset($props['objects']) && is_string($props['objects'])) { + $props['objects'] = JsonString::decode($props['objects']); + } + } unset($props['uuid']); // Not yet if (! $this->showDefaults) { foreach ($props as $key => $value) { @@ -279,16 +305,7 @@ class Exporter protected function exportDatalistEntries(DirectorDatalist $list) { $entries = []; - $id = $list->get('id'); - if ($id === null) { - return $entries; - } - - $dbEntries = DirectorDatalistEntry::loadAllForList($list); - // Hint: they are loaded with entry_name key - ksort($dbEntries); - - foreach ($dbEntries as $entry) { + foreach ($list->getEntries() as $name => $entry) { if ($entry->shouldBeRemoved()) { continue; } diff --git a/library/Director/Data/FieldReferenceLoader.php b/library/Director/Data/FieldReferenceLoader.php index 1e3d92e..99a9925 100644 --- a/library/Director/Data/FieldReferenceLoader.php +++ b/library/Director/Data/FieldReferenceLoader.php @@ -29,12 +29,12 @@ class FieldReferenceLoader } $type = $object->getShortTableName(); $res = $db->fetchAll( - $db->select()->from(['f' => "icinga_${type}_field"], [ + $db->select()->from(['f' => "icinga_{$type}_field"], [ 'f.datafield_id', 'f.is_required', 'f.var_filter', ])->join(['df' => 'director_datafield'], 'df.id = f.datafield_id', []) - ->where("${type}_id = ?", (int) $id) + ->where("{$type}_id = ?", (int) $id) ->order('varname ASC') ); diff --git a/library/Director/Data/HostServiceLoader.php b/library/Director/Data/HostServiceLoader.php index 4cc4b96..c8bd8b9 100644 --- a/library/Director/Data/HostServiceLoader.php +++ b/library/Director/Data/HostServiceLoader.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Data; use gipfl\IcingaWeb2\Table\QueryBasedTable; use gipfl\ZfDb\Select; +use Icinga\Authentication\Auth; use Icinga\Data\SimpleQuery; use Icinga\Module\Director\Db; use Icinga\Module\Director\Db\AppliedServiceSetLoader; @@ -26,21 +27,26 @@ class HostServiceLoader /** @var \Zend_Db_Adapter_Abstract */ protected $db; + /** @var Auth */ + protected $auth; + /** @var bool */ protected $resolveHostServices = false; /** @var bool */ protected $resolveObjects = false; - public function __construct(Db $connection) + public function __construct(Db $connection, Auth $auth) { $this->connection = $connection; $this->db = $connection->getDbAdapter(); + $this->auth = $auth; } public function fetchServicesForHost(IcingaHost $host) { - $table = (new ObjectsTableService($this->connection))->setHost($host); + $table = (new ObjectsTableService($this->connection, $this->auth)) + ->setHost($host); $services = $this->fetchServicesForTable($table); if ($this->resolveHostServices) { foreach ($this->fetchAllServicesForHost($host) as $service) { @@ -69,7 +75,7 @@ class HostServiceLoader /** @var IcingaHost[] $parents */ $parents = IcingaTemplateRepository::instanceByObject($host)->getTemplatesFor($host, true); foreach ($parents as $parent) { - $table = (new ObjectsTableService($this->connection)) + $table = (new ObjectsTableService($this->connection, $this->auth)) ->setHost($parent) ->setInheritedBy($host); foreach ($this->fetchServicesForTable($table) as $service) { diff --git a/library/Director/Data/ObjectImporter.php b/library/Director/Data/ObjectImporter.php new file mode 100644 index 0000000..231ad1c --- /dev/null +++ b/library/Director/Data/ObjectImporter.php @@ -0,0 +1,168 @@ +<?php + +namespace Icinga\Module\Director\Data; + +use gipfl\Json\JsonDecodeException; +use gipfl\Json\JsonString; +use Icinga\Module\Director\Data\Db\DbObject; +use Icinga\Module\Director\Db; +use Icinga\Module\Director\DirectorObject\Automation\Basket; +use Icinga\Module\Director\Objects\DirectorJob; +use Icinga\Module\Director\Objects\IcingaHost; +use Icinga\Module\Director\Objects\IcingaService; +use Icinga\Module\Director\Objects\IcingaServiceSet; +use Icinga\Module\Director\Objects\ImportSource; +use Icinga\Module\Director\Objects\SyncRule; +use InvalidArgumentException; +use Ramsey\Uuid\Uuid; +use stdClass; + +class ObjectImporter +{ + protected static $templatesOnly = [ + IcingaHost::class, + IcingaService::class, + IcingaServiceSet::class, + ]; + + /** @var Db */ + protected $db; + + public function __construct(Db $db) + { + $this->db = $db; + } + + /** + * @param class-string|DbObject $implementation + * @param stdClass $plain + * @return DbObject + * @throws JsonDecodeException + */ + public function import(string $implementation, stdClass $plain): DbObject + { + $this->assertTemplate($implementation, $plain); + $this->fixRelations($implementation, $plain); + $this->applyOtherWorkarounds($implementation, $plain); + $this->fixLegacyBaskets($implementation, $plain); + $this->fixSubObjects($implementation, $plain); + + $object = $this->loadExistingObject($implementation, $plain); + if ($object === null) { + $object = $implementation::create([], $this->db); + } + + $properties = (array) $plain; + unset($properties['fields']); + unset($properties['originalId']); + if ($implementation === Basket::class) { + if (isset($properties['objects']) && is_string($properties['objects'])) { + $properties['objects'] = JsonString::decode($properties['objects']); + } + } + $object->setProperties($properties); + + return $object; + } + + protected function fixLegacyBaskets(string $implementation, stdClass $plain) + { + // TODO: Check, whether current export sets modifiers = [] in case there is none + if ($implementation == ImportSource::class) { + if (!isset($plain->modifiers)) { + $plain->modifiers = []; + } + } + } + + protected function applyOtherWorkarounds(string $implementation, stdClass $plain) + { + if ($implementation === SyncRule::class) { + if (isset($plain->properties)) { + $plain->syncProperties = $plain->properties; + unset($plain->properties); + } + } + } + + protected function fixSubObjects(string $implementation, stdClass $plain) + { + if ($implementation === IcingaServiceSet::class) { + foreach ($plain->services as $service) { + unset($service->fields); + } + // Hint: legacy baskets are carrying service names as object keys, new baskets have arrays + $plain->services = array_values((array) $plain->services); + } + } + + protected function fixRelations(string $implementation, stdClass $plain) + { + if ($implementation === DirectorJob::class) { + $settings = $plain->settings; + $source = $settings->source ?? null; + if ($source && !isset($settings->source_id)) { + $settings->source_id = ImportSource::load($source, $this->db)->get('id'); + unset($settings->source); + } + $rule = $settings->rule ?? null; + if ($rule && !isset($settings->rule_id)) { + $settings->rule_id = SyncRule::load($rule, $this->db)->get('id'); + unset($settings->rule); + } + } + } + + /** + * @param class-string<DbObject> $implementation + * @param stdClass $plain + * @return DbObject|null + */ + protected function loadExistingObject(string $implementation, stdClass $plain): ?DbObject + { + if (isset($plain->uuid) + && $instance = $implementation::loadWithUniqueId(Uuid::fromString($plain->uuid), $this->db) + ) { + return $instance; + } + + if ($implementation === IcingaService::class) { + $key = [ + 'object_type' => 'template', + 'object_name' => $plain->object_name + ]; + } else { + $dummy = $implementation::create(); + $keyColumn = $dummy->getKeyName(); + if (is_array($keyColumn)) { + if (empty($keyColumn)) { + throw new \RuntimeException("$implementation has an empty keyColumn array"); + } + $key = []; + foreach ($keyColumn as $column) { + if (isset($plain->$column)) { + $key[$column] = $plain->$column; + } + } + } else { + $key = $plain->$keyColumn; + } + } + + return $implementation::loadOptional($key, $this->db); + } + + protected function assertTemplate(string $implementation, stdClass $plain) + { + if (! in_array($implementation, self::$templatesOnly)) { + return; + } + if ($plain->object_type !== 'template') { + throw new InvalidArgumentException(sprintf( + 'Can import only Templates, got "%s" for "%s"', + $plain->object_type, + $plain->name + )); + } + } +} diff --git a/library/Director/Data/PropertyMangler.php b/library/Director/Data/PropertyMangler.php index a457f1d..40b2570 100644 --- a/library/Director/Data/PropertyMangler.php +++ b/library/Director/Data/PropertyMangler.php @@ -19,7 +19,7 @@ class PropertyMangler throw new InvalidArgumentException(sprintf( 'I can only append to arrays, %s is %s', $key, - var_export($current, 1) + var_export($current, true) )); } @@ -52,7 +52,7 @@ class PropertyMangler throw new InvalidArgumentException(sprintf( 'I can only remove strings or from arrays, %s is %s', $key, - var_export($current, 1) + var_export($current, true) )); } } diff --git a/library/Director/Db/Branch/Branch.php b/library/Director/Db/Branch/Branch.php index cd68ff0..c99b1bd 100644 --- a/library/Director/Db/Branch/Branch.php +++ b/library/Director/Db/Branch/Branch.php @@ -2,11 +2,11 @@ namespace Icinga\Module\Director\Db\Branch; +use Icinga\Application\Hook; use Icinga\Application\Icinga; use Icinga\Authentication\Auth; use Icinga\Module\Director\Db; use Icinga\Module\Director\Hook\BranchSupportHook; -use Icinga\Web\Hook; use Icinga\Web\Request; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidInterface; @@ -45,7 +45,7 @@ class Branch $row->uuid = stream_get_contents($row->uuid); } if (strlen($row->uuid) !== 16) { - throw new RuntimeException('Valid UUID expected, got ' . var_export($row->uuid, 1)); + throw new RuntimeException('Valid UUID expected, got ' . var_export($row->uuid, true)); } $self->branchUuid = Uuid::fromBytes(Db\DbUtil::binaryResult($row->uuid)); $self->name = $row->branch_name; diff --git a/library/Director/Db/Branch/BranchActivity.php b/library/Director/Db/Branch/BranchActivity.php index 3812e75..e95ac7d 100644 --- a/library/Director/Db/Branch/BranchActivity.php +++ b/library/Director/Db/Branch/BranchActivity.php @@ -294,7 +294,13 @@ class BranchActivity */ public function getObjectName() { - return $this->getProperty('object_name', 'unknown object name'); + if ($this->objectTable === BranchSupport::TABLE_ICINGA_SERVICE && $host = $this->getProperty('host')) { + $suffix = " ($host)"; + } else { + $suffix = ''; + } + + return $this->getProperty('object_name', 'unknown object name') . $suffix; } /** diff --git a/library/Director/Db/Branch/BranchStore.php b/library/Director/Db/Branch/BranchStore.php index 196d079..13971b9 100644 --- a/library/Director/Db/Branch/BranchStore.php +++ b/library/Director/Db/Branch/BranchStore.php @@ -56,6 +56,7 @@ class BranchStore $rows = $db->fetchAll($db->select()->from($table)->where('branch_uuid = ?', $oldQuotedUuid)); foreach ($rows as $row) { $modified = (array)$row; + $this->quoteBinaryProperties($modified); $modified['branch_uuid'] = $quotedUuid; if ($table === self::TABLE_ACTIVITY) { $modified['timestamp_ns'] = round($modified['timestamp_ns'] / 1000000); @@ -68,6 +69,21 @@ class BranchStore return $this->fetchBranchByName($newName); } + protected function quoteBinaryProperties(&$properties) + { + foreach ($properties as $key => $value) { + if ($this->isBinaryColumn($key)) { + $properties[$key] = $this->connection->quoteBinary($value); + } + } + } + + protected function isBinaryColumn($key) + { + return (strpos($key, 'uuid') !== false || strpos($key, 'checksum') !== false) + && strpos($key, 'hex') === false; + } + protected function runTransaction($callback) { $db = $this->db; @@ -100,7 +116,6 @@ class BranchStore } } }); - } protected function newFromDbResult($query) diff --git a/library/Director/Db/Branch/PreferredBranchSupport.php b/library/Director/Db/Branch/PreferredBranchSupport.php new file mode 100644 index 0000000..3463bfe --- /dev/null +++ b/library/Director/Db/Branch/PreferredBranchSupport.php @@ -0,0 +1,10 @@ +<?php + +namespace Icinga\Module\Director\Db\Branch; + +use Icinga\Authentication\Auth; + +interface PreferredBranchSupport +{ + public function hasPreferredBranch(Auth $auth): bool; +} diff --git a/library/Director/Db/Branch/UuidLookup.php b/library/Director/Db/Branch/UuidLookup.php index b340e07..4db7866 100644 --- a/library/Director/Db/Branch/UuidLookup.php +++ b/library/Director/Db/Branch/UuidLookup.php @@ -15,18 +15,13 @@ use function is_string; class UuidLookup { /** - * @param Db $connection - * @param Branch $branch - * @param string $objectType * @param int|string $key - * @param IcingaHost|null $host - * @param IcingaServiceSet $set * @return ?UuidInterface */ public static function findServiceUuid( Db $connection, Branch $branch, - $objectType = null, + ?string $objectType = null, $key = null, IcingaHost $host = null, IcingaServiceSet $set = null @@ -37,11 +32,20 @@ class UuidLookup $query->where('object_type = ?', $objectType); } $query = self::addKeyToQuery($connection, $query, $key); - if ($host) { - $query->where('host_id = ?', $host->get('id')); - } if ($set) { - $query->where('service_set_id = ?', $set->get('id')); + $setId = $set->get('id'); + if ($setId === null) { + $query->where('1 = 0'); + } else { + $query->where('service_set_id = ?', $setId); + } + } elseif ($host) { + $hostId = $host->get('id'); + if ($hostId === null) { + $query->where('1 = 0'); + } else { + $query->where('host_id = ?', $hostId); + } } $uuid = self::fetchOptionalUuid($connection, $query); @@ -100,7 +104,7 @@ class UuidLookup $uuid = self::fetchOptionalUuid($connection, $query); if ($uuid === null && $branch->isBranch()) { if (is_array($key) && isset($key['host_id'])) { - $key['host'] = IcingaHost::load($key['host_id'], $connection)->getObjectName(); + $key['host'] = IcingaHost::loadWithAutoIncId((int) $key['host_id'], $connection)->getObjectName(); unset($key['host_id']); } $query = self::addKeyToQuery($connection, $db->select()->from("branched_$table", 'uuid'), $key); diff --git a/library/Director/Db/Cache/CustomVariableCache.php b/library/Director/Db/Cache/CustomVariableCache.php index 243ecae..ee2b9ef 100644 --- a/library/Director/Db/Cache/CustomVariableCache.php +++ b/library/Director/Db/Cache/CustomVariableCache.php @@ -76,9 +76,4 @@ class CustomVariableCache return new CustomVariables(); } } - - public function __destruct() - { - unset($this->db); - } } diff --git a/library/Director/Db/IcingaObjectFilterHelper.php b/library/Director/Db/IcingaObjectFilterHelper.php index 2eef406..2d9f8f3 100644 --- a/library/Director/Db/IcingaObjectFilterHelper.php +++ b/library/Director/Db/IcingaObjectFilterHelper.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Db; use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Resolver\TemplateTree; use InvalidArgumentException; +use Ramsey\Uuid\UuidInterface; use RuntimeException; use Zend_Db_Select as ZfSelect; @@ -30,7 +31,7 @@ class IcingaObjectFilterHelper throw new InvalidArgumentException(sprintf( 'Numeric ID or IcingaObject expected, got %s', // TODO: just type/class info? - var_export($id, 1) + var_export($id, true) )); } } @@ -46,20 +47,49 @@ class IcingaObjectFilterHelper ZfSelect $query, $template, $tableAlias = 'o', - $inheritanceType = self::INHERIT_DIRECT + $inheritanceType = self::INHERIT_DIRECT, + UuidInterface $branchuuid = null ) { $i = $tableAlias . 'i'; $o = $tableAlias; $type = $template->getShortTableName(); $db = $template->getDb(); $id = static::wantId($template); + + if ($branchuuid) { + if ($inheritanceType === self::INHERIT_DIRECT) { + return $query->where('imports LIKE \'%"' . $template->getObjectName() . '"%\''); + } elseif ($inheritanceType === self::INHERIT_INDIRECT + || $inheritanceType === self::INHERIT_DIRECT_OR_INDIRECT + ) { + $tree = new TemplateTree($type, $template->getConnection()); + $templateNames = $tree->getDescendantsFor($template); + + if ($inheritanceType === self::INHERIT_DIRECT_OR_INDIRECT) { + $templateNames[] = $template->getObjectName(); + } + + if (empty($templateNames)) { + $condition = '(1 = 0)'; + } else { + $condition = 'imports LIKE \'%"' . array_pop($templateNames) . '"%\''; + + foreach ($templateNames as $templateName) { + $condition .= " OR imports LIKE '%\"$templateName\"%'"; + } + } + + return $query->where($condition); + } + } + $sub = $db->select()->from( - array($i => "icinga_${type}_inheritance"), + array($i => "icinga_{$type}_inheritance"), array('e' => '(1)') - )->where("$i.${type}_id = $o.id"); + )->where("$i.{$type}_id = $o.id"); if ($inheritanceType === self::INHERIT_DIRECT) { - $sub->where("$i.parent_${type}_id = ?", $id); + $sub->where("$i.parent_{$type}_id = ?", $id); } elseif ($inheritanceType === self::INHERIT_INDIRECT || $inheritanceType === self::INHERIT_DIRECT_OR_INDIRECT ) { @@ -72,7 +102,7 @@ class IcingaObjectFilterHelper if (empty($ids)) { $sub->where('(1 = 0)'); } else { - $sub->where("$i.parent_${type}_id IN (?)", $ids); + $sub->where("$i.parent_{$type}_id IN (?)", $ids); } } else { throw new RuntimeException(sprintf( @@ -95,12 +125,12 @@ class IcingaObjectFilterHelper $query->where('(1 = 0)'); } else { $sub = $query->getAdapter()->select()->from( - array('go' => "icinga_${type}group_${type}"), + array('go' => "icinga_{$type}group_{$type}"), array('e' => '(1)') )->join( - array('g' => "icinga_${type}group"), - "go.${type}group_id = g.id" - )->where("go.${type}_id = ${tableAlias}.id") + array('g' => "icinga_{$type}group"), + "go.{$type}group_id = g.id" + )->where("go.{$type}_id = {$tableAlias}.id") ->where('g.object_name IN (?)', $groups); $query->where('EXISTS ?', $sub); @@ -118,13 +148,13 @@ class IcingaObjectFilterHelper $query->where('(1 = 0)'); } else { $sub = $query->getAdapter()->select()->from( - array('go' => "icinga_${type}group_${type}_resolved"), + array('go' => "icinga_{$type}group_{$type}_resolved"), array('e' => '(1)') )->join( - array('g' => "icinga_${type}group"), - "go.${type}group_id = g.id", + array('g' => "icinga_{$type}group"), + "go.{$type}group_id = g.id", [] - )->where("go.${type}_id = ${tableAlias}.id") + )->where("go.{$type}_id = {$tableAlias}.id") ->where('g.object_name IN (?)', $groups); $query->where('EXISTS ?', $sub); diff --git a/library/Director/Db/Migrations.php b/library/Director/Db/Migrations.php index 2310408..ad59329 100644 --- a/library/Director/Db/Migrations.php +++ b/library/Director/Db/Migrations.php @@ -90,7 +90,7 @@ class Migrations public function applyPendingMigrations() { // Ensure we have enough time to migrate - ini_set('max_execution_time', 0); + ini_set('max_execution_time', '0'); foreach ($this->getPendingMigrations() as $migration) { $migration->apply($this->connection); diff --git a/library/Director/DirectorObject/Automation/Basket.php b/library/Director/DirectorObject/Automation/Basket.php index f7eb8e5..81ae107 100644 --- a/library/Director/DirectorObject/Automation/Basket.php +++ b/library/Director/DirectorObject/Automation/Basket.php @@ -4,8 +4,6 @@ namespace Icinga\Module\Director\DirectorObject\Automation; use Icinga\Module\Director\Core\Json; use Icinga\Module\Director\Data\Db\DbObject; -use Icinga\Module\Director\Db; -use Icinga\Module\Director\Exception\DuplicateKeyException; /** * Class Basket @@ -15,16 +13,17 @@ use Icinga\Module\Director\Exception\DuplicateKeyException; */ class Basket extends DbObject implements ExportInterface { - const SELECTION_ALL = true; - const SELECTION_NONE = false; + const SELECTION_ALL = 'ALL'; + const SELECTION_NONE = 'IGNORE'; + const SELECTION_CUSTOM = '[]'; protected $table = 'director_basket'; protected $keyName = 'basket_name'; - protected $chosenObjects = []; + protected $uuidColumn = 'uuid'; - protected $protectedFormerChosenObjects; + protected $chosenObjects = []; protected $defaultProperties = [ 'uuid' => null, @@ -69,44 +68,6 @@ class Basket extends DbObject implements ExportInterface return $this->get('basket_name'); } - public function export() - { - $result = $this->getProperties(); - unset($result['uuid']); - $result['objects'] = Json::decode($result['objects']); - ksort($result); - - return (object) $result; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return static - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - $name = $properties['basket_name']; - - if ($replace && static::exists($name, $db)) { - $object = static::load($name, $db); - } elseif (static::exists($name, $db)) { - throw new DuplicateKeyException( - 'Basket "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - $object->setProperties($properties); - - return $object; - } - public function supportsCustomSelectionFor($type) { if (! array_key_exists($type, $this->chosenObjects)) { @@ -121,7 +82,6 @@ class Basket extends DbObject implements ExportInterface if (empty($objects)) { $this->chosenObjects = []; } else { - $this->protectedFormerChosenObjects = $this->chosenObjects; $this->chosenObjects = []; foreach ((array) $objects as $type => $object) { $this->addObjects($type, $object); @@ -141,32 +101,22 @@ class Basket extends DbObject implements ExportInterface { BasketSnapshot::assertValidType($type); // '1' -> from Form! - if ($objects === 'ALL') { + if ($objects === self::SELECTION_ALL) { $objects = true; - } elseif ($objects === null || $objects === 'IGNORE') { + } elseif ($objects === null || $objects === self::SELECTION_NONE) { return; - } elseif ($objects === '[]' || is_array($objects)) { + } elseif ($objects === self::SELECTION_CUSTOM || is_array($objects)) { if (! isset($this->chosenObjects[$type]) || ! is_array($this->chosenObjects[$type])) { $this->chosenObjects[$type] = []; } - if (isset($this->protectedFormerChosenObjects[$type])) { - if (is_array($this->protectedFormerChosenObjects[$type])) { - $this->chosenObjects[$type] = $this->protectedFormerChosenObjects[$type]; - } else { - $this->chosenObjects[$type] = []; - } - } - - if ($objects === '[]') { + if ($objects === self::SELECTION_CUSTOM) { $objects = []; } } if ($objects === true) { $this->chosenObjects[$type] = true; - } elseif ($objects === '0') { - // nothing - } else { + } elseif ($objects !== '0') { // TODO: what would generate '0'? foreach ($objects as $object) { $this->addObject($type, $object); } diff --git a/library/Director/DirectorObject/Automation/BasketDiff.php b/library/Director/DirectorObject/Automation/BasketDiff.php new file mode 100644 index 0000000..8dbb423 --- /dev/null +++ b/library/Director/DirectorObject/Automation/BasketDiff.php @@ -0,0 +1,121 @@ +<?php + +namespace Icinga\Module\Director\DirectorObject\Automation; + +use gipfl\Json\JsonString; +use Icinga\Module\Director\Data\Exporter; +use Icinga\Module\Director\Data\ObjectImporter; +use Icinga\Module\Director\Db; +use Icinga\Module\Director\Objects\DirectorDatalist; +use Ramsey\Uuid\UuidInterface; +use stdClass; + +class BasketDiff +{ + /** @var Db */ + protected $db; + /** @var ObjectImporter */ + protected $importer; + /** @var Exporter */ + protected $exporter; + /** @var BasketSnapshot */ + protected $snapshot; + /** @var ?stdClass */ + protected $objects = null; + /** @var BasketSnapshotFieldResolver */ + protected $fieldResolver; + + public function __construct(BasketSnapshot $snapshot, Db $db) + { + $this->db = $db; + $this->importer = new ObjectImporter($db); + $this->exporter = new Exporter($db); + $this->snapshot = $snapshot; + } + + public function hasChangedFor(string $type, string $key, ?UuidInterface $uuid = null): bool + { + return $this->getCurrentString($type, $key, $uuid) !== $this->getBasketString($type, $key); + } + + public function getCurrentString(string $type, string $key, ?UuidInterface $uuid = null): string + { + $current = $this->getCurrent($type, $key, $uuid); + return $current ? JsonString::encode($current, JSON_PRETTY_PRINT) : ''; + } + + public function getBasketString(string $type, string $key): string + { + return JsonString::encode($this->getBasket($type, $key), JSON_PRETTY_PRINT); + } + + protected function getFieldResolver(): BasketSnapshotFieldResolver + { + if ($this->fieldResolver === null) { + $this->fieldResolver = new BasketSnapshotFieldResolver($this->getBasketObjects(), $this->db); + } + + return $this->fieldResolver; + } + + protected function getCurrent(string $type, string $key, ?UuidInterface $uuid = null): ?stdClass + { + if ($uuid && $current = BasketSnapshot::instanceByUuid($type, $uuid, $this->db)) { + $exported = $this->exporter->export($current); + $this->getFieldResolver()->tweakTargetIds($exported); + } elseif ($current = BasketSnapshot::instanceByIdentifier($type, $key, $this->db)) { + $exported = $this->exporter->export($current); + $this->getFieldResolver()->tweakTargetIds($exported); + } else { + $exported = null; + } + CompareBasketObject::normalize($exported); + + return $exported; + } + + protected function getBasket($type, $key): stdClass + { + $object = $this->getBasketObject($type, $key); + $fields = $object->fields ?? null; + $reExport = $this->exporter->export( + $this->importer->import(BasketSnapshot::getClassForType($type), $object) + ); + if ($fields === null) { + unset($reExport->fields); + } else { + $reExport->fields = $fields; + } + CompareBasketObject::normalize($reExport); + + return $reExport; + } + + public function hasCurrentInstance(string $type, string $key, ?UuidInterface $uuid = null): bool + { + return $this->getCurrentInstance($type, $key, $uuid) !== null; + } + + public function getCurrentInstance(string $type, string $key, ?UuidInterface $uuid = null) + { + if ($uuid && $instance = BasketSnapshot::instanceByUuid($type, $uuid, $this->db)) { + return $instance; + } else { + return BasketSnapshot::instanceByIdentifier($type, $key, $this->db); + } + } + + public function getBasketObjects(): stdClass + { + if ($this->objects === null) { + $this->objects = JsonString::decode($this->snapshot->getJsonDump()); + } + + return $this->objects; + } + + public function getBasketObject(string $type, string $key): stdClass + { + return $this->getBasketObjects()->$type->$key; + } +} diff --git a/library/Director/DirectorObject/Automation/BasketSnapshot.php b/library/Director/DirectorObject/Automation/BasketSnapshot.php index 4ddf2ce..9638e49 100644 --- a/library/Director/DirectorObject/Automation/BasketSnapshot.php +++ b/library/Director/DirectorObject/Automation/BasketSnapshot.php @@ -2,10 +2,11 @@ namespace Icinga\Module\Director\DirectorObject\Automation; +use gipfl\Json\JsonDecodeException; use gipfl\Json\JsonEncodeException; use gipfl\Json\JsonString; -use Icinga\Module\Director\Core\Json; use Icinga\Module\Director\Data\Exporter; +use Icinga\Module\Director\Data\ObjectImporter; use Icinga\Module\Director\Db; use Icinga\Module\Director\Data\Db\DbObject; use Icinga\Module\Director\Objects\DirectorDatafield; @@ -29,7 +30,9 @@ use Icinga\Module\Director\Objects\IcingaUserGroup; use Icinga\Module\Director\Objects\ImportSource; use Icinga\Module\Director\Objects\SyncRule; use InvalidArgumentException; +use Ramsey\Uuid\UuidInterface; use RuntimeException; +use stdClass; class BasketSnapshot extends DbObject { @@ -217,16 +220,11 @@ class BasketSnapshot extends DbObject /** * @param Db $connection - * @param bool $replace * @throws \Icinga\Exception\NotFoundError */ - public function restoreTo(Db $connection, $replace = true) + public function restoreTo(Db $connection) { - static::restoreJson( - $this->getJsonDump(), - $connection, - $replace - ); + static::restoreJson($this->getJsonDump(), $connection); } /** @@ -240,61 +238,49 @@ class BasketSnapshot extends DbObject 'basket_uuid' => $basket->get('uuid') ]); $snapshot->objects = []; - foreach ((array) Json::decode($string) as $type => $objects) { + foreach ((array) JsonString::decode($string) as $type => $objects) { $snapshot->objects[$type] = (array) $objects; } return $snapshot; } - public static function restoreJson($string, Db $connection, $replace = true) + public static function restoreJson($string, Db $connection) { - $snapshot = new static(); - $snapshot->restoreObjects( - Json::decode($string), - $connection, - $replace - ); + (new static())->restoreObjects(JsonString::decode($string), $connection); } /** - * @param $all - * @param Db $connection - * @param bool $replace * @throws \Icinga\Module\Director\Exception\DuplicateKeyException * @throws \Zend_Db_Adapter_Exception * @throws \Icinga\Exception\NotFoundError + * @throws JsonDecodeException */ - protected function restoreObjects($all, Db $connection, $replace = true) + protected function restoreObjects(stdClass $all, Db $connection) { $db = $connection->getDbAdapter(); $db->beginTransaction(); $fieldResolver = new BasketSnapshotFieldResolver($all, $connection); - $this->restoreType($all, 'DataList', $fieldResolver, $connection, $replace); - $this->restoreType($all, 'DatafieldCategory', $fieldResolver, $connection, $replace); + $this->restoreType($all, 'DataList', $fieldResolver, $connection); + $this->restoreType($all, 'DatafieldCategory', $fieldResolver, $connection); $fieldResolver->storeNewFields(); foreach ($this->restoreOrder as $typeName) { - $this->restoreType($all, $typeName, $fieldResolver, $connection, $replace); + $this->restoreType($all, $typeName, $fieldResolver, $connection); } $db->commit(); } /** - * @param $all - * @param $typeName - * @param BasketSnapshotFieldResolver $fieldResolver - * @param Db $connection - * @param $replace * @throws \Icinga\Exception\NotFoundError * @throws \Icinga\Module\Director\Exception\DuplicateKeyException * @throws \Zend_Db_Adapter_Exception + * @throws JsonDecodeException */ public function restoreType( - &$all, - $typeName, + stdClass $all, + string $typeName, BasketSnapshotFieldResolver $fieldResolver, - Db $connection, - $replace + Db $connection ) { if (isset($all->$typeName)) { $objects = (array) $all->$typeName; @@ -302,11 +288,10 @@ class BasketSnapshot extends DbObject return; } $class = static::getClassForType($typeName); - + $importer = new ObjectImporter($connection); $changed = []; - foreach ($objects as $key => $object) { - /** @var DbObject $new */ - $new = $class::import($object, $connection, $replace); + foreach ($objects as $object) { + $new = $importer->import($class, $object); if ($new->hasBeenModified()) { if ($new instanceof IcingaObject && $new->supportsImports()) { /** @var ExportInterface $new */ @@ -325,7 +310,6 @@ class BasketSnapshot extends DbObject $fieldResolver->relinkObjectFields($new, $object); } } - $allObjects[spl_object_hash($new)] = $object; } /** @var IcingaObject $object */ @@ -334,7 +318,7 @@ class BasketSnapshot extends DbObject } foreach ($changed as $key => $new) { // Store related fields. As objects might have formerly been - // un-stored, let's to it right here + // un-stored, let's do it right here if ($new instanceof IcingaObject) { $fieldResolver->relinkObjectFields($new, $objects[$key]); } @@ -358,10 +342,9 @@ class BasketSnapshot extends DbObject } /** - * @return BasketContent * @throws \Icinga\Exception\NotFoundError */ - protected function getContent() + protected function getContent(): BasketContent { if ($this->content === null) { $this->content = BasketContent::load($this->get('content_checksum'), $this->getConnection()); @@ -380,26 +363,25 @@ class BasketSnapshot extends DbObject } /** - * @return string - * @throws \Icinga\Exception\NotFoundError + * @throws \Icinga\Exception\NotFoundError|JsonEncodeException */ - public function getJsonSummary() + public function getJsonSummary(): string { if ($this->hasBeenLoadedFromDb()) { return $this->getContent()->get('summary'); } - return Json::encode($this->getSummary(), JSON_PRETTY_PRINT); + return JsonString::encode($this->getSummary(), JSON_PRETTY_PRINT); } /** * @return array|mixed - * @throws \Icinga\Exception\NotFoundError + * @throws \Icinga\Exception\NotFoundError|JsonDecodeException */ public function getSummary() { if ($this->hasBeenLoadedFromDb()) { - return Json::decode($this->getContent()->get('summary')); + return JsonString::decode($this->getContent()->get('summary')); } $summary = []; @@ -412,7 +394,7 @@ class BasketSnapshot extends DbObject /** * @return string - * @throws \Icinga\Exception\NotFoundError + * @throws \Icinga\Exception\NotFoundError|JsonEncodeException */ public function getJsonDump() { @@ -428,7 +410,7 @@ class BasketSnapshot extends DbObject try { JsonString::encode($object); } catch (JsonEncodeException $singleError) { - $dump = var_export($object, 1); + $dump = var_export($object, true); if (function_exists('iconv')) { $dump = iconv('UTF-8', 'UTF-8//IGNORE', $dump); } @@ -486,6 +468,17 @@ class BasketSnapshot extends DbObject } /** + * @return ExportInterface|DbObject|null + */ + public static function instanceByUuid(string $typeName, UuidInterface $uuid, Db $connection) + { + /** @var class-string<DbObject> $class */ + $class = static::getClassForType($typeName); + /** @var ExportInterface $object */ + return $class::loadWithUniqueId($uuid, $connection); + } + + /** * @param $typeName * @param $identifier * @param Db $connection @@ -493,21 +486,17 @@ class BasketSnapshot extends DbObject */ public static function instanceByIdentifier($typeName, $identifier, Db $connection) { + /** @var class-string<DbObject> $class */ $class = static::getClassForType($typeName); - if (substr($class, -13) === 'IcingaService') { + if ($class === IcingaService::class) { $identifier = [ 'object_type' => 'template', 'object_name' => $identifier, ]; } - /** @var ExportInterface $object */ - if ($class::exists($identifier, $connection)) { - $object = $class::load($identifier, $connection); - } else { - $object = null; - } - return $object; + /** @var ExportInterface $object */ + return $class::loadOptional($identifier, $connection); } /** diff --git a/library/Director/DirectorObject/Automation/BasketSnapshotFieldResolver.php b/library/Director/DirectorObject/Automation/BasketSnapshotFieldResolver.php index 4653255..e565f77 100644 --- a/library/Director/DirectorObject/Automation/BasketSnapshotFieldResolver.php +++ b/library/Director/DirectorObject/Automation/BasketSnapshotFieldResolver.php @@ -4,7 +4,10 @@ namespace Icinga\Module\Director\DirectorObject\Automation; use Icinga\Module\Director\Db; use Icinga\Module\Director\Objects\DirectorDatafield; +use Icinga\Module\Director\Objects\DirectorDatalist; use Icinga\Module\Director\Objects\IcingaObject; +use InvalidArgumentException; +use stdClass; class BasketSnapshotFieldResolver { @@ -39,7 +42,7 @@ class BasketSnapshotFieldResolver * @return DirectorDatafield[] * @throws \Icinga\Exception\NotFoundError */ - public function loadCurrentFields(Db $db) + public function loadCurrentFields(Db $db): array { $fields = []; foreach ($this->getRequiredIds() as $id) { @@ -90,6 +93,11 @@ class BasketSnapshotFieldResolver $existingFields[(int) $mapping->datafield_id] = $mapping; } foreach ($object->fields as $field) { + if (! isset($fieldMap[(int) $field->datafield_id])) { + throw new InvalidArgumentException( + 'Basket Snapshot contains invalid field reference: ' . $field->datafield_id + ); + } $id = $fieldMap[(int) $field->datafield_id]; if (isset($existingFields[$id])) { unset($existingFields[$id]); @@ -114,6 +122,8 @@ class BasketSnapshotFieldResolver } /** + * For diff purposes only, gives '(UNKNOWN)' for fields missing in our DB + * * @param object $object * @throws \Icinga\Exception\NotFoundError */ @@ -127,21 +137,34 @@ class BasketSnapshotFieldResolver if (isset($map[$id])) { $field->datafield_id = $map[$id]; } else { - $field->datafield_id = "(NEW)"; + $field->datafield_id = "(UNKNOWN)"; } } } } - /** - * @return int - */ - protected function getNextNewId() + public static function fixOptionalDatalistReference(stdClass $plain, Db $db) + { + if (isset($plain->settings->datalist_uuid)) { + unset($plain->settings->datalist); + return; + } + if (isset($plain->settings->datalist)) { + // Just try to load the list, final import will fail if missing + // No modification in case we do not find the list, + if ($list = DirectorDatalist::loadOptional($plain->settings->datalist, $db)) { + unset($plain->settings->datalist); + $plain->settings->datalist_id = $list->get('id'); + } + } + } + + protected function getNextNewId(): int { return $this->nextNewId++; } - protected function getRequiredIds() + protected function getRequiredIds(): array { if ($this->requiredIds === null) { if (isset($this->objects['Datafield'])) { @@ -169,7 +192,7 @@ class BasketSnapshotFieldResolver * @param $type * @return object[] */ - protected function getObjectsByType($type) + protected function getObjectsByType($type): array { if (isset($this->objects->$type)) { return (array) $this->objects->$type; @@ -182,7 +205,7 @@ class BasketSnapshotFieldResolver * @return DirectorDatafield[] * @throws \Icinga\Exception\NotFoundError */ - protected function getTargetFields() + protected function getTargetFields(): array { if ($this->targetFields === null) { $this->calculateIdMap(); @@ -194,7 +217,7 @@ class BasketSnapshotFieldResolver /** * @throws \Icinga\Exception\NotFoundError */ - protected function getIdMap() + protected function getIdMap(): array { if ($this->idMap === null) { $this->calculateIdMap(); diff --git a/library/Director/DirectorObject/Automation/CompareBasketObject.php b/library/Director/DirectorObject/Automation/CompareBasketObject.php index ef2e9e2..f1ab6a9 100644 --- a/library/Director/DirectorObject/Automation/CompareBasketObject.php +++ b/library/Director/DirectorObject/Automation/CompareBasketObject.php @@ -31,7 +31,7 @@ class CompareBasketObject static::normalize($v); } unset($v); - $value = $sorted; + $value = (object) $sorted; // foreign baskets might not sort those lists correctly: if (isset($value->list_name) && isset($value->entries)) { @@ -46,7 +46,11 @@ class CompareBasketObject protected static function sortListBy($key, &$list) { usort($list, function ($a, $b) use ($key) { - return $a->$key > $b->$key ? -1 : 1; + if (is_array($a)) { + return $a[$key] > $b[$key] ? -1 : 1; + } else { + return $a->$key > $b->$key ? -1 : 1; + } }); } diff --git a/library/Director/DirectorObject/Automation/ExportInterface.php b/library/Director/DirectorObject/Automation/ExportInterface.php index 275dfed..271824f 100644 --- a/library/Director/DirectorObject/Automation/ExportInterface.php +++ b/library/Director/DirectorObject/Automation/ExportInterface.php @@ -2,18 +2,8 @@ namespace Icinga\Module\Director\DirectorObject\Automation; -use Icinga\Module\Director\Db; - interface ExportInterface { - /** - * @deprecated - * @return \stdClass - */ - public function export(); - - public static function import($plain, Db $db, $replace = false); - // TODO: // public function getXyzChecksum(); public function getUniqueIdentifier(); diff --git a/library/Director/DirectorObject/Automation/ImportExport.php b/library/Director/DirectorObject/Automation/ImportExport.php index a5e72fa..1664f5d 100644 --- a/library/Director/DirectorObject/Automation/ImportExport.php +++ b/library/Director/DirectorObject/Automation/ImportExport.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\DirectorObject\Automation; use Icinga\Module\Director\Data\Exporter; +use Icinga\Module\Director\Data\ObjectImporter; use Icinga\Module\Director\Db; use Icinga\Module\Director\Objects\DirectorDatafield; use Icinga\Module\Director\Objects\DirectorDatalist; @@ -125,8 +126,9 @@ class ImportExport { $count = 0; $this->connection->runFailSafeTransaction(function () use ($objects, &$count) { + $importer = new ObjectImporter($this->connection); foreach ($objects as $object) { - ImportSource::import($object, $this->connection)->store(); + $importer->import(ImportSource::class, $object)->store(); $count++; } }); @@ -138,8 +140,9 @@ class ImportExport { $count = 0; $this->connection->runFailSafeTransaction(function () use ($objects, &$count) { + $importer = new ObjectImporter($this->connection); foreach ($objects as $object) { - SyncRule::import($object, $this->connection)->store(); + $importer->import(SyncRule::class, $object)->store(); } $count++; }); diff --git a/library/Director/DirectorObject/Lookup/ServiceFinder.php b/library/Director/DirectorObject/Lookup/ServiceFinder.php index fb8d74c..a14d853 100644 --- a/library/Director/DirectorObject/Lookup/ServiceFinder.php +++ b/library/Director/DirectorObject/Lookup/ServiceFinder.php @@ -4,6 +4,8 @@ namespace Icinga\Module\Director\DirectorObject\Lookup; use gipfl\IcingaWeb2\Url; use Icinga\Authentication\Auth; +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Integration\MonitoringModule\Monitoring; use Icinga\Module\Director\Objects\HostApplyMatches; use Icinga\Module\Director\Objects\IcingaHost; use RuntimeException; @@ -49,31 +51,4 @@ class ServiceFinder return false; } - - /** - * @param $serviceName - * @return Url - */ - public function getRedirectionUrl($serviceName) - { - if ($this->auth === null) { - throw new RuntimeException('Auth is required for ServiceFinder when dealing when asking for URLs'); - } - if ($this->auth->hasPermission('director/host')) { - if ($info = $this::find($this->host, $serviceName)) { - return $info->getUrl(); - } - } - if ($this->auth->hasPermission('director/monitoring/services-ro')) { - return Url::fromPath('director/host/servicesro', [ - 'name' => $this->host->getObjectName(), - 'service' => $serviceName - ]); - } - - return Url::fromPath('director/host/invalidservice', [ - 'name' => $this->host->getObjectName(), - 'service' => $serviceName, - ]); - } } diff --git a/library/Director/DirectorObject/ObjectPurgeHelper.php b/library/Director/DirectorObject/ObjectPurgeHelper.php index a043965..5e50727 100644 --- a/library/Director/DirectorObject/ObjectPurgeHelper.php +++ b/library/Director/DirectorObject/ObjectPurgeHelper.php @@ -44,11 +44,11 @@ class ObjectPurgeHelper // TODO: this is object-specific and to be found in the ::import() function! unset($properties['fields']); $object = $class::fromPlainObject($properties); - } elseif (\get_class($object) !== $class) { + } elseif (get_class($object) !== $class) { throw new InvalidArgumentException( 'Can keep only matching objects, expected "%s", got "%s', $class, - \get_class($keep) + get_class($object) ); } $key = []; diff --git a/library/Director/Field/FormFieldSuggestion.php b/library/Director/Field/FormFieldSuggestion.php new file mode 100644 index 0000000..2f7f875 --- /dev/null +++ b/library/Director/Field/FormFieldSuggestion.php @@ -0,0 +1,167 @@ +<?php + +namespace Icinga\Module\Director\Field; + +use gipfl\Translation\TranslationHelper; +use Icinga\Module\Director\Objects\IcingaCommand; + +class FormFieldSuggestion +{ + use TranslationHelper; + + /** + * Macro/Argument names used in command argument values + * + * @var array + */ + protected $argumentVars = []; + protected $suggestedFields = []; + protected $blacklistedVars = []; + protected $descriptions = []; + protected $booleans = []; + + /** @var ?IcingaCommand */ + protected $command; + + /** @var array */ + protected $existingFields; + + protected $fields = null; + + public function __construct( + ?IcingaCommand $command, + array $existingFields + ) { + $this->command = $command; + $this->existingFields = $existingFields; + } + + public function getCommandFields(): array + { + if ($this->fields === null) { + $this->fields = $this->prepareFields(); + } + + return $this->fields; + } + + protected function prepareFields(): array + { + // TODO: remove assigned ones! + + foreach ($this->existingFields as $id => $field) { + if (preg_match('/ \(([^)]+)\)$/', $field, $m)) { + $this->blacklistedVars['$' . $m[1] . '$'] = $id; + } + } + + if ($this->command) { + foreach ($this->command->arguments() as $arg) { + if ($arg->argument_format === 'string') { + foreach (self::extractMacroNamesFromString($arg->argument_value) as $val) { + $this->addSuggestion($val, $arg->description, $this->argumentVars); + } + } + + if (($arg->set_if_format === 'string' || $arg->set_if_format === null) + && $val = self::getMacroIfStringIsSingleMacro($arg->set_if) + ) { + $this->addSuggestion($val, $arg->description, $this->booleans); + } + } + } + + asort($this->suggestedFields, SORT_NATURAL | SORT_FLAG_CASE); + ksort($this->argumentVars); + ksort($this->booleans); + asort($this->existingFields, SORT_NATURAL | SORT_FLAG_CASE); + + // Prepare combined fields array + $fields = []; + if (! empty($this->suggestedFields)) { + $fields[$this->translate('Suggested fields')] = $this->suggestedFields; + } + + if (! empty($this->argumentVars)) { + $fields[$this->translate('Argument macros')] = $this->argumentVars; + } + + if (! empty($this->booleans)) { + $fields[$this->translate('Toggles (boolean arguments)')] = $this->booleans; + } + + if (! empty($this->existingFields)) { + $fields[$this->translate('Other available fields')] = $this->existingFields; + } + + return $fields; + } + + public function getDescription($id) + { + if (array_key_exists($id, $this->descriptions)) { + return $this->descriptions[$id]; + } + + return null; + } + + public function isBoolean(string $macro): bool + { + return isset($this->booleans[$macro]); + } + + protected function addSuggestion( + string $val, + ?string $description, + array &$targetList + ) { + if (array_key_exists($val, $this->blacklistedVars)) { + $id = $this->blacklistedVars[$val]; + + // Hint: if not set it might already have been + // removed in this loop + if (array_key_exists($id, $this->existingFields)) { + $this->suggestedFields[$id] = $this->existingFields[$id]; + unset($this->existingFields[$id]); + } + } else { + $targetList[$val] = $val; + $this->descriptions[$val] = $description; + } + } + + /** + * Returns a macro name string ($macro_name$), if the given string is such, null otherwise + * + * @param ?string $string + * @return ?string + */ + protected static function getMacroIfStringIsSingleMacro(?string $string): ?string + { + if ($string === null) { + return null; + } + + if (preg_match('/^(\$[a-z0-9_]+\$)$/i', $string, $matches)) { + return $matches[1]; + } + + return null; + } + + /** + * Extracts all macro names ($macro_name$) from a given string + * + * @param ?string $string + * @return array + */ + protected static function extractMacroNamesFromString(?string $string): array + { + if ($string !== null && preg_match_all('/(\$[a-z0-9_]+\$)/i', $string, $matches, PREG_PATTERN_ORDER)) { + return $matches[1]; + } + + return []; + } +} diff --git a/library/Director/Filter/CidrExpression.php b/library/Director/Filter/CidrExpression.php new file mode 100644 index 0000000..169ddce --- /dev/null +++ b/library/Director/Filter/CidrExpression.php @@ -0,0 +1,89 @@ +<?php + +namespace Icinga\Module\Director\Filter; + +use Icinga\Data\Filter\FilterExpression; +use InvalidArgumentException; + +use function array_map; +use function filter_var; +use function inet_pton; +use function pack; +use function preg_match; +use function str_pad; +use function str_split; + +class CidrExpression extends FilterExpression +{ + protected $networkAddress; + protected $broadcastAddress; + + public function __construct($column, $sign, $expression) + { + if ($parts = static::splitOptionalCidrString($expression)) { + list($this->networkAddress, $this->broadcastAddress) = $parts; + } else { + throw new InvalidArgumentException("'$expression' isn't valid CIDR notation"); + } + + parent::__construct($column, $sign, $expression); + } + + public static function isCidrFormat(string $string): bool + { + return static::splitOptionalCidrString($string) !== null; + } + + protected static function splitOptionalCidrString(string $string): ?array + { + if (preg_match('#^(.+?)/(\d{1,3})$#', $string, $match)) { + $address = $match[1]; + $mask = (int) $match[2]; + + if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && $mask <= 32) { + $bits = 32; + } elseif (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && $mask <= 128) { + $bits = 128; + } else { + return null; + } + + $binaryAddress = inet_pton($address); + $broadcast = $binaryAddress | static::bitmaskToInverseBinaryMask($mask, $bits); + + return [$binaryAddress, $broadcast]; + } + + return null; + } + + public function matches($row): bool + { + if (! isset($row->{$this->column})) { + return false; + } + $value = inet_pton((string) $row->{$this->column}); + + return $value >= $this->networkAddress && $value <= $this->broadcastAddress; + } + + public static function fromExpression(FilterExpression $filter): CidrExpression + { + $sign = $filter->getSign(); + if ($sign !== '=') { + throw new InvalidArgumentException("'$sign' cannot be applied to CIDR notation"); + } + return new CidrExpression($filter->getColumn(), $sign, $filter->getExpression()); + } + + protected static function bitmaskToInverseBinaryMask($mask, $maxLen): string + { + $binary = str_pad(str_pad('', $mask, '0'), $maxLen, '1'); + $address = ''; + foreach (array_map('bindec', str_split($binary, 8)) as $char) { + $address .= pack('C*', $char); + } + + return $address; + } +} diff --git a/library/Director/Filter/FilterEnrichment.php b/library/Director/Filter/FilterEnrichment.php new file mode 100644 index 0000000..c726f76 --- /dev/null +++ b/library/Director/Filter/FilterEnrichment.php @@ -0,0 +1,29 @@ +<?php + +namespace Icinga\Module\Director\Filter; + +use Icinga\Data\Filter\Filter; +use Icinga\Data\Filter\FilterChain; +use Icinga\Data\Filter\FilterExpression; + +class FilterEnrichment +{ + public static function enrichFilter(Filter $filter): Filter + { + if ($filter instanceof FilterExpression) { + if (CidrExpression::isCidrFormat($filter->getExpression())) { + return CidrExpression::fromExpression($filter); + } + } elseif ($filter instanceof FilterChain) { + foreach ($filter->filters() as $subFilter) { + if ($subFilter instanceof FilterExpression + && CidrExpression::isCidrFormat($subFilter->getExpression()) + ) { + $filter->replaceById($subFilter->getId(), CidrExpression::fromExpression($subFilter)); + } + } + } + + return $filter; + } +} diff --git a/library/Director/Hook/BranchSupportHook.php b/library/Director/Hook/BranchSupportHook.php index 6615cbe..72ce096 100644 --- a/library/Director/Hook/BranchSupportHook.php +++ b/library/Director/Hook/BranchSupportHook.php @@ -14,7 +14,7 @@ abstract class BranchSupportHook { /** * @param Request $request - * @param BranchSTore $store + * @param BranchStore $store * @param Auth $auth * @return Branch */ diff --git a/library/Director/IcingaConfig/AgentWizard.php b/library/Director/IcingaConfig/AgentWizard.php index aceddb1..93527f5 100644 --- a/library/Director/IcingaConfig/AgentWizard.php +++ b/library/Director/IcingaConfig/AgentWizard.php @@ -148,15 +148,34 @@ class AgentWizard public function renderIcinga4WindowsWizardCommand($token) { - $script = "Use-Icinga;\n" - . 'Start-IcingaAgentInstallWizard `' . "\n " + $ifwParams = [ + "IfW-DirectorSelfServiceKey" => [ + "Values" => [$token], + ], + "IfW-DirectorUrl" => [ + "Values" => [$this->getDirectorUrl()], + ], + "IfW-StableRepository" => [ + "Values" => ["https://packages.icinga.com/IcingaForWindows/stable"], + ] + ]; + + $script = "[Net.ServicePointManager]::SecurityProtocol = 'tls12, tls11';\n" + . "\$ProgressPreference = 'SilentlyContinue';" . "\n" + . "[string]\$ScriptFile = 'C:\Users\Public\IcingaForWindows.ps1';\n" + . "\n" + . "Invoke-WebRequest `\n " . $this->renderPowershellParameters([ - 'DirectorUrl' => $this->getDirectorUrl(), - 'SelfServiceAPIKey' => $token, - 'UseDirectorSelfService' => 1, - 'OverrideDirectorVars' => 0, - 'Reconfigure', - 'RunInstaller' + 'UseBasicParsing', + 'Uri' => "https://packages.icinga.com/IcingaForWindows/IcingaForWindows.ps1", + 'OutFile' => '$ScriptFile;', + ]) . "\n" + . "\n" + . "& \$ScriptFile `\n " + . $this->renderPowershellParameters([ + 'ModuleDirectory' => "C:\Program Files\WindowsPowerShell\Modules\\", + 'InstallCommand' => json_encode($ifwParams, JSON_UNESCAPED_SLASHES), + 'IcingaRepository' => "https://packages.icinga.com/IcingaForWindows/stable/ifw.repo.json" ]); return $script; @@ -235,6 +254,8 @@ class AgentWizard $ret .= implode(', ', $vals); } elseif (is_int($value)) { $ret .= $value; + } elseif (is_string($value) && $value[0] === '$') { + $ret .= $value; } else { $ret .= $this->renderPowershellString($value); } @@ -297,7 +318,7 @@ class AgentWizard } else { $value = escapeshellarg($value); } - $script = preg_replace("~^#?$quotedKey='@$quotedKey@'$~m", "${key}=${value}", $script); + $script = preg_replace("~^#?$quotedKey='@$quotedKey@'$~m", "{$key}={$value}", $script); } return $script; diff --git a/library/Director/IcingaConfig/AssignRenderer.php b/library/Director/IcingaConfig/AssignRenderer.php index 6acbfee..495ad1e 100644 --- a/library/Director/IcingaConfig/AssignRenderer.php +++ b/library/Director/IcingaConfig/AssignRenderer.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\IcingaConfig; +use gipfl\Json\JsonDecodeException; use gipfl\Json\JsonString; use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\FilterAnd; @@ -128,8 +129,14 @@ class AssignRenderer } $column = $filter->getColumn(); - $rawExpression = Json::decode($filter->getExpression()); - $expression = $this->renderExpressionValue($rawExpression); + try { + $rawExpression = JsonString::decode($filter->getExpression()); + $expression = $this->renderExpressionValue($rawExpression); + } catch (JsonDecodeException $e) { + throw new InvalidArgumentException( + "Got invalid JSON in filter string: $column" . $filter->getSign() . $filter->getExpression() + ); + } if (is_array($rawExpression) && $filter instanceof FilterMatch) { return $this->renderInArray($column, $expression); diff --git a/library/Director/IcingaConfig/ExtensibleSet.php b/library/Director/IcingaConfig/ExtensibleSet.php index 9120816..d52a30e 100644 --- a/library/Director/IcingaConfig/ExtensibleSet.php +++ b/library/Director/IcingaConfig/ExtensibleSet.php @@ -50,7 +50,7 @@ class ExtensibleSet $set->object = $object; $set->propertyName = $propertyName; - if ($object->hasBeenLoadedFromDb()) { + if ($object->hasBeenLoadedFromDb() && $id = $object->get('id')) { $set->loadFromDb(); } diff --git a/library/Director/IcingaConfig/IcingaConfig.php b/library/Director/IcingaConfig/IcingaConfig.php index 72edd7e..a79bf3c 100644 --- a/library/Director/IcingaConfig/IcingaConfig.php +++ b/library/Director/IcingaConfig/IcingaConfig.php @@ -25,6 +25,9 @@ class IcingaConfig protected $zoneMap = array(); + /** @var ?array Exists for caching reasons at rendering time */ + protected $nonGlobalZones = null; + protected $lastActivityChecksum; /** @var \Zend_Db_Adapter_Abstract */ @@ -349,6 +352,15 @@ class IcingaConfig return $this->zoneMap[$id]; } + public function listNonGlobalZones(): array + { + if ($this->nonGlobalZones === null) { + $this->nonGlobalZones = array_values($this->connection->enumNonglobalZones()); + } + + return $this->nonGlobalZones; + } + /** * @return self */ @@ -436,9 +448,9 @@ class IcingaConfig $start = microtime(true); MemoryLimit::raiseTo('1024M'); - ini_set('max_execution_time', 0); + ini_set('max_execution_time', '0'); // Workaround for https://bugs.php.net/bug.php?id=68606 or similar - ini_set('zend.enable_gc', 0); + ini_set('zend.enable_gc', '0'); if (! $this->connection->isPgsql() && $this->db->quote("1\0") !== '\'1\\0\'') { throw new RuntimeException( @@ -501,6 +513,7 @@ class IcingaConfig "\nconst DirectorStageDir = dirname(dirname(current_filename))\n" . $this->renderFlappingLogHelper() . $this->renderHostOverridableVars() + . $this->renderIfwFallbackTemplate() ); return $this; @@ -566,6 +579,20 @@ if (! globals.contains(DirectorOverrideTemplate)) { ); } + + protected function renderIfwFallbackTemplate(): string + { + return ' +// Make sure config validates for Icinga < 2.14 with IfW 1.11 configuration. This might look weird, +// but is intentional. get_object() does\'t work as expected at parse time. +if (! globals.System || ! System.get_template || ! get_template(CheckCommand, "ifw-api-check-command")) { + object CheckCommand "ifw-api" { + import "plugin-check-command" + } +} +'; + } + /** * @param string $checksum * diff --git a/library/Director/IcingaConfig/IcingaConfigHelper.php b/library/Director/IcingaConfig/IcingaConfigHelper.php index 03c017e..634337f 100644 --- a/library/Director/IcingaConfig/IcingaConfigHelper.php +++ b/library/Director/IcingaConfig/IcingaConfigHelper.php @@ -177,7 +177,7 @@ class IcingaConfigHelper throw new InvalidArgumentException(sprintf( 'Unexpected type %s', - var_export($value, 1) + var_export($value, true) )); } diff --git a/library/Director/Import/ImportSourceCoreApi.php b/library/Director/Import/ImportSourceCoreApi.php index 6d590ec..3c54d48 100644 --- a/library/Director/Import/ImportSourceCoreApi.php +++ b/library/Director/Import/ImportSourceCoreApi.php @@ -30,7 +30,7 @@ class ImportSourceCoreApi extends ImportSourceHook public function listColumns() { $res = $this->fetchData(); - if (empty($data)) { + if (empty($res)) { return array('object_name'); } diff --git a/library/Director/Import/ImportSourceLdap.php b/library/Director/Import/ImportSourceLdap.php index 4518565..559669d 100644 --- a/library/Director/Import/ImportSourceLdap.php +++ b/library/Director/Import/ImportSourceLdap.php @@ -45,7 +45,7 @@ class ImportSourceLdap extends ImportSourceHook public static function addSettingsFormFields(QuickForm $form) { - Util::addLDAPResourceFormElement($form, 'resource'); + Util::addLdapResourceFormElement($form, 'resource'); $form->addElement('text', 'base', array( 'label' => $form->translate('LDAP Search Base'), 'description' => $form->translate( diff --git a/library/Director/Import/ImportSourceRestApi.php b/library/Director/Import/ImportSourceRestApi.php index dc772e1..45f7351 100644 --- a/library/Director/Import/ImportSourceRestApi.php +++ b/library/Director/Import/ImportSourceRestApi.php @@ -69,6 +69,7 @@ class ImportSourceRestApi extends ImportSourceHook $data = $result; foreach ($parts as $part) { // un-escape any dots + /** @var string $part */ $part = preg_replace('~\\\\.~', '.', $part); if (property_exists($data, $part)) { diff --git a/library/Director/Import/Sync.php b/library/Director/Import/Sync.php index 8fea46c..2957433 100644 --- a/library/Director/Import/Sync.php +++ b/library/Director/Import/Sync.php @@ -16,6 +16,7 @@ use Icinga\Module\Director\Objects\HostGroupMembershipResolver; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaHostGroup; use Icinga\Module\Director\Objects\IcingaObject; +use Icinga\Module\Director\Objects\IcingaObjectGroup; use Icinga\Module\Director\Objects\ImportSource; use Icinga\Module\Director\Objects\IcingaService; use Icinga\Module\Director\Objects\SyncProperty; @@ -49,6 +50,9 @@ class Sync /** @var array<mixed, array<int, string>> key => [property, property]*/ protected $setNull = []; + /** @var array<mixed, array<string, mixed>> key => [propertyName, newValue]*/ + protected $newProperties = []; + /** @var bool Whether we already prepared your sync */ protected $isPrepared = false; @@ -88,6 +92,12 @@ class Sync /** @var ?DbObjectStore */ protected $store; + /** @var IcingaObjectGroup[] */ + protected $modifiedGroups = []; + + /** @var IcingaObject[] */ + protected $modifiedGroupObjects = []; + /** * @param SyncRule $rule * @param ?DbObjectStore $store @@ -137,24 +147,6 @@ class Sync } /** - * Transform the given value to an array - * - * @param array|string|null $value - * - * @return array - */ - protected function wantArray($value) - { - if (is_array($value)) { - return $value; - } elseif ($value === null) { - return []; - } else { - return [$value]; - } - } - - /** * Raise PHP resource limits * * @return self; @@ -162,7 +154,7 @@ class Sync protected function raiseLimits() { MemoryLimit::raiseTo('1024M'); - ini_set('max_execution_time', 0); + ini_set('max_execution_time', '0'); return $this; } @@ -452,7 +444,28 @@ class Sync if ($this->store) { $objects = $this->store->loadAll(DbObjectTypeRegistry::tableNameByType($ruleObjectType), 'object_name'); } else { - $objects = IcingaObject::loadAllByType($ruleObjectType, $this->db); + $keyColumn = null; + $query = null; + // We enforce named index for combined-key templates (Services and Sets) and applied Sets + if ($ruleObjectType === 'service' || $ruleObjectType === 'serviceSet') { + foreach ($this->syncProperties as $prop) { + $configuredObjectType = $prop->get('source_expression'); + if ($prop->get('destination_field') === 'object_type' + && ( + $configuredObjectType === 'template' + || ($configuredObjectType === 'apply' && $ruleObjectType === 'serviceSet') + ) + ) { + $keyColumn = 'object_name'; + $table = $ruleObjectType === 'service' + ? BranchSupport::TABLE_ICINGA_SERVICE + : BranchSupport::TABLE_ICINGA_SERVICE_SET; + $query = $this->db->getDbAdapter()->select() + ->from($table)->where('object_type = ?', $configuredObjectType); + } + } + } + $objects = IcingaObject::loadAllByType($ruleObjectType, $this->db, $query, $keyColumn); } if ($useLowerCaseKeys) { @@ -532,6 +545,15 @@ class Sync */ protected function prepareNewObject($row, DbObject $object, $objectKey, $sourceId) { + if (!isset($this->newProperties[$objectKey])) { + $this->newProperties[$objectKey] = []; + } + // TODO: some more improvements are possible here. First, no need to instantiate + // all new objects, we could stick with the newProperties array. Next, we + // should be more correct when respecting sync property order. Right now, + // a property from another Import Source might win, even if property order + // tells something different. This is a very rare case, but still incorrect. + $properties = &$this->newProperties[$objectKey]; foreach ($this->syncProperties as $propertyKey => $p) { if ($p->get('source_id') !== $sourceId) { continue; @@ -557,38 +579,35 @@ class Sync $varName = substr($prop, 5); if (substr($varName, -2) === '[]') { $varName = substr($varName, 0, -2); - $current = $this->wantArray($object->vars()->$varName); $object->vars()->$varName = array_merge( - $current, - $this->wantArray($val) + (array) ($object->vars()->$varName), + (array) $val ); } else { - if ($val === null) { - $this->setNull[$objectKey][$prop] = $prop; - } else { - unset($this->setNull[$objectKey][$prop]); - $object->vars()->$varName = $val; - } + $this->setPropertyWithNullLogic($object, $objectKey, $prop, $val, $properties); } } else { - if ($val === null) { - $this->setNull[$objectKey][$prop] = $prop; - } else { - unset($this->setNull[$objectKey][$prop]); - $object->set($prop, $val); - } + $this->setPropertyWithNullLogic($object, $objectKey, $prop, $val, $properties); } } else { - if ($val === null) { - $this->setNull[$objectKey][$prop] = $prop; - } else { - unset($this->setNull[$objectKey][$prop]); - $object->set($prop, $val); - } + $this->setPropertyWithNullLogic($object, $objectKey, $prop, $val, $properties); } } } + protected function setPropertyWithNullLogic(DbObject $object, $objectKey, $property, $value, &$allProps) + { + if ($value === null) { + if (! array_key_exists($property, $allProps) || $allProps[$property] === null) { + $this->setNull[$objectKey][$property] = $property; + } + } else { + unset($this->setNull[$objectKey][$property]); + $object->set($property, $value); + } + $allProps[$property] = $value; + } + /** * @return $this */ @@ -625,6 +644,9 @@ class Sync protected function notifyResolvers() { if ($resolver = $this->getHostGroupMembershipResolver()) { + if ($this->rule->get('object_type') === 'hostgroup') { + $resolver->setGroups($this->modifiedGroups); + } $resolver->refreshDb(true); } @@ -748,6 +770,13 @@ class Sync } } + protected function optionallyTellResolverAboutModifiedGroup(IcingaObjectGroup $group) + { + if (in_array('assign_filter', $group->getModifiedProperties())) { + $this->modifiedGroups[] = $group; + } + } + /** * @param $key * @param DbObject|IcingaObject $object @@ -791,7 +820,11 @@ class Sync } } - if (isset($this->setNull[$key])) { + // Hint: in theory, NULL should be set on new objects, but this has no effect + // anyway, and we also do not store vars.something = null, this would + // instead delete the variable. So here we do not need to check for new + // objects, and skip all null values with update policy = 'ignore' + if ($policy !== 'ignore' && isset($this->setNull[$key])) { foreach ($this->setNull[$key] as $property) { $this->objects[$key]->set($property, null); } @@ -850,6 +883,9 @@ class Sync } if ($object->hasBeenModified()) { + if ($object instanceof IcingaObjectGroup) { + $this->optionallyTellResolverAboutModifiedGroup($object); + } $existing = $object->hasBeenLoadedFromDb(); if ($existing) { if ($this->store) { diff --git a/library/Director/Import/SyncUtils.php b/library/Director/Import/SyncUtils.php index 5528b2d..c106c20 100644 --- a/library/Director/Import/SyncUtils.php +++ b/library/Director/Import/SyncUtils.php @@ -99,7 +99,7 @@ class SyncUtils throw new InvalidArgumentException(sprintf( 'Data is not nested, cannot access %s: %s', $var, - var_export($row, 1) + var_export($row, true) )); } diff --git a/library/Director/Integration/BackendInterface.php b/library/Director/Integration/BackendInterface.php new file mode 100644 index 0000000..7b2b88c --- /dev/null +++ b/library/Director/Integration/BackendInterface.php @@ -0,0 +1,55 @@ +<?php + +namespace Icinga\Module\Director\Integration; + +use Icinga\Web\Url; + +interface BackendInterface +{ + /** + * Whether the backend has the given host + * + * @param ?string $hostName + * + * @return bool + */ + public function hasHost(?string $hostName): bool; + + /** + * Whether the backend has the given service of the specified host + * + * @param ?string $hostName + * @param ?string $serviceName + * + * @return bool + */ + public function hasService(?string $hostName, ?string $serviceName): bool; + + /** + * Whether an authenticated user has the permission (is not restricted) to modify given host + * + * @param ?string $hostName + * + * @return bool + */ + public function canModifyHost(?string $hostName): bool; + + /** + * Whether an authenticated user has the permission (is not restricted) to modify given service of specified host + * + * @param ?string $hostName + * @param ?string $serviceName + * + * @return bool + */ + public function canModifyService(?string $hostName, ?string $serviceName): bool; + + /** + * Get the url of given host + * + * @param ?string $hostName + * + * @return Url + */ + public function getHostUrl(?string $hostName): ?Url; +} diff --git a/library/Director/Integration/Icingadb/IcingadbBackend.php b/library/Director/Integration/Icingadb/IcingadbBackend.php new file mode 100644 index 0000000..874cddd --- /dev/null +++ b/library/Director/Integration/Icingadb/IcingadbBackend.php @@ -0,0 +1,127 @@ +<?php + +namespace Icinga\Module\Director\Integration\Icingadb; + +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Auth\Restriction; +use Icinga\Module\Director\Integration\BackendInterface; +use Icinga\Module\Icingadb\Common\Auth; +use Icinga\Module\Icingadb\Common\Database; +use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Model\Service; +use Icinga\Web\Url; +use ipl\Orm\Query; +use ipl\Stdlib\Filter; + +class IcingadbBackend implements BackendInterface +{ + use Database; + use Auth; + + public function hasHost(?string $hostName): bool + { + if ($hostName === null) { + return false; + } + + return $this->getHostQuery($hostName)->first() !== null; + } + + public function hasService(?string $hostName, ?string $serviceName): bool + { + if ($hostName === null || $serviceName === null) { + return false; + } + + return $this->getServiceQuery($hostName, $serviceName)->first() !== null; + } + + public function getHostUrl(?string $hostName): ?Url + { + if ($hostName === null) { + return null; + } + + return Url::fromPath('icingadb/host', ['name' => $hostName]); + } + + public function canModifyHost(?string $hostName): bool + { + if ($hostName === null + || ! $this->getAuth()->hasPermission(Permission::ICINGADB_HOSTS) + ) { + return false; + } + + $query = $this->getHostQuery($hostName); + + return $query->first() !== null; + } + + public function canModifyService(?string $hostName, ?string $serviceName): bool + { + if ($hostName === null + || $serviceName === null + || ! $this->getAuth()->hasPermission(Permission::ICINGADB_SERVICES) + ) { + return false; + } + + $query = $this->getServiceQuery($hostName, $serviceName); + + return $query->first() !== null; + } + + /** + * Get the query for given host + * + * @param string $hostName + * + * @return Query + */ + protected function getHostQuery(string $hostName): Query + { + $query = Host::on($this->getDb()) + ->filter(Filter::equal('host.name', $hostName)); + + $this->applyDirectorRestrictions($query); + + return $query; + } + + /** + * Get the query for given host and service + * + * @param string $hostName + * @param string $serviceName + * + * @return Query + */ + protected function getServiceQuery(string $hostName, string $serviceName): Query + { + $query = Service::on($this->getDb()) + ->filter(Filter::all( + Filter::equal('service.name', $serviceName), + Filter::equal('host.name', $hostName) + )); + + $this->applyDirectorRestrictions($query); + + return $query; + } + + /** + * Apply director restrictions on the given query + * + * @param Query $query + */ + protected function applyDirectorRestrictions(Query $query): void + { + $queryFilter = Filter::any(); + foreach ($this->getAuth()->getRestrictions(Restriction::ICINGADB_RW_OBJECT_FILTER) as $restriction) { + $queryFilter->add($this->parseRestriction($restriction, Restriction::ICINGADB_RW_OBJECT_FILTER)); + } + + $query->filter($queryFilter); + } +} diff --git a/library/Director/Integration/MonitoringModule/Monitoring.php b/library/Director/Integration/MonitoringModule/Monitoring.php new file mode 100644 index 0000000..5a2dfde --- /dev/null +++ b/library/Director/Integration/MonitoringModule/Monitoring.php @@ -0,0 +1,200 @@ +<?php + +namespace Icinga\Module\Director\Integration\MonitoringModule; + +use Exception; +use Icinga\Application\Icinga; +use Icinga\Authentication\Auth; +use Icinga\Data\Filter\Filter; +use Icinga\Exception\ConfigurationError; +use Icinga\Module\Director\Auth\MonitoringRestriction; +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Auth\Restriction; +use Icinga\Module\Director\Integration\BackendInterface; +use Icinga\Module\Monitoring\Backend\MonitoringBackend; +use Icinga\Web\Url; + +class Monitoring implements BackendInterface +{ + /** @var ?MonitoringBackend */ + protected $backend; + + /** @var Auth */ + protected $auth; + + public function __construct(Auth $auth) + { + $this->auth = $auth; + $this->initializeMonitoringBackend(); + } + + public function getHostUrl(?string $hostName): ?Url + { + if ($hostName === null) { + return null; + } + + return Url::fromPath('monitoring/host/show', ['host' => $hostName]); + } + + public function hasHost(?string $hostName): bool + { + if ($hostName === null || ! $this->isAvailable()) { + return false; + } + + try { + return $this->selectHost($hostName)->fetchOne() === $hostName; + } catch (Exception $_) { + return false; + } + } + + public function hasService(?string $hostName, ?string $serviceName): bool + { + if ($hostName === null || $serviceName === null || ! $this->isAvailable()) { + return false; + } + + try { + return $this->rowIsService( + $this->selectService($hostName, $serviceName)->fetchRow(), + $hostName, + $serviceName + ); + } catch (Exception $_) { + return false; + } + } + + public function canModifyService(?string $hostName, ?string $serviceName): bool + { + if (! $this->isAvailable() || $hostName === null || $serviceName === null) { + return false; + } + if ($this->auth->hasPermission(Permission::MONITORING_SERVICES)) { + $restriction = null; + foreach ($this->auth->getRestrictions(Restriction::MONITORING_RW_OBJECT_FILTER) as $restriction) { + if ($this->hasServiceWithFilter($hostName, $serviceName, Filter::fromQueryString($restriction))) { + return true; + } + } + if ($restriction === null) { + return $this->hasService($hostName, $serviceName); + } + } + + return false; + } + + public function canModifyHost(?string $hostName): bool + { + if ($hostName !== null && $this->isAvailable() && $this->auth->hasPermission(Permission::MONITORING_HOSTS)) { + $restriction = null; + foreach ($this->auth->getRestrictions(Restriction::MONITORING_RW_OBJECT_FILTER) as $restriction) { + if ($this->hasHostWithFilter($hostName, Filter::fromQueryString($restriction))) { + return true; + } + } + if ($restriction === null) { + return $this->hasHost($hostName); + } + } + + return false; + } + + protected function hasHostWithFilter($hostname, Filter $filter): bool + { + try { + return $this->selectHost($hostname)->applyFilter($filter)->fetchOne() === $hostname; + } catch (Exception $e) { + return false; + } + } + + protected function hasServiceWithFilter($hostname, $service, Filter $filter): bool + { + try { + return $this->rowIsService( + $this->selectService($hostname, $service)->applyFilter($filter)->fetchRow(), + $hostname, + $service + ); + } catch (Exception $e) { + return false; + } + } + + protected function selectHost($hostname) + { + return $this->selectHostStatus($hostname, [ + 'hostname' => 'host_name', + ]); + } + + protected function selectHostStatus($hostname, $columns) + { + return $this->restrictQuery( + $this->backend + ->select() + ->from('hostStatus', $columns) + ->where('host_name', $hostname) + ); + } + + protected function selectService($hostname, $service) + { + return $this->selectServiceStatus($hostname, $service, [ + 'hostname' => 'host_name', + 'service' => 'service_description', + ]); + } + + protected function selectServiceStatus($hostname, $service, $columns) + { + return $this->restrictQuery( + $this->backend + ->select() + ->from('serviceStatus', $columns) + ->where('host_name', $hostname) + ->where('service_description', $service) + ); + } + + protected function restrictQuery($query) + { + $query->applyFilter(MonitoringRestriction::getObjectsFilter($this->auth)); + return $query; + } + + protected function rowIsService($row, $hostname, $service): bool + { + return (array) $row === [ + 'hostname' => $hostname, + 'service' => $service, + ]; + } + + protected function initializeMonitoringBackend() + { + $app = Icinga::app(); + $modules = $app->getModuleManager(); + if (!$modules->hasLoaded('monitoring') && $app->isCli()) { + $modules->loadEnabledModules(); + } + + if ($modules->hasLoaded('monitoring')) { + try { + $this->backend = MonitoringBackend::instance(); + } catch (ConfigurationError $e) { + $this->backend = null; + } + } + } + + protected function isAvailable(): bool + { + return $this->backend !== null; + } +} diff --git a/library/Director/Monitoring.php b/library/Director/Monitoring.php deleted file mode 100644 index f5d4108..0000000 --- a/library/Director/Monitoring.php +++ /dev/null @@ -1,149 +0,0 @@ -<?php - -namespace Icinga\Module\Director; - -use Icinga\Application\Icinga; -use Icinga\Authentication\Auth; -use Icinga\Data\Filter\Filter; -use Icinga\Module\Monitoring\Backend\MonitoringBackend; - -class Monitoring -{ - protected $backend; - - public function __construct() - { - $app = Icinga::app(); - $modules = $app->getModuleManager(); - if (!$modules->hasLoaded('monitoring') && $app->isCli()) { - $app->getModuleManager()->loadEnabledModules(); - } - - if ($modules->hasLoaded('monitoring')) { - $this->backend = MonitoringBackend::instance(); - } - } - - public function isAvailable() - { - return $this->backend !== null; - } - - public function hasHost($hostname) - { - return $this->backend->select()->from('hostStatus', [ - 'hostname' => 'host_name', - ])->where('host_name', $hostname)->fetchOne() === $hostname; - } - - public function hasService($hostname, $service) - { - return (array) $this->prepareServiceKeyColumnQuery($hostname, $service)->fetchRow() === [ - 'hostname' => $hostname, - 'service' => $service, - ]; - } - - public function authCanEditHost(Auth $auth, $hostname) - { - if ($auth->hasPermission('director/monitoring/hosts')) { - $restriction = null; - foreach ($auth->getRestrictions('director/monitoring/rw-object-filter') as $restriction) { - if ($this->hasHostWithExtraFilter($hostname, Filter::fromQueryString($restriction))) { - return true; - } - } - if ($restriction === null) { - return $this->hasHost($hostname); - } - } - - return false; - } - - public function authCanEditService(Auth $auth, $hostname, $service) - { - if ($hostname === null || $service === null) { - // TODO: UUID support! - return false; - } - if ($auth->hasPermission('director/monitoring/services')) { - $restriction = null; - foreach ($auth->getRestrictions('director/monitoring/rw-object-filter') as $restriction) { - if ($this->hasServiceWithExtraFilter($hostname, $service, Filter::fromQueryString($restriction))) { - return true; - } - } - if ($restriction === null) { - return $this->hasService($hostname, $service); - } - } - - return false; - } - - public function hasHostWithExtraFilter($hostname, Filter $filter) - { - return $this->backend->select()->from('hostStatus', [ - 'hostname' => 'host_name', - ])->where('host_name', $hostname)->applyFilter($filter)->fetchOne() === $hostname; - } - - public function hasServiceWithExtraFilter($hostname, $service, Filter $filter) - { - return (array) $this - ->prepareServiceKeyColumnQuery($hostname, $service) - ->applyFilter($filter) - ->fetchRow() === [ - 'hostname' => $hostname, - 'service' => $service, - ]; - } - - public function getHostState($hostname) - { - $hostStates = [ - '0' => 'up', - '1' => 'down', - '2' => 'unreachable', - '99' => 'pending', - ]; - - $query = $this->backend->select()->from('hostStatus', [ - 'hostname' => 'host_name', - 'state' => 'host_state', - 'problem' => 'host_problem', - 'acknowledged' => 'host_acknowledged', - 'in_downtime' => 'host_in_downtime', - 'output' => 'host_output', - ])->where('host_name', $hostname); - - $res = $query->fetchRow(); - if ($res === false) { - $res = (object) [ - 'hostname' => $hostname, - 'state' => '99', - 'problem' => '0', - 'acknowledged' => '0', - 'in_downtime' => '0', - 'output' => null, - ]; - } - - $res->state = $hostStates[$res->state]; - - return $res; - } - - protected function prepareServiceKeyColumnQuery($hostname, $service) - { - return $this->backend - ->select() - ->from('serviceStatus', [ - 'hostname' => 'host_name', - 'service' => 'service_description', - ]) - ->where('host_name', $hostname) - ->where('service_description', $service); - } -} diff --git a/library/Director/Objects/DirectorActivityLog.php b/library/Director/Objects/DirectorActivityLog.php index cb041b6..2cecc2e 100644 --- a/library/Director/Objects/DirectorActivityLog.php +++ b/library/Director/Objects/DirectorActivityLog.php @@ -7,6 +7,7 @@ use Icinga\Module\Director\Db; use Icinga\Authentication\Auth; use Icinga\Application\Icinga; use Icinga\Application\Logger; +use stdClass; class DirectorActivityLog extends DbObject { @@ -176,7 +177,19 @@ class DirectorActivityLog extends DbObject { $name = $object->getObjectName(); $type = $object->getTableName(); - $oldProps = json_encode($object->getPlainUnmodifiedObject()); + /** @var stdClass $plainUnmodifiedObject */ + $plainUnmodifiedObject = $object->getPlainUnmodifiedObject(); + + if ($object instanceof IcingaServiceSet) { + $services = []; + foreach ($object->getCachedServices() as $service) { + $services[$service->getObjectName()] = $service->toPlainObject(); + } + + $plainUnmodifiedObject->services = $services; + } + + $oldProps = json_encode($plainUnmodifiedObject); $data = [ 'object_name' => $name, diff --git a/library/Director/Objects/DirectorDatafield.php b/library/Director/Objects/DirectorDatafield.php index 84db068..ced6218 100644 --- a/library/Director/Objects/DirectorDatafield.php +++ b/library/Director/Objects/DirectorDatafield.php @@ -2,28 +2,30 @@ namespace Icinga\Module\Director\Objects; -use Icinga\Module\Director\Core\Json; use Icinga\Module\Director\Data\Db\DbObjectWithSettings; use Icinga\Module\Director\Db; +use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshotFieldResolver; use Icinga\Module\Director\DirectorObject\Automation\CompareBasketObject; -use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\Forms\IcingaServiceForm; use Icinga\Module\Director\Hook\DataTypeHook; use Icinga\Module\Director\Resolver\OverriddenVarsResolver; use Icinga\Module\Director\Web\Form\DirectorObjectForm; -use InvalidArgumentException; +use Ramsey\Uuid\Uuid; +use stdClass; use Zend_Form_Element as ZfElement; class DirectorDatafield extends DbObjectWithSettings { protected $table = 'director_datafield'; - protected $keyName = 'id'; - protected $autoincKeyName = 'id'; + protected $uuidColumn = 'uuid'; + protected $settingsTable = 'director_datafield_setting'; + protected $settingsRemoteId = 'datafield_id'; protected $defaultProperties = [ 'id' => null, + 'uuid' => null, 'category_id' => null, 'varname' => null, 'caption' => null, @@ -33,16 +35,11 @@ class DirectorDatafield extends DbObjectWithSettings ]; protected $relations = [ - 'category' => 'DirectorDatafieldCategory' + 'category' => 'DirectorDatafieldCategory' ]; - protected $settingsTable = 'director_datafield_setting'; - - protected $settingsRemoteId = 'datafield_id'; - - /** @var DirectorDatafieldCategory|null */ + /** @var ?DirectorDatafieldCategory */ private $category; - private $object; public static function fromDbRow($row, Db $connection) @@ -70,10 +67,9 @@ class DirectorDatafield extends DbObjectWithSettings } /** - * @return DirectorDatafieldCategory|null * @throws \Icinga\Exception\NotFoundError */ - public function getCategory() + public function getCategory(): ?DirectorDatafieldCategory { if ($this->category) { return $this->category; @@ -84,7 +80,7 @@ class DirectorDatafield extends DbObjectWithSettings } } - public function getCategoryName() + public function getCategoryName(): ?string { $category = $this->getCategory(); if ($category === null) { @@ -105,27 +101,26 @@ class DirectorDatafield extends DbObjectWithSettings } $this->category = $category; } else { - if (DirectorDatafieldCategory::exists($category, $this->getConnection())) { - $this->setCategory(DirectorDatafieldCategory::load($category, $this->getConnection())); + if ($category = DirectorDatafieldCategory::loadOptional($category, $this->getConnection())) { + $this->setCategory($category); } else { $this->setCategory(DirectorDatafieldCategory::create([ 'category_name' => $category ], $this->getConnection())); } } - - return $this; } /** - * @return object * @throws \Icinga\Exception\NotFoundError */ - public function export() + public function export(): stdClass { $plain = (object) $this->getProperties(); - $plain->originalId = $plain->id; unset($plain->id); + if ($uuid = $this->get('uuid')) { + $plain->uuid = Uuid::fromBytes($uuid)->toString(); + } $plain->settings = (object) $this->getSettings(); if (property_exists($plain->settings, 'datalist_id')) { @@ -144,63 +139,35 @@ class DirectorDatafield extends DbObjectWithSettings } /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return DirectorDatafield * @throws \Icinga\Exception\NotFoundError */ - public static function import($plain, Db $db, $replace = false) + public static function import(stdClass $plain, Db $db): DirectorDatafield { - $properties = (array) $plain; - if (isset($properties['originalId'])) { - $id = $properties['originalId']; - unset($properties['originalId']); - } else { - $id = null; - } - - if (isset($properties['settings']->datalist)) { - // Just try to load the list, import should fail if missing - $list = DirectorDatalist::load( - $properties['settings']->datalist, - $db - ); - } else { - $list = null; - } - - $compare = Json::decode(Json::encode($properties)); - if ($id && static::exists($id, $db)) { - $existing = static::loadWithAutoIncId($id, $db); - $existingProperties = (array) $existing->export(); - unset($existingProperties['originalId']); - if (CompareBasketObject::equals((object) $compare, (object) $existingProperties)) { - return $existing; + $dba = $db->getDbAdapter(); + if ($uuid = $plain->uuid ?? null) { + $uuid = Uuid::fromString($uuid); + if ($candidate = DirectorDatafield::loadWithUniqueId($uuid, $db)) { + BasketSnapshotFieldResolver::fixOptionalDatalistReference($plain, $db); + assert($candidate instanceof DirectorDatafield); + $candidate->setProperties((array) $plain); + return $candidate; } } - - if ($list) { - unset($properties['settings']->datalist); - $properties['settings']->datalist_id = $list->get('id'); - } - - $dba = $db->getDbAdapter(); - $query = $dba->select() - ->from('director_datafield') - ->where('varname = ?', $plain->varname); + $query = $dba->select()->from('director_datafield')->where('varname = ?', $plain->varname); $candidates = DirectorDatafield::loadAll($db, $query); foreach ($candidates as $candidate) { $export = $candidate->export(); - unset($export->originalId); CompareBasketObject::normalize($export); - if (CompareBasketObject::equals($export, $compare)) { + unset($export->uuid); + unset($plain->originalId); + if (CompareBasketObject::equals($export, $plain)) { return $candidate; } } + BasketSnapshotFieldResolver::fixOptionalDatalistReference($plain, $db); - return static::create($properties, $db); + return static::create((array) $plain, $db); } protected function beforeStore() @@ -223,7 +190,7 @@ class DirectorDatafield extends DbObjectWithSettings return $this->object; } - public function getFormElement(DirectorObjectForm $form, $name = null) + public function getFormElement(DirectorObjectForm $form, $name = null): ?ZfElement { $className = $this->get('datatype'); @@ -305,7 +272,7 @@ class DirectorDatafield extends DbObjectWithSettings } } - protected function eventuallyGetResolvedCommandVar(IcingaObject $object, $varName) + protected function eventuallyGetResolvedCommandVar(IcingaObject $object, $varName): ?array { if (! $object->hasRelation('check_command')) { return null; diff --git a/library/Director/Objects/DirectorDatalist.php b/library/Director/Objects/DirectorDatalist.php index ae5c983..1bb821b 100644 --- a/library/Director/Objects/DirectorDatalist.php +++ b/library/Director/Objects/DirectorDatalist.php @@ -4,68 +4,35 @@ namespace Icinga\Module\Director\Objects; use Exception; use Icinga\Module\Director\Data\Db\DbObject; -use Icinga\Module\Director\Db; +use Icinga\Module\Director\DataType\DataTypeDatalist; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; use Icinga\Module\Director\Exception\DuplicateKeyException; class DirectorDatalist extends DbObject implements ExportInterface { protected $table = 'director_datalist'; - protected $keyName = 'list_name'; - protected $autoincKeyName = 'id'; + protected $uuidColumn = 'uuid'; - protected $defaultProperties = array( + protected $defaultProperties = [ 'id' => null, + 'uuid' => null, 'list_name' => null, 'owner' => null - ); + ]; /** @var DirectorDatalistEntry[] */ - protected $storedEntries; + protected $entries; public function getUniqueIdentifier() { return $this->get('list_name'); } - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return static - * @throws \Icinga\Exception\NotFoundError - * @throws DuplicateKeyException - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - if (isset($properties['originalId'])) { - unset($properties['originalId']); - } else { - $id = null; - } - $name = $properties['list_name']; - - if ($replace && static::exists($name, $db)) { - $object = static::load($name, $db); - } elseif (static::exists($name, $db)) { - throw new DuplicateKeyException( - 'Data List %s already exists', - $name - ); - } else { - $object = static::create([], $db); - } - $object->setProperties($properties); - - return $object; - } - - public function setEntries($entries) + public function setEntries($entries): void { - $existing = $this->getStoredEntries(); + $existing = $this->getEntries(); $new = []; $seen = []; @@ -101,15 +68,13 @@ class DirectorDatalist extends DbObject implements ExportInterface $this->hasBeenModified = true; } - $this->storedEntries = $existing; - ksort($this->storedEntries); - - return $this; + $this->entries = $existing; + ksort($this->entries); } protected function beforeDelete() { - if ($this->hasBeenUsed()) { + if ($this->isInUse()) { throw new Exception( sprintf( "Cannot delete '%s', as the datalist '%s' is currently being used.", @@ -120,9 +85,13 @@ class DirectorDatalist extends DbObject implements ExportInterface } } - protected function hasBeenUsed() + protected function isInUse(): bool { - $datalistType = 'Icinga\\Module\\Director\\DataType\\DataTypeDatalist'; + $id = $this->get('id'); + if ($id === null) { + return false; + } + $db = $this->getDb(); $dataFieldsCheck = $db->select() @@ -137,8 +106,8 @@ class DirectorDatalist extends DbObject implements ExportInterface 'l.id = dfs.setting_value', [] ) - ->where('datatype = ?', $datalistType) - ->where('setting_value = ?', $this->get('id')); + ->where('datatype = ?', DataTypeDatalist::class) + ->where('setting_value = ?', $id); if ($db->fetchOne($dataFieldsCheck)) { return true; @@ -147,7 +116,7 @@ class DirectorDatalist extends DbObject implements ExportInterface $syncCheck = $db->select() ->from(['sp' =>'sync_property'], ['source_expression']) ->where('sp.destination_field = ?', 'list_id') - ->where('sp.source_expression = ?', $this->get('id')); + ->where('sp.source_expression = ?', $id); if ($db->fetchOne($syncCheck)) { return true; @@ -161,65 +130,38 @@ class DirectorDatalist extends DbObject implements ExportInterface */ public function onStore() { - if ($this->storedEntries) { + if ($this->entries) { $db = $this->getConnection(); $removedKeys = []; $myId = $this->get('id'); - foreach ($this->storedEntries as $key => $entry) { + foreach ($this->entries as $key => $entry) { if ($entry->shouldBeRemoved()) { $entry->delete(); $removedKeys[] = $key; } else { - if (! $entry->hasBeenLoadedFromDb()) { - $entry->set('list_id', $myId); - } $entry->set('list_id', $myId); $entry->store($db); } } foreach ($removedKeys as $key) { - unset($this->storedEntries[$key]); - } - } - } - - /** - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @return object - */ - public function export() - { - $plain = (object) $this->getProperties(); - $plain->originalId = $plain->id; - unset($plain->id); - - $plain->entries = []; - foreach ($this->getStoredEntries() as $key => $entry) { - if ($entry->shouldBeRemoved()) { - continue; + unset($this->entries[$key]); } - $plainEntry = (object) $entry->getProperties(); - unset($plainEntry->list_id); - - $plain->entries[] = $plainEntry; } - - return $plain; } - protected function getStoredEntries() + public function getEntries(): array { - if ($this->storedEntries === null) { - if ($id = $this->get('id')) { - $this->storedEntries = DirectorDatalistEntry::loadAllForList($this); - ksort($this->storedEntries); + if ($this->entries === null) { + if ($this->get('id')) { + $this->entries = DirectorDatalistEntry::loadAllForList($this); + ksort($this->entries); } else { - $this->storedEntries = []; + $this->entries = []; } } - return $this->storedEntries; + return $this->entries; } } diff --git a/library/Director/Objects/DirectorDatalistEntry.php b/library/Director/Objects/DirectorDatalistEntry.php index 086686a..278de97 100644 --- a/library/Director/Objects/DirectorDatalistEntry.php +++ b/library/Director/Objects/DirectorDatalistEntry.php @@ -51,7 +51,7 @@ class DirectorDatalistEntry extends DbObject } else { throw new RuntimeException( 'Expected array or null for allowed_roles, got %s', - var_export($roles, 1) + var_export($roles, true) ); } } diff --git a/library/Director/Objects/DirectorDeploymentLog.php b/library/Director/Objects/DirectorDeploymentLog.php index 0794a3c..e9b07ce 100644 --- a/library/Director/Objects/DirectorDeploymentLog.php +++ b/library/Director/Objects/DirectorDeploymentLog.php @@ -46,7 +46,11 @@ class DirectorDeploymentLog extends DbObject public function getConfigHexChecksum() { - return bin2hex($this->config_checksum); + $checksum = $this->get('config_checksum'); + if ($checksum === null) { + return null; + } + return bin2hex($checksum); } public function getConfig() diff --git a/library/Director/Objects/DirectorJob.php b/library/Director/Objects/DirectorJob.php index 361f764..2a18d52 100644 --- a/library/Director/Objects/DirectorJob.php +++ b/library/Director/Objects/DirectorJob.php @@ -122,8 +122,12 @@ class DirectorJob extends DbObjectWithSettings implements ExportInterface, Insta return false; } + if ($this->get('ts_last_attempt') === null) { + return true; + } + return ( - strtotime((int) $this->get('ts_last_attempt')) + $this->get('run_interval') * 2 + strtotime($this->get('ts_last_attempt')) + $this->get('run_interval') * 2 ) < time(); } @@ -194,87 +198,6 @@ class DirectorJob extends DbObjectWithSettings implements ExportInterface, Insta } /** - * @return object - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError - */ - public function export() - { - $plain = (object) $this->getProperties(); - $plain->originalId = $plain->id; - unset($plain->id); - unset($plain->timeperiod_id); - if ($this->hasTimeperiod()) { - $plain->timeperiod = $this->timeperiod()->getObjectName(); - } - - foreach ($this->stateProperties as $key) { - unset($plain->$key); - } - $plain->settings = $this->getInstance()->exportSettings(); - - return $plain; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return DirectorJob - * @throws DuplicateKeyException - * @throws NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $dummy = new static; - $idCol = $dummy->autoincKeyName; - $keyCol = $dummy->keyName; - $properties = (array) $plain; - if (isset($properties['originalId'])) { - $id = $properties['originalId']; - unset($properties['originalId']); - } else { - $id = null; - } - $name = $properties[$keyCol]; - - if ($replace && $id && static::existsWithNameAndId($name, $id, $db)) { - $object = static::loadWithAutoIncId($id, $db); - } elseif ($replace && static::exists($name, $db)) { - $object = static::load($name, $db); - } elseif (static::exists($name, $db)) { - throw new DuplicateKeyException( - 'Director Job "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - $settings = (array) $properties['settings']; - - if (array_key_exists('source', $settings) && ! (array_key_exists('source_id', $settings))) { - $val = ImportSource::load($settings['source'], $db)->get('id'); - $settings['source_id'] = $val; - unset($settings['source']); - } - - if (array_key_exists('rule', $settings) && ! (array_key_exists('rule_id', $settings))) { - $val = SyncRule::load($settings['rule'], $db)->get('id'); - $settings['rule_id'] = $val; - unset($settings['rule']); - } - - $properties['settings'] = (object) $settings; - $object->setProperties($properties); - if ($id !== null) { - $object->reallySet($idCol, $id); - } - - return $object; - } - - /** * @param string $name * @param int $id * @param Db $connection diff --git a/library/Director/Objects/GroupMembershipResolver.php b/library/Director/Objects/GroupMembershipResolver.php index f5ef418..7266de9 100644 --- a/library/Director/Objects/GroupMembershipResolver.php +++ b/library/Director/Objects/GroupMembershipResolver.php @@ -211,7 +211,7 @@ abstract class GroupMembershipResolver $query, $object, 'o', - Db\IcingaObjectFilterHelper::INHERIT_DIRECT_OR_INDIRECT + IcingaObjectFilterHelper::INHERIT_DIRECT_OR_INDIRECT ); foreach ($object::loadAll($this->connection, $query) as $child) { @@ -352,7 +352,7 @@ abstract class GroupMembershipResolver $type = $this->type; if ($this->groupMap === null) { $this->groupMap = $this->db->fetchPairs( - $this->db->select()->from("icinga_${type}group", ['object_name', 'id']) + $this->db->select()->from("icinga_{$type}group", ['object_name', 'id']) ); } @@ -390,9 +390,9 @@ abstract class GroupMembershipResolver $db->delete( $this->getResolvedTableName(), sprintf( - "(${type}group_id = %d AND ${type}_id = %d)", - $row["${type}group_id"], - $row["${type}_id"] + "({$type}group_id = %d AND {$type}_id = %d)", + $row["{$type}group_id"], + $row["{$type}_id"] ) ); } @@ -416,16 +416,16 @@ abstract class GroupMembershipResolver foreach ($objectIds as $objectId) { if (! array_key_exists($objectId, $right[$groupId])) { $diff[] = array( - "${type}group_id" => $groupId, - "${type}_id" => $objectId, + "{$type}group_id" => $groupId, + "{$type}_id" => $objectId, ); } } } else { foreach ($objectIds as $objectId) { $diff[] = array( - "${type}group_id" => $groupId, - "${type}_id" => $objectId, + "{$type}group_id" => $groupId, + "{$type}_id" => $objectId, ); } } @@ -445,16 +445,16 @@ abstract class GroupMembershipResolver $query = $this->db->select()->from( array('hgh' => $this->getResolvedTableName()), array( - 'group_id' => "${type}group_id", - 'object_id' => "${type}_id", + 'group_id' => "{$type}group_id", + 'object_id' => "{$type}_id", ) ); - $this->addMembershipWhere($query, "${type}_id", $this->objects); - $this->addMembershipWhere($query, "${type}group_id", $this->groups); + $this->addMembershipWhere($query, "{$type}_id", $this->objects); + $this->addMembershipWhere($query, "{$type}group_id", $this->groups); if (! empty($this->groups)) { // load staticGroups (we touched here) additionally, so we can compare changes - $this->addMembershipWhere($query, "${type}group_id", $this->staticGroups); + $this->addMembershipWhere($query, "{$type}group_id", $this->staticGroups); } foreach ($this->db->fetchAll($query) as $row) { @@ -602,7 +602,7 @@ abstract class GroupMembershipResolver { $type = $this->getType(); $query = $this->db->select()->from( - array('hg' => "icinga_${type}group"), + array('hg' => "icinga_{$type}group"), array( 'id', 'assign_filter', @@ -629,7 +629,7 @@ abstract class GroupMembershipResolver protected function getTableName() { $type = $this->getType(); - return "icinga_${type}group_${type}"; + return "icinga_{$type}group_{$type}"; } protected function getResolvedTableName() diff --git a/library/Director/Objects/IcingaArguments.php b/library/Director/Objects/IcingaArguments.php index e788da8..22bf914 100644 --- a/library/Director/Objects/IcingaArguments.php +++ b/library/Director/Objects/IcingaArguments.php @@ -155,7 +155,9 @@ class IcingaArguments implements Iterator, Countable, IcingaConfigRenderer if (property_exists($value, 'type')) { // argument is directly set as function, no further properties if ($value->type === 'Function') { - $attrs['argument_value'] = self::COMMENT_DSL_UNSUPPORTED; + $attrs['argument_value'] = property_exists($value, 'body') + ? $value->body + : self::COMMENT_DSL_UNSUPPORTED; $attrs['argument_format'] = 'expression'; } } elseif (property_exists($value, 'value')) { @@ -296,6 +298,7 @@ class IcingaArguments implements Iterator, Countable, IcingaConfigRenderer $this->arguments = IcingaCommandArgument::loadAll($connection, $query, 'argument_name'); $this->cloneStored(); $this->refreshIndex(); + $this->modified = false; return $this; } @@ -360,6 +363,7 @@ class IcingaArguments implements Iterator, Countable, IcingaConfigRenderer } $this->refreshIndex(); $this->cloneStored(); + $this->modified = false; } /** @@ -393,7 +397,9 @@ class IcingaArguments implements Iterator, Countable, IcingaConfigRenderer unset($this->arguments[$key]); } + $this->refreshIndex(); $this->cloneStored(); + $this->modified = false; return $this; } diff --git a/library/Director/Objects/IcingaCommand.php b/library/Director/Objects/IcingaCommand.php index 35f38a4..8c5aed0 100644 --- a/library/Director/Objects/IcingaCommand.php +++ b/library/Director/Objects/IcingaCommand.php @@ -2,9 +2,7 @@ namespace Icinga\Module\Director\Objects; -use Icinga\Module\Director\Db; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; -use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c; use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1; use Icinga\Module\Director\Objects\Extension\Arguments; @@ -129,10 +127,8 @@ class IcingaCommand extends IcingaObject implements ObjectWithArguments, ExportI // return $value; } - if (self::$pluginDir !== null) { - if (($pos = strpos($value, self::$pluginDir)) === 0) { - $value = substr($value, strlen(self::$pluginDir) + 1); - } + if (isset($value, self::$pluginDir) && strpos($value, self::$pluginDir) === 0) { + $value = substr($value, strlen(self::$pluginDir) + 1); } return $value; @@ -212,89 +208,6 @@ class IcingaCommand extends IcingaObject implements ObjectWithArguments, ExportI return $this->getObjectName(); } - /** - * @return object - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError - */ - public function export() - { - $props = (array) $this->toPlainObject(); - if (isset($props['arguments'])) { - foreach ($props['arguments'] as $key => $argument) { - if (property_exists($argument, 'command_id')) { - unset($props['arguments'][$key]->command_id); - } - } - } - $props['fields'] = $this->loadFieldReferences(); - ksort($props); - - return (object) $props; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return IcingaCommand - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - $name = $properties['object_name']; - $key = $name; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Command "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - unset($properties['fields']); - $object->setProperties($properties); - - return $object; - } - - /** - * @deprecated please use \Icinga\Module\Director\Data\FieldReferenceLoader - * @return array - */ - protected function loadFieldReferences() - { - $db = $this->getDb(); - - $res = $db->fetchAll( - $db->select()->from([ - 'cf' => 'icinga_command_field' - ], [ - 'cf.datafield_id', - 'cf.is_required', - 'cf.var_filter', - ])->join(['df' => 'director_datafield'], 'df.id = cf.datafield_id', []) - ->where('command_id = ?', $this->get('id')) - ->order('varname ASC') - ); - - if (empty($res)) { - return []; - } else { - foreach ($res as $field) { - $field->datafield_id = (int) $field->datafield_id; - } - - return $res; - } - } - protected function renderCommand() { $command = $this->get('command'); diff --git a/library/Director/Objects/IcingaDependency.php b/library/Director/Objects/IcingaDependency.php index c9d9b89..abd92e6 100644 --- a/library/Director/Objects/IcingaDependency.php +++ b/library/Director/Objects/IcingaDependency.php @@ -3,9 +3,7 @@ namespace Icinga\Module\Director\Objects; use Icinga\Exception\ConfigurationError; -use Icinga\Module\Director\Db; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; -use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c; use Icinga\Exception\NotFoundError; use Icinga\Data\Filter\Filter; @@ -80,52 +78,21 @@ class IcingaDependency extends IcingaObject implements ExportInterface return $this->getObjectName(); } - /** - * @return object - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError - */ - public function export() + public function parentHostIsVar() { - $props = (array) $this->toPlainObject(); - ksort($props); - - return (object) $props; + return $this->get('parent_host_var') !== null; } /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return static - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError + * Check if the given string is a custom variable + * + * @param $string string + * + * @return false|int */ - public static function import($plain, Db $db, $replace = false) + protected function isCustomVar(string $string) { - $properties = (array) $plain; - $name = $properties['object_name']; - $key = $name; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Dependency "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - $object->setProperties($properties); - - return $object; - } - - public function parentHostIsVar() - { - return $this->get('parent_host_var') !== null; + return preg_match('/^(?:host|service)\.vars\..+$/', $string); } /** @@ -485,9 +452,16 @@ class IcingaDependency extends IcingaObject implements ExportInterface public function renderParent_service_by_name() { // @codingStandardsIgnoreEnd + $var = $this->get('parent_service_by_name'); + if ($this->isCustomVar($var)) { + return c::renderKeyValue( + 'parent_service_name', + $var + ); + } return c::renderKeyValue( 'parent_service_name', - c::renderString($this->get('parent_service_by_name')) + c::renderString($var) ); } @@ -506,7 +480,7 @@ class IcingaDependency extends IcingaObject implements ExportInterface protected function resolveUnresolvedRelatedProperty($name) { $short = substr($name, 0, -3); - /** @var IcingaObject $class */ + /** @var IcingaObject|string $class */ $class = $this->getRelationClass($short); $objKey = $this->unresolvedRelatedProperties[$name]; @@ -589,7 +563,25 @@ class IcingaDependency extends IcingaObject implements ExportInterface $this->reallySet($name, $object->get('id')); unset($this->unresolvedRelatedProperties[$name]); } else { - throw new NotFoundError('Unable to resolve related property: "%s"', $name); + // Depend on a single service on a single host. Rare case, as usually you want to + // depend on a service on the very same host - and leave the Host field empty. The + // latter is already being handled above. This duplicates some code, but I'll leave + // it this way for now. There might have been a reason for the parent_host_id = null + // check in that code. + if ($name === 'parent_service_id' && $this->get('object_type') === 'apply') { + $this->reallySet( + 'parent_service_by_name', + $this->unresolvedRelatedProperties[$name] + ); + $this->reallySet('parent_service_id', null); + unset($this->unresolvedRelatedProperties[$name]); + return; + } + throw new NotFoundError(sprintf( + 'Unable to resolve related property: %s "%s"', + $name, + $this->unresolvedRelatedProperties[$name] + )); } } @@ -620,8 +612,12 @@ class IcingaDependency extends IcingaObject implements ExportInterface $related = parent::getRelatedProperty($key); // handle special case for plain string parent service on Dependency // Apply rules - if ($related === null && $key === 'parent_service' - && null !== $this->get('parent_service_by_name') + if ($related === null + && $key === 'parent_service' + && ( + $this->get('parent_service_by_name') + && ! $this->isCustomVar($this->get('parent_service_by_name')) + ) ) { return $this->get('parent_service_by_name'); } diff --git a/library/Director/Objects/IcingaHost.php b/library/Director/Objects/IcingaHost.php index 2731f4a..7859324 100644 --- a/library/Director/Objects/IcingaHost.php +++ b/library/Director/Objects/IcingaHost.php @@ -7,7 +7,6 @@ use Icinga\Exception\NotFoundError; use Icinga\Module\Director\Data\PropertiesFilter; use Icinga\Module\Director\Db; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; -use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\IcingaConfig\IcingaConfig; use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c; use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1; @@ -310,88 +309,18 @@ class IcingaHost extends IcingaObject implements ExportInterface } } - /** - * @return object - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError - */ - public function export() + protected function rendersConditionalTemplate(): bool { - // TODO: ksort in toPlainObject? - $props = (array) $this->toPlainObject(); - $props['fields'] = $this->loadFieldReferences(); - ksort($props); - - return (object) $props; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return IcingaHost - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - $name = $properties['object_name']; - if ($properties['object_type'] !== 'template') { - throw new InvalidArgumentException(sprintf( - 'Can import only Templates, got "%s" for "%s"', - $properties['object_type'], - $name - )); - } - $key = $name; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Service Template "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - // $object->newFields = $properties['fields']; - unset($properties['fields']); - $object->setProperties($properties); - - return $object; + return $this->getRenderingZone() === self::ALL_NON_GLOBAL_ZONES; } - /** - * @deprecated please use \Icinga\Module\Director\Data\FieldReferenceLoader - * @return array - */ - protected function loadFieldReferences() + protected function getDefaultZone(IcingaConfig $config = null) { - $db = $this->getDb(); - - $res = $db->fetchAll( - $db->select()->from([ - 'hf' => 'icinga_host_field' - ], [ - 'hf.datafield_id', - 'hf.is_required', - 'hf.var_filter', - ])->join(['df' => 'director_datafield'], 'df.id = hf.datafield_id', []) - ->where('host_id = ?', $this->get('id')) - ->order('varname ASC') - ); - - if (empty($res)) { - return []; - } else { - foreach ($res as $field) { - $field->datafield_id = (int) $field->datafield_id; - } - return $res; + if ($this->isTemplate()) { + return self::ALL_NON_GLOBAL_ZONES; } + + return parent::getDefaultZone(); } public function beforeDelete() diff --git a/library/Director/Objects/IcingaHostGroup.php b/library/Director/Objects/IcingaHostGroup.php index e11f672..e78e931 100644 --- a/library/Director/Objects/IcingaHostGroup.php +++ b/library/Director/Objects/IcingaHostGroup.php @@ -31,12 +31,8 @@ class IcingaHostGroup extends IcingaObjectGroup return $this; } - protected function notifyResolvers() + protected function getMemberShipResolver() { - $resolver = $this->getHostGroupMembershipResolver(); - $resolver->addGroup($this); - $resolver->refreshDb(); - - return $this; + return $this->getHostGroupMembershipResolver(); } } diff --git a/library/Director/Objects/IcingaNotification.php b/library/Director/Objects/IcingaNotification.php index 9c5d08d..4768704 100644 --- a/library/Director/Objects/IcingaNotification.php +++ b/library/Director/Objects/IcingaNotification.php @@ -2,9 +2,8 @@ namespace Icinga\Module\Director\Objects; -use Icinga\Module\Director\Db; +use Icinga\Module\Director\CustomVariable\CustomVariables; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; -use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c; use RuntimeException; @@ -29,6 +28,8 @@ class IcingaNotification extends IcingaObject implements ExportInterface 'notification_interval' => null, 'period_id' => null, 'zone_id' => null, + 'users_var' => null, + 'user_groups_var' => null, 'assign_filter' => null, ]; @@ -85,92 +86,76 @@ class IcingaNotification extends IcingaObject implements ExportInterface * @codingStandardsIgnoreStart * @return string */ - protected function renderTimes_end() + protected function renderUsers_var() { // @codingStandardsIgnoreEnd - return c::renderKeyValue('times.end', c::renderInterval($this->get('times_end'))); - } - - public function getUniqueIdentifier() - { - return $this->getObjectName(); + return ''; } /** - * @return \stdClass - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError + * @codingStandardsIgnoreStart + * @return string */ - public function export() + protected function renderUser_groups_var() { - // TODO: ksort in toPlainObject? - $props = (array) $this->toPlainObject(); - $props['fields'] = $this->loadFieldReferences(); - ksort($props); - - return (object) $props; + // @codingStandardsIgnoreEnd + return ''; } - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return static - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) + protected function renderUserVarsSuffixFor($property) { - $properties = (array) $plain; - $name = $properties['object_name']; - $key = $name; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Notification "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); + $varName = $this->getResolvedProperty("{$property}_var"); + if ($varName === null) { + return ''; + } + + $varSuffix = CustomVariables::renderKeySuffix($varName); + $indent = ' '; + $objectType = $this->get('apply_to'); + if ($objectType === 'service') { + return "{$indent}if (service.vars$varSuffix) {\n" + . c::renderKeyOperatorValue($property, '+=', "service.vars$varSuffix", $indent . ' ') + . "$indent} else {\n" + . $this->getHostSnippet($indent . ' ') + . "$indent if (host.vars$varSuffix) { " + . c::renderKeyOperatorValue($property, '+=', "host.vars$varSuffix }", '') + . "$indent}\n"; + } elseif ($objectType === 'host') { + return $this->getHostSnippet() + . "{$indent}if (host.vars$varSuffix) { " + . c::renderKeyOperatorValue($property, '+=', "host.vars$varSuffix }"); } - // $object->newFields = $properties['fields']; - unset($properties['fields']); - $object->setProperties($properties); + return ''; + } + + protected function getHostSnippet($indent = ' ') + { + return "{$indent}if (! host) {\n" + . "$indent var host = get_host(host_name)\n" + . "$indent}\n"; + } - return $object; + protected function renderSuffix() + { + return $this->renderUserVarsSuffixFor('users') + . $this->renderUserVarsSuffixFor('user_groups') + . parent::renderSuffix(); } /** - * @deprecated please use \Icinga\Module\Director\Data\FieldReferenceLoader - * @return array + * @codingStandardsIgnoreStart + * @return string */ - protected function loadFieldReferences() + protected function renderTimes_end() { - $db = $this->getDb(); - - $res = $db->fetchAll( - $db->select()->from([ - 'nf' => 'icinga_notification_field' - ], [ - 'nf.datafield_id', - 'nf.is_required', - 'nf.var_filter', - ])->join(['df' => 'director_datafield'], 'df.id = nf.datafield_id', []) - ->where('notification_id = ?', $this->get('id')) - ->order('varname ASC') - ); - - if (empty($res)) { - return []; - } else { - foreach ($res as $field) { - $field->datafield_id = (int) $field->datafield_id; - } - return $res; - } + // @codingStandardsIgnoreEnd + return c::renderKeyValue('times.end', c::renderInterval($this->get('times_end'))); + } + + public function getUniqueIdentifier() + { + return $this->getObjectName(); } /** diff --git a/library/Director/Objects/IcingaObject.php b/library/Director/Objects/IcingaObject.php index 04ae32b..3b6236d 100644 --- a/library/Director/Objects/IcingaObject.php +++ b/library/Director/Objects/IcingaObject.php @@ -27,6 +27,7 @@ use RuntimeException; abstract class IcingaObject extends DbObject implements IcingaConfigRenderer { const RESOLVE_ERROR = '(unable to resolve)'; + const ALL_NON_GLOBAL_ZONES = '(all non-global zones)'; protected $keyName = 'object_name'; @@ -63,9 +64,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer protected $type; - /* key/value!! */ - protected $booleans = []; - // Property suffixed with _id must exist protected $relations = [ // property => PropertyClass @@ -142,11 +140,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this->connection; } - public function propertyIsBoolean($property) - { - return array_key_exists($property, $this->booleans); - } - public function propertyIsInterval($property) { return array_key_exists($property, $this->intervalProperties); @@ -771,10 +764,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return $this; } - if ($this->propertyIsBoolean($key)) { - return parent::set($key, DbDataFormatter::normalizeBoolean($value)); - } - // e.g. zone_id if ($this->propertyIsRelation($key)) { return $this->setRelation($key, $value); @@ -906,20 +895,20 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer $type = strtolower($this->getType()); $query = $this->db->select()->from( - ['gr' => "icinga_${type}group_${type}_resolved"], + ['gr' => "icinga_{$type}group_{$type}_resolved"], ['g.object_name'] )->join( - ['g' => "icinga_${type}group"], - "g.id = gr.${type}group_id", + ['g' => "icinga_{$type}group"], + "g.id = gr.{$type}group_id", [] )->joinLeft( - ['go' => "icinga_${type}group_${type}"], - "go.${type}group_id = gr.${type}group_id AND go.${type}_id = " . (int) $id, + ['go' => "icinga_{$type}group_{$type}"], + "go.{$type}group_id = gr.{$type}group_id AND go.{$type}_id = " . (int) $id, [] )->where( - "gr.${type}_id = ?", + "gr.{$type}_id = ?", (int) $id - )->where("go.${type}_id IS NULL")->order('g.object_name'); + )->where("go.{$type}_id IS NULL")->order('g.object_name'); return $this->db->fetchCol($query); } @@ -1812,9 +1801,21 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return; } - $config->configFile( - 'zones.d/' . $this->getRenderingZone($config) . '/' . $this->getRenderingFilename() - )->addObject($this); + foreach ($this->getRenderingZones($config) as $zone) { + $config->configFile( + 'zones.d/' . $zone . '/' . $this->getRenderingFilename() + )->addObject($this); + } + } + + protected function getRenderingZones(IcingaConfig $config): array + { + $zone = $this->getRenderingZone($config); + if ($zone === self::ALL_NON_GLOBAL_ZONES) { + return $config->listNonGlobalZones(); + } + + return [$zone]; } public function getRenderingFilename() @@ -2193,7 +2194,12 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer protected function renderSuffix() { - return "}\n\n"; + $prefix = ''; + if ($this->rendersConditionalTemplate()) { + $prefix = '} '; + } + + return "$prefix}\n\n"; } protected function renderLegacySuffix() @@ -2418,14 +2424,25 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer protected function renderObjectHeader() { + $prefix = ''; + $renderedName = c::renderString($this->getObjectName()); + if ($this->rendersConditionalTemplate()) { + $prefix = sprintf('if (! get_template(%s, %s)) { ', $this->getType(), $renderedName); + } return sprintf( - "%s %s %s {\n", + "%s%s %s %s {\n", + $prefix, $this->getObjectTypeName(), $this->getType(), - c::renderString($this->getObjectName()) + $renderedName ); } + protected function rendersConditionalTemplate(): bool + { + return false; + } + public function getLegacyObjectType() { return strtolower($this->getType()); @@ -2674,16 +2691,16 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer /** @var DbObject $class */ $class = DbObjectTypeRegistry::classByType($type); + if ($keyColumn === null && is_array($class::create()->getKeyName())) { + return $class::loadAll($db, $query); + } + if ($keyColumn === null) { if (method_exists($class, 'getKeyColumnName')) { $keyColumn = $class::getKeyColumnName(); } } - if (is_array($class::create()->getKeyName())) { - return $class::loadAll($db, $query); - } - if (PrefetchCache::shouldBeUsed() && $query === null && $keyColumn === static::getKeyColumnName() @@ -2890,11 +2907,14 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer } } } + if ($this->propertyIsInterval($k) && is_string($v) && ctype_digit($v)) { + $v = (int) $v; + } // TODO: Do not ship null properties based on flag? if (!$skipDefaults || $this->differsFromDefaultValue($k, $v)) { if ($k === 'disabled' || $this->propertyIsBoolean($k)) { - $props[$k] = $this->booleanForDbValue($v); + $props[$k] = DbDataFormatter::booleanForDbValue($v); } else { $props[$k] = $v; } @@ -3005,18 +3025,6 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer return (object) $props; } - protected function booleanForDbValue($value) - { - if ($value === 'y') { - return true; - } - if ($value === 'n') { - return false; - } - - return $value; // let this fail elsewhere, if not null - } - public function listImportNames() { if ($this->gotImports()) { @@ -3161,7 +3169,7 @@ abstract class IcingaObject extends DbObject implements IcingaConfigRenderer if ($this->differsFromDefaultValue($k, $v)) { if ($k === 'disabled' || $this->propertyIsBoolean($k)) { - $props[$k] = $this->booleanForDbValue($v); + $props[$k] = DbDataFormatter::booleanForDbValue($v); } else { $props[$k] = $v; } diff --git a/library/Director/Objects/IcingaObjectGroup.php b/library/Director/Objects/IcingaObjectGroup.php index c0bec54..c076f52 100644 --- a/library/Director/Objects/IcingaObjectGroup.php +++ b/library/Director/Objects/IcingaObjectGroup.php @@ -2,9 +2,7 @@ namespace Icinga\Module\Director\Objects; -use Icinga\Module\Director\Db; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; -use Icinga\Module\Director\Exception\DuplicateKeyException; abstract class IcingaObjectGroup extends IcingaObject implements ExportInterface { @@ -24,53 +22,51 @@ abstract class IcingaObjectGroup extends IcingaObject implements ExportInterface 'assign_filter' => null, ]; + protected $memberShipShouldBeRefreshed = false; + public function getUniqueIdentifier() { return $this->getObjectName(); } - /** - * @return object - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError - */ - public function export() + protected function prefersGlobalZone() { - return $this->toPlainObject(); + return true; } - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return IcingaObjectGroup - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) + protected function beforeStore() { - $properties = (array) $plain; - $name = $properties['object_name']; - $key = $name; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Group "%s" already exists', - $name - ); + parent::beforeStore(); + if ($this->hasBeenLoadedFromDb()) { + if (!array_key_exists('assign_filter', $this->getModifiedProperties())) { + $this->memberShipShouldBeRefreshed = false; + return; + } } else { - $object = static::create([], $db); + if ($this->hasProperty('assign_filter') && $this->get('assign_filter') === null) { + $this->memberShipShouldBeRefreshed = false; + return; + } } - $object->setProperties($properties); + if ($this->hasProperty('assign_filter')) { + $this->memberShipShouldBeRefreshed = true; + } + } - return $object; + protected function notifyResolvers() + { + if ($this->memberShipShouldBeRefreshed) { + $resolver = $this->getMemberShipResolver(); + $resolver->addGroup($this); + $resolver->refreshDb(); + } + + return $this; } - protected function prefersGlobalZone() + protected function getMemberShipResolver() { - return true; + return null; } } diff --git a/library/Director/Objects/IcingaObjectGroups.php b/library/Director/Objects/IcingaObjectGroups.php index 8bef1b1..8683c77 100644 --- a/library/Director/Objects/IcingaObjectGroups.php +++ b/library/Director/Objects/IcingaObjectGroups.php @@ -183,6 +183,10 @@ class IcingaObjectGroups implements Iterator, Countable, IcingaConfigRenderer return $this; } + if (is_int($group)) { + $group = (string) $group; + } + /** @var IcingaObjectGroup $class */ $class = $this->getGroupClass(); @@ -224,7 +228,7 @@ class IcingaObjectGroups implements Iterator, Countable, IcingaConfigRenderer } else { throw new RuntimeException( 'Invalid group object: %s', - var_export($group, 1) + var_export($group, true) ); } diff --git a/library/Director/Objects/IcingaObjectLegacyAssignments.php b/library/Director/Objects/IcingaObjectLegacyAssignments.php index 6ab75c8..2db29b4 100644 --- a/library/Director/Objects/IcingaObjectLegacyAssignments.php +++ b/library/Director/Objects/IcingaObjectLegacyAssignments.php @@ -36,7 +36,7 @@ class IcingaObjectLegacyAssignments $assigns = array(); $ignores = array(); foreach ($values as $type => $value) { - if (strpos($value, '|') !== false || strpos($value, '&' !== false)) { + if (strpos($value, '|') !== false || strpos($value, '&') !== false) { $value = '(' . $value . ')'; } diff --git a/library/Director/Objects/IcingaObjectMultiRelations.php b/library/Director/Objects/IcingaObjectMultiRelations.php index a1ec9a2..5931595 100644 --- a/library/Director/Objects/IcingaObjectMultiRelations.php +++ b/library/Director/Objects/IcingaObjectMultiRelations.php @@ -239,7 +239,7 @@ class IcingaObjectMultiRelations implements Iterator, Countable, IcingaConfigRen } else { throw new ProgrammingError( 'Invalid related object: %s', - var_export($relation, 1) + var_export($relation, true) ); } diff --git a/library/Director/Objects/IcingaRelatedObject.php b/library/Director/Objects/IcingaRelatedObject.php index d35bcb0..ca33688 100644 --- a/library/Director/Objects/IcingaRelatedObject.php +++ b/library/Director/Objects/IcingaRelatedObject.php @@ -180,7 +180,7 @@ class IcingaRelatedObject } else { throw new ProgrammingError( 'Related object can be name or object, got: %s', - var_export($related, 1) + var_export($related, true) ); } diff --git a/library/Director/Objects/IcingaService.php b/library/Director/Objects/IcingaService.php index 9479ef7..cbf9ca5 100644 --- a/library/Director/Objects/IcingaService.php +++ b/library/Director/Objects/IcingaService.php @@ -8,7 +8,6 @@ use Icinga\Module\Director\Data\PropertiesFilter; use Icinga\Module\Director\Db; use Icinga\Module\Director\Db\Cache\PrefetchCache; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; -use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\IcingaConfig\IcingaConfig; use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c; use Icinga\Module\Director\IcingaConfig\IcingaLegacyConfigHelper as c1; @@ -170,94 +169,6 @@ class IcingaService extends IcingaObject implements ExportInterface } /** - * @return object - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError - */ - public function export() - { - // TODO: ksort in toPlainObject? - $props = (array) $this->toPlainObject(); - $props['fields'] = $this->loadFieldReferences(); - ksort($props); - - return (object) $props; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return IcingaService - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - $name = $properties['object_name']; - if ($properties['object_type'] !== 'template') { - throw new InvalidArgumentException(sprintf( - 'Can import only Templates, got "%s" for "%s"', - $properties['object_type'], - $name - )); - } - $key = [ - 'object_type' => 'template', - 'object_name' => $name - ]; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Service Template "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - // $object->newFields = $properties['fields']; - unset($properties['fields']); - $object->setProperties($properties); - - return $object; - } - - /** - * @deprecated please use \Icinga\Module\Director\Data\FieldReferenceLoader - * @return array - */ - protected function loadFieldReferences() - { - $db = $this->getDb(); - - $res = $db->fetchAll( - $db->select()->from([ - 'sf' => 'icinga_service_field' - ], [ - 'sf.datafield_id', - 'sf.is_required', - 'sf.var_filter', - ])->join(['df' => 'director_datafield'], 'df.id = sf.datafield_id', []) - ->where('service_id = ?', $this->get('id')) - ->order('varname ASC') - ); - - if (empty($res)) { - return []; - } else { - foreach ($res as $field) { - $field->datafield_id = (int) $field->datafield_id; - } - - return $res; - } - } - - /** * @param string $key * @return $this */ @@ -473,6 +384,11 @@ class IcingaService extends IcingaObject implements ExportInterface } } + protected function rendersConditionalTemplate(): bool + { + return $this->getRenderingZone() === self::ALL_NON_GLOBAL_ZONES; + } + /** * @return bool */ @@ -667,11 +583,22 @@ class IcingaService extends IcingaObject implements ExportInterface protected function getDefaultZone(IcingaConfig $config = null) { + // Hint: this isn't possible yet, as we're unable to render dependent apply rules to multiple zones as well + // if ($this->isTemplate()) { + // return self::ALL_NON_GLOBAL_ZONES; + // } if ($this->get('host_id') === null) { return parent::getDefaultZone(); } else { - return $this->getRelatedObject('host', $this->get('host_id')) + $zone = $this->getRelatedObject('host', $this->get('host_id')) ->getRenderingZone($config); + + // Hint: this avoids problems with host templates rendered to all non-global zones + if ($zone === self::ALL_NON_GLOBAL_ZONES) { + $zone = $this->connection->getDefaultGlobalZoneName(); + } + + return $zone; } } diff --git a/library/Director/Objects/IcingaServiceGroup.php b/library/Director/Objects/IcingaServiceGroup.php index ae43ff3..92fb1cb 100644 --- a/library/Director/Objects/IcingaServiceGroup.php +++ b/library/Director/Objects/IcingaServiceGroup.php @@ -31,12 +31,8 @@ class IcingaServiceGroup extends IcingaObjectGroup return $this; } - protected function notifyResolvers() + protected function getMemberShipResolver() { - $resolver = $this->getServiceGroupMembershipResolver(); - $resolver->addGroup($this); - $resolver->refreshDb(); - - return $this; + return $this->getServiceGroupMembershipResolver(); } } diff --git a/library/Director/Objects/IcingaServiceSet.php b/library/Director/Objects/IcingaServiceSet.php index 8217a59..252c52a 100644 --- a/library/Director/Objects/IcingaServiceSet.php +++ b/library/Director/Objects/IcingaServiceSet.php @@ -5,16 +5,14 @@ namespace Icinga\Module\Director\Objects; use Exception; use Icinga\Data\Filter\Filter; use Icinga\Module\Director\Data\Db\ServiceSetQueryBuilder; -use Icinga\Module\Director\Db; use Icinga\Module\Director\Db\Cache\PrefetchCache; -use Icinga\Module\Director\Db\DbUtil; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\IcingaConfig\IcingaConfig; use Icinga\Module\Director\Resolver\HostServiceBlacklist; use InvalidArgumentException; use Ramsey\Uuid\Uuid; -use RuntimeException; +use stdClass; class IcingaServiceSet extends IcingaObject implements ExportInterface { @@ -46,6 +44,33 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface 'host' => 'IcingaHost', ); + /** @var IcingaService[] Cached services */ + protected $cachedServices = []; + + /** @var IcingaService[]|null */ + private $services; + + /** + * Set the services to be cached + * + * @param $services IcingaService[] + * @return void + */ + public function setCachedServices($services) + { + $this->cachedServices = $services; + } + + /** + * Get the cached services + * + * @return IcingaService[] + */ + public function getCachedServices() + { + return $this->cachedServices; + } + public function isDisabled() { return false; @@ -79,6 +104,61 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface } /** + * @param stdClass[] $services + * @return void + */ + public function setServices(array $services) + { + $existing = $this->getServices(); + $uuidMap = []; + foreach ($existing as $service) { + $uuidMap[$service->getUniqueId()->getBytes()] = $service; + } + $this->services = []; + foreach ($services as $service) { + if (isset($service->uuid)) { + $uuid = Uuid::fromString($service->uuid)->getBytes(); + $current = $uuidMap[$uuid] ?? IcingaService::create([], $this->connection); + } else { + if (! is_object($service)) { + var_dump($service); + exit; + } + $current = $existing[$service->object_name] ?? IcingaService::create([], $this->connection); + } + $current->setProperties((array) $service); + $this->services[] = $current; + } + } + + protected function storeRelatedServices() + { + if ($this->services === null) { + $cachedServices = $this->getCachedServices(); + if ($cachedServices) { + $this->services = $cachedServices; + } else { + return; + } + } + + $seen = []; + /** @var IcingaService $service */ + foreach ($this->services as $service) { + $seen[$service->getUniqueId()->getBytes()] = true; + $service->set('service_set_id', $this->get('id')); + $service->store(); + } + + foreach ($this->fetchServices() as $service) { + if (!isset($seen[$service->getUniqueId()->getBytes()])) { + $service->delete(); + } + } + } + + /** + * @deprecated * @return IcingaService[] * @throws \Icinga\Exception\NotFoundError */ @@ -126,129 +206,9 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface return $this->getObjectName(); } - /** - * @return object - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @throws \Icinga\Exception\NotFoundError - */ - public function export() - { - if ($this->get('host_id')) { - $result = $this->exportSetOnHost(); - } else { - $result = $this->exportTemplate(); - } - - unset($result->uuid); - return $result; - } - - protected function exportSetOnHost() - { - // TODO. - throw new RuntimeException('Not yet'); - } - - /** - * @return object - * @deprecated - * @throws \Icinga\Exception\NotFoundError - */ - protected function exportTemplate() - { - $props = $this->getProperties(); - unset($props['id'], $props['host_id']); - $props['services'] = []; - foreach ($this->getServiceObjects() as $serviceObject) { - $props['services'][$serviceObject->getObjectName()] = $serviceObject->export(); - } - ksort($props); - - return (object) $props; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return IcingaServiceSet - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - $name = $properties['object_name']; - if (isset($properties['services'])) { - $services = $properties['services']; - unset($properties['services']); - } else { - $services = []; - } - - if ($properties['object_type'] !== 'template') { - throw new InvalidArgumentException(sprintf( - 'Can import only Templates, got "%s" for "%s"', - $properties['object_type'], - $name - )); - } - if ($replace && static::exists($name, $db)) { - $object = static::load($name, $db); - } elseif (static::exists($name, $db)) { - throw new DuplicateKeyException( - 'Service Set "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - $object->setProperties($properties); - - // This is not how other imports work, but here we need an ID - if (! $object->hasBeenLoadedFromDb()) { - $object->store(); - } - - $setId = $object->get('id'); - $sQuery = $db->getDbAdapter()->select()->from( - ['s' => 'icinga_service'], - 's.*' - )->where('service_set_id = ?', $setId); - $existingServices = IcingaService::loadAll($db, $sQuery, 'object_name'); - $serviceNames = []; - foreach ($services as $service) { - if (isset($service->fields)) { - unset($service->fields); - } - $name = $service->object_name; - $serviceNames[] = $name; - if (isset($existingServices[$name])) { - $existing = $existingServices[$name]; - $existing->setProperties((array) $service); - $existing->set('service_set_id', $setId); - if ($existing->hasBeenModified()) { - $existing->store(); - } - } else { - $new = IcingaService::create((array) $service, $db); - $new->set('service_set_id', $setId); - $new->store(); - } - } - - foreach ($existingServices as $existing) { - if (!in_array($existing->getObjectName(), $serviceNames)) { - $existing->delete(); - } - } - - return $object; - } - public function beforeDelete() { + $this->setCachedServices($this->getServices()); // check if this is a template, or directly assigned to a host if ($this->get('host_id') === null) { // find all host sets and delete them @@ -295,8 +255,8 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface */ public function renderToConfig(IcingaConfig $config) { - // always print the header, so you have minimal info present - $file = $this->getConfigFileWithHeader($config); + $files = []; + $zone = $this->getRenderingZone($config) ; if ($this->get('assign_filter') === null && $this->isTemplate()) { return; @@ -334,7 +294,15 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface } $this->copyVarsToService($service); - $file->addObject($service); + foreach ($service->getRenderingZones($config) as $serviceZone) { + $file = $this->getConfigFileWithHeader($config, $serviceZone, $files); + $file->addObject($service); + } + } + + if (empty($files)) { + // always print the header, so you have minimal info present + $this->getConfigFileWithHeader($config, $zone, $files); } } @@ -355,14 +323,18 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface return $lookup->getBlacklistedHostnamesForService($service); } - protected function getConfigFileWithHeader(IcingaConfig $config) + protected function getConfigFileWithHeader(IcingaConfig $config, $zone, &$files = []) { - $file = $config->configFile( - 'zones.d/' . $this->getRenderingZone($config) . '/servicesets' - ); + if (!isset($files[$zone])) { + $file = $config->configFile( + 'zones.d/' . $zone . '/servicesets' + ); - $file->addContent($this->getConfigHeaderComment($config)); - return $file; + $file->addContent($this->getConfigHeaderComment($config)); + $files[$zone] = $file; + } + + return $files[$zone]; } protected function getConfigHeaderComment(IcingaConfig $config) @@ -372,13 +344,13 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface if ($config->isLegacy()) { if ($assign !== null) { - return "## applied Service Set '${name}'\n\n"; + return "## applied Service Set '{$name}'\n\n"; } else { - return "## Service Set '${name}' on this host\n\n"; + return "## Service Set '{$name}' on this host\n\n"; } } else { $comment = [ - "Service Set: ${name}", + "Service Set: {$name}", ]; if (($host = $this->get('host')) !== null) { @@ -505,7 +477,23 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface /** * @return IcingaService[] */ - public function fetchServices() + public function getServices(): array + { + if ($this->services !== null) { + return $this->services; + } + + if ($this->hasBeenLoadedFromDb()) { + return $this->fetchServices(); + } + + return []; + } + + /** + * @return IcingaService[] + */ + public function fetchServices(): array { if ($store = self::$dbObjectStore) { $uuid = $store->getBranch()->getUuid(); @@ -569,6 +557,24 @@ class IcingaServiceSet extends IcingaObject implements ExportInterface } } + public function onStore() + { + $this->storeRelatedServices(); + } + + public function hasBeenModified() + { + if ($this->services !== null) { + foreach ($this->services as $service) { + if ($service->hasBeenModified()) { + return true; + } + } + } + + return parent::hasBeenModified(); + } + public function toSingleIcingaConfig() { $config = parent::toSingleIcingaConfig(); diff --git a/library/Director/Objects/IcingaTemplateChoice.php b/library/Director/Objects/IcingaTemplateChoice.php index 1a1be90..a2be07a 100644 --- a/library/Director/Objects/IcingaTemplateChoice.php +++ b/library/Director/Objects/IcingaTemplateChoice.php @@ -3,9 +3,7 @@ namespace Icinga\Module\Director\Objects; use Icinga\Exception\ProgrammingError; -use Icinga\Module\Director\Db; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; -use Icinga\Module\Director\Exception\DuplicateKeyException; use Icinga\Module\Director\Web\Form\QuickForm; class IcingaTemplateChoice extends IcingaObject implements ExportInterface @@ -36,63 +34,6 @@ class IcingaTemplateChoice extends IcingaObject implements ExportInterface return $this->getObjectName(); } - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return IcingaTemplateChoice - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - if (isset($properties['originalId'])) { - unset($properties['originalId']); - } - $name = $properties['object_name']; - $key = $name; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Template Choice "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - $object->setProperties($properties); - - return $object; - } - - /** - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @return array|object|\stdClass - */ - public function export() - { - $plain = (object) $this->getProperties(); - $plain->originalId = $plain->id; - unset($plain->id); - $requiredId = $plain->required_template_id; - unset($plain->required_template_id); - if ($requiredId) { - $db = $this->getDb(); - $query = $db->select() - ->from(['o' => $this->getObjectTableName()], 'o.object_name')->where("o.object_type = 'template'") - ->where('o.id = ?', $this->get('id')); - $plain->required_template = $db->fetchOne($query); - } - - $plain->members = array_values($this->getMembers()); - - return $plain; - } - public function isMainChoice() { return $this->hasBeenLoadedFromDb() @@ -155,7 +96,7 @@ class IcingaTemplateChoice extends IcingaObject implements ExportInterface public function hasBeenModified() { - if ($this->newChoices !== null && $this->choices !== $this->newChoices) { + if ($this->newChoices !== null && ($this->choices ?? $this->fetchChoices()) !== $this->newChoices) { return true; } @@ -284,7 +225,7 @@ class IcingaTemplateChoice extends IcingaObject implements ExportInterface } else { throw new ProgrammingError( 'Expected array or null for allowed_roles, got %s', - var_export($roles, 1) + var_export($roles, true) ); } } diff --git a/library/Director/Objects/IcingaTemplateResolver.php b/library/Director/Objects/IcingaTemplateResolver.php index 61122a0..7f14967 100644 --- a/library/Director/Objects/IcingaTemplateResolver.php +++ b/library/Director/Objects/IcingaTemplateResolver.php @@ -45,7 +45,6 @@ class IcingaTemplateResolver { $this->object = $object; $this->type = $object->getShortTableName(); - $this->table = $object->getTableName(); $this->connection = $object->getConnection(); $this->db = $this->connection->getDbAdapter(); diff --git a/library/Director/Objects/IcingaTimePeriod.php b/library/Director/Objects/IcingaTimePeriod.php index 1232366..081cdd9 100644 --- a/library/Director/Objects/IcingaTimePeriod.php +++ b/library/Director/Objects/IcingaTimePeriod.php @@ -2,9 +2,7 @@ namespace Icinga\Module\Director\Objects; -use Icinga\Module\Director\Db; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; -use Icinga\Module\Director\Exception\DuplicateKeyException; class IcingaTimePeriod extends IcingaObject implements ExportInterface { @@ -56,48 +54,6 @@ class IcingaTimePeriod extends IcingaObject implements ExportInterface } /** - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @return object - * @throws \Icinga\Exception\NotFoundError - */ - public function export() - { - $props = (array) $this->toPlainObject(); - ksort($props); - - return (object) $props; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return static - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - $name = $properties['object_name']; - $key = $name; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Time Period "%s" already exists', - $name - ); - } else { - $object = static::create([], $db); - } - $object->setProperties($properties); - - return $object; - } - - /** * Render update property * * Avoid complaints for method names with underscore: diff --git a/library/Director/Objects/IcingaUser.php b/library/Director/Objects/IcingaUser.php index 394e849..4100245 100644 --- a/library/Director/Objects/IcingaUser.php +++ b/library/Director/Objects/IcingaUser.php @@ -48,43 +48,6 @@ class IcingaUser extends IcingaObject implements ExportInterface 'zone' => 'IcingaZone', ); - public function export() - { - return ImportExportHelper::simpleExport($this); - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return IcingaUser - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - $key = $properties['object_name']; - - if ($replace && static::exists($key, $db)) { - $object = static::load($key, $db); - } elseif (static::exists($key, $db)) { - throw new DuplicateKeyException( - 'Cannot import, %s "%s" already exists', - static::create([])->getShortTableName(), - $key - ); - } else { - $object = static::create([], $db); - } - - // $object->newFields = $properties['fields']; - unset($properties['fields']); - $object->setProperties($properties); - - return $object; - } - public function getUniqueIdentifier() { return $this->getObjectName(); diff --git a/library/Director/Objects/ImportExportHelper.php b/library/Director/Objects/ImportExportHelper.php deleted file mode 100644 index 98d34c6..0000000 --- a/library/Director/Objects/ImportExportHelper.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php - -namespace Icinga\Module\Director\Objects; - -use Icinga\Module\Director\Db; - -/** - * Helper class, allows to reduce duplicate code. Might be moved elsewhere - * afterwards - */ -class ImportExportHelper -{ - /** - * Does not support every type out of the box - * - * @param IcingaObject $object - * @return object - * @throws \Icinga\Exception\NotFoundError - */ - public static function simpleExport(IcingaObject $object) - { - $props = (array) $object->toPlainObject(); - $props['fields'] = static::fetchFields($object); - ksort($props); // TODO: ksort in toPlainObject? - - return (object) $props; - } - - public static function fetchFields(IcingaObject $object) - { - return static::loadFieldReferences( - $object->getConnection(), - $object->getShortTableName(), - $object->get('id') - ); - } - - /** - * @param Db $connection - * @param string $type Warning: this will not be validated. - * @param int $id - * @return array - */ - public static function loadFieldReferences(Db $connection, $type, $id) - { - $db = $connection->getDbAdapter(); - $res = $db->fetchAll( - $db->select()->from([ - 'f' => "icinga_${type}_field" - ], [ - 'f.datafield_id', - 'f.is_required', - 'f.var_filter', - ])->join(['df' => 'director_datafield'], 'df.id = f.datafield_id', []) - ->where("${type}_id = ?", $id) - ->order('varname ASC') - ); - - if (empty($res)) { - return []; - } - - foreach ($res as $field) { - $field->datafield_id = (int) $field->datafield_id; - } - return $res; - } -} diff --git a/library/Director/Objects/ImportRowModifier.php b/library/Director/Objects/ImportRowModifier.php index 76982c2..afebbad 100644 --- a/library/Director/Objects/ImportRowModifier.php +++ b/library/Director/Objects/ImportRowModifier.php @@ -18,13 +18,14 @@ class ImportRowModifier extends DbObjectWithSettings implements InstantiatedViaH protected $autoincKeyName = 'id'; protected $defaultProperties = [ - 'id' => null, - 'source_id' => null, - 'property_name' => null, - 'provider_class' => null, - 'target_property' => null, - 'priority' => null, - 'description' => null, + 'id' => null, + 'source_id' => null, + 'property_name' => null, + 'provider_class' => null, + 'target_property' => null, + 'filter_expression' => null, + 'priority' => null, + 'description' => null, ]; protected $settingsTable = 'import_row_modifier_setting'; diff --git a/library/Director/Objects/ImportSource.php b/library/Director/Objects/ImportSource.php index fd892ef..7477472 100644 --- a/library/Director/Objects/ImportSource.php +++ b/library/Director/Objects/ImportSource.php @@ -3,12 +3,14 @@ namespace Icinga\Module\Director\Objects; use Icinga\Application\Benchmark; +use Icinga\Data\Filter\Filter; use Icinga\Exception\NotFoundError; use Icinga\Module\Director\Application\MemoryLimit; use Icinga\Module\Director\Data\Db\DbObjectWithSettings; use Icinga\Module\Director\Db; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; use Icinga\Module\Director\Exception\DuplicateKeyException; +use Icinga\Module\Director\Filter\FilterEnrichment; use Icinga\Module\Director\Hook\PropertyModifierHook; use Icinga\Module\Director\Import\Import; use Icinga\Module\Director\Import\SyncUtils; @@ -52,68 +54,6 @@ class ImportSource extends DbObjectWithSettings implements ExportInterface private $newRowModifiers; - /** - * @deprecated please use \Icinga\Module\Director\Data\FieldReferenceLoader - * @return \stdClass - */ - public function export() - { - $plain = $this->getProperties(); - $plain['originalId'] = $plain['id']; - unset($plain['id']); - - foreach ($this->stateProperties as $key) { - unset($plain[$key]); - } - - $plain['settings'] = (object) $this->getSettings(); - $plain['modifiers'] = $this->exportRowModifiers(); - ksort($plain); - - return (object) $plain; - } - - /** - * @param $plain - * @param Db $db - * @param bool $replace - * @return ImportSource - * @throws DuplicateKeyException - * @throws NotFoundError - */ - public static function import($plain, Db $db, $replace = false) - { - $properties = (array) $plain; - if (isset($properties['originalId'])) { - $id = $properties['originalId']; - unset($properties['originalId']); - } else { - $id = null; - } - $name = $properties['source_name']; - - if ($replace && $id && static::existsWithNameAndId($name, $id, $db)) { - $object = static::loadWithAutoIncId($id, $db); - } elseif ($replace && static::exists($name, $db)) { - $object = static::load($name, $db); - } elseif (static::existsWithName($name, $db)) { - throw new DuplicateKeyException( - 'Import Source %s already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - if (! isset($properties['modifiers'])) { - $properties['modifiers'] = []; - } - - $object->setProperties($properties); - - return $object; - } - public function setModifiers(array $modifiers) { if ($this->loadedRowModifiers === null && $this->hasBeenLoadedFromDb()) { @@ -314,10 +254,14 @@ class ImportSource extends DbObjectWithSettings implements ExportInterface foreach ($modifiers as $modPair) { /** @var PropertyModifierHook $modifier */ - list($property, $modifier) = $modPair; + /** @var ?Filter $filter */ + list($property, $modifier, $filter) = $modPair; $rejected = []; $newRows = []; foreach ($data as $key => $row) { + if ($filter && ! $filter->matches($row)) { + continue; + } $this->applyPropertyModifierToRow($modifier, $property, $row); if ($modifier->rejectsRow()) { $rejected[] = $key; @@ -434,7 +378,12 @@ class ImportSource extends DbObjectWithSettings implements ExportInterface { $mods = []; foreach ($this->fetchRowModifiers() as $mod) { - $mods[] = [$mod->get('property_name'), $mod->getInstance()]; + if ($filterExpression = $mod->get('filter_expression')) { + $filter = FilterEnrichment::enrichFilter(Filter::fromQueryString($filterExpression)); + } else { + $filter = null; + } + $mods[] = [$mod->get('property_name'), $mod->getInstance(), $filter]; } return $mods; @@ -530,7 +479,7 @@ class ImportSource extends DbObjectWithSettings implements ExportInterface protected function raiseLimits() { MemoryLimit::raiseTo('1024M'); - ini_set('max_execution_time', 0); + ini_set('max_execution_time', '0'); return $this; } diff --git a/library/Director/Objects/ObjectApplyMatches.php b/library/Director/Objects/ObjectApplyMatches.php index 018c880..d749d6a 100644 --- a/library/Director/Objects/ObjectApplyMatches.php +++ b/library/Director/Objects/ObjectApplyMatches.php @@ -172,7 +172,7 @@ abstract class ObjectApplyMatches $col = $filter->getColumn(); $type = static::$type; - if ($type && substr($col, 0, strlen($type) + 1) === "${type}.") { + if ($type && substr($col, 0, strlen($type) + 1) === "{$type}.") { $filter->setColumn($col = substr($col, strlen($type) + 1)); } diff --git a/library/Director/Objects/SyncRule.php b/library/Director/Objects/SyncRule.php index 89f7fd1..270a882 100644 --- a/library/Director/Objects/SyncRule.php +++ b/library/Director/Objects/SyncRule.php @@ -43,6 +43,10 @@ class SyncRule extends DbObject implements ExportInterface 'last_attempt', ]; + protected $booleans = [ + 'purge_existing' => 'purge_existing', + ]; + private $sync; private $purgeStrategy; @@ -60,8 +64,6 @@ class SyncRule extends DbObject implements ExportInterface private $newSyncProperties; - private $originalId; - public function listInvolvedSourceIds() { if (! $this->hasBeenLoadedFromDb()) { @@ -257,61 +259,13 @@ class SyncRule extends DbObject implements ExportInterface } /** - * @deprecated please use \Icinga\Module\Director\Data\Exporter - * @return object - */ - public function export() - { - $plain = $this->getProperties(); - $plain['originalId'] = $plain['id']; - unset($plain['id']); - - foreach ($this->stateProperties as $key) { - unset($plain[$key]); - } - $plain['properties'] = $this->exportSyncProperties(); - ksort($plain); - - return (object) $plain; - } - - /** - * @param object $plain - * @param Db $db - * @param bool $replace - * @return static - * @throws DuplicateKeyException - * @throws \Icinga\Exception\NotFoundError + * Flat object has 'properties', but setProperties() is not available in DbObject + * + * @return void */ - public static function import($plain, Db $db, $replace = false) + public function setSyncProperties(?array $value) { - $properties = (array) $plain; - if (isset($properties['originalId'])) { - $id = $properties['originalId']; - unset($properties['originalId']); - } else { - $id = null; - } - $name = $properties['rule_name']; - - if ($replace && $id && static::existsWithNameAndId($name, $id, $db)) { - $object = static::loadWithAutoIncId($id, $db); - } elseif ($replace && static::exists($name, $db)) { - $object = static::load($name, $db); - } elseif (static::existsWithName($name, $db)) { - throw new DuplicateKeyException( - 'Sync Rule %s already exists', - $name - ); - } else { - $object = static::create([], $db); - } - - $object->newSyncProperties = $properties['properties']; - unset($properties['properties']); - $object->setProperties($properties); - - return $object; + $this->newSyncProperties = $value; } public function getUniqueIdentifier() @@ -329,12 +283,6 @@ class SyncRule extends DbObject implements ExportInterface $connection = $this->getConnection(); $db = $connection->getDbAdapter(); $myId = $this->get('id'); - if ($this->originalId === null) { - $originalId = $myId; - } else { - $originalId = $this->originalId; - $this->originalId = null; - } if ($this->hasBeenLoadedFromDb()) { $db->delete( 'sync_property', diff --git a/library/Director/PlainObjectRenderer.php b/library/Director/PlainObjectRenderer.php index 4dadf4f..e613f1f 100644 --- a/library/Director/PlainObjectRenderer.php +++ b/library/Director/PlainObjectRenderer.php @@ -105,7 +105,7 @@ class PlainObjectRenderer } elseif (is_string($object)) { return self::renderString($object); } else { - return '(UNKNOWN TYPE) ' . var_export($object, 1); + return '(UNKNOWN TYPE) ' . var_export($object, true); } } diff --git a/library/Director/PropertyModifier/PropertyModifierArrayFilter.php b/library/Director/PropertyModifier/PropertyModifierArrayFilter.php index 0b52987..a8fcbf7 100644 --- a/library/Director/PropertyModifier/PropertyModifierArrayFilter.php +++ b/library/Director/PropertyModifier/PropertyModifierArrayFilter.php @@ -116,7 +116,7 @@ class PropertyModifierArrayFilter extends PropertyModifierHook default: throw new ConfigurationError( '%s is not a valid value for an ArrayFilter filter_method', - var_export($method, 1) + var_export($method, true) ); } diff --git a/library/Director/PropertyModifier/PropertyModifierExtractFromDN.php b/library/Director/PropertyModifier/PropertyModifierExtractFromDN.php index c79c5b2..6b0651d 100644 --- a/library/Director/PropertyModifier/PropertyModifierExtractFromDN.php +++ b/library/Director/PropertyModifier/PropertyModifierExtractFromDN.php @@ -74,7 +74,7 @@ class PropertyModifierExtractFromDN extends PropertyModifierHook default: throw new InvalidPropertyException( 'DN part extraction failed for %s', - var_export($value, 1) + var_export($value, true) ); } } diff --git a/library/Director/PropertyModifier/PropertyModifierGetHostByName.php b/library/Director/PropertyModifier/PropertyModifierGetHostByName.php index 36884e8..d7921de 100644 --- a/library/Director/PropertyModifier/PropertyModifierGetHostByName.php +++ b/library/Director/PropertyModifier/PropertyModifierGetHostByName.php @@ -34,7 +34,8 @@ class PropertyModifierGetHostByName extends PropertyModifierHook } $host = gethostbyname($value); - if (strlen(@inet_pton($host)) !== 4) { + $inAddr = inet_pton($host); + if (! $inAddr || strlen($inAddr) !== 4) { switch ($this->getSetting('on_failure')) { case 'null': return null; diff --git a/library/Director/PropertyModifier/PropertyModifierJsonDecode.php b/library/Director/PropertyModifier/PropertyModifierJsonDecode.php index f6b9af8..4ab119a 100644 --- a/library/Director/PropertyModifier/PropertyModifierJsonDecode.php +++ b/library/Director/PropertyModifier/PropertyModifierJsonDecode.php @@ -2,8 +2,9 @@ namespace Icinga\Module\Director\PropertyModifier; +use Exception; +use gipfl\Json\JsonString; use Icinga\Exception\InvalidPropertyException; -use Icinga\Module\Director\Exception\JsonException; use Icinga\Module\Director\Hook\PropertyModifierHook; use Icinga\Module\Director\Web\Form\QuickForm; @@ -38,16 +39,22 @@ class PropertyModifierJsonDecode extends PropertyModifierHook /** * @param $value * @return mixed|null - * @throws InvalidPropertyException + * @throws InvalidPropertyException|\gipfl\Json\JsonDecodeException */ public function transform($value) { if (null === $value) { - return $value; + return null; } - - $decoded = @json_decode($value); - if ($decoded === null && JSON_ERROR_NONE !== json_last_error()) { + try { + if (is_string($value)) { + $decoded = JsonString::decode($value); + } else { + throw new InvalidPropertyException( + 'JSON decode expects a string, got ' . gettype($value) + ); + } + } catch (Exception $e) { switch ($this->getSetting('on_failure')) { case 'null': return null; @@ -55,11 +62,7 @@ class PropertyModifierJsonDecode extends PropertyModifierHook return $value; case 'fail': default: - throw new InvalidPropertyException( - 'JSON decoding failed with "%s" for %s', - JsonException::getJsonErrorMessage(json_last_error()), - substr($value, 0, 128) - ); + throw $e; } } diff --git a/library/Director/PropertyModifier/PropertyModifierMap.php b/library/Director/PropertyModifier/PropertyModifierMap.php index a6cb422..e411c54 100644 --- a/library/Director/PropertyModifier/PropertyModifierMap.php +++ b/library/Director/PropertyModifier/PropertyModifierMap.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Director\PropertyModifier; use Icinga\Exception\InvalidPropertyException; use Icinga\Module\Director\Hook\PropertyModifierHook; +use Icinga\Module\Director\Import\SyncUtils; use Icinga\Module\Director\Web\Form\QuickForm; class PropertyModifierMap extends PropertyModifierHook @@ -30,15 +31,37 @@ class PropertyModifierMap extends PropertyModifierHook . ' or interrupt the import process' ), 'multiOptions' => $form->optionalEnum(array( - 'null' => $form->translate('Set null'), - 'keep' => $form->translate('Return lookup key unmodified'), - 'fail' => $form->translate('Let the import fail'), + 'null' => $form->translate('Set null'), + 'keep' => $form->translate('Return lookup key unmodified'), + 'custom' => $form->translate('Return custom default value'), + 'fail' => $form->translate('Let the import fail'), )), + 'class' => 'autosubmit', )); + $method = $form->getSetting('on_missing'); + if ($method == 'custom') { + $form->addElement('text', 'custom_value', array( + 'label' => $form->translate('Default value'), + 'required' => true, + 'description' => $form->translate( + 'This value will be evaluated, and variables like ${some_column}' + . ' will be filled accordingly. A typical use-case is generating' + . ' unique service identifiers via ${host}!${service} in case your' + . ' data source doesn\'t allow you to ship such. The chosen "property"' + . ' has no effect here and will be ignored.' + ) + )); + } + // TODO: ignore case } + public function requiresRow() + { + return true; + } + public function transform($value) { $this->loadCache(); @@ -53,6 +76,9 @@ class PropertyModifierMap extends PropertyModifierHook case 'keep': return $value; + case 'custom': + return SyncUtils::fillVariables($this->getSetting('custom_value'), $this->getRow()); + case 'fail': default: throw new InvalidPropertyException( diff --git a/library/Director/PropertyModifier/PropertyModifierRegexReplace.php b/library/Director/PropertyModifier/PropertyModifierRegexReplace.php index 59cb245..eeae69e 100644 --- a/library/Director/PropertyModifier/PropertyModifierRegexReplace.php +++ b/library/Director/PropertyModifier/PropertyModifierRegexReplace.php @@ -9,25 +9,36 @@ class PropertyModifierRegexReplace extends PropertyModifierHook { public static function addSettingsFormFields(QuickForm $form) { - $form->addElement('text', 'pattern', array( - 'label' => 'Regex pattern', + $form->addElement('text', 'pattern', [ + 'label' => $form->translate('Regex pattern'), 'description' => $form->translate( 'The pattern you want to search for. This can be a regular expression like /^www\d+\./' ), 'required' => true, - )); + ]); - $form->addElement('text', 'replacement', array( - 'label' => 'Replacement', + $form->addElement('text', 'replacement', [ + 'label' => $form->translate('Replacement'), 'description' => $form->translate( - 'The string that should be used as a preplacement' + 'The string that should be used as a replacement' ), - )); + ]); + $form->addElement('select', 'when_not_matched', [ + 'label' => $form->translate('When not matched'), + 'description' => $form->translate( + "What should happen, if the given pattern doesn't match" + ), + 'value' => 'keep', + 'multiOptions' => [ + 'keep' => $form->translate('Keep the given string'), + 'set_null' => $form->translate('Set the value to NULL') + ] + ]); } public function getName() { - return 'Regular expression based replacement'; + return mt('director', 'Regular expression based replacement'); } public function transform($value) @@ -36,10 +47,13 @@ class PropertyModifierRegexReplace extends PropertyModifierHook return null; } - return preg_replace( - $this->getSetting('pattern'), - $this->getSetting('replacement'), - $value - ); + $result = preg_replace($this->getSetting('pattern'), $this->getSetting('replacement'), $value); + if ($result === $value && $this->getSetting('when_not_matched', 'keep') === 'set_null') { + if (!preg_match($this->getSetting('pattern'), $value)) { + return null; + } + } + + return $result; } } diff --git a/library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php b/library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php index 1485d5d..04c49c5 100644 --- a/library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php +++ b/library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php @@ -128,7 +128,7 @@ class PropertyModifierRejectOrSelect extends PropertyModifierHook default: throw new ConfigurationError( '%s is not a valid value for an ArrayFilter filter_method', - var_export($method, 1) + var_export($method, true) ); } diff --git a/library/Director/PropertyModifier/PropertyModifierSplit.php b/library/Director/PropertyModifier/PropertyModifierSplit.php index 4a6fef6..3eec77d 100644 --- a/library/Director/PropertyModifier/PropertyModifierSplit.php +++ b/library/Director/PropertyModifier/PropertyModifierSplit.php @@ -33,7 +33,7 @@ class PropertyModifierSplit extends PropertyModifierHook public function transform($value) { - if (! strlen(trim($value))) { + if ($value === null || ! strlen(trim($value))) { if ($this->getSetting('when_empty', 'empty_array') === 'empty_array') { return array(); } else { diff --git a/library/Director/ProvidedHook/IcingaDbCubeLinks.php b/library/Director/ProvidedHook/IcingaDbCubeLinks.php index 234f61f..f3fe402 100644 --- a/library/Director/ProvidedHook/IcingaDbCubeLinks.php +++ b/library/Director/ProvidedHook/IcingaDbCubeLinks.php @@ -7,6 +7,7 @@ use Icinga\Exception\ProgrammingError; use Icinga\Module\Cube\Hook\IcingaDbActionsHook; use Icinga\Module\Cube\IcingaDb\IcingaDbCube; use Icinga\Module\Cube\IcingaDb\IcingaDbHostStatusCube; +use ipl\Stdlib\Filter\Condition; class IcingaDbCubeLinks extends IcingaDbActionsHook { @@ -25,17 +26,19 @@ class IcingaDbCubeLinks extends IcingaDbActionsHook if ($filterChain->count() === 1) { $url = 'director/host/edit?'; - $params = ['name' => $filterChain->getIterator()->current()->getValue()]; + /** @var Condition $rule */ + $rule = $filterChain->getIterator()->current(); + /** @var string $name */ + $name = $rule->getValue(); + $params = ['name' => $name]; $title = t('Modify a host'); - $description = sprintf( - t('This allows you to modify properties for "%s"'), - $filterChain->getIterator()->current()->getValue() - ); + $description = sprintf(t('This allows you to modify properties for "%s"'), $name); } else { $params = null; $urlFilter = Filter::matchAny(); + /** @var Condition $filter */ foreach ($filterChain as $filter) { $urlFilter->addFilter( Filter::matchAny( diff --git a/library/Director/ProvidedHook/Icingadb/HostActions.php b/library/Director/ProvidedHook/Icingadb/HostActions.php new file mode 100644 index 0000000..d7332ea --- /dev/null +++ b/library/Director/ProvidedHook/Icingadb/HostActions.php @@ -0,0 +1,78 @@ +<?php + +namespace Icinga\Module\Director\ProvidedHook\Icingadb; + +use Exception; +use Icinga\Application\Config; +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Db; +use Icinga\Module\Director\Integration\Icingadb\IcingadbBackend; +use Icinga\Module\Director\Objects\IcingaHost; +use Icinga\Module\Director\Util; +use Icinga\Module\Icingadb\Hook\HostActionsHook; +use Icinga\Module\Icingadb\Model\Host; +use ipl\Web\Url; +use ipl\Web\Widget\Link; + +class HostActions extends HostActionsHook +{ + public function getActionsForObject(Host $host): array + { + try { + return $this->getThem($host); + } catch (Exception $e) { + return []; + } + } + + protected function getThem(Host $host): array + { + $actions = []; + $db = $this->db(); + if (! $db) { + return $actions; + } + $hostname = $host->name; + if (Util::hasPermission(Permission::INSPECT)) { + $actions[] = new Link( + mt('director', 'Inspect'), + Url::fromPath( + 'director/inspect/object', + ['type' => 'host', 'plural' => 'hosts', 'name' => $hostname] + ) + ); + } + + $allowEdit = false; + if (Util::hasPermission(Permission::HOSTS) && IcingaHost::exists($hostname, $db)) { + $allowEdit = true; + } + if (Util::hasPermission(Permission::ICINGADB_HOSTS)) { + if ((new IcingadbBackend())->canModifyHost($hostname)) { + $allowEdit = IcingaHost::exists($hostname, $db); + } + } + + if ($allowEdit) { + $label = mt('director', 'Modify'); + $actions[] = new Link( + $label, + Url::fromPath('director/host/edit', [ + 'name' => $hostname + ]) + ); + } + + return $actions; + } + + protected function db() + { + $resourceName = Config::module('director')->get('db', 'resource'); + if (! $resourceName) { + return false; + } + + return Db::fromResourceName($resourceName); + } +} diff --git a/library/Director/ProvidedHook/Icingadb/IcingadbSupport.php b/library/Director/ProvidedHook/Icingadb/IcingadbSupport.php new file mode 100644 index 0000000..5a59304 --- /dev/null +++ b/library/Director/ProvidedHook/Icingadb/IcingadbSupport.php @@ -0,0 +1,10 @@ +<?php + +namespace Icinga\Module\Director\ProvidedHook\Icingadb; + +use Icinga\Module\Icingadb\Hook\IcingadbSupportHook; + +class IcingadbSupport extends IcingadbSupportHook +{ + +} diff --git a/library/Director/ProvidedHook/Icingadb/ServiceActions.php b/library/Director/ProvidedHook/Icingadb/ServiceActions.php new file mode 100644 index 0000000..1603dc3 --- /dev/null +++ b/library/Director/ProvidedHook/Icingadb/ServiceActions.php @@ -0,0 +1,87 @@ +<?php + +namespace Icinga\Module\Director\ProvidedHook\Icingadb; + +use Exception; +use Icinga\Application\Config; +use Icinga\Module\Director\Auth\Permission; +use Icinga\Module\Director\Db; +use Icinga\Module\Director\Integration\Icingadb\IcingadbBackend; +use Icinga\Module\Director\Objects\IcingaHost; +use Icinga\Module\Director\Util; +use Icinga\Module\Icingadb\Hook\ServiceActionsHook; +use Icinga\Module\Icingadb\Model\Service; +use ipl\Web\Url; +use ipl\Web\Widget\Link; + +class ServiceActions extends ServiceActionsHook +{ + public function getActionsForObject(Service $service): array + { + try { + return $this->getThem($service); + } catch (Exception $e) { + return []; + } + } + + /** + * @param Service $service + * @return array + * @throws \Icinga\Exception\ProgrammingError + */ + protected function getThem(Service $service) + { + $actions = []; + $db = $this->db(); + if (! $db) { + return []; + } + + $hostname = $service->host->name; + $serviceName = $service->name; + if (Util::hasPermission(Permission::INSPECT)) { + $actions[] = new Link( + mt('director', 'Inspect'), + Url::fromPath('director/inspect/object', [ + 'type' => 'service', + 'plural' => 'services', + 'name' => sprintf('%s!%s', $hostname, $serviceName) + ]) + ); + } + + $title = null; + if (Util::hasPermission(Permission::HOSTS)) { + $title = mt('director', 'Modify'); + } elseif (Util::hasPermission(Permission::ICINGADB_SERVICES)) { + if ((new IcingadbBackend())->canModifyService($hostname, $serviceName)) { + $title = mt('director', 'Modify'); + } + } elseif (Util::hasPermission(Permission::ICINGADB_SERVICES_RO)) { + $title = mt('director', 'Configuration'); + } + + if ($title && IcingaHost::exists($hostname, $db)) { + $actions[] = new Link( + $title, + Url::fromPath('director/host/findservice', [ + 'name' => $hostname, + 'service' => $serviceName + ]) + ); + } + + return $actions; + } + + protected function db() + { + $resourceName = Config::module('director')->get('db', 'resource'); + if (! $resourceName) { + return false; + } + + return Db::fromResourceName($resourceName); + } +} diff --git a/library/Director/ProvidedHook/Monitoring/HostActions.php b/library/Director/ProvidedHook/Monitoring/HostActions.php index 2e3fba0..2d0469d 100644 --- a/library/Director/ProvidedHook/Monitoring/HostActions.php +++ b/library/Director/ProvidedHook/Monitoring/HostActions.php @@ -5,8 +5,9 @@ namespace Icinga\Module\Director\ProvidedHook\Monitoring; use Exception; use Icinga\Application\Config; use Icinga\Authentication\Auth; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Db; -use Icinga\Module\Director\Monitoring; +use Icinga\Module\Director\Integration\MonitoringModule\Monitoring; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Util; use Icinga\Module\Monitoring\Hook\HostActionsHook; @@ -32,7 +33,7 @@ class HostActions extends HostActionsHook return $actions; } $hostname = $host->host_name; - if (Util::hasPermission('director/inspect')) { + if (Util::hasPermission(Permission::INSPECT)) { $actions[mt('director', 'Inspect')] = Url::fromPath( 'director/inspect/object', array('type' => 'host', 'plural' => 'hosts', 'name' => $hostname) @@ -40,22 +41,17 @@ class HostActions extends HostActionsHook } $allowEdit = false; - if (Util::hasPermission('director/hosts') && IcingaHost::exists($hostname, $db)) { + if (Util::hasPermission(Permission::HOSTS) && IcingaHost::exists($hostname, $db)) { $allowEdit = true; } - $auth = Auth::getInstance(); - if (Util::hasPermission('director/monitoring/hosts')) { - $monitoring = new Monitoring(); - if ($monitoring->isAvailable() && $monitoring->authCanEditHost($auth, $hostname)) { + if (Util::hasPermission(Permission::MONITORING_HOSTS)) { + if ((new Monitoring(Auth::getInstance()))->canModifyHost($hostname)) { $allowEdit = IcingaHost::exists($hostname, $db); } } if ($allowEdit) { - $actions[mt('director', 'Modify')] = Url::fromPath( - 'director/host/edit', - array('name' => $hostname) - ); + $actions[mt('director', 'Modify')] = Url::fromPath('director/host/edit', ['name' => $hostname]); } return $actions; diff --git a/library/Director/ProvidedHook/Monitoring/ServiceActions.php b/library/Director/ProvidedHook/Monitoring/ServiceActions.php index b2e303a..834b166 100644 --- a/library/Director/ProvidedHook/Monitoring/ServiceActions.php +++ b/library/Director/ProvidedHook/Monitoring/ServiceActions.php @@ -5,8 +5,9 @@ namespace Icinga\Module\Director\ProvidedHook\Monitoring; use Exception; use Icinga\Application\Config; use Icinga\Authentication\Auth; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Db; -use Icinga\Module\Director\Monitoring; +use Icinga\Module\Director\Integration\MonitoringModule\Monitoring; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Util; use Icinga\Module\Monitoring\Hook\ServiceActionsHook; @@ -39,7 +40,7 @@ class ServiceActions extends ServiceActionsHook $hostname = $service->host_name; $serviceName = $service->service_description; - if (Util::hasPermission('director/inspect')) { + if (Util::hasPermission(Permission::INSPECT)) { $actions[mt('director', 'Inspect')] = Url::fromPath('director/inspect/object', [ 'type' => 'service', 'plural' => 'services', @@ -52,16 +53,13 @@ class ServiceActions extends ServiceActionsHook } $title = null; - if (Util::hasPermission('director/hosts')) { + if (Util::hasPermission(Permission::HOSTS)) { $title = mt('director', 'Modify'); - } elseif (Util::hasPermission('director/monitoring/services')) { - $monitoring = new Monitoring(); - if ($monitoring->isAvailable() - && $monitoring->authCanEditService(Auth::getInstance(), $hostname, $serviceName) - ) { + } elseif (Util::hasPermission(Permission::MONITORING_SERVICES)) { + if ((new Monitoring(Auth::getInstance()))->canModifyService($hostname, $serviceName)) { $title = mt('director', 'Modify'); } - } elseif (Util::hasPermission('director/monitoring/services-ro')) { + } elseif (Util::hasPermission(Permission::MONITORING_SERVICES_RO)) { $title = mt('director', 'Configuration'); } diff --git a/library/Director/Resolver/CommandUsage.php b/library/Director/Resolver/CommandUsage.php index 7e3e0c5..49fc31b 100644 --- a/library/Director/Resolver/CommandUsage.php +++ b/library/Director/Resolver/CommandUsage.php @@ -75,7 +75,7 @@ class CommandUsage $suffix = $urlSuffix[$objectType]; $links[] = Link::create( sprintf($caption, $res->$objectType), - "director/${type}s$suffix", + "director/{$type}s$suffix", ['command' => $name] ); } @@ -96,7 +96,7 @@ class CommandUsage $query = $this->db->select()->from("icinga_$table", $columns); foreach ($rels as $rel) { - $query->orWhere("${rel}_id = ?", $id); + $query->orWhere("{$rel}_id = ?", $id); } return $this->db->fetchRow($query); diff --git a/library/Director/Resolver/IcingaObjectResolver.php b/library/Director/Resolver/IcingaObjectResolver.php index 540e2c2..c751476 100644 --- a/library/Director/Resolver/IcingaObjectResolver.php +++ b/library/Director/Resolver/IcingaObjectResolver.php @@ -176,7 +176,7 @@ class IcingaObjectResolver $object->groups = $groups; } - $templates = $this->getTemplateNamesById($id); + $templates = $this->getTemplateNamesByID($id); if (! empty($templates)) { $object->templates = \array_reverse($templates); } @@ -198,7 +198,7 @@ class IcingaObjectResolver } $query = $this->db->select() ->from([ - 'oi' => "${baseTable}_inheritance" + 'oi' => "{$baseTable}_inheritance" ], [ $relColumn, $groupColumn @@ -494,12 +494,12 @@ class IcingaObjectResolver { $type = $this->getType(); $groupsTable = $this->baseTable . 'group'; - $groupMembershipTable = "${groupsTable}_$type"; + $groupMembershipTable = "{$groupsTable}_$type"; if ($resolved) { $groupMembershipTable .= '_resolved'; } - $oRef = "${type}_id"; - $gRef = "${type}group_id"; + $oRef = "{$type}_id"; + $gRef = "{$type}group_id"; return $this->db->select() ->from(['gm' => $groupMembershipTable], [ diff --git a/library/Director/Resolver/TemplateTree.php b/library/Director/Resolver/TemplateTree.php index f8d8fed..bf941e2 100644 --- a/library/Director/Resolver/TemplateTree.php +++ b/library/Director/Resolver/TemplateTree.php @@ -80,13 +80,13 @@ class TemplateTree $map = []; $db = $this->db; $type = $this->type; - $table = "icinga_${type}_inheritance"; + $table = "icinga_{$type}_inheritance"; $query = $db->select()->from( ['i' => $table], [ - 'object' => "i.${type}_id", - 'parent' => "i.parent_${type}_id", + 'object' => "i.{$type}_id", + 'parent' => "i.parent_{$type}_id", ] )->order('i.weight'); @@ -439,12 +439,12 @@ class TemplateTree if ($type === 'command') { $joinCondition = $db->quoteInto( - "p.id = i.parent_${type}_id", + "p.id = i.parent_{$type}_id", 'template' ); } else { $joinCondition = $db->quoteInto( - "p.id = i.parent_${type}_id AND p.object_type = ?", + "p.id = i.parent_{$type}_id AND p.object_type = ?", 'template' ); } @@ -466,7 +466,7 @@ class TemplateTree ['p' => $table], $joinCondition, [] - )->order('o.id')->order('i.weight'); + )->order('o.object_name')->order('i.weight'); if ($type !== 'command') { $query->where( diff --git a/library/Director/RestApi/RestApiClient.php b/library/Director/RestApi/RestApiClient.php index 2ebc4d4..6dcf93c 100644 --- a/library/Director/RestApi/RestApiClient.php +++ b/library/Director/RestApi/RestApiClient.php @@ -8,7 +8,6 @@ use RuntimeException; class RestApiClient { - /** @var resource */ private $curl; /** @var string HTTP or HTTPS */ @@ -287,7 +286,7 @@ class RestApiClient if ($statusCode >= 400) { throw new RuntimeException( - "Got $statusCode: " . \var_export($res, 1) + "Got $statusCode: " . \var_export($res, true) ); } @@ -295,14 +294,14 @@ class RestApiClient } /** - * @return resource + * @throws RuntimeException */ protected function curl() { if ($this->curl === null) { - $this->curl = \curl_init(\sprintf('https://%s:%d', $this->host, $this->port)); + $this->curl = curl_init(sprintf('https://%s:%d', $this->host, $this->port)); if (! $this->curl) { - throw new RuntimeException('CURL INIT ERROR: ' . \curl_error($this->curl)); + throw new RuntimeException('CURL INIT FAILED'); } } diff --git a/library/Director/RestApi/RestApiParams.php b/library/Director/RestApi/RestApiParams.php index c237ac5..741eeed 100644 --- a/library/Director/RestApi/RestApiParams.php +++ b/library/Director/RestApi/RestApiParams.php @@ -19,8 +19,9 @@ class RestApiParams } $exporter->enableHostServices(); } + /** @var ?string $properties */ $properties = $params->shift('properties'); - if ($properties !== null && strlen($properties)) { + if ($properties) { $exporter->filterProperties(preg_split('/\s*,\s*/', $properties, -1, PREG_SPLIT_NO_EMPTY)); } $exporter->resolveObjects($resolved); diff --git a/library/Director/Restriction/FilterByNameRestriction.php b/library/Director/Restriction/FilterByNameRestriction.php index 8c3b256..aef28c4 100644 --- a/library/Director/Restriction/FilterByNameRestriction.php +++ b/library/Director/Restriction/FilterByNameRestriction.php @@ -30,7 +30,7 @@ class FilterByNameRestriction extends ObjectRestriction protected function setNameForType($type) { - $this->name = "director/${type}/filter-by-name"; + $this->name = "director/{$type}/filter-by-name"; } public function allows(IcingaObject $object) diff --git a/library/Director/Restriction/HostgroupRestriction.php b/library/Director/Restriction/HostgroupRestriction.php index 1a6792b..f2face4 100644 --- a/library/Director/Restriction/HostgroupRestriction.php +++ b/library/Director/Restriction/HostgroupRestriction.php @@ -2,7 +2,7 @@ namespace Icinga\Module\Director\Restriction; -use Icinga\Exception\ProgrammingError; +use Icinga\Module\Director\Auth\Restriction; use Icinga\Module\Director\Db\IcingaObjectFilterHelper; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaHostGroup; @@ -11,7 +11,7 @@ use Zend_Db_Select as ZfSelect; class HostgroupRestriction extends ObjectRestriction { - protected $name = 'director/filter/hostgroups'; + protected $name = Restriction::FILTER_HOSTGROUPS; public function allows(IcingaObject $object) { @@ -93,7 +93,7 @@ class HostgroupRestriction extends ObjectRestriction ['id'] )->where('id = ?', $hostgroup->id); - $this->filterHostGroupsQuery($query); + $this->filterHostGroupsQuery($query, 'h'); return (int) $this->db->fetchOne($query) === (int) $hostgroup->get('id'); } @@ -141,7 +141,7 @@ class HostgroupRestriction extends ObjectRestriction if (empty($groups)) { $query->where('(1 = 0)'); } else { - $query->where("${tableAlias}.object_name IN (?)", $groups); + $query->where("{$tableAlias}.object_name IN (?)", $groups); } } diff --git a/library/Director/StartupLogRenderer.php b/library/Director/StartupLogRenderer.php index bc7b3ea..9d5810f 100644 --- a/library/Director/StartupLogRenderer.php +++ b/library/Director/StartupLogRenderer.php @@ -33,7 +33,9 @@ class StartupLogRenderer implements ValidHtml // len [stage] + 1 $markReplace = ' ^'; - foreach (preg_split('/\n/', $log) as $line) { + /** @var string[] $logLines */ + $logLines = preg_split('/\n/', $log); + foreach ($logLines as $line) { if (preg_match('/^\[([\d\s\:\+\-]+)\]\s/', $line, $m)) { $time = $m[1]; // TODO: we might use new DateTime($time) and show a special "timeAgo" @@ -83,9 +85,9 @@ class StartupLogRenderer implements ValidHtml } if ($time === null) { - $lines[] .= $line; + $lines[] = $line; } else { - $lines[] .= "[$time] $line"; + $lines[] = "[$time] $line"; } } return implode("\n", $lines); diff --git a/library/Director/Test/BaseTestCase.php b/library/Director/Test/BaseTestCase.php index 611805b..f0cf8e5 100644 --- a/library/Director/Test/BaseTestCase.php +++ b/library/Director/Test/BaseTestCase.php @@ -10,20 +10,15 @@ use Icinga\Module\Director\Db; use Icinga\Module\Director\Db\Migrations; use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Objects\IcingaZone; -use PHPUnit_Framework_TestCase; +use Icinga\Test\BaseTestCase as IcingaBaseTestCase; -abstract class BaseTestCase extends PHPUnit_Framework_TestCase +abstract class BaseTestCase extends IcingaBaseTestCase { private static $app; /** @var Db */ private static $db; - public function setUp() - { - $this->app(); - } - protected function skipForMissingDb() { if ($this->hasDb()) { @@ -69,6 +64,9 @@ abstract class BaseTestCase extends PHPUnit_Framework_TestCase if (array_key_exists('DIRECTOR_TESTDB_HOST', $_SERVER)) { $dbConfig->host = $_SERVER['DIRECTOR_TESTDB_HOST']; } + if (array_key_exists('DIRECTOR_TESTDB_PORT', $_SERVER)) { + $dbConfig->port = $_SERVER['DIRECTOR_TESTDB_PORT']; + } if (array_key_exists('DIRECTOR_TESTDB_USER', $_SERVER)) { $dbConfig->username = $_SERVER['DIRECTOR_TESTDB_USER']; } @@ -78,11 +76,14 @@ abstract class BaseTestCase extends PHPUnit_Framework_TestCase self::$db = new Db($dbConfig); $migrations = new Migrations(self::$db); $migrations->applyPendingMigrations(); - IcingaZone::create([ + $zone = IcingaZone::create([ 'object_name' => 'director-global', 'object_type' => 'external_object', 'is_global' => 'y' - ])->store(self::$db); + ]); + if (! IcingaZone::exists($zone->getId(), self::$db)) { + $zone->store(self::$db); + } } return self::$db; diff --git a/library/Director/Test/IcingaObjectTestCase.php b/library/Director/Test/IcingaObjectTestCase.php index a37fced..5d0dde3 100644 --- a/library/Director/Test/IcingaObjectTestCase.php +++ b/library/Director/Test/IcingaObjectTestCase.php @@ -76,7 +76,7 @@ abstract class IcingaObjectTestCase extends BaseTestCase /** * @inheritdoc */ - public function tearDown() + public function tearDown(): void { if ($this->hasDb()) { /** @var IcingaObject $object */ @@ -88,5 +88,7 @@ abstract class IcingaObjectTestCase extends BaseTestCase $this->subject->delete(); } } + + parent::tearDown(); } } diff --git a/library/Director/Test/SyncTest.php b/library/Director/Test/SyncTest.php index 7614ff9..d118eea 100644 --- a/library/Director/Test/SyncTest.php +++ b/library/Director/Test/SyncTest.php @@ -29,8 +29,9 @@ abstract class SyncTest extends BaseTestCase /** @var Sync */ protected $sync; - public function setUp() + public function setUp(): void { + parent::setUp(); $this->source = ImportSource::create(array( 'source_name' => 'testimport', 'provider_class' => 'Icinga\\Module\\Director\\Test\\ImportSourceDummy', @@ -49,7 +50,7 @@ abstract class SyncTest extends BaseTestCase $this->sync = new Sync($this->rule); } - public function tearDown() + public function tearDown(): void { // properties should be deleted automatically if ($this->rule !== null && $this->rule->hasBeenLoadedFromDb()) { @@ -75,6 +76,7 @@ abstract class SyncTest extends BaseTestCase // make sure cache is clean for other tests PrefetchCache::forget(); DbObject::clearAllPrefetchCaches(); + parent::tearDown(); } /** diff --git a/library/Director/Test/TestSuiteLint.php b/library/Director/Test/TestSuiteLint.php index 41941eb..0010c28 100644 --- a/library/Director/Test/TestSuiteLint.php +++ b/library/Director/Test/TestSuiteLint.php @@ -10,6 +10,8 @@ class TestSuiteLint extends TestSuite protected $failed; + protected $result = []; + public function run() { $this->checked = $this->failed = array(); diff --git a/library/Director/Test/TestSuiteUnit.php b/library/Director/Test/TestSuiteUnit.php index 8156eba..93dc692 100644 --- a/library/Director/Test/TestSuiteUnit.php +++ b/library/Director/Test/TestSuiteUnit.php @@ -4,6 +4,8 @@ namespace Icinga\Module\Director\Test; abstract class TestSuiteUnit { + private $testdoxFile; + public function run() { } @@ -15,7 +17,7 @@ abstract class TestSuiteUnit public function __destruct() { if ($this->testdoxFile && file_exists($this->testdoxFile)) { - unlink($this->testDoxfile); + unlink($this->testdoxFile); } } diff --git a/library/Director/Web/Controller/ActionController.php b/library/Director/Web/Controller/ActionController.php index 6282a16..e851d82 100644 --- a/library/Director/Web/Controller/ActionController.php +++ b/library/Director/Web/Controller/ActionController.php @@ -4,10 +4,14 @@ namespace Icinga\Module\Director\Web\Controller; use gipfl\Translation\StaticTranslator; use Icinga\Application\Benchmark; +use Icinga\Application\Modules\Module; use Icinga\Data\Paginatable; use Icinga\Exception\NotFoundError; use Icinga\Exception\ProgrammingError; -use Icinga\Module\Director\Monitoring; +use Icinga\Module\Director\Integration\Icingadb\IcingadbBackend; +use Icinga\Module\Director\Integration\BackendInterface; +use Icinga\Module\Director\Integration\MonitoringModule\Monitoring; +use Icinga\Module\Director\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Director\Web\Controller\Extension\CoreApi; use Icinga\Module\Director\Web\Controller\Extension\DirectorDb; use Icinga\Module\Director\Web\Controller\Extension\RestApi; @@ -36,8 +40,8 @@ abstract class ActionController extends Controller implements ControlsAndContent /** @var UrlParams Hint for IDE, somehow does not work in web */ protected $params; - /** @var Monitoring */ - private $monitoring; + /** @var BackendInterface */ + private $backend; /** * @throws SecurityException @@ -219,7 +223,7 @@ abstract class ActionController extends Controller implements ControlsAndContent // Hint -> $this->view->compact is the only way since v2.8.0 if ($this->view->compact || $this->getOriginalUrl()->getParam('view') === 'compact') { if ($this->view->controls) { - $this->controls()->getAttributes()->add('style', 'display: none;'); + $this->controls()->getAttributes()->add('class', 'compact'); } } } else { @@ -240,14 +244,18 @@ abstract class ActionController extends Controller implements ControlsAndContent } /** - * @return Monitoring + * @return BackendInterface */ - protected function monitoring() + protected function backend(): BackendInterface { - if ($this->monitoring === null) { - $this->monitoring = new Monitoring; + if ($this->backend === null) { + if (Module::exists('icingadb') && IcingadbSupport::useIcingaDbAsBackend()) { + $this->backend = new IcingadbBackend(); + } else { + $this->backend = new Monitoring($this->getAuth()); + } } - return $this->monitoring; + return $this->backend; } } diff --git a/library/Director/Web/Controller/BranchHelper.php b/library/Director/Web/Controller/BranchHelper.php index ac2a480..89aa6c1 100644 --- a/library/Director/Web/Controller/BranchHelper.php +++ b/library/Director/Web/Controller/BranchHelper.php @@ -3,12 +3,13 @@ namespace Icinga\Module\Director\Web\Controller; use Icinga\Module\Director\Data\Db\DbObjectStore; -use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry; use Icinga\Module\Director\Db\Branch\Branch; use Icinga\Module\Director\Db\Branch\BranchStore; use Icinga\Module\Director\Db\Branch\BranchSupport; +use Icinga\Module\Director\Db\Branch\PreferredBranchSupport; use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Web\Widget\NotInBranchedHint; +use Ramsey\Uuid\UuidInterface; trait BranchHelper { @@ -18,15 +19,21 @@ trait BranchHelper /** @var BranchStore */ protected $branchStore; + /** @var ?bool */ + protected $hasPreferredBranch = null; + /** - * @return false|\Ramsey\Uuid\UuidInterface + * @return ?UuidInterface */ - protected function getBranchUuid() + protected function getBranchUuid(): ?UuidInterface { return $this->getBranch()->getUuid(); } - protected function getBranch() + /** + * @return Branch + */ + protected function getBranch(): Branch { if ($this->branch === null) { /** @var ActionController $this */ @@ -39,7 +46,7 @@ trait BranchHelper /** * @return BranchStore */ - protected function getBranchStore() + protected function getBranchStore(): BranchStore { if ($this->branchStore === null) { $this->branchStore = new BranchStore($this->db()); @@ -48,12 +55,15 @@ trait BranchHelper return $this->branchStore; } - protected function hasBranch() + /** + * @return bool + */ + protected function hasBranch(): bool { return $this->getBranchUuid() !== null; } - protected function enableStaticObjectLoader($table) + protected function enableStaticObjectLoader($table): void { if (BranchSupport::existsForTableName($table)) { IcingaObject::setDbObjectStore(new DbObjectStore($this->db(), $this->getBranch())); @@ -64,7 +74,7 @@ trait BranchHelper * @param string $subject * @return bool */ - protected function showNotInBranch($subject) + protected function showNotInBranch($subject): bool { if ($this->getBranch()->isBranch()) { $this->content()->add(new NotInBranchedHint($subject, $this->getBranch(), $this->Auth())); @@ -73,4 +83,18 @@ trait BranchHelper return false; } + + protected function hasPreferredBranch(): bool + { + if ($this->hasPreferredBranch === null) { + $implementation = Branch::optionalHook(); + if ($implementation instanceof PreferredBranchSupport) { + $this->hasPreferredBranch = $implementation->hasPreferredBranch($this->Auth()); + } else { + $this->hasPreferredBranch = false; + } + } + + return $this->hasPreferredBranch; + } } diff --git a/library/Director/Web/Controller/Extension/DirectorDb.php b/library/Director/Web/Controller/Extension/DirectorDb.php index 03bec81..c36e358 100644 --- a/library/Director/Web/Controller/Extension/DirectorDb.php +++ b/library/Director/Web/Controller/Extension/DirectorDb.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Web\Controller\Extension; +use Icinga\Module\Director\Auth\Restriction; use Icinga\Module\Director\Db; use Icinga\Module\Director\Web\Controller\ActionController; use Icinga\Module\Director\Web\Window; @@ -65,7 +66,7 @@ trait DirectorDb $auth = $this->Auth(); $available = $this->listAvailableDbResourceNames(); - if ($resourceNames = $auth->getRestrictions('director/db_resource')) { + if ($resourceNames = $auth->getRestrictions(Restriction::DB_RESOURCE)) { $names = []; foreach ($resourceNames as $rNames) { foreach ($this->splitList($rNames) as $name) { diff --git a/library/Director/Web/Controller/Extension/RestApi.php b/library/Director/Web/Controller/Extension/RestApi.php index 3158f49..fb10c86 100644 --- a/library/Director/Web/Controller/Extension/RestApi.php +++ b/library/Director/Web/Controller/Extension/RestApi.php @@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Web\Controller\Extension; use Icinga\Exception\AuthenticationException; use Icinga\Exception\NotFoundError; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Exception\JsonException; use Icinga\Web\Response; use InvalidArgumentException; @@ -55,7 +56,7 @@ trait RestApi */ protected function assertApiPermission() { - if (! $this->hasPermission('director/api')) { + if (! $this->hasPermission(Permission::API)) { throw new AuthenticationException('You are not allowed to access this API'); } } diff --git a/library/Director/Web/Controller/Extension/SingleObjectApiHandler.php b/library/Director/Web/Controller/Extension/SingleObjectApiHandler.php deleted file mode 100644 index bc51548..0000000 --- a/library/Director/Web/Controller/Extension/SingleObjectApiHandler.php +++ /dev/null @@ -1,236 +0,0 @@ -<?php - -namespace Icinga\Module\Director\Web\Controller\Extension; - -use Exception; -use Icinga\Exception\IcingaException; -use Icinga\Exception\InvalidPropertyException; -use Icinga\Exception\NotFoundError; -use Icinga\Module\Director\Forms\IcingaDeleteObjectForm; -use Icinga\Module\Director\Objects\IcingaObject; -use Icinga\Web\Request; -use Icinga\Web\Response; - -class SingleObjectApiHandler -{ - use DirectorDb; - - /** @var IcingaObject */ - private $object; - - /** @var string */ - private $type; - - /** @var Request */ - private $request; - - /** @var Response */ - private $response; - - /** @var \Icinga\Web\UrlParams */ - private $params; - - public function __construct($type, Request $request, Response $response) - { - $this->type = $type; - $this->request = $request; - $this->response = $response; - $this->params = $request->getUrl()->getParams(); - } - - public function runFailSafe() - { - try { - $this->loadObject(); - $this->run(); - } catch (NotFoundError $e) { - $this->sendJsonError($e->getMessage(), 404); - } catch (Exception $e) { - $response = $this->response; - if ($response->getHttpResponseCode() === 200) { - $response->setHttpResponseCode(500); - } - - $this->sendJsonError($e->getMessage()); - } - } - - protected function retrieveObject() - { - $this->requireObject(); - $this->sendJson( - $this->object->toPlainObject( - $this->params->shift('resolved'), - ! $this->params->shift('withNull'), - $this->params->shift('properties') - ) - ); - } - - protected function deleteObject() - { - $this->requireObject(); - $obj = $this->object->toPlainObject(false, true); - $form = new IcingaDeleteObjectForm(); - $form->setObject($this->object) - ->setRequest($this->request) - ->onSuccess(); - - $this->sendJson($obj); - } - - protected function storeObject() - { - $data = json_decode($this->request->getRawBody()); - - if ($data === null) { - $this->response->setHttpResponseCode(400); - throw new IcingaException( - 'Invalid JSON: %s' . $this->request->getRawBody(), - $this->getLastJsonError() - ); - } else { - $data = (array) $data; - } - - if ($object = $this->object) { - if ($this->request->getMethod() === 'POST') { - $object->setProperties($data); - } else { - $data = array_merge([ - 'object_type' => $object->object_type, - 'object_name' => $object->object_name - ], $data); - $object->replaceWith( - IcingaObject::createByType($this->type, $data, $db) - ); - } - } else { - $object = IcingaObject::createByType($this->type, $data, $db); - } - - if ($object->hasBeenModified()) { - $status = $object->hasBeenLoadedFromDb() ? 200 : 201; - $object->store(); - $this->response->setHttpResponseCode($status); - } else { - $this->response->setHttpResponseCode(304); - } - - $this->sendJson($object->toPlainObject(false, true)); - } - - public function run() - { - switch ($this->request->getMethod()) { - case 'DELETE': - $this->deleteObject(); - break; - - case 'POST': - case 'PUT': - $this->storeObject(); - break; - - case 'GET': - $this->retrieveObject(); - break; - - default: - $this->response->setHttpResponseCode(400); - throw new IcingaException( - 'Unsupported method: %s', - $this->request->getMethod() - ); - } - } - - protected function requireObject() - { - if (! $this->object) { - $this->response->setHttpResponseCode(404); - if (! $this->params->get('name')) { - throw new NotFoundError('You need to pass a "name" parameter to access a specific object'); - } else { - throw new NotFoundError('No such object available'); - } - } - } - - // TODO: just return json_last_error_msg() for PHP >= 5.5.0 - protected function getLastJsonError() - { - switch (json_last_error()) { - case JSON_ERROR_DEPTH: - return 'The maximum stack depth has been exceeded'; - case JSON_ERROR_CTRL_CHAR: - return 'Control character error, possibly incorrectly encoded'; - case JSON_ERROR_STATE_MISMATCH: - return 'Invalid or malformed JSON'; - case JSON_ERROR_SYNTAX: - return 'Syntax error'; - case JSON_ERROR_UTF8: - return 'Malformed UTF-8 characters, possibly incorrectly encoded'; - default: - return 'An error occured when parsing a JSON string'; - } - } - - protected function sendJson($object) - { - $this->response->setHeader('Content-Type', 'application/json', true); - $this->_helper->layout()->disableLayout(); - $this->_helper->viewRenderer->setNoRender(true); - echo json_encode($object, JSON_PRETTY_PRINT) . "\n"; - } - - protected function sendJsonError($message, $code = null) - { - $response = $this->response; - - if ($code !== null) { - $response->setHttpResponseCode((int) $code); - } - - $this->sendJson((object) ['error' => $message]); - } - - protected function loadObject() - { - if ($this->object === null) { - if ($name = $this->params->get('name')) { - $this->object = IcingaObject::loadByType( - $this->type, - $name, - $this->db() - ); - - if (! $this->allowsObject($this->object)) { - $this->object = null; - throw new NotFoundError('No such object available'); - } - } elseif ($id = $this->params->get('id')) { - $this->object = IcingaObject::loadByType( - $this->type, - (int) $id, - $this->db() - ); - } elseif ($this->request->isApiRequest()) { - if ($this->request->isGet()) { - $this->response->setHttpResponseCode(422); - - throw new InvalidPropertyException( - 'Cannot load object, missing parameters' - ); - } - } - } - - return $this->object; - } - - protected function allowsObject(IcingaObject $object) - { - return true; - } -} diff --git a/library/Director/Web/Controller/ObjectController.php b/library/Director/Web/Controller/ObjectController.php index 0c06937..994a717 100644 --- a/library/Director/Web/Controller/ObjectController.php +++ b/library/Director/Web/Controller/ObjectController.php @@ -10,6 +10,7 @@ use Icinga\Exception\ProgrammingError; use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry; use Icinga\Module\Director\Db\Branch\Branch; use Icinga\Module\Director\Db\Branch\BranchedObject; +use Icinga\Module\Director\Db\Branch\BranchSupport; use Icinga\Module\Director\Db\Branch\UuidLookup; use Icinga\Module\Director\Deployment\DeploymentInfo; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; @@ -61,8 +62,11 @@ abstract class ObjectController extends ActionController public function init() { - parent::init(); $this->enableStaticObjectLoader($this->getTableName()); + if (! $this->getRequest()->isApiRequest()) { + $this->loadOptionalObject(); + } + parent::init(); if ($this->getRequest()->isApiRequest()) { $this->initializeRestApi(); } else { @@ -97,7 +101,6 @@ abstract class ObjectController extends ActionController protected function initializeWebRequest() { - $this->loadOptionalObject(); if ($this->getRequest()->getActionName() === 'add') { $this->addSingleTab( sprintf($this->translate('Add %s'), ucfirst($this->getType())), @@ -151,8 +154,11 @@ abstract class ObjectController extends ActionController $this->addObject(); } $branch = $this->getBranch(); - if ($branch->isBranch() && ! $this->getRequest()->isApiRequest()) { - $this->content()->add(new BranchedObjectHint($branch, $this->Auth())); + if (! $this->getRequest()->isApiRequest()) { + $hasPreferred = $this->hasPreferredBranch(); + if ($branch->isBranch() || $hasPreferred) { + $this->content()->add(new BranchedObjectHint($branch, $this->Auth(), null, $hasPreferred)); + } } $form->handleRequest(); @@ -267,7 +273,7 @@ abstract class ObjectController extends ActionController if ($id = $this->params->get('field_id')) { $form->loadObject([ - "${type}_id" => $object->id, + "{$type}_id" => $object->id, 'datafield_id' => $id ]); @@ -362,7 +368,7 @@ abstract class ObjectController extends ActionController $this->actions()->add([ Link::create( $this->translate('Usage'), - "director/${type}template/usage", + "director/{$type}template/usage", ['name' => $object->getObjectName()], ['class' => 'icon-sitemap'] ) @@ -558,8 +564,16 @@ abstract class ObjectController extends ActionController if (! $this->allowsObject($object)) { throw new NotFoundError('No such object available'); } - if ($showHint && $branch->isBranch() && $object->isObject() && ! $this->getRequest()->isApiRequest()) { - $this->content()->add(new BranchedObjectHint($branch, $this->Auth(), $branchedObject)); + if ($showHint) { + $hasPreferredBranch = $this->hasPreferredBranch(); + if (($hasPreferredBranch || $branch->isBranch()) + && $object->isObject() + && ! $this->getRequest()->isApiRequest() + ) { + $this->content()->add( + new BranchedObjectHint($branch, $this->Auth(), $branchedObject, $hasPreferredBranch) + ); + } } return $object; diff --git a/library/Director/Web/Controller/ObjectsController.php b/library/Director/Web/Controller/ObjectsController.php index 8c10b44..c4c96c5 100644 --- a/library/Director/Web/Controller/ObjectsController.php +++ b/library/Director/Web/Controller/ObjectsController.php @@ -13,6 +13,7 @@ use Icinga\Module\Director\Forms\IcingaMultiEditForm; use Icinga\Module\Director\Objects\IcingaCommand; use Icinga\Module\Director\Objects\IcingaHost; use Icinga\Module\Director\Objects\IcingaObject; +use Icinga\Module\Director\Objects\IcingaService; use Icinga\Module\Director\RestApi\IcingaObjectsHandler; use Icinga\Module\Director\Web\ActionBar\ObjectsActionBar; use Icinga\Module\Director\Web\ActionBar\TemplateActionBar; @@ -84,8 +85,9 @@ abstract class ObjectsController extends ActionController } elseif ($request->getActionName() === 'applyrules') { $table->filterObjectType('apply'); } + /** @var ?string $search */ $search = $this->params->get('q'); - if ($search !== null && \strlen($search) > 0) { + if ($search) { $table->search($search); } @@ -110,7 +112,7 @@ abstract class ObjectsController extends ActionController $type = $this->getType(); if ($this->params->get('format') === 'json') { $filename = sprintf( - "director-${type}_%s.json", + "director-{$type}_%s.json", date('YmdHis') ); $this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true); @@ -124,7 +126,7 @@ abstract class ObjectsController extends ActionController ->addTitle($this->translate(ucfirst($this->getPluralType()))) ->actions(new ObjectsActionBar($this->getBaseObjectUrl(), $this->url())); - $this->content()->add(new BranchedObjectsHint($this->getBranch(), $this->Auth())); + $this->content()->add(new BranchedObjectsHint($this->getBranch(), $this->Auth(), $this->hasPreferredBranch())); if ($type === 'command' && $this->params->get('type') === 'external_object') { $this->tabs()->activate('external'); @@ -143,8 +145,7 @@ abstract class ObjectsController extends ActionController */ protected function getTable() { - $table = ObjectsTable::create($this->getType(), $this->db()) - ->setAuth($this->getAuth()) + $table = ObjectsTable::create($this->getType(), $this->db(), $this->getAuth()) ->setBranchUuid($this->getBranchUuid()) ->setBaseObjectUrl($this->getBaseObjectUrl()); @@ -157,7 +158,7 @@ abstract class ObjectsController extends ActionController */ protected function getApplyRulesTable() { - $table = new ApplyRulesTable($this->db()); + $table = (new ApplyRulesTable($this->db()))->setBranch($this->getBranch()); $table->setType($this->getType()) ->setBaseObjectUrl($this->getBaseObjectUrl()); $this->eventuallyFilterCommand($table); @@ -235,7 +236,7 @@ abstract class ObjectsController extends ActionController if ($this->params->get('format') === 'json') { $filename = sprintf( - "director-${type}-templates_%s.json", + "director-{$type}-templates_%s.json", date('YmdHis') ); $this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true); @@ -290,7 +291,7 @@ abstract class ObjectsController extends ActionController if ($this->params->get('format') === 'json') { $filename = sprintf( - "director-${type}-applyrules_%s.json", + "director-{$type}-applyrules_%s.json", date('YmdHis') ); $this->getResponse()->setHeader('Content-disposition', "attachment; filename=$filename", true); @@ -313,7 +314,7 @@ abstract class ObjectsController extends ActionController ->add( Link::create( $this->translate('Add'), - "${baseUrl}/add", + "{$baseUrl}/add", ['type' => 'apply'], [ 'title' => sprintf( @@ -354,7 +355,7 @@ abstract class ObjectsController extends ActionController $this->actions()->add( Link::create( $this->translate('Add'), - "director/${type}set/add", + "director/{$type}set/add", null, [ 'title' => sprintf( @@ -409,7 +410,12 @@ abstract class ObjectsController extends ActionController $objects[$name] = $class::load($name, $db); } elseif ($col === 'uuid') { $object = $store->load($table, Uuid::fromString($ex->getExpression())); - $objects[$object->getObjectName()] = $object; + if ($object instanceof IcingaService) { + $host = $object->getRelated('host'); + $objects[$host->getObjectName() . ': ' . $object->getObjectName()] = $object; + } else { + $objects[$object->getObjectName()] = $object; + } } else { throw new InvalidArgumentException("'$col' is no a valid key component for '$type'"); } diff --git a/library/Director/Web/Controller/TemplateController.php b/library/Director/Web/Controller/TemplateController.php index c368a82..4f0898a 100644 --- a/library/Director/Web/Controller/TemplateController.php +++ b/library/Director/Web/Controller/TemplateController.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Web\Controller; use gipfl\Web\Widget\Hint; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\DirectorObject\Automation\ExportInterface; use Icinga\Module\Director\Exception\NestingError; use Icinga\Module\Director\Objects\IcingaCommand; @@ -10,6 +11,7 @@ use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Web\Controller\Extension\DirectorDb; use Icinga\Module\Director\Web\Table\ApplyRulesTable; use Icinga\Module\Director\Web\Table\ObjectsTable; +use Icinga\Module\Director\Web\Table\ObjectsTableSetMembers; use Icinga\Module\Director\Web\Table\TemplatesTable; use Icinga\Module\Director\Web\Table\TemplateUsageTable; use Icinga\Module\Director\Web\Tabs\ObjectTabs; @@ -23,6 +25,8 @@ abstract class TemplateController extends CompatController { use DirectorDb; + use BranchHelper; + /** @var IcingaObject */ protected $template; @@ -39,9 +43,29 @@ abstract class TemplateController extends CompatController $template->getObjectName() )->addBackToUsageLink($template); - ObjectsTable::create($this->getType(), $this->db()) - ->setAuth($this->Auth()) + ObjectsTable::create($this->getType(), $this->db(), $this->Auth()) + ->setBranch($this->getBranch()) + ->setBaseObjectUrl($this->getBaseObjectUrl()) + ->filterTemplate($template, $this->getInheritance()) + ->renderTo($this); + } + + public function setmembersAction() + { + $template = $this->requireTemplate(); + $plural = $this->getTranslatedPluralType(); + $this + ->addSingleTab($plural) + ->setAutorefreshInterval(10) + ->addTitle( + $this->translate('%s in service sets based on %s'), + $plural, + $template->getObjectName() + )->addBackToUsageLink($template); + + ObjectsTableSetMembers::create($this->getType(), $this->db(), $this->Auth()) ->setBaseObjectUrl($this->getBaseObjectUrl()) + ->setBranch($this->getBranch()) ->filterTemplate($template, $this->getInheritance()) ->renderTo($this); } @@ -60,6 +84,7 @@ abstract class TemplateController extends CompatController ApplyRulesTable::create($type, $this->db()) ->setBaseObjectUrl($this->getBaseObjectUrl()) + ->setBranch($this->getBranch()) ->filterTemplate($template, $this->params->get('inheritance', 'direct')) ->renderTo($this); } @@ -93,7 +118,7 @@ abstract class TemplateController extends CompatController $this->actions()->add( Link::create( $this->translate('Back'), - "director/${type}template/usage", + "director/{$type}template/usage", ['name' => $template->getObjectName()], ['class' => 'icon-left-big'] ) @@ -152,7 +177,7 @@ abstract class TemplateController extends CompatController )] )); } - if ($auth->hasPermission('director/admin')) { + if ($auth->hasPermission(Permission::ADMIN)) { $list->addItem(new FormattedString( $this->translate('Create a new %s inheriting from this one'), [Link::create( @@ -188,7 +213,7 @@ abstract class TemplateController extends CompatController try { $this->content()->add( - TemplateUsageTable::forTemplate($template) + TemplateUsageTable::forTemplate($template, $this->Auth(), $this->getBranch()) ); } catch (NestingError $e) { $this->content()->add(Hint::error($e->getMessage())); diff --git a/library/Director/Web/Form/CloneImportSourceForm.php b/library/Director/Web/Form/CloneImportSourceForm.php index 0849dd4..46dc7a3 100644 --- a/library/Director/Web/Form/CloneImportSourceForm.php +++ b/library/Director/Web/Form/CloneImportSourceForm.php @@ -2,8 +2,10 @@ namespace Icinga\Module\Director\Web\Form; +use gipfl\Web\Form; use Icinga\Module\Director\Data\Exporter; -use ipl\Html\Form; +use Icinga\Module\Director\Data\ObjectImporter; +use Icinga\Module\Director\Db; use ipl\Html\FormDecorator\DdDtDecorator; use gipfl\Translation\TranslationHelper; use gipfl\IcingaWeb2\Url; @@ -36,37 +38,25 @@ class CloneImportSourceForm extends Form ]); } - /** - * @return \Icinga\Module\Director\Db - */ - protected function getTargetDb() - { - return $this->source->getConnection(); - } - - /** - * @throws \Icinga\Module\Director\Exception\DuplicateKeyException - */ public function onSuccess() { - $db = $this->getTargetDb(); + $db = $this->source->getConnection(); + assert($db instanceof Db); $export = (new Exporter($db))->export($this->source); $newName = $this->getElement('source_name')->getValue(); $export->source_name = $newName; - unset($export->originalId); + unset($export->uuid); + if (ImportSource::existsWithName($newName, $db)) { $this->getElement('source_name')->addMessage('Name already exists'); } - $this->newSource = ImportSource::import($export, $db); + $importer = new ObjectImporter($db); + $this->newSource = $importer->import(ImportSource::class, $export); $this->newSource->store(); } public function getSuccessUrl() { - if ($this->newSource === null) { - return parent::getSuccessUrl(); - } else { - return Url::fromPath('director/importsource', ['id' => $this->newSource->get('id')]); - } + return Url::fromPath('director/importsource', ['id' => $this->newSource->get('id')]); } } diff --git a/library/Director/Web/Form/CloneSyncRuleForm.php b/library/Director/Web/Form/CloneSyncRuleForm.php index f90b593..ccd61ec 100644 --- a/library/Director/Web/Form/CloneSyncRuleForm.php +++ b/library/Director/Web/Form/CloneSyncRuleForm.php @@ -2,8 +2,10 @@ namespace Icinga\Module\Director\Web\Form; +use gipfl\Web\Form; use Icinga\Module\Director\Data\Exporter; -use ipl\Html\Form; +use Icinga\Module\Director\Data\ObjectImporter; +use Icinga\Module\Director\Db; use ipl\Html\FormDecorator\DdDtDecorator; use gipfl\Translation\TranslationHelper; use gipfl\IcingaWeb2\Url; @@ -37,40 +39,30 @@ class CloneSyncRuleForm extends Form } /** - * @return \Icinga\Module\Director\Db - */ - protected function getTargetDb() - { - return $this->rule->getConnection(); - } - - /** * @throws \Icinga\Exception\NotFoundError * @throws \Icinga\Module\Director\Exception\DuplicateKeyException */ public function onSuccess() { - $db = $this->getTargetDb(); + $db = $this->rule->getConnection(); + assert($db instanceof Db); $exporter = new Exporter($db); $export = $exporter->export($this->rule); $newName = $this->getValue('rule_name'); $export->rule_name = $newName; - unset($export->originalId); + unset($export->uuid); if (SyncRule::existsWithName($newName, $db)) { $this->getElement('rule_name')->addMessage('Name already exists'); } - $this->newRule = SyncRule::import($export, $db); + $importer = new ObjectImporter($db); + $this->newRule = $importer->import(SyncRule::class, $export); $this->newRule->store(); } public function getSuccessUrl() { - if ($this->newRule === null) { - return parent::getSuccessUrl(); - } else { - return Url::fromPath('director/syncrule', ['id' => $this->newRule->get('id')]); - } + return Url::fromPath('director/syncrule', ['id' => $this->newRule->get('id')]); } } diff --git a/library/Director/Web/Form/CsrfToken.php b/library/Director/Web/Form/CsrfToken.php index 24edf88..f6c29ec 100644 --- a/library/Director/Web/Form/CsrfToken.php +++ b/library/Director/Web/Form/CsrfToken.php @@ -17,7 +17,7 @@ class CsrfToken return false; } - list($seed, $token) = explode('|', $elementValue); + list($seed, $token) = explode('|', $token); if (!is_numeric($seed)) { return false; diff --git a/library/Director/Web/Form/DbSelectorForm.php b/library/Director/Web/Form/DbSelectorForm.php index 52fe5ea..8b4f432 100644 --- a/library/Director/Web/Form/DbSelectorForm.php +++ b/library/Director/Web/Form/DbSelectorForm.php @@ -69,7 +69,7 @@ class DbSelectorForm extends Form $params = []; } - if (array_key_exists($name, $params)) { + if (is_array($params) && array_key_exists($name, $params)) { return $params[$name]; } diff --git a/library/Director/Web/Form/DirectorForm.php b/library/Director/Web/Form/DirectorForm.php index 145be5b..36c0577 100644 --- a/library/Director/Web/Form/DirectorForm.php +++ b/library/Director/Web/Form/DirectorForm.php @@ -34,7 +34,7 @@ abstract class DirectorForm extends QuickForm public static function load() { return new static([ - 'icingaModule' => Icinga::App()->getModuleManager()->getModule('director') + 'icingaModule' => Icinga::app()->getModuleManager()->getModule('director') ]); } diff --git a/library/Director/Web/Form/DirectorObjectForm.php b/library/Director/Web/Form/DirectorObjectForm.php index b70bd7b..abbd4f0 100644 --- a/library/Director/Web/Form/DirectorObjectForm.php +++ b/library/Director/Web/Form/DirectorObjectForm.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Web\Form; use Exception; use gipfl\IcingaWeb2\Url; use Icinga\Authentication\Auth; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Data\Db\DbObjectStore; use Icinga\Module\Director\Db; use Icinga\Module\Director\Data\Db\DbObject; @@ -443,7 +444,7 @@ abstract class DirectorObjectForm extends DirectorForm $this->setInheritedValue( $el, $object->getRelatedObjectName($k, $v), - $origins->{"${k}_id"} + $origins->{"{$k}_id"} ); } } @@ -540,7 +541,9 @@ abstract class DirectorObjectForm extends DirectorForm 'inherited_groups', 'applied_groups', 'users', + 'users_var', 'user_groups', + 'user_groups_var', 'apply_to', 'command_id', // Notification 'notification_interval', @@ -788,7 +791,9 @@ abstract class DirectorObjectForm extends DirectorForm return; } - $post = $values = $this->getRequest()->getPost(); + /** @var array $post */ + $post = $this->getRequest()->getPost(); + $values = $post; foreach ($post as $key => $value) { if (preg_match('/^(.+?)_(\d+)__(MOVE_DOWN|MOVE_UP|REMOVE)$/', $key, $m)) { @@ -1239,7 +1244,7 @@ abstract class DirectorObjectForm extends DirectorForm if ($this->hasBeenSent()) { $this->addError($this->translate('No template has been chosen')); } else { - if ($this->hasPermission('director/admin')) { + if ($this->hasPermission(Permission::ADMIN)) { $html = $this->translate('Please define a related template first'); } else { $html = $this->translate('No related template has been provided yet'); @@ -1274,7 +1279,7 @@ abstract class DirectorObjectForm extends DirectorForm 'required' => $required, 'spellcheck' => 'false', 'hideOptions' => $choiceNames, - 'suggest' => "${type}templates", + 'suggest' => "{$type}templates", // 'multiOptions' => $this->optionallyAddFromEnum($enum), 'sorted' => true, 'value' => $this->presetImports, @@ -1516,6 +1521,7 @@ abstract class DirectorObjectForm extends DirectorForm return []; } + /** @var int|string $id */ $id = $object->get('id'); if (array_key_exists($id, $tpl)) { diff --git a/library/Director/Web/Form/Element/DataFilter.php b/library/Director/Web/Form/Element/DataFilter.php index adae07d..7beb651 100644 --- a/library/Director/Web/Form/Element/DataFilter.php +++ b/library/Director/Web/Form/Element/DataFilter.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Web\Form\Element; +use gipfl\Json\JsonString; use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\FilterChain; use Icinga\Data\Filter\FilterExpression; @@ -268,13 +269,13 @@ class DataFilter extends FormElement return Filter::expression( $entry['column'], '=', - json_encode(true) + $this->jsonEncode(true) ); } elseif ($entry['sign'] === 'false') { return Filter::expression( $entry['column'], '=', - json_encode(false) + $this->jsonEncode(false) ); } elseif ($entry['sign'] === 'in') { if (array_key_exists('value', $entry)) { @@ -291,13 +292,13 @@ class DataFilter extends FormElement return Filter::expression( $entry['column'], '=', - json_encode($value) + $this->jsonEncode($value) ); } elseif ($entry['sign'] === 'contains') { $value = array_key_exists('value', $entry) ? $entry['value'] : null; return Filter::expression( - json_encode($value), + $this->jsonEncode($value), '=', $entry['column'] ); @@ -307,11 +308,20 @@ class DataFilter extends FormElement return Filter::expression( $entry['column'], $entry['sign'], - json_encode($value) + $this->jsonEncode($value) ); } } + protected function jsonEncode($string) + { + return preg_replace( + ['/&/u', '/\|/u', '/!/u', '/=/u', '/>/u', '/</u'], + ['\u0026', '\u007c', '\u0021', '\u003d', '\u003e', '\u003c'], + JsonString::encode($string) + ); + } + protected function entryAction($entry) { if (array_key_exists('action', $entry)) { diff --git a/library/Director/Web/Form/Element/ExtensibleSet.php b/library/Director/Web/Form/Element/ExtensibleSet.php index f3c968f..e443b06 100644 --- a/library/Director/Web/Form/Element/ExtensibleSet.php +++ b/library/Director/Web/Form/Element/ExtensibleSet.php @@ -28,7 +28,7 @@ class ExtensibleSet extends FormElement if (! is_array($value)) { throw new InvalidArgumentException(sprintf( 'ExtensibleSet expects to work with Arrays, got %s', - var_export($value, 1) + var_export($value, true) )); } $value = array_filter($value, 'strlen'); diff --git a/library/Director/Web/Form/IcingaObjectFieldLoader.php b/library/Director/Web/Form/IcingaObjectFieldLoader.php index c900edf..ae00855 100644 --- a/library/Director/Web/Form/IcingaObjectFieldLoader.php +++ b/library/Director/Web/Form/IcingaObjectFieldLoader.php @@ -613,7 +613,7 @@ class IcingaObjectFieldLoader $fields = []; /** @var HostFieldHook|ServiceFieldHook $hook */ $type = ucfirst($object->getShortTableName()); - foreach (Hook::all("Director\\${type}Field") as $hook) { + foreach (Hook::all("Director\\{$type}Field") as $hook) { if ($hook->wants($object)) { $id = $object->get('id'); $spec = $hook->getFieldSpec($object); diff --git a/library/Director/Web/Form/IplElement/ExtensibleSetElement.php b/library/Director/Web/Form/IplElement/ExtensibleSetElement.php index a4dbb20..b723d47 100644 --- a/library/Director/Web/Form/IplElement/ExtensibleSetElement.php +++ b/library/Director/Web/Form/IplElement/ExtensibleSetElement.php @@ -26,6 +26,8 @@ class ExtensibleSetElement extends BaseHtmlElement private $description; + private $descriptions; + private $multiOptions; private $validOptions; @@ -109,7 +111,7 @@ class ExtensibleSetElement extends BaseHtmlElement if (null !== $value && ! is_array($value)) { throw new ProgrammingError( 'Got unexpected value, no array: %s', - var_export($value, 1) + var_export($value, true) ); } @@ -323,7 +325,7 @@ class ExtensibleSetElement extends BaseHtmlElement } else { return \sprintf( $this->translate('%s (not an Array!)'), - \var_export($this->inherited, 1) + \var_export($this->inherited, true) ); } } diff --git a/library/Director/Web/Form/QuickForm.php b/library/Director/Web/Form/QuickForm.php index 91c8f00..6100ec9 100644 --- a/library/Director/Web/Form/QuickForm.php +++ b/library/Director/Web/Form/QuickForm.php @@ -620,6 +620,10 @@ abstract class QuickForm extends QuickBaseForm $this->hasBeenSent = true; } elseif ($req->isPost()) { $post = $req->getPost(); + if (! CsrfToken::isValid($post[self::CSRF])) { + throw new Exception('Invalid CSRF token provided'); + } + $this->hasBeenSent = array_key_exists(self::ID, $post) && $post[self::ID] === $this->getName(); } else { diff --git a/library/Director/Web/SelfService.php b/library/Director/Web/SelfService.php index 33756b7..723cbf6 100644 --- a/library/Director/Web/SelfService.php +++ b/library/Director/Web/SelfService.php @@ -155,19 +155,6 @@ class SelfService ['class' => 'logfile'], $wizard->renderIcinga4WindowsWizardCommand($key) ), - Html::tag('h3', $this->translate('Icinga 2 Powershell Module')), - Html::tag('p', Html::sprintf( - $this->translate('In case you\'re using the legacy %s, please run:'), - Html::tag('a', [ - 'href' => 'https://github.com/Icinga/icinga2-powershell-module', - 'target' => '_blank', - ], $this->translate('Icinga 2 Powershell Module')) - )), - Html::tag( - 'pre', - ['class' => 'logfile'], - $wizard->renderPowershellModuleInstaller($key) - ), ]; } @@ -264,6 +251,7 @@ class SelfService null, ['class' => 'icon-download', 'target' => '_blank'] ), + Html::tag('p', null, $this->translate('Just download and run this script on your Linux Client Machine:')), Html::tag('pre', $class, $wizard->renderLinuxInstaller()) ]); diff --git a/library/Director/Web/Table/ActivityLogTable.php b/library/Director/Web/Table/ActivityLogTable.php index 5460bc2..a57b86e 100644 --- a/library/Director/Web/Table/ActivityLogTable.php +++ b/library/Director/Web/Table/ActivityLogTable.php @@ -2,14 +2,15 @@ namespace Icinga\Module\Director\Web\Table; -use gipfl\Format\LocalTimeFormat; +use DateTime; use gipfl\IcingaWeb2\Link; -use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Util; +use IntlDateFormatter; use ipl\Html\Html; use ipl\Html\HtmlElement; -class ActivityLogTable extends ZfQueryBasedTable +class ActivityLogTable extends IntlZfQueryBasedTable { protected $filters = []; @@ -27,9 +28,6 @@ class ActivityLogTable extends ZfQueryBasedTable 'object_type', ]; - /** @var LocalTimeFormat */ - protected $timeFormat; - protected $ranges = []; /** @var ?object */ @@ -44,7 +42,6 @@ class ActivityLogTable extends ZfQueryBasedTable public function __construct($db) { parent::__construct($db); - $this->timeFormat = new LocalTimeFormat(); } public function assemble() @@ -96,7 +93,9 @@ class ActivityLogTable extends ZfQueryBasedTable if (! $this->hasObjectFilter) { $columns[] = $this->makeRangeInfo($row->id); } - $columns[] = $this::td($this->timeFormat->getTime($row->ts_change_time)); + + + $columns[] = $this::td($this->getTime($row->ts_change_time)); return $this::tr($columns)->addAttributes(['class' => $action]); } @@ -107,7 +106,7 @@ class ActivityLogTable extends ZfQueryBasedTable */ protected function renderDayIfNew($timestamp) { - $day = $this->getDateFormatter()->getFullDay($timestamp); + $day = $this->getDateFormatter()->format((new DateTime())->setTimestamp($timestamp)); if ($this->lastDay !== $day) { $this->nextHeader()->add( @@ -206,7 +205,7 @@ class ActivityLogTable extends ZfQueryBasedTable $type = substr($type, 7); } - if (Util::hasPermission('director/showconfig')) { + if (Util::hasPermission(Permission::SHOW_CONFIG)) { // Later on replacing, service_set -> serviceset // multi column key :( diff --git a/library/Director/Web/Table/ApplyRulesTable.php b/library/Director/Web/Table/ApplyRulesTable.php index a861bac..a5379b5 100644 --- a/library/Director/Web/Table/ApplyRulesTable.php +++ b/library/Director/Web/Table/ApplyRulesTable.php @@ -6,6 +6,7 @@ use Icinga\Authentication\Auth; use Icinga\Data\Filter\Filter; use Icinga\Exception\IcingaException; use Icinga\Module\Director\Db; +use Icinga\Module\Director\Db\DbSelectParenthesis; use Icinga\Module\Director\Db\DbUtil; use Icinga\Module\Director\Db\IcingaObjectFilterHelper; use Icinga\Module\Director\IcingaConfig\AssignRenderer; @@ -20,6 +21,8 @@ use Zend_Db_Select as ZfSelect; class ApplyRulesTable extends ZfQueryBasedTable { + use TableWithBranchSupport; + protected $searchColumns = [ 'o.object_name', 'o.assign_filter', @@ -94,10 +97,14 @@ class ApplyRulesTable extends ZfQueryBasedTable // NOT (YET) static::td($this->createActionLinks($row))->setSeparator(' ') ]); + $classes = $this->getRowClasses($row); + if ($row->disabled === 'y') { - $tr->getAttributes()->add('class', 'disabled'); + $classes[] = 'disabled'; } + $tr->getAttributes()->add('class', $classes); + return $tr; } @@ -117,7 +124,8 @@ class ApplyRulesTable extends ZfQueryBasedTable $this->getQuery(), $template, 'o', - $inheritance + $inheritance, + $this->branchUuid ); return $this; @@ -146,7 +154,7 @@ class ApplyRulesTable extends ZfQueryBasedTable $links = []; $links[] = Link::create( Icon::create('sitemap'), - "${baseUrl}template/applytargets", + "{$baseUrl}template/applytargets", ['id' => $row->id], ['title' => $this->translate('Show affected Objects')] ); @@ -196,6 +204,15 @@ class ApplyRulesTable extends ZfQueryBasedTable return FilterRenderer::applyToQuery($filter, $query); } + protected function getRowClasses($row) + { + // TODO: remove isset, to figure out where it is missing + if (isset($row->branch_uuid) && $row->branch_uuid !== null) { + return ['branch_modified']; + } + return []; + } + /** * @return IcingaObject @@ -216,6 +233,7 @@ class ApplyRulesTable extends ZfQueryBasedTable 'id' => 'o.id', 'uuid' => 'o.uuid', 'object_name' => 'o.object_name', + 'object_type' => 'o.object_type', 'disabled' => 'o.disabled', 'assign_filter' => 'o.assign_filter', 'apply_for' => '(NULL)', @@ -224,17 +242,92 @@ class ApplyRulesTable extends ZfQueryBasedTable if ($table === 'icinga_service') { $columns['apply_for'] = 'o.apply_for'; } + + $conn = $this->connection(); $query = $this->db()->select()->from( ['o' => $table], $columns - )->where( - "object_type = 'apply'" )->order('o.object_name'); - if ($this->type === 'service') { - $query->where('service_set_id IS NULL'); + if ($this->branchUuid) { + $columns = $this->branchifyColumns($columns); + $columns['branch_uuid'] = 'bo.branch_uuid'; + if ($conn->isPgsql()) { + $columns['imports'] = 'CONCAT(\'[\', ARRAY_TO_STRING(ARRAY_AGG' + . '(CONCAT(\'"\', sub_o.object_name, \'"\')), \',\'), \']\')'; + } else { + $columns['imports'] = 'CONCAT(\'[\', ' + . 'GROUP_CONCAT(CONCAT(\'"\', sub_o.object_name, \'"\')), \']\')'; + } + + $this->stripSearchColumnAliases(); + + $query->reset('columns'); + $right = clone($query); + + $query->columns($columns) + ->joinLeft( + ['oi' => $table . '_inheritance'], + 'o.id = oi.' . $this->getType() . '_id', + [] + )->joinLeft( + ['sub_o' => $table], + 'sub_o.id = oi.parent_' . $this->getType() . '_id', + [] + )->group(['o.id', 'bo.uuid', 'bo.branch_uuid']); + + $query->joinLeft( + ['bo' => "branched_$table"], + // TODO: PgHexFunc + $this->db()->quoteInto( + 'bo.uuid = o.uuid AND bo.branch_uuid = ?', + DbUtil::quoteBinaryLegacy($this->branchUuid->getBytes(), $this->db()) + ), + [] + )->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')"); + + if ($this->type === 'service') { + $query->where('o.service_set_id IS NULL AND bo.service_set IS NULL'); + } + + $columns['imports'] = 'bo.imports'; + + $right->columns($columns) + ->joinRight( + ['bo' => "branched_$table"], + 'bo.uuid = o.uuid', + [] + ) + ->where('o.uuid IS NULL') + ->where('bo.branch_uuid = ?', $conn->quoteBinary($this->branchUuid->getBytes())); + + $query = $this->db()->select()->union([ + 'l' => new DbSelectParenthesis($query), + 'r' => new DbSelectParenthesis($right), + ]); + + $query = $this->db()->select()->from(['u' => $query]); + $query->order('object_name')->limit(100); + } else { + if ($this->type === 'service') { + $query->where('service_set_id IS NULL'); + } } + $query->where( + "object_type = 'apply'" + ); + + $this->applyRestrictions($query); + return $this->applyRestrictions($query); } + + /** + * @return Db + */ + public function connection() + { + return parent::connection(); + } } diff --git a/library/Director/Web/Table/BasketSnapshotTable.php b/library/Director/Web/Table/BasketSnapshotTable.php index 08f808a..6fe0e16 100644 --- a/library/Director/Web/Table/BasketSnapshotTable.php +++ b/library/Director/Web/Table/BasketSnapshotTable.php @@ -4,13 +4,12 @@ namespace Icinga\Module\Director\Web\Table; use ipl\Html\Html; use gipfl\IcingaWeb2\Link; -use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; use Icinga\Date\DateFormatter; use Icinga\Module\Director\Core\Json; use Icinga\Module\Director\DirectorObject\Automation\Basket; use RuntimeException; -class BasketSnapshotTable extends ZfQueryBasedTable +class BasketSnapshotTable extends IntlZfQueryBasedTable { use DbHelper; @@ -67,7 +66,7 @@ class BasketSnapshotTable extends ZfQueryBasedTable if (! is_object($summary) && ! is_array($summary)) { throw new RuntimeException(sprintf( 'Got invalid basket summary: %s ', - var_export($summary, 1) + var_export($summary, true) )); } diff --git a/library/Director/Web/Table/BranchActivityTable.php b/library/Director/Web/Table/BranchActivityTable.php index e7131ef..cbf940d 100644 --- a/library/Director/Web/Table/BranchActivityTable.php +++ b/library/Director/Web/Table/BranchActivityTable.php @@ -2,15 +2,14 @@ namespace Icinga\Module\Director\Web\Table; -use gipfl\Format\LocalTimeFormat; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Db; use Icinga\Module\Director\Db\Branch\BranchActivity; use Icinga\Module\Director\Util; use gipfl\IcingaWeb2\Link; -use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; use Ramsey\Uuid\UuidInterface; -class BranchActivityTable extends ZfQueryBasedTable +class BranchActivityTable extends IntlZfQueryBasedTable { protected $extraParams = []; @@ -20,16 +19,12 @@ class BranchActivityTable extends ZfQueryBasedTable /** @var ?UuidInterface */ protected $objectUuid; - /** @var LocalTimeFormat */ - protected $timeFormat; - protected $linkToObject = true; public function __construct(UuidInterface $branchUuid, $db, UuidInterface $objectUuid = null) { $this->branchUuid = $branchUuid; $this->objectUuid = $objectUuid; - $this->timeFormat = new LocalTimeFormat(); parent::__construct($db); } @@ -45,7 +40,7 @@ class BranchActivityTable extends ZfQueryBasedTable $activity = BranchActivity::fromDbRow($row); return $this::tr([ $this::td($this->makeBranchLink($activity))->setSeparator(' '), - $this::td($this->timeFormat->getTime($ts)) + $this::td($this->getTime($ts)) ])->addAttributes(['class' => ['action-' . $activity->getAction(), 'branched']]); } @@ -75,7 +70,7 @@ class BranchActivityTable extends ZfQueryBasedTable { $type = preg_replace('/^icinga_/', '', $activity->getObjectTable()); - if (Util::hasPermission('director/showconfig')) { + if (Util::hasPermission(Permission::SHOW_CONFIG)) { // Later on replacing, service_set -> serviceset return [ '[' . $activity->getAuthor() . ']', diff --git a/library/Director/Web/Table/ChoicesTable.php b/library/Director/Web/Table/ChoicesTable.php index 4ba2460..9574520 100644 --- a/library/Director/Web/Table/ChoicesTable.php +++ b/library/Director/Web/Table/ChoicesTable.php @@ -44,7 +44,7 @@ class ChoicesTable extends ZfQueryBasedTable public function renderRow($row) { $type = $this->getType(); - $url = Url::fromPath("director/templatechoice/${type}", [ + $url = Url::fromPath("director/templatechoice/{$type}", [ 'name' => $row->object_name ]); @@ -56,7 +56,7 @@ class ChoicesTable extends ZfQueryBasedTable protected function prepareQuery() { $type = $this->getType(); - $table = "icinga_${type}_template_choice"; + $table = "icinga_{$type}_template_choice"; return $this->db() ->select() ->from(['o' => $table], 'object_name') diff --git a/library/Director/Web/Table/CustomvarTable.php b/library/Director/Web/Table/CustomvarTable.php index f9a3844..1aead19 100644 --- a/library/Director/Web/Table/CustomvarTable.php +++ b/library/Director/Web/Table/CustomvarTable.php @@ -91,11 +91,11 @@ class CustomvarTable extends ZfQueryBasedTable $columns["cnt_$type"] = 'COUNT(*)'; $columns["distinct_$type"] = 'COUNT(DISTINCT varvalue)'; return $db->select()->from( - ['v' => "icinga_${type}_var"], + ['v' => "icinga_{$type}_var"], $columns )->join( - ['o' => "icinga_${type}"], - "o.id = v.${type}_id", + ['o' => "icinga_{$type}"], + "o.id = v.{$type}_id", [] )->where('o.object_type != ?', 'external_object')->group('varname'); } diff --git a/library/Director/Web/Table/CustomvarVariantsTable.php b/library/Director/Web/Table/CustomvarVariantsTable.php index 80fca70..8447e36 100644 --- a/library/Director/Web/Table/CustomvarVariantsTable.php +++ b/library/Director/Web/Table/CustomvarVariantsTable.php @@ -108,11 +108,11 @@ class CustomvarVariantsTable extends ZfQueryBasedTable $columns["cnt_$type"] = 'COUNT(*)'; $columns['format'] = 'v.format'; return $db->select()->from( - ['v' => "icinga_${type}_var"], + ['v' => "icinga_{$type}_var"], $columns )->join( - ['o' => "icinga_${type}"], - "o.id = v.${type}_id", + ['o' => "icinga_{$type}"], + "o.id = v.{$type}_id", [] )->where( 'v.varname = ?', diff --git a/library/Director/Web/Table/DatafieldTable.php b/library/Director/Web/Table/DatafieldTable.php index 4b321d7..0062626 100644 --- a/library/Director/Web/Table/DatafieldTable.php +++ b/library/Director/Web/Table/DatafieldTable.php @@ -5,12 +5,13 @@ namespace Icinga\Module\Director\Web\Table; use gipfl\IcingaWeb2\Link; use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; use Zend_Db_Adapter_Abstract as ZfDbAdapter; +use Zend_Db_Expr as DbExpr; use Zend_Db_Select as ZfDbSelect; class DatafieldTable extends ZfQueryBasedTable { protected $searchColumns = [ - 'df.varname', + 'lc_varname', 'df.caption', ]; @@ -19,6 +20,7 @@ class DatafieldTable extends ZfQueryBasedTable return [ 'id' => 'df.id', 'varname' => 'df.varname', + 'lc_varname' => new DbExpr('LOWER(df.varname)'), 'caption' => 'df.caption', 'description' => 'df.description', 'datatype' => 'df.datatype', @@ -88,6 +90,15 @@ class DatafieldTable extends ZfQueryBasedTable )->group('df.id')->group('df.varname')->group('dfc.category_name')->order('caption ASC'); } + public function search($search) + { + if ($search !== null) { + $search = strtolower($search); + } + + return parent::search($search); + } + /** * @param $type * @param ZfDbAdapter $db @@ -96,7 +107,7 @@ class DatafieldTable extends ZfQueryBasedTable */ protected function makeDatafieldSub($type, ZfDbAdapter $db) { - return $db->select()->from("icinga_${type}_field", [ + return $db->select()->from("icinga_{$type}_field", [ 'cnt' => 'COUNT(*)', 'datafield_id' ])->group('datafield_id'); @@ -110,7 +121,7 @@ class DatafieldTable extends ZfQueryBasedTable */ protected function makeVarSub($type, ZfDbAdapter $db) { - return $db->select()->from("icinga_${type}_var", [ + return $db->select()->from("icinga_{$type}_var", [ 'cnt' => 'COUNT(*)', 'varname' ])->group('varname'); diff --git a/library/Director/Web/Table/DependencyTemplateUsageTable.php b/library/Director/Web/Table/DependencyTemplateUsageTable.php index d7537c5..2c1de50 100644 --- a/library/Director/Web/Table/DependencyTemplateUsageTable.php +++ b/library/Director/Web/Table/DependencyTemplateUsageTable.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Web\Table; +use Icinga\Module\Director\Db; + class DependencyTemplateUsageTable extends TemplateUsageTable { public function getTypes() @@ -12,11 +14,15 @@ class DependencyTemplateUsageTable extends TemplateUsageTable ]; } - protected function getTypeSummaryDefinitions() + protected function getSummaryTables(string $templateType, Db $connection) { return [ - 'templates' => $this->getSummaryLine('template'), - 'applyrules' => $this->getSummaryLine('apply'), + 'templates' => TemplatesTable::create( + $templateType, + $connection + ), + 'applyrules' => ApplyRulesTable::create($templateType, $connection) + ->setBranchUuid($this->branchUuid) ]; } } diff --git a/library/Director/Web/Table/DeploymentLogTable.php b/library/Director/Web/Table/DeploymentLogTable.php index 2d5cb94..4849218 100644 --- a/library/Director/Web/Table/DeploymentLogTable.php +++ b/library/Director/Web/Table/DeploymentLogTable.php @@ -3,10 +3,9 @@ namespace Icinga\Module\Director\Web\Table; use gipfl\IcingaWeb2\Link; -use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; use Icinga\Date\DateFormatter; -class DeploymentLogTable extends ZfQueryBasedTable +class DeploymentLogTable extends IntlZfQueryBasedTable { use DbHelper; diff --git a/library/Director/Web/Table/GroupMemberTable.php b/library/Director/Web/Table/GroupMemberTable.php index b0814ad..c24c6af 100644 --- a/library/Director/Web/Table/GroupMemberTable.php +++ b/library/Director/Web/Table/GroupMemberTable.php @@ -109,7 +109,7 @@ class GroupMemberTable extends ZfQueryBasedTable ]; } - $url = Url::fromPath("director/${type}", $params); + $url = Url::fromPath("director/{$type}", $params); $tr = $this::tr(); @@ -163,7 +163,7 @@ class GroupMemberTable extends ZfQueryBasedTable 'o.id', 'o.object_type', 'o.object_name', - 'membership_type' => "CASE WHEN go.${type}_id IS NULL THEN 'apply' ELSE 'direct' END" + 'membership_type' => "CASE WHEN go.{$type}_id IS NULL THEN 'apply' ELSE 'direct' END" ]; if ($this->group === null) { @@ -176,19 +176,19 @@ class GroupMemberTable extends ZfQueryBasedTable } $query = $this->db()->select()->from( - ['gro' => "icinga_${type}group_${type}_resolved"], + ['gro' => "icinga_{$type}group_{$type}_resolved"], $columns )->join( - ['o' => "icinga_${type}"], - "o.id = gro.${type}_id", + ['o' => "icinga_{$type}"], + "o.id = gro.{$type}_id", [] )->join( - ['g' => "icinga_${type}group"], - "gro.${type}group_id = g.id", + ['g' => "icinga_{$type}group"], + "gro.{$type}group_id = g.id", [] )->joinLeft( - ['go' => "icinga_${type}group_${type}"], - "go.${type}_id = o.id AND go.${type}group_id = g.id", + ['go' => "icinga_{$type}group_{$type}"], + "go.{$type}_id = o.id AND go.{$type}group_id = g.id", [] )->order('o.object_name'); diff --git a/library/Director/Web/Table/HostTemplateUsageTable.php b/library/Director/Web/Table/HostTemplateUsageTable.php index 2d1ee2f..672691f 100644 --- a/library/Director/Web/Table/HostTemplateUsageTable.php +++ b/library/Director/Web/Table/HostTemplateUsageTable.php @@ -11,12 +11,4 @@ class HostTemplateUsageTable extends TemplateUsageTable 'objects' => $this->translate('Objects'), ]; } - - protected function getTypeSummaryDefinitions() - { - return [ - 'templates' => $this->getSummaryLine('template'), - 'objects' => $this->getSummaryLine('object'), - ]; - } } diff --git a/library/Director/Web/Table/IcingaServiceSetServiceTable.php b/library/Director/Web/Table/IcingaServiceSetServiceTable.php index c205e66..2c3dbc4 100644 --- a/library/Director/Web/Table/IcingaServiceSetServiceTable.php +++ b/library/Director/Web/Table/IcingaServiceSetServiceTable.php @@ -12,6 +12,7 @@ use Icinga\Module\Director\Objects\IcingaServiceSet; use gipfl\IcingaWeb2\Link; use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; use gipfl\IcingaWeb2\Url; +use Ramsey\Uuid\Uuid; class IcingaServiceSetServiceTable extends ZfQueryBasedTable { @@ -122,9 +123,12 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable ]; $url = 'director/host/servicesetservice'; } else { + if (is_resource($row->uuid)) { + $row->uuid =stream_get_contents($row->uuid); + } + $params = [ - 'name' => $row->service, - 'set' => $row->service_set + 'uuid' => Uuid::fromBytes($row->uuid)->toString(), ]; $url = 'director/service'; } @@ -194,14 +198,28 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable $connection = $this->connection(); assert($connection instanceof Db); $builder = new ServiceSetQueryBuilder($connection, $this->branchUuid); - return $builder->selectServicesForSet($this->set)->limit(100); + $query = $builder->selectServicesForSet($this->set); + $alias = $this->branchUuid ? 'u' : 'o'; + + if ($this->affectedHost) { + if ($hostId = $this->affectedHost->get('id')) { + $query->joinLeft( + ['hsb' => 'icinga_host_service_blacklist'], + $this->db()->quoteInto("$alias.id = hsb.service_id AND hsb.host_id = ?", $hostId), + [] + )->columns([ + 'blacklisted' => "CASE WHEN hsb.service_id IS NULL THEN 'n' ELSE 'y' END" + ]); + } + } + + return $query->limit(100); } protected function createFakeRemoveLinkForReadonlyView() { return Html::tag('span', [ - 'class' => 'icon-paste', - 'style' => 'float: right; font-weight: normal', + 'class' => ['icon-paste', 'seviceset-obj-link'], ], $this->host->getObjectName()); } @@ -209,8 +227,7 @@ class IcingaServiceSetServiceTable extends ZfQueryBasedTable { $hostname = $host->getObjectName(); return Link::create($hostname, 'director/host/services', ['name' => $hostname], [ - 'class' => 'icon-paste', - 'style' => 'float: right; font-weight: normal', + 'class' => ['icon-paste', 'seviceset-obj-link'], 'data-base-target' => '_next', 'title' => sprintf( $this->translate('This set has been inherited from %s'), diff --git a/library/Director/Web/Table/IntlZfQueryBasedTable.php b/library/Director/Web/Table/IntlZfQueryBasedTable.php new file mode 100644 index 0000000..81ef14c --- /dev/null +++ b/library/Director/Web/Table/IntlZfQueryBasedTable.php @@ -0,0 +1,51 @@ +<?php + +namespace Icinga\Module\Director\Web\Table; + +use DateTime; +use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; +use IntlDateFormatter; +use Locale; + +abstract class IntlZfQueryBasedTable extends ZfQueryBasedTable +{ + protected function getDateFormatter() + { + return (new IntlDateFormatter( + Locale::getDefault(), + IntlDateFormatter::FULL, + IntlDateFormatter::NONE + )); + } + + /** + * @param int $timestamp + */ + protected function renderDayIfNew($timestamp) + { + $day = $this->getDateFormatter()->format((new DateTime())->setTimestamp($timestamp)); + + if ($this->lastDay !== $day) { + $this->nextHeader()->add( + $this::th($day, [ + 'colspan' => 2, + 'class' => 'table-header-day' + ]) + ); + + $this->lastDay = $day; + $this->nextBody(); + } + } + + protected function getTime(int $timeStamp) + { + $timeFormatter = $this->getDateFormatter(); + + $timeFormatter->setPattern( + in_array(Locale::getDefault(), ['en_US', 'en_US.UTF-8']) ? 'h:mm:ss a': 'H:mm:ss' + ); + + return $timeFormatter->format((new DateTime())->setTimestamp($timeStamp)); + } +} diff --git a/library/Director/Web/Table/NotificationTemplateUsageTable.php b/library/Director/Web/Table/NotificationTemplateUsageTable.php index da411a3..d8cd3d8 100644 --- a/library/Director/Web/Table/NotificationTemplateUsageTable.php +++ b/library/Director/Web/Table/NotificationTemplateUsageTable.php @@ -2,6 +2,8 @@ namespace Icinga\Module\Director\Web\Table; +use Icinga\Module\Director\Db; + class NotificationTemplateUsageTable extends TemplateUsageTable { public function getTypes() @@ -12,11 +14,15 @@ class NotificationTemplateUsageTable extends TemplateUsageTable ]; } - protected function getTypeSummaryDefinitions() + protected function getSummaryTables(string $templateType, Db $connection) { return [ - 'templates' => $this->getSummaryLine('template'), - 'applyrules' => $this->getSummaryLine('apply', 'o.host_id IS NULL'), + 'templates' => TemplatesTable::create( + $templateType, + $connection + ), + 'applyrules' => ApplyRulesTable::create($templateType, $connection) + ->setBranchUuid($this->branchUuid) ]; } } diff --git a/library/Director/Web/Table/ObjectSetTable.php b/library/Director/Web/Table/ObjectSetTable.php index 2773841..4df9bdd 100644 --- a/library/Director/Web/Table/ObjectSetTable.php +++ b/library/Director/Web/Table/ObjectSetTable.php @@ -2,7 +2,9 @@ namespace Icinga\Module\Director\Web\Table; +use gipfl\IcingaWeb2\Zf1\Db\FilterRenderer; use Icinga\Authentication\Auth; +use Icinga\Data\Filter\Filter; use Icinga\Module\Director\Db; use gipfl\IcingaWeb2\Link; use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; @@ -28,6 +30,8 @@ class ObjectSetTable extends ZfQueryBasedTable /** @var Auth */ private $auth; + protected $queries = []; + public static function create($type, Db $db, Auth $auth) { $table = new static($db); @@ -53,7 +57,7 @@ class ObjectSetTable extends ZfQueryBasedTable 'uuid' => Uuid::fromBytes(Db\DbUtil::binaryResult($row->uuid))->toString(), ]; - $url = Url::fromPath("director/${type}set", $params); + $url = Url::fromPath("director/{$type}set", $params); $classes = $this->getRowClasses($row); $tr = static::tr([ @@ -85,7 +89,7 @@ class ObjectSetTable extends ZfQueryBasedTable { $type = $this->getType(); - $table = "icinga_${type}_set"; + $table = "icinga_{$type}_set"; $columns = [ 'id' => 'os.id', 'uuid' => 'os.uuid', @@ -106,15 +110,15 @@ class ObjectSetTable extends ZfQueryBasedTable ['os' => $table], $columns )->joinLeft( - ['o' => "icinga_${type}"], - "o.${type}_set_id = os.id", + ['o' => "icinga_{$type}"], + "o.{$type}_set_id = os.id", [] ); $nameFilter = new FilterByNameRestriction( $this->connection(), $this->auth, - "${type}_set" + "{$type}_set" ); $nameFilter->applyToQuery($query, 'os'); /** @var Db $conn */ @@ -145,7 +149,20 @@ class ObjectSetTable extends ZfQueryBasedTable $query->group('bos.uuid')->group('os.uuid')->group('os.id')->group('bos.branch_uuid'); $right->group('bos.uuid')->group('os.uuid')->group('os.id')->group('bos.branch_uuid'); } - + $right->joinLeft( + ['bo' => "branched_icinga_{$type}"], + "bo.{$type}_set = bos.object_name", + [] + )->group(['bo.object_name', 'o.object_name']); + $query->joinLeft( + ['bo' => "branched_icinga_{$type}"], + "bo.{$type}_set = bos.object_name", + [] + )->group(['bo.object_name', 'o.object_name']); + $this->queries = [ + $query, + $right + ]; $query = $this->db()->select()->union([ 'l' => new DbSelectParenthesis($query), 'r' => new DbSelectParenthesis($right), @@ -168,16 +185,16 @@ class ObjectSetTable extends ZfQueryBasedTable ->group('assign_filter') ->group('description') ->group('count_services'); - }; + } } else { // Disabled for now, check for correctness: // $query->joinLeft( - // ['osi' => "icinga_${type}_set_inheritance"], - // "osi.parent_${type}_set_id = os.id", + // ['osi' => "icinga_{$type}_set_inheritance"], + // "osi.parent_{$type}_set_id = os.id", // [] // )->joinLeft( - // ['oso' => "icinga_${type}_set"], - // "oso.id = oso.${type}_set_id", + // ['oso' => "icinga_{$type}_set"], + // "oso.id = oso.{$type}_set_id", // [] // ); // 'count_hosts' => 'COUNT(DISTINCT oso.id)', @@ -196,11 +213,40 @@ class ObjectSetTable extends ZfQueryBasedTable ->group('os.assign_filter') ->group('os.description'); }; + $this->queries = [$query]; } return $query; } + public function search($search) + { + if (! empty($search)) { + $columns = $this->getSearchColumns(); + if (strpos($search, ' ') === false) { + $filter = Filter::matchAny(); + foreach ($columns as $column) { + $filter->addFilter(Filter::expression($column, '=', "*$search*")); + } + } else { + $filter = Filter::matchAll(); + foreach (explode(' ', $search) as $s) { + $sub = Filter::matchAny(); + foreach ($columns as $column) { + $sub->addFilter(Filter::expression($column, '=', "*$s*")); + } + $filter->addFilter($sub); + } + } + + foreach ($this->queries as $query) { + FilterRenderer::applyToQuery($filter, $query); + } + } + + return $this; + } + /** * @return Db */ diff --git a/library/Director/Web/Table/ObjectsTable.php b/library/Director/Web/Table/ObjectsTable.php index 792cb6d..4ad1166 100644 --- a/library/Director/Web/Table/ObjectsTable.php +++ b/library/Director/Web/Table/ObjectsTable.php @@ -14,6 +14,7 @@ use gipfl\IcingaWeb2\Link; use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; use gipfl\IcingaWeb2\Url; use Ramsey\Uuid\Uuid; +use Zend_Db_Adapter_Pdo_Pgsql; use Zend_Db_Select as ZfSelect; class ObjectsTable extends ZfQueryBasedTable @@ -50,12 +51,18 @@ class ObjectsTable extends ZfQueryBasedTable /** @var Auth */ private $auth; + public function __construct($db, Auth $auth) + { + $this->auth = $auth; + parent::__construct($db); + } + /** * @param $type * @param Db $db * @return static */ - public static function create($type, Db $db) + public static function create($type, Db $db, Auth $auth) { $class = __NAMESPACE__ . '\\ObjectsTable' . ucfirst($type); if (! class_exists($class)) { @@ -63,7 +70,7 @@ class ObjectsTable extends ZfQueryBasedTable } /** @var static $table */ - $table = new $class($db); + $table = new $class($db, $auth); $table->type = $type; return $table; } @@ -84,20 +91,6 @@ class ObjectsTable extends ZfQueryBasedTable return $this; } - /** - * @return Auth - */ - public function getAuth() - { - return $this->auth; - } - - public function setAuth(Auth $auth) - { - $this->auth = $auth; - return $this; - } - public function filterObjectType($type) { $this->filterObjectType = $type; @@ -124,11 +117,17 @@ class ObjectsTable extends ZfQueryBasedTable IcingaObject $template, $inheritance = Db\IcingaObjectFilterHelper::INHERIT_DIRECT ) { + if ($this->branchUuid) { + $tableAlias = 'u'; + } else { + $tableAlias = 'o'; + } IcingaObjectFilterHelper::filterByTemplate( $this->getQuery(), $template, - 'o', - $inheritance + $tableAlias, + $inheritance, + $this->branchUuid ); return $this; @@ -142,7 +141,7 @@ class ObjectsTable extends ZfQueryBasedTable protected function renderObjectNameColumn($row) { $type = $this->baseObjectUrl; - $url = Url::fromPath("director/${type}", [ + $url = Url::fromPath("director/{$type}", [ 'uuid' => Uuid::fromBytes($row->uuid)->toString() ]); @@ -227,11 +226,10 @@ class ObjectsTable extends ZfQueryBasedTable { /** @var Db $db */ $db = $this->connection(); - $auth = $this->getAuth(); return [ - new HostgroupRestriction($db, $auth), - new FilterByNameRestriction($db, $auth, $this->getDummyObject()->getShortTableName()) + new HostgroupRestriction($db, $this->auth), + new FilterByNameRestriction($db, $this->auth, $this->getDummyObject()->getShortTableName()) ]; } @@ -279,7 +277,39 @@ class ObjectsTable extends ZfQueryBasedTable $conn->quoteBinary($this->branchUuid->getBytes()) ), [] - )->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')"); + ); + + // keep the imported templates as columns + $leftColumns = $columns; + $rightColumns = $columns; + + if ($this->db() instanceof Zend_Db_Adapter_Pdo_Pgsql) { + $leftColumns['imports'] = 'CONCAT(\'[\', ARRAY_TO_STRING(ARRAY_AGG' + . '(CONCAT(\'"\', sub_o.object_name, \'"\')), \',\'), \']\')'; + } else { + $leftColumns['imports'] = 'CONCAT(\'[\', ' + . 'GROUP_CONCAT(CONCAT(\'"\', sub_o.object_name, \'"\')), \']\')'; + } + + $query->reset('columns'); + + $query->columns($leftColumns) + ->joinLeft( + ['oi' => $table . '_inheritance'], + 'o.id = oi.' . $this->getType() . '_id', + [] + )->joinLeft( + ['sub_o' => $table], + 'sub_o.id = oi.parent_' . $this->getType() . '_id', + [] + )->group(['o.id', 'bo.uuid', 'bo.branch_uuid']); + + $rightColumns['imports'] = 'bo.imports'; + + $right->reset('columns'); + $right->columns($rightColumns); + + $query->where("(bo.branch_deleted IS NULL OR bo.branch_deleted = 'n')"); $this->applyObjectTypeFilter($query, $right); $right->joinRight( ['bo' => "branched_$table"], @@ -298,6 +328,7 @@ class ObjectsTable extends ZfQueryBasedTable $query->order('object_name')->limit(100); } else { $this->applyObjectTypeFilter($query); + $query = $this->applyRestrictions($query); $query->order('o.object_name')->limit(100); } diff --git a/library/Director/Web/Table/ObjectsTableService.php b/library/Director/Web/Table/ObjectsTableService.php index 2d4ad41..c9bce72 100644 --- a/library/Director/Web/Table/ObjectsTableService.php +++ b/library/Director/Web/Table/ObjectsTableService.php @@ -203,8 +203,14 @@ class ObjectsTableService extends ObjectsTable 'hsb.service_id = o.id AND hsb.host_id = o.host_id', [] )->where('o.service_set_id IS NULL') + ->group(['o.id', 'h.id','hsb.service_id', 'hsb.host_id']) ->order('o.object_name')->order('h.object_name'); + if ($this->branchUuid) { + $subQuery->where('bo.service_set IS NULL') + ->group(['bo.uuid', 'bo.branch_uuid']); + } + if ($this->host) { if ($this->branchUuid) { $subQuery->where('COALESCE(h.object_name, bo.host) = ?', $this->host->getObjectName()); diff --git a/library/Director/Web/Table/ObjectsTableSetMembers.php b/library/Director/Web/Table/ObjectsTableSetMembers.php new file mode 100644 index 0000000..6b18ac9 --- /dev/null +++ b/library/Director/Web/Table/ObjectsTableSetMembers.php @@ -0,0 +1,255 @@ +<?php + +namespace Icinga\Module\Director\Web\Table; + +use Icinga\Authentication\Auth; +use Icinga\Module\Director\Db; +use gipfl\IcingaWeb2\Link; +use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; +use gipfl\IcingaWeb2\Url; +use Icinga\Module\Director\Db\DbSelectParenthesis; +use Icinga\Module\Director\Db\IcingaObjectFilterHelper; +use Icinga\Module\Director\Objects\IcingaObject; +use Icinga\Module\Director\Restriction\FilterByNameRestriction; +use Ramsey\Uuid\Uuid; + +class ObjectsTableSetMembers extends ZfQueryBasedTable +{ + use TableWithBranchSupport; + + protected $searchColumns = [ + 'os.object_name', + 'o.object_name', + ]; + + private $type; + + /** @var IcingaObject */ + protected $dummyObject; + + protected $baseObjectUrl; + + /** @var Auth */ + private $auth; + + public static function create($type, Db $db, Auth $auth) + { + $table = new static($db); + $table->type = $type; + $table->auth = $auth; + return $table; + } + + public function getType() + { + return $this->type; + } + + public function getColumnsToBeRendered() + { + return [ + 'os.object_name' => 'Service Set', + 'o.object_name' => 'Service Name' + ]; + } + + public function setBaseObjectUrl($url) + { + $this->baseObjectUrl = $url; + + return $this; + } + + protected function getRowClasses($row) + { + // TODO: remove isset, to figure out where it is missing + if (isset($row->branch_uuid) && $row->branch_uuid !== null) { + return ['branch_modified']; + } + return []; + } + + /** + * Should be triggered from renderRow, still unused. + * + * @param IcingaObject $template + * @param string $inheritance + * @return $this + * @throws \Icinga\Exception\ProgrammingError + */ + public function filterTemplate( + IcingaObject $template, + $inheritance = IcingaObjectFilterHelper::INHERIT_DIRECT + ) { + IcingaObjectFilterHelper::filterByTemplate( + $this->getQuery(), + $template, + 'o', + $inheritance, + $this->branchUuid + ); + + return $this; + } + + + public function renderRow($row) + { + $url = Url::fromPath('director/service/edit', [ + 'name' => $row->object_name, + 'uuid' => Uuid::fromBytes($row->uuid)->toString(), + ]); + + return static::tr([ + static::td([ + Link::create($row->service_set, $url), + ]), + static::td($row->object_name), + ])->addAttributes(['class' => $this->getRowClasses($row)]); + } + + /** + * @return IcingaObject + */ + protected function getDummyObject() + { + if ($this->dummyObject === null) { + $type = $this->type; + $this->dummyObject = IcingaObject::createByType($type); + } + return $this->dummyObject; + } + + protected function prepareQuery() + { + $table = $this->getDummyObject()->getTableName(); + $type = $this->getType(); + + $columns = [ + 'id' => 'o.id', + 'uuid' => 'o.uuid', + 'service_set' => 'os.object_name', + 'object_name' => 'o.object_name', + 'object_type' => 'os.object_type', + 'assign_filter' => 'os.assign_filter', + 'description' => 'os.description', + ]; + + $query = $this->db()->select()->from( + ['o' => $table], + $columns + )->joinLeft( + ['os' => "icinga_{$type}_set"], + "o.{$type}_set_id = os.id", + [] + )->where('o.host_id IS NULL'); + + $nameFilter = new FilterByNameRestriction( + $this->connection(), + $this->auth, + "{$type}_set" + ); + $nameFilter->applyToQuery($query, 'os'); + + if ($this->branchUuid) { + $columns['branch_uuid'] = 'bos.branch_uuid'; + $conn = $this->connection(); + if ($conn->isPgsql()) { + $columns['imports'] = 'CONCAT(\'[\', ARRAY_TO_STRING(ARRAY_AGG' + . '(CONCAT(\'"\', sub_o.object_name, \'"\')), \',\'), \']\')'; + } else { + $columns['imports'] = 'CONCAT(\'[\', ' + . 'GROUP_CONCAT(CONCAT(\'"\', sub_o.object_name, \'"\')), \']\')'; + } + + $columns = $this->branchifyColumns($columns); + $this->stripSearchColumnAliases(); + + $query->reset('columns'); + $right = clone($query); + $conn = $this->connection(); + + $query->columns($columns)->joinLeft( + ['bos' => "branched_icinga_{$type}_set"], + // TODO: PgHexFunc + $this->db()->quoteInto( + 'bos.uuid = os.uuid AND bos.branch_uuid = ?', + $conn->quoteBinary($this->branchUuid->getBytes()) + ), + [] + )->joinLeft( + ['oi' => $table . '_inheritance'], + 'o.id = oi.' . $this->getType() . '_id', + [] + )->joinLeft( + ['sub_o' => $table], + 'sub_o.id = oi.parent_' . $this->getType() . '_id', + [] + )->where("(bos.branch_deleted IS NULL OR bos.branch_deleted = 'n')"); + + $columns['imports'] = 'bo.imports'; + $right->columns($columns)->joinRight( + ['bos' => "branched_icinga_{$type}_set"], + 'bos.uuid = os.uuid', + [] + ) + ->where('os.uuid IS NULL') + ->where('bos.branch_uuid = ?', $conn->quoteBinary($this->branchUuid->getBytes())); + $query->group('COALESCE(os.uuid, bos.uuid)'); + $right->group('COALESCE(os.uuid, bos.uuid)'); + if ($conn->isPgsql()) { + // This is ugly, might want to modify the query - even a subselect looks better + $query->group('bos.uuid')->group('os.uuid')->group('os.id')->group('bos.branch_uuid')->group('o.id'); + $right->group('bos.uuid')->group('os.uuid')->group('os.id')->group('bos.branch_uuid')->group('o.id'); + } + $right->joinLeft( + ['bo' => "branched_icinga_{$type}"], + "bo.{$type}_set = bos.object_name", + [] + )->group(['bo.object_name', 'o.object_name', 'bo.uuid', 'bo.imports']); + $query->joinLeft( + ['bo' => "branched_icinga_{$type}"], + "bo.{$type}_set = bos.object_name", + [] + )->group(['bo.object_name', 'o.object_name', 'bo.uuid']); + + $query = $this->db()->select()->union([ + 'l' => new DbSelectParenthesis($query), + 'r' => new DbSelectParenthesis($right), + ]); + $query = $this->db()->select()->from(['u' => $query]); + $query->order('object_name')->limit(100); + + $query + ->group('uuid') + ->where('object_type = ?', 'template') + ->order('object_name'); + if ($conn->isPgsql()) { + $query + ->group('uuid') + ->group('id') + ->group('imports') + ->group('branch_uuid') + ->group('object_name') + ->group('object_type') + ->group('assign_filter') + ->group('description') + ->group('service_set'); + } + } else { + $query + ->where('o.object_type = ?', 'object') + ->order('os.object_name'); + } + + return $query; + } + + /** + * @return Db + */ + public function connection() + { + return parent::connection(); + } +} diff --git a/library/Director/Web/Table/ReadOnlyFormAvpTable.php b/library/Director/Web/Table/ReadOnlyFormAvpTable.php deleted file mode 100644 index c3b44f3..0000000 --- a/library/Director/Web/Table/ReadOnlyFormAvpTable.php +++ /dev/null @@ -1,113 +0,0 @@ -<?php - -namespace Icinga\Module\Director\Web\Table; - -use Icinga\Module\Director\PlainObjectRenderer; -use Icinga\Module\Director\Web\Form\QuickForm; -use Zend_Form_Element as ZfElement; -use Zend_Form_DisplayGroup as ZfDisplayGroup; - -class ReadOnlyFormAvpTable -{ - protected $form; - - public function __construct(QuickForm $form) - { - $this->form = $form; - } - - protected function renderDisplayGroups(QuickForm $form) - { - $html = ''; - - foreach ($form->getDisplayGroups() as $group) { - $elements = $this->filterGroupElements($group); - - if (empty($elements)) { - continue; - } - - $html .= '<tr><th colspan="2" style="text-align: right">' . $group->getLegend() . '</th></tr>'; - $html .= $this->renderElements($elements); - } - - return $html; - } - - /** - * @param ZfDisplayGroup $group - * @return ZfElement[] - */ - protected function filterGroupElements(ZfDisplayGroup $group) - { - $blacklist = array('disabled', 'assign_filter'); - $elements = array(); - /** @var ZfElement $element */ - foreach ($group->getElements() as $element) { - if ($element->getValue() === null) { - continue; - } - - if ($element->getType() === 'Zend_Form_Element_Hidden') { - continue; - } - - if (in_array($element->getName(), $blacklist)) { - continue; - } - - - $elements[] = $element; - } - - return $elements; - } - - protected function renderElements($elements) - { - $html = ''; - foreach ($elements as $element) { - $html .= $this->renderElement($element); - } - - return $html; - } - - /** - * @param ZfElement $element - * - * @return string - */ - protected function renderElement(ZfElement $element) - { - $value = $element->getValue(); - return '<tr><th>' - . $this->escape($element->getLabel()) - . '</th><td>' - . $this->renderValue($value) - . '</td></tr>'; - } - - protected function renderValue($value) - { - if (is_string($value)) { - return $this->escape($value); - } elseif (is_array($value)) { - return $this->escape(implode(', ', $value)); - } - return $this->escape(PlainObjectRenderer::render($value)); - } - - protected function escape($string) - { - return htmlspecialchars($string); - } - - public function render() - { - $this->form->initializeForObject(); - return '<table class="name-value-table">' . "\n" - . $this->renderDisplayGroups($this->form) - . '</table>'; - } -} diff --git a/library/Director/Web/Table/ServiceTemplateUsageTable.php b/library/Director/Web/Table/ServiceTemplateUsageTable.php index 82f9643..c2806f6 100644 --- a/library/Director/Web/Table/ServiceTemplateUsageTable.php +++ b/library/Director/Web/Table/ServiceTemplateUsageTable.php @@ -2,6 +2,9 @@ namespace Icinga\Module\Director\Web\Table; +use Icinga\Authentication\Auth; +use Icinga\Module\Director\Db; + class ServiceTemplateUsageTable extends TemplateUsageTable { public function getTypes() @@ -10,18 +13,27 @@ class ServiceTemplateUsageTable extends TemplateUsageTable 'templates' => $this->translate('Templates'), 'objects' => $this->translate('Objects'), 'applyrules' => $this->translate('Apply Rules'), - // 'setmembers' => $this->translate('Set Members'), + 'setmembers' => $this->translate('Set Members'), ]; } - protected function getTypeSummaryDefinitions() + protected function getSummaryTables(string $templateType, Db $connection) { + $auth = Auth::getInstance(); return [ - 'templates' => $this->getSummaryLine('template'), - 'objects' => $this->getSummaryLine('object'), - 'applyrules' => $this->getSummaryLine('apply', 'o.service_set_id IS NULL'), - // TODO: re-enable - // 'setmembers' => $this->getSummaryLine('apply', 'o.service_set_id IS NOT NULL'), + 'templates' => TemplatesTable::create( + $templateType, + $connection + ), + 'objects' => ObjectsTable::create($templateType, $connection, $this->auth) + ->setBranchUuid($this->branchUuid), + 'applyrules' => ApplyRulesTable::create($templateType, $connection) + ->setBranchUuid($this->branchUuid), + 'setmembers' => ObjectsTableSetMembers::create( + $templateType, + $connection, + $auth + ) ]; } } diff --git a/library/Director/Web/Table/SyncRunTable.php b/library/Director/Web/Table/SyncRunTable.php index e08aad7..19f2678 100644 --- a/library/Director/Web/Table/SyncRunTable.php +++ b/library/Director/Web/Table/SyncRunTable.php @@ -2,22 +2,17 @@ namespace Icinga\Module\Director\Web\Table; -use gipfl\Format\LocalTimeFormat; use Icinga\Module\Director\Objects\SyncRule; use gipfl\IcingaWeb2\Link; -use gipfl\IcingaWeb2\Table\ZfQueryBasedTable; -class SyncRunTable extends ZfQueryBasedTable +class SyncRunTable extends IntlZfQueryBasedTable { /** @var SyncRule */ protected $rule; - protected $timeFormat; - public function __construct(SyncRule $rule) { parent::__construct($rule->getConnection()); - $this->timeFormat = new LocalTimeFormat(); $this->getAttributes() ->set('data-base-target', '_self') ->add('class', 'history'); @@ -31,7 +26,7 @@ class SyncRunTable extends ZfQueryBasedTable return $this::tr([ $this::td($this->makeSummary($row)), $this::td(new Link( - $this->timeFormat->getTime($time), + $this->getTime($time), 'director/syncrule/history', [ 'id' => $row->rule_id, diff --git a/library/Director/Web/Table/TableWithBranchSupport.php b/library/Director/Web/Table/TableWithBranchSupport.php index 7c5b15c..9e412c3 100644 --- a/library/Director/Web/Table/TableWithBranchSupport.php +++ b/library/Director/Web/Table/TableWithBranchSupport.php @@ -56,6 +56,9 @@ trait TableWithBranchSupport $result[$alias] = $column; } + if (isset($result['count_services'])) { + $result['count_services'] = 'COUNT(DISTINCT COALESCE(o.uuid, bo.uuid))'; + } return $result; } diff --git a/library/Director/Web/Table/TemplateUsageTable.php b/library/Director/Web/Table/TemplateUsageTable.php index 66e56ea..376a499 100644 --- a/library/Director/Web/Table/TemplateUsageTable.php +++ b/library/Director/Web/Table/TemplateUsageTable.php @@ -2,9 +2,12 @@ namespace Icinga\Module\Director\Web\Table; +use Icinga\Authentication\Auth; use Icinga\Exception\ProgrammingError; +use Icinga\Module\Director\Db; +use Icinga\Module\Director\Db\Branch\Branch; +use Icinga\Module\Director\Db\IcingaObjectFilterHelper; use Icinga\Module\Director\Objects\IcingaObject; -use Icinga\Module\Director\Resolver\TemplateTree; use gipfl\IcingaWeb2\Link; use ipl\Html\Table; use gipfl\Translation\TranslationHelper; @@ -13,10 +16,17 @@ class TemplateUsageTable extends Table { use TranslationHelper; + use TableWithBranchSupport; + + /** @var Auth */ + protected $auth; + protected $defaultAttributes = ['class' => 'pivot']; protected $objectType; + protected $searchColumns = []; + public function getTypes() { return [ @@ -25,26 +35,22 @@ class TemplateUsageTable extends Table ]; } - protected function getTypeSummaryDefinitions() - { - return [ - 'templates' => $this->getSummaryLine('template'), - 'objects' => $this->getSummaryLine('object'), - ]; - } - /** * @param IcingaObject $template + * @param Branch|null $branch + * * @return TemplateUsageTable + * + * @throws ProgrammingError */ - public static function forTemplate(IcingaObject $template) + public static function forTemplate(IcingaObject $template, Auth $auth, Branch $branch = null) { $type = ucfirst($template->getShortTableName()); - $class = __NAMESPACE__ . "\\${type}TemplateUsageTable"; + $class = __NAMESPACE__ . "\\{$type}TemplateUsageTable"; if (class_exists($class)) { - return new $class($template); + return new $class($template, $auth, $branch); } else { - return new static($template); + return new static($template, $auth, $branch); } } @@ -58,8 +64,9 @@ class TemplateUsageTable extends Table ]; } - protected function __construct(IcingaObject $template) + protected function __construct(IcingaObject $template, Auth $auth, Branch $branch = null) { + $this->auth = $auth; if ($template->get('object_type') !== 'template') { throw new ProgrammingError( @@ -68,6 +75,7 @@ class TemplateUsageTable extends Table ); } + $this->setBranch($branch); $this->objectType = $objectType = $template->getShortTableName(); $types = $this->getTypes(); $usage = $this->getUsageSummary($template); @@ -85,7 +93,7 @@ class TemplateUsageTable extends Table Table::td( Link::create( $count, - "director/${objectType}template/$type", + "director/{$objectType}template/$type", [ 'name' => $template->getObjectName(), 'inheritance' => $inheritance @@ -98,6 +106,7 @@ class TemplateUsageTable extends Table } if ($used) { + $this->getHeader()->add(Table::row($this->getColumnsToBeRendered(), null, 'th')); $this->add($rows); } else { $this->add($this->translate('This template is not in use')); @@ -106,52 +115,51 @@ class TemplateUsageTable extends Table protected function getUsageSummary(IcingaObject $template) { - $id = $template->getAutoincId(); $connection = $template->getConnection(); $db = $connection->getDbAdapter(); - $oType = $this->objectType; - $tree = new TemplateTree($oType, $connection); - $ids = $tree->listDescendantIdsFor($template); - if (empty($ids)) { - $ids = [0]; + + $types = array_keys($this->getTypes()); + $direct = []; + $indirect = []; + $templateType = $template->getShortTableName(); + + foreach ($this->getSummaryTables($templateType, $connection) as $type => $summaryTable) { + $directTable = clone $summaryTable; + $inDirectTable = clone $summaryTable; + + $direct[$type] = $db->query( + $directTable + ->filterTemplate($template, IcingaObjectFilterHelper::INHERIT_DIRECT) + ->getQuery() + )->rowCount(); + $indirect[$type] = $db->query( + $inDirectTable + ->filterTemplate($template, IcingaObjectFilterHelper::INHERIT_INDIRECT) + ->getQuery() + )->rowCount(); } - $baseQuery = $db->select()->from( - ['o' => 'icinga_' . $oType], - $this->getTypeSummaryDefinitions() - )->joinLeft( - ['oi' => "icinga_${oType}_inheritance"], - "oi.${oType}_id = o.id", - [] - ); - - $query = clone($baseQuery); - $direct = $db->fetchRow( - $query->where("oi.parent_${oType}_id = ?", $id) - ); - $query = clone($baseQuery); - $indirect = $db->fetchRow( - $query->where("oi.parent_${oType}_id IN (?)", $ids) - ); - //$indirect->templates = count($ids) - 1; $total = []; - $types = array_keys($this->getTypes()); foreach ($types as $type) { - $total[$type] = $direct->$type + $indirect->$type; + $total[$type] = $direct[$type] + $indirect[$type]; } return (object) [ - 'direct' => $direct, - 'indirect' => $indirect, + 'direct' => (object) $direct, + 'indirect' => (object) $indirect, 'total' => (object) $total ]; } - protected function getSummaryLine($type, $extra = null) + protected function getSummaryTables(string $templateType, Db $connection) { - if ($extra !== null) { - $extra = " AND $extra"; - } - return "COALESCE(SUM(CASE WHEN o.object_type = '${type}'${extra} THEN 1 ELSE 0 END), 0)"; + return [ + 'templates' => TemplatesTable::create( + $templateType, + $connection + ), + 'objects' => ObjectsTable::create($templateType, $connection, $this->auth) + ->setBranchUuid($this->branchUuid) + ]; } } diff --git a/library/Director/Web/Table/TemplatesTable.php b/library/Director/Web/Table/TemplatesTable.php index be195b2..d6582fd 100644 --- a/library/Director/Web/Table/TemplatesTable.php +++ b/library/Director/Web/Table/TemplatesTable.php @@ -36,8 +36,8 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage { $type = $this->type; $this->enableMultiSelect( - "director/${type}s/edittemplates", - "director/${type}template", + "director/{$type}s/edittemplates", + "director/{$type}template", ['name'] ); } @@ -60,12 +60,12 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage $name, Html::tag( 'span', - ['style' => 'font-style: italic'], + ['class' => 'font-italic'], $this->translate(' - not in use -') ) ]; - $url = Url::fromPath("director/${type}template/usage", [ + $url = Url::fromPath("director/{$type}template/usage", [ 'name' => $name ]); @@ -101,8 +101,8 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage { $type = $this->getType(); $this->getQuery()->where( - "(EXISTS (SELECT ${type}_id FROM icinga_${type}_inheritance" - . " WHERE parent_${type}_id = o.id))" + "(EXISTS (SELECT {$type}_id FROM icinga_{$type}_inheritance" + . " WHERE parent_{$type}_id = o.id))" ); } @@ -110,8 +110,8 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage { $type = $this->getType(); $this->getQuery()->where( - "(NOT EXISTS (SELECT ${type}_id FROM icinga_${type}_inheritance" - . " WHERE parent_${type}_id = o.id))" + "(NOT EXISTS (SELECT {$type}_id FROM icinga_{$type}_inheritance" + . " WHERE parent_{$type}_id = o.id))" ); } @@ -135,8 +135,8 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage protected function prepareQuery() { $type = $this->getType(); - $used = "CASE WHEN EXISTS(SELECT 1 FROM icinga_${type}_inheritance oi" - . " WHERE oi.parent_${type}_id = o.id) THEN 'y' ELSE 'n' END"; + $used = "CASE WHEN EXISTS(SELECT 1 FROM icinga_{$type}_inheritance oi" + . " WHERE oi.parent_{$type}_id = o.id) THEN 'y' ELSE 'n' END"; $columns = [ 'object_name' => 'o.object_name', @@ -145,7 +145,7 @@ class TemplatesTable extends ZfQueryBasedTable implements FilterableByUsage 'is_used' => $used, ]; $query = $this->db()->select()->from( - ['o' => "icinga_${type}"], + ['o' => "icinga_{$type}"], $columns )->where( "o.object_type = 'template'" diff --git a/library/Director/Web/Tabs/InfraTabs.php b/library/Director/Web/Tabs/InfraTabs.php index 8a65c4e..ea7a0cc 100644 --- a/library/Director/Web/Tabs/InfraTabs.php +++ b/library/Director/Web/Tabs/InfraTabs.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Web\Tabs; use Icinga\Authentication\Auth; use gipfl\Translation\TranslationHelper; use gipfl\IcingaWeb2\Widget\Tabs; +use Icinga\Module\Director\Auth\Permission; class InfraTabs extends Tabs { @@ -24,21 +25,21 @@ class InfraTabs extends Tabs { $auth = $this->auth; - if ($auth->hasPermission('director/audit')) { + if ($auth->hasPermission(Permission::AUDIT)) { $this->add('activitylog', [ 'label' => $this->translate('Activity Log'), 'url' => 'director/config/activities' ]); } - if ($auth->hasPermission('director/deploy')) { + if ($auth->hasPermission(Permission::DEPLOY)) { $this->add('deploymentlog', [ 'label' => $this->translate('Deployments'), 'url' => 'director/config/deployments' ]); } - if ($auth->hasPermission('director/admin')) { + if ($auth->hasPermission(Permission::ADMIN)) { $this->add('infrastructure', [ 'label' => $this->translate('Infrastructure'), 'url' => 'director/dashboard', diff --git a/library/Director/Web/Tabs/MainTabs.php b/library/Director/Web/Tabs/MainTabs.php index 5ea2e9b..48ffa7c 100644 --- a/library/Director/Web/Tabs/MainTabs.php +++ b/library/Director/Web/Tabs/MainTabs.php @@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Web\Tabs; use gipfl\Translation\TranslationHelper; use gipfl\IcingaWeb2\Widget\Tabs; use Icinga\Authentication\Auth; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Web\Widget\Daemon\BackgroundDaemonState; use Icinga\Module\Director\Db; use Icinga\Module\Director\Health; @@ -26,7 +27,7 @@ class MainTabs extends Tabs 'label' => $this->translate('Overview'), 'url' => 'director' ]); - if ($this->auth->hasPermission('director/admin')) { + if ($this->auth->hasPermission(Permission::ADMIN)) { $this->add('health', [ 'label' => $this->translate('Health'), 'url' => 'director/health' @@ -39,7 +40,7 @@ class MainTabs extends Tabs public function render() { - if ($this->auth->hasPermission('director/admin')) { + if ($this->auth->hasPermission(Permission::ADMIN)) { if ($this->getActiveName() !== 'health') { $state = $this->getHealthState(); if ($state->isProblem()) { diff --git a/library/Director/Web/Tabs/ObjectTabs.php b/library/Director/Web/Tabs/ObjectTabs.php index cbd3f15..c355304 100644 --- a/library/Director/Web/Tabs/ObjectTabs.php +++ b/library/Director/Web/Tabs/ObjectTabs.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Web\Tabs; use Icinga\Authentication\Auth; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Objects\IcingaObject; use gipfl\Translation\TranslationHelper; use gipfl\IcingaWeb2\Widget\Tabs; @@ -46,10 +47,10 @@ class ObjectTabs extends Tabs protected function addTabsForNewObject() { $type = $this->type; - $this->add('add', array( + $this->add('add', [ 'url' => sprintf('director/%s/add', $type), 'label' => sprintf($this->translate('Add %s'), ucfirst($type)), - )); + ]); } protected function addTabsForExistingObject() @@ -59,14 +60,12 @@ class ObjectTabs extends Tabs $object = $this->object; $params = $object->getUrlParams(); - if (! $object->isExternal() - || in_array($object->getShortTableName(), $this->allowedExternals) - ) { - $this->add('modify', array( + if (! $object->isExternal() || in_array($object->getShortTableName(), $this->allowedExternals)) { + $this->add('modify', [ 'url' => sprintf('director/%s', $type), 'urlParams' => $params, 'label' => $this->translate(ucfirst($type)) - )); + ]); } if ($object->getShortTableName() === 'host') { $this->add('services', [ @@ -76,19 +75,17 @@ class ObjectTabs extends Tabs ]); } - if ($auth->hasPermission('director/showconfig')) { - if ($object->getShortTableName() !== 'service' - || $object->get('service_set_id') === null - ) { - $this->add('render', array( + if ($auth->hasPermission(Permission::SHOW_CONFIG)) { + if ($object->getShortTableName() !== 'service' || $object->get('service_set_id') === null) { + $this->add('render', [ 'url' => sprintf('director/%s/render', $type), 'urlParams' => $params, 'label' => $this->translate('Preview'), - )); + ]); } } - if ($auth->hasPermission('director/audit')) { + if ($auth->hasPermission(Permission::AUDIT)) { $this->add('history', array( 'url' => sprintf('director/%s/history', $type), 'urlParams' => $params, @@ -96,7 +93,7 @@ class ObjectTabs extends Tabs )); } - if ($auth->hasPermission('director/admin') && $this->hasFields()) { + if ($auth->hasPermission(Permission::ADMIN) && $this->hasFields()) { $this->add('fields', array( 'url' => sprintf('director/%s/fields', $type), 'urlParams' => $params, @@ -117,7 +114,7 @@ class ObjectTabs extends Tabs if ($object->supportsRanges()) { $this->add('ranges', [ - 'url' => "director/${type}/ranges", + 'url' => "director/{$type}/ranges", 'urlParams' => $params, 'label' => $this->translate('Ranges') ]); @@ -138,11 +135,11 @@ class ObjectTabs extends Tabs ]); } - if ($object->getShortTableName() === 'host' && $auth->hasPermission('director/hosts')) { + if ($object->getShortTableName() === 'host' && $auth->hasPermission(Permission::HOSTS)) { $this->add('agent', [ - 'url' => 'director/host/agent', + 'url' => 'director/host/agent', 'urlParams' => $params, - 'label' => $this->translate('Agent') + 'label' => $this->translate('Agent') ]); } } diff --git a/library/Director/Web/Tabs/ObjectsTabs.php b/library/Director/Web/Tabs/ObjectsTabs.php index 4f9e5a8..9d2a737 100644 --- a/library/Director/Web/Tabs/ObjectsTabs.php +++ b/library/Director/Web/Tabs/ObjectsTabs.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Director\Web\Tabs; use Icinga\Authentication\Auth; +use Icinga\Module\Director\Auth\Permission; use Icinga\Module\Director\Objects\IcingaObject; use gipfl\Translation\TranslationHelper; use gipfl\IcingaWeb2\Widget\Tabs; @@ -21,65 +22,66 @@ class ObjectsTabs extends Tabs $plType = strtolower(preg_replace('/cys$/', 'cies', $shortName . 's')); $plType = str_replace('_', '-', $plType); - if ($auth->hasPermission("director/${plType}")) { - $this->add('index', array( + if ($auth->hasPermission("director/{$plType}")) { + $this->add('index', [ 'url' => sprintf('director/%s', $plType), 'label' => $this->translate(ucfirst($plType)), - )); + ]); } if ($object->getShortTableName() === 'command') { - $this->add('external', array( - 'url' => sprintf('director/%s', strtolower($plType)), + $this->add('external', [ + 'url' => sprintf('director/%s', strtolower($plType)), 'urlParams' => ['type' => 'external_object'], - 'label' => $this->translate('External'), - )); + 'label' => $this->translate('External'), + ]); } - if ($auth->hasPermission('director/admin') || ( + if ($auth->hasPermission(Permission::ADMIN) + || ( $object->getShortTableName() === 'notification' - && $auth->hasPermission('director/notifications') + && $auth->hasPermission(Permission::NOTIFICATIONS) ) || ( $object->getShortTableName() === 'scheduled_downtime' - && $auth->hasPermission('director/scheduled-downtimes') + && $auth->hasPermission(Permission::SCHEDULED_DOWNTIMES) )) { if ($object->supportsApplyRules()) { - $this->add('applyrules', array( - 'url' => sprintf('director/%s/applyrules', $plType), + $this->add('applyrules', [ + 'url' => sprintf('director/%s/applyrules', $plType), 'label' => $this->translate('Apply') - )); + ]); } } - if ($auth->hasPermission('director/admin') && $type !== 'zone') { + if ($auth->hasPermission(Permission::ADMIN) && $type !== 'zone') { if ($object->supportsImports()) { - $this->add('templates', array( - 'url' => sprintf('director/%s/templates', $plType), + $this->add('templates', [ + 'url' => sprintf('director/%s/templates', $plType), 'label' => $this->translate('Templates'), - )); + ]); } if ($object->supportsGroups()) { - $this->add('groups', array( - 'url' => sprintf('director/%sgroups', $typeUrl), + $this->add('groups', [ + 'url' => sprintf('director/%sgroups', $typeUrl), 'label' => $this->translate('Groups') - )); + ]); } } - if ($auth->hasPermission('director/admin')) { + if ($auth->hasPermission(Permission::ADMIN)) { if ($object->supportsChoices()) { - $this->add('choices', array( - 'url' => sprintf('director/templatechoices/%s', $shortName), + $this->add('choices', [ + 'url' => sprintf('director/templatechoices/%s', $shortName), 'label' => $this->translate('Choices') - )); + ]); } } - if ($object->supportsSets() && $auth->hasPermission("director/${typeUrl}sets")) { - $this->add('sets', array( - 'url' => sprintf('director/%s/sets', $plType), + if ($object->supportsSets() && $auth->hasPermission("director/{$typeUrl}sets")) { + $this->add('sets', [ + 'url' => sprintf('director/%s/sets', $plType), 'label' => $this->translate('Sets') - )); + ]); } } } diff --git a/library/Director/Web/Tree/TemplateTreeRenderer.php b/library/Director/Web/Tree/TemplateTreeRenderer.php index e238ded..8b23518 100644 --- a/library/Director/Web/Tree/TemplateTreeRenderer.php +++ b/library/Director/Web/Tree/TemplateTreeRenderer.php @@ -71,7 +71,7 @@ class TemplateTreeRenderer extends BaseHtmlElement } else { $li->add(Link::create( $tree['name'], - "director/${type}template/usage", + "director/{$type}template/usage", array('name' => $tree['name']), array('class' => 'icon-' .$type) )); diff --git a/library/Director/Web/Widget/ActivityLogInfo.php b/library/Director/Web/Widget/ActivityLogInfo.php index 8454b26..2b64fd4 100644 --- a/library/Director/Web/Widget/ActivityLogInfo.php +++ b/library/Director/Web/Widget/ActivityLogInfo.php @@ -3,7 +3,10 @@ namespace Icinga\Module\Director\Web\Widget; use gipfl\Json\JsonString; +use Icinga\Module\Director\Data\FieldReferenceLoader; +use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshotFieldResolver; use Icinga\Module\Director\Objects\DirectorActivityLog; +use Icinga\Module\Director\Web\Form\IcingaObjectFieldLoader; use ipl\Html\HtmlDocument; use ipl\Html\HtmlElement; use Icinga\Date\DateFormatter; @@ -83,8 +86,7 @@ class ActivityLogInfo extends HtmlDocument /** @var Url $url */ $url = $url->without('checksum')->without('show'); $div = Html::tag('div', [ - 'class' => 'pagination-control', - 'style' => 'float: right; width: 5em' + 'class' => ['pagination-control', 'activity-log-control'], ]); $ul = Html::tag('ul', ['class' => 'nav tab-nav']); @@ -434,11 +436,30 @@ class ActivityLogInfo extends HtmlDocument { if ($object instanceof IcingaService) { return $this->previewService($object); + } elseif ($object instanceof IcingaServiceSet) { + return $this->previewServiceSet($object); } else { return $object->toSingleIcingaConfig(); } } + /** + * Render service set to be previewed + * + * @param IcingaServiceSet $object + * + * @return IcingaConfig + */ + protected function previewServiceSet(IcingaServiceSet $object) + { + $config = $object->toSingleIcingaConfig(); + foreach ($object->getCachedServices() as $service) { + $service->renderToConfig($config); + } + + return $config; + } + protected function previewService(IcingaService $service) { if (($set = $service->get('service_set')) !== null) { @@ -625,10 +646,27 @@ class ActivityLogInfo extends HtmlDocument $newProps['object_type'] = $props->object_type; } - return IcingaObject::createByType( + $object = IcingaObject::createByType( $type, $newProps, $this->db - )->setProperties((array) $props); + ); + + if ($type === 'icinga_service_set' && isset($props->services)) { + $services = []; + foreach ($props->services as $service) { + $services[$service->object_name] = IcingaObject::createByType( + 'icinga_service', + (array) $service, + $this->db + ); + } + + /** @var IcingaServiceSet $object */ + $object->setCachedServices($services); + unset($props->services); + } + + return $object->setProperties((array) $props); } } diff --git a/library/Director/Web/Widget/AdditionalTableActions.php b/library/Director/Web/Widget/AdditionalTableActions.php index 978f399..7495189 100644 --- a/library/Director/Web/Widget/AdditionalTableActions.php +++ b/library/Director/Web/Widget/AdditionalTableActions.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Web\Widget; +use Icinga\Module\Director\Auth\Permission; use ipl\Html\Html; use ipl\Html\HtmlDocument; use gipfl\IcingaWeb2\Icon; @@ -35,10 +36,10 @@ class AdditionalTableActions public function appendTo(HtmlDocument $parent) { $links = []; - if ($this->hasPermission('director/admin')) { + if ($this->hasPermission(Permission::ADMIN)) { $links[] = $this->createDownloadJsonLink(); } - if ($this->hasPermission('director/showsql')) { + if ($this->hasPermission(Permission::SHOW_SQL)) { $links[] = $this->createShowSqlToggle(); } diff --git a/library/Director/Web/Widget/BranchedObjectHint.php b/library/Director/Web/Widget/BranchedObjectHint.php index ec16094..c50f923 100644 --- a/library/Director/Web/Widget/BranchedObjectHint.php +++ b/library/Director/Web/Widget/BranchedObjectHint.php @@ -15,33 +15,45 @@ class BranchedObjectHint extends HtmlDocument { use TranslationHelper; - public function __construct(Branch $branch, Auth $auth, BranchedObject $object = null) + public function __construct(Branch $branch, Auth $auth, BranchedObject $object = null, $hasPreferredBranch = false) { if (! $branch->isBranch()) { - return; - } - $hook = Branch::requireHook(); - - $name = $branch->getName(); - if (substr($name, 0, 1) === '/') { - $label = $this->translate('this configuration branch'); + if ($hasPreferredBranch) { + $main = true; + $hintMethod = 'warning'; + $link = $this->translate('the main configuration branch'); + $deployHint = ' ' . $this->translate('This will be part of the next deployment'); + } else { + return; + } } else { - $label = $name; + $main = false; + $hintMethod = 'info'; + $deployHint = ' ' . $this->translate('This will not be part of any deployment, unless being merged'); + $hook = Branch::requireHook(); + $name = $branch->getName(); + if (substr($name, 0, 1) === '/') { + $label = $this->translate('this configuration branch'); + } else { + $label = $name; + } + $link = $hook->linkToBranch($branch, $auth, $label); } - $link = $hook->linkToBranch($branch, $auth, $label); + if ($object === null) { - $this->add(Hint::info(Html::sprintf($this->translate( - 'This object will be created in %s. It will not be part of any deployment' - . ' unless being merged' - ), $link))); + $this->add(Hint::$hintMethod(Html::sprintf($this->translate( + 'This object will be created in %s.' + ) . $deployHint, $link))); return; } if (! $object->hasBeenTouchedByBranch()) { - $this->add(Hint::info(Html::sprintf($this->translate( - 'Your changes will be stored in %s. The\'ll not be part of any deployment' - . ' unless being merged' - ), $link))); + $this->add(Hint::$hintMethod(Html::sprintf($this->translate( + 'Your changes are going to be stored in %s.' + ) . $deployHint, $link))); + return; + } + if ($main) { return; } diff --git a/library/Director/Web/Widget/BranchedObjectsHint.php b/library/Director/Web/Widget/BranchedObjectsHint.php index d689178..3f00f9e 100644 --- a/library/Director/Web/Widget/BranchedObjectsHint.php +++ b/library/Director/Web/Widget/BranchedObjectsHint.php @@ -13,9 +13,14 @@ class BranchedObjectsHint extends HtmlDocument { use TranslationHelper; - public function __construct(Branch $branch, Auth $auth) + public function __construct(Branch $branch, Auth $auth, $hasPreferredBranch = false) { if (! $branch->isBranch()) { + if ($hasPreferredBranch) { + $this->add(Hint::warning($this->translate( + "You're currently in the master branch, your changes will make part of the next Deployment" + ))); + } return; } $hook = Branch::requireHook(); diff --git a/library/Director/Web/Widget/DeploymentInfo.php b/library/Director/Web/Widget/DeploymentInfo.php index 110200f..1f87abc 100644 --- a/library/Director/Web/Widget/DeploymentInfo.php +++ b/library/Director/Web/Widget/DeploymentInfo.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Web\Widget; +use Icinga\Module\Director\Auth\Permission; use ipl\Html\HtmlDocument; use Icinga\Authentication\Auth; use Icinga\Module\Director\IcingaConfig\IcingaConfig; @@ -55,7 +56,7 @@ class DeploymentInfo extends HtmlDocument 'url' => $request->getUrl() ))->activate('deployment'); - if ($dep->config_checksum !== null && $auth->hasPermission('director/showconfig')) { + if ($dep->config_checksum !== null && $auth->hasPermission(Permission::SHOW_CONFIG)) { $tabs->add('config', array( 'label' => $this->translate('Config'), 'url' => 'director/config/files', @@ -72,7 +73,8 @@ class DeploymentInfo extends HtmlDocument protected function createInfoTable() { $dep = $this->deployment; - $table = new NameValueTable(); + $table = (new NameValueTable()) + ->addAttributes(['class' => 'deployment-details']); $table->addNameValuePairs([ $this->translate('Deployment time') => $dep->start_time, $this->translate('Sent to') => $dep->peer_identity, @@ -135,16 +137,21 @@ class DeploymentInfo extends HtmlDocument } else { return [$this->translate('Unknown, failed to collect related information'), new Icon('help')]; } - } elseif ($dep->startup_succeeded === 'y') { - return $this->colored('green', [$this->translate('Succeeded'), new Icon('ok')]); } else { - return $this->colored('red', [$this->translate('Failed'), new Icon('cancel')]); - } - } + $div = Html::tag('div')->setSeparator(' '); - protected function colored($color, array $content) - { - return Html::tag('div', ['style' => "color: $color;"], $content)->setSeparator(' '); + if ($dep->startup_succeeded === 'y') { + $div + ->addAttributes(['class' => 'succeeded']) + ->add([$this->translate('Succeeded'), new Icon('ok')]); + } else { + $div + ->addAttributes(['class' => 'failed']) + ->add([$this->translate('Failed'), new Icon('cancel')]); + } + + return $div; + } } public function render() diff --git a/library/Director/Web/Widget/IcingaObjectInspection.php b/library/Director/Web/Widget/IcingaObjectInspection.php index 61f3567..d9cf69d 100644 --- a/library/Director/Web/Widget/IcingaObjectInspection.php +++ b/library/Director/Web/Widget/IcingaObjectInspection.php @@ -205,7 +205,7 @@ class IcingaObjectInspection extends BaseHtmlElement $this->add(Html::tag('p')->add(Html::sprintf( 'The configuration for this object has been rendered by Icinga' . ' Director %s to %s', - DateFormatter::timeAgo(strtotime($deployment->start_time, false)), + DateFormatter::timeAgo(strtotime($deployment->start_time)), $this->linkToSourceLocation($deployment, $source) ))); } diff --git a/module.info b/module.info index 631d881..214809a 100644 --- a/module.info +++ b/module.info @@ -1,6 +1,6 @@ Name: Icinga Director -Version: 1.10.2 -Depends: reactbundle (>=0.9.0), ipl (>=0.5.0), incubator (>=0.18.0) +Version: 1.11.1 +Depends: reactbundle (>=0.9.0), ipl (>=0.5.0), incubator (>=0.21.0) Description: Director - Config tool for Icinga 2 Icinga Director is a configuration tool that has been designed to make Icinga 2 configuration easy and understandable. diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..259e940 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,706 @@ +parameters: + ignoreErrors: + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: application/controllers/BranchController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: application/controllers/BranchController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Table\\\\ObjectsTable\\:\\:setType\\(\\)\\.$#" + count: 1 + path: application/controllers/CommandsController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: application/controllers/ConfigController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: application/controllers/ConfigController.php + + - + message: "#^Call to an undefined method Icinga\\\\Web\\\\View\\:\\:formSelect\\(\\)\\.$#" + count: 2 + path: application/controllers/ConfigController.php + + - + message: "#^Call to an undefined method Icinga\\\\Data\\\\Filter\\\\Filter\\:\\:filters\\(\\)\\.$#" + count: 2 + path: application/controllers/HostsController.php + + - + message: "#^PHPDoc tag @var has invalid value \\(\\$filter FilterChain\\)\\: Unexpected token \"\\$filter\", expected type at offset 9$#" + count: 2 + path: application/controllers/HostsController.php + + - + message: "#^PHPDoc tag @var has invalid value \\(\\$sub FilterChain\\)\\: Unexpected token \"\\$sub\", expected type at offset 9$#" + count: 2 + path: application/controllers/HostsController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: application/controllers/ImportsourceController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: application/controllers/ImportsourceController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: application/controllers/JobController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: application/controllers/JobController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: application/controllers/KickstartController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: application/controllers/KickstartController.php + + - + message: "#^Variable \\$tab in PHPDoc tag @var does not exist\\.$#" + count: 1 + path: application/controllers/NotificationController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\DirectorObjectForm\\:\\:createApplyRuleFor\\(\\)\\.$#" + count: 1 + path: application/controllers/ServiceController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: application/controllers/SyncruleController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: application/controllers/SyncruleController.php + + - + message: "#^Variable \\$after might not be defined\\.$#" + count: 3 + path: application/controllers/SyncruleController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: application/controllers/TemplatechoiceController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: application/controllers/TemplatechoiceController.php + + - + message: "#^Call to an undefined method Zend_View_Interface\\:\\:icon\\(\\)\\.$#" + count: 1 + path: application/forms/DeployConfigForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getSettings\\(\\)\\.$#" + count: 2 + path: application/forms/DirectorDatafieldForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getSettings\\(\\)\\.$#" + count: 1 + path: application/forms/DirectorJobForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getObjectName\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaAddServiceSetForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getResolvedProperty\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaAddServiceSetForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:setImports\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaDependencyForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getAppliedGroups\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaHostForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getGroups\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaHostForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Forms\\\\IcingaImportObjectForm\\:\\:addNote\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaImportObjectForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getUrlParams\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaScheduledDowntimeForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:isApplyRule\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaScheduledDowntimeForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:isApplyRule\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaServiceDictionaryMemberForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:isApplyRule\\(\\)\\.$#" + count: 2 + path: application/forms/IcingaServiceForm.php + + - + message: "#^Cannot cast Icinga\\\\Data\\\\Filter\\\\Filter to string\\.$#" + count: 1 + path: application/forms/IcingaServiceForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getResolvedProperty\\(\\)\\.$#" + count: 1 + path: application/forms/IcingaServiceSetForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getSetting\\(\\)\\.$#" + count: 1 + path: application/forms/ImportRowModifierForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getSettings\\(\\)\\.$#" + count: 1 + path: application/forms/ImportRowModifierForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getSettings\\(\\)\\.$#" + count: 1 + path: application/forms/ImportSourceForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Forms\\\\RestoreBasketForm\\:\\:Window\\(\\)\\.$#" + count: 1 + path: application/forms/RestoreBasketForm.php + + - + message: "#^Function translate not found\\.$#" + count: 8 + path: application/locale/translateMe.php + + - + message: "#^Call to an undefined method Zend_View_Interface\\:\\:formIplExtensibleSet\\(\\)\\.$#" + count: 1 + path: application/views/helpers/FormDataFilter.php + + - + message: "#^Call to an undefined method Zend_View_Interface\\:\\:formSelect\\(\\)\\.$#" + count: 1 + path: application/views/helpers/FormDataFilter.php + + - + message: "#^Call to an undefined method Zend_View_Interface\\:\\:formSubmit\\(\\)\\.$#" + count: 1 + path: application/views/helpers/FormDataFilter.php + + - + message: "#^Call to an undefined method Zend_View_Interface\\:\\:formText\\(\\)\\.$#" + count: 4 + path: application/views/helpers/FormDataFilter.php + + - + message: "#^Call to an undefined method Zend_View_Interface\\:\\:translate\\(\\)\\.$#" + count: 1 + path: application/views/helpers/FormDataFilter.php + + - + message: "#^Variable \\$id might not be defined\\.$#" + count: 1 + path: application/views/helpers/FormStoredPassword.php + + - + message: "#^Binary operation \"\\*\\=\" between string and 1024 results in an error\\.$#" + count: 1 + path: library/Director/Application/MemoryLimit.php + + - + message: "#^Constructor of class Icinga\\\\Module\\\\Director\\\\Core\\\\RestApiClient has an unused parameter \\$cn\\.$#" + count: 1 + path: library/Director/Core/RestApiClient.php + + - + message: "#^Binary operation \"\\*\" between string and 1000 results in an error\\.$#" + count: 1 + path: library/Director/Daemon/DaemonUtil.php + + - + message: "#^Anonymous function has an unused use \\$id\\.$#" + count: 2 + path: library/Director/Daemon/JobRunner.php + + - + message: "#^Variable \\$hook in PHPDoc tag @var does not exist\\.$#" + count: 1 + path: library/Director/Dashboard/BranchesDashboard.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Restriction\\\\HostgroupRestriction\\:\\:applyToHostGroupsQuery\\(\\)\\.$#" + count: 1 + path: library/Director/Dashboard/Dashboard.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbConnection\\:\\:db\\(\\)\\.$#" + count: 1 + path: library/Director/Data/Db/DbConnection.php + + - + message: "#^Call to an undefined method Icinga\\\\Data\\\\Filter\\\\Filter\\:\\:filters\\(\\)\\.$#" + count: 1 + path: library/Director/Data/Db/IcingaObjectFilterRenderer.php + + - + message: "#^Variable \\$filter in PHPDoc tag @var does not match any variable in the foreach loop\\: \\$sub$#" + count: 1 + path: library/Director/Data/Db/IcingaObjectFilterRenderer.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\IcingaObjectQuery\\:\\:tableAliases\\(\\)\\.$#" + count: 1 + path: library/Director/Data/Db/IcingaObjectQuery.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getObjectName\\(\\)\\.$#" + count: 1 + path: library/Director/Data/Db/ServiceSetQueryBuilder.php + + - + message: "#^Access to an undefined property object\\:\\:\\$datalist\\.$#" + count: 1 + path: library/Director/Data/Exporter.php + + - + message: "#^PHPDoc tag @param references unknown parameter\\: \\$id$#" + count: 1 + path: library/Director/Data/FieldReferenceLoader.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:toPlainObject\\(\\)\\.$#" + count: 1 + path: library/Director/Data/HostServiceLoader.php + + - + message: "#^Call to an undefined static method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:fromPlainObject\\(\\)\\.$#" + count: 1 + path: library/Director/Data/HostServiceLoader.php + + - + message: "#^PHPDoc tag @param for parameter \\$implementation with type class\\-string\\|Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject is not subtype of native type string\\.$#" + count: 1 + path: library/Director/Data/ObjectImporter.php + + - + message: "#^Access to an undefined property object\\:\\:\\$format\\.$#" + count: 1 + path: library/Director/Data/PropertiesFilter/ArrayCustomVariablesFilter.php + + - + message: "#^PHPDoc tag @param references unknown parameter\\: \\$object$#" + count: 1 + path: library/Director/Data/SerializableValue.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\QuickForm\\:\\:getDb\\(\\)\\.$#" + count: 1 + path: library/Director/DataType/DataTypeDatalist.php + + - + message: "#^Call to an undefined method Icinga\\\\Application\\\\ApplicationBootstrap\\:\\:getRequest\\(\\)\\.$#" + count: 1 + path: library/Director/Db/Branch/Branch.php + + - + message: "#^PHPDoc tag @param references unknown parameter\\: \\$db$#" + count: 1 + path: library/Director/Db/Branch/Branch.php + + - + message: "#^PHPDoc tag @var has invalid value \\(@var string\\)\\: Unexpected token \"@var\", expected type at offset 9$#" + count: 1 + path: library/Director/Db/Branch/Branch.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Db\\\\Branch\\\\Branch\\:\\:getBytes\\(\\)\\.$#" + count: 1 + path: library/Director/Db/Branch/BranchMerger.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:toPlainObject\\(\\)\\.$#" + count: 1 + path: library/Director/Db/Branch/BranchedObject.php + + - + message: "#^Call to an undefined method Zend_Db_Adapter_Abstract\\:\\:exec\\(\\)\\.$#" + count: 4 + path: library/Director/Db/Housekeeping.php + + - + message: "#^Variable \\$helper in PHPDoc tag @var does not exist\\.$#" + count: 1 + path: library/Director/Db/MembershipHousekeeping.php + + - + message: "#^Variable \\$object in PHPDoc tag @var does not exist\\.$#" + count: 2 + path: library/Director/DirectorObject/Automation/BasketSnapshot.php + + - + message: "#^Access to an undefined property object\\:\\:\\$datalist_id\\.$#" + count: 1 + path: library/Director/DirectorObject/Automation/BasketSnapshotFieldResolver.php + + - + message: "#^Binary operation \"\\|\" between string\\|false and string results in an error\\.$#" + count: 1 + path: library/Director/Filter/CidrExpression.php + + - + message: "#^Class Icinga\\\\Module\\\\Director\\\\Db\\\\Branch\\\\BranchStore referenced with incorrect case\\: Icinga\\\\Module\\\\Director\\\\Db\\\\Branch\\\\BranchSTore\\.$#" + count: 3 + path: library/Director/Hook/BranchSupportHook.php + + - + message: "#^Call to an undefined method Icinga\\\\Application\\\\ApplicationBootstrap\\:\\:getRequest\\(\\)\\.$#" + count: 1 + path: library/Director/IcingaConfig/AgentWizard.php + + - + message: "#^Binary operation \"\\*\" between string and 3600 results in an error\\.$#" + count: 1 + path: library/Director/IcingaConfig/IcingaConfigHelper.php + + - + message: "#^Binary operation \"\\*\" between string and 60 results in an error\\.$#" + count: 1 + path: library/Director/IcingaConfig/IcingaConfigHelper.php + + - + message: "#^Binary operation \"\\*\" between string and 86400 results in an error\\.$#" + count: 1 + path: library/Director/IcingaConfig/IcingaConfigHelper.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\QuickForm\\:\\:getSentOrObjectSetting\\(\\)\\.$#" + count: 3 + path: library/Director/Import/ImportSourceRestApi.php + + - + message: "#^Access to an undefined property object\\:\\:\\$order\\.$#" + count: 1 + path: library/Director/Objects/IcingaCommandArgument.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Objects\\\\IcingaService\\:\\:assignments\\(\\)\\.$#" + count: 1 + path: library/Director/Objects/IcingaDependency.php + + - + message: "#^Call to an undefined static method Icinga\\\\Module\\\\Director\\\\Objects\\\\IcingaObject\\:\\:renderAssignments\\(\\)\\.$#" + count: 1 + path: library/Director/Objects/IcingaDependency.php + + - + message: "#^Default value of the parameter \\#2 \\$preserve \\(array\\) of method Icinga\\\\Module\\\\Director\\\\Objects\\\\IcingaObject\\:\\:replaceWith\\(\\) is incompatible with type null\\.$#" + count: 1 + path: library/Director/Objects/IcingaObject.php + + - + message: "#^Static call to instance method stdClass\\:\\:getKeyColumnName\\(\\)\\.$#" + count: 1 + path: library/Director/Objects/IcingaObject.php + + - + message: "#^Variable \\$imports in PHPDoc tag @var does not exist\\.$#" + count: 1 + path: library/Director/Objects/IcingaObject.php + + - + message: "#^PHPDoc tag @param references unknown parameter\\: \\$filter$#" + count: 1 + path: library/Director/Objects/IcingaObjectField.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Objects\\\\IcingaRanges\\:\\:\\$objectIdColumn\\.$#" + count: 3 + path: library/Director/Objects/IcingaRanges.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Objects\\\\IcingaRanges\\:\\:\\$rangeClass\\.$#" + count: 1 + path: library/Director/Objects/IcingaRanges.php + + - + message: "#^Call to protected method getRelationObjectClass\\(\\) of class Icinga\\\\Module\\\\Director\\\\Objects\\\\IcingaObject\\.$#" + count: 1 + path: library/Director/Objects/IcingaRelatedObject.php + + - + message: "#^Undefined variable\\: \\$object$#" + count: 2 + path: library/Director/Objects/IcingaRelatedObject.php + + - + message: "#^Undefined variable\\: \\$name$#" + count: 1 + path: library/Director/Objects/IcingaTemplateResolver.php + + - + message: "#^Undefined variable\\: \\$type$#" + count: 2 + path: library/Director/Objects/IcingaTemplateResolver.php + + - + message: "#^Variable \\$obj in PHPDoc tag @var does not exist\\.$#" + count: 1 + path: library/Director/Objects/ImportRowModifier.php + + - + message: "#^Call to an undefined method Icinga\\\\Data\\\\Filter\\\\Filter\\:\\:filters\\(\\)\\.$#" + count: 1 + path: library/Director/Objects/ObjectApplyMatches.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\QuickForm\\:\\:getDb\\(\\)\\.$#" + count: 1 + path: library/Director/PropertyModifier/PropertyModifierMap.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\QuickForm\\:\\:getSetting\\(\\)\\.$#" + count: 1 + path: library/Director/PropertyModifier/PropertyModifierMap.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\QuickForm\\:\\:getSetting\\(\\)\\.$#" + count: 1 + path: library/Director/PropertyModifier/PropertyModifierRejectOrSelect.php + + - + message: "#^Access to an undefined property Zend_Controller_Action_HelperBroker\\:\\:\\$viewRenderer\\.$#" + count: 1 + path: library/Director/Web/Controller/ActionController.php + + - + message: "#^Access to an undefined property Zend_View_Interface\\:\\:\\$compact\\.$#" + count: 1 + path: library/Director/Web/Controller/ActionController.php + + - + message: "#^Access to an undefined property Zend_View_Interface\\:\\:\\$controls\\.$#" + count: 1 + path: library/Director/Web/Controller/ActionController.php + + - + message: "#^Call to an undefined method Zend_Controller_Action_HelperBroker\\:\\:layout\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Controller/ActionController.php + + - + message: "#^Call to an undefined method Zend_Controller_Request_Abstract\\:\\:getHeader\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Controller/ActionController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: library/Director/Web/Controller/ObjectController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Controller/ObjectController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: library/Director/Web/Controller/ObjectsController.php + + - + message: "#^Call to an undefined method Icinga\\\\Data\\\\Filter\\\\Filter\\:\\:filters\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Controller/ObjectsController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getObjectName\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Controller/ObjectsController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Controller/ObjectsController.php + + - + message: "#^PHPDoc tag @var has invalid value \\(\\$ex FilterChain\\|FilterExpression\\)\\: Unexpected token \"\\$ex\", expected type at offset 9$#" + count: 1 + path: library/Director/Web/Controller/ObjectsController.php + + - + message: "#^PHPDoc tag @var has invalid value \\(\\$filter FilterChain\\)\\: Unexpected token \"\\$filter\", expected type at offset 9$#" + count: 1 + path: library/Director/Web/Controller/ObjectsController.php + + - + message: "#^PHPDoc tag @var has invalid value \\(\\$sub FilterChain\\)\\: Unexpected token \"\\$sub\", expected type at offset 9$#" + count: 1 + path: library/Director/Web/Controller/ObjectsController.php + + - + message: "#^Access to an undefined property Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:\\$branch\\.$#" + count: 1 + path: library/Director/Web/Controller/TemplateController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Controller\\\\ActionController\\:\\:getBranchStore\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Controller/TemplateController.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:getShortTableName\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Form/DirectorObjectForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:listImportNames\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Form/DirectorObjectForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:ranges\\(\\)\\.$#" + count: 2 + path: library/Director/Web/Form/DirectorObjectForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:supportsApplyRules\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Form/DirectorObjectForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Data\\\\Db\\\\DbObject\\:\\:supportsImports\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Form/DirectorObjectForm.php + + - + message: "#^Class Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\Element\\\\Boolean referenced with incorrect case\\: Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\Element\\\\boolean\\.$#" + count: 1 + path: library/Director/Web/Form/Element/InstanceSummary.php + + - + message: "#^Class Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\Element\\\\Boolean referenced with incorrect case\\: Icinga\\\\Module\\\\Director\\\\Web\\\\Form\\\\Element\\\\boolean\\.$#" + count: 1 + path: library/Director/Web/Form/Element/SimpleNote.php + + - + message: "#^Variable \\$file might not be defined\\.$#" + count: 1 + path: library/Director/Web/Form/FormLoader.php + + - + message: "#^PHPDoc tag @var has invalid value \\(\\$filter FilterChain\\|FilterExpression\\)\\: Unexpected token \"\\$filter\", expected type at offset 9$#" + count: 1 + path: library/Director/Web/Form/IcingaObjectFieldLoader.php + + - + message: "#^Variable \\$hook in PHPDoc tag @var does not match assigned variable \\$type\\.$#" + count: 1 + path: library/Director/Web/Form/IcingaObjectFieldLoader.php + + - + message: "#^PHPDoc tag @var above assignment does not specify variable name\\.$#" + count: 1 + path: library/Director/Web/Form/QuickBaseForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Application\\\\ApplicationBootstrap\\:\\:getFrontController\\(\\)\\.$#" + count: 4 + path: library/Director/Web/Form/QuickForm.php + + - + message: "#^Variable \\$req in PHPDoc tag @var does not exist\\.$#" + count: 1 + path: library/Director/Web/Form/QuickForm.php + + - + message: "#^Call to an undefined method Icinga\\\\Application\\\\ApplicationBootstrap\\:\\:getRequest\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php + + - + message: "#^PHPDoc tag @var has invalid value \\(\\$app Web\\)\\: Unexpected token \"\\$app\", expected type at offset 9$#" + count: 1 + path: library/Director/Web/Navigation/Renderer/ConfigHealthItemRenderer.php + + - + message: "#^Method gipfl\\\\IcingaWeb2\\\\Widget\\\\ControlsAndContent\\:\\:addTitle\\(\\) invoked with 2 parameters, 1 required\\.$#" + count: 1 + path: library/Director/Web/ObjectPreview.php + + - + message: "#^Access to an undefined property object\\:\\:\\$object_name\\.$#" + count: 2 + path: library/Director/Web/Table/GroupMemberTable.php + + - + message: "#^Comparison operation \"\\<\" between \\(array\\|float\\|int\\) and int\\<1, max\\> results in an error\\.$#" + count: 1 + path: library/Director/Web/Table/JobTable.php + + - + message: "#^Method ipl\\\\Html\\\\BaseHtmlElement\\:\\:tag\\(\\) invoked with 3 parameters, 0 required\\.$#" + count: 1 + path: library/Director/Web/Table/PropertymodifierTable.php + + - + message: "#^Call to an undefined method Icinga\\\\Application\\\\ApplicationBootstrap\\:\\:getViewRenderer\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Table/QuickTable.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Table\\\\QuickTable\\:\\:renderAdditionalActions\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Table/QuickTable.php + + - + message: "#^Call to an undefined method Icinga\\\\Web\\\\Widget\\\\AbstractWidget\\:\\:setColumns\\(\\)\\.$#" + count: 1 + path: library/Director/Web/Table/QuickTable.php + + - + message: "#^Variable \\$file might not be defined\\.$#" + count: 1 + path: library/Director/Web/Table/TableLoader.php + + - + message: "#^Call to an undefined method Icinga\\\\Module\\\\Director\\\\Web\\\\Widget\\\\IcingaObjectInspection\\:\\:db\\(\\)\\.$#" + count: 2 + path: library/Director/Web/Widget/IcingaObjectInspection.php diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..c02492f --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,40 @@ +includes: + - phpstan-baseline.neon + +parameters: + level: 2 + + checkFunctionNameCase: true + checkInternalClassCaseSensitivity: true + treatPhpDocTypesAsCertain: false + + paths: + - application + - library/Director + + ignoreErrors: + - + messages: + - '#Unsafe usage of new static\(\)#' + - '#. but return statement is missing#' + reportUnmatched: false + + scanDirectories: + - /icingaweb2 + - /usr/share/icinga-php + - /usr/share/icingaweb2-modules + + excludePaths: + - library/Director/CoreBeta + - test + - library/Director/Test + + universalObjectCratesClasses: + - Icinga\Module\Director\Data\Db\DbObject + - Icinga\Data\ConfigObject + - Icinga\Web\View + - Icinga\Module\Monitoring\Object\MonitoredObject + - Icinga\Module\Monitoring\DataView\DataView + - Icinga\Web\Session\SessionNamespace + - Icinga\User\Preferences + - ipl\Orm\Model diff --git a/public/css/module.less b/public/css/module.less index 1f11251..51c4ec2 100644 --- a/public/css/module.less +++ b/public/css/module.less @@ -49,6 +49,15 @@ div.action-bar > a { margin-right: 1em; } +.controls.compact { + display: none; +} + +.controls > .pagination-control.activity-log-control { + float: right; + width: 5em; +} + .controls > .pagination-control li > a { padding: 0.5em 0 0.5em 0; } @@ -243,7 +252,7 @@ pre.logfile { background: @gray-lighter; color: @gray; overflow: auto; - white-space: pre; + white-space: pre-wrap; a { color: @link-color; @@ -337,6 +346,10 @@ table.avp th { left: -100%; } +form.remove-link-form { + float: right; +} + form.director-form input[type=file] { padding-right: 1em; } @@ -462,6 +475,11 @@ form.director-form dl { padding: 0; } +form.director-form .host-group-links { + line-height: 2.5em; + padding-left: 0.5em; +} + .strike-links a, table.common-table .strike-links a { text-decoration: line-through; &:hover { @@ -502,6 +520,12 @@ form.director-form.editor { } } +ul.unordred-list { + list-style-type: none; + margin: 0; + padding: 0; +} + ul.extensible-set { margin: 0; padding: 0; @@ -917,6 +941,10 @@ form.director-form dd.active li.active input.related-action[type='submit'] { } form.director-form { + select.config-diff { + width: auto; + } + p.description { color: @gray; font-style: italic; @@ -1223,6 +1251,17 @@ div.content.compact table.icinga-objects thead { display: none; } +table.deployment-details { + .succeeded { + color: @state-ok; + } + + .failed { + color: @color-critical; + } +} + + table.deployment-log { tr td:nth-child(2), tr th:nth-child(2) { @@ -1833,3 +1872,36 @@ table.table-basket-changes { min-width: 10em; } } + +.font-italic { + font-style: italic; +} + +.table-basket-changes { + .basket-new { + color: green; + font-weight: bold + } + + .basket-modified { + color: orange; + font-weight: bold + } + + .basket-unchanged { + color: green; + } +} + +.seviceset-obj-link { + float: right; + font-weight: normal +} + +.dictionary-header { + margin-top: 2em; +} + +.text-align-left { + text-align: left +} diff --git a/register-hooks.php b/register-hooks.php index 62fd5f5..36e7e70 100644 --- a/register-hooks.php +++ b/register-hooks.php @@ -66,6 +66,9 @@ use Icinga\Module\Director\ProvidedHook\IcingaDbCubeLinks; if ($this->getConfig()->get('frontend', 'disabled', 'no') !== 'yes') { $this->provideHook('monitoring/HostActions'); $this->provideHook('monitoring/ServiceActions'); + $this->provideHook('icingadb/HostActions'); + $this->provideHook('icingadb/ServiceActions'); + $this->provideHook('icingadb/icingadbSupport'); $this->provideHook('cube/Actions', CubeLinks::class); $this->provideHook('cube/IcingaDbActions', IcingaDbCubeLinks::class); } diff --git a/schema/mysql-migrations/upgrade_183.sql b/schema/mysql-migrations/upgrade_183.sql new file mode 100644 index 0000000..3e9577d --- /dev/null +++ b/schema/mysql-migrations/upgrade_183.sql @@ -0,0 +1,9 @@ +ALTER TABLE icinga_notification + ADD COLUMN users_var VARCHAR(255) DEFAULT NULL AFTER zone_id; + +ALTER TABLE icinga_notification + ADD COLUMN user_groups_var VARCHAR(255) DEFAULT NULL AFTER users_var; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (183, NOW()); diff --git a/schema/mysql-migrations/upgrade_184.sql b/schema/mysql-migrations/upgrade_184.sql new file mode 100644 index 0000000..8081654 --- /dev/null +++ b/schema/mysql-migrations/upgrade_184.sql @@ -0,0 +1,9 @@ +ALTER TABLE branched_icinga_notification + ADD COLUMN users_var VARCHAR(255) DEFAULT NULL AFTER zone; + +ALTER TABLE branched_icinga_notification + ADD COLUMN user_groups_var VARCHAR(255) DEFAULT NULL AFTER users_var; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (184, NOW()); diff --git a/schema/mysql-migrations/upgrade_186.sql b/schema/mysql-migrations/upgrade_186.sql new file mode 100644 index 0000000..f0c8bda --- /dev/null +++ b/schema/mysql-migrations/upgrade_186.sql @@ -0,0 +1,35 @@ +ALTER TABLE director_datafield ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id; +SET @tmp_uuid = LOWER(CONCAT( + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-', + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-', + '4', + LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-', + HEX(FLOOR(RAND() * 4 + 8)), + LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-', + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0') +)); +UPDATE director_datafield SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL; +ALTER TABLE director_datafield MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid); + +ALTER TABLE director_datalist ADD COLUMN uuid VARBINARY(16) DEFAULT NULL AFTER id; +SET @tmp_uuid = LOWER(CONCAT( + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-', + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), '-', + '4', + LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-', + HEX(FLOOR(RAND() * 4 + 8)), + LPAD(HEX(FLOOR(RAND() * 0x0fff)), 3, '0'), '-', + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0'), + LPAD(HEX(FLOOR(RAND() * 0xffff)), 4, '0') +)); +UPDATE director_datalist SET uuid = UNHEX(LPAD(LPAD(HEX(id), 8, '0'), 32, REPLACE(@tmp_uuid, '-', ''))) WHERE uuid IS NULL; +ALTER TABLE director_datalist MODIFY COLUMN uuid VARBINARY(16) NOT NULL, ADD UNIQUE INDEX uuid (uuid); + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (186, NOW()); diff --git a/schema/mysql-migrations/upgrade_187.sql b/schema/mysql-migrations/upgrade_187.sql new file mode 100644 index 0000000..0e96f14 --- /dev/null +++ b/schema/mysql-migrations/upgrade_187.sql @@ -0,0 +1,5 @@ +ALTER TABLE import_row_modifier ADD COLUMN filter_expression TEXT DEFAULT NULL AFTER priority; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (187, NOW()); diff --git a/schema/mysql.sql b/schema/mysql.sql index 02ac5d9..832ab12 100644 --- a/schema/mysql.sql +++ b/schema/mysql.sql @@ -177,6 +177,7 @@ CREATE TABLE director_deployment_log ( CREATE TABLE director_datalist ( id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL, + uuid VARBINARY(16) NOT NULL, list_name VARCHAR(255) NOT NULL, owner VARCHAR(255) NOT NULL, PRIMARY KEY (id), @@ -207,6 +208,7 @@ CREATE TABLE director_datafield_category ( CREATE TABLE director_datafield ( id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, + uuid VARBINARY(16) NOT NULL, category_id INT(10) UNSIGNED DEFAULT NULL, varname VARCHAR(64) NOT NULL COLLATE utf8_bin, caption VARCHAR(255) NOT NULL, @@ -1260,6 +1262,8 @@ CREATE TABLE icinga_notification ( command_id INT(10) UNSIGNED DEFAULT NULL, period_id INT(10) UNSIGNED DEFAULT NULL, zone_id INT(10) UNSIGNED DEFAULT NULL, + users_var VARCHAR(255) DEFAULT NULL, + user_groups_var VARCHAR(255) DEFAULT NULL, assign_filter TEXT DEFAULT NULL, PRIMARY KEY (id), UNIQUE INDEX uuid (uuid), @@ -1455,6 +1459,7 @@ CREATE TABLE import_row_modifier ( target_property VARCHAR(255) DEFAULT NULL, provider_class VARCHAR(128) NOT NULL, priority SMALLINT UNSIGNED NOT NULL, + filter_expression TEXT DEFAULT NULL, description TEXT DEFAULT NULL, PRIMARY KEY (id), KEY search_idx (property_name), @@ -2351,6 +2356,8 @@ CREATE TABLE branched_icinga_notification ( command VARCHAR(255) DEFAULT NULL, period VARCHAR(255) DEFAULT NULL, zone VARCHAR(255) DEFAULT NULL, + users_var VARCHAR(255) DEFAULT NULL, + user_groups_var VARCHAR(255) DEFAULT NULL, assign_filter TEXT DEFAULT NULL, states TEXT DEFAULT NULL, @@ -2439,4 +2446,4 @@ CREATE TABLE branched_icinga_dependency ( INSERT INTO director_schema_migration (schema_version, migration_time) - VALUES (182, NOW()); + VALUES (187, NOW()); diff --git a/schema/pgsql-migrations/upgrade_183.sql b/schema/pgsql-migrations/upgrade_183.sql new file mode 100644 index 0000000..b9964ef --- /dev/null +++ b/schema/pgsql-migrations/upgrade_183.sql @@ -0,0 +1,9 @@ +ALTER TABLE icinga_notification + ADD COLUMN users_var character varying(255) DEFAULT NULL; + +ALTER TABLE icinga_notification + ADD COLUMN user_groups_var character varying(255) DEFAULT NULL; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (183, NOW()); diff --git a/schema/pgsql-migrations/upgrade_184.sql b/schema/pgsql-migrations/upgrade_184.sql new file mode 100644 index 0000000..834e6a9 --- /dev/null +++ b/schema/pgsql-migrations/upgrade_184.sql @@ -0,0 +1,9 @@ +ALTER TABLE branched_icinga_notification + ADD COLUMN users_var character varying(255) DEFAULT NULL; + +ALTER TABLE branched_icinga_notification + ADD COLUMN user_groups_var character varying(255) DEFAULT NULL; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (184, NOW()); diff --git a/schema/pgsql-migrations/upgrade_186.sql b/schema/pgsql-migrations/upgrade_186.sql new file mode 100644 index 0000000..cb491f6 --- /dev/null +++ b/schema/pgsql-migrations/upgrade_186.sql @@ -0,0 +1,11 @@ +ALTER TABLE director_datafield ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16); +UPDATE director_datafield SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL; +ALTER TABLE director_datafield ALTER COLUMN uuid SET NOT NULL; + +ALTER TABLE director_datalist ADD COLUMN uuid bytea UNIQUE CHECK(LENGTH(uuid) = 16); +UPDATE director_datalist SET uuid = decode(replace(gen_random_uuid()::text, '-', ''), 'hex') WHERE uuid IS NULL; +ALTER TABLE director_datalist ALTER COLUMN uuid SET NOT NULL; + +INSERT INTO director_schema_migration +(schema_version, migration_time) +VALUES (186, NOW()); diff --git a/schema/pgsql-migrations/upgrade_187.sql b/schema/pgsql-migrations/upgrade_187.sql new file mode 100644 index 0000000..08b422a --- /dev/null +++ b/schema/pgsql-migrations/upgrade_187.sql @@ -0,0 +1,5 @@ +ALTER TABLE import_row_modifier ADD COLUMN filter_expression text DEFAULT NULL; + +INSERT INTO director_schema_migration + (schema_version, migration_time) + VALUES (187, NOW()); diff --git a/schema/pgsql.sql b/schema/pgsql.sql index b9b2cf8..32931e6 100644 --- a/schema/pgsql.sql +++ b/schema/pgsql.sql @@ -246,6 +246,7 @@ CREATE INDEX start_time_idx ON director_deployment_log (start_time); CREATE TABLE director_datalist ( id serial, + uuid bytea CHECK(LENGTH(uuid) = 16) NOT NULL, list_name character varying(255) NOT NULL, owner character varying(255) NOT NULL, PRIMARY KEY (id) @@ -283,6 +284,7 @@ CREATE UNIQUE INDEX datafield_category_name ON director_datafield_category (cate CREATE TABLE director_datafield ( id serial, + uuid bytea CHECK(LENGTH(uuid) = 16) NOT NULL, category_id integer DEFAULT NULL, varname character varying(64) NOT NULL, caption character varying(255) NOT NULL, @@ -1503,6 +1505,8 @@ CREATE TABLE icinga_notification ( command_id integer DEFAULT NULL, period_id integer DEFAULT NULL, zone_id integer DEFAULT NULL, + users_var character varying(255) DEFAULT NULL, + user_groups_var character varying(255) DEFAULT NULL, assign_filter text DEFAULT NULL, PRIMARY KEY (id), CONSTRAINT icinga_notification_host @@ -1604,6 +1608,7 @@ CREATE TABLE import_row_modifier ( target_property character varying(255) DEFAULT NULL, provider_class character varying(128) NOT NULL, priority integer NOT NULL, + filter_expression text DEFAULT NULL, description text DEFAULT NULL, PRIMARY KEY (id), CONSTRAINT row_modifier_import_source @@ -2684,6 +2689,8 @@ CREATE TABLE branched_icinga_notification ( command character varying(255) DEFAULT NULL, period character varying(255) DEFAULT NULL, zone character varying(255) DEFAULT NULL, + users_var character varying(255) DEFAULT NULL, + user_groups_var character varying(255) DEFAULT NULL, assign_filter text DEFAULT NULL, states TEXT DEFAULT NULL, @@ -2778,4 +2785,4 @@ CREATE INDEX branched_dependency_search_object_name ON branched_icinga_dependenc INSERT INTO director_schema_migration (schema_version, migration_time) - VALUES (182, NOW()); + VALUES (187, NOW()); diff --git a/test/config/config.ini b/test/config/config.ini deleted file mode 100644 index e69de29..0000000 --- a/test/config/config.ini +++ /dev/null diff --git a/test/php/library/Director/Data/AssignFilterHelperTest.php b/test/php/library/Director/Data/AssignFilterHelperTest.php index 5fcdd95..e7c2f84 100644 --- a/test/php/library/Director/Data/AssignFilterHelperTest.php +++ b/test/php/library/Director/Data/AssignFilterHelperTest.php @@ -11,7 +11,7 @@ class AssignFilterHelperTest extends BaseTestCase { protected static $exampleHost; - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { self::$exampleHost = (object) [ 'address' => '127.0.0.1', diff --git a/test/php/library/Director/Data/RecursiveUtf8ValidatorTest.php b/test/php/library/Director/Data/RecursiveUtf8ValidatorTest.php index 1434d4a..9b4bf33 100644 --- a/test/php/library/Director/Data/RecursiveUtf8ValidatorTest.php +++ b/test/php/library/Director/Data/RecursiveUtf8ValidatorTest.php @@ -7,11 +7,10 @@ use Icinga\Module\Director\Test\BaseTestCase; class RecursiveUtf8ValidatorTest extends BaseTestCase { - /** - * @expectedException \InvalidArgumentException - */ public function testDetectInvalidUtf8Character() { + $this->expectException(\InvalidArgumentException::class); + RecursiveUtf8Validator::validateRows([ (object) [ 'name' => 'test 1', diff --git a/test/php/library/Director/Form/IcingaObjectFieldFormTest.php b/test/php/library/Director/Form/IcingaObjectFieldFormTest.php new file mode 100644 index 0000000..8a5e0cc --- /dev/null +++ b/test/php/library/Director/Form/IcingaObjectFieldFormTest.php @@ -0,0 +1,151 @@ +<?php + +namespace Tests\Icinga\Module\Director\Field; + +use Icinga\Module\Director\Forms\IcingaObjectFieldForm; +use Icinga\Module\Director\Objects\DirectorDatafield; +use Icinga\Module\Director\Objects\IcingaHost; +use Icinga\Module\Director\Test\BaseTestCase; +use Icinga\Module\Director\Objects\IcingaCommand; + +class IcingaObjectFieldFormTest extends BaseTestCase +{ + /** @var string */ + protected const COMMAND_NAME = 'icingaTestCommand'; + + /** @var string */ + protected const DATAFIELD_NAME = 'dataFieldTest'; + + /** @var string */ + protected const HOST_NAME = 'testHost'; + + /** @var ?DirectorDatafield */ + protected $testDatafield = null; + + /** @var ?IcingaCommand */ + protected $testIcingaCommand = null; + + /** @var IcingaHost */ + private $testHost; + + public function setUp(): void + { + parent::setUp(); + if ($this->hasDb()) { + $db = $this->getDb(); + $this->testDatafield = DirectorDatafield::create([ + 'varname' => self::DATAFIELD_NAME, + 'caption' => 'Blah', + 'description' => '', + 'datatype' => 'Icinga\Module\Director\DataType\DataTypeArray', + 'format' => 'json' + ]); + $this->testDatafield->store($db); + + $this->testIcingaCommand = IcingaCommand::create( + [ + 'object_name' => self::COMMAND_NAME, + 'object_type' => 'object' + ], + $db + ); + $this->testIcingaCommand->store($db); + + $this->testHost = IcingaHost::create([ + 'object_name' => self::HOST_NAME, + 'object_type' => 'object', + 'display_name' => 'Whatever' + ], $this->getDb()); + } + } + + public function testFieldSuggestionsWithoutCheckCommand() + { + if ($this->skipForMissingDb()) { + return; + } + + $db = $this->getDb(); + + $icingaHostFieldForm = (new IcingaObjectFieldForm()) + ->setDb($db) + ->setIcingaObject($this->testHost); + + $icingaHostFieldForm->setup(); + /** @var array<string> $suggestions */ + $suggestions = $icingaHostFieldForm->getElement('datafield_id') + ->getAttrib('options'); + + array_shift($suggestions); + + $this->assertEquals( + [ + 'Other available fields' => [ + $this->testDatafield->get('id') => "Blah (dataFieldTest)" + ] + ], + $suggestions + ); + } + + public function testFieldSuggestionsWithCheckCommand() + { + if ($this->skipForMissingDb()) { + return; + } + + $db = $this->getDb(); + + $this->testHost->check_command = self::COMMAND_NAME; + $icingaHostFieldForm = (new IcingaObjectFieldForm()) + ->setDb($db) + ->setIcingaObject($this->testHost); + + $icingaHostFieldForm->setup(); + + /** @var array<string> $suggestions */ + $suggestions = $icingaHostFieldForm->getElement('datafield_id') + ->getAttrib('options'); + + array_shift($suggestions); + $this->assertEquals( + [ + 'Other available fields' => [ + $this->testDatafield->get('id') => "Blah (dataFieldTest)" + ] + ], + $suggestions + ); + } + + public function tearDown(): void + { + if ($this->hasDb()) { + $db = $this->getDb(); + $this->deleteDatafields(); + + if (IcingaHost::exists(self::HOST_NAME, $db)) { + IcingaHost::load(self::HOST_NAME, $db)->delete(); + } + + if (IcingaCommand::exists(self::COMMAND_NAME, $db)) { + IcingaCommand::load(self::COMMAND_NAME, $db)->delete(); + } + } + + parent::tearDown(); + } + + protected function deleteDatafields() + { + $db = $this->getDb(); + $dbAdapter = $db->getDbAdapter(); + + $query = $dbAdapter->select() + ->from('director_datafield') + ->where('varname = ?', self::DATAFIELD_NAME); + foreach (DirectorDatafield::loadAll($db, $query, 'id') as $datafield) { + $datafield->delete(); + } + } +} diff --git a/test/php/library/Director/IcingaConfig/IcingaConfigHelperTest.php b/test/php/library/Director/IcingaConfig/IcingaConfigHelperTest.php index 506f3b8..10cd644 100644 --- a/test/php/library/Director/IcingaConfig/IcingaConfigHelperTest.php +++ b/test/php/library/Director/IcingaConfig/IcingaConfigHelperTest.php @@ -18,11 +18,10 @@ class IcingaConfigHelperTest extends BaseTestCase $this->assertEquals(c::parseInterval('1h 5m 60s'), 3960); } - /** - * @expectedException \InvalidArgumentException - */ public function testWhetherInvalidIntervalStringRaisesException() { + $this->expectException(\InvalidArgumentException::class); + c::parseInterval('1h 5m 60x'); } diff --git a/test/php/library/Director/IcingaConfig/StateFilterTest.php b/test/php/library/Director/IcingaConfig/StateFilterTest.php index 82e94d8..2c997bd 100644 --- a/test/php/library/Director/IcingaConfig/StateFilterTest.php +++ b/test/php/library/Director/IcingaConfig/StateFilterTest.php @@ -2,6 +2,8 @@ namespace Tests\Icinga\Module\Director\IcingaConfig; +use Icinga\Exception\InvalidPropertyException; +use Icinga\Exception\ProgrammingError; use Icinga\Module\Director\IcingaConfig\StateFilterSet; use Icinga\Module\Director\Objects\IcingaUser; use Icinga\Module\Director\Test\BaseTestCase; @@ -23,19 +25,17 @@ class StateFilterSetTest extends BaseTestCase ); } - /** - * @expectedException \Icinga\Exception\InvalidPropertyException - */ public function testFailsForInvalidProperties() { + $this->expectException(InvalidPropertyException::class); + $set = new StateFilterSet('bla'); } - /** - * @expectedException \Icinga\Exception\ProgrammingError - */ public function testCannotBeStoredForAnUnstoredUser() { + $this->expectException(ProgrammingError::class); + StateFilterSet::forIcingaObject( $this->user1(), 'states' @@ -152,7 +152,7 @@ class StateFilterSetTest extends BaseTestCase )); } - public function tearDown() + public function tearDown(): void { if ($this->hasDb()) { $users = array( @@ -167,5 +167,7 @@ class StateFilterSetTest extends BaseTestCase } } } + + parent::tearDown(); } } diff --git a/test/php/library/Director/Import/HostSyncTest.php b/test/php/library/Director/Import/HostSyncTest.php index eeee7a4..a18fc3d 100644 --- a/test/php/library/Director/Import/HostSyncTest.php +++ b/test/php/library/Director/Import/HostSyncTest.php @@ -242,7 +242,7 @@ class HostSyncTest extends SyncTest } } - public function tearDown() + public function tearDown(): void { $this->removeGroups(['SYNCTEST_groupa', 'SYNCTEST_groupb']); parent::tearDown(); diff --git a/test/php/library/Director/Objects/HostGroupMembershipResolverTest.php b/test/php/library/Director/Objects/HostGroupMembershipResolverTest.php index cf2fb36..df4b24c 100644 --- a/test/php/library/Director/Objects/HostGroupMembershipResolverTest.php +++ b/test/php/library/Director/Objects/HostGroupMembershipResolverTest.php @@ -15,8 +15,9 @@ class HostGroupMembershipResolverTest extends BaseTestCase const PREFIX = '__groupmembership'; const TYPE = 'host'; - public function setUp() + public function setUp(): void { + parent::setUp(); IcingaTemplateRepository::clear(); } @@ -32,12 +33,12 @@ class HostGroupMembershipResolverTest extends BaseTestCase $db->delete('icinga_' . self::TYPE, $where); } - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { static::cleanArtifacts(); } - public static function tearDownAfterClass() + public static function tearDownAfterClass(): void { static::cleanArtifacts(); } diff --git a/test/php/library/Director/Objects/IcingaCommandTest.php b/test/php/library/Director/Objects/IcingaCommandTest.php index 8e564d8..e3c9d89 100644 --- a/test/php/library/Director/Objects/IcingaCommandTest.php +++ b/test/php/library/Director/Objects/IcingaCommandTest.php @@ -206,11 +206,13 @@ class IcingaCommandTest extends BaseTestCase return file_get_contents(__DIR__ . '/rendered/' . $name . '.out'); } - public function tearDown() + public function tearDown(): void { $db = $this->getDb(); if (IcingaCommand::exists($this->testCommandName, $db)) { IcingaCommand::load($this->testCommandName, $db)->delete(); } + + parent::tearDown(); } } diff --git a/test/php/library/Director/Objects/IcingaHostTest.php b/test/php/library/Director/Objects/IcingaHostTest.php index b4902bf..f8ec222 100644 --- a/test/php/library/Director/Objects/IcingaHostTest.php +++ b/test/php/library/Director/Objects/IcingaHostTest.php @@ -2,6 +2,7 @@ namespace Tests\Icinga\Module\Director\Objects; +use Icinga\Exception\NotFoundError; use Icinga\Module\Director\Data\PropertiesFilter\ArrayCustomVariablesFilter; use Icinga\Module\Director\Data\PropertiesFilter\CustomVariablesFilter; use Icinga\Module\Director\IcingaConfig\IcingaConfig; @@ -255,14 +256,14 @@ class IcingaHostTest extends BaseTestCase $zone->delete(); } - /** - * @expectedException \RuntimeException - */ public function testFailsToStoreWithMissingLazyRelations() { if ($this->skipForMissingDb()) { return; } + + $this->expectException(\RuntimeException::class); + $db = $this->getDb(); $host = $this->host(); $host->zone = '___TEST___zone'; @@ -336,15 +337,14 @@ class IcingaHostTest extends BaseTestCase ); } - /** - * @expectedException \RuntimeException - */ public function testFailsToStoreWithInvalidUnresolvedDependencies() { if ($this->skipForMissingDb()) { return; } + $this->expectException(\RuntimeException::class); + $host = $this->host(); $host->zone = 'invalid'; $host->store($this->getDb()); @@ -396,10 +396,16 @@ class IcingaHostTest extends BaseTestCase $host->object_type = 'template'; $host->zone_id = null; + $zone = $this->newObject('zone', '___TEST___zone2'); + $zone->store($db); + $config = new IcingaConfig($db); $host->renderToConfig($config); $this->assertEquals( - array('zones.d/director-global/host_templates.conf'), + [ + 'zones.d/___TEST___zone/host_templates.conf', + 'zones.d/___TEST___zone2/host_templates.conf', + ], $config->getFileNames() ); } @@ -474,15 +480,14 @@ class IcingaHostTest extends BaseTestCase $b->delete(); } - /** - * @expectedException \Icinga\Exception\NotFoundError - */ public function testWhetherInvalidApiKeyThrows404() { if ($this->skipForMissingDb()) { return; } + $this->expectException(NotFoundError::class); + $db = $this->getDb(); IcingaHost::loadWithApiKey('No___such___key', $db); } @@ -694,36 +699,36 @@ class IcingaHostTest extends BaseTestCase protected function getDefaultHostProperties($prefix = '') { return array( - "${prefix}name" => "name", - "${prefix}action_url" => "action_url", - "${prefix}address" => "address", - "${prefix}address6" => "address6", - "${prefix}api_key" => "api_key", - "${prefix}check_command" => "check_command", - "${prefix}check_interval" => "check_interval", - "${prefix}check_period" => "check_period", - "${prefix}check_timeout" => "check_timeout", - "${prefix}command_endpoint" => "command_endpoint", - "${prefix}display_name" => "display_name", - "${prefix}enable_active_checks" => "enable_active_checks", - "${prefix}enable_event_handler" => "enable_event_handler", - "${prefix}enable_flapping" => "enable_flapping", - "${prefix}enable_notifications" => "enable_notifications", - "${prefix}enable_passive_checks" => "enable_passive_checks", - "${prefix}enable_perfdata" => "enable_perfdata", - "${prefix}event_command" => "event_command", - "${prefix}flapping_threshold_high" => "flapping_threshold_high", - "${prefix}flapping_threshold_low" => "flapping_threshold_low", - "${prefix}icon_image" => "icon_image", - "${prefix}icon_image_alt" => "icon_image_alt", - "${prefix}max_check_attempts" => "max_check_attempts", - "${prefix}notes" => "notes", - "${prefix}notes_url" => "notes_url", - "${prefix}retry_interval" => "retry_interval", - "${prefix}volatile" => "volatile", - "${prefix}zone" => "zone", - "${prefix}groups" => "Groups", - "${prefix}templates" => "templates" + "{$prefix}name" => "name", + "{$prefix}action_url" => "action_url", + "{$prefix}address" => "address", + "{$prefix}address6" => "address6", + "{$prefix}api_key" => "api_key", + "{$prefix}check_command" => "check_command", + "{$prefix}check_interval" => "check_interval", + "{$prefix}check_period" => "check_period", + "{$prefix}check_timeout" => "check_timeout", + "{$prefix}command_endpoint" => "command_endpoint", + "{$prefix}display_name" => "display_name", + "{$prefix}enable_active_checks" => "enable_active_checks", + "{$prefix}enable_event_handler" => "enable_event_handler", + "{$prefix}enable_flapping" => "enable_flapping", + "{$prefix}enable_notifications" => "enable_notifications", + "{$prefix}enable_passive_checks" => "enable_passive_checks", + "{$prefix}enable_perfdata" => "enable_perfdata", + "{$prefix}event_command" => "event_command", + "{$prefix}flapping_threshold_high" => "flapping_threshold_high", + "{$prefix}flapping_threshold_low" => "flapping_threshold_low", + "{$prefix}icon_image" => "icon_image", + "{$prefix}icon_image_alt" => "icon_image_alt", + "{$prefix}max_check_attempts" => "max_check_attempts", + "{$prefix}notes" => "notes", + "{$prefix}notes_url" => "notes_url", + "{$prefix}retry_interval" => "retry_interval", + "{$prefix}volatile" => "volatile", + "{$prefix}zone" => "zone", + "{$prefix}groups" => "Groups", + "{$prefix}templates" => "templates" ); } protected function loadRendered($name) @@ -731,7 +736,7 @@ class IcingaHostTest extends BaseTestCase return file_get_contents(__DIR__ . '/rendered/' . $name . '.out'); } - public function tearDown() + public function tearDown(): void { if ($this->hasDb()) { $db = $this->getDb(); @@ -742,7 +747,7 @@ class IcingaHostTest extends BaseTestCase } } - $kill = array('___TEST___zone'); + $kill = ['___TEST___zone', '___TEST___zone2']; foreach ($kill as $name) { if (IcingaZone::exists($name, $db)) { IcingaZone::load($name, $db)->delete(); @@ -751,6 +756,8 @@ class IcingaHostTest extends BaseTestCase $this->deleteDatafields(); } + + parent::tearDown(); } protected function deleteDatafields() diff --git a/test/php/library/Director/Objects/IcingaNotificationTest.php b/test/php/library/Director/Objects/IcingaNotificationTest.php index 9d9436a..dbbce91 100644 --- a/test/php/library/Director/Objects/IcingaNotificationTest.php +++ b/test/php/library/Director/Objects/IcingaNotificationTest.php @@ -226,7 +226,7 @@ class IcingaNotificationTest extends BaseTestCase return file_get_contents(__DIR__ . '/rendered/' . $name . '.out'); } - public function tearDown() + public function tearDown(): void { if ($this->hasDb()) { $db = $this->getDb(); @@ -244,5 +244,7 @@ class IcingaNotificationTest extends BaseTestCase } } } + + parent::tearDown(); } } diff --git a/test/php/library/Director/Objects/IcingaServiceSetTest.php b/test/php/library/Director/Objects/IcingaServiceSetTest.php index ad7c135..a9a9fa1 100644 --- a/test/php/library/Director/Objects/IcingaServiceSetTest.php +++ b/test/php/library/Director/Objects/IcingaServiceSetTest.php @@ -10,8 +10,9 @@ class IcingaServiceSetTest extends IcingaObjectTestCase protected $table = 'icinga_service_set'; protected $testObjectName = '___TEST___set'; - public function setUp() + public function setUp(): void { + parent::setUp(); $this->assertNull($this->subject, 'subject must have been taken down before!'); if ($this->hasDb()) { @@ -106,22 +107,20 @@ class IcingaServiceSetTest extends IcingaObjectTestCase $this->checkForDanglingServices(); } - /** - * @expectedException \RuntimeException - */ public function testCreatingSetWithoutType() { + $this->expectException(\RuntimeException::class); + $set = IcingaServiceSet::create(array( 'object_name' => '___TEST__set_BAD', )); $set->store($this->getDb()); } - /** - * @expectedException \InvalidArgumentException - */ public function testCreatingServiceSetWithoutHost() { + $this->expectException(\InvalidArgumentException::class); + $set = IcingaServiceSet::create(array( 'object_name' => '___TEST__set_BAD2', 'object_type' => 'object', diff --git a/test/php/library/Director/Objects/IcingaServiceTest.php b/test/php/library/Director/Objects/IcingaServiceTest.php index 468db67..3005349 100644 --- a/test/php/library/Director/Objects/IcingaServiceTest.php +++ b/test/php/library/Director/Objects/IcingaServiceTest.php @@ -26,15 +26,14 @@ class IcingaServiceTest extends BaseTestCase ); } - /** - * @expectedException \RuntimeException - */ public function testFailsToStoreWithMissingLazyRelations() { if ($this->skipForMissingDb()) { return; } + $this->expectException(\RuntimeException::class); + $db = $this->getDb(); $service = $this->service(); $service->display_name = 'Something else'; @@ -45,16 +44,16 @@ class IcingaServiceTest extends BaseTestCase public function testAcceptsAssignRules() { + $this->expectNotToPerformAssertions(); $service = $this->service(); $service->object_type = 'apply'; $service->assign_filter = 'host.address="127.*"'; } - /** - * @expectedException \LogicException - */ public function testRefusesAssignRulesWhenNotBeingAnApply() { + $this->expectException(\LogicException::class); + $service = $this->service(); $service->assign_filter = 'host.address=127.*'; } @@ -271,7 +270,7 @@ class IcingaServiceTest extends BaseTestCase return file_get_contents(__DIR__ . '/rendered/' . $name . '.out'); } - public function tearDown() + public function tearDown(): void { if ($this->hasDb()) { $db = $this->getDb(); @@ -289,5 +288,7 @@ class IcingaServiceTest extends BaseTestCase } } } + + parent::tearDown(); } } diff --git a/test/php/library/Director/Objects/IcingaTemplateResolverTest.php b/test/php/library/Director/Objects/IcingaTemplateResolverTest.php index 09d0ead..f521d74 100644 --- a/test/php/library/Director/Objects/IcingaTemplateResolverTest.php +++ b/test/php/library/Director/Objects/IcingaTemplateResolverTest.php @@ -144,7 +144,7 @@ class IcingaTemplateResolverTest extends BaseTestCase return $host; } - public function tearDown() + public function tearDown(): void { $db = $this->getDb(); $kill = array('t1', 't2', 't6', 't3', 't4', 't5'); @@ -154,5 +154,7 @@ class IcingaTemplateResolverTest extends BaseTestCase IcingaHost::load($name, $db)->delete(); } } + + parent::tearDown(); } } diff --git a/test/php/library/Director/Objects/IcingaTimePeriodTest.php b/test/php/library/Director/Objects/IcingaTimePeriodTest.php index 84496d3..9888fa4 100644 --- a/test/php/library/Director/Objects/IcingaTimePeriodTest.php +++ b/test/php/library/Director/Objects/IcingaTimePeriodTest.php @@ -171,7 +171,7 @@ class IcingaTimePeriodTest extends BaseTestCase return IcingaTimePeriod::load($this->testPeriodName . $suffix, $this->getDb()); } - public function tearDown() + public function tearDown(): void { $db = $this->getDb(); @@ -180,5 +180,7 @@ class IcingaTimePeriodTest extends BaseTestCase IcingaTimePeriod::load($name, $db)->delete(); } } + + parent::tearDown(); } } diff --git a/test/php/library/Director/PropertyModifier/PropertyModifierArrayElementByPositionTest.php b/test/php/library/Director/PropertyModifier/PropertyModifierArrayElementByPositionTest.php index 84465f3..2f0522a 100644 --- a/test/php/library/Director/PropertyModifier/PropertyModifierArrayElementByPositionTest.php +++ b/test/php/library/Director/PropertyModifier/PropertyModifierArrayElementByPositionTest.php @@ -31,11 +31,10 @@ class PropertyModifierArrayElementByPositionTest extends BaseTestCase ); } - /** - * @expectedException \InvalidArgumentException - */ public function testGettingFirstFailsForEmptyArray() { + $this->expectException(\InvalidArgumentException::class); + $this->buildModifier('first')->transform([]); } @@ -60,11 +59,10 @@ class PropertyModifierArrayElementByPositionTest extends BaseTestCase ); } - /** - * @expectedException \InvalidArgumentException - */ public function testGettingLastFailsForEmptyArray() { + $this->expectException(\InvalidArgumentException::class); + $this->buildModifier('last')->transform([]); } @@ -89,11 +87,10 @@ class PropertyModifierArrayElementByPositionTest extends BaseTestCase ); } - /** - * @expectedException \InvalidArgumentException - */ public function testGettingSpecificFailsForEmptyArray() { + $this->expectException(\InvalidArgumentException::class); + $this->buildModifier('fixed', 1)->transform([]); } @@ -102,11 +99,10 @@ class PropertyModifierArrayElementByPositionTest extends BaseTestCase $this->assertNull($this->buildModifier('fixed', 1, 'null')->transform([])); } - /** - * @expectedException \InvalidArgumentException - */ public function testGettingSpecificFailsForMissingValue() { + $this->expectException(\InvalidArgumentException::class); + $this->buildModifier('fixed', 3)->transform(['one', 'two', 'three']); } @@ -115,11 +111,10 @@ class PropertyModifierArrayElementByPositionTest extends BaseTestCase $this->assertNull($this->buildModifier('fixed', 3, 'null')->transform(['one', 'two', 'three'])); } - /** - * @expectedException \InvalidArgumentException - */ public function testFailsForStrings() { + $this->expectException(\InvalidArgumentException::class); + $this->buildModifier('first')->transform('string'); } diff --git a/test/php/library/Director/PropertyModifier/PropertyModifierListToObjectTest.php b/test/php/library/Director/PropertyModifier/PropertyModifierListToObjectTest.php index 93d498c..0a150be 100644 --- a/test/php/library/Director/PropertyModifier/PropertyModifierListToObjectTest.php +++ b/test/php/library/Director/PropertyModifier/PropertyModifierListToObjectTest.php @@ -23,21 +23,19 @@ class PropertyModifierListToObjectTest extends BaseTestCase ); } - /** - * @expectedException \InvalidArgumentException - */ public function testFailsOnMissingKey() { + $this->expectException(\InvalidArgumentException::class); + $input = $this->getInputArrays(); unset($input[0]['name']); $this->getNewModifier()->transform($input); } - /** - * @expectedException \InvalidArgumentException - */ public function testFailsWithDuplicateRows() { + $this->expectException(\InvalidArgumentException::class); + $input = $this->getInputArrays(); $input[1]['name'] = 'row1'; $this->getNewModifier()->transform($input); diff --git a/test/php/library/Director/PropertyModifier/PropertyModifierParseURLTest.php b/test/php/library/Director/PropertyModifier/PropertyModifierParseURLTest.php index a5ccb79..fe89ac6 100644 --- a/test/php/library/Director/PropertyModifier/PropertyModifierParseURLTest.php +++ b/test/php/library/Director/PropertyModifier/PropertyModifierParseURLTest.php @@ -2,6 +2,7 @@ namespace Tests\Icinga\Module\Director\PropertyModifier; +use Icinga\Exception\InvalidPropertyException; use Icinga\Module\Director\PropertyModifier\PropertyModifierParseURL; use Icinga\Module\Director\Test\BaseTestCase; @@ -50,11 +51,10 @@ class PropertyModifierParseURLTest extends BaseTestCase $this->assertEquals('http://www.icinga.org/path/', $modifier->transform('http://www.icinga.org/path/')); } - /** - * @expectedException \Icinga\Exception\InvalidPropertyException - */ public function testMissingComponentThrowsExceptionOnfailureFail() { + $this->expectException(InvalidPropertyException::class); + $modifier = new PropertyModifierParseURL(); $modifier->setSettings([ 'url_component' => 'query', @@ -87,11 +87,10 @@ class PropertyModifierParseURLTest extends BaseTestCase $this->assertEquals(self::$invalidurl, $modifier->transform(self::$invalidurl)); } - /** - * @expectedException \Icinga\Exception\InvalidPropertyException - */ public function testInvalidUrlThrowsExceptionOnfailureFail() { + $this->expectException(InvalidPropertyException::class); + $modifier = new PropertyModifierParseURL(); $modifier->setSettings([ 'url_component' => 'host', diff --git a/test/php/library/Director/Resolver/TemplateTreeTest.php b/test/php/library/Director/Resolver/TemplateTreeTest.php index f44d081..c2ed916 100644 --- a/test/php/library/Director/Resolver/TemplateTreeTest.php +++ b/test/php/library/Director/Resolver/TemplateTreeTest.php @@ -248,12 +248,14 @@ class TemplateTreeTest extends BaseTestCase } } - public function tearDown() + public function tearDown(): void { if ($this->hasDb()) { $db = $this->getDb(); $this->removeHosts($db); $this->removeServices($db); } + + parent::tearDown(); } } diff --git a/test/setup_vendor.sh b/test/setup_vendor.sh deleted file mode 100755 index c53982f..0000000 --- a/test/setup_vendor.sh +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -set -ex - -MODULE_HOME=${MODULE_HOME:="$(dirname "$(readlink -f "$(dirname "$0")")")"} -PHP_VERSION="$(php -r 'echo phpversion();')" - -ICINGAWEB_VERSION=${ICINGAWEB_VERSION:=2.7.1} -ICINGAWEB_GITREF=${ICINGAWEB_GITREF:=} - -if [ "$PHP_VERSION" '<' 7.1.0 ]; then - PHPCS_VERSION=${PHPCS_VERSION:=3.3.2} -else - PHPCS_VERSION=${PHPCS_VERSION:=3.5.2} -fi - -if [ "$PHP_VERSION" '<' 5.6.0 ]; then - PHPUNIT_VERSION=${PHPUNIT_VERSION:=4.8} -else - PHPUNIT_VERSION=${PHPUNIT_VERSION:=5.7} -fi - -cd "${MODULE_HOME}" - -test -d vendor || mkdir vendor -cd vendor/ - -# icingaweb2 -if [ -n "$ICINGAWEB_GITREF" ]; then - icingaweb_path="icingaweb2" - test ! -L "$icingaweb_path" || rm "$icingaweb_path" - - if [ ! -d "$icingaweb_path" ]; then - git clone https://github.com/Icinga/icingaweb2.git "$icingaweb_path" - fi - - ( - set -e - cd "$icingaweb_path" - git fetch -p - git checkout -f "$ICINGAWEB_GITREF" - ) -else - icingaweb_path="icingaweb2-${ICINGAWEB_VERSION}" - if [ ! -e "${icingaweb_path}".tar.gz ]; then - wget -O "${icingaweb_path}".tar.gz https://github.com/Icinga/icingaweb2/archive/v"${ICINGAWEB_VERSION}".tar.gz - fi - if [ ! -d "${icingaweb_path}" ]; then - tar xf "${icingaweb_path}".tar.gz - fi - - rm -f icingaweb2 - ln -svf "${icingaweb_path}" icingaweb2 -fi -ln -svf "${icingaweb_path}"/library/Icinga Icinga -ln -svf "${icingaweb_path}"/library/vendor/Zend Zend - -# phpunit -phpunit_path="phpunit-${PHPUNIT_VERSION}" -if [ ! -e "${phpunit_path}".phar ]; then - wget -O "${phpunit_path}".phar https://phar.phpunit.de/phpunit-${PHPUNIT_VERSION}.phar -fi -ln -svf "${phpunit_path}".phar phpunit.phar - -# phpcs -phpcs_path="phpcs-${PHPCS_VERSION}" -if [ ! -e "${phpcs_path}".phar ]; then - wget -O "${phpcs_path}".phar \ - https://github.com/squizlabs/PHP_CodeSniffer/releases/download/${PHPCS_VERSION}/phpcs.phar -fi -ln -svf "${phpcs_path}".phar phpcs.phar diff --git a/test/travis-prepare.sh b/test/travis-prepare.sh deleted file mode 100755 index 7a303e8..0000000 --- a/test/travis-prepare.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -set -ex - -: "${DIRECTOR_TESTDB:=director_test}" - -psql_cmd() { - psql -U postgres ${DIRECTOR_TESTDB} -q -c "$@" -} - -if [ "$DB" = mysql ]; then - mysql -u root -e "DROP DATABASE IF EXISTS ${DIRECTOR_TESTDB}; CREATE DATABASE ${DIRECTOR_TESTDB};" -elif [ "$DB" = pgsql ]; then - : "${DIRECTOR_TESTDB_USER:=director_test}" - - psql -U postgres postgres -q -c "DROP DATABASE IF EXISTS ${DIRECTOR_TESTDB};" - psql -U postgres postgres -q -c "CREATE DATABASE ${DIRECTOR_TESTDB} WITH ENCODING 'UTF8';" - psql_cmd "CREATE USER ${DIRECTOR_TESTDB_USER} WITH PASSWORD 'testing';" - psql_cmd "GRANT ALL PRIVILEGES ON DATABASE ${DIRECTOR_TESTDB} TO ${DIRECTOR_TESTDB_USER};" - psql_cmd "CREATE EXTENSION pgcrypto;" -else - echo "Unknown database set in environment!" >&2 - env - exit 1 -fi |