mirror of
https://github.com/Icinga/icingaweb2-module-director.git
synced 2025-04-08 17:15:10 +02:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1c1f5e306e | ||
|
e49cccd13c | ||
|
087ce05ebe | ||
|
babf42c764 | ||
|
05dfef5ccc | ||
|
19df9eef8c | ||
|
2527541326 | ||
|
cda5f56038 | ||
|
9de28e7c79 | ||
|
62a684b928 | ||
|
98b07b6dbe | ||
|
367fb811b1 | ||
|
d87057e43d | ||
|
3a2f019e18 | ||
|
575c8fad4e | ||
|
b80fdc9c37 | ||
|
032b043e3a | ||
|
ea2c4fdaf7 |
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@ -1,7 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
2
.github/workflows/L10n-update.yml
vendored
2
.github/workflows/L10n-update.yml
vendored
@ -12,7 +12,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Repository dispatch
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
uses: peter-evans/repository-dispatch@v1
|
||||
with:
|
||||
token: ${{ secrets.ICINGABOT_TOKEN }}
|
||||
repository: Icinga/L10n
|
||||
|
174
.github/workflows/php.yml
vendored
174
.github/workflows/php.yml
vendored
@ -1,174 +0,0 @@
|
||||
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@v4
|
||||
|
||||
- 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
|
||||
|
||||
- name: PHP Lint
|
||||
if: ${{ ! cancelled() }}
|
||||
run: ./vendor/bin/phplint -n --exclude={^vendor/.*} -- .
|
||||
|
||||
- name: PHP CodeSniffer
|
||||
if: ${{ ! cancelled() }}
|
||||
run: phpcs
|
||||
|
||||
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@v4
|
||||
|
||||
- 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
|
16
.github/workflows/phpstan.yml
vendored
16
.github/workflows/phpstan.yml
vendored
@ -1,16 +0,0 @@
|
||||
name: PHPStan
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
phpstan:
|
||||
uses: icinga/github-actions/.github/workflows/phpstan.yml@main
|
||||
with:
|
||||
dependencies: |
|
||||
{
|
||||
"/icingaweb2" : "https://github.com/Icinga/icingaweb2.git",
|
||||
"/usr/share/icingaweb2-modules/icingadb" : "https://github.com/Icinga/icingadb-web.git",
|
||||
"/usr/share/icingaweb2-modules/cube" : "https://github.com/Icinga/icingaweb2-module-cube.git",
|
||||
"/usr/share/icingaweb2-modules/incubator" : "-b stable/0.22.0 https://github.com/Icinga/icingaweb2-module-incubator"
|
||||
}
|
42
.travis.yml
Normal file
42
.travis.yml
Normal file
@ -0,0 +1,42 @@
|
||||
language: php
|
||||
php:
|
||||
- '5.6'
|
||||
- '7.0'
|
||||
- '7.1'
|
||||
- '7.2'
|
||||
- '7.3'
|
||||
- '7.4snapshot'
|
||||
- nightly
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
|
||||
#cache:
|
||||
# directories:
|
||||
# - vendor
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- env: CHECK=phpcs
|
||||
php: nightly # Note: will be allowed failure
|
||||
- env: CHECK=phpcs
|
||||
php: '7.0'
|
||||
- env: CHECK=phpcs
|
||||
php: '5.6'
|
||||
allow_failures:
|
||||
- php: nightly
|
||||
|
||||
env:
|
||||
- CHECK=phpunit DB=mysql DIRECTOR_TESTDB_RES="Director MySQL TestDB" DIRECTOR_TESTDB="director_test"
|
||||
- CHECK=phpunit DB=pgsql DIRECTOR_TESTDB_RES="Director PostgreSQL TestDB" DIRECTOR_TESTDB="director_test"
|
||||
DIRECTOR_TESTDB_USER="director_test"
|
||||
|
||||
before_script:
|
||||
- ./test/setup_vendor.sh
|
||||
- '[ "$CHECK" != phpunit ] || ./test/travis-prepare.sh'
|
||||
|
||||
script:
|
||||
- '[ "$CHECK" != phpcs ] || php vendor/phpcs.phar'
|
||||
- '[ "$CHECK" != phpunit ] || php vendor/phpunit.phar --testdox || php vendor/phpunit.phar --verbose'
|
@ -42,6 +42,9 @@ or code.
|
||||
* Make sure your code conforms to the [PSR-2: Coding Style Guide](http://www.php-fig.org/psr/psr-2/)
|
||||
* [Unit-Tests](doc/93-Testing.md) would be great
|
||||
* Send a [Pull Request](https://github.com/Icinga/icingaweb2-module-director/pulls)
|
||||
(it will automatically be tested on Travis-CI)
|
||||
* We try hard to keep our master always green: [](https://travis-ci.org/Icinga/icingaweb2-module-director)
|
||||
|
||||
|
||||
Addons
|
||||
------
|
||||
|
@ -4,10 +4,8 @@ namespace Icinga\Module\Director\Clicommands;
|
||||
|
||||
use Icinga\Date\DateFormatter;
|
||||
use Icinga\Module\Director\Cli\Command;
|
||||
use Icinga\Module\Director\Core\Json;
|
||||
use Icinga\Module\Director\DirectorObject\Automation\Basket;
|
||||
use Icinga\Module\Director\DirectorObject\Automation\BasketSnapshot;
|
||||
use Icinga\Module\Director\DirectorObject\ObjectPurgeHelper;
|
||||
|
||||
/**
|
||||
* Export Director Config Objects
|
||||
@ -81,43 +79,14 @@ class BasketCommand extends Command
|
||||
* icingacli director basket restore < basket-dump.json
|
||||
*
|
||||
* OPTIONS
|
||||
* --purge <ObjectType>[,<ObjectType] Purge objects of the
|
||||
* Given types. WARNING: this removes ALL objects that are
|
||||
* not shipped with the given basket
|
||||
* --force Purge refuses to purge Objects in case there are
|
||||
* no Objects of a given ObjectType in the provided basket
|
||||
* unless forced to do so
|
||||
*/
|
||||
public function restoreAction()
|
||||
{
|
||||
if ($purge = $this->params->get('purge')) {
|
||||
$purge = explode(',', $purge);
|
||||
ObjectPurgeHelper::assertObjectTypesAreEligibleForPurge($purge);
|
||||
}
|
||||
$json = file_get_contents('php://stdin');
|
||||
BasketSnapshot::restoreJson($json, $this->db());
|
||||
if ($purge) {
|
||||
$this->purgeObjectTypes(Json::decode($json), $purge, $this->params->get('force'));
|
||||
}
|
||||
echo "Objects from Basket Snapshot have been restored\n";
|
||||
}
|
||||
|
||||
protected function purgeObjectTypes($objects, array $types, $force = false)
|
||||
{
|
||||
$helper = new ObjectPurgeHelper($this->db());
|
||||
if ($force) {
|
||||
$helper->force();
|
||||
}
|
||||
foreach ($types as $type) {
|
||||
list($className, $typeFilter) = BasketSnapshot::getClassAndObjectTypeForType($type);
|
||||
$helper->purge(
|
||||
isset($objects->$type) ? (array) $objects->$type : [],
|
||||
$className,
|
||||
$typeFilter
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
protected function requireBasket()
|
||||
|
@ -5,8 +5,6 @@ namespace Icinga\Module\Director\Clicommands;
|
||||
use Icinga\Application\Benchmark;
|
||||
use Icinga\Module\Director\Cli\Command;
|
||||
use Icinga\Module\Director\Core\Json;
|
||||
use Icinga\Module\Director\Deployment\ConditionalDeployment;
|
||||
use Icinga\Module\Director\Deployment\DeploymentGracePeriod;
|
||||
use Icinga\Module\Director\Deployment\DeploymentStatus;
|
||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||
use Icinga\Module\Director\Import\SyncUtils;
|
||||
@ -88,23 +86,12 @@ class ConfigCommand extends Command
|
||||
/**
|
||||
* Deploy the current configuration
|
||||
*
|
||||
* USAGE
|
||||
*
|
||||
* icingacli director config deploy [--checksum <checksum>] [--force] [--wait <seconds>]
|
||||
* [--grace-period <seconds>]
|
||||
*
|
||||
* OPTIONS
|
||||
*
|
||||
* --checksum <checksum> Optionally deploy a specific configuration
|
||||
* --force Force a deployment, even when the configuration
|
||||
* hasn't changed
|
||||
* --wait <seconds> Optionally wait until Icinga completed it's
|
||||
* restart
|
||||
* --grace-period <seconds> Do not deploy if a deployment took place
|
||||
* less than <seconds> ago
|
||||
* Does nothing if config didn't change unless you provide
|
||||
* the --force parameter
|
||||
*/
|
||||
public function deployAction()
|
||||
{
|
||||
$api = $this->api();
|
||||
$db = $this->db();
|
||||
|
||||
$checksum = $this->params->get('checksum');
|
||||
@ -115,31 +102,24 @@ class ConfigCommand extends Command
|
||||
$checksum = $config->getHexChecksum();
|
||||
}
|
||||
|
||||
$deployer = new ConditionalDeployment($db, $this->api());
|
||||
$deployer->force((bool) $this->params->get('force'));
|
||||
if ($graceTime = $this->params->get('grace-period')) {
|
||||
$deployer->setGracePeriod(new DeploymentGracePeriod((int) $graceTime, $db));
|
||||
$api->wipeInactiveStages($db);
|
||||
$current = $api->getActiveChecksum($db);
|
||||
if ($current === $checksum) {
|
||||
if ($this->params->get('force')) {
|
||||
fwrite(STDERR, "WARNING: force overrides Grace period\n");
|
||||
echo "Config matches active stage, deploying anyway\n";
|
||||
} else {
|
||||
echo "Config matches active stage, nothing to do\n";
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
$deployer->refresh();
|
||||
|
||||
if ($deployment = $deployer->deploy($config)) {
|
||||
if ($deployer->hasBeenForced()) {
|
||||
echo $deployer->getNoDeploymentReason() . ", deploying anyway\n";
|
||||
}
|
||||
if ($api->dumpConfig($config, $db)) {
|
||||
printf("Config '%s' has been deployed\n", $checksum);
|
||||
} else {
|
||||
echo $deployer->getNoDeploymentReason() . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if ($timeout = $this->getWaitTime()) {
|
||||
$deployed = $deployer->waitForStartupAfterDeploy($deployment, $timeout);
|
||||
if ($deployed !== true) {
|
||||
$this->fail("Waiting for Icinga restart failed '%s': %s\n", $checksum, $deployed);
|
||||
}
|
||||
$this->fail(
|
||||
sprintf("Failed to deploy config '%s'\n", $checksum)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,17 +142,4 @@ class ConfigCommand extends Command
|
||||
echo Json::encode($result, JSON_PRETTY_PRINT) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
protected function getWaitTime()
|
||||
{
|
||||
if ($timeout = $this->params->get('wait')) {
|
||||
if (!ctype_digit($timeout)) {
|
||||
$this->fail("--wait must be the number of seconds to wait'");
|
||||
}
|
||||
|
||||
return (int) $timeout;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ namespace Icinga\Module\Director\Clicommands;
|
||||
|
||||
use Icinga\Application\Benchmark;
|
||||
use Icinga\Module\Director\Cli\Command;
|
||||
use Icinga\Module\Director\Core\Json;
|
||||
use Icinga\Module\Director\Hook\ImportSourceHook;
|
||||
use Icinga\Module\Director\Objects\ImportSource;
|
||||
|
||||
@ -91,7 +90,7 @@ class ImportsourceCommand extends Command
|
||||
$data = $hook->fetchData();
|
||||
$source->applyModifiers($data);
|
||||
Benchmark::measure(sprintf('Got %d rows, ready to dump JSON', count($data)));
|
||||
echo Json::encode($data, JSON_PRETTY_PRINT);
|
||||
echo json_encode($data, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,9 +29,8 @@ class KickstartCommand extends Command
|
||||
* require => Exec['Icinga Director DB migration'],
|
||||
* }
|
||||
*
|
||||
* 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.
|
||||
* Exit code 0 means that a kickstart run is required, code 2 that it is
|
||||
* not.
|
||||
*/
|
||||
public function requiredAction()
|
||||
{
|
||||
|
@ -2,12 +2,8 @@
|
||||
|
||||
namespace Icinga\Module\Director\Clicommands;
|
||||
|
||||
use Icinga\Cli\Params;
|
||||
use Icinga\Module\Director\Cli\ObjectCommand;
|
||||
use Icinga\Module\Director\DirectorObject\Lookup\ServiceFinder;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Resolver\OverrideHelper;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Manage Icinga Services
|
||||
@ -17,53 +13,6 @@ use InvalidArgumentException;
|
||||
*/
|
||||
class ServiceCommand extends ObjectCommand
|
||||
{
|
||||
public function setAction()
|
||||
{
|
||||
if (($host = $this->params->get('host')) && $this->params->shift('allow-overrides')) {
|
||||
if ($this->setServiceProperties($host)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
parent::setAction();
|
||||
}
|
||||
|
||||
protected function setServiceProperties($hostname)
|
||||
{
|
||||
$serviceName = $this->getName();
|
||||
$host = IcingaHost::load($hostname, $this->db());
|
||||
$service = ServiceFinder::find($host, $serviceName);
|
||||
if ($service->requiresOverrides()) {
|
||||
self::checkForOverrideSafety($this->params);
|
||||
$properties = $this->remainingParams();
|
||||
unset($properties['host']);
|
||||
OverrideHelper::applyOverriddenVars($host, $serviceName, $properties);
|
||||
$this->persistChanges($host, 'Host', $hostname . " (Overrides for $serviceName)", 'modified');
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static function checkForOverrideSafety(Params $params)
|
||||
{
|
||||
if ($params->shift('replace')) {
|
||||
throw new InvalidArgumentException('--replace is not available for Variable Overrides');
|
||||
}
|
||||
$appends = self::stripPrefixedProperties($params, 'append-');
|
||||
$remove = self::stripPrefixedProperties($params, 'remove-');
|
||||
OverrideHelper::assertVarsForOverrides($appends);
|
||||
OverrideHelper::assertVarsForOverrides($remove);
|
||||
if (!empty($appends)) {
|
||||
throw new InvalidArgumentException('--append- is not available for Variable Overrides');
|
||||
}
|
||||
if (!empty($remove)) {
|
||||
throw new InvalidArgumentException('--remove- is not available for Variable Overrides');
|
||||
}
|
||||
// Alternative, untested:
|
||||
// $this->appendToArrayProperties($object, $appends);
|
||||
// $this->removeProperties($object, $remove);
|
||||
}
|
||||
|
||||
protected function load($name)
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace Icinga\Module\Director\Clicommands;
|
||||
|
||||
use Icinga\Module\Director\Cli\Command;
|
||||
use Icinga\Module\Director\Objects\DirectorActivityLog;
|
||||
use Icinga\Module\Director\Objects\IcingaObject;
|
||||
use Icinga\Module\Director\Objects\SyncRule;
|
||||
use RuntimeException;
|
||||
@ -99,9 +98,9 @@ class SyncruleCommand extends Command
|
||||
}
|
||||
|
||||
return (object) [
|
||||
DirectorActivityLog::ACTION_CREATE => $create,
|
||||
DirectorActivityLog::ACTION_MODIFY => $modify,
|
||||
DirectorActivityLog::ACTION_DELETE => $delete,
|
||||
'create' => $create,
|
||||
'modify' => $modify,
|
||||
'delete' => $delete,
|
||||
];
|
||||
}
|
||||
|
||||
@ -167,7 +166,7 @@ class SyncruleCommand extends Command
|
||||
return 'There are pending changes for this Sync Rule. You should'
|
||||
. ' trigger a new Sync Run.';
|
||||
case 'failing':
|
||||
return 'This Sync Rule failed: ' . $rule->get('last_error_message');
|
||||
return 'This Sync Rule failed: '. $rule->get('last_error_message');
|
||||
default:
|
||||
throw new RuntimeException('Invalid sync state: ' . $rule->get('sync_state'));
|
||||
}
|
||||
|
@ -9,10 +9,12 @@ 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\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;
|
||||
@ -21,7 +23,6 @@ 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
|
||||
{
|
||||
@ -125,26 +126,6 @@ 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
|
||||
*/
|
||||
@ -165,12 +146,6 @@ 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(
|
||||
@ -269,9 +244,11 @@ class BasketController extends ActionController
|
||||
$connection = $this->db();
|
||||
}
|
||||
|
||||
$json = $snapshot->getJsonDump();
|
||||
$this->addSingleTab($this->translate('Snapshot'));
|
||||
$diff = new BasketDiff($snapshot, $connection);
|
||||
foreach ($diff->getBasketObjects() as $type => $objects) {
|
||||
$all = Json::decode($json);
|
||||
$fieldResolver = new BasketSnapshotFieldResolver($all, $connection);
|
||||
foreach ($all 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
|
||||
@ -295,33 +272,39 @@ class BasketController extends ActionController
|
||||
$linkParams['target_db'] = $targetDbName;
|
||||
}
|
||||
try {
|
||||
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'),
|
||||
$current = BasketSnapshot::instanceByIdentifier($type, $key, $connection);
|
||||
if ($current === null) {
|
||||
$table->addNameValueRow(
|
||||
$key,
|
||||
Link::create(
|
||||
Html::tag('strong', ['style' => 'color: green'], $this->translate('new')),
|
||||
'director/basket/snapshotobject',
|
||||
$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']
|
||||
$linkParams
|
||||
)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$table->addNameValueRow($key, $link);
|
||||
$currentExport = $current->export();
|
||||
$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'))
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
$table->addNameValueRow(
|
||||
$key,
|
||||
@ -337,6 +320,7 @@ class BasketController extends ActionController
|
||||
$this->content()->add(Html::tag('h2', $type));
|
||||
$this->content()->add($table);
|
||||
}
|
||||
$this->content()->add(Html::tag('div', ['style' => 'height: 5em']));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -383,27 +367,38 @@ class BasketController extends ActionController
|
||||
*/
|
||||
]);
|
||||
|
||||
$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);
|
||||
}
|
||||
$diff = new BasketDiff($snapshot, $connection);
|
||||
$object = $diff->getBasketObject($type, $key);
|
||||
if ($uuid = $object->uuid ?? null) {
|
||||
$uuid = Uuid::fromString($uuid);
|
||||
$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 = $current->export();
|
||||
$fieldResolver->tweakTargetIds($exported);
|
||||
unset($exported->originalId);
|
||||
CompareBasketObject::normalize($exported);
|
||||
$current = Json::encode($exported, JSON_PRETTY_PRINT);
|
||||
}
|
||||
$basketJson = $diff->getBasketString($type, $key);
|
||||
$currentJson = $diff->getCurrentString($type, $key, $uuid);
|
||||
if ($currentJson === $basketJson) {
|
||||
|
||||
if ($current === $objectFromBasket) {
|
||||
$this->content()->add([
|
||||
Hint::ok('Basket equals current object'),
|
||||
Html::tag('pre', $currentJson)
|
||||
Html::tag('pre', $current)
|
||||
]);
|
||||
} else {
|
||||
$this->content()->add(new InlineDiff(new PhpDiff($currentJson, $basketJson)));
|
||||
$this->content()->add(new InlineDiff(new PhpDiff($current, $objectFromBasket)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,138 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use gipfl\Diff\HtmlRenderer\SideBySideDiff;
|
||||
use gipfl\Diff\PhpDiff;
|
||||
use gipfl\IcingaWeb2\Widget\NameValueTable;
|
||||
use Icinga\Module\Director\Data\Db\DbObjectStore;
|
||||
use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
|
||||
use Icinga\Module\Director\Db\Branch\BranchActivity;
|
||||
use Icinga\Module\Director\Db\Branch\BranchStore;
|
||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||
use Icinga\Module\Director\Objects\IcingaObject;
|
||||
use Icinga\Module\Director\Objects\SyncRule;
|
||||
use Icinga\Module\Director\PlainObjectRenderer;
|
||||
use Icinga\Module\Director\Web\Controller\ActionController;
|
||||
use Icinga\Module\Director\Web\Controller\BranchHelper;
|
||||
use Icinga\Module\Director\Web\Widget\IcingaConfigDiff;
|
||||
use ipl\Html\Html;
|
||||
|
||||
class BranchController extends ActionController
|
||||
{
|
||||
use BranchHelper;
|
||||
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
IcingaObject::setDbObjectStore(new DbObjectStore($this->db(), $this->getBranch()));
|
||||
SyncRule::setDbObjectStore(new DbObjectStore($this->db(), $this->getBranch()));
|
||||
}
|
||||
|
||||
protected function checkDirectorPermissions()
|
||||
{
|
||||
}
|
||||
|
||||
public function activityAction()
|
||||
{
|
||||
$this->assertPermission('director/showconfig');
|
||||
$ts = $this->params->getRequired('ts');
|
||||
$activity = BranchActivity::load($ts, $this->db());
|
||||
$store = new BranchStore($this->db());
|
||||
$branch = $store->fetchBranchByUuid($activity->getBranchUuid());
|
||||
if ($branch->isSyncPreview()) {
|
||||
$this->addSingleTab($this->translate('Sync Preview'));
|
||||
$this->addTitle($this->translate('Expected Modification'));
|
||||
} else {
|
||||
$this->addSingleTab($this->translate('Activity'));
|
||||
$this->addTitle($this->translate('Branch Activity'));
|
||||
}
|
||||
|
||||
$this->content()->add($this->prepareActivityInfo($activity));
|
||||
$this->showActivity($activity);
|
||||
}
|
||||
|
||||
protected function prepareActivityInfo(BranchActivity $activity)
|
||||
{
|
||||
$table = new NameValueTable();
|
||||
$table->addNameValuePairs([
|
||||
$this->translate('Author') => $activity->getAuthor(),
|
||||
$this->translate('Date') => date('Y-m-d H:i:s', $activity->getTimestamp()),
|
||||
$this->translate('Action') => $activity->getAction()
|
||||
. ' ' . preg_replace('/^icinga_/', '', $activity->getObjectTable())
|
||||
. ' ' . $activity->getObjectName(),
|
||||
// $this->translate('Actions') => ['Undo form'],
|
||||
]);
|
||||
return $table;
|
||||
}
|
||||
|
||||
protected function leftFromActivity(BranchActivity $activity)
|
||||
{
|
||||
if ($activity->isActionCreate()) {
|
||||
return null;
|
||||
}
|
||||
$object = DbObjectTypeRegistry::newObject($activity->getObjectTable(), [], $this->db());
|
||||
$properties = $this->objectTypeFirst($activity->getFormerProperties()->jsonSerialize());
|
||||
foreach ($properties as $key => $value) {
|
||||
$object->set($key, $value);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
protected function rightFromActivity(BranchActivity $activity)
|
||||
{
|
||||
if ($activity->isActionDelete()) {
|
||||
return null;
|
||||
}
|
||||
$object = DbObjectTypeRegistry::newObject($activity->getObjectTable(), [], $this->db());
|
||||
if (! $activity->isActionCreate()) {
|
||||
foreach ($activity->getFormerProperties()->jsonSerialize() as $key => $value) {
|
||||
$object->set($key, $value);
|
||||
}
|
||||
}
|
||||
$properties = $this->objectTypeFirst($activity->getModifiedProperties()->jsonSerialize());
|
||||
foreach ($properties as $key => $value) {
|
||||
$object->set($key, $value);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
|
||||
protected function objectTypeFirst($properties)
|
||||
{
|
||||
$properties = (array) $properties;
|
||||
if (isset($properties['object_type'])) {
|
||||
$type = $properties['object_type'];
|
||||
unset($properties['object_type']);
|
||||
$properties = ['object_type' => $type] + $properties;
|
||||
}
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
protected function showActivity(BranchActivity $activity)
|
||||
{
|
||||
$left = $this->leftFromActivity($activity);
|
||||
$right = $this->rightFromActivity($activity);
|
||||
if ($left instanceof IcingaObject || $right instanceof IcingaObject) {
|
||||
$this->content()->add(new IcingaConfigDiff(
|
||||
$left ? $left->toSingleIcingaConfig() : $this->createEmptyConfig(),
|
||||
$right ? $right->toSingleIcingaConfig() : $this->createEmptyConfig()
|
||||
));
|
||||
} else {
|
||||
$this->content()->add([
|
||||
Html::tag('h3', $this->translate('Modification')),
|
||||
new SideBySideDiff(new PhpDiff(
|
||||
PlainObjectRenderer::render($left->getProperties()),
|
||||
PlainObjectRenderer::render($right->getProperties())
|
||||
))
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function createEmptyConfig()
|
||||
{
|
||||
return new IcingaConfig($this->db());
|
||||
}
|
||||
}
|
@ -3,8 +3,6 @@
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use gipfl\Web\Widget\Hint;
|
||||
use Icinga\Module\Director\Objects\IcingaCommandArgument;
|
||||
use Icinga\Module\Director\Web\Table\BranchedIcingaCommandArgumentTable;
|
||||
use ipl\Html\Html;
|
||||
use Icinga\Module\Director\Forms\IcingaCommandArgumentForm;
|
||||
use Icinga\Module\Director\Objects\IcingaCommand;
|
||||
@ -24,14 +22,9 @@ class CommandController extends ObjectController
|
||||
parent::init();
|
||||
$o = $this->object;
|
||||
if ($o && ! $o->isExternal()) {
|
||||
if ($this->getBranch()->isBranch()) {
|
||||
$urlParams = ['uuid' => $o->getUniqueId()->toString()];
|
||||
} else {
|
||||
$urlParams = ['name' => $o->getObjectName()];
|
||||
}
|
||||
$this->tabs()->add('arguments', [
|
||||
'url' => 'director/command/arguments',
|
||||
'urlParams' => $urlParams,
|
||||
'urlParams' => ['name' => $o->getObjectName()],
|
||||
'label' => 'Arguments'
|
||||
]);
|
||||
}
|
||||
@ -90,33 +83,16 @@ class CommandController extends ObjectController
|
||||
$o = $this->object;
|
||||
$this->tabs()->activate('arguments');
|
||||
$this->addTitle($this->translate('Command arguments: %s'), $o->getObjectName());
|
||||
$form = (new IcingaCommandArgumentForm())
|
||||
->setBranch($this->getBranch())
|
||||
->setCommandObject($o);
|
||||
if ($argument = $p->shift('argument')) {
|
||||
$form = IcingaCommandArgumentForm::load()->setCommandObject($o);
|
||||
if ($id = $p->shift('argument_id')) {
|
||||
$this->addBackLink('director/command/arguments', [
|
||||
'name' => $p->get('name')
|
||||
]);
|
||||
if ($this->branch->isBranch()) {
|
||||
$arguments = $o->arguments();
|
||||
$argument = $arguments->get($argument);
|
||||
// IcingaCommandArgument::create((array) $arguments->get($argument)->toFullPlainObject());
|
||||
// $argument->setBeingLoadedFromDb();
|
||||
} else {
|
||||
$argument = IcingaCommandArgument::load([
|
||||
'command_id' => $o->get('id'),
|
||||
'argument_name' => $argument
|
||||
], $this->db());
|
||||
}
|
||||
$form->setObject($argument);
|
||||
$form->loadObject($id);
|
||||
}
|
||||
$form->handleRequest();
|
||||
$this->content()->add([$form]);
|
||||
if ($this->branch->isBranch()) {
|
||||
(new BranchedIcingaCommandArgumentTable($o, $this->getBranch()))->renderTo($this);
|
||||
} else {
|
||||
(new IcingaCommandArgumentTable($o, $this->getBranch()))->renderTo($this);
|
||||
}
|
||||
IcingaCommandArgumentTable::create($o)->renderTo($this);
|
||||
}
|
||||
|
||||
protected function hasBasketSupport()
|
||||
|
@ -8,17 +8,13 @@ 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;
|
||||
use Icinga\Module\Director\Forms\SettingsForm;
|
||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||
use Icinga\Module\Director\Objects\DirectorDeploymentLog;
|
||||
use Icinga\Module\Director\Settings;
|
||||
use Icinga\Module\Director\Web\Controller\BranchHelper;
|
||||
use Icinga\Module\Director\Web\Table\ActivityLogTable;
|
||||
use Icinga\Module\Director\Web\Table\BranchActivityTable;
|
||||
use Icinga\Module\Director\Web\Table\ConfigFileDiffTable;
|
||||
use Icinga\Module\Director\Web\Table\DeploymentLogTable;
|
||||
use Icinga\Module\Director\Web\Table\GeneratedConfigFileTable;
|
||||
@ -38,8 +34,6 @@ use gipfl\IcingaWeb2\Url;
|
||||
|
||||
class ConfigController extends ActionController
|
||||
{
|
||||
use BranchHelper;
|
||||
|
||||
protected $isApified = true;
|
||||
|
||||
protected function checkDirectorPermissions()
|
||||
@ -67,15 +61,13 @@ class ConfigController extends ActionController
|
||||
// No problem, Icinga might be reloading
|
||||
}
|
||||
|
||||
if (! $this->getBranch()->isBranch()) {
|
||||
// TODO: a form!
|
||||
$this->actions()->add(Link::create(
|
||||
$this->translate('Render config'),
|
||||
'director/config/store',
|
||||
null,
|
||||
['class' => 'icon-wrench']
|
||||
));
|
||||
}
|
||||
// TODO: a form!
|
||||
$this->actions()->add(Link::create(
|
||||
$this->translate('Render config'),
|
||||
'director/config/store',
|
||||
null,
|
||||
['class' => 'icon-wrench']
|
||||
));
|
||||
|
||||
$this->tabs(new InfraTabs($this->Auth()))->activate('deploymentlog');
|
||||
$table = new DeploymentLogTable($this->db());
|
||||
@ -155,7 +147,7 @@ class ConfigController extends ActionController
|
||||
return;
|
||||
}
|
||||
$this->assertPermission('director/audit');
|
||||
$this->showOptionalBranchActivity();
|
||||
|
||||
$this->setAutorefreshInterval(10);
|
||||
$this->tabs(new InfraTabs($this->Auth()))->activate('activitylog');
|
||||
$this->addTitle($this->translate('Activity Log'));
|
||||
@ -187,7 +179,7 @@ class ConfigController extends ActionController
|
||||
['class' => 'icon-user', 'data-base-target' => '_self']
|
||||
));
|
||||
}
|
||||
if ($this->hasPermission(Permission::DEPLOY) && ! $this->getBranch()->isBranch()) {
|
||||
if ($this->hasPermission('director/deploy')) {
|
||||
if ($this->db()->hasDeploymentEndpoint()) {
|
||||
$this->actions()->add(DeployConfigForm::load()
|
||||
->setDb($this->db())
|
||||
@ -284,7 +276,6 @@ class ConfigController extends ActionController
|
||||
$config,
|
||||
$this->db(),
|
||||
$this->api(),
|
||||
$this->getBranch(),
|
||||
$deploymentId
|
||||
));
|
||||
|
||||
@ -370,35 +361,33 @@ class ConfigController extends ActionController
|
||||
|
||||
$configs = $db->enumDeployedConfigs();
|
||||
foreach (array($leftSum, $rightSum) as $sum) {
|
||||
if ($sum && ! array_key_exists($sum, $configs)) {
|
||||
if (! 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', '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
|
||||
)),
|
||||
])
|
||||
);
|
||||
$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
|
||||
)),
|
||||
]));
|
||||
|
||||
if ($rightSum === null || $leftSum === null || ! strlen($rightSum) || ! strlen($leftSum)) {
|
||||
if (! strlen($rightSum) || ! strlen($leftSum)) {
|
||||
return;
|
||||
}
|
||||
ConfigFileDiffTable::load($leftSum, $rightSum, $this->db())->renderTo($this);
|
||||
@ -433,32 +422,6 @@ class ConfigController extends ActionController
|
||||
)));
|
||||
}
|
||||
|
||||
protected function showOptionalBranchActivity()
|
||||
{
|
||||
if ($this->url()->hasParam('idRangeEx')) {
|
||||
return;
|
||||
}
|
||||
$branch = $this->getBranch();
|
||||
if ($branch->isBranch() && (int) $this->params->get('page', '1') === 1) {
|
||||
$table = new BranchActivityTable($branch->getUuid(), $this->db());
|
||||
if (count($table) > 0) {
|
||||
$this->content()->add(Hint::info(Html::sprintf($this->translate(
|
||||
'The following modifications are visible in this %s only...'
|
||||
), Branch::requireHook()->linkToBranch(
|
||||
$branch,
|
||||
$this->Auth(),
|
||||
$this->translate('configuration branch')
|
||||
))));
|
||||
$this->content()->add($table);
|
||||
$this->content()->add(Html::tag('br'));
|
||||
$this->content()->add(Hint::ok($this->translate(
|
||||
'...and the modifications below are already in the main branch:'
|
||||
)));
|
||||
$this->content()->add(Html::tag('br'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $checksum
|
||||
*/
|
||||
@ -482,7 +445,7 @@ class ConfigController extends ActionController
|
||||
*/
|
||||
protected function deploymentFailed($checksum, $error = null)
|
||||
{
|
||||
$extra = $error ? ': ' . $error : '';
|
||||
$extra = $error ? ': ' . $error: '';
|
||||
|
||||
if ($this->getRequest()->isApiRequest()) {
|
||||
$this->sendJsonError($this->getResponse(), 'Config deployment failed' . $extra);
|
||||
@ -503,8 +466,7 @@ class ConfigController extends ActionController
|
||||
{
|
||||
$tabs = $this->tabs();
|
||||
|
||||
if (
|
||||
$this->hasPermission(Permission::DEPLOY)
|
||||
if ($this->hasPermission('director/deploy')
|
||||
&& $deploymentId = $this->params->get('deployment_id')
|
||||
) {
|
||||
$tabs->add('deployment', [
|
||||
@ -514,7 +476,7 @@ class ConfigController extends ActionController
|
||||
]);
|
||||
}
|
||||
|
||||
if ($this->hasPermission(Permission::SHOW_CONFIG)) {
|
||||
if ($this->hasPermission('director/showconfig')) {
|
||||
$tabs->add('config', [
|
||||
'label' => $this->translate('Config'),
|
||||
'url' => 'director/config/files',
|
||||
|
@ -3,7 +3,9 @@
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Icinga\Module\Director\Web\Tabs\MainTabs;
|
||||
use Icinga\Module\Director\Web\Widget\HealthCheckPluginOutput;
|
||||
use Icinga\Module\Director\Dashboard\Dashboard;
|
||||
use Icinga\Module\Director\Health;
|
||||
use Icinga\Module\Director\Web\Controller\ActionController;
|
||||
use Icinga\Module\Director\Web\Form\DbSelectorForm;
|
||||
|
||||
@ -36,7 +38,6 @@ class DashboardController extends ActionController
|
||||
$mainDashboards = [
|
||||
'Objects',
|
||||
'Alerts',
|
||||
'Branches',
|
||||
'Automation',
|
||||
'Deployment',
|
||||
'Director',
|
||||
|
@ -2,18 +2,10 @@
|
||||
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use gipfl\Web\Widget\Hint;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Module\Director\Forms\DirectorDatalistEntryForm;
|
||||
use Icinga\Module\Director\Forms\DirectorDatalistForm;
|
||||
use Icinga\Module\Director\Forms\IcingaServiceDictionaryMemberForm;
|
||||
use Icinga\Module\Director\Objects\DirectorDatalist;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Objects\IcingaObject;
|
||||
use Icinga\Module\Director\Objects\IcingaService;
|
||||
use Icinga\Module\Director\PlainObjectRenderer;
|
||||
use Icinga\Module\Director\Web\Controller\ActionController;
|
||||
use Icinga\Module\Director\Web\Form\IcingaObjectFieldLoader;
|
||||
use Icinga\Module\Director\Web\Table\CustomvarTable;
|
||||
use Icinga\Module\Director\Web\Table\DatafieldCategoryTable;
|
||||
use Icinga\Module\Director\Web\Table\DatafieldTable;
|
||||
@ -21,9 +13,6 @@ use Icinga\Module\Director\Web\Table\DatalistEntryTable;
|
||||
use Icinga\Module\Director\Web\Table\DatalistTable;
|
||||
use Icinga\Module\Director\Web\Tabs\DataTabs;
|
||||
use gipfl\IcingaWeb2\Link;
|
||||
use InvalidArgumentException;
|
||||
use ipl\Html\Html;
|
||||
use ipl\Html\Table;
|
||||
|
||||
class DataController extends ActionController
|
||||
{
|
||||
@ -151,218 +140,6 @@ class DataController extends ActionController
|
||||
$this->content()->add([$form, $table]);
|
||||
}
|
||||
|
||||
public function dictionaryAction()
|
||||
{
|
||||
$connection = $this->db();
|
||||
$this->addSingleTab('Nested Dictionary');
|
||||
$varName = $this->params->get('varname');
|
||||
$instance = $this->url()->getParam('instance');
|
||||
$action = $this->url()->getParam('action');
|
||||
$object = $this->requireObject();
|
||||
|
||||
if ($instance || $action) {
|
||||
$this->actions()->add(
|
||||
Link::create($this->translate('Back'), $this->url()->without(['action', 'instance']), null, [
|
||||
'class' => 'icon-edit'
|
||||
])
|
||||
);
|
||||
} else {
|
||||
$this->actions()->add(
|
||||
Link::create($this->translate('Add'), $this->url(), [
|
||||
'action' => 'add'
|
||||
], [
|
||||
'class' => 'icon-edit'
|
||||
])
|
||||
);
|
||||
}
|
||||
$subjects = $this->prepareSubjectsLabel($object, $varName);
|
||||
$fieldLoader = new IcingaObjectFieldLoader($object);
|
||||
$instances = $this->getCurrentInstances($object, $varName);
|
||||
|
||||
if (empty($instances)) {
|
||||
$this->content()->add(Hint::info(sprintf(
|
||||
$this->translate('No %s have been created yet'),
|
||||
$subjects
|
||||
)));
|
||||
} else {
|
||||
$this->content()->add($this->prepareInstancesTable($instances));
|
||||
}
|
||||
|
||||
$field = $this->getFieldByName($fieldLoader, $varName);
|
||||
$template = $object::load([
|
||||
'object_name' => $field->getSetting('template_name')
|
||||
], $connection);
|
||||
|
||||
$form = new IcingaServiceDictionaryMemberForm();
|
||||
$form->setDb($connection);
|
||||
if ($instance) {
|
||||
$instanceObject = $object::create([
|
||||
'imports' => [$template],
|
||||
'object_name' => $instance,
|
||||
'vars' => $instances[$instance]
|
||||
], $connection);
|
||||
$form->setObject($instanceObject);
|
||||
} elseif ($action === 'add') {
|
||||
$form->presetImports([$template->getObjectName()]);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if ($instance) {
|
||||
if (! isset($instances[$instance])) {
|
||||
throw new NotFoundError("There is no such instance: $instance");
|
||||
}
|
||||
$subTitle = sprintf($this->translate('Modify instance: %s'), $instance);
|
||||
} else {
|
||||
$subTitle = $this->translate('Add a new instance');
|
||||
}
|
||||
|
||||
$this->content()->add(Html::tag('h2', ['class' => 'dictionary-header'], $subTitle));
|
||||
$form->handleRequest($this->getRequest());
|
||||
$this->content()->add($form);
|
||||
if ($form->succeeded()) {
|
||||
$virtualObject = $form->getObject();
|
||||
$name = $virtualObject->getObjectName();
|
||||
$params = $form->getObject()->getVars();
|
||||
$instances[$name] = $params;
|
||||
if ($name !== $instance) { // Has been renamed
|
||||
unset($instances[$instance]);
|
||||
}
|
||||
ksort($instances);
|
||||
$object->set("vars.$varName", (object)$instances);
|
||||
$object->store();
|
||||
$this->redirectNow($this->url()->without(['instance', 'action']));
|
||||
} elseif ($form->shouldBeDeleted()) {
|
||||
unset($instances[$instance]);
|
||||
if (empty($instances)) {
|
||||
$object->set("vars.$varName", null)->store();
|
||||
} else {
|
||||
$object->set("vars.$varName", (object)$instances)->store();
|
||||
}
|
||||
$this->redirectNow($this->url()->without(['instance', 'action']));
|
||||
}
|
||||
}
|
||||
|
||||
protected function requireObject()
|
||||
{
|
||||
$connection = $this->db();
|
||||
$hostName = $this->params->getRequired('host');
|
||||
$serviceName = $this->params->get('service');
|
||||
if ($serviceName) {
|
||||
$host = IcingaHost::load($hostName, $connection);
|
||||
$object = IcingaService::load([
|
||||
'host_id' => $host->get('id'),
|
||||
'object_name' => $serviceName,
|
||||
], $connection);
|
||||
} else {
|
||||
$object = IcingaHost::load($hostName, $connection);
|
||||
}
|
||||
|
||||
if (! $object->isObject()) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Only single objects allowed, %s is a %s',
|
||||
$object->getObjectName(),
|
||||
$object->get('object_type')
|
||||
));
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
protected function shorten($string, $maxLen)
|
||||
{
|
||||
if (strlen($string) <= $maxLen) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
return substr($string, 0, $maxLen) . '...';
|
||||
}
|
||||
|
||||
protected function getFieldByName(IcingaObjectFieldLoader $loader, $name)
|
||||
{
|
||||
foreach ($loader->getFields() as $field) {
|
||||
if ($field->get('varname') === $name) {
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException("Found no configured field for '$name'");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IcingaObject $object
|
||||
* @param $varName
|
||||
* @return array
|
||||
*/
|
||||
protected function getCurrentInstances(IcingaObject $object, $varName)
|
||||
{
|
||||
$currentVars = $object->getVars();
|
||||
if (isset($currentVars->$varName)) {
|
||||
$currentValue = $currentVars->$varName;
|
||||
} else {
|
||||
$currentValue = (object)[];
|
||||
}
|
||||
if (is_object($currentValue)) {
|
||||
$currentValue = (array)$currentValue;
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'"%s" is not a valid Dictionary',
|
||||
json_encode($currentValue)
|
||||
));
|
||||
}
|
||||
return $currentValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $currentValue
|
||||
* @param $subjects
|
||||
* @return Hint|Table
|
||||
*/
|
||||
protected function prepareInstancesTable(array $currentValue)
|
||||
{
|
||||
$table = new Table();
|
||||
$table->addAttributes([
|
||||
'class' => 'common-table table-row-selectable'
|
||||
]);
|
||||
$table->getHeader()->add(
|
||||
Table::row([
|
||||
$this->translate('Key / Instance'),
|
||||
$this->translate('Properties')
|
||||
], ['class' => 'text-align-left'], 'th')
|
||||
);
|
||||
foreach ($currentValue as $key => $item) {
|
||||
$table->add(Table::row([
|
||||
Link::create($key, $this->url()->with('instance', $key)),
|
||||
str_replace("\n", ' ', $this->shorten(PlainObjectRenderer::render($item), 512))
|
||||
]));
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param IcingaObject $object
|
||||
* @param $varName
|
||||
* @return string
|
||||
*/
|
||||
protected function prepareSubjectsLabel(IcingaObject $object, $varName)
|
||||
{
|
||||
if ($object instanceof IcingaService) {
|
||||
$hostName = $object->get('host');
|
||||
$subjects = $object->getObjectName() . " ($varName)";
|
||||
} else {
|
||||
$hostName = $object->getObjectName();
|
||||
$subjects = sprintf(
|
||||
$this->translate('%s instances'),
|
||||
$varName
|
||||
);
|
||||
}
|
||||
$this->addTitle(sprintf(
|
||||
$this->translate('%s on %s'),
|
||||
$subjects,
|
||||
$hostName
|
||||
));
|
||||
return $subjects;
|
||||
}
|
||||
|
||||
protected function addListActions(DirectorDatalist $list)
|
||||
{
|
||||
$this->actions()->add(
|
||||
|
@ -19,11 +19,17 @@ class DatafieldController extends ActionController
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
$edit = false;
|
||||
|
||||
if ($id = $this->params->get('id')) {
|
||||
$edit = true;
|
||||
}
|
||||
|
||||
$form = DirectorDatafieldForm::load()
|
||||
->setDb($this->db());
|
||||
|
||||
if ($id = $this->params->get('id')) {
|
||||
$form->loadObject((int) $id);
|
||||
if ($edit) {
|
||||
$form->loadObject($id);
|
||||
$this->addTitle(
|
||||
$this->translate('Modify %s'),
|
||||
$form->getObject()->varname
|
||||
|
@ -3,10 +3,6 @@
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use gipfl\Web\Widget\Hint;
|
||||
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;
|
||||
use gipfl\IcingaWeb2\Url;
|
||||
@ -14,7 +10,6 @@ use gipfl\IcingaWeb2\Widget\Tabs;
|
||||
use Exception;
|
||||
use Icinga\Module\Director\CustomVariable\CustomVariableDictionary;
|
||||
use Icinga\Module\Director\Db\AppliedServiceSetLoader;
|
||||
use Icinga\Module\Director\DirectorObject\Lookup\ServiceFinder;
|
||||
use Icinga\Module\Director\Forms\IcingaAddServiceForm;
|
||||
use Icinga\Module\Director\Forms\IcingaServiceForm;
|
||||
use Icinga\Module\Director\Forms\IcingaServiceSetForm;
|
||||
@ -27,52 +22,23 @@ use Icinga\Module\Director\Web\Controller\ObjectController;
|
||||
use Icinga\Module\Director\Web\SelfService;
|
||||
use Icinga\Module\Director\Web\Table\IcingaHostAppliedForServiceTable;
|
||||
use Icinga\Module\Director\Web\Table\IcingaHostAppliedServicesTable;
|
||||
use Icinga\Module\Director\Web\Table\IcingaHostServiceTable;
|
||||
use Icinga\Module\Director\Web\Table\IcingaServiceSetServiceTable;
|
||||
use Icinga\Module\Director\Web\Widget\HostServiceRedirector;
|
||||
|
||||
class HostController extends ObjectController
|
||||
{
|
||||
protected function checkDirectorPermissions()
|
||||
{
|
||||
$host = $this->getHostObject();
|
||||
$auth = $this->Auth();
|
||||
$backend = $this->backend();
|
||||
if (
|
||||
$this->isServiceAction()
|
||||
&& $backend->canModifyService($host->getObjectName(), $this->getParam('service'))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if ($this->isServicesReadOnlyAction() && $auth->hasPermission($this->getServicesReadOnlyPermission())) {
|
||||
return;
|
||||
}
|
||||
if ($auth->hasPermission(Permission::HOSTS)) { // faster
|
||||
return;
|
||||
}
|
||||
if ($backend->canModifyHost($host->getObjectName())) {
|
||||
return;
|
||||
}
|
||||
$this->assertPermission(Permission::HOSTS); // complain about default hosts permission
|
||||
}
|
||||
|
||||
protected function isServicesReadOnlyAction()
|
||||
{
|
||||
return in_array($this->getRequest()->getActionName(), [
|
||||
if (in_array($this->getRequest()->getActionName(), [
|
||||
'servicesro',
|
||||
'findservice',
|
||||
'invalidservice',
|
||||
]);
|
||||
}
|
||||
|
||||
protected function isServiceAction()
|
||||
{
|
||||
return in_array($this->getRequest()->getActionName(), [
|
||||
'servicesro',
|
||||
'findservice',
|
||||
'invalidservice',
|
||||
'servicesetservice',
|
||||
'appliedservice',
|
||||
'inheritedservice',
|
||||
]);
|
||||
'invalidservice'
|
||||
])) {
|
||||
$this->assertPermission('director/monitoring/services-ro');
|
||||
} else {
|
||||
$this->assertPermission('director/hosts');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -96,7 +62,6 @@ class HostController extends ObjectController
|
||||
$this->addTitle($this->translate('Add Service to %s'), $host->getObjectName());
|
||||
$this->content()->add(
|
||||
IcingaAddServiceForm::load()
|
||||
->setBranch($this->getBranch())
|
||||
->setHost($host)
|
||||
->setDb($this->db())
|
||||
->handleRequest()
|
||||
@ -108,10 +73,8 @@ class HostController extends ObjectController
|
||||
$host = $this->getHostObject();
|
||||
$this->addServicesHeader();
|
||||
$this->addTitle($this->translate('Add Service Set to %s'), $host->getObjectName());
|
||||
|
||||
$this->content()->add(
|
||||
IcingaServiceSetForm::load()
|
||||
->setBranch($this->getBranch())
|
||||
->setHost($host)
|
||||
->setDb($this->db())
|
||||
->handleRequest()
|
||||
@ -137,38 +100,16 @@ class HostController extends ObjectController
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Icinga\Exception\NotFoundError
|
||||
*/
|
||||
public function findserviceAction()
|
||||
{
|
||||
$auth = $this->Auth();
|
||||
$host = $this->getHostObject();
|
||||
$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);
|
||||
$redirector = new HostServiceRedirector($host, $this->getAuth());
|
||||
$this->redirectNow(
|
||||
$redirector->getRedirectionUrl($this->params->get('service'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,16 +157,12 @@ class HostController extends ObjectController
|
||||
public function servicesAction()
|
||||
{
|
||||
$this->addServicesHeader();
|
||||
$db = $this->db();
|
||||
$host = $this->getHostObject();
|
||||
$this->addTitle($this->translate('Services: %s'), $host->getObjectName());
|
||||
$branch = $this->getBranch();
|
||||
$hostHasBeenCreatedInBranch = $branch->isBranch() && $host->get('id');
|
||||
$content = $this->content();
|
||||
$table = (new ObjectsTableService($this->db(), $this->Auth()))
|
||||
->setHost($host)
|
||||
->setBranch($branch)
|
||||
->setTitle($this->translate('Individual Service objects'))
|
||||
->removeQueryLimit();
|
||||
$table = IcingaHostServiceTable::load($host)
|
||||
->setTitle($this->translate('Individual Service objects'));
|
||||
|
||||
if (count($table)) {
|
||||
$content->add($table);
|
||||
@ -235,25 +172,18 @@ class HostController extends ObjectController
|
||||
$parents = IcingaTemplateRepository::instanceByObject($this->object)
|
||||
->getTemplatesFor($this->object, true);
|
||||
foreach ($parents as $parent) {
|
||||
$table = (new ObjectsTableService($this->db(), $this->Auth()))
|
||||
->setBranch($branch)
|
||||
->setHost($parent)
|
||||
->setInheritedBy($host)
|
||||
->removeQueryLimit();
|
||||
|
||||
$table = IcingaHostServiceTable::load($parent)->setInheritedBy($host);
|
||||
if (count($table)) {
|
||||
$content->add(
|
||||
$table->setTitle(sprintf(
|
||||
$this->translate('Inherited from %s'),
|
||||
'Inherited from %s',
|
||||
$parent->getObjectName()
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (! $hostHasBeenCreatedInBranch) {
|
||||
$this->addHostServiceSetTables($host);
|
||||
}
|
||||
$this->addHostServiceSetTables($host);
|
||||
foreach ($parents as $parent) {
|
||||
$this->addHostServiceSetTables($parent, $host);
|
||||
}
|
||||
@ -265,10 +195,8 @@ class HostController extends ObjectController
|
||||
$content->add(
|
||||
IcingaServiceSetServiceTable::load($set)
|
||||
// ->setHost($host)
|
||||
->setBranch($branch)
|
||||
->setAffectedHost($host)
|
||||
->setTitle($title)
|
||||
->removeQueryLimit()
|
||||
);
|
||||
}
|
||||
|
||||
@ -291,19 +219,15 @@ class HostController extends ObjectController
|
||||
*/
|
||||
public function servicesroAction()
|
||||
{
|
||||
$this->assertPermission($this->getServicesReadOnlyPermission());
|
||||
$this->assertPermission('director/monitoring/services-ro');
|
||||
$host = $this->getHostObject();
|
||||
$service = $this->params->getRequired('service');
|
||||
$db = $this->db();
|
||||
$branch = $this->getBranch();
|
||||
$this->controls()->setTabs(new Tabs());
|
||||
$this->addSingleTab($this->translate('Configuration (read-only)'));
|
||||
$this->addTitle($this->translate('Services on %s'), $host->getObjectName());
|
||||
$content = $this->content();
|
||||
|
||||
$table = (new ObjectsTableService($db, $this->Auth()))
|
||||
->setHost($host)
|
||||
->setBranch($branch)
|
||||
$table = IcingaHostServiceTable::load($host)
|
||||
->setReadonly()
|
||||
->highlightService($service)
|
||||
->setTitle($this->translate('Individual Service objects'));
|
||||
@ -316,10 +240,8 @@ class HostController extends ObjectController
|
||||
$parents = IcingaTemplateRepository::instanceByObject($this->object)
|
||||
->getTemplatesFor($this->object, true);
|
||||
foreach ($parents as $parent) {
|
||||
$table = (new ObjectsTableService($db, $this->Auth()))
|
||||
$table = IcingaHostServiceTable::load($parent)
|
||||
->setReadonly()
|
||||
->setBranch($branch)
|
||||
->setHost($parent)
|
||||
->highlightService($service)
|
||||
->setInheritedBy($host);
|
||||
if (count($table)) {
|
||||
@ -344,7 +266,6 @@ class HostController extends ObjectController
|
||||
$content->add(
|
||||
IcingaServiceSetServiceTable::load($set)
|
||||
// ->setHost($host)
|
||||
->setBranch($branch)
|
||||
->setAffectedHost($host)
|
||||
->setReadonly()
|
||||
->highlightService($service)
|
||||
@ -372,9 +293,6 @@ class HostController extends ObjectController
|
||||
if ($affectedHost === null) {
|
||||
$affectedHost = $host;
|
||||
}
|
||||
if ($host->get('id') === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $db->getDbAdapter()->select()
|
||||
->from(
|
||||
@ -396,9 +314,7 @@ class HostController extends ObjectController
|
||||
$title = sprintf($this->translate('%s (Service set)'), $name);
|
||||
$table = IcingaServiceSetServiceTable::load($set)
|
||||
->setHost($host)
|
||||
->setBranch($this->getBranch())
|
||||
->setAffectedHost($affectedHost)
|
||||
->removeQueryLimit()
|
||||
->setTitle($title);
|
||||
if ($roService) {
|
||||
$table->setReadonly()->highlightService($roService);
|
||||
@ -434,7 +350,6 @@ class HostController extends ObjectController
|
||||
$this->content()->add(
|
||||
IcingaServiceForm::load()
|
||||
->setDb($db)
|
||||
->setBranch($this->getBranch())
|
||||
->setHost($host)
|
||||
->setApplyGenerated($parent)
|
||||
->setObject($service)
|
||||
@ -475,7 +390,6 @@ class HostController extends ObjectController
|
||||
|
||||
$form = IcingaServiceForm::load()
|
||||
->setDb($db)
|
||||
->setBranch($this->getBranch())
|
||||
->setHost($host)
|
||||
->setInheritedFrom($from->getObjectName())
|
||||
->setObject($service)
|
||||
@ -553,7 +467,6 @@ class HostController extends ObjectController
|
||||
|
||||
$form = IcingaServiceForm::load()
|
||||
->setDb($db)
|
||||
->setBranch($this->getBranch())
|
||||
->setHost($host)
|
||||
->setServiceSet($set)
|
||||
->setObject($service)
|
||||
@ -594,20 +507,20 @@ class HostController extends ObjectController
|
||||
{
|
||||
$host = $this->object;
|
||||
try {
|
||||
$backend = $this->backend();
|
||||
if (
|
||||
$host instanceof IcingaHost
|
||||
&& $host->isObject()
|
||||
&& $backend->hasHost($host->getObjectName())
|
||||
$mon = $this->monitoring();
|
||||
if ($host->isObject()
|
||||
&& $mon->isAvailable()
|
||||
&& $mon->hasHost($host->getObjectName())
|
||||
) {
|
||||
$this->actions()->add(
|
||||
Link::create(
|
||||
$this->translate('Show'),
|
||||
$backend->getHostUrl($host->getObjectName()),
|
||||
null,
|
||||
['class' => 'icon-globe critical', 'data-base-target' => '_next']
|
||||
)
|
||||
);
|
||||
$this->actions()->add(Link::create(
|
||||
$this->translate('Show'),
|
||||
'monitoring/host/show',
|
||||
['host' => $host->getObjectName()],
|
||||
[
|
||||
'class' => 'icon-globe critical',
|
||||
'data-base-target' => '_next'
|
||||
]
|
||||
));
|
||||
|
||||
// Intentionally placed here, show it only for deployed Hosts
|
||||
$this->addOptionalInspectLink();
|
||||
@ -619,7 +532,7 @@ class HostController extends ObjectController
|
||||
|
||||
protected function addOptionalInspectLink()
|
||||
{
|
||||
if (! $this->hasPermission(Permission::INSPECT)) {
|
||||
if (! $this->hasPermission('director/inspect')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -639,25 +552,11 @@ class HostController extends ObjectController
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?IcingaHost
|
||||
* @return IcingaHost
|
||||
*/
|
||||
protected function getHostObject()
|
||||
{
|
||||
if ($this->object !== null) {
|
||||
assert($this->object instanceof IcingaHost);
|
||||
}
|
||||
/** @var IcingaHost $this->object */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -3,16 +3,12 @@
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Exception;
|
||||
use gipfl\Web\Widget\Hint;
|
||||
use Icinga\Module\Director\Data\Exporter;
|
||||
use Icinga\Module\Director\Db\Branch\Branch;
|
||||
use Icinga\Module\Director\Forms\ImportRowModifierForm;
|
||||
use Icinga\Module\Director\Forms\ImportSourceForm;
|
||||
use Icinga\Module\Director\Hook\ImportSourceHook;
|
||||
use Icinga\Module\Director\Web\ActionBar\AutomationObjectActionBar;
|
||||
use Icinga\Module\Director\Web\Controller\ActionController;
|
||||
use Icinga\Module\Director\Objects\ImportSource;
|
||||
use Icinga\Module\Director\Web\Controller\BranchHelper;
|
||||
use Icinga\Module\Director\Web\Form\CloneImportSourceForm;
|
||||
use Icinga\Module\Director\Web\Table\ImportrunTable;
|
||||
use Icinga\Module\Director\Web\Table\ImportsourceHookTable;
|
||||
@ -22,12 +18,9 @@ use Icinga\Module\Director\Web\Widget\ImportSourceDetails;
|
||||
use InvalidArgumentException;
|
||||
use gipfl\IcingaWeb2\Link;
|
||||
use ipl\Html\Error;
|
||||
use ipl\Html\Html;
|
||||
|
||||
class ImportsourceController extends ActionController
|
||||
{
|
||||
use BranchHelper;
|
||||
|
||||
/** @var ImportSource|null */
|
||||
private $importSource;
|
||||
|
||||
@ -85,36 +78,24 @@ class ImportsourceController extends ActionController
|
||||
$this->addMainActions();
|
||||
$source = $this->getImportSource();
|
||||
if ($this->params->get('format') === 'json') {
|
||||
$this->sendJson($this->getResponse(), (new Exporter($this->db()))->export($source));
|
||||
$this->sendJson($this->getResponse(), $source->export());
|
||||
return;
|
||||
}
|
||||
$this->addTitle(
|
||||
$this->translate('Import source: %s'),
|
||||
$source->get('source_name')
|
||||
)->setAutorefreshInterval(10);
|
||||
$branch = $this->getBranch();
|
||||
if ($this->getBranch()->isBranch()) {
|
||||
$this->content()->add(Hint::info(Html::sprintf($this->translate(
|
||||
'Please note that importing data will take place in your main Branch.'
|
||||
. ' Modifications to Import Sources are not allowed while being in a Configuration Branch.'
|
||||
. ' To get the full functionality, please deactivate %s'
|
||||
), Branch::requireHook()->linkToBranch($branch, $this->getAuth(), $branch->getName()))));
|
||||
}
|
||||
$this->content()->add(new ImportSourceDetails($source));
|
||||
}
|
||||
|
||||
public function addAction()
|
||||
{
|
||||
$this->addTitle($this->translate('Add import source'));
|
||||
if ($this->showNotInBranch($this->translate('Creating Import Sources'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->content()->add(
|
||||
ImportSourceForm::load()->setDb($this->db())
|
||||
->setSuccessUrl('director/importsources')
|
||||
->handleRequest()
|
||||
);
|
||||
$this->addTitle($this->translate('Add import source'))
|
||||
->content()->add(
|
||||
ImportSourceForm::load()->setDb($this->db())
|
||||
->setSuccessUrl('director/importsources')
|
||||
->handleRequest()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -124,9 +105,6 @@ class ImportsourceController extends ActionController
|
||||
{
|
||||
$this->addMainActions();
|
||||
$this->activateTabWithPostfix($this->translate('Modify'));
|
||||
if ($this->showNotInBranch($this->translate('Modifying Import Sources'))) {
|
||||
return;
|
||||
}
|
||||
$form = ImportSourceForm::load()
|
||||
->setObject($this->getImportSource())
|
||||
->setListUrl('director/importsources')
|
||||
@ -146,9 +124,6 @@ class ImportsourceController extends ActionController
|
||||
{
|
||||
$this->addMainActions();
|
||||
$this->activateTabWithPostfix($this->translate('Clone'));
|
||||
if ($this->showNotInBranch($this->translate('Cloning Import Sources'))) {
|
||||
return;
|
||||
}
|
||||
$source = $this->getImportSource();
|
||||
$this->addTitle('Clone: %s', $source->get('source_name'));
|
||||
$form = new CloneImportSourceForm($source);
|
||||
@ -180,7 +155,9 @@ 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) {
|
||||
@ -229,13 +206,9 @@ class ImportsourceController extends ActionController
|
||||
protected function requireImportSourceAndAddModifierTable()
|
||||
{
|
||||
$source = $this->getImportSource();
|
||||
$table = PropertymodifierTable::load($source, $this->url());
|
||||
if ($this->getBranch()->isBranch()) {
|
||||
$table->setReadOnly();
|
||||
} else {
|
||||
$table->handleSortPriorityActions($this->getRequest(), $this->getResponse());
|
||||
}
|
||||
$table->renderTo($this);
|
||||
PropertymodifierTable::load($source, $this->url())
|
||||
->handleSortPriorityActions($this->getRequest(), $this->getResponse())
|
||||
->renderTo($this);
|
||||
|
||||
return $source;
|
||||
}
|
||||
@ -280,10 +253,6 @@ class ImportsourceController extends ActionController
|
||||
)->addBackToModifiersLink($source);
|
||||
$this->tabs()->activate('modifier');
|
||||
|
||||
if ($this->showNotInBranch($this->translate('Modifying Import Sources'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->content()->prepend(
|
||||
ImportRowModifierForm::load()->setDb($this->db())
|
||||
->setSource($source)
|
||||
@ -310,15 +279,12 @@ class ImportsourceController extends ActionController
|
||||
)->addBackToModifiersLink($source);
|
||||
$source = $this->requireImportSourceAndAddModifierTable();
|
||||
$this->tabs()->activate('modifier');
|
||||
if ($this->showNotInBranch($this->translate('Modifying Import Sources'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$listUrl = 'director/importsource/modifier?source_id='
|
||||
. (int) $source->get('id');
|
||||
$this->content()->prepend(
|
||||
ImportRowModifierForm::load()->setDb($this->db())
|
||||
->loadObject((int) $this->params->getRequired('id'))
|
||||
->loadObject($this->params->getRequired('id'))
|
||||
->setListUrl($listUrl)
|
||||
->setSource($source)
|
||||
->handleRequest()
|
||||
|
@ -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'
|
||||
|
@ -6,13 +6,10 @@ use gipfl\IcingaWeb2\Link;
|
||||
use Icinga\Module\Director\Forms\DirectorJobForm;
|
||||
use Icinga\Module\Director\Web\Controller\ActionController;
|
||||
use Icinga\Module\Director\Objects\DirectorJob;
|
||||
use Icinga\Module\Director\Web\Controller\BranchHelper;
|
||||
use Icinga\Module\Director\Web\Widget\JobDetails;
|
||||
|
||||
class JobController extends ActionController
|
||||
{
|
||||
use BranchHelper;
|
||||
|
||||
/**
|
||||
* @throws \Icinga\Exception\MissingParameterException
|
||||
* @throws \Icinga\Exception\NotFoundError
|
||||
@ -32,17 +29,13 @@ class JobController extends ActionController
|
||||
{
|
||||
$this
|
||||
->addSingleTab($this->translate('New Job'))
|
||||
->addTitle($this->translate('Add a new Job'));
|
||||
if ($this->showNotInBranch($this->translate('Creating Jobs'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->content()->add(
|
||||
DirectorJobForm::load()
|
||||
->setSuccessUrl('director/job')
|
||||
->setDb($this->db())
|
||||
->handleRequest()
|
||||
);
|
||||
->addTitle($this->translate('Add a new Job'))
|
||||
->content()->add(
|
||||
DirectorJobForm::load()
|
||||
->setSuccessUrl('director/job')
|
||||
->setDb($this->db())
|
||||
->handleRequest()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,19 +45,16 @@ class JobController extends ActionController
|
||||
public function editAction()
|
||||
{
|
||||
$job = $this->requireJob();
|
||||
$this
|
||||
->addJobTabs($job, 'edit')
|
||||
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
|
||||
->addToBasketLink();
|
||||
if ($this->showNotInBranch($this->translate('Modifying Jobs'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form = DirectorJobForm::load()
|
||||
->setListUrl('director/jobs')
|
||||
->setObject($job)
|
||||
->handleRequest();
|
||||
$this->content()->add($form);
|
||||
|
||||
$this
|
||||
->addJobTabs($job, 'edit')
|
||||
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
|
||||
->addToBasketLink()
|
||||
->content()->add($form);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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');
|
||||
|
||||
|
@ -4,19 +4,13 @@ namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Module\Director\Forms\KickstartForm;
|
||||
use Icinga\Module\Director\Web\Controller\BranchHelper;
|
||||
|
||||
class KickstartController extends DashboardController
|
||||
{
|
||||
use BranchHelper;
|
||||
|
||||
public function indexAction()
|
||||
{
|
||||
$this->addSingleTab($this->translate('Kickstart'))
|
||||
->addTitle($this->translate('Director Kickstart Wizard'));
|
||||
if ($this->showNotInBranch($this->translate('Kickstart'))) {
|
||||
return;
|
||||
}
|
||||
$form = KickstartForm::load();
|
||||
try {
|
||||
$form->setEndpoint($this->db()->getDeploymentEndpoint());
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Module\Director\Web\Controller\ObjectController;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Objects\IcingaNotification;
|
||||
@ -53,11 +52,6 @@ class NotificationController extends ObjectController
|
||||
}
|
||||
}
|
||||
|
||||
protected function hasBasketSupport()
|
||||
{
|
||||
return $this->object->isTemplate() || $this->object->isApplyRule();
|
||||
}
|
||||
|
||||
protected function loadObject()
|
||||
{
|
||||
if ($this->object === null) {
|
||||
@ -81,10 +75,6 @@ class NotificationController extends ObjectController
|
||||
}
|
||||
}
|
||||
|
||||
if (! $this->allowsObject($this->object)) {
|
||||
throw new NotFoundError('No such object available');
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
}
|
||||
|
@ -11,11 +11,6 @@ class ScheduledDowntimeController extends ObjectController
|
||||
{
|
||||
protected $objectBaseUrl = 'director/scheduled-downtime';
|
||||
|
||||
protected function checkDirectorPermissions()
|
||||
{
|
||||
$this->assertPermission('director/scheduled-downtimes');
|
||||
}
|
||||
|
||||
public function rangesAction()
|
||||
{
|
||||
/** @var IcingaScheduledDowntime $object */
|
||||
|
@ -34,14 +34,4 @@ class ScheduledDowntimesController extends ObjectsController
|
||||
{
|
||||
return 'scheduled-downtime';
|
||||
}
|
||||
|
||||
protected function assertApplyRulePermission()
|
||||
{
|
||||
return $this->assertPermission('director/scheduled-downtimes');
|
||||
}
|
||||
|
||||
protected function checkDirectorPermissions()
|
||||
{
|
||||
$this->assertPermission('director/scheduled-downtimes');
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class SchemaController extends ActionController
|
||||
return file_get_contents(
|
||||
sprintf(
|
||||
'%s/schema/%s.sql',
|
||||
$this->Module()->getBaseDir(),
|
||||
$this->Module()->getBasedir(),
|
||||
$type
|
||||
)
|
||||
);
|
||||
|
@ -194,7 +194,7 @@ class SelfServiceController extends ActionController
|
||||
} else {
|
||||
throw new ProgrammingError(
|
||||
'Expected boolean value, got %s',
|
||||
var_export($value, true)
|
||||
var_export($value, 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -275,7 +275,7 @@ class SelfServiceController extends ActionController
|
||||
// PluginsUrl => framework_plugins_url
|
||||
];
|
||||
$username = $settings->get('self-service/icinga_service_user');
|
||||
if ($username) {
|
||||
if (strlen($username)) {
|
||||
$params['icinga_service_user'] = $username;
|
||||
}
|
||||
|
||||
@ -397,14 +397,14 @@ class SelfServiceController extends ActionController
|
||||
$params['parent_zone'] = $zoneName;
|
||||
$params['ca_server'] = $master->getObjectName();
|
||||
$params['parent_endpoints'] = $endpointNames;
|
||||
$params['accept_config'] = $host->getSingleResolvedProperty('accept_config') === 'y';
|
||||
$params['accept_config'] = $host->getSingleResolvedProperty('accept_config')=== 'y';
|
||||
}
|
||||
|
||||
protected function addStringSettingsToParams(Settings $settings, array $keys, array &$params)
|
||||
{
|
||||
foreach ($keys as $key) {
|
||||
$value = $settings->get("self-service/$key");
|
||||
if ($value) {
|
||||
if (strlen($value)) {
|
||||
$params[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,9 @@
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
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\Objects\IcingaObject;
|
||||
use Icinga\Module\Director\Web\Controller\ObjectController;
|
||||
use Icinga\Module\Director\Objects\IcingaServiceSet;
|
||||
use Icinga\Module\Director\Objects\IcingaService;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
|
||||
@ -29,79 +25,64 @@ class ServiceController extends ObjectController
|
||||
|
||||
protected function checkDirectorPermissions()
|
||||
{
|
||||
if (
|
||||
$this->host
|
||||
&& $this->object
|
||||
&& $this->backend()->canModifyService($this->host->getObjectName(), $this->object->getObjectName())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->assertPermission(Permission::HOSTS);
|
||||
$this->assertPermission('director/hosts');
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
// This happens in parent::init() too, but is required to take place before the next two lines
|
||||
$this->enableStaticObjectLoader($this->getTableName());
|
||||
|
||||
// Hint: having Host and Set loaded first is important for UUID lookups with legacy URLs
|
||||
$this->host = $this->getOptionalRelatedObjectFromParams('host', 'host');
|
||||
$this->set = $this->getOptionalRelatedObjectFromParams('service_set', 'set');
|
||||
if ($host = $this->params->get('host')) {
|
||||
$this->host = IcingaHost::load($host, $this->db());
|
||||
} elseif ($hostId = $this->params->get('host_id')) {
|
||||
$this->host = IcingaHost::loadWithAutoIncId($hostId, $this->db());
|
||||
} elseif ($set = $this->params->get('set')) {
|
||||
$this->set = IcingaServiceSet::load(['object_name' => $set], $this->db());
|
||||
} elseif ($apply = $this->params->get('apply')) {
|
||||
$this->apply = IcingaService::load(
|
||||
['object_name' => $apply, 'object_type' => 'template'],
|
||||
$this->db()
|
||||
);
|
||||
}
|
||||
parent::init();
|
||||
$this->addOptionalHostTabs();
|
||||
$this->addOptionalSetTabs();
|
||||
}
|
||||
|
||||
protected function getOptionalRelatedObjectFromParams($type, $parameter)
|
||||
{
|
||||
if ($id = $this->params->get("{$parameter}_id")) {
|
||||
$key = (int) $id;
|
||||
} else {
|
||||
$key = $this->params->get($parameter);
|
||||
if ($this->host) {
|
||||
$hostname = $this->host->getObjectName();
|
||||
$tabs = new Tabs();
|
||||
$tabs->add('host', [
|
||||
'url' => 'director/host',
|
||||
'urlParams' => ['name' => $hostname],
|
||||
'label' => $this->translate('Host'),
|
||||
])->add('services', [
|
||||
'url' => 'director/host/services',
|
||||
'urlParams' => ['name' => $hostname],
|
||||
'label' => $this->translate('Services'),
|
||||
]);
|
||||
|
||||
$this->addParamToTabs('host', $hostname);
|
||||
$this->controls()->prependTabs($tabs);
|
||||
}
|
||||
if ($key !== null) {
|
||||
$table = DbObjectTypeRegistry::tableNameByType($type);
|
||||
$key = UuidLookup::findUuidForKey($key, $table, $this->db(), $this->getBranch());
|
||||
return $this->loadSpecificObject($table, $key);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function loadOptionalObject(): void
|
||||
{
|
||||
parent::loadOptionalObject();
|
||||
|
||||
if ($this->object) {
|
||||
if ($this->host === null) {
|
||||
$this->host = $this->loadOptionalRelatedObject($this->object, 'host');
|
||||
}
|
||||
if ($this->set === null) {
|
||||
$this->set = $this->loadOptionalRelatedObject($this->object, 'service_set');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function loadOptionalRelatedObject(IcingaObject $object, $relation)
|
||||
{
|
||||
$key = $object->getUnresolvedRelated($relation);
|
||||
if ($key === null) {
|
||||
if ($key = $object->get("{$relation}_id")) {
|
||||
$key = (int) $key;
|
||||
} else {
|
||||
$key = $object->get($relation);
|
||||
// We reach this when accessing Service Template Fields
|
||||
if (! $this->set && $this->object->get('service_set_id')) {
|
||||
$this->set = $this->object->getRelated('service_set');
|
||||
}
|
||||
}
|
||||
|
||||
if ($key === null) {
|
||||
return null;
|
||||
}
|
||||
if ($this->set) {
|
||||
$setName = $this->set->getObjectName();
|
||||
$tabs = new Tabs();
|
||||
$tabs->add('set', [
|
||||
'url' => 'director/serviceset',
|
||||
'urlParams' => ['name' => $setName],
|
||||
'label' => $this->translate('ServiceSet'),
|
||||
])->add('services', [
|
||||
'url' => 'director/serviceset/services',
|
||||
'urlParams' => ['name' => $setName],
|
||||
'label' => $this->translate('Services'),
|
||||
]);
|
||||
|
||||
$table = DbObjectTypeRegistry::tableNameByType($relation);
|
||||
$uuid = UuidLookup::findUuidForKey($key, $table, $this->db(), $this->getBranch());
|
||||
return $this->loadSpecificObject($table, $uuid);
|
||||
$this->addParamToTabs('serviceset', $setName);
|
||||
$this->controls()->prependTabs($tabs);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addParamToTabs($name, $value)
|
||||
@ -118,7 +99,6 @@ class ServiceController extends ObjectController
|
||||
{
|
||||
parent::addAction();
|
||||
if ($this->host) {
|
||||
// TODO: use setTitle. And figure out, where we use this old route.
|
||||
$this->view->title = $this->host->object_name . ': ' . $this->view->title;
|
||||
} elseif ($this->set) {
|
||||
$this->view->title = sprintf(
|
||||
@ -151,23 +131,18 @@ class ServiceController extends ObjectController
|
||||
/** @var IcingaService $object */
|
||||
$object = $this->object;
|
||||
$this->addTitle($object->getObjectName());
|
||||
if ($object->isTemplate() && $this->showNotInBranch($this->translate('Modifying Templates'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form = IcingaServiceForm::load()->setDb($this->db());
|
||||
$form->setBranch($this->getBranch());
|
||||
|
||||
if ($this->host) {
|
||||
$this->actions()->add(Link::create(
|
||||
$this->translate('back'),
|
||||
'director/host/services',
|
||||
['uuid' => $this->host->getUniqueId()->toString()],
|
||||
['name' => $this->host->getObjectName()],
|
||||
['class' => 'icon-left-big']
|
||||
));
|
||||
$form->setHost($this->host);
|
||||
}
|
||||
|
||||
$form = IcingaServiceForm::load()->setDb($this->db());
|
||||
|
||||
if ($this->set) {
|
||||
$form->setServiceSet($this->set);
|
||||
}
|
||||
@ -197,8 +172,7 @@ class ServiceController extends ObjectController
|
||||
}
|
||||
|
||||
try {
|
||||
if (
|
||||
$object->isTemplate()
|
||||
if ($object->isTemplate()
|
||||
&& $object->getResolvedProperty('check_command_id')
|
||||
) {
|
||||
$this->view->actionLinks .= ' ' . $this->view->qlink(
|
||||
@ -239,81 +213,33 @@ class ServiceController extends ObjectController
|
||||
$this->content()->add($table);
|
||||
}
|
||||
|
||||
protected function getLegacyKey()
|
||||
{
|
||||
if ($key = $this->params->get('id')) {
|
||||
$key = (int) $key;
|
||||
} else {
|
||||
$key = $this->params->get('name');
|
||||
}
|
||||
|
||||
if ($key === null) {
|
||||
throw new \InvalidArgumentException('uuid, name or id required');
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
protected function loadObject()
|
||||
{
|
||||
if ($this->params->has('uuid')) {
|
||||
parent::loadObject();
|
||||
return;
|
||||
}
|
||||
if ($this->object === null) {
|
||||
if ($id = $this->params->get('id')) {
|
||||
$this->object = IcingaService::loadWithAutoIncId(
|
||||
(int) $id,
|
||||
$this->db()
|
||||
);
|
||||
} elseif ($name = $this->params->get('name')) {
|
||||
$params = array('object_name' => $name);
|
||||
$db = $this->db();
|
||||
|
||||
$key = $this->getLegacyKey();
|
||||
// Hint: not passing 'object' as type, we still have name-based links in previews and similar
|
||||
$uuid = UuidLookup::findServiceUuid($this->db(), $this->getBranch(), null, $key, $this->host, $this->set);
|
||||
if ($uuid === null) {
|
||||
if (! $this->params->get('allowOverrides')) {
|
||||
throw new NotFoundError('Not found');
|
||||
if ($this->host) {
|
||||
// $this->view->host = $this->host;
|
||||
$params['host_id'] = $this->host->id;
|
||||
}
|
||||
|
||||
if ($this->set) {
|
||||
// $this->view->set = $this->set;
|
||||
$params['service_set_id'] = $this->set->id;
|
||||
}
|
||||
$this->object = IcingaService::load($params, $db);
|
||||
} else {
|
||||
parent::loadObject();
|
||||
}
|
||||
} else {
|
||||
$this->params->set('uuid', $uuid->toString());
|
||||
parent::loadObject();
|
||||
}
|
||||
}
|
||||
|
||||
protected function addOptionalHostTabs()
|
||||
{
|
||||
if ($this->host === null) {
|
||||
return;
|
||||
}
|
||||
$hostname = $this->host->getObjectName();
|
||||
$tabs = new Tabs();
|
||||
$urlParams = ['uuid' => $this->host->getUniqueId()->toString()];
|
||||
$tabs->add('host', [
|
||||
'url' => 'director/host',
|
||||
'urlParams' => $urlParams,
|
||||
'label' => $this->translate('Host'),
|
||||
])->add('services', [
|
||||
'url' => 'director/host/services',
|
||||
'urlParams' => $urlParams,
|
||||
'label' => $this->translate('Services'),
|
||||
]);
|
||||
|
||||
$this->addParamToTabs('host', $hostname);
|
||||
$this->controls()->prependTabs($tabs);
|
||||
}
|
||||
|
||||
protected function addOptionalSetTabs()
|
||||
{
|
||||
if ($this->set === null) {
|
||||
return;
|
||||
}
|
||||
$setName = $this->set->getObjectName();
|
||||
$tabs = new Tabs();
|
||||
$tabs->add('set', [
|
||||
'url' => 'director/serviceset',
|
||||
'urlParams' => ['name' => $setName],
|
||||
'label' => $this->translate('ServiceSet'),
|
||||
])->add('services', [
|
||||
'url' => 'director/serviceset/services',
|
||||
'urlParams' => ['name' => $setName],
|
||||
'label' => $this->translate('Services'),
|
||||
]);
|
||||
|
||||
$this->addParamToTabs('serviceset', $setName);
|
||||
$this->controls()->prependTabs($tabs);
|
||||
return $this->object;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Icinga\Data\Filter\Filter;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Module\Director\Forms\IcingaServiceSetForm;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Objects\IcingaServiceSet;
|
||||
@ -72,9 +71,7 @@ class ServicesetController extends ObjectController
|
||||
['class' => 'icon-plus']
|
||||
));
|
||||
|
||||
IcingaServiceSetServiceTable::load($set)
|
||||
->setBranch($this->getBranch())
|
||||
->renderTo($this);
|
||||
IcingaServiceSetServiceTable::load($set)->renderTo($this);
|
||||
}
|
||||
|
||||
public function hostsAction()
|
||||
@ -92,7 +89,7 @@ class ServicesetController extends ObjectController
|
||||
$table->renderTo($this);
|
||||
}
|
||||
$filter = $set->get('assign_filter');
|
||||
if ($filter !== null && \strlen($filter) > 0) {
|
||||
if (\strlen($filter) > 0) {
|
||||
$this->content()->add(
|
||||
IcingaHostsMatchingFilterTable::load(Filter::fromQueryString($filter), $this->db())
|
||||
);
|
||||
@ -101,19 +98,15 @@ class ServicesetController extends ObjectController
|
||||
|
||||
protected function addServiceSetTabs()
|
||||
{
|
||||
$hexUuid = $this->object->getUniqueId()->toString();
|
||||
$tabs = $this->tabs();
|
||||
$name = $this->object->getObjectName();
|
||||
$tabs->add('services', [
|
||||
'url' => 'director/serviceset/services',
|
||||
'urlParams' => ['uuid' => $hexUuid],
|
||||
'urlParams' => ['name' => $name],
|
||||
'label' => 'Services'
|
||||
]);
|
||||
if ($this->branch->isBranch()) {
|
||||
return $this;
|
||||
}
|
||||
$tabs->add('hosts', [
|
||||
])->add('hosts', [
|
||||
'url' => 'director/serviceset/hosts',
|
||||
'urlParams' => ['uuid' => $hexUuid],
|
||||
'urlParams' => ['name' => $name],
|
||||
'label' => 'Hosts'
|
||||
]);
|
||||
|
||||
@ -137,10 +130,6 @@ class ServicesetController extends ObjectController
|
||||
}
|
||||
}
|
||||
|
||||
if (! $this->allowsObject($this->object)) {
|
||||
throw new NotFoundError('No such object available');
|
||||
}
|
||||
|
||||
return $this->object;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Icinga\Module\Director\Restriction\HostgroupRestriction;
|
||||
use ipl\Html\Html;
|
||||
use Icinga\Exception\NotFoundError;
|
||||
use Icinga\Module\Director\Hook\ImportSourceHook;
|
||||
@ -109,8 +108,6 @@ class SuggestController extends ActionController
|
||||
if ($type !== null) {
|
||||
$query->where('object_type = ?', $type);
|
||||
}
|
||||
$restriction = new HostgroupRestriction($this->db(), $this->Auth());
|
||||
$restriction->filterHostsQuery($query);
|
||||
|
||||
return $db->fetchCol($query);
|
||||
}
|
||||
@ -122,7 +119,7 @@ class SuggestController extends ActionController
|
||||
|
||||
protected function suggestServicenames()
|
||||
{
|
||||
$r = array();
|
||||
$r=array();
|
||||
$this->assertPermission('director/services');
|
||||
$db = $this->db()->getDbAdapter();
|
||||
$for_host = $this->getRequest()->getPost('for_host');
|
||||
@ -152,7 +149,7 @@ class SuggestController extends ActionController
|
||||
$matcher = HostApplyMatches::prepare($tmp_host);
|
||||
foreach ($this->getAllApplyRules() as $rule) {
|
||||
if ($matcher->matchesFilter($rule->filter)) { //TODO
|
||||
$r[] = $rule->name;
|
||||
$r[]=$rule->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -291,7 +288,7 @@ class SuggestController extends ActionController
|
||||
$db = $this->db()->getDbAdapter();
|
||||
|
||||
$query = $db->select()
|
||||
->from(['f' => 'director_datafield'], [])
|
||||
->from(['f' =>'director_datafield'], [])
|
||||
->join(
|
||||
['sid' => 'director_datafield_setting'],
|
||||
'sid.datafield_id = f.id AND sid.setting_name = \'datalist_id\'',
|
||||
@ -369,7 +366,7 @@ class SuggestController extends ActionController
|
||||
|
||||
protected function getAllApplyRules()
|
||||
{
|
||||
$allApplyRules = $this->fetchAllApplyRules();
|
||||
$allApplyRules=$this->fetchAllApplyRules();
|
||||
foreach ($allApplyRules as $rule) {
|
||||
$rule->filter = Filter::fromQueryString($rule->assign_filter);
|
||||
}
|
||||
|
@ -2,18 +2,10 @@
|
||||
|
||||
namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use gipfl\Diff\HtmlRenderer\SideBySideDiff;
|
||||
use gipfl\Diff\PhpDiff;
|
||||
use gipfl\IcingaWeb2\Link;
|
||||
use gipfl\Web\Widget\Hint;
|
||||
use Icinga\Date\DateFormatter;
|
||||
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\Web\Controller\BranchHelper;
|
||||
use Icinga\Module\Director\Web\Form\ClickHereForm;
|
||||
use Icinga\Module\Director\Web\Table\BranchActivityTable;
|
||||
use Icinga\Module\Director\Web\Widget\IcingaConfigDiff;
|
||||
use Icinga\Module\Director\Web\Widget\UnorderedList;
|
||||
use Icinga\Module\Director\Db\Cache\PrefetchCache;
|
||||
use Icinga\Module\Director\DirectorObject\Automation\ExportInterface;
|
||||
@ -35,38 +27,25 @@ use Icinga\Module\Director\Web\Table\SyncpropertyTable;
|
||||
use Icinga\Module\Director\Web\Table\SyncRunTable;
|
||||
use Icinga\Module\Director\Web\Tabs\SyncRuleTabs;
|
||||
use Icinga\Module\Director\Web\Widget\SyncRunDetails;
|
||||
use Icinga\Web\Notification;
|
||||
use ipl\Html\Form;
|
||||
use ipl\Html\Html;
|
||||
use ipl\Html\ValidHtml;
|
||||
|
||||
class SyncruleController extends ActionController
|
||||
{
|
||||
use BranchHelper;
|
||||
|
||||
/**
|
||||
* @throws \Icinga\Exception\NotFoundError
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$this->setAutorefreshInterval(10);
|
||||
$this->setAutoRefreshInterval(10);
|
||||
$rule = $this->requireSyncRule();
|
||||
$this->tabs(new SyncRuleTabs($rule))->activate('show');
|
||||
$ruleName = $rule->get('rule_name');
|
||||
$this->addTitle($this->translate('Sync rule: %s'), $ruleName);
|
||||
|
||||
$checkForm = SyncCheckForm::load()->setSyncRule($rule)->handleRequest();
|
||||
$store = new DbObjectStore($this->db(), $this->getBranch());
|
||||
$runForm = new SyncRunForm($rule, $store);
|
||||
$runForm->on(SyncRunForm::ON_SUCCESS, function (SyncRunForm $form) {
|
||||
$message = $form->getSuccessMessage();
|
||||
if ($message === null) {
|
||||
Notification::error($this->translate('Synchronization failed'));
|
||||
} else {
|
||||
Notification::success($message);
|
||||
}
|
||||
$this->redirectNow($this->url());
|
||||
});
|
||||
$runForm->handleRequest($this->getServerRequest());
|
||||
$runForm = SyncRunForm::load()->setSyncRule($rule)->handleRequest();
|
||||
|
||||
if ($lastRunId = $rule->getLastSyncRunId()) {
|
||||
$run = SyncRun::load($lastRunId, $this->db());
|
||||
@ -94,7 +73,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 be in Sync at %s.'),
|
||||
$this->translate('This Sync Rule was last found to by in Sync at %s.'),
|
||||
$rule->get('last_attempt')
|
||||
)));
|
||||
/*
|
||||
@ -121,15 +100,6 @@ class SyncruleController extends ActionController
|
||||
}
|
||||
|
||||
$c->add($checkForm);
|
||||
if ($this->hasBranch()) {
|
||||
$objectType = $rule->get('object_type');
|
||||
$table = DbObjectTypeRegistry::tableNameByType($objectType);
|
||||
if (! BranchSupport::existsForTableName($table)) {
|
||||
$this->showNotInBranch(sprintf($this->translate("Synchronizing '%s'"), $objectType));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$c->add($runForm);
|
||||
|
||||
if ($run) {
|
||||
@ -174,97 +144,31 @@ class SyncruleController extends ActionController
|
||||
public function previewAction()
|
||||
{
|
||||
$rule = $this->requireSyncRule();
|
||||
$branchSupport = BranchSupport::existsForSyncRule($rule);
|
||||
$branchStore = new BranchStore($this->db());
|
||||
$owner = $this->getAuth()->getUser()->getUsername();
|
||||
if ($branchSupport) {
|
||||
if ($this->getBranch()->isBranch()) {
|
||||
$tmpBranchName = sprintf(
|
||||
'%s/%s-%s',
|
||||
Branch::PREFIX_SYNC_PREVIEW,
|
||||
$this->getBranch()->getUuid()->toString(),
|
||||
$rule->get('id')
|
||||
);
|
||||
// We could keep changes for preview on branch too
|
||||
$branchStore->deleteByName($tmpBranchName);
|
||||
$tmpBranch = $branchStore->cloneBranchForSync($this->getBranch(), $tmpBranchName, $owner);
|
||||
$after = 1600000000; // a date in 2020, minus 10000000
|
||||
} else {
|
||||
$tmpBranchName = Branch::PREFIX_SYNC_PREVIEW . '/' . $rule->get('id');
|
||||
$tmpBranch = $branchStore->fetchOrCreateByName($tmpBranchName, $owner);
|
||||
$after = null;
|
||||
}
|
||||
$store = new DbObjectStore($this->db(), $tmpBranch);
|
||||
} else {
|
||||
$tmpBranch = $store = null;
|
||||
}
|
||||
|
||||
// $rule->set('update_policy', 'replace');
|
||||
$this->tabs(new SyncRuleTabs($rule))->activate('preview');
|
||||
$this->addTitle($this->translate('Sync Preview'));
|
||||
$sync = new Sync($rule, $store);
|
||||
$keepBranchPreview = false;
|
||||
if ($tmpBranch) {
|
||||
if ($lastTime = $branchStore->getLastActivityTime($tmpBranch, $after)) {
|
||||
if ((time() - $lastTime) > 100) {
|
||||
$branchStore->wipeBranch($tmpBranch, $after);
|
||||
} else {
|
||||
$here = (new ClickHereForm())->handleRequest($this->getServerRequest());
|
||||
if ($here->hasBeenClicked()) {
|
||||
$branchStore->wipeBranch($tmpBranch, $after);
|
||||
$this->redirectNow($this->url());
|
||||
} else {
|
||||
$keepBranchPreview = true;
|
||||
}
|
||||
$this->content()->add(Hint::info(Html::sprintf(
|
||||
$this->translate('This preview has been generated %s, please click %s to regenerate it'),
|
||||
DateFormatter::timeAgo($lastTime),
|
||||
$here
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$keepBranchPreview) {
|
||||
$this->addTitle('Sync Preview');
|
||||
$sync = new Sync($rule);
|
||||
try {
|
||||
$modifications = $sync->getExpectedModifications();
|
||||
} catch (\Exception $e) {
|
||||
$this->content()->add(Hint::error($e->getMessage()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($tmpBranch) {
|
||||
try {
|
||||
if (!$keepBranchPreview) {
|
||||
$sync->apply();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->content()->add(Hint::error($e->getMessage()));
|
||||
return;
|
||||
}
|
||||
if (empty($modifications)) {
|
||||
$this->content()->add(Hint::ok($this->translate(
|
||||
'This Sync Rule is in sync and would currently not apply any changes'
|
||||
)));
|
||||
|
||||
$changes = new BranchActivityTable($tmpBranch->getUuid(), $this->db());
|
||||
$changes->disableObjectLink();
|
||||
if (count($changes) === 0) {
|
||||
$this->showInSync();
|
||||
}
|
||||
$changes->renderTo($this);
|
||||
} else {
|
||||
if (empty($modifications)) {
|
||||
$this->showInSync();
|
||||
return;
|
||||
}
|
||||
$this->showExpectedModificationSummary($modifications);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function showInSync()
|
||||
{
|
||||
$this->content()->add(Hint::ok($this->translate(
|
||||
'This Sync Rule is in sync and would currently not apply any changes'
|
||||
)));
|
||||
}
|
||||
|
||||
protected function showExpectedModificationSummary($modifications)
|
||||
{
|
||||
$create = [];
|
||||
$modify = [];
|
||||
$delete = [];
|
||||
$modifiedProperties = [];
|
||||
|
||||
/** @var IcingaObject $object */
|
||||
foreach ($modifications as $object) {
|
||||
if ($object->hasBeenLoadedFromDb()) {
|
||||
@ -380,7 +284,10 @@ class SyncruleController extends ActionController
|
||||
protected function firstNames($objects, $max = 50)
|
||||
{
|
||||
$names = [];
|
||||
$list = new UnorderedList([], ['class' => 'unordred-list']);
|
||||
$list = new UnorderedList();
|
||||
$list->addAttributes([
|
||||
'style' => 'list-style-type: none; marign: 0; padding: 0',
|
||||
]);
|
||||
$total = count($objects);
|
||||
$i = 0;
|
||||
PrefetchCache::forget();
|
||||
@ -402,7 +309,7 @@ class SyncruleController extends ActionController
|
||||
$cfgOld = new IcingaConfig($this->db());
|
||||
$oldObject->renderToConfig($cfgOld);
|
||||
$object->renderToConfig($cfgNew);
|
||||
foreach (IcingaConfigDiff::getDiffs($cfgOld, $cfgNew) as $file => $diff) {
|
||||
foreach ($this->getConfigDiffs($cfgOld, $cfgNew) as $file => $diff) {
|
||||
$names[$name . '___PRETITLE___' . $file] = Html::tag('h3', $file);
|
||||
$names[$name . '___PREVIEW___' . $file] = $diff;
|
||||
}
|
||||
@ -427,7 +334,7 @@ class SyncruleController extends ActionController
|
||||
$cfgOld = new IcingaConfig($this->db());
|
||||
$oldObject->renderToConfig($cfgOld);
|
||||
$object->renderToConfig($cfgNew);
|
||||
foreach (IcingaConfigDiff::getDiffs($cfgOld, $cfgNew) as $file => $diff) {
|
||||
foreach ($this->getConfigDiffs($cfgOld, $cfgNew) as $file => $diff) {
|
||||
$names[$name . '___PRETITLE___' . $file] = Html::tag('h3', $file);
|
||||
$names[$name . '___PREVIEW___' . $file] = $diff;
|
||||
}
|
||||
@ -457,11 +364,48 @@ class SyncruleController extends ActionController
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stolen from elsewhere, should be de-duplicated
|
||||
*
|
||||
* @param IcingaConfig $oldConfig
|
||||
* @param IcingaConfig $newConfig
|
||||
* @return ValidHtml[]
|
||||
*/
|
||||
protected function getConfigDiffs(IcingaConfig $oldConfig, IcingaConfig $newConfig)
|
||||
{
|
||||
$oldFileNames = $oldConfig->getFileNames();
|
||||
$newFileNames = $newConfig->getFileNames();
|
||||
|
||||
$fileNames = array_merge($oldFileNames, $newFileNames);
|
||||
|
||||
$diffs = [];
|
||||
foreach ($fileNames as $filename) {
|
||||
if (in_array($filename, $oldFileNames)) {
|
||||
$left = $oldConfig->getFile($filename)->getContent();
|
||||
} else {
|
||||
$left = '';
|
||||
}
|
||||
|
||||
if (in_array($filename, $newFileNames)) {
|
||||
$right = $newConfig->getFile($filename)->getContent();
|
||||
} else {
|
||||
$right = '';
|
||||
}
|
||||
if ($left === $right) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$diffs[$filename] = new SideBySideDiff(new PhpDiff($left, $right));
|
||||
}
|
||||
|
||||
return $diffs;
|
||||
}
|
||||
|
||||
protected function listModifiedProperties($properties)
|
||||
{
|
||||
$list = new UnorderedList();
|
||||
foreach ($properties as $property => $cnt) {
|
||||
$list->addItem("{$cnt}x $property");
|
||||
$list->addItem("${cnt}x $property");
|
||||
}
|
||||
|
||||
return $list;
|
||||
@ -511,15 +455,9 @@ class SyncruleController extends ActionController
|
||||
if (! $rule->hasSyncProperties()) {
|
||||
$this->addPropertyHint($rule);
|
||||
}
|
||||
if ($this->showNotInBranch($this->translate('Modifying Sync Rules'))) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$this->addTitle($this->translate('Add sync rule'));
|
||||
$this->tabs(new SyncRuleTabs())->activate('add');
|
||||
if ($this->showNotInBranch($this->translate('Creating Sync Rules'))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$form->handleRequest();
|
||||
@ -552,9 +490,6 @@ class SyncruleController extends ActionController
|
||||
['class' => 'icon-paste']
|
||||
)
|
||||
);
|
||||
if ($this->showNotInBranch($this->translate('Cloning Sync Rules'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$form = new CloneSyncRuleForm($rule);
|
||||
$this->content()->add($form);
|
||||
@ -603,13 +538,6 @@ class SyncruleController extends ActionController
|
||||
$ruleId = (int) $rule->get('id');
|
||||
|
||||
$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']
|
||||
));
|
||||
if ($id = $this->params->get('id')) {
|
||||
$form->loadObject((int) $id);
|
||||
$this->addTitle(
|
||||
@ -617,21 +545,24 @@ class SyncruleController extends ActionController
|
||||
$form->getObject()->get('destination_field'),
|
||||
$rule->get('rule_name')
|
||||
);
|
||||
if ($this->showNotInBranch($this->translate('Modifying Sync Rules'))) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$this->addTitle(
|
||||
$this->translate('Add sync property: %s'),
|
||||
$rule->get('rule_name')
|
||||
);
|
||||
if ($this->showNotInBranch($this->translate('Modifying Sync Rules'))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$form->setRule($rule);
|
||||
$form->setSuccessUrl('director/syncrule/property', ['rule_id' => $ruleId]);
|
||||
|
||||
$this->actions()->add(new Link(
|
||||
$this->translate('back'),
|
||||
'director/syncrule/property',
|
||||
['rule_id' => $ruleId],
|
||||
['class' => 'icon-left-big']
|
||||
));
|
||||
|
||||
$this->content()->add($form->handleRequest());
|
||||
$this->tabs(new SyncRuleTabs($rule))->activate('property');
|
||||
SyncpropertyTable::create($rule)
|
||||
->handleSortPriorityActions($this->getRequest(), $this->getResponse())
|
||||
->renderTo($this);
|
||||
@ -642,7 +573,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'));
|
||||
@ -651,7 +582,7 @@ class SyncruleController extends ActionController
|
||||
$run = SyncRun::load($runId, $this->db());
|
||||
$this->content()->add(new SyncRunDetails($run));
|
||||
}
|
||||
(new SyncRunTable($rule))->renderTo($this);
|
||||
SyncRunTable::create($rule)->renderTo($this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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'
|
||||
|
@ -4,12 +4,9 @@ namespace Icinga\Module\Director\Controllers;
|
||||
|
||||
use Icinga\Module\Director\Forms\IcingaTemplateChoiceForm;
|
||||
use Icinga\Module\Director\Web\Controller\ActionController;
|
||||
use Icinga\Module\Director\Web\Controller\BranchHelper;
|
||||
|
||||
class TemplatechoiceController extends ActionController
|
||||
{
|
||||
use BranchHelper;
|
||||
|
||||
protected function checkDirectorPermissions()
|
||||
{
|
||||
$this->assertPermission('director/admin');
|
||||
@ -27,15 +24,12 @@ class TemplatechoiceController extends ActionController
|
||||
|
||||
protected function prepare($type, $title)
|
||||
{
|
||||
$this->addSingleTab('Choice')
|
||||
->addTitle($title);
|
||||
$form = IcingaTemplateChoiceForm::create($type, $this->db())
|
||||
->optionallyLoad($this->params->get('name'))
|
||||
->setListUrl("director/templatechoices/$type")
|
||||
->handleRequest();
|
||||
if ($this->showNotInBranch($this->translate('Modifying Template Choices'))) {
|
||||
return;
|
||||
}
|
||||
$this->content()->add($form);
|
||||
$this->addSingleTab('Choice')
|
||||
->addTitle($title)
|
||||
->content()->add($form);
|
||||
}
|
||||
}
|
||||
|
@ -30,9 +30,4 @@ class TimeperiodController extends ObjectController
|
||||
$this->content()->add($form->handleRequest());
|
||||
IcingaTimePeriodRangeTable::load($object)->renderTo($this);
|
||||
}
|
||||
|
||||
protected function hasBasketSupport()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,4 @@ class UserController extends ObjectController
|
||||
{
|
||||
$this->assertPermission('director/users');
|
||||
}
|
||||
|
||||
protected function hasBasketSupport()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ use Icinga\Module\Director\Web\Form\DirectorForm;
|
||||
|
||||
class AddToBasketForm extends DirectorForm
|
||||
{
|
||||
/** @var Basket */
|
||||
private $basket;
|
||||
|
||||
private $type = '(has not been set)';
|
||||
|
||||
private $names = [];
|
||||
@ -27,6 +30,7 @@ class AddToBasketForm extends DirectorForm
|
||||
'b' => 'basket_name',
|
||||
])->order('basket_name'));
|
||||
|
||||
$names = [];
|
||||
$basket = null;
|
||||
if ($this->hasBeenSent()) {
|
||||
$basketName = $this->getSentValue('basket');
|
||||
@ -34,17 +38,25 @@ class AddToBasketForm extends DirectorForm
|
||||
$basket = Basket::load($basketName, $this->getDb());
|
||||
}
|
||||
}
|
||||
|
||||
$names = [];
|
||||
$count = 0;
|
||||
$type = $this->type;
|
||||
foreach ($this->names as $name) {
|
||||
if (! $basket || ! $basket->hasObject($this->type, $name)) {
|
||||
if (! empty($names)) {
|
||||
$names[] = ', ';
|
||||
}
|
||||
if ($basket && $basket->hasObject($type, $name)) {
|
||||
$names[] = Html::tag('span', [
|
||||
'style' => 'text-decoration: line-through'
|
||||
], $name);
|
||||
} else {
|
||||
$count++;
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
$this->addHtmlHint(
|
||||
(new HtmlDocument())
|
||||
->add(sprintf('The following objects will be added: %s', implode(", ", $names)))
|
||||
);
|
||||
$this->addHtmlHint((new HtmlDocument())->add([
|
||||
'The following objects will be added: ',
|
||||
$names
|
||||
]));
|
||||
$this->addElement('select', 'basket', [
|
||||
'label' => $this->translate('Basket'),
|
||||
'multiOptions' => $this->optionalEnum($enum),
|
||||
@ -52,10 +64,10 @@ class AddToBasketForm extends DirectorForm
|
||||
'class' => 'autosubmit',
|
||||
]);
|
||||
|
||||
if (! empty($names)) {
|
||||
if ($count > 0) {
|
||||
$this->setSubmitLabel(sprintf(
|
||||
$this->translate('Add %s objects'),
|
||||
count($names)
|
||||
$count
|
||||
));
|
||||
} else {
|
||||
$this->setSubmitLabel($this->translate('Add'));
|
||||
@ -100,18 +112,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;
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,6 @@ class BasketForm extends DirectorObjectForm
|
||||
'IcingaTemplateChoiceService' => $this->translate('Service Template Choice'),
|
||||
'ServiceTemplate' => $this->translate('Service Templates'),
|
||||
'ServiceSet' => $this->translate('Service Sets'),
|
||||
'UserGroup' => $this->translate('User Groups'),
|
||||
'UserTemplate' => $this->translate('User Templates'),
|
||||
'User' => $this->translate('Users'),
|
||||
'NotificationTemplate' => $this->translate('Notification Templates'),
|
||||
'Notification' => $this->translate('Notifications'),
|
||||
'TimePeriod' => $this->translate('Time Periods'),
|
||||
@ -52,9 +49,9 @@ class BasketForm extends DirectorObjectForm
|
||||
$types = $this->getAvailableTypes();
|
||||
|
||||
$options = [
|
||||
Basket::SELECTION_NONE => $this->translate('Ignore'),
|
||||
Basket::SELECTION_ALL => $this->translate('All of them'),
|
||||
Basket::SELECTION_CUSTOM => $this->translate('Custom Selection'),
|
||||
'IGNORE' => $this->translate('Ignore'),
|
||||
'ALL' => $this->translate('All of them'),
|
||||
'[]' => $this->translate('Custom Selection'),
|
||||
];
|
||||
|
||||
$this->addHtmlHint($this->translate(
|
||||
@ -92,13 +89,13 @@ class BasketForm extends DirectorObjectForm
|
||||
/** @var Basket $object */
|
||||
$values = [];
|
||||
foreach ($this->getAvailableTypes() as $type => $label) {
|
||||
$values[$type] = Basket::SELECTION_NONE;
|
||||
$values[$type] = 'IGNORE';
|
||||
}
|
||||
foreach ($object->getChosenObjects() as $type => $selection) {
|
||||
if ($selection === true) {
|
||||
$values[$type] = Basket::SELECTION_ALL;
|
||||
$values[$type] = 'ALL';
|
||||
} elseif (is_array($selection)) {
|
||||
$values[$type] = Basket::SELECTION_CUSTOM;
|
||||
$values[$type] = '[]';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,12 +25,10 @@ class BasketUploadForm extends DirectorObjectForm
|
||||
*/
|
||||
public function setup()
|
||||
{
|
||||
if ($this->object === null) {
|
||||
$this->addElement('text', 'basket_name', [
|
||||
'label' => $this->translate('Basket Name'),
|
||||
'required' => true,
|
||||
]);
|
||||
}
|
||||
$this->addElement('text', 'basket_name', [
|
||||
'label' => $this->translate('Basket Name'),
|
||||
'required' => true,
|
||||
]);
|
||||
$this->setAttrib('enctype', 'multipart/form-data');
|
||||
|
||||
$this->addElement('file', 'uploaded_file', [
|
||||
@ -55,6 +53,16 @@ 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
|
||||
@ -65,8 +73,7 @@ class BasketUploadForm extends DirectorObjectForm
|
||||
throw new IcingaException('Got no file');
|
||||
}
|
||||
|
||||
if (
|
||||
! isset($_FILES['uploaded_file']['tmp_name'])
|
||||
if (! isset($_FILES['uploaded_file']['tmp_name'])
|
||||
|| ! is_uploaded_file($_FILES['uploaded_file']['tmp_name'])
|
||||
) {
|
||||
$this->addError('Got no uploaded file');
|
||||
@ -127,17 +134,13 @@ class BasketUploadForm extends DirectorObjectForm
|
||||
|
||||
$basket->set('owner_type', 'user');
|
||||
$basket->set('owner_value', $this->getAuth()->getUser()->getUsername());
|
||||
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);
|
||||
}
|
||||
$basket->store($this->db);
|
||||
|
||||
BasketSnapshot::forBasketFromJson(
|
||||
$basket,
|
||||
$this->rawUpload
|
||||
)->store($this->db);
|
||||
$this->setObjectSuccessUrl();
|
||||
$this->beforeSuccessfulRedirect();
|
||||
$this->redirectOnSuccess($this->translate('Basket has been uploaded'));
|
||||
}
|
||||
|
@ -51,13 +51,11 @@ trait DeployFormsBug7530
|
||||
];
|
||||
|
||||
foreach ($objectTypes as $objectType) {
|
||||
if (
|
||||
(int) $db->fetchOne(
|
||||
$db->select()
|
||||
if ((int) $db->fetchOne(
|
||||
$db->select()
|
||||
->from($objectType, 'COUNT(*)')
|
||||
->where('zone_id IN (?)', $zoneIds)
|
||||
) > 0
|
||||
) {
|
||||
) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -72,8 +70,7 @@ trait DeployFormsBug7530
|
||||
$version = $this->api->getVersion();
|
||||
if ($version === null) {
|
||||
throw new \RuntimeException($this->translate('Unable to detect your Icinga 2 Core version'));
|
||||
} elseif (
|
||||
\version_compare($version, '2.11.0', '>=')
|
||||
} elseif (\version_compare($version, '2.11.0', '>=')
|
||||
&& \version_compare($version, '2.12.0', '<')
|
||||
) {
|
||||
return true;
|
||||
|
@ -4,7 +4,6 @@ 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;
|
||||
@ -83,7 +82,7 @@ class DeploymentLinkForm extends DirectorForm
|
||||
);
|
||||
}
|
||||
|
||||
$this->setAttrib('class', 'gipfl-inline-form');
|
||||
$this->setAttrib('class', 'inline');
|
||||
$this->addHtml(Icon::create('wrench'));
|
||||
try {
|
||||
// As this is shown for single objects, ignore errors caused by an
|
||||
@ -101,7 +100,7 @@ class DeploymentLinkForm extends DirectorForm
|
||||
|
||||
protected function canDeploy()
|
||||
{
|
||||
return $this->auth->hasPermission(Permission::DEPLOY);
|
||||
return $this->auth->hasPermission('director/deploy');
|
||||
}
|
||||
|
||||
public function render(Zend_View_Interface $view = null)
|
||||
@ -157,7 +156,7 @@ class DeploymentLinkForm extends DirectorForm
|
||||
|
||||
protected function deploymentFailed($checksum, $error = null)
|
||||
{
|
||||
$extra = $error ? ': ' . $error : '';
|
||||
$extra = $error ? ': ' . $error: '';
|
||||
|
||||
if ($this->getRequest()->isApiRequest()) {
|
||||
throw new IcingaException('Not yet');
|
||||
|
@ -140,7 +140,8 @@ class DirectorDatafieldForm extends DirectorObjectForm
|
||||
$this->addElement('text', 'varname', array(
|
||||
'label' => $this->translate('Field name'),
|
||||
'description' => $this->translate(
|
||||
'This will be the name of the custom variable in the rendered Icinga configuration.'
|
||||
'The unique name of the field. This will be the name of the custom'
|
||||
. ' variable in the rendered Icinga configuration.'
|
||||
),
|
||||
'required' => true,
|
||||
));
|
||||
@ -165,7 +166,7 @@ class DirectorDatafieldForm extends DirectorObjectForm
|
||||
|
||||
$this->addElement('select', 'category_id', [
|
||||
'label' => $this->translate('Data Field Category'),
|
||||
'multiOptions' => $this->optionalEnum($this->enumCategories()),
|
||||
'multiOptions' => $this->optionalEnum($this->enumCategpories()),
|
||||
]);
|
||||
|
||||
$error = false;
|
||||
@ -175,7 +176,7 @@ class DirectorDatafieldForm extends DirectorObjectForm
|
||||
$error = $e->getMessage();
|
||||
$types = $this->optionalEnum(array());
|
||||
}
|
||||
|
||||
|
||||
$this->addElement('select', 'datatype', array(
|
||||
'label' => $this->translate('Data type'),
|
||||
'description' => $this->translate('Field type'),
|
||||
@ -281,7 +282,7 @@ class DirectorDatafieldForm extends DirectorObjectForm
|
||||
protected function enumDataTypes()
|
||||
{
|
||||
$hooks = Hook::all('Director\\DataType');
|
||||
$enum = [null => $this->translate('- please choose -')];
|
||||
$enum = array(null => '- please choose -');
|
||||
/** @var DataTypeHook $hook */
|
||||
foreach ($hooks as $hook) {
|
||||
$enum[get_class($hook)] = $hook->getName();
|
||||
@ -290,7 +291,7 @@ class DirectorDatafieldForm extends DirectorObjectForm
|
||||
return $enum;
|
||||
}
|
||||
|
||||
protected function enumCategories()
|
||||
protected function enumCategpories()
|
||||
{
|
||||
$db = $this->getDb()->getDbAdapter();
|
||||
return $db->fetchPairs(
|
||||
|
@ -3,7 +3,6 @@
|
||||
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;
|
||||
@ -30,13 +29,7 @@ class IcingaAddServiceForm extends DirectorObjectForm
|
||||
);
|
||||
}
|
||||
|
||||
$this->addSingleImportElement(true);
|
||||
|
||||
if (empty($this->enumServiceTemplates())) {
|
||||
$this->setSubmitLabel(false);
|
||||
|
||||
return;
|
||||
}
|
||||
$this->addSingleImportElement();
|
||||
|
||||
if (! ($imports = $this->getSentOrObjectValue('imports'))) {
|
||||
$this->setSubmitLabel($this->translate('Next'));
|
||||
@ -89,7 +82,7 @@ class IcingaAddServiceForm extends DirectorObjectForm
|
||||
if ($this->hasBeenSent()) {
|
||||
$this->addError($this->translate('No service has been chosen'));
|
||||
} else {
|
||||
if ($this->hasPermission(Permission::ADMIN)) {
|
||||
if ($this->hasPermission('director/admin')) {
|
||||
$html = sprintf(
|
||||
$this->translate('Please define a %s first'),
|
||||
Link::create(
|
||||
@ -107,12 +100,15 @@ class IcingaAddServiceForm extends DirectorObjectForm
|
||||
|
||||
return $this;
|
||||
}
|
||||
$this->addElement('text', 'imports', [
|
||||
|
||||
$this->addElement('select', 'imports', [
|
||||
'label' => $this->translate('Service'),
|
||||
'description' => $this->translate('Choose a service template'),
|
||||
'description' => $this->translate(
|
||||
'Choose a service template'
|
||||
),
|
||||
'required' => true,
|
||||
'data-suggestion-context' => 'servicetemplates',
|
||||
'class' => 'autosubmit director-suggest'
|
||||
'multiOptions' => $this->optionalEnum($enum),
|
||||
'class' => 'autosubmit'
|
||||
]);
|
||||
|
||||
return $this;
|
||||
@ -160,11 +156,7 @@ class IcingaAddServiceForm extends DirectorObjectForm
|
||||
public function onSuccess()
|
||||
{
|
||||
if ($this->host !== null) {
|
||||
if ($id = $this->host->get('id')) {
|
||||
$this->object->set('host_id', $id);
|
||||
} else {
|
||||
$this->object->set('host', $this->host->getObjectName());
|
||||
}
|
||||
$this->object->set('host_id', $this->host->get('id'));
|
||||
parent::onSuccess();
|
||||
return;
|
||||
}
|
||||
@ -172,11 +164,10 @@ class IcingaAddServiceForm extends DirectorObjectForm
|
||||
$plain = $this->object->toPlainObject();
|
||||
$db = $this->object->getConnection();
|
||||
|
||||
// TODO: Test this:
|
||||
foreach ($this->hosts as $host) {
|
||||
$service = IcingaService::fromPlainObject($plain, $db)
|
||||
->set('host_id', $host->get('id'));
|
||||
$this->getDbObjectStore()->store($service);
|
||||
IcingaService::fromPlainObject($plain, $db)
|
||||
->set('host_id', $host->get('id'))
|
||||
->store();
|
||||
}
|
||||
|
||||
$msg = sprintf(
|
||||
|
@ -2,13 +2,8 @@
|
||||
|
||||
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;
|
||||
@ -22,25 +17,8 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
|
||||
protected $baseObjectUrl;
|
||||
|
||||
/** @var Branch */
|
||||
protected $branch;
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$isBranch = $this->branch && $this->branch->isBranch();
|
||||
$branchOnly = $this->object->get('id') === null;
|
||||
|
||||
if (
|
||||
$isBranch
|
||||
&& $this->object->isTemplate()
|
||||
&& ! $this->object instanceof IcingaServiceSet
|
||||
) {
|
||||
$this->addHtml(Hint::error($this->translate(
|
||||
'Templates cannot be cloned in Configuration Branches'
|
||||
)));
|
||||
$this->submitLabel = false;
|
||||
return;
|
||||
}
|
||||
$name = $this->object->getObjectName();
|
||||
$this->addElement('text', 'new_object_name', array(
|
||||
'label' => $this->translate('New name'),
|
||||
@ -48,7 +26,7 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
'value' => $name,
|
||||
));
|
||||
|
||||
if (!$branchOnly && Acl::instance()->hasPermission(Permission::ADMIN)) {
|
||||
if (Acl::instance()->hasPermission('director/admin')) {
|
||||
$this->addElement('select', 'clone_type', array(
|
||||
'label' => 'Clone type',
|
||||
'required' => true,
|
||||
@ -59,9 +37,8 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
));
|
||||
}
|
||||
|
||||
if (
|
||||
!$branchOnly && ($this->object instanceof IcingaHost
|
||||
|| $this->object instanceof IcingaServiceSet)
|
||||
if ($this->object instanceof IcingaHost
|
||||
|| $this->object instanceof IcingaServiceSet
|
||||
) {
|
||||
$this->addBoolean('clone_services', [
|
||||
'label' => $this->translate('Clone Services'),
|
||||
@ -71,7 +48,7 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
], 'y');
|
||||
}
|
||||
|
||||
if (!$branchOnly && $this->object instanceof IcingaHost) {
|
||||
if ($this->object instanceof IcingaHost) {
|
||||
$this->addBoolean('clone_service_sets', [
|
||||
'label' => $this->translate('Clone Service Sets'),
|
||||
'description' => $this->translate(
|
||||
@ -103,10 +80,7 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
($this->object->isTemplate() || $this->object instanceof IcingaCommand)
|
||||
&& $this->object->supportsFields()
|
||||
) {
|
||||
if ($this->object->isTemplate() && $this->object->supportsFields()) {
|
||||
$this->addBoolean('clone_fields', [
|
||||
'label' => $this->translate('Clone Template Fields'),
|
||||
'description' => $this->translate(
|
||||
@ -121,13 +95,6 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
);
|
||||
}
|
||||
|
||||
public function setBranch(Branch $branch)
|
||||
{
|
||||
$this->branch = $branch;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setObjectBaseUrl($url)
|
||||
{
|
||||
$this->baseObjectUrl = $url;
|
||||
@ -143,7 +110,7 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
$connection = $object->getConnection();
|
||||
$db = $connection->getDbAdapter();
|
||||
$newName = $this->getValue('new_object_name');
|
||||
$resolve = Acl::instance()->hasPermission(Permission::ADMIN)
|
||||
$resolve = Acl::instance()->hasPermission('director/admin')
|
||||
&& $this->getValue('clone_type') === 'flat';
|
||||
|
||||
$msg = sprintf(
|
||||
@ -153,16 +120,6 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
$object->getObjectName()
|
||||
);
|
||||
|
||||
$isBranch = $this->branch && $this->branch->isBranch();
|
||||
|
||||
if (
|
||||
$isBranch
|
||||
&& $this->object->isTemplate()
|
||||
&& ! $this->object instanceof IcingaServiceSet
|
||||
) {
|
||||
throw new IcingaException('Cloning templates is not available for Branches');
|
||||
}
|
||||
|
||||
if ($object->isTemplate() && $object->getObjectName() === $newName) {
|
||||
throw new IcingaException(
|
||||
$this->translate('Name needs to be changed when cloning a Template')
|
||||
@ -206,14 +163,13 @@ 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 = [];
|
||||
}
|
||||
|
||||
$store = new DbObjectStore($connection, $this->branch);
|
||||
if ($store->store($new)) {
|
||||
if ($new->store()) {
|
||||
$newId = $new->get('id');
|
||||
foreach ($services as $service) {
|
||||
$clone = IcingaService::fromPlainObject(
|
||||
@ -222,39 +178,22 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
);
|
||||
|
||||
if ($new instanceof IcingaHost) {
|
||||
if ($isBranch) {
|
||||
$clone->set('host', $newName);
|
||||
} else {
|
||||
$clone->set('host_id', $newId);
|
||||
}
|
||||
$clone->set('host_id', $newId);
|
||||
} elseif ($new instanceof IcingaServiceSet) {
|
||||
if ($isBranch) {
|
||||
$clone->set('service_set', $newName);
|
||||
} else {
|
||||
$clone->set('service_set_id', $newId);
|
||||
}
|
||||
$clone->set('service_set_id', $newId);
|
||||
}
|
||||
|
||||
$store->store($clone);
|
||||
$clone->store();
|
||||
}
|
||||
|
||||
foreach ($sets as $set) {
|
||||
$newSet = IcingaServiceSet::fromPlainObject(
|
||||
IcingaServiceSet::fromPlainObject(
|
||||
$set->toPlainObject(),
|
||||
$connection
|
||||
);
|
||||
|
||||
if ($isBranch) {
|
||||
$newSet->set('host', $newName);
|
||||
} else {
|
||||
$newSet->set('host_id', $newId);
|
||||
}
|
||||
|
||||
$store->store($newSet);
|
||||
)->set('host_id', $newId)->store();
|
||||
}
|
||||
|
||||
foreach ($fields as $row) {
|
||||
$row->{"{$type}_id"} = $newId;
|
||||
$row->{"${type}_id"} = $newId;
|
||||
$db->insert($table . '_field', (array) $row);
|
||||
}
|
||||
|
||||
@ -280,7 +219,6 @@ class IcingaCloneObjectForm extends DirectorForm
|
||||
return $db->fetchPairs(
|
||||
$db->select()
|
||||
->from('icinga_service_set', ['id', 'object_name'])
|
||||
->where('object_type = ?', 'template')
|
||||
->order('object_name')
|
||||
);
|
||||
}
|
||||
|
@ -134,22 +134,16 @@ class IcingaCommandArgumentForm extends DirectorObjectForm
|
||||
$cmd = $this->commandObject;
|
||||
|
||||
$msg = sprintf(
|
||||
$this->translate('%s argument "%s" has been removed'),
|
||||
'%s argument "%s" has been removed',
|
||||
$this->translate($this->getObjectShortClassName()),
|
||||
$object->argument_name
|
||||
);
|
||||
|
||||
// TODO: remove argument_id, once verified that it is no longer in use
|
||||
$url = $this->getSuccessUrl()->without('argument_id')->without('argument');
|
||||
$url = $this->getSuccessUrl()->without('argument_id');
|
||||
|
||||
$cmd->arguments()->remove($object->argument_name);
|
||||
if ($this->branch->isBranch()) {
|
||||
$this->getDbObjectStore()->store($cmd);
|
||||
if ($cmd->store()) {
|
||||
$this->setSuccessUrl($url);
|
||||
} else {
|
||||
if ($cmd->store()) {
|
||||
$this->setSuccessUrl($url);
|
||||
}
|
||||
}
|
||||
|
||||
$this->redirectOnSuccess($msg);
|
||||
@ -173,17 +167,20 @@ class IcingaCommandArgumentForm extends DirectorObjectForm
|
||||
$this->translate('The argument %s has successfully been stored'),
|
||||
$object->get('argument_name')
|
||||
);
|
||||
$this->getDbObjectStore()->store($cmd);
|
||||
$cmd->store($this->db);
|
||||
} else {
|
||||
if ($this->isApiRequest()) {
|
||||
$this->setHttpResponseCode(304);
|
||||
}
|
||||
$msg = $this->translate('No action taken, object has not been modified');
|
||||
}
|
||||
$this->setSuccessUrl('director/command/arguments', [
|
||||
'argument' => $object->get('argument_name'),
|
||||
'name' => $cmd->getObjectName()
|
||||
]);
|
||||
$this->setSuccessUrl(
|
||||
'director/command/arguments',
|
||||
[
|
||||
'argument_id' => $object->get('id'),
|
||||
'name' => $cmd->getObjectName()
|
||||
]
|
||||
);
|
||||
|
||||
$this->redirectOnSuccess($msg);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ class IcingaCommandForm extends DirectorObjectForm
|
||||
'ClusterZoneCheck' => 'Icinga Cluster Zone Check Command',
|
||||
'IdoCheck' => 'Ido Check Command',
|
||||
'RandomCheck' => 'Random Check Command',
|
||||
'CrlCheck' => 'Crl Check Command',
|
||||
)
|
||||
),
|
||||
'required' => ! $this->isTemplate(),
|
||||
|
@ -5,7 +5,6 @@ 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
|
||||
{
|
||||
@ -165,7 +164,7 @@ class IcingaDependencyForm extends DirectorObjectForm
|
||||
], null);
|
||||
|
||||
$this->addBoolean('disable_notifications', [
|
||||
'label' => $this->translate('Disable Notifications'),
|
||||
'label' => $this->translate('Disable Notificiations'),
|
||||
'description' => $this->translate(
|
||||
'Whether to disable notifications when this dependency fails.'
|
||||
. ' Defaults to true.'
|
||||
@ -193,83 +192,38 @@ class IcingaDependencyForm extends DirectorObjectForm
|
||||
$parentHost = $dependency->get('parent_host');
|
||||
if ($parentHost === null) {
|
||||
$parentHostVar = $dependency->get('parent_host_var');
|
||||
if ($parentHostVar !== null && \strlen($parentHostVar) > 0) {
|
||||
if (\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' => $parentHostDescription,
|
||||
'class' => "autosubmit director-suggest",
|
||||
'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",
|
||||
'data-suggestion-context' => 'hostnames',
|
||||
'order' => 10,
|
||||
'required' => $this->isObject(),
|
||||
'value' => $parentHost,
|
||||
'validators' => [$parentHostValidator]
|
||||
'order' => 10,
|
||||
'required' => $this->isObject(),
|
||||
'value' => $parentHost
|
||||
]);
|
||||
$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' => $parentServiceDescription,
|
||||
'class' => "autosubmit director-suggest",
|
||||
'data-suggestion-context' => 'servicenames',
|
||||
'data-suggestion-for-host' => $sentParent,
|
||||
'order' => 20,
|
||||
'value' => $parentService,
|
||||
'validators' => [$parentServiceValidator]
|
||||
]);
|
||||
'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
|
||||
]);
|
||||
}
|
||||
|
||||
// If configuring Object, allow selection of child host and/or service,
|
||||
@ -336,22 +290,11 @@ class IcingaDependencyForm extends DirectorObjectForm
|
||||
protected function handleProperties(DbObject $object, &$values)
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
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'] = '';
|
||||
}
|
||||
if (isset($values['parent_host'])
|
||||
&& $this->isCustomVar($values['parent_host'])
|
||||
) {
|
||||
$values['parent_host_var'] = \trim($values['parent_host'], '$');
|
||||
$values['parent_host'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,6 +303,7 @@ class IcingaDependencyForm extends DirectorObjectForm
|
||||
|
||||
protected function isCustomVar($string)
|
||||
{
|
||||
return preg_match('/^\$(?:host|service)\.vars\..+\$$/', $string);
|
||||
return \preg_match('/^\$(?:host)\.vars\..+\$$/', $string);
|
||||
// Eventually: return \preg_match('/^\$(?:host|service)\.vars\..+\$$/', $string);
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,7 @@
|
||||
|
||||
namespace Icinga\Module\Director\Forms;
|
||||
|
||||
use Exception;
|
||||
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;
|
||||
@ -84,13 +81,7 @@ class IcingaHostForm extends DirectorObjectForm
|
||||
'class' => 'autosubmit',
|
||||
]);
|
||||
|
||||
try {
|
||||
$hasAgent = $this->getSentOrResolvedObjectValue('has_agent') === 'y';
|
||||
} catch (Exception $e) {
|
||||
$hasAgent = false;
|
||||
}
|
||||
|
||||
if ($hasAgent) {
|
||||
if ($this->getSentOrResolvedObjectValue('has_agent') === 'y') {
|
||||
$this->addBoolean('master_should_connect', [
|
||||
'label' => $this->translate('Establish connection'),
|
||||
'description' => $this->translate(
|
||||
@ -106,17 +97,6 @@ class IcingaHostForm extends DirectorObjectForm
|
||||
|
||||
$this->addHidden('command_endpoint_id', null);
|
||||
$this->setSentValue('command_endpoint_id', null);
|
||||
|
||||
$settings = $this->object->getConnection()->settings();
|
||||
if ($settings->get('feature_custom_endpoint') === 'y' && ! $this->isTemplate()) {
|
||||
$this->addElement('text', 'custom_endpoint_name', [
|
||||
'label' => $this->translate('Custom Endpoint Name'),
|
||||
'description' => $this->translate(
|
||||
'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 endpoint.'
|
||||
),
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
if ($this->isTemplate()) {
|
||||
$this->addElement('select', 'command_endpoint_id', [
|
||||
@ -143,7 +123,6 @@ class IcingaHostForm extends DirectorObjectForm
|
||||
'master_should_connect',
|
||||
'accept_config',
|
||||
'command_endpoint_id',
|
||||
'custom_endpoint_name',
|
||||
'api_key',
|
||||
];
|
||||
$this->addDisplayGroup($elements, 'clustering', [
|
||||
@ -171,7 +150,7 @@ class IcingaHostForm extends DirectorObjectForm
|
||||
if ($this->hasBeenSent()) {
|
||||
$this->addError($this->translate('No Host template has been chosen'));
|
||||
} else {
|
||||
if ($this->hasPermission(Permission::ADMIN)) {
|
||||
if ($this->hasPermission('director/admin')) {
|
||||
$html = sprintf(
|
||||
$this->translate('Please define a %s first'),
|
||||
Link::create(
|
||||
@ -216,9 +195,8 @@ class IcingaHostForm extends DirectorObjectForm
|
||||
*/
|
||||
protected function addGroupsElement()
|
||||
{
|
||||
if (
|
||||
$this->hasHostGroupRestriction()
|
||||
&& ! $this->getAuth()->hasPermission(Permission::GROUPS_FOR_RESTRICTED_HOSTS)
|
||||
if ($this->hasHostGroupRestriction()
|
||||
&& ! $this->getAuth()->hasPermission('director/groups-for-restricted-hosts')
|
||||
) {
|
||||
return $this;
|
||||
}
|
||||
@ -272,6 +250,15 @@ 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()) {
|
||||
@ -296,7 +283,9 @@ class IcingaHostForm extends DirectorObjectForm
|
||||
);
|
||||
}
|
||||
|
||||
return Html::tag('span', ['class' => 'host-group-links'], $links);
|
||||
return Html::tag('span', [
|
||||
'style' => 'line-height: 2.5em; padding-left: 0.5em'
|
||||
], $links);
|
||||
}
|
||||
|
||||
protected function getAppliedGroups()
|
||||
@ -310,7 +299,7 @@ class IcingaHostForm extends DirectorObjectForm
|
||||
|
||||
protected function hasHostGroupRestriction()
|
||||
{
|
||||
return $this->getAuth()->getRestrictions(Restriction::FILTER_HOSTGROUPS);
|
||||
return $this->getAuth()->getRestrictions('director/filter/hostgroups');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21,9 +21,6 @@ class IcingaMultiEditForm extends DirectorObjectForm
|
||||
|
||||
private $propertiesToPick;
|
||||
|
||||
/** @var array<string, string> Custom variable name map to its element's name in the form */
|
||||
private $varNameMap = [];
|
||||
|
||||
public function setObjects($objects)
|
||||
{
|
||||
$this->objects = $objects;
|
||||
@ -51,7 +48,6 @@ class IcingaMultiEditForm extends DirectorObjectForm
|
||||
$loader = new IcingaObjectFieldLoader($object);
|
||||
$loader->prepareElements($this);
|
||||
$loader->addFieldsToForm($this);
|
||||
$this->varNameMap = $loader->getNameMap();
|
||||
|
||||
if ($form = $this->relatedForm) {
|
||||
if ($form instanceof DirectorObjectForm) {
|
||||
@ -72,7 +68,8 @@ class IcingaMultiEditForm extends DirectorObjectForm
|
||||
|
||||
/** @var \Zend_Form_Element $el */
|
||||
foreach ($this->getElements() as $el) {
|
||||
if ($this->isCustomVar($el->getName())) {
|
||||
$name = $el->getName();
|
||||
if (substr($name, 0, 4) === 'var_') {
|
||||
$this->makeVariants($el);
|
||||
}
|
||||
}
|
||||
@ -140,8 +137,8 @@ class IcingaMultiEditForm extends DirectorObjectForm
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->isCustomVar($property)) {
|
||||
$property = 'vars.' . $this->varNameMap[$property];
|
||||
if (substr($property, 0, 4) === 'var_') {
|
||||
$property = 'vars.' . substr($property, 4);
|
||||
}
|
||||
|
||||
foreach ($this->getObjects($objects) as $object) {
|
||||
@ -150,26 +147,13 @@ class IcingaMultiEditForm extends DirectorObjectForm
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given property is a custom var
|
||||
*
|
||||
* @param string $property
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function isCustomVar(string $property): bool
|
||||
{
|
||||
return substr($property, 0, 4) === 'var_';
|
||||
}
|
||||
|
||||
protected function storeModifiedObjects()
|
||||
{
|
||||
$modified = 0;
|
||||
$store = $this->getDbObjectStore();
|
||||
foreach ($this->objects as $object) {
|
||||
if ($object->hasBeenModified()) {
|
||||
$modified++;
|
||||
$store->store($object);
|
||||
$object->store();
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,7 +221,6 @@ class IcingaMultiEditForm extends DirectorObjectForm
|
||||
$key = $element->getName();
|
||||
$this->removeElement($key);
|
||||
$label = $element->getLabel();
|
||||
|
||||
$group = $this->getDisplayGroupForElement($element);
|
||||
$description = $element->getDescription();
|
||||
|
||||
@ -257,13 +240,11 @@ class IcingaMultiEditForm extends DirectorObjectForm
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function getVariants($key)
|
||||
{
|
||||
$variants = array();
|
||||
if ($this->isCustomVar($key)) {
|
||||
$key = 'vars.' . $this->varNameMap[$key];
|
||||
if (substr($key, 0, 4) === 'var_') {
|
||||
$key = 'vars.' . substr($key, 4);
|
||||
}
|
||||
|
||||
foreach ($this->objects as $name => $object) {
|
||||
@ -328,9 +309,8 @@ class IcingaMultiEditForm extends DirectorObjectForm
|
||||
$this->translate($this->object->getShortTableName())
|
||||
);
|
||||
|
||||
$store = $this->getDbObjectStore();
|
||||
foreach ($this->objects as $object) {
|
||||
$store->delete($object);
|
||||
$object->delete();
|
||||
}
|
||||
|
||||
if ($this->listUrl) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Icinga\Module\Director\Forms;
|
||||
|
||||
use Icinga\Module\Director\DataType\DataTypeDirectorObject;
|
||||
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
|
||||
|
||||
class IcingaNotificationForm extends DirectorObjectForm
|
||||
@ -122,32 +121,20 @@ class IcingaNotificationForm extends DirectorObjectForm
|
||||
{
|
||||
$users = $this->enumUsers();
|
||||
if (empty($users)) {
|
||||
$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', [
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'extensibleSet',
|
||||
'users',
|
||||
array(
|
||||
'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;
|
||||
}
|
||||
@ -159,59 +146,24 @@ class IcingaNotificationForm extends DirectorObjectForm
|
||||
{
|
||||
$groups = $this->enumUsergroups();
|
||||
if (empty($groups)) {
|
||||
$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', [
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->addElement(
|
||||
'extensibleSet',
|
||||
'user_groups',
|
||||
array(
|
||||
'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
|
||||
*/
|
||||
@ -244,7 +196,7 @@ class IcingaNotificationForm extends DirectorObjectForm
|
||||
array(
|
||||
'label' => $this->translate('First notification delay'),
|
||||
'description' => $this->translate(
|
||||
'Delay until the first notification should be sent'
|
||||
'Delay unless the first notification should be sent'
|
||||
) . '. ' . $this->getTimeValueInfo()
|
||||
)
|
||||
);
|
||||
|
@ -2,9 +2,6 @@
|
||||
|
||||
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;
|
||||
@ -18,9 +15,6 @@ 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;
|
||||
@ -42,9 +36,22 @@ 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')) {
|
||||
@ -53,16 +60,56 @@ class IcingaObjectFieldForm extends DirectorObjectForm
|
||||
$command = null;
|
||||
}
|
||||
|
||||
$suggestions = $this->fieldSuggestion = new FormFieldSuggestion($command, $this->db->enumDatafields());
|
||||
$fields = $suggestions->getCommandFields();
|
||||
if ($command) {
|
||||
foreach ($command->arguments() as $arg) {
|
||||
if ($arg->argument_format === 'string') {
|
||||
$val = $arg->argument_value;
|
||||
// TODO: create var::extractMacros or so
|
||||
|
||||
$this->addElement('select', 'datafield_id', [
|
||||
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;
|
||||
}
|
||||
|
||||
$this->addElement('select', 'datafield_id', array(
|
||||
'label' => 'Field',
|
||||
'required' => true,
|
||||
'description' => 'Field to assign',
|
||||
'class' => 'autosubmit',
|
||||
'multiOptions' => $this->optionalEnum($fields)
|
||||
]);
|
||||
));
|
||||
|
||||
if (empty($fields)) {
|
||||
// TODO: show message depending on permissions
|
||||
@ -74,58 +121,67 @@ class IcingaObjectFieldForm extends DirectorObjectForm
|
||||
}
|
||||
|
||||
if (($id = $this->getSentValue('datafield_id')) && ! ctype_digit($id)) {
|
||||
$this->addElement('text', 'caption', [
|
||||
$this->addElement('text', 'caption', array(
|
||||
'label' => $this->translate('Caption'),
|
||||
'required' => true,
|
||||
'ignore' => true,
|
||||
'value' => trim($id, '$'),
|
||||
'description' => $this->translate(
|
||||
'The caption which should be displayed to your users when this field'
|
||||
. ' is shown'
|
||||
)
|
||||
]);
|
||||
'description' => $this->translate('The caption which should be displayed')
|
||||
));
|
||||
|
||||
$this->addElement('textarea', 'description', [
|
||||
$this->addElement('textarea', 'description', array(
|
||||
'label' => $this->translate('Description'),
|
||||
'description' => $this->translate(
|
||||
'An extended description for this field. Will be shown as soon as a'
|
||||
. ' user puts the focus on this field'
|
||||
),
|
||||
'description' => $this->translate('A description about the field'),
|
||||
'ignore' => true,
|
||||
'value' => $command ? $suggestions->getDescription($id) : null,
|
||||
'value' => array_key_exists($id, $argumentVarDescriptions) ? $argumentVarDescriptions[$id] : null,
|
||||
'rows' => '3',
|
||||
]);
|
||||
));
|
||||
}
|
||||
|
||||
$this->addElement('select', 'is_required', [
|
||||
$this->addElement('select', 'is_required', array(
|
||||
'label' => $this->translate('Mandatory'),
|
||||
'description' => $this->translate('Whether this field should be mandatory'),
|
||||
'required' => true,
|
||||
'multiOptions' => [
|
||||
'multiOptions' => array(
|
||||
'n' => $this->translate('Optional'),
|
||||
'y' => $this->translate('Mandatory'),
|
||||
]
|
||||
]);
|
||||
)
|
||||
));
|
||||
|
||||
if ($filterFields = $this->getFilterFields($object)) {
|
||||
$this->addFilterElement('var_filter', [
|
||||
$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(
|
||||
'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([$this->getElement('var_filter')], 'field_filter', [
|
||||
'decorators' => [
|
||||
$this->addDisplayGroup(array($this->getElement('var_filter')), 'field_filter', array(
|
||||
'decorators' => array(
|
||||
'FormElements',
|
||||
['HtmlTag', ['tag' => 'dl']],
|
||||
array('HtmlTag', array('tag' => 'dl')),
|
||||
'Fieldset',
|
||||
],
|
||||
),
|
||||
'order' => 30,
|
||||
'legend' => $this->translate('Show based on filter')
|
||||
]);
|
||||
));
|
||||
}
|
||||
|
||||
$this->setButtons();
|
||||
@ -146,42 +202,18 @@ class IcingaObjectFieldForm extends DirectorObjectForm
|
||||
$fieldId = $this->getValue('datafield_id');
|
||||
|
||||
if (! ctype_digit($fieldId)) {
|
||||
$field = DirectorDatafield::create([
|
||||
$field = DirectorDatafield::create(array(
|
||||
'varname' => trim($fieldId, '$'),
|
||||
'caption' => $this->getValue('caption'),
|
||||
'description' => $this->getValue('description'),
|
||||
'datatype' => $this->fieldSuggestion && $this->fieldSuggestion->isBoolean($fieldId)
|
||||
? DataTypeBoolean::class
|
||||
: DataTypeString::class
|
||||
]);
|
||||
'datatype' => 'Icinga\Module\Director\DataType\DataTypeString',
|
||||
));
|
||||
$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'));
|
||||
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;
|
||||
return parent::onSuccess();
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,6 @@ class IcingaScheduledDowntimeForm extends DirectorObjectForm
|
||||
'required' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($this->object()->isApplyRule()) {
|
||||
$this->eventuallyAddNameRestriction('director/scheduled-downtime/apply/filter-by-name');
|
||||
}
|
||||
$this->addImportsElement();
|
||||
$this->addElement('text', 'author', [
|
||||
'label' => $this->translate('Author'),
|
||||
|
@ -21,7 +21,7 @@ class IcingaScheduledDowntimeRangeForm extends DirectorObjectForm
|
||||
$this->addElement('text', 'range_key', [
|
||||
'label' => $this->translate('Day(s)'),
|
||||
'description' => $this->translate(
|
||||
'Might be monday, tuesday or 2016-01-28 - have a look at the documentation for more examples'
|
||||
'Might be, monday, tuesday, 2016-01-28 - have a look at the documentation for more examples'
|
||||
),
|
||||
]);
|
||||
|
||||
|
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Module\Director\Forms;
|
||||
|
||||
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
|
||||
use Icinga\Module\Director\Objects\IcingaService;
|
||||
|
||||
class IcingaServiceDictionaryMemberForm extends DirectorObjectForm
|
||||
{
|
||||
/** @var IcingaService */
|
||||
protected $object;
|
||||
|
||||
private $succeeded;
|
||||
|
||||
/**
|
||||
* @throws \Zend_Form_Exception
|
||||
*/
|
||||
public function setup()
|
||||
{
|
||||
$this->addHidden('object_type', 'object');
|
||||
$this->addElement('text', 'object_name', [
|
||||
'label' => $this->translate('Name'),
|
||||
'required' => !$this->object()->isApplyRule(),
|
||||
'description' => $this->translate(
|
||||
'Name for the instance you are going to create'
|
||||
)
|
||||
]);
|
||||
$this->groupMainProperties()->setButtons();
|
||||
}
|
||||
|
||||
protected function isNew()
|
||||
{
|
||||
return $this->object === null;
|
||||
}
|
||||
|
||||
protected function deleteObject($object)
|
||||
{
|
||||
}
|
||||
|
||||
protected function getObjectClassname()
|
||||
{
|
||||
return IcingaService::class;
|
||||
}
|
||||
|
||||
public function succeeded()
|
||||
{
|
||||
return $this->succeeded;
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
{
|
||||
$this->succeeded = true;
|
||||
}
|
||||
}
|
@ -6,15 +6,12 @@ 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;
|
||||
use Icinga\Module\Director\Objects\IcingaServiceSet;
|
||||
use Icinga\Module\Director\Web\Table\ObjectsTableHost;
|
||||
use ipl\Html\Html;
|
||||
use gipfl\IcingaWeb2\Link;
|
||||
use RuntimeException;
|
||||
@ -130,8 +127,6 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
if (! $this->providesOverrides()) {
|
||||
return;
|
||||
}
|
||||
$hasDeleteButton = false;
|
||||
$isBranch = $this->branch && $this->branch->isBranch();
|
||||
|
||||
if ($this->hasBeenBlacklisted()) {
|
||||
$this->addHtml(
|
||||
@ -139,10 +134,7 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
['name' => 'HINT_blacklisted']
|
||||
);
|
||||
$group = null;
|
||||
if (! $isBranch) {
|
||||
$this->addDeleteButton($this->translate('Reactivate'));
|
||||
$hasDeleteButton = true;
|
||||
}
|
||||
$this->addDeleteButton($this->translate('Reactivate'));
|
||||
$this->setSubmitLabel(false);
|
||||
} else {
|
||||
$this->addOverrideHint();
|
||||
@ -171,13 +163,10 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
$this->setSubmitLabel(false);
|
||||
}
|
||||
|
||||
if (! $isBranch) {
|
||||
$this->addDeleteButton($this->translate('Deactivate'));
|
||||
$hasDeleteButton = true;
|
||||
}
|
||||
$this->addDeleteButton($this->translate('Deactivate'));
|
||||
}
|
||||
|
||||
if (! $this->hasSubmitButton() && $hasDeleteButton) {
|
||||
if (! $this->hasSubmitButton()) {
|
||||
$this->addDisplayGroup([$this->deleteButtonName], 'buttons', [
|
||||
'decorators' => [
|
||||
'FormElements',
|
||||
@ -198,16 +187,14 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
}
|
||||
|
||||
/**
|
||||
* Hint: could be moved elsewhere
|
||||
*
|
||||
* @param IcingaService $object
|
||||
* @return IcingaObject|IcingaService|IcingaServiceSet
|
||||
* @param IcingaService $service
|
||||
* @return IcingaService
|
||||
* @throws \Icinga\Exception\NotFoundError
|
||||
*/
|
||||
protected static function getFirstParent(IcingaObject $object)
|
||||
protected function getFirstParent(IcingaService $service)
|
||||
{
|
||||
/** @var IcingaObject[] $objects */
|
||||
$objects = $object->imports()->getObjects();
|
||||
/** @var IcingaService[] $objects */
|
||||
$objects = $service->imports()->getObjects();
|
||||
if (empty($objects)) {
|
||||
throw new RuntimeException('Something went wrong, got no parent');
|
||||
}
|
||||
@ -228,19 +215,13 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
|
||||
if ($this->blacklisted === null) {
|
||||
$host = $this->host;
|
||||
// Safety check, branches
|
||||
$hostId = $host->get('id');
|
||||
$service = $this->getServiceToBeBlacklisted();
|
||||
$serviceId = $service->get('id');
|
||||
if (! $hostId || ! $serviceId) {
|
||||
return false;
|
||||
}
|
||||
$db = $this->db->getDbAdapter();
|
||||
if ($this->providesOverrides()) {
|
||||
$this->blacklisted = 1 === (int)$db->fetchOne(
|
||||
$db->select()->from('icinga_host_service_blacklist', 'COUNT(*)')
|
||||
->where('host_id = ?', $hostId)
|
||||
->where('service_id = ?', $serviceId)
|
||||
->where('host_id = ?', $host->get('id'))
|
||||
->where('service_id = ?', $service->get('id'))
|
||||
);
|
||||
} else {
|
||||
$this->blacklisted = false;
|
||||
@ -282,12 +263,10 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
$db = $this->db->getDbAdapter();
|
||||
$host->unsetOverriddenServiceVars($this->object->getObjectName())->store();
|
||||
|
||||
if (
|
||||
$db->insert('icinga_host_service_blacklist', [
|
||||
if ($db->insert('icinga_host_service_blacklist', [
|
||||
'host_id' => $host->get('id'),
|
||||
'service_id' => $service->get('id')
|
||||
])
|
||||
) {
|
||||
])) {
|
||||
$msg = sprintf(
|
||||
$this->translate('%s has been deactivated on %s'),
|
||||
$service->getObjectName(),
|
||||
@ -306,7 +285,7 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
if ($this->set) {
|
||||
return $this->object;
|
||||
} else {
|
||||
return self::getFirstParent($this->object);
|
||||
return $this->getFirstParent($this->object);
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,14 +333,14 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
protected function setupServiceElements()
|
||||
{
|
||||
if ($this->object) {
|
||||
$objectType = $this->object->get('object_type');
|
||||
$objectType = $this->object->object_type;
|
||||
} elseif ($this->preferredObjectType) {
|
||||
$objectType = $this->preferredObjectType;
|
||||
} else {
|
||||
$objectType = 'template';
|
||||
}
|
||||
$this->addHidden('object_type', $objectType);
|
||||
$forceCommandElements = $this->hasPermission(Permission::ADMIN);
|
||||
$forceCommandElements = $this->hasPermission('director/admin');
|
||||
|
||||
$this->addNameElement()
|
||||
->addHostObjectElement()
|
||||
@ -443,6 +422,10 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
$this->addHtmlHint($hint, ['name' => 'inheritance_hint']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IcingaException
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
protected function setupOnHostForSet()
|
||||
{
|
||||
$msg = $this->translate(
|
||||
@ -495,7 +478,7 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
*/
|
||||
protected function setupHostRelatedElements()
|
||||
{
|
||||
$this->addHidden('host', $this->host->getObjectName());
|
||||
$this->addHidden('host_id', $this->host->id);
|
||||
$this->addHidden('object_type', 'object');
|
||||
$this->addImportsElement();
|
||||
$imports = $this->getSentOrObjectValue('imports');
|
||||
@ -518,7 +501,13 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
->addExtraInfoElements()
|
||||
->setButtons();
|
||||
|
||||
$this->setDefaultNameFromTemplate($imports);
|
||||
if ($this->hasBeenSent()) {
|
||||
$name = $this->getSentOrObjectValue('object_name');
|
||||
if (!strlen($name)) {
|
||||
$this->setElementValue('object_name', end($imports));
|
||||
$this->object->object_name = end($imports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -536,7 +525,7 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
*/
|
||||
protected function setupSetRelatedElements()
|
||||
{
|
||||
$this->addHidden('service_set', $this->set->getObjectName());
|
||||
$this->addHidden('service_set_id', $this->set->id);
|
||||
$this->addHidden('object_type', 'apply');
|
||||
$this->addImportsElement();
|
||||
$this->setButtons();
|
||||
@ -556,13 +545,19 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
->addGroupsElement()
|
||||
->groupMainProperties();
|
||||
|
||||
if ($this->hasPermission(Permission::ADMIN)) {
|
||||
if ($this->hasPermission('director/admin')) {
|
||||
$this->addCheckCommandElements(true)
|
||||
->addCheckExecutionElements(true)
|
||||
->addExtraInfoElements();
|
||||
}
|
||||
|
||||
$this->setDefaultNameFromTemplate($imports);
|
||||
if ($this->hasBeenSent()) {
|
||||
$name = $this->getSentOrObjectValue('object_name');
|
||||
if (!strlen($name)) {
|
||||
$this->setElementValue('object_name', end($imports));
|
||||
$this->object->object_name = end($imports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setServiceSet(IcingaServiceSet $set)
|
||||
@ -599,14 +594,14 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
protected function addHostObjectElement()
|
||||
{
|
||||
if ($this->isObject()) {
|
||||
$this->addElement('select', 'host', [
|
||||
$this->addElement('select', 'host_id', array(
|
||||
'label' => $this->translate('Host'),
|
||||
'required' => true,
|
||||
'multiOptions' => $this->optionalEnum($this->enumHostsAndTemplates()),
|
||||
'description' => $this->translate(
|
||||
'Choose the host this single service should be assigned to'
|
||||
)
|
||||
]);
|
||||
));
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -708,35 +703,10 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
|
||||
protected function enumHostsAndTemplates()
|
||||
{
|
||||
if ($this->branch && $this->branch->isBranch()) {
|
||||
return $this->enumHosts();
|
||||
}
|
||||
|
||||
return [
|
||||
$this->translate('Templates') => $this->enumHostTemplates(),
|
||||
$this->translate('Hosts') => $this->enumHosts(),
|
||||
];
|
||||
}
|
||||
|
||||
protected function enumHostTemplates()
|
||||
{
|
||||
$names = array_values($this->db->enumHostTemplates());
|
||||
return array_combine($names, $names);
|
||||
}
|
||||
|
||||
protected function enumHosts()
|
||||
{
|
||||
$db = $this->db->getDbAdapter();
|
||||
$table = new ObjectsTableHost($this->db, $this->getAuth());
|
||||
if ($this->branch && $this->branch->isBranch()) {
|
||||
$table->setBranchUuid($this->branch->getUuid());
|
||||
}
|
||||
$result = [];
|
||||
foreach ($db->fetchAll($table->getQuery()->reset(\Zend_Db_Select::LIMIT_COUNT)) as $row) {
|
||||
$result[$row->object_name] = $row->object_name;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return array(
|
||||
$this->translate('Templates') => $this->db->enumHostTemplates(),
|
||||
$this->translate('Hosts') => $this->db->enumHosts(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function enumServicegroups()
|
||||
@ -753,6 +723,10 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
return $db->fetchPairs($select);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IcingaException
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
protected function succeedForOverrides()
|
||||
{
|
||||
$vars = array();
|
||||
@ -773,7 +747,7 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
$this->translate($host->getObjectName())
|
||||
);
|
||||
|
||||
$this->getDbObjectStore()->store($host);
|
||||
$host->store();
|
||||
} else {
|
||||
if ($this->isApiRequest()) {
|
||||
$this->setHttpResponseCode(304);
|
||||
@ -785,27 +759,16 @@ class IcingaServiceForm extends DirectorObjectForm
|
||||
$this->redirectOnSuccess($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IcingaException
|
||||
* @throws ProgrammingError
|
||||
*/
|
||||
public function onSuccess()
|
||||
{
|
||||
if ($this->providesOverrides()) {
|
||||
$this->succeedForOverrides();
|
||||
return;
|
||||
return $this->succeedForOverrides();
|
||||
}
|
||||
|
||||
parent::onSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $imports
|
||||
*/
|
||||
protected function setDefaultNameFromTemplate($imports)
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
$name = $this->getSentOrObjectValue('object_name');
|
||||
if ($name === null || !strlen($name)) {
|
||||
$this->setElementValue('object_name', end($imports));
|
||||
$this->object->set('object_name', end($imports));
|
||||
}
|
||||
}
|
||||
return parent::onSuccess();
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Icinga\Module\Director\Forms;
|
||||
|
||||
use Icinga\Module\Director\Auth\Permission;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
|
||||
|
||||
@ -70,8 +69,7 @@ class IcingaServiceSetForm extends DirectorObjectForm
|
||||
}
|
||||
|
||||
$this->addHidden('object_type', 'object');
|
||||
$this->addHidden('host', $this->host->getObjectName());
|
||||
$this->groupMainProperties();
|
||||
$this->addHidden('host_id', $this->host->id);
|
||||
}
|
||||
|
||||
public function setHost(IcingaHost $host)
|
||||
@ -79,7 +77,6 @@ class IcingaServiceSetForm extends DirectorObjectForm
|
||||
$this->host = $host;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function addSingleImportsElement()
|
||||
{
|
||||
$enum = $this->enumAllowedTemplates();
|
||||
@ -114,7 +111,7 @@ class IcingaServiceSetForm extends DirectorObjectForm
|
||||
|
||||
protected function addAssignmentElements()
|
||||
{
|
||||
if (! $this->hasPermission(Permission::SERVICE_SET_APPLY)) {
|
||||
if (! $this->hasPermission('director/service_set/apply')) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
@ -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()));
|
||||
}
|
||||
|
||||
@ -91,15 +91,6 @@ class IcingaTemplateChoiceForm extends DirectorObjectForm
|
||||
'value' => 1,
|
||||
));
|
||||
|
||||
$this->addElement('select', 'required_template', [
|
||||
'label' => $this->translate('Associated Template'),
|
||||
'description' => $this->translate(
|
||||
'Choose Choice Associated Template'
|
||||
),
|
||||
'required' => true,
|
||||
'multiOptions' => $this->fetchUnboundTemplates(),
|
||||
]);
|
||||
|
||||
$this->setButtons();
|
||||
}
|
||||
|
||||
@ -133,7 +124,7 @@ class IcingaTemplateChoiceForm extends DirectorObjectForm
|
||||
/** @var IcingaTemplateChoice $object */
|
||||
$object = $this->object();
|
||||
$this->setSuccessUrl(
|
||||
'director/templatechoice/' . $object->getObjectShortTableName(),
|
||||
'director/templatechoice/' . $object->getObjectshortTableName(),
|
||||
$object->getUrlParams()
|
||||
);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class IcingaTimePeriodRangeForm extends DirectorObjectForm
|
||||
$this->addElement('text', 'range_key', array(
|
||||
'label' => $this->translate('Day(s)'),
|
||||
'description' => $this->translate(
|
||||
'Might be monday, tuesday or 2016-01-28 - have a look at the documentation for more examples'
|
||||
'Might be, monday, tuesday, 2016-01-28 - have a look at the documentation for more examples'
|
||||
),
|
||||
));
|
||||
|
||||
|
@ -64,41 +64,6 @@ 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'),
|
||||
@ -198,10 +163,10 @@ class ImportRowModifierForm extends DirectorObjectForm
|
||||
|
||||
if ($class !== null) {
|
||||
if (! class_exists($class)) {
|
||||
throw new RuntimeException(sprintf(
|
||||
throw new RuntimeException(
|
||||
'The hooked class "%s" for this property modifier does no longer exist',
|
||||
$class
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
$class::addSettingsFormFields($this);
|
||||
@ -214,13 +179,4 @@ class ImportRowModifierForm extends DirectorObjectForm
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
{
|
||||
if ($this->getValue('use_filter') === 'n') {
|
||||
$this->getObject()->set('filter_expression', null);
|
||||
}
|
||||
|
||||
parent::onSuccess();
|
||||
}
|
||||
}
|
||||
|
@ -41,18 +41,12 @@ class KickstartForm extends DirectorForm
|
||||
$this->addResourceConfigElements();
|
||||
$this->addResourceDisplayGroup();
|
||||
|
||||
if (
|
||||
!$this->config()->get('db', 'resource')
|
||||
|| ($this->config()->get('db', 'resource') !== $this->getResourceName())
|
||||
) {
|
||||
if (!$this->config()->get('db', 'resource')
|
||||
|| ($this->config()->get('db', 'resource') !== $this->getResourceName())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->hasBeenSent() && !$this->tryDbConnection()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->migrations()->hasSchema()) {
|
||||
$this->addHtmlHint($this->translate(
|
||||
'No database schema has been created yet'
|
||||
@ -77,7 +71,7 @@ class KickstartForm extends DirectorForm
|
||||
$hint = Html::sprintf(
|
||||
$this->translate('Your database looks good, you are ready to %s'),
|
||||
Link::create(
|
||||
$this->translate('start working with the Icinga Director'),
|
||||
'start working with the Icinga Director',
|
||||
'director',
|
||||
null,
|
||||
['data-base-target' => '_main']
|
||||
@ -200,8 +194,35 @@ class KickstartForm extends DirectorForm
|
||||
// Do not hinder the form from being stored
|
||||
return;
|
||||
}
|
||||
if ($resourceName = $this->getResourceName()) {
|
||||
$resourceConfig = ResourceFactory::getResourceConfig($resourceName);
|
||||
if (! isset($resourceConfig->charset)
|
||||
|| ! in_array($resourceConfig->charset, array('utf8', 'utf8mb4', 'UTF8', 'UTF-8'))
|
||||
) {
|
||||
if ($resource = $this->getElement('resource')) {
|
||||
$resource->addError('Please change the encoding for the director database to utf8');
|
||||
} else {
|
||||
$this->addError('Please change the encoding for the director database to utf8');
|
||||
}
|
||||
}
|
||||
|
||||
$this->tryDbConnection();
|
||||
$resource = $this->getResource();
|
||||
$db = $resource->getDbAdapter();
|
||||
|
||||
try {
|
||||
$db->fetchOne('SELECT 1');
|
||||
} catch (Exception $e) {
|
||||
$this->getElement('resource')
|
||||
->addError('Could not connect to database: ' . $e->getMessage());
|
||||
|
||||
$hint = $this->translate(
|
||||
'Please make sure that your database exists and your user has'
|
||||
. ' been granted enough permissions'
|
||||
);
|
||||
|
||||
$this->addHtmlHint($hint, array('name' => 'HINT_db_perms'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -322,7 +343,7 @@ class KickstartForm extends DirectorForm
|
||||
)
|
||||
);
|
||||
$this->addHtmlHint(
|
||||
Html::tag('pre', null, (string) $config),
|
||||
Html::tag('pre', null, $config),
|
||||
array('name' => 'HINT_config_store')
|
||||
);
|
||||
|
||||
@ -355,10 +376,8 @@ class KickstartForm extends DirectorForm
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
$this->getSubmitLabel() === $this->createDbLabel
|
||||
|| $this->getSubmitLabel() === $this->migrateDbLabel
|
||||
) {
|
||||
if ($this->getSubmitLabel() === $this->createDbLabel
|
||||
|| $this->getSubmitLabel() === $this->migrateDbLabel) {
|
||||
$this->migrations()->applyPendingMigrations();
|
||||
parent::onSuccess();
|
||||
}
|
||||
@ -447,41 +466,4 @@ class KickstartForm extends DirectorForm
|
||||
|
||||
return $resources;
|
||||
}
|
||||
|
||||
protected function tryDbConnection()
|
||||
{
|
||||
if ($resourceName = $this->getResourceName()) {
|
||||
$resourceConfig = ResourceFactory::getResourceConfig($resourceName);
|
||||
if (
|
||||
!isset($resourceConfig->charset)
|
||||
|| !in_array($resourceConfig->charset, array('utf8', 'utf8mb4', 'UTF8', 'UTF-8'))
|
||||
) {
|
||||
if ($resource = $this->getElement('resource')) {
|
||||
$resource->addError('Please change the encoding for the director database to utf8');
|
||||
} else {
|
||||
$this->addError('Please change the encoding for the director database to utf8');
|
||||
}
|
||||
}
|
||||
|
||||
$resource = $this->getResource();
|
||||
$db = $resource->getDbAdapter();
|
||||
|
||||
try {
|
||||
$db->fetchOne('SELECT 1');
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
$this->getElement('resource')
|
||||
->addError('Could not connect to database: ' . $e->getMessage());
|
||||
|
||||
$hint = $this->translate(
|
||||
'Please make sure that your database exists and your user has'
|
||||
. ' been granted enough permissions'
|
||||
);
|
||||
|
||||
$this->addHtmlHint($hint, array('name' => 'HINT_db_perms'));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,10 @@ class RemoveLinkForm extends DirectorForm
|
||||
{
|
||||
// Required to detect the right instance
|
||||
$this->formName = 'RemoveSet' . sha1(json_encode($params));
|
||||
parent::__construct(['data-base-target' => '_self']);
|
||||
parent::__construct([
|
||||
'style' => 'float: right',
|
||||
'data-base-target' => '_self'
|
||||
]);
|
||||
$this->label = $label;
|
||||
$this->title = $title;
|
||||
foreach ($params as $name => $value) {
|
||||
@ -35,7 +38,7 @@ class RemoveLinkForm extends DirectorForm
|
||||
|
||||
public function setup()
|
||||
{
|
||||
$this->addAttribs(['class' => ['inline', 'remove-link-form']]);
|
||||
$this->setAttrib('class', 'inline');
|
||||
$this->addHtml(Icon::create('cancel'));
|
||||
$this->addSubmitButton($this->label, [
|
||||
'class' => 'link-button',
|
||||
|
@ -105,18 +105,6 @@ class SettingsForm extends DirectorForm
|
||||
));
|
||||
}
|
||||
|
||||
$this->addBoolean('feature_custom_endpoint', [
|
||||
'label' => $this->translate('Feature: Custom Endpoint Name'),
|
||||
'description' => $this->translate(
|
||||
'Enabled the feature for custom endpoint names,'
|
||||
. ' where you can choose a different name for the generated endpoint object.'
|
||||
. ' This uses some Icinga config snippets and a special custom variable.'
|
||||
. ' Please do NOT enable this, unless you really need divergent endpoint names!'
|
||||
),
|
||||
'value' => $settings->getStoredValue('feature_custom_endpoint')
|
||||
]);
|
||||
|
||||
|
||||
$this->addElement('select', 'config_format', array(
|
||||
'label' => $this->translate('Configuration format'),
|
||||
'multiOptions' => $this->eventuallyConfiguredEnum(
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Icinga\Module\Director\Forms;
|
||||
|
||||
use Icinga\Module\Director\Objects\DirectorActivityLog;
|
||||
use Icinga\Module\Director\Objects\SyncRule;
|
||||
use Icinga\Module\Director\Web\Form\DirectorForm;
|
||||
|
||||
@ -32,20 +31,16 @@ class SyncCheckForm extends DirectorForm
|
||||
$this->notifySuccess(
|
||||
$this->translate(('This Sync Rule would apply new changes'))
|
||||
);
|
||||
$sum = [
|
||||
DirectorActivityLog::ACTION_CREATE => 0,
|
||||
DirectorActivityLog::ACTION_MODIFY => 0,
|
||||
DirectorActivityLog::ACTION_DELETE => 0
|
||||
];
|
||||
$sum = array('create' => 0, 'modify' => 0, 'delete' => 0);
|
||||
|
||||
// TODO: Preview them? Like "hosta, hostb and 4 more would be...
|
||||
foreach ($this->rule->getExpectedModifications() as $object) {
|
||||
if ($object->shouldBeRemoved()) {
|
||||
$sum[DirectorActivityLog::ACTION_DELETE]++;
|
||||
$sum['delete']++;
|
||||
} elseif (! $object->hasBeenLoadedFromDb()) {
|
||||
$sum[DirectorActivityLog::ACTION_CREATE]++;
|
||||
$sum['create']++;
|
||||
} elseif ($object->hasBeenModified()) {
|
||||
$sum[DirectorActivityLog::ACTION_MODIFY]++;
|
||||
$sum['modify']++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +50,7 @@ class SyncCheckForm extends DirectorForm
|
||||
} elseif ($sum['modify'] > 1) {
|
||||
}
|
||||
*/
|
||||
$html = '<pre>' . print_r($sum, true) . '</pre>';
|
||||
$html = '<pre>' . print_r($sum, 1) . '</pre>';
|
||||
|
||||
$this->addHtml($html);
|
||||
} elseif ($this->rule->get('sync_state') === 'in-sync') {
|
||||
|
@ -25,7 +25,7 @@ class SyncPropertyForm extends DirectorObjectForm
|
||||
|
||||
private $dummyObject;
|
||||
|
||||
public const EXPRESSION = '__EXPRESSION__';
|
||||
const EXPRESSION = '__EXPRESSION__';
|
||||
|
||||
/**
|
||||
* @throws \Zend_Form_Exception
|
||||
@ -93,8 +93,7 @@ class SyncPropertyForm extends DirectorObjectForm
|
||||
$this->setElementValue('use_filter', $useFilter = 'n');
|
||||
}
|
||||
} else {
|
||||
$expression = $this->getObject()->filter_expression;
|
||||
$useFilter = ($expression === null || strlen($expression) === 0) ? 'n' : 'y';
|
||||
$useFilter = strlen($this->getObject()->filter_expression) ? 'y' : 'n';
|
||||
$this->setElementValue('use_filter', $useFilter);
|
||||
}
|
||||
|
||||
|
@ -74,22 +74,8 @@ class SyncRuleForm extends DirectorObjectForm
|
||||
. ' longer exist at your import source.'
|
||||
),
|
||||
'required' => true,
|
||||
'class' => 'autosubmit',
|
||||
]);
|
||||
|
||||
if ($this->getSentOrObjectValue('purge_existing') === 'y') {
|
||||
$this->addElement('select', 'purge_action', [
|
||||
'label' => $this->translate('Purge Action'),
|
||||
'description' => $this->translate(
|
||||
'Whether to delete or to disable objects subject to purge'
|
||||
),
|
||||
'multiOptions' => $this->optionalEnum([
|
||||
'delete' => $this->translate('Delete'),
|
||||
'disable' => $this->translate('Disable'),
|
||||
]),
|
||||
'required' => true,
|
||||
]);
|
||||
}
|
||||
]);
|
||||
|
||||
$this->addElement('text', 'filter_expression', [
|
||||
'label' => $this->translate('Filter Expression'),
|
||||
|
@ -2,66 +2,44 @@
|
||||
|
||||
namespace Icinga\Module\Director\Forms;
|
||||
|
||||
use gipfl\Translation\TranslationHelper;
|
||||
use gipfl\Web\Form;
|
||||
use Icinga\Module\Director\Data\Db\DbObjectStore;
|
||||
use Icinga\Module\Director\Import\Sync;
|
||||
use Icinga\Module\Director\Objects\SyncRule;
|
||||
use Icinga\Module\Director\Web\Form\DirectorForm;
|
||||
|
||||
class SyncRunForm extends Form
|
||||
class SyncRunForm extends DirectorForm
|
||||
{
|
||||
use TranslationHelper;
|
||||
|
||||
protected $defaultDecoratorClass = null;
|
||||
|
||||
/** @var ?string */
|
||||
protected $successMessage = null;
|
||||
|
||||
/** @var SyncRule */
|
||||
protected $rule;
|
||||
|
||||
/** @var DbObjectStore */
|
||||
protected $store;
|
||||
|
||||
public function __construct(SyncRule $rule, DbObjectStore $store)
|
||||
public function setSyncRule(SyncRule $rule)
|
||||
{
|
||||
$this->rule = $rule;
|
||||
$this->store = $store;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function assemble()
|
||||
public function setup()
|
||||
{
|
||||
if ($this->store->getBranch()->isBranch()) {
|
||||
$label = sprintf($this->translate('Sync to Branch: %s'), $this->store->getBranch()->getName());
|
||||
} else {
|
||||
$label = $this->translate('Trigger this Sync');
|
||||
}
|
||||
$this->addElement('submit', 'submit', [
|
||||
'label' => $label,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getSuccessMessage()
|
||||
{
|
||||
return $this->successMessage;
|
||||
$this->submitLabel = false;
|
||||
$this->addElement('submit', 'submit', array(
|
||||
'label' => $this->translate('Trigger this Sync'),
|
||||
'decorators' => array('ViewHelper')
|
||||
));
|
||||
}
|
||||
|
||||
public function onSuccess()
|
||||
{
|
||||
$sync = new Sync($this->rule, $this->store);
|
||||
if ($sync->hasModifications()) {
|
||||
if ($sync->apply()) {
|
||||
// and changed
|
||||
$this->successMessage = $this->translate(('Source has successfully been synchronized'));
|
||||
} else {
|
||||
$this->successMessage = $this->translate('Nothing changed, rule is in sync');
|
||||
}
|
||||
$rule = $this->rule;
|
||||
$changed = $rule->applyChanges();
|
||||
|
||||
if ($changed) {
|
||||
$this->setSuccessMessage(
|
||||
$this->translate(('Source has successfully been synchronized'))
|
||||
);
|
||||
} elseif ($rule->get('sync_state') === 'in-sync') {
|
||||
$this->notifySuccess(
|
||||
$this->translate('Nothing changed, rule is in sync')
|
||||
);
|
||||
} else {
|
||||
// Used to be $rule->get('sync_state') === 'in-sync', $changed = $rule->applyChanges();
|
||||
$this->successMessage = $this->translate('Nothing to do, rule is in sync');
|
||||
$this->addError($this->translate('Synchronization failed'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1839,7 +1839,7 @@ msgstr ""
|
||||
"essere basate sui gruppi."
|
||||
|
||||
#: application/forms/IcingaNotificationForm.php:199
|
||||
msgid "Delay until the first notification should be sent"
|
||||
msgid "Delay unless 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 Notifications"
|
||||
msgid "Disable Notificiations"
|
||||
msgstr "Disattivare le notifiche"
|
||||
|
||||
#: application/forms/SettingsForm.php:54
|
||||
@ -3429,7 +3429,7 @@ msgstr "Regole su Unisci"
|
||||
#: application/forms/IcingaScheduledDowntimeRangeForm.php:24
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Might be monday, tuesday or 2016-01-28 - have a look at the documentation for "
|
||||
"Might be, monday, tuesday, 2016-01-28 - have a look at the documentation for "
|
||||
"more examples"
|
||||
msgstr ""
|
||||
"Per esempio lunedí, martedí, 2020-01-28 - consulta la documentazione per "
|
||||
@ -7428,4 +7428,4 @@ msgid "e.g. "
|
||||
msgstr "per es."
|
||||
|
||||
msgid "start using"
|
||||
msgstr "inizia ad utilizzare"
|
||||
msgstr "inizia ad utilizzare"
|
@ -1665,7 +1665,7 @@ msgstr "サービスグループを定義すると、より構造がわかりま
|
||||
"最適です。 通知と許可はグループに基づいている場合があります。"
|
||||
|
||||
#: ../../../../modules/director/application/forms/IcingaNotificationForm.php:196
|
||||
msgid "Delay until the first notification should be sent"
|
||||
msgid "Delay unless 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 Notifications"
|
||||
msgid "Disable Notificiations"
|
||||
msgstr "通知を無効化"
|
||||
|
||||
#: ../../../../modules/director/application/forms/SettingsForm.php:54
|
||||
@ -3058,7 +3058,7 @@ msgstr "マージポリシー"
|
||||
|
||||
#: ../../../../modules/director/application/forms/IcingaTimePeriodRangeForm.php:23
|
||||
msgid ""
|
||||
"Might be monday, tuesday or 2016-01-28 - have a look at the documentation for "
|
||||
"Might be, monday, tuesday, 2016-01-28 - have a look at the documentation for "
|
||||
"more examples"
|
||||
msgstr "monday, tuesday, 2016-01-28といった書式で指定します。"
|
||||
"より多くの例についてはドキュメントを見てください"
|
||||
|
@ -44,16 +44,14 @@ 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 ($attribs) {
|
||||
if (array_key_exists('columns', $attribs)) {
|
||||
$this->setColumns($attribs['columns']);
|
||||
unset($attribs['columns']);
|
||||
}
|
||||
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
|
||||
@ -219,7 +217,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}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,7 +236,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",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -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,20 +26,20 @@ 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'
|
||||
]));
|
||||
|
||||
if ($sentValue !== null && \strlen($sentValue)) {
|
||||
if (\strlen($sentValue)) {
|
||||
$el->getAttributes()->set('value', $sentValue);
|
||||
} elseif ($value !== null && \strlen($value) > 0) {
|
||||
} elseif (\strlen($value) > 0) {
|
||||
$el->getAttributes()->set('value', '__UNCHANGED_VALUE__');
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// Avoid complaints about missing namespace and invalid class name
|
||||
// @codingStandardsIgnoreStart
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
<?php
|
||||
|
||||
use Icinga\Application\Modules\Manager;
|
||||
|
||||
?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
<h1><?= $this->escape($this->title) ?></h1>
|
||||
|
@ -1,99 +1,72 @@
|
||||
<?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 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'));
|
||||
$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/*', $this->translate('Allow unrestricted access to Icinga Director'));
|
||||
|
||||
$monitoringExists = Module::exists('monitoring');
|
||||
$icingadbExists = Module::exists('icingadb');
|
||||
$this->provideRestriction(
|
||||
'director/filter/hostgroups',
|
||||
$this->translate(
|
||||
'Limit access to the given comma-separated list of hostgroups'
|
||||
)
|
||||
);
|
||||
$this->providePermission(
|
||||
'director/groups-for-restricted-hosts',
|
||||
$this->translate('Allow users with Hostgroup restrictions to access the Groups field')
|
||||
);
|
||||
|
||||
$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->provideRestriction(
|
||||
'director/service/apply/filter-by-name',
|
||||
$this->translate(
|
||||
'Filter available service apply rules'
|
||||
)
|
||||
);
|
||||
|
||||
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/notification/apply/filter-by-name',
|
||||
$this->translate(
|
||||
'Filter available notification 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'
|
||||
));
|
||||
}
|
||||
|
||||
if ($monitoringExists) {
|
||||
$this->provideRestriction(Restriction::MONITORING_RW_OBJECT_FILTER, $this->translate(
|
||||
'Additional (monitoring module) object filter to further restrict write access'
|
||||
));
|
||||
}
|
||||
|
||||
if ($icingadbExists) {
|
||||
$this->provideRestriction(Restriction::ICINGADB_RW_OBJECT_FILTER, $this->translate(
|
||||
'Additional (Icinga DB Web) object filter to further restrict write access'
|
||||
));
|
||||
}
|
||||
|
||||
$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->provideRestriction(
|
||||
'director/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);
|
||||
|
||||
@ -110,10 +83,10 @@ $this->provideRestriction(
|
||||
);
|
||||
*/
|
||||
|
||||
$this->provideConfigTab('config', [
|
||||
$this->provideConfigTab('config', array(
|
||||
'title' => 'Configuration',
|
||||
'url' => 'settings'
|
||||
]);
|
||||
));
|
||||
$mainTitle = N_('Icinga Director');
|
||||
|
||||
try {
|
||||
@ -140,38 +113,41 @@ try {
|
||||
$mainTitle .= ' (?!)';
|
||||
}
|
||||
|
||||
// Hint: director/admin and director/deployments are intentionally
|
||||
$section = $this->menuSection($mainTitle)
|
||||
->setUrl('director')
|
||||
->setPriority(60)
|
||||
->setIcon('cubes')
|
||||
->setRenderer(['SummaryNavigationItemRenderer', 'state' => 'critical']);
|
||||
$section = $this->menuSection(
|
||||
$mainTitle
|
||||
)->setUrl('director')->setPriority(60)->setIcon(
|
||||
'cubes'
|
||||
)->setRenderer(array(
|
||||
'SummaryNavigationItemRenderer',
|
||||
'state' => 'critical'
|
||||
));
|
||||
|
||||
$section->add(N_('Hosts'))
|
||||
->setUrl('director/dashboard?name=hosts')
|
||||
->setPermission(Permission::HOSTS)
|
||||
->setPermission('director/hosts')
|
||||
->setPriority(30);
|
||||
$section->add(N_('Services'))
|
||||
->setUrl('director/dashboard?name=services')
|
||||
->setPermission(Permission::SERVICES)
|
||||
->setPermission('director/services')
|
||||
->setPriority(40);
|
||||
$section->add(N_('Commands'))
|
||||
->setUrl('director/dashboard?name=commands')
|
||||
->setPermission(Permission::ADMIN)
|
||||
->setPermission('director/admin')
|
||||
->setPriority(50);
|
||||
$section->add(N_('Notifications'))
|
||||
->setUrl('director/dashboard?name=notifications')
|
||||
->setPermission(Permission::NOTIFICATIONS)
|
||||
->setPermission('director/notifications')
|
||||
->setPriority(70);
|
||||
$section->add(N_('Automation'))
|
||||
->setUrl('director/importsources')
|
||||
->setPermission(Permission::ADMIN)
|
||||
->setPermission('director/admin')
|
||||
->setPriority(901);
|
||||
$section->add(N_('Activity log'))
|
||||
->setUrl('director/config/activities')
|
||||
->setPriority(902)
|
||||
->setPermission(Permission::AUDIT)
|
||||
->setPermission('director/audit')
|
||||
->setRenderer('ConfigHealthItemRenderer');
|
||||
$section->add(N_('Deployments'))
|
||||
->setUrl('director/config/deployments')
|
||||
->setPriority(902)
|
||||
->setPermission(Permission::DEPLOYMENTS);
|
||||
->setPermission('director/deployments');
|
||||
|
@ -1,75 +1,147 @@
|
||||
<!-- {% if index %} -->
|
||||
# Installing Icinga Director
|
||||
<a id="Installation"></a>Installation
|
||||
=====================================
|
||||
|
||||
The recommended way to install Icinga Director and its dependencies is to use prebuilt packages for
|
||||
all supported platforms from our official release repository.
|
||||
Please note that [Icinga Web](https://icinga.com/docs/icinga-web) is required to run Icinga Director
|
||||
and if it is not already set up, it is best to do this first.
|
||||
These are the instructions for manual Director installations. You can
|
||||
learn more about how to automate this in the [automation](03-Automation.md) section
|
||||
of this documentation. In case you already installed Director and want to upgrade
|
||||
to the latest version, please [read on here](05-Upgrading.md).
|
||||
|
||||
The following steps will guide you through installing and setting up Icinga Director.
|
||||
Requirements
|
||||
------------
|
||||
|
||||
To upgrade an existing Icinga Director installation to a newer version,
|
||||
see the [upgrading](05-Upgrading.md) documentation for the necessary steps.
|
||||
* Icinga 2 (>= 2.6.0)
|
||||
* It is recommended to use the latest feature release of Icinga 2
|
||||
* All versions since 2.4.3 should also work fine, but
|
||||
we do no longer test and support them.
|
||||
* Some features require newer Icinga 2 releases
|
||||
* Flapping requires 2.8 for the thresholds to work - and at least 2.7 on all
|
||||
nodes
|
||||
* Icinga Web 2 (>= 2.6.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:
|
||||
* [ipl](https://github.com/Icinga/icingaweb2-module-ipl) (>=0.3.0)
|
||||
* [incubator](https://github.com/Icinga/icingaweb2-module-incubator) (>=0.21.0)
|
||||
* [reactbundle](https://github.com/Icinga/icingaweb2-module-reactbundle) (>=0.7.0)
|
||||
* A database, MySQL (>= 5.1) or PostgreSQL (>= 9.1). MariaDB and other
|
||||
MySQL forks are also fine. Mentioned versions are the required minimum,
|
||||
for MySQL we suggest using at least 5.5.3, for PostgreSQL 9.4.
|
||||
* PHP (>= 5.6.3). For best performance please consider use 7.x or 8.x
|
||||
* php-pdo-mysql and/or php-pdo-pgsql
|
||||
* php-curl
|
||||
* php-iconv
|
||||
* php-pcntl (might already be built into your PHP binary)
|
||||
* php-posix (on RHEL/CentOS this is php-process, or rh-php7x-php-process)
|
||||
* php-sockets (might already be built into your PHP binary)
|
||||
* php-mbstring and php-json (already required by Icinga Web 2)
|
||||
|
||||
If you want to automate the installation, configuration and upgrade,
|
||||
you can learn more about it in the [automation](03-Automation.md) section of this documentation.
|
||||
Optional Requirements
|
||||
---------------------
|
||||
* For IBM DB2 Imports: php-pdo-ibm
|
||||
* For MSSQL Imports: php-mssql or php-pdo-dblib (or -sybase on some platforms)
|
||||
* For Oracle DB Imports: php-oci8 or php-pdo-oci
|
||||
* For Sqlite Imports: php-pdo-sqlite
|
||||
|
||||
## Optional Requirements
|
||||
Database
|
||||
--------
|
||||
|
||||
The following requirements are not necessary for installation,
|
||||
but may be needed later if you want to import from one of the listed sources:
|
||||
### Create an empty Icinga Director database
|
||||
|
||||
* For **IBM Db2** imports: `php-pdo-ibm`
|
||||
* For **Microsoft SQL Server** imports: `php-mssql`, `php-pdo-dblib` or `php-sybase` depending on your platform
|
||||
* For **Oracle Database** imports: `php-oci8` or `php-pdo-oci` depending on your platform
|
||||
* For **SQLite** imports: `php-pdo-sqlite`
|
||||
<!-- {% else %} -->
|
||||
<!-- {% if not icingaDocs %} -->
|
||||
HINT: You should replace `some-password` with a secure custom password.
|
||||
|
||||
## Installing Icinga Director Package
|
||||
#### MySQL (or MariaDB)
|
||||
|
||||
If the [repository](https://packages.icinga.com) is not configured yet, please add it first.
|
||||
Then use your distribution's package manager to install the `icinga-director` package
|
||||
or install [from source](02-Installation.md.d/From-Source.md).
|
||||
<!-- {% endif %} -->
|
||||
mysql -e "CREATE DATABASE director CHARACTER SET 'utf8';
|
||||
CREATE USER director@localhost IDENTIFIED BY 'some-password';
|
||||
GRANT ALL ON director.* TO director@localhost;"
|
||||
|
||||
## Setting up the Database
|
||||
In case your MySQL root user is password-protected, please add `-p` to this
|
||||
command.
|
||||
|
||||
A MySQL (≥5.7), MariaDB (≥10.1), or PostgreSQL (≥9.6) database is required to run Icinga Director.
|
||||
Please follow the steps listed for your target database, to set up the database and the user.
|
||||
The schema will be imported later via the web interface.
|
||||
#### PostgreSQL
|
||||
|
||||
### Setting up a MySQL or MariaDB Database
|
||||
|
||||
> **Warning**
|
||||
> Make sure to replace `CHANGEME` with a secure password.
|
||||
psql -q -c "CREATE DATABASE director WITH ENCODING 'UTF8';"
|
||||
psql director -q -c "CREATE USER director WITH PASSWORD 'some-password';
|
||||
GRANT ALL PRIVILEGES ON DATABASE director TO director;
|
||||
CREATE EXTENSION pgcrypto;"
|
||||
|
||||
```
|
||||
mysql -e "CREATE DATABASE director CHARACTER SET 'utf8';
|
||||
CREATE USER director@localhost IDENTIFIED BY 'CHANGEME';
|
||||
GRANT ALL ON director.* TO director@localhost;"
|
||||
```
|
||||
Hint: pgcrypto helps to boost performance, but is currently optional. In case you
|
||||
do not have it available on your platform and/or do not know how to solve this
|
||||
just leave away the 'CREATE EXTENSION' part.
|
||||
|
||||
### Setting up a PostgreSQL Database
|
||||
Web-based Configuration
|
||||
-----------------------
|
||||
|
||||
> **Warning**
|
||||
> Make sure to replace `CHANGEME` with a secure password.
|
||||
The following steps should guide you through the web-based Kickstart wizard.
|
||||
In case you prefer automated configuration, you should check the dedicated
|
||||
[documentation section](03-Automation.md).
|
||||
|
||||
```
|
||||
psql -q -c "CREATE DATABASE director WITH ENCODING 'UTF8';"
|
||||
psql director -q -c "CREATE USER director WITH PASSWORD 'CHANGEME';
|
||||
GRANT ALL PRIVILEGES ON DATABASE director TO director;
|
||||
CREATE EXTENSION pgcrypto;"
|
||||
```
|
||||
### Create a Database resource
|
||||
|
||||
## Configuring Icinga Director
|
||||
In your web frontend please go to `Configuration / Application / Resources`
|
||||
and create a new database resource pointing to your newly created database.
|
||||
Please make sure that you choose `utf8` as an encoding.
|
||||
|
||||
Log in to your running Icinga Web setup with a privileged user
|
||||
and follow the steps below to configure Icinga Director:
|
||||
|
||||
1. Create a new resource for the Icinga Director [database](#setting-up-the-database) via the
|
||||
`Configuration → Application → Resources` menu.
|
||||
Please make sure that you configure `utf8` as encoding.
|
||||
2. Select `Icinga Director` directly from the main menu
|
||||
and you will be taken to the kickstart wizard. Follow the instructions and you are done!
|
||||
<!-- {% endif %} --><!-- {# end else if index #} -->
|
||||
### Install the Director module
|
||||
|
||||
As with any Icinga Web 2 module, installation is pretty straight-forward. In
|
||||
case you're installing it from source all you have to do is to drop the director
|
||||
module in one of your module paths. You can examine (and set) the module path(s)
|
||||
in `Configuration / Application`. In a typical environment you'll probably drop the
|
||||
module to `/usr/share/icingaweb2/modules/director`. Please note that the directory
|
||||
name MUST be `director` and not `icingaweb2-module-director` or anything else.
|
||||
|
||||
#### Installation from release tarball
|
||||
|
||||
Download the [latest version](https://github.com/Icinga/icingaweb2-module-director/releases)
|
||||
and extract it to a folder named `director` in one of your Icinga Web 2 module path directories.
|
||||
|
||||
You might want to use a script as follows for this task:
|
||||
|
||||
ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules"
|
||||
REPO_URL="https://github.com/icinga/icingaweb2-module-director"
|
||||
TARGET_DIR="${ICINGAWEB_MODULEPATH}/director"
|
||||
MODULE_VERSION="1.8.2"
|
||||
URL="${REPO_URL}/archive/v${MODULE_VERSION}.tar.gz"
|
||||
install -d -m 0755 "${TARGET_DIR}"
|
||||
wget -q -O - "$URL" | tar xfz - -C "${TARGET_DIR}" --strip-components 1
|
||||
|
||||
Proceed to enabling the module.
|
||||
|
||||
#### Installation from GIT repository
|
||||
|
||||
Another convenient method is the installation directly from our GIT repository.
|
||||
Just clone the repository to one of your Icinga Web 2 module path directories.
|
||||
It will be immediately ready for use:
|
||||
|
||||
|
||||
ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules"
|
||||
REPO_URL="https://github.com/icinga/icingaweb2-module-director"
|
||||
TARGET_DIR="${ICINGAWEB_MODULEPATH}/director"
|
||||
MODULE_VERSION="1.8.2"
|
||||
git clone "${REPO_URL}" "${TARGET_DIR}" --branch v${MODULE_VERSION}
|
||||
|
||||
You can now directly use our current GIT master or check out a specific version.
|
||||
|
||||
cd "${TARGET_DIR}" && git checkout "v${MODULE_VERSION}"
|
||||
|
||||
Proceed to enabling the module.
|
||||
|
||||
#### Enable the newly installed module
|
||||
|
||||
Enable the `director` module either on the CLI by running
|
||||
|
||||
icingacli module enable director
|
||||
|
||||
Or go to your Icinga Web 2 frontend, choose `Configuration / Modules`,
|
||||
select the `director` module and choose `State: enable`.
|
||||
|
||||
### Run the graphical kickstart wizard
|
||||
|
||||
Choose either `Icinga Director` directly from the main menu or
|
||||
navigate into `Configuration / Modules / director` and select the `Configuration`
|
||||
tab.
|
||||
|
||||
Either way you'll reach the kickstart wizards. Follow the instructions and
|
||||
you're all done!
|
||||
|
@ -1,83 +0,0 @@
|
||||
# Installing Icinga Director from Source
|
||||
|
||||
These are the instructions for manual Director installations.
|
||||
|
||||
Please see the Icinga Web documentation on
|
||||
[how to install modules](https://icinga.com/docs/icinga-web-2/latest/doc/08-Modules/#installation) from source.
|
||||
Make sure you use `director` as the module name. The following requirements must also be met.
|
||||
|
||||
## Requirements
|
||||
|
||||
* PHP (≥7.3)
|
||||
* Director v1.10 is the last version with support for PHP v5.6
|
||||
* [Icinga 2](https://github.com/Icinga/icinga2) (≥2.8.0)
|
||||
* It is recommended to use the latest feature release of Icinga 2
|
||||
* All versions since 2.4.3 should also work fine, but
|
||||
we do no longer test and support them.
|
||||
* Some features require newer Icinga 2 releases
|
||||
* Flapping requires 2.8 for the thresholds to work - and at least 2.7 on all
|
||||
nodes
|
||||
* [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.22.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)
|
||||
* A database: MariaDB (≥10.1), MySQL (≥5.7), PostgreSQL (≥9.6). Other
|
||||
forks and older versions might work, but are neither tested nor supported
|
||||
* `php-pdo-mysql` and/or `php-pdo-pgsql`
|
||||
* `php-curl`
|
||||
* `php-iconv`
|
||||
* `php-pcntl` (might already be built into your PHP binary)
|
||||
* `php-posix` or `php-process` depending on your platform
|
||||
* `php-sockets` (might already be built into your PHP binary)
|
||||
|
||||
## Installing from Release Tarball
|
||||
|
||||
Download the [latest version](https://github.com/Icinga/icingaweb2-module-director/releases)
|
||||
and extract it to a folder named `director` in one of your Icinga Web module path directories.
|
||||
|
||||
You might want to use a script as follows for this task:
|
||||
|
||||
```shell
|
||||
MODULE_VERSION="1.11.4"
|
||||
ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules"
|
||||
REPO_URL="https://github.com/icinga/icingaweb2-module-director"
|
||||
TARGET_DIR="${ICINGAWEB_MODULEPATH}/director"
|
||||
URL="${REPO_URL}/archive/v${MODULE_VERSION}.tar.gz"
|
||||
|
||||
install -d -m 0755 "${TARGET_DIR}"
|
||||
wget -q -O - "$URL" | tar xfz - -C "${TARGET_DIR}" --strip-components 1
|
||||
icingacli module enable director
|
||||
```
|
||||
|
||||
## Installing from Git Repository
|
||||
|
||||
Another convenient method is to install directly from our Git repository.
|
||||
Simply clone the repository in one of your Icinga web module path directories.
|
||||
|
||||
You might want to use a script as follows for this task:
|
||||
|
||||
```shell
|
||||
MODULE_VERSION="1.11.4"
|
||||
ICINGAWEB_MODULEPATH="/usr/share/icingaweb2/modules"
|
||||
REPO_URL="https://github.com/icinga/icingaweb2-module-director"
|
||||
TARGET_DIR="${ICINGAWEB_MODULEPATH}/director"
|
||||
|
||||
git clone "${REPO_URL}" "${TARGET_DIR}" --branch v${MODULE_VERSION}
|
||||
icingacli module enable director
|
||||
```
|
||||
|
||||
## Setting up the Director Daemon
|
||||
|
||||
For manual installations, the daemon user, its directory, and the systemd service need to be set up:
|
||||
|
||||
```shell
|
||||
useradd -r -g icingaweb2 -d /var/lib/icingadirector -s /sbin/nologin icingadirector
|
||||
install -d -o icingadirector -g icingaweb2 -m 0750 /var/lib/icingadirector
|
||||
install -pm 0644 contrib/systemd/icinga-director.service /etc/systemd/system
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now icinga-director
|
||||
```
|
||||
<!-- {% include "02-Installation.md" %} -->
|
@ -5,7 +5,7 @@ Icinga Director is very upgrade-friendly. We never had any complaint referring
|
||||
data loss on upgrade. But to be on the safe side, please always [backup](#backup-first)
|
||||
your database before running an upgrade.
|
||||
|
||||
Then drop the new version to your Icinga Web 2 module folder, and you're all done.
|
||||
Then drop the new version to your Icinga Web 2 module folder and you're all done.
|
||||
Eventually refresh the page in your browser<sup>[[1]](#footnote1)</sup>, and you
|
||||
are ready to go.
|
||||
|
||||
@ -15,9 +15,6 @@ 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)
|
||||
* [Upgrading to 1.7.x](#upgrade-to-1.7.x)
|
||||
* [Upgrading to 1.6.x](#upgrade-to-1.6.x)
|
||||
@ -42,36 +39,11 @@ 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.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.22.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
|
||||
one of them, the Web UI will tell you after the upgrade. You'll then be prompted
|
||||
to apply pending Database Migrations.
|
||||
|
||||
PHP 7.3 is now claimed to be required, but we still support 5.6+ on Director
|
||||
v1.10.x. Same goes for database dependencies: you should upgrade them to recent
|
||||
versions, but v1.10 still works on the ones supported with v1.9.x.
|
||||
|
||||
<a name="upgrade-to-1.9.x"></a>Upgrading to 1.9.x
|
||||
-------------------------------------------------
|
||||
|
||||
Please check module dependencies, we raised some of them. In case you're missing
|
||||
one of them, the Web UI will tell you after the upgrade. You'll then be prompted
|
||||
to apply pending Database Migrations.
|
||||
|
||||
<a name="upgrade-to-1.8.x"></a>Upgrading to 1.8.x
|
||||
-------------------------------------------------
|
||||
|
||||
Before upgrading, please upgrade the [incubator module](https://github.com/Icinga/icingaweb2-module-incubator)
|
||||
to (at least) v0.6.0. As always, you'll be prompted to apply pending Database
|
||||
to (at least) v0.21.0. As always, you'll be prompted to apply pending Database
|
||||
Migrations.
|
||||
|
||||
<a name="upgrade-to-1.7.x"></a>Upgrading to 1.7.x
|
||||
|
@ -94,7 +94,7 @@ slightly to fit ITL Commands in case you're using those (snmpv3_*_type VS _alg).
|
||||
Your Cisco Health checks assigned to all:
|
||||
|
||||
* routers or switches
|
||||
* manufactured by Cisco
|
||||
* manifactured by Cisco
|
||||
* with SNMP credentials, regardless of which version
|
||||
|
||||
...might then look as follows:
|
||||
|
@ -75,12 +75,6 @@ icingacli director host create localhost \
|
||||
--json '{ "address": "127.0.0.1", "vars": { "test": [ "one", "two" ] } }'
|
||||
```
|
||||
|
||||
Passing JSON via STDIN is also possible:
|
||||
|
||||
```shell
|
||||
icingacli director host create localhost --json < my-host.json
|
||||
```
|
||||
|
||||
|
||||
### Delete a specific object
|
||||
|
||||
@ -132,18 +126,17 @@ Use this command to modify specific properties of an existing Icinga object.
|
||||
|
||||
#### Options
|
||||
|
||||
| Option | Description |
|
||||
|----------------------------|-------------------------------------------------------|
|
||||
| `--<key> <value>` | Provide all properties as single command line options |
|
||||
| `--append-<key> <value>` | Appends to array values, like `imports`, |
|
||||
| | `groups` or `vars.system_owners` |
|
||||
| `--remove-<key> [<value>]` | Remove a specific property, eventually only |
|
||||
| | when matching `value`. In case the property is an |
|
||||
| | array it will remove just `value` when given |
|
||||
| `--json` | Otherwise provide all options as a JSON string |
|
||||
| `--replace` | Replace all object properties with the given ones |
|
||||
| `--auto-create` | Create the object in case it does not exist |
|
||||
| `--allow-overrides` | Set variable overrides for virtual Services |
|
||||
| Option | Description |
|
||||
|-------------------|-------------------------------------------------------|
|
||||
| `--<key> <value>` | Provide all properties as single command line options |
|
||||
| `--append-<key> <value>` | Appends to array values, like `imports`, |
|
||||
| | `groups` or `vars.system_owners` |
|
||||
| `--remove-<key> [<value>]` | Remove a specific property, eventually only |
|
||||
| | when matching `value`. In case the property is an |
|
||||
| | array it will remove just `value` when given |
|
||||
| `--json` | Otherwise provide all options as a JSON string |
|
||||
| `--replace` | Replace all object properties with the given ones |
|
||||
| `--auto-create` | Create the object in case it does not exist |
|
||||
|
||||
|
||||
#### Examples
|
||||
@ -191,16 +184,16 @@ in JSON format.
|
||||
|
||||
#### Options
|
||||
|
||||
| Option | Description |
|
||||
|-------------------|------------------------------------------------------|
|
||||
| `--resolved` | Resolve all inherited properties and show a flat |
|
||||
| | object |
|
||||
| `--json` | Use JSON format |
|
||||
| `--no-pretty` | JSON is pretty-printed per default (for PHP >= 5.4) |
|
||||
| | Use this flag to enforce unformatted JSON |
|
||||
| `--no-defaults` | Per default JSON output skips null or default values |
|
||||
| | With this flag you will get all properties |
|
||||
| `--with-services` | For hosts only, also shows attached services |
|
||||
| Option | Description |
|
||||
|-----------------|---------------------------------------------------------|
|
||||
| `--resolved` | Resolve all inherited properties and show a flat object |
|
||||
| | object |
|
||||
| `--json` | Use JSON format |
|
||||
| `--no-pretty` | JSON is pretty-printed per default (for PHP >= 5.4) |
|
||||
| | Use this flag to enforce unformatted JSON |
|
||||
| `--no-defaults` | Per default JSON output skips null or default values |
|
||||
| | With this flag you will get all properties |
|
||||
|
||||
|
||||
### Clone an existing object
|
||||
|
||||
@ -288,7 +281,7 @@ on this object would have been removed.
|
||||
|
||||
The Icinga Director distincts between the following object types:
|
||||
|
||||
| Type | Description |
|
||||
| Type | Description
|
||||
|-------------------|-------------------------------------------------------------|
|
||||
| `object` | The default object type. A host, a command and similar |
|
||||
| `template` | An Icinga template |
|
||||
@ -463,22 +456,7 @@ Config with checksum b330febd0820493fb12921ad8f5ea42102a5c871 already exists
|
||||
|
||||
### Config deployment
|
||||
|
||||
#### Usage
|
||||
|
||||
`icingacli director config deploy [options]`
|
||||
|
||||
#### Options
|
||||
|
||||
| Option | Description |
|
||||
|----------------------------|------------------------------------------------------------------|
|
||||
| `--checksum <checksum>` | Optionally deploy a specific configuration |
|
||||
| `--force` | Force a deployment, even when the configuration hasn't changed |
|
||||
| `--wait <seconds>` | Optionally wait until Icinga completed it's restart |
|
||||
| `--grace-period <seconds>` | Do not deploy if a deployment took place less than <seconds> ago |
|
||||
|
||||
#### Examples
|
||||
|
||||
You do not need to explicitly render your config before deploying it to your
|
||||
You do not need to explicitely render your config before deploying it to your
|
||||
Icinga 2 master node. Just trigger a deployment, it will re-render the current
|
||||
config:
|
||||
|
||||
@ -512,13 +490,6 @@ version the `deploy` command allows you to provide a specific checksum:
|
||||
icingacli director config deploy --checksum b330febd0820493fb12921ad8f5ea42102a5c871
|
||||
```
|
||||
|
||||
When using `icingacli` deployments in an automated way, and want to avoid fast
|
||||
consecutive deployments, you can provide a grace period:
|
||||
|
||||
```shell
|
||||
icingacli director config deploy --grace-period 300
|
||||
```
|
||||
|
||||
### Deployments status
|
||||
In case you want to fetch the information about the deployments status,
|
||||
you can call the following CLI command:
|
||||
|
@ -39,15 +39,12 @@ URL scheme and supported methods
|
||||
|
||||
We support GET, POST, PUT and DELETE.
|
||||
|
||||
| Method | Meaning |
|
||||
|--------|---------------------------------------------------------------------|
|
||||
| GET | Read / fetch data. Not allowed to run operations with the potential |
|
||||
| | to cause any harm |
|
||||
| POST | Trigger actions, create or modify objects. Can also be used to |
|
||||
| | partially modify objects |
|
||||
| PUT | Creates or replaces objects, cannot be used to modify single object |
|
||||
| | properties |
|
||||
| DELETE | Remove a specific object |
|
||||
| Method | Meaning
|
||||
| ------ | ------------------------------------------------------------
|
||||
| GET | Read / fetch data. Not allowed to run operations with the potential to cause any harm
|
||||
| POST | Trigger actions, create or modify objects. Can also be used to partially modify objects
|
||||
| PUT | Creates or replaces objects, cannot be used to modify single object properties
|
||||
| DELETE | Remove a specific object
|
||||
|
||||
TODO: more examples showing the difference between POST and PUT
|
||||
|
||||
@ -116,37 +113,23 @@ Icinga Objects
|
||||
|
||||
### Special parameters
|
||||
|
||||
| Parameter | Description |
|
||||
|----------------|-------------------------------------------------------------|
|
||||
| resolved | Resolve all inherited properties and show a flat object |
|
||||
| withNull | Retrieve default (null) properties also |
|
||||
| withServices | Show services attached to a host. `resolved` and `withNull` |
|
||||
| | are applied for services too |
|
||||
| allowOverrides | Set variable overrides for virtual Services |
|
||||
| showStacktrace | Returns the related stack trace, in case an error occurs |
|
||||
|
||||
#### Resolve object properties
|
||||
|
||||
In case you add the `resolved` parameter to your URL, all inherited object
|
||||
In case you add the `resolve` parameter to your URL, all inherited object
|
||||
properties will be resolved. Such a URL could look as follows:
|
||||
|
||||
director/host?name=hostname.example.com&resolved
|
||||
|
||||
|
||||
#### Retrieve default (null) properties also
|
||||
#### Retrieve all properties
|
||||
|
||||
TODO: adjust the code to fix this, current implementation has `withNull`
|
||||
|
||||
Per default properties with `null` value are skipped when shipping a result.
|
||||
You can influence this behavior with the `properties` parameter. Just append
|
||||
`&withNull` to your URL:
|
||||
You can influence this behavior with the properties parameter. Just append
|
||||
`properties=ALL` to your URL:
|
||||
|
||||
director/host?name=hostname.example.com&withNull
|
||||
|
||||
|
||||
#### Fetch host with it's services
|
||||
|
||||
This is what the `withServices` parameter exists:
|
||||
|
||||
director/host?name=hostname.example.com&withServices
|
||||
director/host?name=hostname.example.com&properties=all
|
||||
|
||||
|
||||
#### Retrieve only specific properties
|
||||
@ -158,23 +141,6 @@ when they have no (`null`) value:
|
||||
director/host?name=hostname.example.com&properties=object_name,address,vars
|
||||
|
||||
|
||||
#### Override vars for inherited/applied Services
|
||||
|
||||
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&allowOverrides
|
||||
|
||||
```json
|
||||
{ "vars.uptime_warning": 300 }
|
||||
```
|
||||
|
||||
In case `Uptime` is an Apply Rule, calling this without `allowOverrides` will
|
||||
trigger a 404 response. Please note that when modifying the Host object, the
|
||||
body for response 200 will show the Host object, as that's the one that has
|
||||
been modified.
|
||||
|
||||
### Example
|
||||
|
||||
GET director/host?name=pe2015.example.com
|
||||
@ -257,7 +223,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 +526,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?configs=617b9cbad9e141cfc3f4cb636ec684bd60073be2,
|
||||
617b9cbad9e141cfc3f4cb636ec684bd60073be1&activitiess=617b9cbad9e141cfc3f4cb636ec684bd60073be1,
|
||||
GET director/config/deployment-status?config_checksums=617b9cbad9e141cfc3f4cb636ec684bd60073be2,
|
||||
617b9cbad9e141cfc3f4cb636ec684bd60073be1&activity_log_checksums=617b9cbad9e141cfc3f4cb636ec684bd60073be1,
|
||||
028b3a19ca7457f5fc9dbb5e4ea527eaf61616a2
|
||||
|
||||
```json
|
||||
|
@ -4,495 +4,12 @@
|
||||
Please make sure to always read our [Upgrading](05-Upgrading.md) documentation
|
||||
before switching to a new version.
|
||||
|
||||
v1.11.4
|
||||
-------
|
||||
|
||||
### Security
|
||||
|
||||
- Rest API endpoints accessible to restricted users ([GHSA-3233-ggc5-m3qg](https://github.com/Icinga/icingaweb2-module-director/security/advisories/GHSA-3233-ggc5-m3qg))
|
||||
1.8.2
|
||||
-----
|
||||
|
||||
### UI
|
||||
|
||||
- Fix editing of custom variables for multi-selected objects [#2950](https://github.com/Icinga/icingaweb2-module-director/issues/2950)
|
||||
- Fix: Check for the existence of service templates to add services [#1249](https://github.com/Icinga/icingaweb2-module-director/issues/1249)
|
||||
|
||||
### Import and Sync
|
||||
|
||||
- Fix erratic job behavior during summer and winter time change (no issue)
|
||||
|
||||
### Integration
|
||||
|
||||
- Fix custom variable renderer for service apply for rules (no issue)
|
||||
- Fix custom variable renderer for array type data lists [#2960](https://github.com/Icinga/icingaweb2-module-director/issues/2960)
|
||||
|
||||
### Database Schema
|
||||
|
||||
- Fix MySQL 8.4 nonstandard foreign keys deprecation [#2885](https://github.com/Icinga/icingaweb2-module-director/issues/2885)
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
You can find issues related to this release on our [roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/39?closed=1)
|
||||
|
||||
v1.11.3
|
||||
-------
|
||||
|
||||
### UI
|
||||
* FIX: Property sort tables does not cause CSRF token validation anymore (#2937)
|
||||
* FIX: No error when clicking `modify` action link for services belonging to service set in Icinga DB (#2938)
|
||||
* FIX: No crashing of Host template form when invalid check command is entered (#2941)
|
||||
|
||||
### Internals
|
||||
* FIX: Filter can be now removed in import source modifiers (#2939)
|
||||
|
||||
v1.11.2
|
||||
-------
|
||||
|
||||
### UI
|
||||
* FIX: No more errors when changing import source modifier priorities (#2270)
|
||||
* FIX: Choosing `HTTP proxy` in import source type `REST API` no longer causes deprecation notice (#2889)
|
||||
* FIX: Deleting data lists when using PostgreSQL as backend no longer yields errors (#2913)
|
||||
* FIX: Previewing sync rules with boolean properties now functions without errors (#2905)
|
||||
* FIX: Basket snapshots correctly display content if present (#2901)
|
||||
* FIX: Time periods now include `Add to basket` functionality (#2542)
|
||||
|
||||
### API
|
||||
* FIX: API updates for notifications return 304 instead of 200 when unchanged (#2882)
|
||||
|
||||
### Internals
|
||||
* FIX: The `apply_changes` setting from sync jobs restored from a basket is applied properly (#2904)
|
||||
* FIX: The `Get host by name (DNS lookup)` modifier handles failed lookups without errors (#2877)
|
||||
|
||||
### Director Branches
|
||||
* FIX: Cloning a host retains its services and service sets (#2897)
|
||||
* FIX: Service sets are now clonable (#2890)
|
||||
|
||||
### Integrations
|
||||
* Show Director labels in monitoring module and Icinga DB custom vars section (#2239)
|
||||
|
||||
### Fixed issues
|
||||
* You can find issues and feature requests related to this release on our
|
||||
[roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/36?closed=1)
|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
Behind the scenes, some Icinga DSL assures that Icinga behaves as expected:
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
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
|
||||
-------
|
||||
|
||||
This is a minor bugfix release, addressing some Sync-related issues: purge for
|
||||
objects with uppercase characters now works as expected, automated Sync jobs run
|
||||
again, and manually triggered Sync has been fixed on PostgreSQL.
|
||||
|
||||
Some UI glitches have been addressed, and a few problems appearing only in
|
||||
certain conditions - related to Configuration Baskets, our Self Service REST API
|
||||
and the Activity Log.
|
||||
|
||||
### Fixed issues
|
||||
* You can find issues and feature requests related to this release on our
|
||||
[roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/31?closed=1)
|
||||
|
||||
### UI
|
||||
* FEATURE: improve Service Set table layout (#2648)
|
||||
* FIX: modifying single time-period ranges had no effect (#2525)
|
||||
* FIX: activity log pagination is now on a single line (#2649)
|
||||
|
||||
### Import and Sync
|
||||
* FIX: triggering Sync manually produced an error on PostgreSQL (#2636)
|
||||
* FIX: purge stopped working for objects with uppercase characters (#2627)
|
||||
* FIX: Notification Apply rule is now possible (wasn't since v1.8) (#2142, #2634)
|
||||
* FIX: nested property access with intermediate NULL values now gives NULL (#2474, #2584)
|
||||
* FIX: automated Sync jobs stopped working (#2633)
|
||||
|
||||
### Configuration Baskets
|
||||
* FEATURE: more details shown in error messages related to invalid characters (#2646)
|
||||
* FIX: snapshots for Baskets containing Baskets failed since v1.10 (#2644)
|
||||
|
||||
### REST API
|
||||
* FIX: Self Service API returned invalid JSON on PHP 8.1 (#2614)
|
||||
|
||||
### Internals
|
||||
* FIX: issue with empty activity log, deprecate outdated method (#2630)
|
||||
|
||||
v1.10.1
|
||||
-------
|
||||
|
||||
This is a minor bugfix release, addressing issues with modifying services via
|
||||
the monitoring module, Sync problems and a copy and paste error in the DB schema,
|
||||
which caused problems for fresh installations since v1.10.
|
||||
|
||||
Please note that a long-standing issue for our Sync Rules has been fixed: with
|
||||
"merge" policy, NULL properties have been ignored for quite some time. This has
|
||||
now been fixed. If in doubt, please **preview** your Sync Rules to make sure,
|
||||
that they behave as expected.
|
||||
|
||||
This release brings a small schema migration, cleaning up invalid Sync history
|
||||
entries. If in doubt, please create a [database backup](05-Upgrading.md#backup-first) first.
|
||||
|
||||
### Fixed issues
|
||||
* You can find issues and feature requests related to this release on our
|
||||
[roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/30?closed=1)
|
||||
|
||||
### Import and Sync
|
||||
* FIX: sync lower-cased all object names since v1.10 (#2608)
|
||||
* FIX: sync for Datalist entries has been fixed (#2618)
|
||||
* FIX: Sync now applied NULL values with merge policy (#2623)
|
||||
* FIX: Sync created Sync History entries for every preview (#2632)
|
||||
* FIX: "Purge" stopped working for Sync (#2627)
|
||||
|
||||
### UI
|
||||
* FIX: "Modify" Services via the monitoring module (#2615, #2619)
|
||||
|
||||
### Configuration Baskets
|
||||
* FIX: restore Import/Sync/Job when exported with v1.10 (#2620)
|
||||
* FIX: restoring Job with ImportSource or SyncRule (#2528)
|
||||
|
||||
### Database Schema
|
||||
* FIX: new DB schema failed due to duplicate line in SQL statement (#2609)
|
||||
|
||||
v1.10.0
|
||||
-------
|
||||
|
||||
An advanced **Sync Preview** is one of the features I'd love to highlight in
|
||||
v1.10.0. We have been able to leverage our Configuration Branch support as
|
||||
an underlying technology for this:
|
||||
|
||||

|
||||
|
||||
In case you have lots of changes, you can browse all of them - formerly this
|
||||
hasn't been possible. Also, this now allows you to inspect every single upcoming
|
||||
change before applying the Sync:
|
||||
|
||||

|
||||
|
||||
This has been possible based on the code we implemented to support the
|
||||
[Director Branches](https://icinga.com/docs/icinga-director-branches/latest/)
|
||||
module. In case you never heard about it,
|
||||
[here](https://icinga.com/blog/2022/07/21/releasing-icinga-director-branches/)
|
||||
you can find the related announcement.
|
||||
|
||||
This release also contains a lot of related fixes and new Features. It is now
|
||||
possible to deal with **Service Sets** in Configuration Branches, the **commit
|
||||
remark** can be proposed with a merge request, and the Activity Log shows not
|
||||
only who has merged the change, but also the **original author**.
|
||||
|
||||
Powerful new features have been implemented for those who love to orchestrate
|
||||
the Director from the outside. Please check our
|
||||
[CLI](https://github.com/Icinga/icingaweb2-module-director/blob/v1.10.0/doc/60-CLI.md)
|
||||
and [REST API](https://github.com/Icinga/icingaweb2-module-director/blob/v1.10.0/doc/70-REST-API.md)
|
||||
documentation for related details, especially look for --with-services (withServices)
|
||||
and --allow-overrides (allowOverrides).
|
||||
|
||||
CLI now supports **JSON on STDIN**, REST API can request detailed stack traces
|
||||
in case an error occurs.
|
||||
|
||||
### Breaking Changes
|
||||
* Module and system dependencies have been raised, [Upgrading](05-Upgrading.md)
|
||||
and [Installation](02-Installation.md) documentations contain related details
|
||||
|
||||
### Fixed issues
|
||||
* You can find issues and feature requests related to this release on our
|
||||
[roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/27?closed=1)
|
||||
|
||||
### User Interface
|
||||
* FIX: links from Service Previews (Icinga DSL) to templates (#2554)
|
||||
* FIX: daemon health visualization on systems w/o /proc filesystem (#2544)
|
||||
|
||||
### Import and Sync
|
||||
* FIX: Sync now compares keys in a case-insensitive way (#2598, #2419, #1140)
|
||||
* FIX: Sync now preserves Self Service API keys in override mode (#2590)
|
||||
* FEATURE: clone a row for nested Dictionary/Hash entries (#2555)
|
||||
* FEATURE: Sync in "override" mode now preserves Self Service API keys (#2590)
|
||||
* FEATURE: split a row in multiple ones, based on a Dictionary (#2555)
|
||||
* FEATURE: it's now possible to sync to a configuration branch (#2552)
|
||||
* FEATURE: Sync preview now allows to navigate single changes (#2607)
|
||||
|
||||
### Configuration Baskets
|
||||
* BREAKING: configuration baskets no longer contain originalId (#2549)
|
||||
* FEATURE: exporting/snapshot-logic has been centralized (#2549)
|
||||
|
||||
### Configuration Branches
|
||||
* FIX: PostgreSQL now allows for the same object in multiple branches (#2605)
|
||||
* FEATURE: merge comments can now be proposed (#2604)
|
||||
* FEATURE: activity log now shows author and committer (#2606)
|
||||
|
||||
### Integrations
|
||||
* FIX: Monitoring Hooks are no longer provided with disable Director UI (#2597)
|
||||
* FIX: cleanup for IcingaDbCube (#2484)
|
||||
|
||||
### Kickstart
|
||||
* FIX: breaking change in ipl/html, affected setups with ro INI files (#2595)
|
||||
* FEATURE: better explanation for missing DSL bodies fetched from core (#2557)
|
||||
|
||||
### REST API
|
||||
* FIX: addressing service templates by name has been fixed (#2487)
|
||||
* FIX: allow for object_name in body only (#2576)
|
||||
* FIX: notice on PHP 8.1 (#2575)
|
||||
* FEATURE: Stack traces can now be requested (#2570)
|
||||
* FEATURE: Hosts can now be exported with their services (#2568)
|
||||
* FEATURE: "magic" variable overrides are now supported (#2569)
|
||||
|
||||
### CLI
|
||||
* FIX: config deploy doesn't try to wait in case of no deployment (#2522)
|
||||
* FIX: renderer now shows full service sets (#2550)
|
||||
* FEATURE: improved wording for deployment error messages (#2523)
|
||||
* FEATURE: JSON can now be shipped via STDIN (#1570)
|
||||
* FEATURE: improved readability for some error messages (#2567)
|
||||
* FEATURE: allows showing hosts with their services (#2565)
|
||||
* FEATURE: allow showing resolved Host services (#2571)
|
||||
* FEATURE: "magic" variable overrides are now supported (#2560)
|
||||
* FEATURE: error messages are now friendlier (#2567)
|
||||
* FEATURE: STDIN support for --json is now available (#1570)
|
||||
|
||||
### Activity Log
|
||||
|
||||
* FIX: deleted objects might have been missing related properties (#2559)
|
||||
|
||||
### Deployment Log
|
||||
* FEATURE: visualization performance has been improved (#2551)
|
||||
|
||||
### Internals
|
||||
|
||||
* FEATURE: there is now a centralized Exporter implementation (#2549)
|
||||
|
||||
1.9.1
|
||||
-----
|
||||
|
||||
### Fixed issues
|
||||
* You can find issues and feature requests related to this release on our
|
||||
[roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/28?closed=1)
|
||||
|
||||
### User Interface
|
||||
* FIX: DataList-backed fields failed to validate (#2475)
|
||||
* FIX: No Host list limit when adding a single service globally (#2481)
|
||||
* FIX: Cleared activity log caused exception (#2505, #2506)
|
||||
* FEATURE: Icinga Web 2.10 dark mode support (#2433)
|
||||
|
||||
### Configuration Baskets
|
||||
* FIX: failed to export Baskets with Service Sets (#2488)
|
||||
* FIX: Sync Rule restore from snapshot on name change (#2467)
|
||||
* FIX: Do not export UUIDs with Service Sets (#2488)
|
||||
|
||||
### CLI
|
||||
* FEATURE: Allow to define deployment grace period on CLI (#2499)
|
||||
|
||||
### Integrations
|
||||
* FIX: Cleanup IcingaDbCubeLinks (#2484)
|
||||
|
||||
### DB Schema
|
||||
* FIX: applying DB Schema migrations failed on PostgreSQL (#2482)
|
||||
|
||||
1.9.0
|
||||
-----
|
||||
|
||||
### Breaking Changes
|
||||
* Module dependencies have been raised, [Upgrading](05-Upgrading.md) and
|
||||
[Installation](02-Installation.md) documentations contain related details
|
||||
|
||||
### Fixed issues
|
||||
* You can find issues and feature requests related to this release on our
|
||||
[roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/25?closed=1)
|
||||
|
||||
### Import and Sync
|
||||
* FIX: string property modifiers now preserve NULL values (#2371)
|
||||
* FIX: "to int" property modifiers now fails for non-string values (#2372)
|
||||
* FEATURE: introduce 'disable' as your purge action on Sync (#2285)
|
||||
* FEATURE: there is now a simple "group by" Property Modifier (#2317)
|
||||
|
||||
### Configuration Baskets
|
||||
* FIX: Notification Apply Rules have not been exported (#2335)
|
||||
* FIX: Restore now supports the set_if_format switch (#2291)
|
||||
* FEATURE: it's now possible to purge objects of specific types (#2201)
|
||||
* FEATURE: exporting Users, User-Templates and -Groups is now possible (#2328)
|
||||
* FEATURE: Data Field Categories are now supported (#2256)
|
||||
|
||||
### Permissions and Restrictions
|
||||
* FEATURE: allow using monitoring module permissions (#2304)
|
||||
* FEATURE: it's now possible to grant (global) access to scheduled downtimes (#2086)
|
||||
|
||||
### Configuration / Templating
|
||||
* FEATURE: offering choices based on a specific imports is now possible (#1178)
|
||||
|
||||
### User Interface
|
||||
* FIX: allow switching DB config while connection is failing (#2300)
|
||||
* FIX: Links to duplicate services in Sets didn't check for deactivation (#2323)
|
||||
* FIX: SQL error for Data Fields table on PostgreSQL (#2310)
|
||||
* FIX: SQL error when searching for Data Field Categories (#2367)
|
||||
* FIX: Icon used for Notifications has been changed (#2455)
|
||||
* FEATURE: show "deprecated" flag on object attribute inspection (#2312)
|
||||
* FEATURE: Service Template for single Host services provides auto-completion (#1974)
|
||||
|
||||
### CLI
|
||||
* FEATURE: config deployment now allows to --wait for an Icinga restart (#2314)
|
||||
|
||||
### Activity log
|
||||
* FEATURE: Activity log now allows for remarks (addon module required, #2471)
|
||||
|
||||
### Documentation
|
||||
* FIX: configure the daemon with main setup instructions (#2296, #2320)
|
||||
|
||||
### Internals
|
||||
* FEATURE: PHP 8.1 is now supported, works once available in Icinga Web (#2435)
|
||||
* FEATURE: Config Branches have been implemented, leveraged via Hook/Addon (#2376)
|
||||
* FEATURE: UUIDs have been implemented for most Icinga objects, more to come
|
||||
* FEATURE: new Deployment Hook, triggers onCollect(ing) Icinga startup info (#2315)
|
||||
|
||||
1.8.1
|
||||
-----
|
||||
|
||||
|
@ -12,12 +12,16 @@ 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 GitHub
|
||||
### Tests on Travis-CI
|
||||
|
||||
When pushing to [GitHub](https://github.com/Icinga/icingaweb2-module-director/)
|
||||
or sending pull requests, Unit-Tests are automatically triggered.
|
||||
or sending pull requests, Unit-Tests are automatically triggered on
|
||||
[Travis-CI](https://travis-ci.org/Icinga/icingaweb2-module-director):
|
||||
|
||||

|
||||
[](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.
|
||||
|
||||
### Tests for supported Platforms
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 41 KiB |
Binary file not shown.
Before Width: | Height: | Size: 95 KiB |
Binary file not shown.
Before Width: | Height: | Size: 47 KiB |
Binary file not shown.
Before Width: | Height: | Size: 42 KiB |
Binary file not shown.
Before Width: | Height: | Size: 58 KiB |
Binary file not shown.
Before Width: | Height: | Size: 60 KiB |
@ -56,7 +56,7 @@ class Acl
|
||||
public function listRoleNames()
|
||||
{
|
||||
return array_map(
|
||||
[$this, 'getNameForRole'],
|
||||
array($this, 'getNameForRole'),
|
||||
$this->getUser()->getRoles()
|
||||
);
|
||||
}
|
||||
|
@ -35,20 +35,19 @@ class MemoryLimit
|
||||
$val = trim($string);
|
||||
|
||||
if (preg_match('/^(\d+)([KMG])$/', $val, $m)) {
|
||||
$val = (int) $m[1];
|
||||
|
||||
$val = $m[1];
|
||||
switch ($m[2]) {
|
||||
case 'G':
|
||||
$val *= 1024;
|
||||
// no break
|
||||
// Intentional fall-through
|
||||
case 'M':
|
||||
$val *= 1024;
|
||||
// no break
|
||||
// Intentional fall-through
|
||||
case 'K':
|
||||
$val *= 1024;
|
||||
}
|
||||
}
|
||||
|
||||
return (int) $val;
|
||||
return intval($val);
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
<?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';
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?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';
|
||||
public const DB_RESOURCE = 'director/db_resource';
|
||||
}
|
@ -2,12 +2,11 @@
|
||||
|
||||
namespace Icinga\Module\Director\Cli;
|
||||
|
||||
use gipfl\Json\JsonDecodeException;
|
||||
use gipfl\Json\JsonString;
|
||||
use Icinga\Cli\Command as CliCommand;
|
||||
use Icinga\Module\Director\Application\MemoryLimit;
|
||||
use Icinga\Module\Director\Core\CoreApi;
|
||||
use Icinga\Module\Director\Db;
|
||||
use Icinga\Module\Director\Exception\JsonException;
|
||||
use Icinga\Module\Director\Objects\IcingaEndpoint;
|
||||
use Icinga\Application\Config;
|
||||
use RuntimeException;
|
||||
@ -22,7 +21,7 @@ class Command extends CliCommand
|
||||
|
||||
protected function renderJson($object, $pretty = true)
|
||||
{
|
||||
return JsonString::encode($object, $pretty ? JSON_PRETTY_PRINT : null) . "\n";
|
||||
return json_encode($object, $pretty ? JSON_PRETTY_PRINT : null) . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -31,17 +30,15 @@ class Command extends CliCommand
|
||||
*/
|
||||
protected function parseJson($json)
|
||||
{
|
||||
try {
|
||||
return JsonString::decode($json);
|
||||
} catch (JsonDecodeException $e) {
|
||||
$this->fail('Invalid JSON: %s', $e->getMessage());
|
||||
$res = json_decode($json);
|
||||
|
||||
if ($res === null) {
|
||||
$this->fail('Invalid JSON: %s', $this->getLastJsonError());
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $msg
|
||||
* @return never-return
|
||||
*/
|
||||
public function fail($msg)
|
||||
{
|
||||
$args = func_get_args();
|
||||
@ -49,8 +46,16 @@ class Command extends CliCommand
|
||||
if (count($args)) {
|
||||
$msg = vsprintf($msg, $args);
|
||||
}
|
||||
echo $this->screen->colorize("ERROR", 'red') . ": $msg\n";
|
||||
exit(1);
|
||||
|
||||
throw new RuntimeException($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function getLastJsonError()
|
||||
{
|
||||
return JsonException::getJsonErrorMessage(json_last_error());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,9 +87,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;
|
||||
|
@ -4,11 +4,6 @@ namespace Icinga\Module\Director\Cli;
|
||||
|
||||
use Icinga\Cli\Params;
|
||||
use Icinga\Exception\MissingParameterException;
|
||||
use Icinga\Module\Director\Data\Db\DbObject;
|
||||
use Icinga\Module\Director\Data\Exporter;
|
||||
use Icinga\Module\Director\Data\PropertyMangler;
|
||||
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
|
||||
use Icinga\Module\Director\Objects\IcingaHost;
|
||||
use Icinga\Module\Director\Objects\IcingaObject;
|
||||
use InvalidArgumentException;
|
||||
|
||||
@ -39,58 +34,28 @@ class ObjectCommand extends Command
|
||||
*
|
||||
* OPTIONS
|
||||
*
|
||||
* --resolved Resolve all inherited properties and show a flat
|
||||
* object
|
||||
* --json Use JSON format
|
||||
* --no-pretty JSON is pretty-printed per default. Use this flag
|
||||
* to enforce un-formatted JSON
|
||||
* --no-defaults Per default JSON output ships null or default
|
||||
* values. This flag skips those properties
|
||||
* --with-services For hosts only, also shows attached services
|
||||
* --all-services For hosts only, show applied and inherited services
|
||||
* too
|
||||
* --resolved Resolve all inherited properties and show a flat
|
||||
* object
|
||||
* --json Use JSON format
|
||||
* --no-pretty JSON is pretty-printed per default (for PHP >= 5.4)
|
||||
* Use this flag to enforce unformatted JSON
|
||||
* --no-defaults Per default JSON output ships null or default values
|
||||
* With this flag you will skip those properties
|
||||
*/
|
||||
public function showAction()
|
||||
{
|
||||
$db = $this->db();
|
||||
$object = $this->getObject();
|
||||
$exporter = new Exporter($db);
|
||||
$resolve = (bool) $this->params->shift('resolved');
|
||||
$withServices = (bool) $this->params->get('with-services');
|
||||
$allServices = (bool) $this->params->get('all-services');
|
||||
if ($withServices) {
|
||||
if (!$object instanceof IcingaHost) {
|
||||
$this->fail('--with-services is available for Hosts only');
|
||||
}
|
||||
$exporter->enableHostServices();
|
||||
if ($this->params->shift('resolved')) {
|
||||
$object = $object::fromPlainObject($object->toPlainObject(true), $db);
|
||||
}
|
||||
if ($allServices) {
|
||||
if (!$object instanceof IcingaHost) {
|
||||
$this->fail('--all-services is available for Hosts only');
|
||||
}
|
||||
$exporter->serviceLoader()->resolveHostServices();
|
||||
}
|
||||
|
||||
$exporter->resolveObjects($resolve);
|
||||
$exporter->showDefaults($this->params->shift('no-defaults', false));
|
||||
|
||||
if ($this->params->shift('json')) {
|
||||
echo $this->renderJson($exporter->export($object), !$this->params->shift('no-pretty'));
|
||||
$noDefaults = $this->params->shift('no-defaults', false);
|
||||
$data = $object->toPlainObject(false, $noDefaults);
|
||||
echo $this->renderJson($data, !$this->params->shift('no-pretty'));
|
||||
} else {
|
||||
$config = new IcingaConfig($db);
|
||||
if ($resolve) {
|
||||
$object = $object::fromPlainObject($object->toPlainObject(true, false, null, false), $db);
|
||||
}
|
||||
$object->renderToConfig($config);
|
||||
if ($withServices) {
|
||||
foreach ($exporter->serviceLoader()->fetchServicesForHost($object) as $service) {
|
||||
$service->renderToConfig($config);
|
||||
}
|
||||
}
|
||||
foreach ($config->getFiles() as $filename => $content) {
|
||||
printf("/** %s **/\n\n", $filename);
|
||||
echo $content;
|
||||
}
|
||||
echo $object;
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,9 +87,36 @@ class ObjectCommand extends Command
|
||||
public function createAction()
|
||||
{
|
||||
$type = $this->getType();
|
||||
$props = $this->getObjectProperties();
|
||||
$name = $props['object_name'];
|
||||
$object = IcingaObject::createByType($type, $props, $this->db());
|
||||
$name = $this->params->shift();
|
||||
|
||||
$props = $this->remainingParams();
|
||||
if (! array_key_exists('object_type', $props)) {
|
||||
$props['object_type'] = 'object';
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
if (array_key_exists('object_name', $props)) {
|
||||
if ($name !== $props['object_name']) {
|
||||
$this->fail(sprintf(
|
||||
"Name '%s' conflicts with object_name '%s'\n",
|
||||
$name,
|
||||
$props['object_name']
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$props['object_name'] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
if (! array_key_exists('object_name', $props)) {
|
||||
$this->fail('Cannot create an object with at least an object name');
|
||||
}
|
||||
|
||||
$object = IcingaObject::createByType(
|
||||
$type,
|
||||
$props,
|
||||
$this->db()
|
||||
);
|
||||
|
||||
if ($object->store()) {
|
||||
printf("%s '%s' has been created\n", $type, $name);
|
||||
@ -189,38 +181,33 @@ class ObjectCommand extends Command
|
||||
public function setAction()
|
||||
{
|
||||
$name = $this->getName();
|
||||
$type = $this->getType();
|
||||
|
||||
if ($this->params->shift('auto-create') && ! $this->exists($name)) {
|
||||
$action = 'created';
|
||||
$object = $this->create($type, $name);
|
||||
$object = $this->create($name);
|
||||
} else {
|
||||
$action = 'modified';
|
||||
$object = $this->getObject();
|
||||
}
|
||||
|
||||
$appends = self::stripPrefixedProperties($this->params, 'append-');
|
||||
$remove = self::stripPrefixedProperties($this->params, 'remove-');
|
||||
$appends = $this->stripPrefixedProperties($this->params, 'append-');
|
||||
$remove = $this->stripPrefixedProperties($this->params, 'remove-');
|
||||
|
||||
if ($this->params->shift('replace')) {
|
||||
$object->replaceWith($this->create($type, $name, $this->remainingParams()));
|
||||
$new = $this->create($name)->setProperties($this->remainingParams());
|
||||
$object->replaceWith($new);
|
||||
} else {
|
||||
$object->setProperties($this->remainingParams());
|
||||
}
|
||||
|
||||
PropertyMangler::appendToArrayProperties($object, $appends);
|
||||
PropertyMangler::removeProperties($object, $remove);
|
||||
$this->persistChanges($object, $type, $name, $action);
|
||||
}
|
||||
|
||||
protected function persistChanges(DbObject $object, $type, $name, $action)
|
||||
{
|
||||
$this->appendToArrayProperties($object, $appends);
|
||||
$this->removeProperties($object, $remove);
|
||||
if ($object->hasBeenModified() && $object->store()) {
|
||||
printf("%s '%s' has been %s\n", $type, $name, $action);
|
||||
printf("%s '%s' has been %s\n", $this->getType(), $this->name, $action);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
printf("%s '%s' has not been modified\n", $type, $name);
|
||||
printf("%s '%s' has not been modified\n", $this->getType(), $name);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -339,7 +326,58 @@ class ObjectCommand extends Command
|
||||
exit(0);
|
||||
}
|
||||
|
||||
protected static function stripPrefixedProperties(Params $params, $prefix = 'append-')
|
||||
protected function appendToArrayProperties(IcingaObject $object, $properties)
|
||||
{
|
||||
foreach ($properties as $key => $value) {
|
||||
$current = $object->$key;
|
||||
if ($current === null) {
|
||||
$current = [$value];
|
||||
} elseif (is_array($current)) {
|
||||
$current[] = $value;
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'I can only append to arrays, %s is %s',
|
||||
$key,
|
||||
var_export($current, 1)
|
||||
));
|
||||
}
|
||||
|
||||
$object->$key = $current;
|
||||
}
|
||||
}
|
||||
|
||||
protected function removeProperties(IcingaObject $object, $properties)
|
||||
{
|
||||
foreach ($properties as $key => $value) {
|
||||
if ($value === true) {
|
||||
$object->$key = null;
|
||||
}
|
||||
$current = $object->$key;
|
||||
if ($current === null) {
|
||||
continue;
|
||||
} elseif (is_array($current)) {
|
||||
$new = [];
|
||||
foreach ($current as $item) {
|
||||
if ($item !== $value) {
|
||||
$new[] = $item;
|
||||
}
|
||||
}
|
||||
$object->$key = $new;
|
||||
} elseif (is_string($current)) {
|
||||
if ($current === $value) {
|
||||
$object->$key = null;
|
||||
}
|
||||
} else {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'I can only remove strings or from arrays, %s is %s',
|
||||
$key,
|
||||
var_export($current, 1)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function stripPrefixedProperties(Params $params, $prefix = 'append-')
|
||||
{
|
||||
$appends = [];
|
||||
$len = strlen($prefix);
|
||||
@ -357,37 +395,6 @@ class ObjectCommand extends Command
|
||||
return $appends;
|
||||
}
|
||||
|
||||
protected function getObjectProperties()
|
||||
{
|
||||
$name = $this->params->shift();
|
||||
|
||||
$props = $this->remainingParams();
|
||||
if (! array_key_exists('object_type', $props)) {
|
||||
$props['object_type'] = 'object';
|
||||
}
|
||||
|
||||
// Normalize object_name, compare to given name
|
||||
if ($name) {
|
||||
if (array_key_exists('object_name', $props)) {
|
||||
if ($name !== $props['object_name']) {
|
||||
$this->fail(sprintf(
|
||||
"Name '%s' conflicts with object_name '%s'\n",
|
||||
$name,
|
||||
$props['object_name']
|
||||
));
|
||||
}
|
||||
} else {
|
||||
$props['object_name'] = $name;
|
||||
}
|
||||
} else {
|
||||
if (! array_key_exists('object_name', $props)) {
|
||||
$this->fail('Cannot create an object with at least an object name');
|
||||
}
|
||||
}
|
||||
|
||||
return $props;
|
||||
}
|
||||
|
||||
protected function shiftOneOrMoreNames()
|
||||
{
|
||||
$names = array();
|
||||
@ -405,36 +412,12 @@ class ObjectCommand extends Command
|
||||
protected function remainingParams()
|
||||
{
|
||||
if ($json = $this->params->shift('json')) {
|
||||
if ($json === true) {
|
||||
$json = $this->readFromStdin();
|
||||
if ($json === null) {
|
||||
$this->fail('Please pass JSON either via STDIN or via --json');
|
||||
}
|
||||
}
|
||||
return (array) $this->parseJson($json);
|
||||
} else {
|
||||
return $this->params->getParams();
|
||||
}
|
||||
}
|
||||
|
||||
protected function readFromStdin()
|
||||
{
|
||||
if (!defined('STDIN')) {
|
||||
define('STDIN', fopen('php://stdin', 'r'));
|
||||
}
|
||||
$inputIsTty = function_exists('posix_isatty') && posix_isatty(STDIN);
|
||||
if ($inputIsTty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$stdin = file_get_contents('php://stdin');
|
||||
if (! $stdin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $stdin;
|
||||
}
|
||||
|
||||
protected function exists($name)
|
||||
{
|
||||
return IcingaObject::existsByType(
|
||||
@ -453,12 +436,16 @@ class ObjectCommand extends Command
|
||||
);
|
||||
}
|
||||
|
||||
protected function create($type, $name, $properties = [])
|
||||
protected function create($name)
|
||||
{
|
||||
return IcingaObject::createByType($type, $properties + [
|
||||
'object_type' => 'object',
|
||||
'object_name' => $name
|
||||
], $this->db());
|
||||
return IcingaObject::createByType(
|
||||
$this->getType(),
|
||||
array(
|
||||
'object_type' => 'object',
|
||||
'object_name' => $name
|
||||
),
|
||||
$this->db()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,9 +47,8 @@ class CoreApi implements DeploymentApiInterface
|
||||
{
|
||||
$version = $this->getVersion();
|
||||
|
||||
if (
|
||||
$version === null ||
|
||||
((version_compare($version, '2.8.2', '>=') && version_compare($version, '2.10.2', '<')))
|
||||
if (version_compare($version, '2.8.2', '>=')
|
||||
&& version_compare($version, '2.10.2', '<')
|
||||
) {
|
||||
$this->client->disconnect();
|
||||
$this->client->setKeepAlive(false);
|
||||
@ -570,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';
|
||||
}
|
||||
@ -623,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',
|
||||
@ -682,8 +681,7 @@ constants
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
in_array('startup.log', $availableFiles)
|
||||
if (in_array('startup.log', $availableFiles)
|
||||
&& in_array('status', $availableFiles)
|
||||
) {
|
||||
if ($this->getStagedFile($stage, 'status') === '0') {
|
||||
@ -702,12 +700,6 @@ constants
|
||||
$deployment->set('stage_collected', 'y');
|
||||
|
||||
$deployment->store();
|
||||
|
||||
/** @var DeploymentHook[] $hooks */
|
||||
$hooks = Hook::all('director/Deployment');
|
||||
foreach ($hooks as $hook) {
|
||||
$hook->onCollect($deployment);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($missing as $deployment) {
|
||||
|
@ -8,11 +8,7 @@ class Json
|
||||
{
|
||||
public static function encode($mixed, $flags = null)
|
||||
{
|
||||
if ($flags === null) {
|
||||
$result = \json_encode($mixed);
|
||||
} else {
|
||||
$result = \json_encode($mixed, $flags);
|
||||
}
|
||||
$result = \json_encode($mixed, $flags);
|
||||
|
||||
if ($result === false && json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw JsonEncodeException::forLastJsonError();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user