Compare commits

...

778 Commits

Author SHA1 Message Date
raviks789
2423fad54c upgrade_188: Remove entries with duplicate checksums in director_activity_log
Update schema/mysql-migrations/upgrade_188.sql
2025-04-08 14:18:09 +02:00
Ravi Kumar Kempapura Srinivasa
2a4b78bfd2
Release 1.11.4 (#2969) 2025-03-26 11:24:49 +01:00
raviks789
38f3fe33c9
Release 1.11.4 2025-03-26 11:21:47 +01:00
Ravi Kumar Kempapura Srinivasa
a99a998540
Merge commit from fork
Apply relevant restrictions on REST url endpoints
2025-03-26 11:19:54 +01:00
Ravi Kumar Kempapura Srinivasa
cadac72f4c
Fix job behavior during summer and winter time change (#2954)
ref/IP/52977

`ts_last_attempt`, which is used in the callback function of
`React\EventLoop\LoopInterface::addPeriodicTimer`, had data type
timestamp and was saved as UTC time but retrieved as system time, and
during DST where the clock is moved forward or set back during DST, you
could expect time jumps in the retrieved `ts_last_attempt` value.

And the `React\EventLoop\LoopInterface::addPeriodicTimer` expects the
time source to be monotonous without any such time jumps. This causes
the jobs to be erratically scheduled after DST. And this happens mostly
when the `ts_last_attempt` saved time time falls in the skipped or time
range that was reset.

To avoid such time jumps the `ts_last_attempt` datatype is changed to
`BIGINT` and the values are saved as Unix time stamp.
2025-03-25 16:17:12 +01:00
raviks789
4c283a24c8
Fix: Support data type change of columns ts_last_attempt and ts_last_error from timestamp to bigint 2025-03-25 16:03:30 +01:00
raviks789
63dac34b0f
director_job: Change timestamp data types to integer 2025-03-25 16:03:26 +01:00
raviks789
5f4ad0f827 IcingaAddServiceForm: Check if service templates exist to add services 2025-03-25 16:01:29 +01:00
raviks789
b18cf4f80d Fix editing of custom variables for multi-selected objects 2025-03-25 15:56:11 +01:00
raviks789
42a47d6139 CustomVarRenderer: Fix illegal offset error if the value is an array 2025-03-25 15:53:09 +01:00
raviks789
778b25873c CustomVarRenderer: Fix custom var renderer for apply-for-rules 2025-03-25 15:49:30 +01:00
Mek Skëndo
2196de252d Fix MySQL8.4 nonstandard foreign keys deprecation
If you try to set up icinga director with the latest minor version of MySQL 8.4+, the schema creation will fail with confusing SQL error messages. This commit aims to fix that. https://dev.mysql.com/doc/refman/8.4/en/mysql-nutshell.html#mysql-nutshell-deprecations
2025-03-25 15:42:46 +01:00
raviks789
3fcb20178f
Apply correct restrictions to REST url endpoints
The following url end points should apply relevant restrictions to filter out objects and show correct HTTP status code:
- icingaweb2/director/service, if the host name is left out of the query (Example: icingaweb2/director/service?name=service-name)
- icingaweb2/directore/notification
- icingaweb2/director/serviceset
- icingaweb2/director/scheduled-downtime
2025-01-24 12:21:41 +01:00
Eric Lippmann
de8fe109e2
Release 1.11.3 (#2942) 2024-12-12 13:20:10 +01:00
raviks789
2b55c80cba Release 1.11.3 2024-12-12 13:16:47 +01:00
Eric Lippmann
32a644fad8
IcingaHostForm: Fix crashing of form for invalid check command (#2941)
fixes #2854
2024-12-12 13:16:38 +01:00
raviks789
8161a769fe IcingaHostForm: Fix crashing of form for invalid check command 2024-12-12 13:11:51 +01:00
Eric Lippmann
e37f802cf9
ImportRowModifierForm: Fix removal of filter expression (#2939)
fixes #2922, #2864
2024-12-12 10:54:40 +01:00
raviks789
f4692d7ab4 ImportRowModifierForm: Fix removal of filter expression 2024-12-12 10:45:23 +01:00
Eric Lippmann
d205415f1b
Fix pgsql binary resource handling for uuids (#2938)
fixes #2934
2024-12-12 09:53:08 +01:00
raviks789
175de1ae84 Fix pgsql binary resource handling for uuids 2024-12-12 09:46:00 +01:00
Eric Lippmann
89ebf71d88
PropertyTableSortForm: Don't use ipl`s CSRF counter measure (#2937)
It's incompatible with gipfl`s…

fixes #2935
2024-12-12 09:44:59 +01:00
Johannes Meyer
cdd3fea9d2 PropertyTableSortForm: Don't use ipl`s CSRF counter measure
It's incompatible with gipfl`s…

fixes #2935
2024-12-04 13:28:42 +01:00
Eric Lippmann
4032d49553
Release 1.11.2 (#2933) 2024-11-19 21:12:35 +01:00
Eric Lippmann
c1d5334fc8 Add changelog for version 1.11.2 2024-11-19 16:22:19 +01:00
Eric Lippmann
79e84c074a Raise version to 1.11.2 2024-11-19 15:41:56 +01:00
Eric Lippmann
bd21650332 Raise incubator dependency version to 0.22.0 2024-11-19 15:38:59 +01:00
Eric Lippmann
6dc0bb2596
Allow cloning of service sets in branches (#2896)
fixes #2890 

Blocked by #2895
2024-11-19 15:07:07 +01:00
raviks789
6c766dff43 Allow cloning service sets in Director Branches 2024-11-19 13:34:14 +01:00
Eric Lippmann
d56ca2c235
Enrich custom variable lists in monitoring and icingadb details (#2445)
resolves #2239

requires https://github.com/Icinga/icingaweb2/pull/4614 or
https://github.com/Icinga/icingadb-web/pull/467
2024-11-19 13:33:55 +01:00
raviks789
dbacfa21c0 Icingadb/CustomVarRenderer: Add error handling 2024-11-19 13:15:34 +01:00
raviks789
0e744630d7 Monitoring/CustomVarRenderer: Add error handling 2024-11-19 13:15:34 +01:00
raviks789
b954336170 Icingadb/CustomVarRenderer: Look for the service in all of its types
It can be a directly created service or an applied service or an inherited service or service applied through service set.
2024-11-19 13:15:34 +01:00
raviks789
743997cb57 Monitoring/CustomVarRenderer: Look for the service in all of its types
The service could be directly created, or applied through an apply rule or could be an inherited service or a service applied through service set.
2024-11-19 13:15:34 +01:00
raviks789
c78979b24a Icingadb/CustomVarRenderer: Render labels of key and value as HtmlElements 2024-11-19 13:15:34 +01:00
raviks789
b7ea8aada6 Monitoring/CustomVarRenderer: Cast data field setting value data_list_id to integer for postgres database 2024-11-19 13:15:34 +01:00
raviks789
1d98492429 Monitoring/CustomVarRenderer: Support rendering dictionary values 2024-11-19 13:15:34 +01:00
raviks789
b082db707e Icingadb/CustomVarRenderer: Support rendering of dictionary values 2024-11-19 13:15:34 +01:00
raviks789
9e1646091c Icingadb/CustomVarRenderer: Cast data field setting value data_list_id to integer for postgres database 2024-11-19 13:15:34 +01:00
Johannes Meyer
9919b65fc5 DirectorDatafield: Properly cache category in getCategory()
Makes `getCategoryName()` work.
2024-11-19 13:15:34 +01:00
Johannes Meyer
bf591093d8 Provide implementation for hook Icingadb/CustomVarRenderer 2024-11-19 13:15:34 +01:00
Johannes Meyer
ca0b8ebc4e Provide implementation for hook Monitoring/CustomVarRenderer 2024-11-19 13:15:34 +01:00
Johannes Meyer
431468366c Introduce implementation for hook Icingadb/CustomVarRenderer 2024-11-19 13:15:34 +01:00
Johannes Meyer
c20b477df8 Introduce implementation for hook Monitoring/CustomVarRenderer 2024-11-19 13:15:34 +01:00
Sukhwinder Dhillon
2d48843d87 Phpstan: Separate workflow 2024-11-19 09:57:31 +01:00
Eric Lippmann
ef7f53cc8f
fixes #2393 clusterzone check is not a plugincheck (#2502) 2024-11-07 15:49:58 +01:00
moreamazingnick
fd7babe81e fixes #2393 clusterzone check is not a plugincheck 2024-11-07 15:28:51 +01:00
Eric Lippmann
5daa3a85ed
Add hasBasketSupport for TimePeriods (#2543)
This adds the missing "hasBasketSupport" for TimePeriodController which
allows to add the TimePeriod to specific baskets.
2024-11-07 15:24:45 +01:00
André Nähring
1835661850 Add hasBasketSupport for TimePeriods 2024-11-07 13:16:38 +01:00
Eric Lippmann
853efc8c6d
Fix CSRF validation for sorting in property tables (#2893) 2024-11-07 13:15:52 +01:00
raviks789
7fd1468229 Fix CSRF validation for sorting in property tables 2024-11-07 12:57:40 +01:00
Eric Lippmann
030740942e
IcingaCloneObjectForm: Fix cloning of hosts in director branches (#2898)
The cloned host must also have services and service sets that are under
the original host.
2024-11-07 12:57:02 +01:00
raviks789
9d186638cd IcingaCloneObjectForm: Fix cloning of hots in director branches
The cloned host must also have services and service sets that are under the original host.
2024-11-07 11:32:36 +01:00
Eric Lippmann
d9b3b23de6
IcingaMultiEditForm: Fix editing custom vars with space in their name (#2900) 2024-11-07 11:32:18 +01:00
raviks789
5298c8ee5d IcingaMultiEditForm: Fix editing custom vars with space in their name 2024-11-07 11:21:46 +01:00
Eric Lippmann
39c823c655
Basket::setObjects: Reset $chosenObjects property only if the given objects is empty (#2902) 2024-11-07 11:21:15 +01:00
raviks789
6be8cd49af Basket::setObjects: Reset $chosenObjects property only if the given objects is empty 2024-11-07 11:14:36 +01:00
Eric Lippmann
058bc4a776
PropertyModifierGetHostByName: Fix inet_pton unrecognized address error (#2903) 2024-11-07 11:14:15 +01:00
raviks789
6c7918033d PropertyModifierGetHostByName: Fix inet_pton unrecognized address error 2024-11-07 11:02:21 +01:00
Eric Lippmann
aaf51452be
ObjectImporter: Retransform sync job settings apply_changes from boolean to 'y' or 'n' (#2904)
Sync jobs restored from a basket snapshot with `apply_changes` settings
set to `Yes`, runs without applying any changes to the objects affected
by the sync rule. This happens as the value of the setting is exported
as a boolean but is not retransformed back to `y` or `n` while
importing.


fixes ref/IP/53326
2024-11-07 11:02:03 +01:00
raviks789
44a8bbb70e ObjectImporter: Retransform sync job settings apply_changes from boolean to 'y' or 'n' 2024-11-07 10:39:40 +01:00
Eric Lippmann
2d332a2a16
Fix sync rule preview in case of boolean properties (#2905)
Sync rules created for import sources, importing objects with boolean
properties, throws `SQLSTATE` error as shown in the screenshot below.

![Sync Preview SQL State
error](https://github.com/user-attachments/assets/7c1f27f1-0c98-4945-8599-1e60ea5c9574)

The reason for this is because the preview creates temporary branched
objects by importing the objects' properties to check for the
modifications. And the boolean properties, were not transformed to `y`
or `n` (which is the supported datatype for boolean (`ENUM('y','n')`) to
store in the database) before the temporary object is created.

fixes ref/IP/53248
2024-11-07 10:39:14 +01:00
raviks789
409962251b Fix sync rule preview in case of boolean properties 2024-11-07 10:24:19 +01:00
Eric Lippmann
340e3d550f
IcingaObjectMultiRelations: Set property modified to false when loaded from DB (#2907) 2024-11-07 10:24:04 +01:00
raviks789
c3fd4118d9 IcingaObjectMultiRelations: Set property modified to false when loaded from DB 2024-11-07 09:45:13 +01:00
Eric Lippmann
aa1df8d772
DirectorDatalist: Match column types to join tables in postgres by explicit type casting (#2916) 2024-11-07 09:44:49 +01:00
raviks789
6291179bcc DirectorDatalist: Match column types to join tables in postgres by explicit type casting 2024-11-07 09:41:27 +01:00
Eric Lippmann
2f888ba135
Fix typo in SNMP Data Fields example documentation (#2931) 2024-11-07 09:27:10 +01:00
Sam Banks
75acfad6fb Fixing typo 2024-11-06 14:03:37 +13:00
Eric Lippmann
0287012739
ImportSourceRestApi: Fix strlen deprecation (#2891)
fix #2889
2024-10-23 13:17:45 +02:00
raviks789
d946b0d316
ImportSourceRestApi: Fix strlen deprecation 2024-10-22 16:47:06 +02:00
dependabot[bot]
a6da978ec9
Bump peter-evans/repository-dispatch from 1 to 3 (#2929) 2024-10-22 14:05:05 +00:00
dependabot[bot]
d434a3da40
Bump peter-evans/repository-dispatch from 1 to 3
Bumps [peter-evans/repository-dispatch](https://github.com/peter-evans/repository-dispatch) from 1 to 3.
- [Release notes](https://github.com/peter-evans/repository-dispatch/releases)
- [Commits](https://github.com/peter-evans/repository-dispatch/compare/v1...v3)

---
updated-dependencies:
- dependency-name: peter-evans/repository-dispatch
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-22 14:01:39 +00:00
dependabot[bot]
91147304a9
Bump actions/checkout from 3 to 4 (#2928) 2024-10-22 14:00:43 +00:00
dependabot[bot]
087439d0df
Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-22 13:51:32 +00:00
Eric Lippmann
21aaa77efb
Enable Dependabot for GitHub Actions (#2927) 2024-10-22 15:50:03 +02:00
Eric Lippmann
f21f12528e Enable Dependabot for GitHub Actions 2024-10-22 15:48:24 +02:00
Eric Lippmann
4ed60f527b
Fix PhpStan complaining about arithmetic operations between string and int (#2926) 2024-10-22 15:46:19 +02:00
Eric Lippmann
ce64888b81 Fix const visibility 2024-10-22 15:36:03 +02:00
Eric Lippmann
00985429c5 Fix PSR-12 violations 2024-10-22 14:31:14 +02:00
Eric Lippmann
48ad72f9c2 Use PSR-12 for phpcs 2024-10-22 14:23:16 +02:00
Eric Lippmann
28261d8a7f Fix PhpStan complaining about arithmetic operations between string and int 2024-10-22 14:19:55 +02:00
raviks789
853b6ceb84 Make unique constraints consistent across databases 2024-08-15 09:21:07 +02:00
raviks789
428a49f433 Remove gipfl/format package dependency
refs: #2847
2024-02-08 15:59:13 +01:00
Johannes Meyer
994030260a Prepare version 1.11.1 2024-02-07 14:02:02 +01:00
raviks789
e48ddd2f35 Restore services of service set on restoring service set
All the services which were under the service set when it was deleted must be restored when it is restored from activity log.
2024-02-07 13:40:33 +01:00
Johannes Meyer
6351df68ea
Support the rendering of service custom variable in Dependencies form (#2298)
Earlier the director did not support the rendering of service custom
variables for Parent Service in Dependencies form. Here, this issue is
fixed.

fixes #2289
2024-02-07 12:48:22 +01:00
raviks789
48ea3e46f9 IcingaDependencyForm: Make parent host and parent service element values removeable 2024-02-07 11:59:54 +01:00
Ravi Kumar Kempapura Srinivasa
1b74177d6d Support the rendering of service custom variable in Dependencies form 2024-02-07 11:59:52 +01:00
Johannes Meyer
c65369602f
Phpstan: Fix deprecated function param types (#2858) 2024-02-05 16:17:32 +01:00
Sukhwinder Dhillon
9cccd9067e phpstan: Scan all available modules 2024-02-05 16:05:24 +01:00
Sukhwinder Dhillon
bcdb8911f9 Update phpstan-baseline 2024-02-05 16:05:24 +01:00
Sukhwinder Dhillon
d879186f0e Fix wrong method param types and add var type hints 2024-02-05 16:05:24 +01:00
Sukhwinder Dhillon
3fc16910f7 Ini_set() #param 2 must be string (php < 8.1) 2024-02-05 16:05:24 +01:00
Sukhwinder Dhillon
2acfdecb8d RestApiClient: Remove curl's return type hint and wrong curl_error() param
Php >= 8 returns CurlHandle instead of resource, which confuses phpstan.
2024-02-05 16:05:24 +01:00
Sukhwinder Dhillon
cc3bfd5437 BranchHelper: Define method return types 2024-02-05 16:05:24 +01:00
Sukhwinder Dhillon
c9e78ba7d5 IcingaObjectLegacyAssignments: Fix incorrect if condition 2024-02-05 16:05:23 +01:00
Sukhwinder Dhillon
bb8076a09d var_export() expects #param 2 to be bool 2024-02-05 16:05:23 +01:00
Sukhwinder Dhillon
deddcde0dd phpstan: Relax unmatched ignore errors for certain messages 2024-02-05 16:05:23 +01:00
Sukhwinder Dhillon
9f58dcf8d9 phpstan: Strict check function/class name-case and fix violations 2024-02-05 16:05:23 +01:00
Johannes Meyer
35c6086db3
Support Content-Security-Policy (#2857)
resolves #2845
2024-01-25 10:44:48 +01:00
Sukhwinder Dhillon
28d8f0e7d1 ImportsourceController: Remove unnecessary inline js for collapse 2024-01-19 15:17:41 +01:00
Sukhwinder Dhillon
be6447874c Remove not in use class ReadOnlyFormAvpTable 2024-01-19 15:17:41 +01:00
Sukhwinder Dhillon
c25a66b484 Avoid inline css style 2024-01-19 15:17:41 +01:00
Sukhwinder Dhillon
72f44c326f Remove unnecessary and unused code 2024-01-19 15:17:41 +01:00
Sukhwinder Dhillon
708b4dbe8f Remove unnecessary inline style 2024-01-19 15:17:41 +01:00
Thomas Gelf
6e57e6dc98 IcingaObjectGroup: no membership refresh w/o assign
fixes #2784
2024-01-19 12:29:18 +01:00
Johannes Meyer
0493f93a74
Fix form field suggestions (#2840)
Other available fields should be suggested when no check command has
been chosen for service template.

fixes #2826, #2815
2024-01-16 16:56:46 +01:00
raviks789
80d566f42d PHPStan: Exclude static analysis of tests 2024-01-16 15:30:05 +01:00
raviks789
a0fba398a1 Set up mockery library for php unit test 2024-01-16 15:30:05 +01:00
raviks789
0ea0a8fd83 Fix zone creation and deletion for tests 2024-01-16 15:27:27 +01:00
Johannes Meyer
58e2a8fca6 Change parent class of BaseTestCase to \Icinga\Test\BaseTestCase 2024-01-16 14:33:49 +01:00
raviks789
0ff6c8ee62 FormFieldSuggestionTest: Add tests for nullable command argument 2024-01-16 12:38:19 +01:00
raviks789
c0e870d543 Fix form field suggestions
Other available fields should be suggested when no check command has been
chosen for service template.
2024-01-16 12:38:19 +01:00
Johannes Meyer
6851778863
add support for icingadb as only icingaweb2 data backend (#2635) 2024-01-16 11:16:08 +01:00
Sukhwinder Dhillon
a850ff13d7 IcingadbBackend: Remove isAvailable method and property
As it is only used internally now, it is no more required
2024-01-16 10:27:10 +01:00
Sukhwinder Dhillon
2461724271 IcingadbBackend: Drop icingadb restriction check and only check for director restrictions
Monitoring does the same.
2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
147170e58a phpstan: Add icingadb module 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
d30a56a385 Fix phpcs issues 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
d26a619577 ServiceController: Use given properties to get host/service name 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
4ef7f5664a ActionController::backend(): Add condition to check which backend should be used
- If both are available
2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
f52d05de31 IcingadbBackend: Apply director restrictions properly 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
8a489bcc46 HostController: Move ServiceFinder::getRedirectionUrl() method code to findserviceAction()
- This helps to detect backend easily, and was only called in this method anyway.
- Add and use helping method getServicesReadOnlyPermission()
-
2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
4e6528e862 ServiceController: Remove redudant if condition 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
26f8769d28 Icingadb (Host/Service)Actions: Fix permissions and code style 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
1048c33fa4 configuration.php: Only provide monitoring/icingadb permissions/restrictions if module exists 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
a272b0d242 Introduce icingadb permissions/restrictions 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
db7181c29e Backend: Remove unnecessary calls to isAvailable() 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
eeaf87741a IcingadbBackend: Always check if module is available 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
677f5dc72a Monitoring/IcingadbBackend: Handle if $hostName or $serviceName is null 2024-01-16 09:51:47 +01:00
Sukhwinder Dhillon
956cce84cb Cleanup code
- Remove superfluous methods/usages
- Simplify the code
2024-01-16 09:51:44 +01:00
Sukhwinder Dhillon
8ea8a62ef4 BackendInterface: Add phpDocs 2024-01-15 16:25:05 +01:00
Sukhwinder Dhillon
604667ca65 Relocate Backend classes 2024-01-15 16:25:02 +01:00
Sukhwinder Dhillon
9baa3c4341 Remove redudant class MonitorBackendMonitoring and adjuct code accordigly
- Use class `Monitoring` instead
- Remove not in use methods from `MonitorBackend` interface and from classes that implements this interface
- Add param types and return type hint to methods
2024-01-15 16:24:27 +01:00
Sukhwinder Dhillon
89134e0366 Remove obsolate class Backend and its usages
- Create the backend directly in ActionController::backend()
- Simplify the code
2024-01-15 16:24:25 +01:00
Tobias Tiederle
b28b36f815 move classes into subfolder
fix some problems and mark TODO
2023-12-04 10:12:54 +01:00
Tobias Tiederle
1c6090193d add support for icingadb as only icingaweb2 data backend 2023-12-04 10:12:54 +01:00
Sukhwinder Dhillon
12cca3ebcf
Phpstan: Streamline vendor file location with local dev-env (#2838) 2023-12-04 10:12:04 +01:00
Sukhwinder Dhillon
4edf4b43a9 Github Actions: Add checks for php 8.3 2023-12-01 10:56:12 +01:00
Sukhwinder Dhillon
2aa4a21e5e phpstan: Streamline vendor file location with local dev-env
- Remove superfluous dir and composer requires
2023-12-01 10:29:19 +01:00
Christian Schramm
aa31b37fd1 Fix db type error, when hostgroup is accidentially interpreted as integer
fixes #2821
2023-10-19 15:46:52 +02:00
Thomas Gelf
9a9799e491 Changelog, Upgrading: alt. texts, title swap 2023-10-13 11:47:13 +02:00
Thomas Gelf
9c6a955f64 module.info: back to master 2023-10-13 11:46:58 +02:00
Thomas Gelf
a6f0a0830c WIP: doc, module.info: prepare v1.11.0
fixes #2085
2023-10-13 11:33:16 +02:00
Thomas Gelf
fb1a23fb01 ObjectsTableSetMembers: fix uuid in link 2023-10-12 19:56:25 +02:00
Thomas Gelf
7267953e13 TemplateUsageTable: pass auth to constructor 2023-10-12 08:45:12 +02:00
Thomas Gelf
a2abbd326b TemplateController: pass auth 2023-10-12 08:43:58 +02:00
Thomas Gelf
48db90c7df ObjectsTable: require Auth
fixes #2808
2023-10-11 12:24:36 +02:00
Thomas Gelf
6178265a12 HostgroupRestriction: pass fitting table alias
fixes #2164
fixes #2809
2023-10-11 11:37:21 +02:00
Thomas Gelf
d02e430008 Sync: conditional membership sync
fixes #2812
2023-10-11 10:01:14 +02:00
Thomas Gelf
dcf03dc0d5 IcingaArguments: accept DSL
fixes #2811
2023-10-10 13:54:49 +02:00
julian-smithies
70e1aef111 Provide explanation for all exit codes 2023-10-10 11:39:10 +02:00
Thomas Gelf
742013673e PropertyModifierJsonDecode: explicitly fail for...
...non-string inputs

fixes #2810
2023-10-10 11:11:23 +02:00
raviks789
76509bb7c8 IcingaServiceSetServiceTable: Change table alias for director branches 2023-09-22 13:44:09 +02:00
raviks789
ca855c6ee7 TemplateUsageTable: Fix indrect object count
fixes #2806
2023-09-22 13:16:33 +02:00
Thomas Gelf
7c2a3f254b ObjectSetTable: fix on pgsql 2023-09-21 16:02:07 +02:00
Thomas Gelf
4d050834db IcingaConfig: render host templates to all...
...non-global zones, instead of the default global zone

refs #2410
2023-09-21 15:22:31 +02:00
raviks789
63a3e6a1ec Fix editing of multi-selected services with same name
Since the object names function as keys for the multi-selected objects array, this becomes a problem when
multiple services as the same name. Hence for the services the array keys must be a combination of service name
and the host name to which the service is related.
2023-09-21 14:59:42 +02:00
raviks789
7426e65067 Update PHPStan baseline 2023-09-21 14:57:30 +02:00
raviks789
dcd36877ea Make TemplateUsageTables and other tables compatible with director branches
`TemplateUsageTable`, `ApplyRulesTable`, `ObjectsTableSetmembers` and `TemplatesTable` are
made compatible with `director branches`.
2023-09-21 14:57:30 +02:00
raviks789
3c7082cabc Modify IcingaObjectFilterHelper::filterByTemplate for director branches
Icinga objects must be filterable based on templates when a director branch is active.
2023-09-21 14:57:30 +02:00
raviks789
e6f7d82c09 Add a imports column to the objects
The host or service objects require retrieve the imports column. This
makes it possible to filter them based on templates when a director
branch is active.
2023-09-21 14:57:30 +02:00
Ravi Kumar Kempapura Srinivasa
939f805378 Add setmembers summyary line to TemplateUsageTable
`'setmembers' => $this->getSummaryLine('object', 'o.service_set_id IS NOT NULL AND o.host_id IS NOT NULL'),` is added to TemplateUsageTable
and `objects` is set to ` $this->getSummaryLine('object', 'o.service_set_id IS NULL')`. Subsequently, ObjectTableSetMembers
is added which is used in `setmembersAction` in `TemplateController`. `ObjectTableSetMembers` uses service set name or service name
as search columns.
2023-09-21 14:57:30 +02:00
Thomas Gelf
ac7b899d5e doc/changelog: mention fix 2023-09-21 14:49:48 +02:00
raviks789
9e332b4022 Remove limit count for service set directly added to the host 2023-09-21 14:37:03 +02:00
Thomas Gelf
612165c4c3 doc/changelog: refresh 2023-09-21 13:01:10 +02:00
Thomas Gelf
53323ad861 de_DE: compile translation 2023-09-21 13:01:10 +02:00
Thomas Gelf
0c33c5d6bc IcingaNotificationForm: just a dot 2023-09-21 13:01:10 +02:00
Thomas Gelf
bfa72ee892 de_DE: use relative paths 2023-09-21 13:01:10 +02:00
Thomas Gelf
dbd1ed249a de_DE: refresh translation 2023-09-21 13:01:10 +02:00
Thomas Gelf
3199eb627b FormFieldSuggestion: fix wording 2023-09-21 13:01:10 +02:00
Johannes Meyer
89fa677941 phpstan: Remove obsolete pattern from baseline 2023-09-21 09:15:16 +02:00
raviks789
228cbc8376 Dashboard: Suppress covariance error of count() method 2023-09-21 09:00:55 +02:00
raviks789
32e674aca2 PHPStan: Add baseline 2023-09-21 09:00:55 +02:00
raviks789
9cc04eb5c6 StartupLogRenderer: Use correct syntax to write to array $lines 2023-09-21 09:00:55 +02:00
raviks789
fcaa97e1b2 Remove dead class SingleObjectApiHandler 2023-09-21 09:00:55 +02:00
raviks789
dec1951774 CustomVariableCache: Remove redundant destructor
Property `$db` is not declared for it to be unset
2023-09-21 09:00:55 +02:00
raviks789
98f6768dcb Declare properties that are dynamically used
Dynamic properties are deprecated since PHP 8.2.
2023-09-21 09:00:55 +02:00
raviks789
00523d9b35 IcingaTemplateResolver: Remove unused dynamic property $table 2023-09-21 09:00:55 +02:00
raviks789
69a3e9aa8e Workflow: Add PHPStan static analyzer 2023-09-21 09:00:55 +02:00
raviks789
132d49777a Workflow: Add PHP 8.2 version to the workflow 2023-09-21 09:00:55 +02:00
Johannes Meyer
079bf87a9a
Add php action workflow (#2309) 2023-08-31 10:32:34 +02:00
Johannes Meyer
48c4ae1d73 doc: Add note for GitHub tests 2023-08-31 10:24:54 +02:00
Johannes Meyer
2ca1fc99c9 test: Replace usages of @expectException 2023-08-31 09:48:48 +02:00
Johannes Meyer
8d0c8515da Drop travis integration 2023-08-30 17:31:38 +02:00
Johannes Meyer
629297116b BaseTestCase: Use phpunit's new TestCase 2023-08-30 17:28:06 +02:00
Johannes Meyer
37c8056689 Fix phpcs errors 2023-08-30 17:28:06 +02:00
Johannes Meyer
aaf59945d9 Add php action workflow 2023-08-30 17:28:06 +02:00
Thomas Gelf
fc7bfe7db9 Datalist: fix snapshot diff
fixes #2791
2023-08-25 17:15:08 +02:00
Thomas Gelf
5298243d94 SyncruleController: fix typo
fixes #2613
2023-08-25 11:00:39 +02:00
Thomas Gelf
a7a58c5893 Merge branch 'fix/setting-null-with-merge' 2023-08-23 15:49:18 +02:00
Thomas Gelf
b19c01daef Sync: ignore null for policy = ignore
fixes #2657
2023-08-23 15:48:13 +02:00
Thomas Gelf
e94ad714fb Sync: drop obsolete/useless method 2023-08-22 10:32:44 +02:00
Thomas Gelf
8896e54d69 IcingaArguments: be unmodified when loaded from db
fixes #2660
2023-08-21 12:44:59 +02:00
Thomas Gelf
907d93ebe9 FormFieldSuggestion: propose macros from set_if
fixes #514
2023-08-20 13:11:19 +02:00
Thomas Gelf
7aa7f51929 IcingaObjectFieldForm: move back getFilterFields() 2023-08-20 13:11:12 +02:00
Thomas Gelf
d97bbc0526 FormFieldSuggestion: refactor, dedicated class 2023-08-20 13:11:02 +02:00
Thomas Gelf
62f59d4c5a DirectorDatafieldForm: fix typo, translate 2023-08-20 13:10:52 +02:00
Lorenz Kästle
71b311e258 Add missing time unit in translation 2023-08-11 08:36:33 +02:00
Michael Pirogov
b9ad2ef9f5 migrations: fix syntax error on 187 2023-08-04 14:51:58 +02:00
moreamazingnick
f3455c197d Fix duplicate service sets on clone service
fixes #2671
2023-07-31 08:33:46 +02:00
Sebastian Gumprich
6e49615740 fix wrong example in rest-api docs
the example uses wrong parameters to get configs and activities, according to the code: https://github.com/Icinga/icingaweb2-module-director/blob/master/application/controllers/ConfigController.php#L144
2023-07-30 20:57:36 +02:00
Thomas Gelf
479d964841 BasketSnapshotFieldResolver: provide fixOptional...
...DatalistReference()
2023-07-30 20:54:39 +02:00
Thomas Gelf
02d6ebb0af DirectorDatafield: prefer list uuid...
...on basket restore
2023-07-30 20:52:56 +02:00
Thomas Gelf
14604b64d6 GroupMembershipResolver: namespace is useless 2023-07-30 20:45:14 +02:00
Thomas Gelf
5371b57630 BasketSnapshotFieldResolver: return types 2023-07-30 20:42:59 +02:00
Thomas Gelf
388f743290 TemplateUsageTable: show header
fixes #2780
2023-07-30 20:39:21 +02:00
Thomas Gelf
8e4ebb79d7 AssignRenderer: show JSON parsing error source
refs #2667
2023-07-30 20:26:32 +02:00
Thomas Gelf
26a4a10536 DbObject: compare id/ints only when not null 2023-07-30 20:05:24 +02:00
Thomas Gelf
2a140a512b DataFilter: hide json-encoded special characters
...from our filter parser

fixes #2667
2023-07-30 19:46:38 +02:00
Thomas Gelf
d429c9e5cc IcingaObjectGroup: re-enable group membership...
...resolver

refs #2048
2023-07-30 17:31:23 +02:00
Thomas Gelf
8cbde4a50e IcingaServiceForm: getFirstParent() prepared to...
...be moved elsewhere
2023-07-30 17:27:02 +02:00
Thomas Gelf
33c4c078d4 doc/changelog: mention case insensitiveness 2023-07-20 16:26:46 +02:00
Thomas Gelf
f7a295ccd5 Merge branch 'feature/datafields-search-case-insensitive-2359' 2023-07-20 16:25:06 +02:00
Thomas Gelf
7a29d7db87 DatafieldTable: search case insensitive
fixes #2359
2023-07-20 16:24:56 +02:00
Thomas Gelf
7ed87f0cd4 module.info, doc: raise requirements
incubator >= 0.20, main reason: db expressions in ZfDbTable
2023-07-20 16:23:34 +02:00
raviks789
fb39b25602 Change the install script for Icinga for Windows
Remove the powershell module in Agents tab and change the install script for Icinga for windows.
2023-07-20 12:46:01 +02:00
EmTeedee
6b7bff80de ${var} deprecated in favor of {$var}
See: https://www.php.net/manual/en/migration82.deprecated.php#migration82.deprecated.core.dollar-brace-interpolation
2023-07-19 10:44:40 +02:00
Thomas Gelf
de1311928c IcingaConfig: render IfW fallback template
fixes #2776
2023-07-19 07:00:46 +02:00
Thomas Gelf
91b99d8e46 ObjectsTable: apply filters for non-branched views
fixes #2775
2023-07-18 11:11:41 +02:00
Johannes Meyer
3e8b49f69a Revert "workflows: temporarily disable job"
This reverts commit ac73affcb481689102f47823e1b6affde621b52e.
2023-07-05 15:24:23 +02:00
raviks789
b47478293f fetch $this->affectedHost->get('id') only if $this->affectedHost->get('id') is not null for service set 2023-06-29 17:12:14 +02:00
raviks789
df08e91bc9 Strikethrough deactivated services in applied service set 2023-06-29 15:26:54 +02:00
Thomas Gelf
8e60e0aab9 HostController: relax assertion 2023-06-13 17:39:15 +02:00
Thomas Gelf
abbf580696 ImportSourceCoreApi: fix listColumns
Prior to this fix, only object_name has been listed (while all properties
have been imported)

fixes #2763
2023-06-06 14:32:01 +02:00
Thomas Gelf
83f9c00e9b ImportRowModifierForm: description readability 2023-05-31 07:18:51 +02:00
Thomas Gelf
722499ea76 ImportRowModifier: filters, CIDR support
fixes #2756
fixes #2757
2023-05-25 15:44:56 +02:00
Thomas Gelf
ac73affcb4 workflows: temporarily disable job
It's failing since three weeks, stating:

   Repository not found, OR token has insufficient permissions

Also, there is a warning:

    Node.js 12 actions are deprecated. Please update the following actions to
    use Node.js 16: peter-evans/repository-dispatch@v1. For more information
    see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/.
2023-05-16 11:25:48 +02:00
Thomas Gelf
868e0afe80 BasketDiff: return type is stdClass 2023-05-16 11:19:12 +02:00
Thomas Gelf
fb10bac7e9 Sync: fix loading existing templates
fixes #2217
fixes #2745
2023-05-11 15:07:28 +02:00
Thomas Gelf
623dd1cbc7 PropertyModifierSplit: check for null values
fixes #2739
2023-04-26 14:21:51 +02:00
Thomas Gelf
978d9bc51f PropertyModifierMap: fix duplicate line 2023-04-24 15:18:02 +02:00
Thomas Gelf
e98803a8e5 ObjectSetTable: search for services in branches
fixes #2738
2023-04-24 11:10:36 +02:00
wp-perc
9d6a41571a PropertyModifierMap: allow custom fallback value
fixes #2735
2023-04-21 18:05:20 +02:00
Thomas Gelf
48af679cf0 IcingaObjectGroup: membership calculation...
...is now being triggered only when assign_filter exists / has been
changed

fixes #2048
2023-04-21 16:03:58 +02:00
Silas
4ddf4112b1 Update director.po 2023-04-20 11:55:43 +02:00
Silas
e773bd1201 Update director.po 2023-04-20 11:55:43 +02:00
Silas
444823c3d3 Update director.po 2023-04-20 11:55:43 +02:00
Silas
599a0cce51 Update IcingaDependencyForm.php 2023-04-20 11:55:43 +02:00
Thomas Gelf
6675f17e73 AssignFilterHelper: quote slashes
fixes #2731
2023-04-20 11:53:23 +02:00
Thomas Gelf
9f76d7e605 BranchActivity: show related host for services
fixes #2736
2023-04-20 11:47:17 +02:00
Thomas Gelf
35e90f7b60 ExtensibleSet: do not load for loaded objects...
...w/o id (-> branch)

refs #2711
2023-03-17 07:40:32 +01:00
Thomas Gelf
27e7da9354 DirectorDatafieldForm: varname field description
refs #2723
2023-03-15 10:03:06 +01:00
Thomas Gelf
c3936f63bb BasketSnapshot: remove obsolete flag 2023-03-12 10:45:16 +01:00
Thomas Gelf
25bca75e9b BasketSnapshot: throw for outdated flag 2023-03-12 10:45:16 +01:00
Thomas Gelf
62bff81fac BasketUploadForm: allow uploading snapshots...
...for existing Baskets

fixes #1952
2023-03-12 10:45:09 +01:00
Thomas Gelf
749ab6a356 BasketSnapshotFieldResolver: dedicated exception..
...for invalid baskets, referencing missing fields
2023-03-11 09:34:52 +01:00
Thomas Gelf
b55df21c21 DirectorDatafield: cleanup, types 2023-03-08 17:03:10 +01:00
Thomas Gelf
915f57db99 DirectorDatafield: ignore uuid and originalId...
...on diff
2023-03-08 14:16:14 +01:00
Thomas Gelf
b7e887b251 schema: add UUIDs for datalist and datafield
fixes #2696
2023-03-07 19:31:55 +01:00
Thomas Gelf
6c611a5db4 DbObject: use original UUID in where
This allows to change a UUID
2023-03-07 18:22:59 +01:00
Thomas Gelf
045f4ec941 ObjectImporter, BasketDiff: fallback for baskets...
...with UUID, and no matching entry. Will adjust UUIDs for matching objects
2023-03-07 17:52:59 +01:00
Thomas Gelf
5a732170af Basket: support UUIDs
fixes #2716
2023-03-07 15:13:16 +01:00
Thomas Gelf
7d5d5b38ba Web/Form: fix dark mode for clone forms
fixes #2670
2023-03-07 14:30:56 +01:00
Thomas Gelf
bec49d1230 library: cleanup, drop import/export methods 2023-03-07 14:29:34 +01:00
Thomas Gelf
c07758b5d9 IcingaServiceSet: virtual services property...
...should be handled. We can now store a set with it's services
2023-03-07 14:03:09 +01:00
Thomas Gelf
c42fc4498a BasketDiff: normalize all base objects 2023-03-07 13:41:18 +01:00
Thomas Gelf
df10d6a924 CompareBasketObject::sortListBy() -> support array 2023-03-07 13:38:40 +01:00
Thomas Gelf
70a822f270 BasketDiff: new implementation
fixes #2715
2023-03-07 12:15:59 +01:00
Thomas Gelf
c24961f209 ObjectImporter: new centralized importer
fixes #2714
2023-03-07 12:11:44 +01:00
Thomas Gelf
b4839f6855 CompareBasketObject: objects should stay objects 2023-03-07 11:54:32 +01:00
Thomas Gelf
1d787ccb47 BasketSnapshotFieldResolver: give UNKNOWN, not NEW
This occurs on field removal too
2023-03-07 11:53:10 +01:00
Thomas Gelf
d3625e807d Basket: drop protectedFormerChosenObjects 2023-03-07 11:51:25 +01:00
Thomas Gelf
628f24d3d3 SyncRule: alternative setter for properties 2023-03-07 11:49:13 +01:00
Thomas Gelf
5029a30a62 SyncRule: drop obsolete originalId 2023-03-07 11:47:40 +01:00
Thomas Gelf
3893455388 SyncRule: we have a boolean property 2023-03-07 11:45:52 +01:00
Thomas Gelf
637a304f47 IcingaTemplateChoice: fix hasBeenModified...
...this used to be true, once properties have been set
2023-03-07 11:43:41 +01:00
Thomas Gelf
f1add44beb Basket: introduce constants 2023-03-07 11:41:14 +01:00
Thomas Gelf
7c8edfd467 Exporter: unserialize JSON-encoded Basket objects
New baskets provide a Dictionary
2023-03-07 11:39:11 +01:00
Thomas Gelf
cc211fbdfb Exporter: support booleans for DbObjects 2023-03-07 11:38:47 +01:00
Thomas Gelf
21d913e232 Exporter: services should be an array 2023-03-07 11:20:07 +01:00
Thomas Gelf
d6bec9bfe1 IcingaObject: cast interval properties to int
They might be strings when shipped from DB or older Baskets
2023-03-07 11:18:24 +01:00
Thomas Gelf
903f2c825f DbObject: introduce loadOptional
This prevents useless queries (e.g. exists() && load())
2023-03-07 11:17:37 +01:00
Thomas Gelf
2ade848f4d DbObject: provide boolean properties...
...as IcingaObject did, move convertion logic to DbDataFormatter
2023-03-07 11:16:22 +01:00
Thomas Gelf
bbf85f052b app, lib: formatting, syntax 2023-02-23 12:00:20 +01:00
Thomas Gelf
40254714b8 Permissions: refactor, fix monitoring module checks
fixes #2712
2023-02-23 11:51:53 +01:00
Thomas Gelf
51a7b68803 PropertyModifierRegexReplace: w/o match allow null
fixes #2705
2023-02-23 11:51:34 +01:00
Thomas Gelf
ce10b7e699 IcingaServiceSetServiceTable: link with uuid...
...to services in sets

refs #2710
2023-02-23 11:51:34 +01:00
Thomas Gelf
12aa7e07e2 BranchStore: quote binary values when cloning...
...branches, instead of letting prepared statements deal with this.

refs #2711
2023-02-23 11:51:34 +01:00
Thomas Gelf
b3e09978fa UuidLookup: fix for services created in sets...
...where the set exists in the branch only

fixes #2710
2023-02-23 11:51:34 +01:00
Thomas Gelf
4e41e7f2d8 Revert "Monitoring: no monitoring module, no Host/Service"
This reverts commit d90531858923caeafcfff8b580abb7d5216dda0d.
2023-02-22 11:34:57 +01:00
Thomas Gelf
d905318589 Monitoring: no monitoring module, no Host/Service
...and no error

fixes #2533
fixes #2563
2022-12-29 16:30:14 +01:00
Thomas Gelf
881eba7298 IcingaNotification: deal with missing vars 2022-12-28 11:04:13 +01:00
Thomas Gelf
ccc3e510a6 BranchSupportHook: typo 2022-12-28 11:02:17 +01:00
Thomas Gelf
0e6a574372 BranchesDashboard: comma hurts older PHP versions 2022-12-22 17:11:50 +01:00
Thomas Gelf
2ecca2aeba TemplateTree: sort by name
fixes #2691
2022-12-20 14:13:32 +01:00
Thomas Gelf
e03333b4dc IcingaNotificationForm: fix user groups field...
...detection

refs #462
2022-12-16 15:07:43 +01:00
Thomas Gelf
bacea2eeaa schema: branch support for notification user vars
refs #462
2022-12-16 15:02:59 +01:00
Thomas Gelf
e63870add2 BranchesDashboard: show main branch hint only...
...to users with a preferred branch
2022-12-16 14:39:37 +01:00
Thomas Gelf
c643959d06 PreferredBranchSupport: for directorbranches
fixes #2688
fixes #2689
2022-12-16 14:16:02 +01:00
Thomas Gelf
0db7240c96 Branch: do not use deprecated Hook class 2022-12-16 13:57:05 +01:00
Thomas Gelf
400bf8c0b0 DirectorJob: check for null
Fixes issue with merged PR on PHP 8.1

refs #2680
2022-12-08 13:43:25 +01:00
Thomas Gelf
58d28e6719 doc/changelog: mention merged pr
fixes #2680
2022-12-08 06:42:51 +01:00
Christian Maile
4619f8af9b fix wrong type casting 2022-12-08 06:34:19 +01:00
Thomas Gelf
4c98df7909 css: break Deployment Log lines
fixes #2677
2022-12-05 19:55:28 +01:00
Thomas Gelf
19e8be9801 doc/changelog: mention one more issue 2022-12-05 19:08:43 +01:00
Thomas Gelf
ef010f961b IcingaDependencies: allow unknown service...
...with a given specific host

fixes #2669
2022-12-05 12:58:57 +01:00
Thomas Gelf
e5de673f68 IcingaObjectFieldForm: sort case insensitive
fixes #2358
2022-12-05 12:48:30 +01:00
Thomas Gelf
616d329be3 IcingaNotification: implement users_var
fixes #462
2022-12-01 12:03:45 +01:00
Thomas Gelf
20785af8e7 doc/changelog: milestone link 2022-11-18 11:59:30 +01:00
Thomas Gelf
79db37f093 IcingaDependency: improve (cheated) type hint 2022-11-17 11:47:15 +01:00
Thomas Gelf
1818d0430a doc/rest-api: comma 2022-11-17 11:46:37 +01:00
Thomas Gelf
d042a3943a IcingaDependencyForm: check for null 2022-11-17 11:46:03 +01:00
Thomas Gelf
ef29ffd2af DirectorDeploymentLog: allow missing config 2022-11-16 11:18:22 +01:00
Thomas Gelf
51380a9e0b IcingaServiceSet: respect indivicual template zone
fixes #1589
fixes #2356
2022-11-15 17:28:33 +01:00
Thomas Gelf
071df2a072 IcingaCloneObjectForm: allow fields for Commands
fixes #2264
2022-11-15 15:56:18 +01:00
Thomas Gelf
a1e589ce6d doc/changelog: section for next release 2022-11-15 15:54:22 +01:00
Thomas Gelf
a1f043b34f doc/rest-api: fix typo 2022-11-10 14:11:55 +01:00
Thomas Gelf
f8653144bd doc/installation: raise version 2022-11-03 13:29:37 +01:00
Thomas Gelf
efd83bc095 doc/changelog: prepare v1.10.2 2022-11-03 10:24:53 +01:00
Thomas Gelf
21bb6c5676 Sync: always store stats w/o (branch) store
fixes #2633
2022-11-03 10:22:38 +01:00
Thomas Gelf
54a3f3d366 css: fix activity log pagination look 2022-11-03 08:51:33 +01:00
Thomas Gelf
b91cbd97b4 SyncUtils: give NULL on nested intermediate NULL
fixes #2474
fixes #2584
2022-11-03 08:07:07 +01:00
Thomas Gelf
2a37db1115 BranchController: ensure object type is set first
fixes #2142
fixes #2634
2022-11-03 07:25:39 +01:00
Thomas Gelf
ab952f89b0 ObjectSetTable: improve formatting
fixes #2648
2022-11-03 00:58:38 +01:00
Thomas Gelf
b04f6b7e98 IcingaNotification: improve error message
One more improved exception

refs #2142
2022-11-03 00:23:50 +01:00
Thomas Gelf
63d76abf81 IcingaObject: improve error message
Complain about missing object_type, if assign-related properties cannot be
set because of that reason

refs #2142
2022-11-03 00:20:30 +01:00
Thomas Gelf
693b8fe317 Sync: fix purge for objects with uppercase chars
fixes #2627
2022-11-02 21:12:40 +01:00
Thomas Gelf
01a80c2da8 SelfServiceController: check for null values
fixes #2614
2022-10-27 11:53:54 +02:00
Eric Lippmann
5462784507 docs: Fix link to packages.icinga.com 2022-10-27 09:13:42 +02:00
Eric Lippmann
fb4b1cff92 Docs: recommend to install from packages 2022-10-26 12:44:32 +02:00
Thomas Gelf
e42912d3e8 BranchedObject: set id first
This has an impact on related objects, like timeperiod ranges

fixes #2525
2022-10-26 11:04:58 +02:00
Thomas Gelf
ad5dfc8496 BasketSnapshot: simplify error handling
We have no IcingaObject here, they're all stdClass instances
2022-10-25 11:10:05 +02:00
Thomas Gelf
470137b5c2 Exporter: don't export UUIDs for non-Icinga objects
fixes #2644
2022-10-25 10:59:16 +02:00
Thomas Gelf
9892039b0e BasketSnapshot: show object-related details...
...in case an error occurs at encoding time

fixes #2646
2022-10-25 10:46:50 +02:00
Thomas Gelf
bfda96f569 DbConnection: deprecate/replace quoteBinary()
Proxies to newer code as a fix, related calls should be substituded
in the long run

fixes #2630
2022-10-18 16:53:06 +02:00
Thomas Gelf
deb5b97ea0 DbObjectStore: treat UUID result for PostgreSQL
fixes #2636
2022-10-13 10:58:32 +02:00
Thomas Gelf
5aca652355 doc/installation: raise version to v1.10.1 2022-10-07 12:59:28 +02:00
Thomas Gelf
3b7a7ed367 doc/changelog: prepare v1.10.1 2022-10-07 12:54:33 +02:00
Thomas Gelf
91ca8065e3 Sync: fix purge and invalid sync history
fixes #2632
fixes #2627
2022-10-07 12:23:47 +02:00
Thomas Gelf
82269775f4 DbObject: improve "hasBeenModified" logic 2022-10-07 11:20:32 +02:00
Thomas Gelf
2196426ff5 IcingaObject: fix default value for preserve 2022-10-07 10:25:23 +02:00
Thomas Gelf
166fc88117 doc/changelog: prepare v1.10.1 2022-10-07 10:22:52 +02:00
Thomas Gelf
afc7efe4d5 Sync: do not set null if overridden
refs #2623
2022-10-07 10:18:39 +02:00
Thomas Gelf
9a2c0162d2 Sync: respect null properties on merge
fixes #2623
2022-10-07 10:16:37 +02:00
Thomas Gelf
82fbd5359e DbObjectStore: sort by array index, not uuid 2022-10-07 10:12:00 +02:00
Thomas Gelf
773a135220 DbObject: grant access to default properties 2022-10-07 10:12:00 +02:00
Thomas Gelf
6f0c7aa2a3 IcingaObject: allow to replace with plain object 2022-10-07 10:12:00 +02:00
Thomas Gelf
f447457c40 Sync: load object w/o branch support the old way
fixes #2618
2022-10-06 13:08:48 +02:00
Thomas Gelf
3c2815d2e9 CoreApi: fix version comparison logic
fixes #2629
2022-10-05 11:14:37 +02:00
raviks789
26e76c611e Reset Limit count and offset for $table in HostController::servicesAction
The limit in ObjectsTable::prepareQuery() limits the number of services shown in HostController::servicesAction.
But this limit is required for pagination in ServicesController. Hence, reset the limit when this query is used
in HostController::servicesAction().
2022-10-04 15:33:29 +02:00
Thomas Gelf
560e0e6520 CustomVariables: do not render deleted ones
fixes #2622
2022-09-30 13:47:05 +02:00
Thomas Gelf
867138abe3 AppliedServiceInfo: fetch UUID object
fixes #2615
2022-09-30 12:15:33 +02:00
Thomas Gelf
b6ed832a03 AppliedServiceSetServiceInfo: provide the UUID
fixes #2619
2022-09-30 11:44:18 +02:00
Ravi Kumar Kempapura Srinivasa
2d5d0db77c DirectorJob: fix restoring from snapshot
fixes #2528
2022-09-30 11:40:02 +02:00
Thomas Gelf
5d199b41d5 doc/changelog: mention basket restore
fixes #2620
2022-09-30 11:36:08 +02:00
Thomas Gelf
54c838666c Job, Import, Sync: fix restore w/o ID 2022-09-30 11:32:16 +02:00
Dan Ford
5ddb36e45a Correcting typo translation ids 2022-09-26 09:27:29 +02:00
Dan Ford
ece41868a7 Fixing UI typo for notification times 2022-09-26 09:27:29 +02:00
Thomas Gelf
9ac155bed9 schema: remove duplicate line
fixes #2609
2022-09-23 10:57:50 +02:00
Thomas Gelf
204617a3ee doc/changelog: introduce v1.10.1 section 2022-09-22 17:44:54 +02:00
Thomas Gelf
60bdef6752 Sync: create objects with original key...
...and not with the lower-cased comparison key

fixes #2608
2022-09-22 17:37:26 +02:00
Thomas Gelf
0682ee5ba8 module.info: back to master 2022-09-21 13:59:12 +02:00
Thomas Gelf
26c8e13d96 doc/changelog: summary for v1.10 2022-09-21 13:58:25 +02:00
Thomas Gelf
68b9595bf0 doc, module.info: prepare v1.10.0 2022-09-21 11:51:18 +02:00
Thomas Gelf
f2eb06ae39 BranchStore: wipe branched tables, not real ones 2022-09-21 11:51:05 +02:00
Thomas Gelf
0cb6e40681 IcingaService: improve error message 2022-09-21 11:50:26 +02:00
Thomas Gelf
76be10d0d7 doc/changelog: mention sync preview 2022-09-21 11:50:26 +02:00
Thomas Gelf
ad046b00d2 IcingaServiceForm: set name, not id -> branches 2022-09-21 11:26:47 +02:00
Thomas Gelf
ebb08aceae ObjectSetTable: fix for PgSQL when not in branch 2022-09-21 11:00:07 +02:00
Thomas Gelf
c15ec70ab9 schema/pgsql: drop uuid uniqueness in branches 2022-09-21 09:57:54 +02:00
Thomas Gelf
1ff140e9bc locale: refresh German translation 2022-09-21 09:25:40 +02:00
Johannes Meyer
3055552728 IcingaObjectQuery: Use $connection->renderFilter instead of whereToSql
`whereToSql` did support timestamp handling in comparison, though this
class couldn't have made use of it since it had to use a query which
overrides the `isTimestamp` function.
2022-09-21 09:04:29 +02:00
Daniel Patrick
04c4bd2559 IcingaCommand: Remove obsolete CLR check 2022-09-21 08:52:51 +02:00
Thomas Gelf
05de5b171b BranchMerger: log change author
fixes #2606
2022-09-21 08:50:45 +02:00
Thomas Gelf
e4fdb02de8 doc, module.info: raise dependencies 2022-09-21 08:31:52 +02:00
Thomas Gelf
644ac0d1c7 doc/changelog: mention implemented branch Sync
This has already been merged

fixes #2552
2022-09-21 08:27:09 +02:00
Thomas Gelf
1ac6316a25 doc/changelog: add some missing topics 2022-09-21 08:26:08 +02:00
Thomas Gelf
79f8ca26ef Branch: allow access to description
fixes #2604
2022-09-21 07:51:25 +02:00
Thomas Gelf
c91ff3303c ExtensibleSet: short array syntax, readability 2022-09-20 20:28:05 +02:00
Thomas Gelf
b6bfe913f8 Merge branch 'feature/serviceset-in-branches-refactored' 2022-09-20 15:27:45 +02:00
Thomas Gelf
47488d138e ObjectSetTable: fix a PostgreSQL issue 2022-09-20 15:27:16 +02:00
Thomas Gelf
42b06a0b37 schema: branched service sets 2022-09-20 14:45:04 +02:00
Thomas Gelf
b19dd5f62d IcingaServiceSet: use query builder to retrieve...
...services, this is required for branches
2022-09-20 12:55:55 +02:00
Thomas Gelf
c56b190469 ServicesetController: allow branch access 2022-09-20 12:54:28 +02:00
Thomas Gelf
59d62d0ff9 ObjectSetTable: branch support 2022-09-20 12:53:00 +02:00
Thomas Gelf
25f961a4c8 HostController: allow to add Sets 2022-09-20 12:50:37 +02:00
Thomas Gelf
a684929cf5 ObjectController: allow Service Sets in Branches 2022-09-20 12:48:26 +02:00
Thomas Gelf
de4b890e8b IcingaServiceSetForm: use host, not host_id 2022-09-20 12:30:06 +02:00
Thomas Gelf
6f173b8392 ObjectsController: pass branch to table 2022-09-20 12:22:05 +02:00
Thomas Gelf
131d4e27ba TableWithBranchSupport: provide setter 2022-09-20 12:20:44 +02:00
Thomas Gelf
3c8bb6bd16 IcingaServiceForm: protect against branched objects
...w/o id. Can be improved
2022-09-20 12:19:53 +02:00
Thomas Gelf
4d2f285c01 IcingaServiceSetServiceTable: branch classes 2022-09-20 12:19:31 +02:00
Thomas Gelf
4d8e3f6db7 ServiceSetQueryBuilder: new query builder 2022-09-20 12:19:21 +02:00
Thomas Gelf
4e1cc13320 ServiceController: enableStaticObjectLoader earlier 2022-09-20 12:16:20 +02:00
Thomas Gelf
f301be425c HostController: pass branch to forms 2022-09-20 12:16:00 +02:00
Thomas Gelf
39f53b6cee ObjectController: branch hint on create 2022-09-20 12:06:52 +02:00
Thomas Gelf
2a5909917b BranchSupport, Inspection: allow Sets 2022-09-20 12:05:43 +02:00
Thomas Gelf
758b99126a IcingaServiceForm: no deactivate in branch for now 2022-09-20 12:04:46 +02:00
Thomas Gelf
1fbb4d93b6 BranchedObjectHint: allow no object (create) 2022-09-20 12:03:46 +02:00
Thomas Gelf
b35b6b84cc TableWithBranchSupport: do not branchify relations 2022-09-20 12:03:00 +02:00
Thomas Gelf
ae0992f196 UuidLookup: host_id VS host in branch 2022-09-20 11:54:10 +02:00
Thomas Gelf
8b1513830c IcingaServiceSet: do not delete Services w/o id 2022-09-20 07:20:29 +02:00
Thomas Gelf
166b862114 PropertyModifierFromLatin1: use iconv 2022-09-19 10:09:52 +02:00
Thomas Gelf
e3e92cdb3a AppliedServiceSetLoader: change method visibility
...for fetchAppliedServiceSets()
2022-09-19 07:41:44 +02:00
Thomas Gelf
410913e512 UuidLookup: fix host/set related fallback 2022-09-15 11:45:32 +02:00
Thomas Gelf
8bfbe2a80f IcingaServiceSet: friendlier error message 2022-09-15 11:44:43 +02:00
Thomas Gelf
9434cf5089 IcingaServiceSet: type hint for IDE 2022-09-15 11:44:24 +02:00
Thomas Gelf
0cf8c76617 IcingaObject: more details in the error message 2022-09-13 10:20:24 +02:00
Thomas Gelf
1df495b41e UuidLookup: fix lookup for cloned branches 2022-09-09 14:30:51 +02:00
Thomas Gelf
3c7c7bc61a ServicesetController: stringify uuid once 2022-09-05 12:23:13 +02:00
Thomas Gelf
dd85c2ee35 Sync: compare keys in a case-insensitive way
fixes #2598
2022-08-31 16:36:31 +02:00
Thomas Gelf
28c149efed IcingaServiceSetServiceTable: refactor link logic 2022-08-31 14:45:28 +02:00
Thomas Gelf
d433631174 TableWithBranchSupport: new trait 2022-08-31 14:45:28 +02:00
Thomas Gelf
0f2045c8f6 SyncruleController: fix preview logic 2022-08-31 14:45:28 +02:00
Thomas Gelf
98cfcafdcd BranchSupport: introduce new constants 2022-08-31 14:45:28 +02:00
Thomas Gelf
ae45844bac Sync: fix typo, remove useless cast 2022-08-31 14:45:28 +02:00
Thomas Gelf
956708475e BranchSupport: new helper class 2022-08-31 14:45:28 +02:00
Thomas Gelf
b2afca2496 Sync: support branches 2022-08-31 14:45:28 +02:00
Thomas Gelf
1682175716 register-hooks: no monitoring hook w/o Director UI
fixes #2597
2022-08-31 14:44:44 +02:00
Thomas Gelf
53e45da815 KickstartForm: fix ini file rendering
fixes #2595
2022-08-31 13:33:41 +02:00
Thomas Gelf
3b1d3e25ca css: fix filter element width, add upper border 2022-08-29 23:49:01 +02:00
Thomas Gelf
1c30412abd DirectorActivityLog, others: constants, cleanup 2022-08-20 20:41:07 +02:00
Thomas Gelf
047b14ccbf Sync: preserve Host api_key in override mode
fixes #2590
2022-08-19 10:57:05 +02:00
Thomas Gelf
0cf113e0a6 ObjectCommand: simplify object creation 2022-08-03 12:20:40 +02:00
Thomas Gelf
4666497c55 ObjectCommand: refactor property preparation 2022-08-03 10:50:01 +02:00
Thomas Gelf
fae9783ff9 HostServiceLoader: less logic in Exporter 2022-08-03 10:23:39 +02:00
Thomas Gelf
9015993b05 Exporter: catch improbable error condition 2022-08-03 09:10:00 +02:00
Thomas Gelf
079e6e6514 ImportExportDeniedProperties: extract logic 2022-08-03 09:01:09 +02:00
Thomas Gelf
74ea9adbf2 Exporter: better variable name 2022-08-03 08:54:15 +02:00
Thomas Gelf
5409558d3b ObjectCommand: show created object name...
...even if given via JSON only

fixes #2576
2022-08-02 11:59:21 +02:00
Thomas Gelf
05362a093d IcingaObjectHandler: create object before storing
refs #2576
2022-08-02 11:55:26 +02:00
Thomas Gelf
5686629e27 Exporter: export services, not tables 2022-07-28 15:14:03 +02:00
Thomas Gelf
37954e0aa6 BranchActivityTable: show object name 2022-07-22 14:32:39 +02:00
Thomas Gelf
fca804e74e ObjectCommand: --all-services
fixes #2571
2022-07-21 07:49:12 +02:00
Thomas Gelf
431d0cfe75 ObjectCommand: add --resolve-services 2022-07-20 16:42:26 +02:00
Thomas Gelf
f1df0b6c7a RequestHandler: optionally return stack traces
fixes #2570
2022-07-20 12:03:32 +02:00
Thomas Gelf
b444ec0101 IcingaObjectHandler: allowOverrides for REST API
fixes #2569
2022-07-20 11:58:17 +02:00
Thomas Gelf
e1d7a639d3 ServiceCommand: return after setting overrides 2022-07-20 10:15:00 +02:00
Thomas Gelf
13c09855fa ObjectController: refactor initalization 2022-07-20 09:59:42 +02:00
Thomas Gelf
34d5e445b2 doc/REST-API: document new parameters 2022-07-20 09:45:26 +02:00
Thomas Gelf
0d68ee0fda PropertyMangler: new static helper 2022-07-20 09:04:38 +02:00
Thomas Gelf
a34d5c15ef ServiceCommand: improve readability 2022-07-20 08:54:27 +02:00
Thomas Gelf
1f3b039395 OverrideHelper: centralize applying overrides 2022-07-20 08:52:10 +02:00
Thomas Gelf
6d0b9310c3 Object/ServiceCommand: some more refactoring 2022-07-20 08:48:09 +02:00
Thomas Gelf
fc5d3de568 PropertyModifierReplaceNull: code style fix 2022-07-20 08:38:45 +02:00
Thomas Gelf
02bed9265a ServiceCommand: extract override-logic 2022-07-20 08:34:05 +02:00
Thomas Gelf
706a9b1fc1 ObjectCommand: document --with-services
refs #2565
2022-07-20 08:29:42 +02:00
Thomas Gelf
ab4b5807be RestApi: introduce RestApiParams, use Exporter
fixes #2568
2022-07-20 08:21:34 +02:00
Thomas Gelf
cb355f9b90 Exporter: support property filters
refs #2568
2022-07-20 08:13:25 +02:00
Thomas Gelf
164d1f5874 Command: fail() should show a readable message
fixes #2567
2022-07-20 06:44:41 +02:00
Thomas Gelf
0a25e256d1 ObjectCommand: formattingtt 2022-07-20 06:38:13 +02:00
Thomas Gelf
9775922975 ObjectCommand: support JSON via STDIN
fixes #1570
2022-07-20 06:37:06 +02:00
Thomas Gelf
2821b0721d IcingaObjectsHandler: send error message, not trace 2022-07-19 12:26:51 +02:00
Thomas Gelf
349cc33046 ServiceController: throw 404 2022-07-19 12:07:49 +02:00
Thomas Gelf
cb58573558 SimpleNote: do not fail on invalid content 2022-07-18 12:14:20 +02:00
Thomas Gelf
c586b2c194 ObjectCommand, Exporter: hosts with services
fixes #2565
2022-07-18 11:35:46 +02:00
Thomas Gelf
05d7e137c2 IcingaArguments: clarify reason for missing DSL...
...in External Commands imported via Icinga 2 API

fixes #2557
2022-07-18 10:08:51 +02:00
Thomas Gelf
fe3d5c7076 ObjectsController: fix 8.1 glitch for JSON format 2022-07-15 22:05:56 +02:00
Thomas Gelf
f24f8eb287 IcingaObject: more details in comment 2022-07-12 11:28:54 +02:00
Thomas Gelf
050553164d ServiceCommand: allow magic overrides
fixes #2560
2022-07-12 11:27:42 +02:00
Thomas Gelf
922b19397c IcingaObject: resolve related properties when...
...telling an object to be "unmodified"

fixes #2559
2022-07-12 10:02:58 +02:00
Thomas Gelf
d13919681a IcingaEndpoint: give meaningful error...
...when trying to get an ApiUser where there is no such
2022-07-12 10:00:58 +02:00
Thomas Gelf
b4c05738ae ServiceFinder: optional Auth
Hint: not required on CLI
2022-07-11 10:06:48 +02:00
Thomas Gelf
4a4e540700 ServiceInfo: ship UUID 2022-07-11 10:05:22 +02:00
Thomas Gelf
6d5c48125e Command: remove custom JSON logic 2022-07-11 10:03:23 +02:00
Thomas Gelf
535bdfd23d css: remove quicksearch 2022-07-01 08:42:10 +02:00
Thomas Gelf
0a51d02b86 DeploymentLinkForm: style with gipfl 2022-07-01 08:40:42 +02:00
Thomas Gelf
0796635132 DbHelpers, Connection: improve escapeBinary logic
hex-style for MySQL too, support array values
2022-07-01 08:39:12 +02:00
Thomas Gelf
14317a9c20 css, QuickForm: style director-form only 2022-07-01 08:38:33 +02:00
Thomas Gelf
4c502bb010 ServiceController: do not pass object type...
...when looking up uuid for legacy key

refs #2487
refs #2554
2022-06-24 14:33:38 +02:00
Thomas Gelf
aacfd88df5 Merge branch 'feature/centralized-exporter-2549' 2022-06-24 12:53:14 +02:00
Thomas Gelf
56f81b91bb Exporter: centralize export logic
fixes #2549
2022-06-24 12:52:35 +02:00
Thomas Gelf
0f4bc076e3 Merge branch 'feature/modifier-dict-row-2555' 2022-06-24 12:27:26 +02:00
Thomas Gelf
ef80b6b8bc DictionaryToRow: new property modifier
fixes #2555
2022-06-24 12:26:01 +02:00
Thomas Gelf
9a0279b111 UuidLookup: do not enforce service objects
fixes #2487
fixes #2554
2022-06-24 10:37:09 +02:00
Ibrahim Khalifa
4b229c122c Handle cases when gipfl/linux-health returns false instead of memory usage. 2022-06-24 08:55:09 +02:00
Thomas Gelf
75b73604a8 SyncRule: remove unused property 2022-06-20 09:59:01 +02:00
Thomas Gelf
411733a1ed schema: add index on deployment log startup time
fixes #2551
2022-06-20 09:58:49 +02:00
Thomas Gelf
31c06d8156 ObjectCommand: use real/file-based renderer
fixes #2550
fixes #2204
2022-06-20 09:57:07 +02:00
Thomas Gelf
0f6fc7bfd0 ImportRowModifierForm: fix exception message 2022-06-09 09:38:18 +02:00
raviks789
9e8142b79a Avoid passing null to strlen in SyncJob::addSettingsFormFields() 2022-06-08 16:15:42 +02:00
Patrick Dolinic
4692b28dbd PropertyModifier: Replace Null with String 2022-04-20 14:46:37 +02:00
raviks789
67eb4c1e90 Prevent inserting blank entries for extensible data list. 2022-04-20 08:26:46 +02:00
Thomas Gelf
2c56d5a731 doc/cli: add missing dashes 2022-04-13 14:09:58 +02:00
Thomas Gelf
0539819d4c ConditionalDeployment, ConfigCommand: wording
fixes #2523
2022-04-13 14:07:24 +02:00
Thomas Gelf
70e8c06b06 ConfigCommand: don't wait when no deployment...
...took place

fixes #2522
2022-04-13 13:55:47 +02:00
Thomas Gelf
f61cdf2843 doc/changelog: add section for v1.10.0 2022-04-13 13:55:33 +02:00
Thomas Gelf
957b789a35 doc: v1.9.1 has been released 2022-04-08 11:11:08 +02:00
Johannes Meyer
e88d0472da css: Cleanup variable usage 2022-04-07 11:09:46 +02:00
Florian Strohmaier
dbe92872f4 CSS: Small fixes 2022-04-07 11:09:46 +02:00
Yonas Habteab
052fef98bf CSS: Adjust less variable usages 2022-04-07 11:09:46 +02:00
Thomas Gelf
11f621df30 IcingaServiceSet: do not eport the UUID for now
fixes #2488
2022-04-05 08:48:42 +02:00
Thomas Gelf
d92a5e846b IcingaServiceForm: check for null 2022-04-04 19:40:42 +02:00
Thomas Gelf
93d0afff10 SyncruleController: useless use of use 2022-04-04 19:39:47 +02:00
raviks789
e134f80093 Cleanup IcingaDbCubeLinks with getObjectsFilter provided by IcingaDbCube. 2022-03-28 15:39:49 +02:00
moreamazingnick
83cc12944d
DirectorActivityLog: fix empty activity log exception
fixes #2505: empty activity log causes exception
fixes #2506
2022-03-28 14:52:46 +02:00
Thomas Gelf
1caf0f40db doc/cli: table format 2022-03-23 12:28:14 +01:00
Thomas Gelf
9afa3313ab cli: implement deployment grace period and...
...refactor/restructure related code to achieve the same behavior on CLI and
via automated job

fixes #2499
2022-03-22 10:46:36 +01:00
raviks789
71f3654c0b Fix sync rule restore from snapshot on name change
On name change new Sync rule would be created, hence we do not have to preserve the Sync rule Ids in SyncRule::import() method.
2022-03-17 14:55:35 +01:00
Thomas Gelf
f64822c409 IcingaServiceForm: strip table limit for enum
fixes #2481
2022-03-17 14:23:15 +01:00
Thomas Gelf
0706bd09d4 schema/pgsql: don't duplicate unique index
fixes #2482
2022-02-25 15:52:26 +01:00
Thomas Gelf
ccd6f4266a DbObject: exists() must check for UUID column
fixes #2475
2022-02-24 16:38:48 +01:00
Thomas Gelf
ccd4d694d8 module.info: back to master 2022-02-17 16:52:08 +01:00
Thomas Gelf
6c82a5ae84 README: remove travis 2022-02-17 16:40:49 +01:00
Thomas Gelf
0806749055 de_DE: refresh translation 2022-02-17 16:36:49 +01:00
Thomas Gelf
f1c1cc57e7 Prepare v1.9.0 2022-02-17 15:46:41 +01:00
Thomas Gelf
0f1ef78815 IcingaArguments: remove superfluous semicolon 2022-02-17 15:37:44 +01:00
Thomas Gelf
984e931954 BasketSnapshot: support datafield categories
fixes #2256
2022-02-16 23:14:38 +01:00
Thomas Gelf
a50593c082 doc/changelog: mention more fixes/features 2022-02-15 21:49:51 +01:00
Thomas Gelf
1cfc0c427c ActivityLogInfo: show remarks
refs #2471
2022-02-15 21:13:24 +01:00
Thomas Gelf
aeef51ffa6 IcingaArguments: allow to restore set_if_format
fixes #2291
2022-02-09 21:59:53 +01:00
Thomas Gelf
7ae1ed7798 css: merge comment hover -> default cursor 2022-02-09 16:10:45 +01:00
Thomas Gelf
7eeff6d9b4 css: lighter background for merge messages 2022-02-09 15:54:11 +01:00
Thomas Gelf
ecf7bce482 ActivityLogTable: use more space, hover texts 2022-02-09 15:43:09 +01:00
raviks789
4f38557374 Prevent deletion of data lists that are in use.
Deletion of data lists which are used in icinga objects (through custom variables) or in sync rules is prevented.
2022-02-09 15:17:47 +01:00
Thomas Gelf
95730fb0aa BranchActivity: require connection when creating...
...new objects
2022-02-09 14:46:42 +01:00
Thomas Gelf
767329443b BranchMerger: make comment optional 2022-02-08 08:59:23 +01:00
Thomas Gelf
bb567946d2 BranchMerger: no remark with empty comment 2022-02-08 08:58:34 +01:00
Thomas Gelf
8bcc20e004 ActivityLogTable: support remarks
fixes #2471
2022-02-08 08:58:34 +01:00
Thomas Gelf
9611381956 BranchMerger: trigger activity log entry when...
...deleting an object
2022-02-08 08:58:34 +01:00
Lucas Bickel
3590f725eb fix: use bell icon for notifications 2022-02-06 19:34:03 +01:00
Thomas Gelf
961a46a6cc ServiceController: ask DbObjectTypeRegistry 2022-02-06 19:15:09 +01:00
Thomas Gelf
9269b054f2 IcingaMultiEditForm: store modifications to branch
...when being in a branch
2022-02-06 19:14:35 +01:00
Thomas Gelf
43dddc58aa ObjectsController: allow uuid for MultiSelect
fixes #2466
2022-02-06 19:13:47 +01:00
Thomas Gelf
9a2d165583 BranchedObjectHint: 404 when deleted 2022-02-06 19:09:30 +01:00
Thomas Gelf
9bb600c13b ServiceController: drop obsolete method 2022-02-06 15:32:48 +01:00
Thomas Gelf
ef360809e6 IcingaServiceForm: set host, not host_id
This allows to create services on hosts which have been created in a branch
2022-02-06 13:49:40 +01:00
Thomas Gelf
269637ce9f IcingaServiceForm: store overrides to branch...
...if set
2022-02-06 13:48:59 +01:00
Thomas Gelf
fc6f8740fb ServicesetController: no service access in branch 2022-02-06 13:43:20 +01:00
Thomas Gelf
30f0d85158 UuidLookup: allow multi-key objects
Hint: we do not (yet) support templates in branches, but we need to deal
with related lookups
2022-02-06 13:19:17 +01:00
Thomas Gelf
a05300dc24 DbObject: trigger 404 where we get no UUID 2022-02-06 13:18:58 +01:00
Thomas Gelf
4792859657 IcingaServiceForm: do not return void result 2022-02-06 12:32:51 +01:00
Thomas Gelf
21a67e355f IcingaServiceForm: combine duplicate code 2022-02-06 12:31:59 +01:00
Thomas Gelf
c296b716de IcingaServiceForm: some cleanup 2022-02-06 12:28:18 +01:00
Thomas Gelf
d615ce932c DirectorObjectForm: do not return void 2022-02-06 11:48:03 +01:00
Thomas Gelf
6db30263d0 DirectorObjectForm: allow host (w/o id) in main 2022-02-06 11:47:41 +01:00
Thomas Gelf
2845be7542 DirectorObjectForm: remove unused method 2022-02-06 11:47:23 +01:00
Thomas Gelf
818ee7a01a DirectorObjectForm: don't set vals twice on create 2022-02-06 11:46:22 +01:00
Thomas Gelf
b7aa578dee IcingaHost: filter internal properties from enum 2022-02-06 11:41:20 +01:00
Thomas Gelf
eddaf7c9a4 IcingaObject: some cleanup 2022-02-06 11:39:03 +01:00
Thomas Gelf
891b6112aa IcingaObject: ignore uuid when resolving properties 2022-02-06 11:37:01 +01:00
Thomas Gelf
324cc9ed5b IcingaObject: do not unset unresolved related...
...properties, as long as they do not give us an object with an ID.
This is the case when adding new services to hosts which exist in a
branch only, and will no longer be a problem once our internal caches
work with UUIDs
2022-02-06 11:35:00 +01:00
Thomas Gelf
351c41cb3c IcingaAddServiceForm: avoid duplicate get() call 2022-02-06 11:30:47 +01:00
Thomas Gelf
b6f6b786c5 FiltersWorkAsExpected: test Icinga Web filters...
...for some important cases
2022-02-03 11:03:54 +01:00
raviks789
b04fe28932 Delete newly added Services in Service Set when restoring it from snapshot
The Services which were added into the Service Set after the snapshot was created
must be deleted when the Service Set is being restored from the snapshot.
2022-01-24 15:26:48 +01:00
Johannes Meyer
420dfcbdbf Avoid passing non-string args to ctype_*() functions 2022-01-14 11:31:55 +01:00
Thomas Gelf
2712275c45 DeploymentStatus: fix method signature, use getter 2022-01-10 18:44:45 +01:00
Thomas Gelf
31a66b6619 DeploymentStatus: little fix, formatting 2022-01-10 18:20:08 +01:00
Thomas Gelf
251cd309be DeploymentStatus: fix CLI command for PostgreSQL
fixes #2260
2022-01-10 18:18:09 +01:00
Thomas Gelf
0fcbc2783b IcingaServiceSet: load services by UUID
fixes #2454
2022-01-10 13:31:25 +01:00
Thomas Gelf
274c153837 various: PHP8.1-related warnings 2022-01-10 11:44:33 +01:00
Thomas Gelf
2113484b20 IcingaArguments: fix delete 2022-01-09 21:42:39 +01:00
Thomas Gelf
87a16f11fa DbObject: fix Command Argument creation
fixes #2453
2022-01-09 21:36:40 +01:00
Thomas Gelf
c487a8b447 ServiceController: refactor loading for related...
...objects

refs #2452
2021-12-23 13:47:29 +01:00
Thomas Gelf
36babe65f7 IcingaServiceSetServiceTable: use host uuid for...
...Set Member related to host
2021-12-23 13:46:37 +01:00
Thomas Gelf
caccecded6 IcingaHost: ignore warning 2021-12-23 13:46:04 +01:00
Thomas Gelf
2e01e181aa DbObject: exists should return false...
...in case there is no related uuid

refs #2434
2021-12-23 10:30:58 +01:00
Thomas Gelf
1cbb033911 ServiceController: load Set and Host before...
...the service, which get's loaded in the parent class

fixes #2452
fixes #2449
2021-12-23 10:25:59 +01:00
Thomas Gelf
212596a41e ObjectSetTable: drop name from link 2021-12-23 10:07:07 +01:00
Thomas Gelf
7d68f8014b ServicesetController: one more PHP 8.1 warning 2021-12-23 10:06:38 +01:00
Thomas Gelf
673c1c520e DirectorDeploymentLog: do not query empty stage
fixes #2426
2021-12-22 11:46:18 +01:00
Thomas Gelf
a86c751c33 Cube, BranchedObject: formatting 2021-12-22 11:45:57 +01:00
Thomas Gelf
c7cba433ed DbObject: indentation 2021-12-21 14:18:56 +01:00
Thomas Gelf
68814e0de6 IcingaObjectImports: fix PHP 8.1 notice 2021-12-21 09:01:06 +01:00
Thomas Gelf
27e5e72f41 ObjectsTable: do not apply restrictions to objects
...created in the current config branch
2021-12-17 17:16:50 +01:00
Thomas Gelf
f77d5b8d0c HostController: show services for hosts created...
...in a branch
2021-12-17 13:57:18 +01:00
Thomas Gelf
e3cae7c20a ObjectsTable: remove outdated/duplicate method 2021-12-17 13:56:37 +01:00
Thomas Gelf
4c24781a11 Merge branch 'fix/load-related-branched-objects' 2021-12-17 12:53:09 +01:00
Thomas Gelf
376344257c DbObjectStore: inject into DbObject for related...
...objects in a branch
2021-12-17 12:51:24 +01:00
Thomas Gelf
56d052a804 HostController: translate untranslated string 2021-12-17 11:47:20 +01:00
Thomas Gelf
6caa02c716 dependencies: remove obsolete 'use' 2021-12-17 11:47:14 +01:00
Thomas Gelf
7f22c12f9f Host/ObjectController: no sets in branches 2021-12-17 08:06:20 +01:00
Thomas Gelf
60104327bf ObjectController: add some branch-related hints 2021-12-14 10:46:52 +01:00
Thomas Gelf
b07ee0dd8e TemplatesTable: use uuid for history link 2021-12-14 10:42:48 +01:00
Thomas Gelf
68cf42490f Importsource: some more branch-related hints 2021-12-14 08:36:08 +01:00
Thomas Gelf
bfdcafca52 Ranges: common class, fix store/delete issues
This removes duplicate code, fixes some issues introduced with UUIDs and does
some cleanup

fixes #2415
fixes #2442
2021-12-14 08:33:50 +01:00
Thomas Gelf
eeaf3a84e3 ActivityLogTable: no text search for action
fixes #2057
2021-12-13 14:47:30 +01:00
Thomas Gelf
27abbb59a0 ObjectsTableService: replace HostServiceTable
This removes duplicate logic and shows services created in config
branches
2021-12-13 14:11:35 +01:00
Thomas Gelf
b70b19ad32 Dashlet, Kickstart: fix translatable strings
fixes #2405
2021-12-13 13:36:26 +01:00
Thomas Gelf
f35ded85fb ArrayCustomVariablesFilter: check for type (PHP81) 2021-12-13 13:35:16 +01:00
Yonas Habteab
ef4068ebde Move css styles from SelfService to module.less 2021-12-13 13:09:36 +01:00
apaskowski
e657806ee4 IcingaTimePeriod: make description more clear 2021-12-13 08:59:08 +01:00
Thomas Gelf
100bc4b777 library: php8-related cleanup 2021-12-06 23:03:06 +01:00
Thomas Gelf
2f326576d9 module.info: raise dependencies 2021-12-06 22:11:53 +01:00
Thomas Gelf
257537d022 DbUtil: helper for pgsql binary resource handling 2021-12-06 22:11:31 +01:00
Thomas Gelf
ff57ec5c77 FormStoredPassword: check for null 2021-12-06 22:10:46 +01:00
Thomas Gelf
e27cda645d JobDetails: fix null issue 2021-12-06 21:36:56 +01:00
Thomas Gelf
37db546a0d ObjectsTableHostTemplateChoice: fix method params 2021-12-01 23:50:29 +01:00
Thomas Gelf
215988c3ca library: some hints for PHP 8.1 2021-12-01 23:50:04 +01:00
Thomas Gelf
b7c0559212 Merge branch 'fix/serviceset-uuid'
fixes #2417
fixes #2418
2021-12-01 23:48:14 +01:00
Thomas Gelf
e23e804421 schema: complete migrations for icinga_service_set 2021-11-30 13:48:05 +01:00
Ravi Kumar Kempapura Srinivasa
388c79e430 Add uuid to service sets. 2021-11-28 11:15:31 +01:00
Thomas Gelf
5fe0a8812c Monitoring permissions for single services only 2021-11-28 11:13:28 +01:00
Thomas Gelf
82656de2c2 Director: some PHP 8.1-related changes 2021-11-28 11:13:08 +01:00
Johannes Meyer
ac575858dc schema: Quote keyword groups 2021-11-28 11:08:25 +01:00
raviks789
124c4e4c17 Add cube links for objects from Icingadb and register the hook 2021-11-24 14:43:41 +01:00
Thomas Gelf
6786cc768f Director: some fixes for PHP v8.1
refs #2435
2021-11-24 11:56:18 +01:00
Thomas Gelf
cb16733420 ServiceController: make sure to set branch and...
...host on Service Form
2021-11-24 11:52:07 +01:00
Markus Frosch
4f959572f2 Add feature to specify a custom endpoint name for a host
- Render Endpoint and Zone with a different name per host
- Add custom variable `_director_custom_endpoint_name` to a host with that name
- Update `command_endpoint` behavior in services to use custom var or hostname
- Includes a feature flag that needs to be enabled
2021-10-21 14:59:52 +02:00
Markus Frosch
8237d84cdb Add feature to specify a custom endpoint name for a host
- Render Endpoint and Zone with a different name per host
- Add custom variable `_director_custom_endpoint_name` to a host with that name
- Update `command_endpoint` behavior in services to use custom var or hostname
- Includes a feature flag that needs to be enabled
2021-10-21 14:59:52 +02:00
Thomas Gelf
3d528dc3af ObjectsTableEndpoint: provide UUID 2021-10-18 17:32:58 +02:00
Thomas Gelf
30c6e50e33 BranchMerger: remove obsolete method call 2021-10-18 13:35:57 +02:00
Thomas Gelf
2d79281583 ApplyRulesTable: use UUIDs
refs #2411
2021-10-18 10:04:28 +02:00
Thomas Gelf
ce3ec67eb6 HostServiceBlacklist: fix exception in branches 2021-10-18 07:46:27 +02:00
Thomas Gelf
4916ce3529 SuggestController: apply HostGroup restrictions 2021-10-18 07:46:00 +02:00
Thomas Gelf
e29c025d64 Service/TemplateController: fix links, use uuids
fixes #2411
2021-10-18 07:27:28 +02:00
Thomas Gelf
cbc67439d8 ServiceController: remove debugging break 2021-10-12 13:42:33 +02:00
Thomas Gelf
7b4e9b4f91 IcingaObject: fix null check for ranges
fixes #2408
2021-10-11 17:45:55 +02:00
Thomas Gelf
75e414006d DbObject: UUID on insert is required
fixes #2407
2021-10-08 15:23:17 +02:00
Thomas Gelf
2906dc8acc Merge branch 'feature/branches-rewrite' 2021-10-06 09:41:58 +02:00
Thomas Gelf
95c8884ea6 IcingaAddServiceForm: use branches 2021-10-06 03:27:05 +02:00
Thomas Gelf
6201fb52e4 schema: add branches 2021-10-06 03:24:48 +02:00
Thomas Gelf
fc97d0d4e1 schema: add UUIDs for main Icinga objects 2021-10-06 02:01:58 +02:00
Thomas Gelf
20bb6dfc7f ServiceController: branch-related refactoring 2021-10-05 23:33:30 +02:00
Thomas Gelf
ab28a4b1db ServiceController: enforce optional monitoring...
...module permissions
2021-10-05 23:33:30 +02:00
Thomas Gelf
8ec56ff16e DbObject: allow to set loaded properties 2021-10-05 23:33:30 +02:00
Thomas Gelf
2994403aa8 DbObject: allow arrays in fromDbRow, handle errors 2021-10-05 23:33:30 +02:00
Thomas Gelf
6a68a2c3d8 ConfigController: no branch activity when...
...for id ranges
2021-10-05 23:33:30 +02:00
Thomas Gelf
f0d63ad23b DbObject: add UUID support 2021-10-05 23:33:30 +02:00
Thomas Gelf
fe97970dc3 IcingaCommandArgumentTable: branch-specific fixes 2021-10-05 23:33:30 +02:00
Thomas Gelf
83617b22e8 HostController: services on new branch host, hint 2021-10-05 23:33:30 +02:00
Thomas Gelf
97b2f6c946 CommandController: branch support, argument table 2021-10-05 23:33:30 +02:00
Thomas Gelf
2b62742362 UuidLookup: initial import 2021-10-05 23:33:30 +02:00
Thomas Gelf
78fd6afe94 ImportsourceController: add branch-related hint 2021-10-05 23:33:30 +02:00
Thomas Gelf
a00c91991d ObjectController: refactor Branch usage, give...
...more and better hints
2021-10-05 23:33:30 +02:00
Thomas Gelf
649a5dbe5e BranchedObject: initial import 2021-10-05 23:33:30 +02:00
Thomas Gelf
b59dab535e IcingaCommandArgumentForm: branch support 2021-10-05 23:33:30 +02:00
Thomas Gelf
09c9a9db72 DirectorObjectForm: use new DbObjectStore 2021-10-05 23:33:30 +02:00
Thomas Gelf
098f620802 JobController: not in Branches, formatting 2021-10-05 23:33:30 +02:00
Thomas Gelf
2dc83478ae IcingaHostServiceTable: support Branches 2021-10-05 23:33:30 +02:00
Thomas Gelf
c994610031 DirectorObjectForm: hidden id field, start...
...fading it out - don't want to see this here
2021-10-05 23:33:30 +02:00
Thomas Gelf
2e069ef127 TemplatechoiceController: not in branches 2021-10-05 23:33:30 +02:00
Thomas Gelf
8560abfaa7 DbObjectStore: refactor, drop load() for now 2021-10-05 23:33:30 +02:00
Thomas Gelf
8d3c901db7 IcingaCloneObjectForm: support Branches 2021-10-05 23:33:30 +02:00
Thomas Gelf
57c4dda117 Objects/*, CVs, others: unify setBeingLoadedFromDb 2021-10-05 23:33:30 +02:00
Thomas Gelf
835d01cdec IcingaObject: disabled = null is not a thing 2021-10-05 23:33:30 +02:00
Thomas Gelf
84c299a7db Table/Object*: use UUIDs 2021-10-05 23:33:30 +02:00
Thomas Gelf
13f6ff6131 KickstartController: not in branches 2021-10-05 23:33:30 +02:00
Thomas Gelf
30bbf0836d BranchController: refactored, use new classes 2021-10-05 23:33:30 +02:00
Thomas Gelf
ce13200832 DbObjectTypeRegistry: new helper methods 2021-10-05 23:33:30 +02:00
Thomas Gelf
1845b43314 ObjectsTable: we have UUIDs now, new column names 2021-10-05 23:33:30 +02:00
Thomas Gelf
73884536df ServiceActions: formatting 2021-10-05 23:33:30 +02:00
Thomas Gelf
8601f26f03 BranchSupportHook: drop linkToBranchedObject 2021-10-05 23:33:30 +02:00
Thomas Gelf
b12d50a16a HostgroupRestriction: do not fail on hosts w/o ID 2021-10-05 23:33:30 +02:00
Thomas Gelf
70c0b8f247 BranchActivityTable: new columns, better query 2021-10-05 23:33:30 +02:00
Thomas Gelf
98a8050718 BranchStore: new column names, delete methods 2021-10-05 23:33:30 +02:00
Thomas Gelf
e17535117e BranchModificationInspection: column names, uuid 2021-10-05 23:33:30 +02:00
Thomas Gelf
dc52a54888 BranchMerger: use Activity instances 2021-10-05 23:33:30 +02:00
Thomas Gelf
7ad9cf6c6c BranchActivity: formatting 2021-10-05 23:33:30 +02:00
Thomas Gelf
b22511e341 Branch: add assertBranch helper method 2021-10-05 23:33:30 +02:00
Thomas Gelf
59f6051623 Branch: use new ts_merge_request column 2021-10-05 23:33:30 +02:00
Thomas Gelf
f7d100ea24 Branch: remove outdated classes 2021-10-05 23:33:30 +02:00
Thomas Gelf
5483093959 MergeError: support BranchActivity 2021-10-05 23:33:30 +02:00
Thomas Gelf
2b24e9bcf8 BranchedObjectHint: move, support BranchedObject 2021-10-05 23:33:30 +02:00
Thomas Gelf
2f1a47c34a PlainObjectPropertyDiff: diff calculation 2021-10-05 23:33:30 +02:00
Thomas Gelf
654f845e4e Json: implement decodeOptional() for null support 2021-10-05 23:33:30 +02:00
Thomas Gelf
c2d7b235a5 IcingaConfigDiff: replace duplicate code 2021-10-05 23:33:30 +02:00
Thomas Gelf
5aba966a4b IcingaCommandArgument: use a combined key 2021-10-05 23:33:30 +02:00
Thomas Gelf
792ff03a6d Objects: add uuid column 2021-10-05 23:33:30 +02:00
Thomas Gelf
65bbaa9f98 IcingaObject: custom vars, also load them only...
...when we got an id
2021-10-05 23:33:30 +02:00
Thomas Gelf
182d1b519b IcingaObject: do not load groups when we have...
...no id. With branches this is now possible
2021-10-05 23:33:30 +02:00
Thomas Gelf
1a5df745e3 IcingaObject: add some type-hints 2021-10-05 23:33:30 +02:00
Thomas Gelf
a29efe478c IcingaArguments: remove Argument set to null 2021-10-05 23:33:30 +02:00
Thomas Gelf
5494ab29bd BranchActivity: dedicated class 2021-10-05 23:33:30 +02:00
Thomas Gelf
2c27446c9f NotInBranchHint: dedicated class, used in our...
...BranchHelper
2021-10-05 23:33:30 +02:00
Thomas Gelf
a1fb42878c BranchSettings: some generic settings and helpers 2021-10-05 23:33:30 +02:00
Ravi Kumar Kempapura Srinivasa
90b5f6fdac Convert $imports keys to string explicitly
The keys of $imports in IcingaObjectImports must be converted to string explicitly or else it establishes incorrect parent-child relation
in icinga_host_inheritance table in case the key is integer value and there is an host object with id = key(integer) icinga_host table.
This results in undefined offset while triggering sync rule.
2021-10-01 10:47:54 +02:00
Ravi Kumar Kempapura Srinivasa
6289bf065f Pass $resolved as False for arguments to toPlainObject()
IcingaArguments passes the $resolved through to the individual argument in the toPlainObject. There lies the error,
simply pass false - because the argument itself cannot have any parents and therefore cannot be resolved
2021-10-01 10:47:12 +02:00
Thomas Gelf
378ef5d686 ObjectsTable, Infra: fix method signature
fixes #2395
2021-09-23 07:32:35 +02:00
Thomas Gelf
83c12fefcf SingleServiceInfo: fix URL for single services
This affected clicking "modify" in the monitoring module
2021-09-09 16:25:28 +02:00
Thomas Gelf
de4378cfd3 DbObjectTypeRegistry: support 'serviceset' 2021-09-09 16:17:42 +02:00
Johannes Meyer
82ae0dc52e Host|ServiceActions: Don't check object access if monitoring isn't active 2021-09-01 10:35:32 +02:00
Thomas Gelf
435b1f9b1d BranchModificationStore: centralize encoding rules 2021-08-26 10:18:06 +02:00
Thomas Gelf
6cc902f238 BranchesDashboard: do not fail with no dashlet 2021-08-25 16:24:54 +02:00
Thomas Gelf
b898041caa DirectorObjectForm: use Branch, not UUID 2021-08-25 13:00:56 +02:00
Thomas Gelf
8a280619ad DbObjectStore: load by ID for int keys 2021-08-25 12:14:22 +02:00
Thomas Gelf
430f54837b DeployedConfigInfoHeader: do not re-deploy...
...when being in a branchDeployedConfigInfoHeader: do not re-deploy...

...when being in a branchDeployedConfigInfoHeader: do not re-deploy...

...when being in a branchDeployedConfigInfoHeader: do not re-deploy...

...when being in a branchDeployedConfigInfoHeader: do not re-deploy...

...when being in a branchDeployedConfigInfoHeader: do not re-deploy...

...when being in a branchDeployedConfigInfoHeader: do not re-deploy...

...when being in a branchDeployedConfigInfoHeader: do not re-deploy...

...when being in a branchDeployedConfigInfoHeader: do not re-deploy...

...when being in a branch
2021-08-25 11:38:29 +02:00
Thomas Gelf
a851f58e42 ConfigController: no rendering, no deployment...
...for branches
2021-08-25 11:33:23 +02:00
Thomas Gelf
bdd9e2b1e5 IcingaCloneObjectForm: do not clone templates...
...in branches. Reason: fields
2021-08-25 11:28:51 +02:00
Thomas Gelf
dfdec95358 IcingaObjectModification: allow to pass db
fixes an issue with related objects on create
2021-08-25 00:54:30 +02:00
Thomas Gelf
44b749f2bf BranchModificationStore: cast eventual objects 2021-08-24 18:47:13 +02:00
Thomas Gelf
23f1fae784 BranchModificationStore: fix serialization 2021-08-24 18:46:55 +02:00
Thomas Gelf
607f53fecc BranchesDashboard: prominent hint -> active branch 2021-08-24 16:33:16 +02:00
Thomas Gelf
b321327634 Dashboard: provide space for Branch Hook dashlets 2021-08-24 16:13:22 +02:00
Thomas Gelf
31d6cfe4cd css: color for branch activity 2021-08-23 09:01:34 +02:00
Thomas Gelf
15adce142f ObjectModificationBranchHint: variants, details 2021-08-23 09:01:03 +02:00
Thomas Gelf
290e34a8ca ObjectsTable: add branchUuid, fail-safe 2021-08-23 09:00:26 +02:00
Thomas Gelf
6ff5b0c8d7 ConfigHealthItemRenderer: ask branch for count 2021-08-23 08:58:02 +02:00
Thomas Gelf
085cec0eb7 BranchedObjectsHint: new hints for lists 2021-08-23 08:56:16 +02:00
Thomas Gelf
48ac87cff5 ObjectController: hook has been updated 2021-08-23 08:55:30 +02:00
Thomas Gelf
d83a0aaba5 BranchHelper: use BranchStore 2021-08-23 08:54:34 +02:00
Thomas Gelf
04f3c6363e BranchSupportHook: smaller changes 2021-08-23 08:53:40 +02:00
Thomas Gelf
5002f7a6bf IcingaObjectModification: loop with an array 2021-08-23 08:53:22 +02:00
Thomas Gelf
2897415a1f BranchStore: centralized repository 2021-08-23 08:52:12 +02:00
Thomas Gelf
c79045e9e2 Branch: add a bunch of properties and getters 2021-08-23 08:50:44 +02:00
Thomas Gelf
53b2167925 ConfigController: some hints for branch activity 2021-08-23 08:49:39 +02:00
Thomas Gelf
1470a134f4 Branch support: initial import 2021-08-16 11:43:09 +02:00
Thomas Gelf
38d17af92e DirectorObjectForm: remove unused property 2021-08-16 11:22:50 +02:00
Thomas Gelf
44a90afea2 DbSelectParenthesis: allow to defer Db Expr...
...stringification when required to apply parenthesis (-> union)
2021-08-16 10:51:57 +02:00
Thomas Gelf
7c553257a6 ObjectController: fail when loading twice 2021-08-16 07:12:06 +02:00
Thomas Gelf
f0deb11e7f IcingaObject: no empty vars for unmodified plain 2021-08-16 06:33:34 +02:00
Thomas Gelf
1d5b00a675 IcingaObject: unify DB boolean value converter
Hint: fixes booleans for "plain unmodified" objects
2021-08-16 06:33:23 +02:00
Thomas Gelf
77fca39ff3 IcingaObject: getAppliedGroups with id=null 2021-08-16 06:21:50 +02:00
Thomas Gelf
21dcadd143 Db: remove unused properties 2021-08-16 06:17:46 +02:00
Thomas Gelf
5de3a6a497 Db: clean up methods related to binary PG data 2021-08-16 06:14:34 +02:00
Thomas Gelf
62a31c7858 DbObject: some cleanup 2021-08-16 06:02:36 +02:00
Thomas Gelf
a0253250c1 DbObject: allow to setBeingLoadedFromDb 2021-08-16 06:02:15 +02:00
Thomas Gelf
40c2aaeb22 ObjectsTableService: fix typo
fixes #2357
2021-08-16 05:43:41 +02:00
Thomas Gelf
c822f3b981 DatafieldCategoryTable: fix SQL error on search
fixes #2367
2021-08-16 05:40:23 +02:00
Thomas Gelf
093abfd733 DatafieldTable: fix grouping error on PostgreSQL
fixes #2310
2021-08-16 05:36:10 +02:00
Thomas Gelf
f87eff8a21 PropetyModifierToInt: fail for non-strings
fixes #2372
2021-08-12 11:52:31 +02:00
Thomas Gelf
909fac0419 PropertyModifier: preserve null values
fixes #2371
2021-08-12 11:45:40 +02:00
Thomas Gelf
6678a9a8f9 HostGroupMembershipResolverTest: replace new dummy 2021-08-04 15:06:34 +02:00
Thomas Gelf
66de47b10b DbObjectTypeRegistry: move logic from IcingaObject 2021-08-04 13:18:30 +02:00
Thomas Gelf
be9fcfc3c2 DataArrayHelper: readability 2021-08-04 08:21:58 +02:00
Thomas Gelf
348c2d9de4 DataArrayHelper: new helper class 2021-08-03 15:33:09 +02:00
Thomas Gelf
6152b5d1de SerializableValue: new helper class 2021-08-03 11:45:13 +02:00
Thomas Gelf
f7e9c145eb Data\Json: "reproducible" JSON 2021-08-03 11:30:48 +02:00
Eric Lippmann
159b1825dd ipl and reactbundle are only required for Icinga Web < 2.9.0 2021-07-16 13:00:24 +02:00
Thomas Gelf
7f16d648cc IcingaUser: add basket support
fixes #2328
2021-07-15 19:11:20 +02:00
Thomas Gelf
e72da4cac4 phpunit: remove obsolete (and removed) parameter 2021-07-13 11:05:25 +02:00
Thomas Gelf
5cd01294cf doc: v1.8.1 has been released 2021-07-13 10:27:26 +02:00
Thomas Gelf
6badc53d61 DependencyChecker: new implemenation
This is now also able to give help for web 2.9.x

fixes #2354
fixes #2350
2021-07-13 09:50:17 +02:00
Thomas Gelf
44ca8890f2 ActionController: check view->compact
fixes #2141
2021-07-13 01:01:49 +02:00
schurzi
cc8cbf66f7 fix typo in resolved parameter 2021-07-13 00:54:29 +02:00
Thomas Gelf
025b02bd12 doc/changelog: cherry-pick more issues for 1.8.1 2021-07-13 00:52:15 +02:00
Thomas Gelf
dffbf82821 doc/changelog: picked #2303 into v1.8.1
refs #2303
2021-07-13 00:17:37 +02:00
Eric Lippmann
1a61cfc5c7 Use Icinga 2's generate-ticket API 2021-07-12 23:54:47 +02:00
Thomas Gelf
eee4f7cf55 IcingaConfig: store config file relations in a...
...transaction: all or nothing

fixes #2351
2021-07-12 23:43:04 +02:00
Sebastian Gumprich
fed74eb33d IcingaObject: alias scheduled_downtime
Fixes an error when trying to create scheduled_downtime via api

fixes #1879
2021-07-12 23:25:42 +02:00
Thomas Gelf
f27390d503 ImportRunBasedPurgeStrategy: fixed combined keys
fixes #2339
2021-07-12 23:11:40 +02:00
Thomas Gelf
bf32380d32 IcingaServiceSetServiceTable: show "deactivated"
...in RO users overview table

fixes #2344
2021-06-23 18:29:56 +02:00
Thomas Gelf
2538feaf42 ServiceSetServiceInfo: respect deactivation
fixes #2323
2021-06-23 18:25:14 +02:00
Thomas Gelf
c058359ae3 configuration: type-hint 2021-06-01 21:34:45 +02:00
Thomas Gelf
234bb89454 QuickForm: typo 2021-06-01 21:29:21 +02:00
Thomas Gelf
ac652f5966 Basket: allow Notification Apply Rules export
fixes #2335
2021-05-28 15:24:18 +02:00
Thomas Gelf
40544ac935 ObjectPreview: fix inline Service Template links...
...for Service Sets

fixes #2334
2021-05-28 10:48:29 +02:00
Thomas Gelf
ec87cd0ec2 OverriddenVarsResolver: deal with root templates
fixes #2333
2021-05-28 10:39:29 +02:00
Thomas Gelf
2cff396fe4 DbDataFormatter: new helper class
Trying to reduce logic in IcingaObject
2021-05-20 16:21:46 +02:00
Thomas Gelf
2c950e05ea IcingaConfigHelper: re-order reserved words 2021-05-20 15:20:21 +02:00
Thomas Gelf
7de5b03877 IcingaObject: readability, style 2021-05-20 15:11:12 +02:00
Thomas Gelf
80965053cf IcingaDependency: isApplyForArrayClone(), cleanup 2021-05-20 11:48:17 +02:00
Thomas Gelf
10ada10527 IcingaConfigHelper: improve readability 2021-05-20 10:28:07 +02:00
Thomas Gelf
da1363d236 IcingaService: public hasBeenAssignedToHostTemplate 2021-05-20 10:24:27 +02:00
Thomas Gelf
bd44999e52 doc: configure the daemon with main setup
fixes #2320
2021-05-03 15:25:52 +02:00
Thomas Gelf
e5595431df PropertyModifierSimpleGroupBy: new modifier
fixes #2317
2021-04-23 17:38:52 +02:00
Thomas Gelf
c5e25cdcc7 ScheduledDowntime: introduce a new permission...
...and a related name-based restriction

fixes #2086
2021-04-23 12:33:42 +02:00
Thomas Gelf
ebe1af13ea IcingaAddServiceForm: import -> autocomplete
fixes #1974
2021-04-23 11:42:46 +02:00
Mattia Codato
9387ede99a Add hook deployment onCollect 2021-04-20 16:13:48 +02:00
Gianluca Piccolo
04ba8d12cf Add --wait opt to cli deploy 2021-04-20 14:26:54 +02:00
Thomas Gelf
d86ef63c42 travis-prepare.sh: do not let former failed...
...tests influence the current one: delete the test db in case it exists
2021-04-15 10:23:15 +02:00
Thomas Gelf
a2016e99c0 IcingaObject: do not load resolved memberships...
...for unstored objects
2021-04-15 10:22:45 +02:00
Johannes Meyer
694cacb464 HostController: Fix indentation 2021-04-15 08:53:27 +02:00
Thomas Gelf
7a9e7d163d ObjectPurgeHelper: remove comments 2021-04-15 08:44:18 +02:00
Thomas Gelf
93222099ad BacketCommand: allow to purge objects on restore
fixes #2201
2021-04-15 08:30:32 +02:00
Thomas Gelf
c709c00fbd ObjectApplyMatches: fetch allied host groups
fixes #2313
2021-04-14 09:03:35 +02:00
Thomas Gelf
b6375b477d CoreApiFieldsTable: show "deprecated" flag
fixes #2312
2021-04-13 17:02:28 +02:00
Thomas Gelf
d03751f614 ImportsourceHookTable: just a comment 2021-04-13 16:34:13 +02:00
Thomas Gelf
302c9b645d DirectorDatafield: fix changed method name
fixes #2278
2021-03-19 13:24:58 +01:00
Thomas Gelf
c27d9c7387 Monitoring, various: use monitoring permissions
fixes #2304
2021-03-18 07:01:42 +01:00
Thomas Gelf
29097463be IcingaServiceForm: show Override button also in...
...case all fields belong to categories

fixes #2303
2021-03-18 06:57:05 +01:00
Thomas Gelf
0664da8f12 schema: allow NULL for purge_action 2021-03-12 16:52:44 +01:00
Thomas Gelf
4c4f9541e5 DirectorObjectForm: show inherited non-scalars...
...in select boxes. This should make it more obvious that invalid data has been
inherited.

refs #2288
2021-03-12 00:07:50 +01:00
Thomas Gelf
09a0323ad6 DirectorObjectForm: render inherited scalars only
fixes #2288
2021-03-11 23:47:56 +01:00
Thomas Gelf
bb6530e9f9 KickstartForm: catch DB connection issues early
fixes #2300
2021-03-11 23:12:05 +01:00
Thomas Gelf
5a0c0481b4 doc/changelog: add next version 2021-03-11 23:09:59 +01:00
Thomas Gelf
a8d25b70ee Sync: introduce a 'disable' purge action
fixes #2285
2021-03-11 23:00:52 +01:00
Thomas Gelf
41f428e86b DashboardController: useless use of use 2021-03-10 21:46:09 +01:00
Thomas Gelf
cd55a65a9c DatafieldTable: modernize formatting 2021-03-01 17:16:07 +01:00
Thomas Gelf
f12dac159d DatafieldTable: show category 2021-03-01 17:12:57 +01:00
Thomas Gelf
bc7ab2e6be ImportsourceCommand: show eventual JSON errors 2021-03-01 15:30:33 +01:00
Thomas Gelf
e2a8886148 DirectorObjectForm: deal with "no template"...
...when fetching Choices

fixes #2268
2021-01-21 11:25:23 +01:00
Thomas Gelf
21a284abbc OverriddenVarsResolver: refine api 2021-01-19 01:47:31 +01:00
Thomas Gelf
9889fa9342 DeploymentStatus: do not miss exceptions when...
...talking to Icinga
2021-01-18 17:54:16 +01:00
Thomas Gelf
234e68db31 Lookup: explain various kinds of Services 2021-01-18 17:52:01 +01:00
Thomas Gelf
3325512824 ServiceFinder: new static find() method 2021-01-18 16:03:24 +01:00
Thomas Gelf
6960407825 ServiceInfo: provide requiresOverrides() 2021-01-18 16:03:04 +01:00
Thomas Gelf
e4e96206b4 ServiceFinder: replace HostServiceRedirector 2021-01-16 15:04:29 +01:00
Thomas Gelf
958b19758c DataController: allow for IcingaHost in dictionary 2021-01-15 12:26:10 +01:00
Thomas Gelf
c4261cb241 Merge branch 'feature/datatype-dictionary-337' 2021-01-15 11:51:52 +01:00
Thomas Gelf
fb2872ac7b Merge branch 'feature/choice-with-required-import-1178' 2021-01-15 11:51:45 +01:00
Thomas Gelf
40e1b5a798 DataTypeDictionary: new data type
fixes #337
2021-01-15 11:45:35 +01:00
Thomas Gelf
121dd774c4 IcingaTemplateChoiceForm: allow to require...
...a specific template/import

fixes #1178
2021-01-15 11:20:33 +01:00
Thomas Gelf
6687524d2f IcingaObject/Imports: better error message wording
fixes #2224
2021-01-11 17:32:59 +01:00
Thomas Gelf
0544b57db4 IcingaHostForm: strike only HTML elements
fixes #2253
2020-12-16 05:59:48 +01:00
Thomas Gelf
c5472e8ad1 module.info: master 2020-12-16 05:59:48 +01:00
Thomas Gelf
90cebbab65 doc/changelog: mention Icinga for Windows 2020-12-16 05:59:48 +01:00
522 changed files with 24328 additions and 8485 deletions

7
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

View File

@ -12,7 +12,7 @@ jobs:
steps:
- name: Repository dispatch
uses: peter-evans/repository-dispatch@v1
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ secrets.ICINGABOT_TOKEN }}
repository: Icinga/L10n

174
.github/workflows/php.yml vendored Normal file
View File

@ -0,0 +1,174 @@
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 Normal file
View File

@ -0,0 +1,16 @@
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"
}

View File

@ -1,42 +0,0 @@
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'

View File

@ -42,9 +42,6 @@ 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: [![Build Status](https://travis-ci.org/Icinga/icingaweb2-module-director.svg?branch=master)](https://travis-ci.org/Icinga/icingaweb2-module-director)
Addons
------

View File

@ -4,8 +4,10 @@ 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
@ -79,14 +81,43 @@ 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()

View File

@ -5,6 +5,8 @@ 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;
@ -86,12 +88,23 @@ class ConfigCommand extends Command
/**
* Deploy the current configuration
*
* Does nothing if config didn't change unless you provide
* the --force parameter
* 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
*/
public function deployAction()
{
$api = $this->api();
$db = $this->db();
$checksum = $this->params->get('checksum');
@ -102,24 +115,31 @@ class ConfigCommand extends Command
$checksum = $config->getHexChecksum();
}
$api->wipeInactiveStages($db);
$current = $api->getActiveChecksum($db);
if ($current === $checksum) {
$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));
if ($this->params->get('force')) {
echo "Config matches active stage, deploying anyway\n";
} else {
echo "Config matches active stage, nothing to do\n";
return;
fwrite(STDERR, "WARNING: force overrides Grace period\n");
}
}
$deployer->refresh();
if ($api->dumpConfig($config, $db)) {
if ($deployment = $deployer->deploy($config)) {
if ($deployer->hasBeenForced()) {
echo $deployer->getNoDeploymentReason() . ", deploying anyway\n";
}
printf("Config '%s' has been deployed\n", $checksum);
} else {
$this->fail(
sprintf("Failed to deploy config '%s'\n", $checksum)
);
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);
}
}
}
@ -142,4 +162,17 @@ 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;
}
}

View File

@ -4,6 +4,7 @@ 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;
@ -90,7 +91,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);
}
/**

View File

@ -29,8 +29,9 @@ class KickstartCommand extends Command
* require => Exec['Icinga Director DB migration'],
* }
*
* Exit code 0 means that a kickstart run is required, code 2 that it is
* not.
* Exit code 0: A kickstart run is required.
* Exit code 1: Kickstart is configured but a run is not required.
* Exit code 2: A kickstart run is not required.
*/
public function requiredAction()
{

View File

@ -2,8 +2,12 @@
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
@ -13,6 +17,53 @@ use Icinga\Module\Director\Objects\IcingaHost;
*/
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)
{

View File

@ -3,6 +3,7 @@
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;
@ -98,9 +99,9 @@ class SyncruleCommand extends Command
}
return (object) [
'create' => $create,
'modify' => $modify,
'delete' => $delete,
DirectorActivityLog::ACTION_CREATE => $create,
DirectorActivityLog::ACTION_MODIFY => $modify,
DirectorActivityLog::ACTION_DELETE => $delete,
];
}
@ -166,7 +167,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'));
}

View File

@ -9,12 +9,10 @@ use gipfl\IcingaWeb2\Link;
use gipfl\Web\Table\NameValueTable;
use gipfl\Web\Widget\Hint;
use Icinga\Date\DateFormatter;
use Icinga\Module\Director\Core\Json;
use Icinga\Module\Director\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;
@ -23,6 +21,7 @@ use Icinga\Module\Director\Forms\RestoreBasketForm;
use Icinga\Module\Director\Web\Controller\ActionController;
use ipl\Html\Html;
use Icinga\Module\Director\Web\Table\BasketSnapshotTable;
use Ramsey\Uuid\Uuid;
class BasketController extends ActionController
{
@ -126,6 +125,26 @@ class BasketController extends ActionController
$this->content()->add($form);
}
public function uploadSnapshotAction()
{
$basket = Basket::load($this->params->get('name'), $this->db());
$this->actions()->add(
Link::create(
$this->translate('back'),
'director/basket/snapshots',
['name' => $basket->get('basket_name')],
['class' => 'icon-left-big']
)
);
$this->basketTabs()->activate('snapshots');
$this->addTitle($this->translate('Upload a Configuration Basket Snapshot'));
$form = (new BasketUploadForm())
->setObject($basket)
->setDb($this->db())
->handleRequest();
$this->content()->add($form);
}
/**
* @throws \Icinga\Exception\NotFoundError
*/
@ -146,6 +165,12 @@ class BasketController extends ActionController
$basket->get('basket_name')
));
$this->basketTabs()->activate('snapshots');
$this->actions()->add(Link::create(
$this->translate('Upload'),
'director/basket/upload-snapshot',
['name' => $basket->get('basket_name')],
['class' => 'icon-upload']
));
}
if ($basket !== null) {
$this->content()->add(
@ -244,11 +269,9 @@ class BasketController extends ActionController
$connection = $this->db();
}
$json = $snapshot->getJsonDump();
$this->addSingleTab($this->translate('Snapshot'));
$all = Json::decode($json);
$fieldResolver = new BasketSnapshotFieldResolver($all, $connection);
foreach ($all as $type => $objects) {
$diff = new BasketDiff($snapshot, $connection);
foreach ($diff->getBasketObjects() as $type => $objects) {
if ($type === 'Datafield') {
// TODO: we should now be able to show all fields and link
// to a "diff" for the ones that should be created
@ -272,39 +295,33 @@ class BasketController extends ActionController
$linkParams['target_db'] = $targetDbName;
}
try {
$current = BasketSnapshot::instanceByIdentifier($type, $key, $connection);
if ($current === null) {
$table->addNameValueRow(
$key,
Link::create(
Html::tag('strong', ['style' => 'color: green'], $this->translate('new')),
if ($uuid = $object->uuid ?? null) {
$uuid = Uuid::fromString($uuid);
}
if ($diff->hasCurrentInstance($type, $key, $uuid)) {
if ($diff->hasChangedFor($type, $key, $uuid)) {
$link = Link::create(
$this->translate('modified'),
'director/basket/snapshotobject',
$linkParams
)
);
continue;
}
$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')),
$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
)
: Html::tag('span', ['style' => 'color: green'], $this->translate('unchanged'))
);
$linkParams,
['class' => 'basket-new']
);
}
$table->addNameValueRow($key, $link);
} catch (Exception $e) {
$table->addNameValueRow(
$key,
@ -320,7 +337,6 @@ class BasketController extends ActionController
$this->content()->add(Html::tag('h2', $type));
$this->content()->add($table);
}
$this->content()->add(Html::tag('div', ['style' => 'height: 5em']));
}
/**
@ -367,38 +383,27 @@ 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);
}
$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);
$diff = new BasketDiff($snapshot, $connection);
$object = $diff->getBasketObject($type, $key);
if ($uuid = $object->uuid ?? null) {
$uuid = Uuid::fromString($uuid);
}
if ($current === $objectFromBasket) {
$basketJson = $diff->getBasketString($type, $key);
$currentJson = $diff->getCurrentString($type, $key, $uuid);
if ($currentJson === $basketJson) {
$this->content()->add([
Hint::ok('Basket equals current object'),
Html::tag('pre', $current)
Html::tag('pre', $currentJson)
]);
} else {
$this->content()->add(new InlineDiff(new PhpDiff($current, $objectFromBasket)));
$this->content()->add(new InlineDiff(new PhpDiff($currentJson, $basketJson)));
}
}

View File

@ -0,0 +1,138 @@
<?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());
}
}

View File

@ -3,6 +3,8 @@
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;
@ -22,9 +24,14 @@ 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' => ['name' => $o->getObjectName()],
'urlParams' => $urlParams,
'label' => 'Arguments'
]);
}
@ -83,16 +90,33 @@ class CommandController extends ObjectController
$o = $this->object;
$this->tabs()->activate('arguments');
$this->addTitle($this->translate('Command arguments: %s'), $o->getObjectName());
$form = IcingaCommandArgumentForm::load()->setCommandObject($o);
if ($id = $p->shift('argument_id')) {
$form = (new IcingaCommandArgumentForm())
->setBranch($this->getBranch())
->setCommandObject($o);
if ($argument = $p->shift('argument')) {
$this->addBackLink('director/command/arguments', [
'name' => $p->get('name')
]);
$form->loadObject($id);
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->handleRequest();
$this->content()->add([$form]);
IcingaCommandArgumentTable::create($o)->renderTo($this);
if ($this->branch->isBranch()) {
(new BranchedIcingaCommandArgumentTable($o, $this->getBranch()))->renderTo($this);
} else {
(new IcingaCommandArgumentTable($o, $this->getBranch()))->renderTo($this);
}
}
protected function hasBasketSupport()

View File

@ -8,13 +8,17 @@ 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;
@ -34,6 +38,8 @@ use gipfl\IcingaWeb2\Url;
class ConfigController extends ActionController
{
use BranchHelper;
protected $isApified = true;
protected function checkDirectorPermissions()
@ -61,13 +67,15 @@ class ConfigController extends ActionController
// No problem, Icinga might be reloading
}
// TODO: a form!
$this->actions()->add(Link::create(
$this->translate('Render config'),
'director/config/store',
null,
['class' => 'icon-wrench']
));
if (! $this->getBranch()->isBranch()) {
// 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());
@ -147,7 +155,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'));
@ -179,7 +187,7 @@ class ConfigController extends ActionController
['class' => 'icon-user', 'data-base-target' => '_self']
));
}
if ($this->hasPermission('director/deploy')) {
if ($this->hasPermission(Permission::DEPLOY) && ! $this->getBranch()->isBranch()) {
if ($this->db()->hasDeploymentEndpoint()) {
$this->actions()->add(DeployConfigForm::load()
->setDb($this->db())
@ -276,6 +284,7 @@ class ConfigController extends ActionController
$config,
$this->db(),
$this->api(),
$this->getBranch(),
$deploymentId
));
@ -361,33 +370,35 @@ class ConfigController extends ActionController
$configs = $db->enumDeployedConfigs();
foreach (array($leftSum, $rightSum) as $sum) {
if (! array_key_exists($sum, $configs)) {
if ($sum && ! array_key_exists($sum, $configs)) {
$configs[$sum] = substr($sum, 0, 7);
}
}
$baseUrl = $this->url()->without(['left', 'right']);
$this->content()->add(Html::tag('form', ['action' => (string) $baseUrl, 'method' => 'GET'], [
new HtmlString($this->view->formSelect(
'left',
$leftSum,
['class' => 'autosubmit', 'style' => 'width: 37%'],
[null => $this->translate('- please choose -')] + $configs
)),
Link::create(
Icon::create('flapping'),
$baseUrl,
['left' => $rightSum, 'right' => $leftSum]
),
new HtmlString($this->view->formSelect(
'right',
$rightSum,
['class' => 'autosubmit', 'style' => 'width: 37%'],
[null => $this->translate('- please choose -')] + $configs
)),
]));
$this->content()->add(
Html::tag('form', ['action' => (string) $baseUrl, 'method' => 'GET', 'class' => 'director-form'], [
new HtmlString($this->view->formSelect(
'left',
$leftSum,
['class' => ['autosubmit', 'config-diff']],
[null => $this->translate('- please choose -')] + $configs
)),
Link::create(
Icon::create('flapping'),
$baseUrl,
['left' => $rightSum, 'right' => $leftSum]
),
new HtmlString($this->view->formSelect(
'right',
$rightSum,
['class' => ['autosubmit', 'config-diff']],
[null => $this->translate('- please choose -')] + $configs
)),
])
);
if (! strlen($rightSum) || ! strlen($leftSum)) {
if ($rightSum === null || $leftSum === null || ! strlen($rightSum) || ! strlen($leftSum)) {
return;
}
ConfigFileDiffTable::load($leftSum, $rightSum, $this->db())->renderTo($this);
@ -422,6 +433,32 @@ 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
*/
@ -445,7 +482,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);
@ -466,7 +503,8 @@ class ConfigController extends ActionController
{
$tabs = $this->tabs();
if ($this->hasPermission('director/deploy')
if (
$this->hasPermission(Permission::DEPLOY)
&& $deploymentId = $this->params->get('deployment_id')
) {
$tabs->add('deployment', [
@ -476,7 +514,7 @@ class ConfigController extends ActionController
]);
}
if ($this->hasPermission('director/showconfig')) {
if ($this->hasPermission(Permission::SHOW_CONFIG)) {
$tabs->add('config', [
'label' => $this->translate('Config'),
'url' => 'director/config/files',

View File

@ -3,9 +3,7 @@
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;
@ -38,6 +36,7 @@ class DashboardController extends ActionController
$mainDashboards = [
'Objects',
'Alerts',
'Branches',
'Automation',
'Deployment',
'Director',

View File

@ -2,10 +2,18 @@
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;
@ -13,6 +21,9 @@ 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
{
@ -140,6 +151,218 @@ 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(

View File

@ -19,17 +19,11 @@ class DatafieldController extends ActionController
public function indexAction()
{
$edit = false;
if ($id = $this->params->get('id')) {
$edit = true;
}
$form = DirectorDatafieldForm::load()
->setDb($this->db());
if ($edit) {
$form->loadObject($id);
if ($id = $this->params->get('id')) {
$form->loadObject((int) $id);
$this->addTitle(
$this->translate('Modify %s'),
$form->getObject()->varname

View File

@ -3,6 +3,10 @@
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;
@ -10,6 +14,7 @@ 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;
@ -22,23 +27,52 @@ 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()
{
if (in_array($this->getRequest()->getActionName(), [
$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(), [
'servicesro',
'findservice',
'invalidservice'
])) {
$this->assertPermission('director/monitoring/services-ro');
} else {
$this->assertPermission('director/hosts');
}
'invalidservice',
]);
}
protected function isServiceAction()
{
return in_array($this->getRequest()->getActionName(), [
'servicesro',
'findservice',
'invalidservice',
'servicesetservice',
'appliedservice',
'inheritedservice',
]);
}
/**
@ -62,6 +96,7 @@ 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()
@ -73,8 +108,10 @@ 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()
@ -100,16 +137,38 @@ class HostController extends ObjectController
));
}
/**
* @throws \Icinga\Exception\NotFoundError
*/
public function findserviceAction()
{
$auth = $this->Auth();
$host = $this->getHostObject();
$redirector = new HostServiceRedirector($host, $this->getAuth());
$this->redirectNow(
$redirector->getRedirectionUrl($this->params->get('service'))
);
$hostName = $host->getObjectName();
$serviceName = $this->params->get('service');
$info = ServiceFinder::find($host, $serviceName);
$backend = $this->backend();
if ($info && $auth->hasPermission(Permission::HOSTS)) {
$redirectUrl = $info->getUrl();
} elseif (
$info
&& (($backend instanceof Monitoring && $auth->hasPermission(Permission::MONITORING_HOSTS))
|| ($backend instanceof IcingadbBackend && $auth->hasPermission(Permission::ICINGADB_HOSTS))
)
&& $backend->canModifyService($hostName, $serviceName)
) {
$redirectUrl = $info->getUrl();
} elseif ($auth->hasPermission($this->getServicesReadOnlyPermission())) {
$redirectUrl = Url::fromPath('director/host/servicesro', [
'name' => $hostName,
'service' => $serviceName
]);
} else {
$redirectUrl = Url::fromPath('director/host/invalidservice', [
'name' => $hostName,
'service' => $serviceName,
]);
}
$this->redirectNow($redirectUrl);
}
/**
@ -157,12 +216,16 @@ 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 = IcingaHostServiceTable::load($host)
->setTitle($this->translate('Individual Service objects'));
$table = (new ObjectsTableService($this->db(), $this->Auth()))
->setHost($host)
->setBranch($branch)
->setTitle($this->translate('Individual Service objects'))
->removeQueryLimit();
if (count($table)) {
$content->add($table);
@ -172,18 +235,25 @@ class HostController extends ObjectController
$parents = IcingaTemplateRepository::instanceByObject($this->object)
->getTemplatesFor($this->object, true);
foreach ($parents as $parent) {
$table = IcingaHostServiceTable::load($parent)->setInheritedBy($host);
$table = (new ObjectsTableService($this->db(), $this->Auth()))
->setBranch($branch)
->setHost($parent)
->setInheritedBy($host)
->removeQueryLimit();
if (count($table)) {
$content->add(
$table->setTitle(sprintf(
'Inherited from %s',
$this->translate('Inherited from %s'),
$parent->getObjectName()
))
);
}
}
$this->addHostServiceSetTables($host);
if (! $hostHasBeenCreatedInBranch) {
$this->addHostServiceSetTables($host);
}
foreach ($parents as $parent) {
$this->addHostServiceSetTables($parent, $host);
}
@ -195,8 +265,10 @@ class HostController extends ObjectController
$content->add(
IcingaServiceSetServiceTable::load($set)
// ->setHost($host)
->setBranch($branch)
->setAffectedHost($host)
->setTitle($title)
->removeQueryLimit()
);
}
@ -219,15 +291,19 @@ class HostController extends ObjectController
*/
public function servicesroAction()
{
$this->assertPermission('director/monitoring/services-ro');
$this->assertPermission($this->getServicesReadOnlyPermission());
$host = $this->getHostObject();
$service = $this->params->getRequired('service');
$db = $this->db();
$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 = IcingaHostServiceTable::load($host)
$table = (new ObjectsTableService($db, $this->Auth()))
->setHost($host)
->setBranch($branch)
->setReadonly()
->highlightService($service)
->setTitle($this->translate('Individual Service objects'));
@ -240,8 +316,10 @@ class HostController extends ObjectController
$parents = IcingaTemplateRepository::instanceByObject($this->object)
->getTemplatesFor($this->object, true);
foreach ($parents as $parent) {
$table = IcingaHostServiceTable::load($parent)
$table = (new ObjectsTableService($db, $this->Auth()))
->setReadonly()
->setBranch($branch)
->setHost($parent)
->highlightService($service)
->setInheritedBy($host);
if (count($table)) {
@ -266,6 +344,7 @@ class HostController extends ObjectController
$content->add(
IcingaServiceSetServiceTable::load($set)
// ->setHost($host)
->setBranch($branch)
->setAffectedHost($host)
->setReadonly()
->highlightService($service)
@ -293,6 +372,9 @@ class HostController extends ObjectController
if ($affectedHost === null) {
$affectedHost = $host;
}
if ($host->get('id') === null) {
return;
}
$query = $db->getDbAdapter()->select()
->from(
@ -314,7 +396,9 @@ 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);
@ -350,6 +434,7 @@ class HostController extends ObjectController
$this->content()->add(
IcingaServiceForm::load()
->setDb($db)
->setBranch($this->getBranch())
->setHost($host)
->setApplyGenerated($parent)
->setObject($service)
@ -390,6 +475,7 @@ class HostController extends ObjectController
$form = IcingaServiceForm::load()
->setDb($db)
->setBranch($this->getBranch())
->setHost($host)
->setInheritedFrom($from->getObjectName())
->setObject($service)
@ -467,6 +553,7 @@ class HostController extends ObjectController
$form = IcingaServiceForm::load()
->setDb($db)
->setBranch($this->getBranch())
->setHost($host)
->setServiceSet($set)
->setObject($service)
@ -507,20 +594,20 @@ class HostController extends ObjectController
{
$host = $this->object;
try {
$mon = $this->monitoring();
if ($host->isObject()
&& $mon->isAvailable()
&& $mon->hasHost($host->getObjectName())
$backend = $this->backend();
if (
$host instanceof IcingaHost
&& $host->isObject()
&& $backend->hasHost($host->getObjectName())
) {
$this->actions()->add(Link::create(
$this->translate('Show'),
'monitoring/host/show',
['host' => $host->getObjectName()],
[
'class' => 'icon-globe critical',
'data-base-target' => '_next'
]
));
$this->actions()->add(
Link::create(
$this->translate('Show'),
$backend->getHostUrl($host->getObjectName()),
null,
['class' => 'icon-globe critical', 'data-base-target' => '_next']
)
);
// Intentionally placed here, show it only for deployed Hosts
$this->addOptionalInspectLink();
@ -532,7 +619,7 @@ class HostController extends ObjectController
protected function addOptionalInspectLink()
{
if (! $this->hasPermission('director/inspect')) {
if (! $this->hasPermission(Permission::INSPECT)) {
return;
}
@ -552,11 +639,25 @@ class HostController extends ObjectController
}
/**
* @return IcingaHost
* @return ?IcingaHost
*/
protected function getHostObject()
{
/** @var IcingaHost $this->object */
if ($this->object !== null) {
assert($this->object instanceof IcingaHost);
}
return $this->object;
}
/**
* Get readOnly permission of the service for the current backend
*
* @return string permission
*/
protected function getServicesReadOnlyPermission(): string
{
return $this->backend() instanceof IcingadbBackend
? Permission::ICINGADB_SERVICES_RO
: Permission::MONITORING_SERVICES_RO;
}
}

View File

@ -3,12 +3,16 @@
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;
@ -18,9 +22,12 @@ 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;
@ -78,24 +85,36 @@ class ImportsourceController extends ActionController
$this->addMainActions();
$source = $this->getImportSource();
if ($this->params->get('format') === 'json') {
$this->sendJson($this->getResponse(), $source->export());
$this->sendJson($this->getResponse(), (new Exporter($this->db()))->export($source));
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'))
->content()->add(
ImportSourceForm::load()->setDb($this->db())
->setSuccessUrl('director/importsources')
->handleRequest()
);
$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()
);
}
/**
@ -105,6 +124,9 @@ 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')
@ -124,6 +146,9 @@ 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);
@ -155,9 +180,7 @@ class ImportsourceController extends ActionController
'target' => '_blank',
'class' => 'icon-download',
]
))->add(Link::create('[..]', '#', null, [
'onclick' => 'javascript:$("table.raw-data-table").toggleClass("collapsed");'
]));
));
try {
(new ImportsourceHookTable())->setImportSource($source)->renderTo($this);
} catch (Exception $e) {
@ -206,9 +229,13 @@ class ImportsourceController extends ActionController
protected function requireImportSourceAndAddModifierTable()
{
$source = $this->getImportSource();
PropertymodifierTable::load($source, $this->url())
->handleSortPriorityActions($this->getRequest(), $this->getResponse())
->renderTo($this);
$table = PropertymodifierTable::load($source, $this->url());
if ($this->getBranch()->isBranch()) {
$table->setReadOnly();
} else {
$table->handleSortPriorityActions($this->getRequest(), $this->getResponse());
}
$table->renderTo($this);
return $source;
}
@ -253,6 +280,10 @@ 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)
@ -279,12 +310,15 @@ 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($this->params->getRequired('id'))
->loadObject((int) $this->params->getRequired('id'))
->setListUrl($listUrl)
->setSource($source)
->handleRequest()

View File

@ -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'

View File

@ -6,10 +6,13 @@ 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
@ -29,13 +32,17 @@ class JobController extends ActionController
{
$this
->addSingleTab($this->translate('New Job'))
->addTitle($this->translate('Add a new Job'))
->content()->add(
DirectorJobForm::load()
->setSuccessUrl('director/job')
->setDb($this->db())
->handleRequest()
);
->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()
);
}
/**
@ -45,16 +52,19 @@ 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
->addJobTabs($job, 'edit')
->addTitle($this->translate('Job: %s'), $job->get('job_name'))
->addToBasketLink()
->content()->add($form);
$this->content()->add($form);
}
/**

View File

@ -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');

View File

@ -4,13 +4,19 @@ 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());

View File

@ -2,6 +2,7 @@
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;
@ -52,6 +53,11 @@ class NotificationController extends ObjectController
}
}
protected function hasBasketSupport()
{
return $this->object->isTemplate() || $this->object->isApplyRule();
}
protected function loadObject()
{
if ($this->object === null) {
@ -75,6 +81,10 @@ class NotificationController extends ObjectController
}
}
if (! $this->allowsObject($this->object)) {
throw new NotFoundError('No such object available');
}
return $this->object;
}
}

View File

@ -3,7 +3,8 @@
namespace Icinga\Module\Director\Controllers;
use Icinga\Application\Icinga;
use Icinga\Application\Modules\Manager;
use Icinga\Module\Director\Application\DependencyChecker;
use Icinga\Module\Director\Web\Table\Dependency\DependencyInfoTable;
use Icinga\Web\Controller;
class PhperrorController extends Controller
@ -24,39 +25,19 @@ class PhperrorController extends Controller
public function dependenciesAction()
{
$dependencies = $this->view->dependencies = $this->Module()->getDependencies();
$modules = $this->view->modules = Icinga::app()->getModuleManager();
// Hint: we're duplicating some code here
$satisfied = true;
foreach ($dependencies as $module => $required) {
/** @var Manager $this ->modules */
if ($modules->hasEnabled($module)) {
$installed = $modules->getModule($module, false)->getVersion();
$installed = \ltrim($installed, 'v'); // v0.6.0 VS 0.6.0
if (\preg_match('/^([<>=]+)\s*v?(\d+\.\d+\.\d+)$/', $required, $match)) {
$operator = $match[1];
$vRequired = $match[2];
if (\version_compare($installed, $vRequired, $operator)) {
continue;
}
}
}
$satisfied = false;
}
if ($satisfied) {
$checker = new DependencyChecker(Icinga::app());
if ($checker->satisfiesDependencies($this->Module())) {
$this->redirectNow('director');
}
$this->setAutorefreshInterval(15);
$this->getTabs()->add('error', array(
$this->getTabs()->add('error', [
'label' => $this->translate('Error'),
'url' => $this->getRequest()->getUrl()
))->activate('error');
$msg = $this->translate(
])->activate('error');
$this->view->title = $this->translate('Unsatisfied dependencies');
$this->view->table = (new DependencyInfoTable($checker, $this->Module()))->render();
$this->view->message = $this->translate(
"Icinga Director depends on the following modules, please install/upgrade as required"
);
$this->view->title = $this->translate('Unsatisfied dependencies');
$this->view->message = sprintf($msg, PHP_VERSION);
}
}

View File

@ -11,6 +11,11 @@ class ScheduledDowntimeController extends ObjectController
{
protected $objectBaseUrl = 'director/scheduled-downtime';
protected function checkDirectorPermissions()
{
$this->assertPermission('director/scheduled-downtimes');
}
public function rangesAction()
{
/** @var IcingaScheduledDowntime $object */

View File

@ -34,4 +34,14 @@ class ScheduledDowntimesController extends ObjectsController
{
return 'scheduled-downtime';
}
protected function assertApplyRulePermission()
{
return $this->assertPermission('director/scheduled-downtimes');
}
protected function checkDirectorPermissions()
{
$this->assertPermission('director/scheduled-downtimes');
}
}

View File

@ -62,7 +62,7 @@ class SchemaController extends ActionController
return file_get_contents(
sprintf(
'%s/schema/%s.sql',
$this->Module()->getBasedir(),
$this->Module()->getBaseDir(),
$type
)
);

View File

@ -136,12 +136,7 @@ class SelfServiceController extends ActionController
throw new NotFoundError('The host "%s" is not an agent', $name);
}
$this->sendPowerShellResponse(
Util::getIcingaTicket(
$name,
$this->api()->getTicketSalt()
)
);
$this->sendPowerShellResponse($this->api()->getTicket($name));
} catch (Exception $e) {
if ($e instanceof NotFoundError) {
$this->sendPowerShellError($e->getMessage(), 404);
@ -199,7 +194,7 @@ class SelfServiceController extends ActionController
} else {
throw new ProgrammingError(
'Expected boolean value, got %s',
var_export($value, 1)
var_export($value, true)
);
}
}
@ -280,7 +275,7 @@ class SelfServiceController extends ActionController
// PluginsUrl => framework_plugins_url
];
$username = $settings->get('self-service/icinga_service_user');
if (strlen($username)) {
if ($username) {
$params['icinga_service_user'] = $username;
}
@ -402,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 (strlen($value)) {
if ($value) {
$params[$key] = $value;
}
}

View File

@ -3,9 +3,13 @@
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;
@ -25,64 +29,79 @@ class ServiceController extends ObjectController
protected function checkDirectorPermissions()
{
$this->assertPermission('director/hosts');
if (
$this->host
&& $this->object
&& $this->backend()->canModifyService($this->host->getObjectName(), $this->object->getObjectName())
) {
return;
}
$this->assertPermission(Permission::HOSTS);
}
public function init()
{
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()
);
}
// 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');
parent::init();
$this->addOptionalHostTabs();
$this->addOptionalSetTabs();
}
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);
protected function getOptionalRelatedObjectFromParams($type, $parameter)
{
if ($id = $this->params->get("{$parameter}_id")) {
$key = (int) $id;
} else {
$key = $this->params->get($parameter);
}
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->set && $this->object->get('service_set_id')) {
$this->set = $this->object->getRelated('service_set');
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) {
$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);
if ($key === null) {
return null;
}
$table = DbObjectTypeRegistry::tableNameByType($relation);
$uuid = UuidLookup::findUuidForKey($key, $table, $this->db(), $this->getBranch());
return $this->loadSpecificObject($table, $uuid);
}
protected function addParamToTabs($name, $value)
@ -99,6 +118,7 @@ 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(
@ -131,18 +151,23 @@ 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',
['name' => $this->host->getObjectName()],
['uuid' => $this->host->getUniqueId()->toString()],
['class' => 'icon-left-big']
));
$form->setHost($this->host);
}
$form = IcingaServiceForm::load()->setDb($this->db());
if ($this->set) {
$form->setServiceSet($this->set);
}
@ -172,7 +197,8 @@ class ServiceController extends ObjectController
}
try {
if ($object->isTemplate()
if (
$object->isTemplate()
&& $object->getResolvedProperty('check_command_id')
) {
$this->view->actionLinks .= ' ' . $this->view->qlink(
@ -213,33 +239,81 @@ class ServiceController extends ObjectController
$this->content()->add($table);
}
protected function loadObject()
protected function getLegacyKey()
{
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();
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();
}
if ($key = $this->params->get('id')) {
$key = (int) $key;
} else {
$key = $this->params->get('name');
}
return $this->object;
if ($key === null) {
throw new \InvalidArgumentException('uuid, name or id required');
}
return $key;
}
protected function loadObject()
{
if ($this->params->has('uuid')) {
parent::loadObject();
return;
}
$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');
}
} 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);
}
}

View File

@ -3,6 +3,7 @@
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;
@ -71,7 +72,9 @@ class ServicesetController extends ObjectController
['class' => 'icon-plus']
));
IcingaServiceSetServiceTable::load($set)->renderTo($this);
IcingaServiceSetServiceTable::load($set)
->setBranch($this->getBranch())
->renderTo($this);
}
public function hostsAction()
@ -89,7 +92,7 @@ class ServicesetController extends ObjectController
$table->renderTo($this);
}
$filter = $set->get('assign_filter');
if (\strlen($filter) > 0) {
if ($filter !== null && \strlen($filter) > 0) {
$this->content()->add(
IcingaHostsMatchingFilterTable::load(Filter::fromQueryString($filter), $this->db())
);
@ -98,15 +101,19 @@ 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' => ['name' => $name],
'urlParams' => ['uuid' => $hexUuid],
'label' => 'Services'
])->add('hosts', [
]);
if ($this->branch->isBranch()) {
return $this;
}
$tabs->add('hosts', [
'url' => 'director/serviceset/hosts',
'urlParams' => ['name' => $name],
'urlParams' => ['uuid' => $hexUuid],
'label' => 'Hosts'
]);
@ -130,6 +137,10 @@ class ServicesetController extends ObjectController
}
}
if (! $this->allowsObject($this->object)) {
throw new NotFoundError('No such object available');
}
return $this->object;
}
}

View File

@ -2,6 +2,7 @@
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;
@ -108,6 +109,8 @@ 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);
}
@ -119,7 +122,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');
@ -149,7 +152,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;
}
}
}
@ -288,7 +291,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\'',
@ -366,7 +369,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);
}

View File

@ -2,10 +2,18 @@
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;
@ -27,25 +35,38 @@ 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();
$runForm = SyncRunForm::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());
if ($lastRunId = $rule->getLastSyncRunId()) {
$run = SyncRun::load($lastRunId, $this->db());
@ -73,7 +94,7 @@ class SyncruleController extends ActionController
break;
case 'in-sync':
$c->add(Html::tag('p', null, sprintf(
$this->translate('This Sync Rule was last found to by in Sync at %s.'),
$this->translate('This Sync Rule was last found to be in Sync at %s.'),
$rule->get('last_attempt')
)));
/*
@ -100,6 +121,15 @@ 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) {
@ -144,31 +174,97 @@ class SyncruleController extends ActionController
public function previewAction()
{
$rule = $this->requireSyncRule();
// $rule->set('update_policy', 'replace');
$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;
}
$this->tabs(new SyncRuleTabs($rule))->activate('preview');
$this->addTitle('Sync Preview');
$sync = new Sync($rule);
try {
$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) {
$modifications = $sync->getExpectedModifications();
} 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'
)));
if ($tmpBranch) {
try {
if (!$keepBranchPreview) {
$sync->apply();
}
} catch (\Exception $e) {
$this->content()->add(Hint::error($e->getMessage()));
return;
}
return;
$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);
}
}
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()) {
@ -284,10 +380,7 @@ class SyncruleController extends ActionController
protected function firstNames($objects, $max = 50)
{
$names = [];
$list = new UnorderedList();
$list->addAttributes([
'style' => 'list-style-type: none; marign: 0; padding: 0',
]);
$list = new UnorderedList([], ['class' => 'unordred-list']);
$total = count($objects);
$i = 0;
PrefetchCache::forget();
@ -309,7 +402,7 @@ class SyncruleController extends ActionController
$cfgOld = new IcingaConfig($this->db());
$oldObject->renderToConfig($cfgOld);
$object->renderToConfig($cfgNew);
foreach ($this->getConfigDiffs($cfgOld, $cfgNew) as $file => $diff) {
foreach (IcingaConfigDiff::getDiffs($cfgOld, $cfgNew) as $file => $diff) {
$names[$name . '___PRETITLE___' . $file] = Html::tag('h3', $file);
$names[$name . '___PREVIEW___' . $file] = $diff;
}
@ -334,7 +427,7 @@ class SyncruleController extends ActionController
$cfgOld = new IcingaConfig($this->db());
$oldObject->renderToConfig($cfgOld);
$object->renderToConfig($cfgNew);
foreach ($this->getConfigDiffs($cfgOld, $cfgNew) as $file => $diff) {
foreach (IcingaConfigDiff::getDiffs($cfgOld, $cfgNew) as $file => $diff) {
$names[$name . '___PRETITLE___' . $file] = Html::tag('h3', $file);
$names[$name . '___PREVIEW___' . $file] = $diff;
}
@ -364,48 +457,11 @@ 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;
@ -455,9 +511,15 @@ 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();
@ -490,6 +552,9 @@ class SyncruleController extends ActionController
['class' => 'icon-paste']
)
);
if ($this->showNotInBranch($this->translate('Cloning Sync Rules'))) {
return;
}
$form = new CloneSyncRuleForm($rule);
$this->content()->add($form);
@ -538,6 +603,13 @@ 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(
@ -545,24 +617,21 @@ 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);
@ -573,7 +642,7 @@ class SyncruleController extends ActionController
*/
public function historyAction()
{
$this->setAutoRefreshInterval(30);
$this->setAutorefreshInterval(30);
$rule = $this->requireSyncRule();
$this->tabs(new SyncRuleTabs($rule))->activate('history');
$this->addTitle($this->translate('Sync history') . ': ' . $rule->get('rule_name'));
@ -582,7 +651,7 @@ class SyncruleController extends ActionController
$run = SyncRun::load($runId, $this->db());
$this->content()->add(new SyncRunDetails($run));
}
SyncRunTable::create($rule)->renderTo($this);
(new SyncRunTable($rule))->renderTo($this);
}
/**

View File

@ -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'

View File

@ -4,9 +4,12 @@ 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');
@ -24,12 +27,15 @@ 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();
$this->addSingleTab('Choice')
->addTitle($title)
->content()->add($form);
if ($this->showNotInBranch($this->translate('Modifying Template Choices'))) {
return;
}
$this->content()->add($form);
}
}

View File

@ -30,4 +30,9 @@ class TimeperiodController extends ObjectController
$this->content()->add($form->handleRequest());
IcingaTimePeriodRangeTable::load($object)->renderTo($this);
}
protected function hasBasketSupport()
{
return true;
}
}

View File

@ -10,4 +10,9 @@ class UserController extends ObjectController
{
$this->assertPermission('director/users');
}
protected function hasBasketSupport()
{
return true;
}
}

View File

@ -11,9 +11,6 @@ use Icinga\Module\Director\Web\Form\DirectorForm;
class AddToBasketForm extends DirectorForm
{
/** @var Basket */
private $basket;
private $type = '(has not been set)';
private $names = [];
@ -30,7 +27,6 @@ class AddToBasketForm extends DirectorForm
'b' => 'basket_name',
])->order('basket_name'));
$names = [];
$basket = null;
if ($this->hasBeenSent()) {
$basketName = $this->getSentValue('basket');
@ -38,25 +34,17 @@ class AddToBasketForm extends DirectorForm
$basket = Basket::load($basketName, $this->getDb());
}
}
$count = 0;
$type = $this->type;
$names = [];
foreach ($this->names as $name) {
if (! empty($names)) {
$names[] = ', ';
}
if ($basket && $basket->hasObject($type, $name)) {
$names[] = Html::tag('span', [
'style' => 'text-decoration: line-through'
], $name);
} else {
$count++;
if (! $basket || ! $basket->hasObject($this->type, $name)) {
$names[] = $name;
}
}
$this->addHtmlHint((new HtmlDocument())->add([
'The following objects will be added: ',
$names
]));
$this->addHtmlHint(
(new HtmlDocument())
->add(sprintf('The following objects will be added: %s', implode(", ", $names)))
);
$this->addElement('select', 'basket', [
'label' => $this->translate('Basket'),
'multiOptions' => $this->optionalEnum($enum),
@ -64,10 +52,10 @@ class AddToBasketForm extends DirectorForm
'class' => 'autosubmit',
]);
if ($count > 0) {
if (! empty($names)) {
$this->setSubmitLabel(sprintf(
$this->translate('Add %s objects'),
$count
count($names)
));
} else {
$this->setSubmitLabel($this->translate('Add'));
@ -112,18 +100,18 @@ class AddToBasketForm extends DirectorForm
'Configuration objects have been added to the chosen basket "%s"'
), $basketName));
return parent::onSuccess();
} else {
$this->addHtmlHint(Hint::error(Html::sprintf($this->translate(
'Please check your Basket configuration, %s does not support'
. ' single "%s" configuration objects'
), Link::create(
$basketName,
'director/basket',
['name' => $basketName],
['data-base-target' => '_next']
), $type)));
return false;
}
$this->addHtmlHint(Hint::error(Html::sprintf($this->translate(
'Please check your Basket configuration, %s does not support'
. ' single "%s" configuration objects'
), Link::create(
$basketName,
'director/basket',
['name' => $basketName],
['data-base-target' => '_next']
), $type)));
return false;
}
}

View File

@ -24,6 +24,9 @@ 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'),
@ -49,9 +52,9 @@ class BasketForm extends DirectorObjectForm
$types = $this->getAvailableTypes();
$options = [
'IGNORE' => $this->translate('Ignore'),
'ALL' => $this->translate('All of them'),
'[]' => $this->translate('Custom Selection'),
Basket::SELECTION_NONE => $this->translate('Ignore'),
Basket::SELECTION_ALL => $this->translate('All of them'),
Basket::SELECTION_CUSTOM => $this->translate('Custom Selection'),
];
$this->addHtmlHint($this->translate(
@ -89,13 +92,13 @@ class BasketForm extends DirectorObjectForm
/** @var Basket $object */
$values = [];
foreach ($this->getAvailableTypes() as $type => $label) {
$values[$type] = 'IGNORE';
$values[$type] = Basket::SELECTION_NONE;
}
foreach ($object->getChosenObjects() as $type => $selection) {
if ($selection === true) {
$values[$type] = 'ALL';
$values[$type] = Basket::SELECTION_ALL;
} elseif (is_array($selection)) {
$values[$type] = '[]';
$values[$type] = Basket::SELECTION_CUSTOM;
}
}

View File

@ -25,10 +25,12 @@ class BasketUploadForm extends DirectorObjectForm
*/
public function setup()
{
$this->addElement('text', 'basket_name', [
'label' => $this->translate('Basket Name'),
'required' => true,
]);
if ($this->object === null) {
$this->addElement('text', 'basket_name', [
'label' => $this->translate('Basket Name'),
'required' => true,
]);
}
$this->setAttrib('enctype', 'multipart/form-data');
$this->addElement('file', 'uploaded_file', [
@ -53,16 +55,6 @@ class BasketUploadForm extends DirectorObjectForm
return '\\Icinga\\Module\\Director\\DirectorObject\\Automation\\Basket';
}
protected function setObjectSuccessUrl()
{
/** @var Basket $basket */
$basket = $this->object();
$this->setSuccessUrl(
'director/basket',
['name' => $basket->get('basket_name')]
);
}
/**
* @return bool
* @throws IcingaException
@ -73,7 +65,8 @@ 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');
@ -134,13 +127,17 @@ class BasketUploadForm extends DirectorObjectForm
$basket->set('owner_type', 'user');
$basket->set('owner_value', $this->getAuth()->getUser()->getUsername());
$basket->store($this->db);
if ($basket->hasBeenLoadedFromDb()) {
$this->setSuccessUrl('director/basket/snapshots', ['name' => $basket->get('basket_name')]);
} else {
$this->setSuccessUrl('director/basket', ['name' => $basket->get('basket_name')]);
$basket->store($this->db);
}
BasketSnapshot::forBasketFromJson(
$basket,
$this->rawUpload
)->store($this->db);
$this->setObjectSuccessUrl();
$this->beforeSuccessfulRedirect();
$this->redirectOnSuccess($this->translate('Basket has been uploaded'));
}

View File

@ -51,11 +51,13 @@ 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;
}
}
@ -70,7 +72,8 @@ 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;

View File

@ -4,6 +4,7 @@ namespace Icinga\Module\Director\Forms;
use Icinga\Authentication\Auth;
use Icinga\Exception\IcingaException;
use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Core\DeploymentApiInterface;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Deployment\DeploymentInfo;
@ -82,7 +83,7 @@ class DeploymentLinkForm extends DirectorForm
);
}
$this->setAttrib('class', 'inline');
$this->setAttrib('class', 'gipfl-inline-form');
$this->addHtml(Icon::create('wrench'));
try {
// As this is shown for single objects, ignore errors caused by an
@ -100,7 +101,7 @@ class DeploymentLinkForm extends DirectorForm
protected function canDeploy()
{
return $this->auth->hasPermission('director/deploy');
return $this->auth->hasPermission(Permission::DEPLOY);
}
public function render(Zend_View_Interface $view = null)
@ -156,7 +157,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');

View File

@ -140,8 +140,7 @@ class DirectorDatafieldForm extends DirectorObjectForm
$this->addElement('text', 'varname', array(
'label' => $this->translate('Field name'),
'description' => $this->translate(
'The unique name of the field. This will be the name of the custom'
. ' variable in the rendered Icinga configuration.'
'This will be the name of the custom variable in the rendered Icinga configuration.'
),
'required' => true,
));
@ -166,7 +165,7 @@ class DirectorDatafieldForm extends DirectorObjectForm
$this->addElement('select', 'category_id', [
'label' => $this->translate('Data Field Category'),
'multiOptions' => $this->optionalEnum($this->enumCategpories()),
'multiOptions' => $this->optionalEnum($this->enumCategories()),
]);
$error = false;
@ -176,7 +175,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'),
@ -282,7 +281,7 @@ class DirectorDatafieldForm extends DirectorObjectForm
protected function enumDataTypes()
{
$hooks = Hook::all('Director\\DataType');
$enum = array(null => '- please choose -');
$enum = [null => $this->translate('- please choose -')];
/** @var DataTypeHook $hook */
foreach ($hooks as $hook) {
$enum[get_class($hook)] = $hook->getName();
@ -291,7 +290,7 @@ class DirectorDatafieldForm extends DirectorObjectForm
return $enum;
}
protected function enumCategpories()
protected function enumCategories()
{
$db = $this->getDb()->getDbAdapter();
return $db->fetchPairs(

View File

@ -3,6 +3,7 @@
namespace Icinga\Module\Director\Forms;
use gipfl\IcingaWeb2\Link;
use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaService;
@ -29,7 +30,13 @@ class IcingaAddServiceForm extends DirectorObjectForm
);
}
$this->addSingleImportElement();
$this->addSingleImportElement(true);
if (empty($this->enumServiceTemplates())) {
$this->setSubmitLabel(false);
return;
}
if (! ($imports = $this->getSentOrObjectValue('imports'))) {
$this->setSubmitLabel($this->translate('Next'));
@ -82,7 +89,7 @@ class IcingaAddServiceForm extends DirectorObjectForm
if ($this->hasBeenSent()) {
$this->addError($this->translate('No service has been chosen'));
} else {
if ($this->hasPermission('director/admin')) {
if ($this->hasPermission(Permission::ADMIN)) {
$html = sprintf(
$this->translate('Please define a %s first'),
Link::create(
@ -100,15 +107,12 @@ class IcingaAddServiceForm extends DirectorObjectForm
return $this;
}
$this->addElement('select', 'imports', [
$this->addElement('text', 'imports', [
'label' => $this->translate('Service'),
'description' => $this->translate(
'Choose a service template'
),
'description' => $this->translate('Choose a service template'),
'required' => true,
'multiOptions' => $this->optionalEnum($enum),
'class' => 'autosubmit'
'data-suggestion-context' => 'servicetemplates',
'class' => 'autosubmit director-suggest'
]);
return $this;
@ -156,7 +160,11 @@ class IcingaAddServiceForm extends DirectorObjectForm
public function onSuccess()
{
if ($this->host !== null) {
$this->object->set('host_id', $this->host->get('id'));
if ($id = $this->host->get('id')) {
$this->object->set('host_id', $id);
} else {
$this->object->set('host', $this->host->getObjectName());
}
parent::onSuccess();
return;
}
@ -164,10 +172,11 @@ class IcingaAddServiceForm extends DirectorObjectForm
$plain = $this->object->toPlainObject();
$db = $this->object->getConnection();
// TODO: Test this:
foreach ($this->hosts as $host) {
IcingaService::fromPlainObject($plain, $db)
->set('host_id', $host->get('id'))
->store();
$service = IcingaService::fromPlainObject($plain, $db)
->set('host_id', $host->get('id'));
$this->getDbObjectStore()->store($service);
}
$msg = sprintf(

View File

@ -2,8 +2,13 @@
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;
@ -17,8 +22,25 @@ 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'),
@ -26,7 +48,7 @@ class IcingaCloneObjectForm extends DirectorForm
'value' => $name,
));
if (Acl::instance()->hasPermission('director/admin')) {
if (!$branchOnly && Acl::instance()->hasPermission(Permission::ADMIN)) {
$this->addElement('select', 'clone_type', array(
'label' => 'Clone type',
'required' => true,
@ -37,8 +59,9 @@ class IcingaCloneObjectForm extends DirectorForm
));
}
if ($this->object instanceof IcingaHost
|| $this->object instanceof IcingaServiceSet
if (
!$branchOnly && ($this->object instanceof IcingaHost
|| $this->object instanceof IcingaServiceSet)
) {
$this->addBoolean('clone_services', [
'label' => $this->translate('Clone Services'),
@ -48,7 +71,7 @@ class IcingaCloneObjectForm extends DirectorForm
], 'y');
}
if ($this->object instanceof IcingaHost) {
if (!$branchOnly && $this->object instanceof IcingaHost) {
$this->addBoolean('clone_service_sets', [
'label' => $this->translate('Clone Service Sets'),
'description' => $this->translate(
@ -80,7 +103,10 @@ class IcingaCloneObjectForm extends DirectorForm
}
}
if ($this->object->isTemplate() && $this->object->supportsFields()) {
if (
($this->object->isTemplate() || $this->object instanceof IcingaCommand)
&& $this->object->supportsFields()
) {
$this->addBoolean('clone_fields', [
'label' => $this->translate('Clone Template Fields'),
'description' => $this->translate(
@ -95,6 +121,13 @@ class IcingaCloneObjectForm extends DirectorForm
);
}
public function setBranch(Branch $branch)
{
$this->branch = $branch;
return $this;
}
public function setObjectBaseUrl($url)
{
$this->baseObjectUrl = $url;
@ -110,7 +143,7 @@ class IcingaCloneObjectForm extends DirectorForm
$connection = $object->getConnection();
$db = $connection->getDbAdapter();
$newName = $this->getValue('new_object_name');
$resolve = Acl::instance()->hasPermission('director/admin')
$resolve = Acl::instance()->hasPermission(Permission::ADMIN)
&& $this->getValue('clone_type') === 'flat';
$msg = sprintf(
@ -120,6 +153,16 @@ 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')
@ -163,13 +206,14 @@ 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 = [];
}
if ($new->store()) {
$store = new DbObjectStore($connection, $this->branch);
if ($store->store($new)) {
$newId = $new->get('id');
foreach ($services as $service) {
$clone = IcingaService::fromPlainObject(
@ -178,22 +222,39 @@ class IcingaCloneObjectForm extends DirectorForm
);
if ($new instanceof IcingaHost) {
$clone->set('host_id', $newId);
if ($isBranch) {
$clone->set('host', $newName);
} else {
$clone->set('host_id', $newId);
}
} elseif ($new instanceof IcingaServiceSet) {
$clone->set('service_set_id', $newId);
if ($isBranch) {
$clone->set('service_set', $newName);
} else {
$clone->set('service_set_id', $newId);
}
}
$clone->store();
$store->store($clone);
}
foreach ($sets as $set) {
IcingaServiceSet::fromPlainObject(
$newSet = IcingaServiceSet::fromPlainObject(
$set->toPlainObject(),
$connection
)->set('host_id', $newId)->store();
);
if ($isBranch) {
$newSet->set('host', $newName);
} else {
$newSet->set('host_id', $newId);
}
$store->store($newSet);
}
foreach ($fields as $row) {
$row->{"${type}_id"} = $newId;
$row->{"{$type}_id"} = $newId;
$db->insert($table . '_field', (array) $row);
}
@ -219,6 +280,7 @@ class IcingaCloneObjectForm extends DirectorForm
return $db->fetchPairs(
$db->select()
->from('icinga_service_set', ['id', 'object_name'])
->where('object_type = ?', 'template')
->order('object_name')
);
}

View File

@ -134,16 +134,22 @@ class IcingaCommandArgumentForm extends DirectorObjectForm
$cmd = $this->commandObject;
$msg = sprintf(
'%s argument "%s" has been removed',
$this->translate('%s argument "%s" has been removed'),
$this->translate($this->getObjectShortClassName()),
$object->argument_name
);
$url = $this->getSuccessUrl()->without('argument_id');
// TODO: remove argument_id, once verified that it is no longer in use
$url = $this->getSuccessUrl()->without('argument_id')->without('argument');
$cmd->arguments()->remove($object->argument_name);
if ($cmd->store()) {
if ($this->branch->isBranch()) {
$this->getDbObjectStore()->store($cmd);
$this->setSuccessUrl($url);
} else {
if ($cmd->store()) {
$this->setSuccessUrl($url);
}
}
$this->redirectOnSuccess($msg);
@ -167,20 +173,17 @@ class IcingaCommandArgumentForm extends DirectorObjectForm
$this->translate('The argument %s has successfully been stored'),
$object->get('argument_name')
);
$cmd->store($this->db);
$this->getDbObjectStore()->store($cmd);
} else {
if ($this->isApiRequest()) {
$this->setHttpResponseCode(304);
}
$msg = $this->translate('No action taken, object has not been modified');
}
$this->setSuccessUrl(
'director/command/arguments',
[
'argument_id' => $object->get('id'),
'name' => $cmd->getObjectName()
]
);
$this->setSuccessUrl('director/command/arguments', [
'argument' => $object->get('argument_name'),
'name' => $cmd->getObjectName()
]);
$this->redirectOnSuccess($msg);
}

View File

@ -28,7 +28,6 @@ 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(),

View File

@ -5,6 +5,7 @@ namespace Icinga\Module\Director\Forms;
use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
use Icinga\Module\Director\Objects\IcingaDependency;
use Zend_Validate_Callback;
class IcingaDependencyForm extends DirectorObjectForm
{
@ -164,7 +165,7 @@ class IcingaDependencyForm extends DirectorObjectForm
], null);
$this->addBoolean('disable_notifications', [
'label' => $this->translate('Disable Notificiations'),
'label' => $this->translate('Disable Notifications'),
'description' => $this->translate(
'Whether to disable notifications when this dependency fails.'
. ' Defaults to true.'
@ -192,38 +193,83 @@ class IcingaDependencyForm extends DirectorObjectForm
$parentHost = $dependency->get('parent_host');
if ($parentHost === null) {
$parentHostVar = $dependency->get('parent_host_var');
if (\strlen($parentHostVar) > 0) {
if ($parentHostVar !== null && \strlen($parentHostVar) > 0) {
$parentHost = '$' . $dependency->get('parent_host_var') . '$';
}
}
$parentHostDescription = $this->translate('Optional. The parent host.');
$applyTo = $this->getSentOrObjectValue('apply_to');
$parentHostValidator = new Zend_Validate_Callback(function ($value) use ($applyTo) {
if ($applyTo === 'host' && $this->isCustomVar($value)) {
return explode('.', trim($value, '$'))[0] === 'host';
}
return true;
});
$parentHostValidator->setMessage(
$this->translate('The parent host cannot be a service custom variable for a host dependency'),
Zend_Validate_Callback::INVALID_VALUE
);
if ($applyTo === 'service') {
$additionalDescription = $this->translate(
'You might want to refer to Host or Service Custom Variables via $host|service.vars.varname$'
);
} else {
$additionalDescription = $this->translate(
'You might want to refer to Host Custom Variables via $host.vars.varname$'
);
}
$parentHostDescription .= ' ' . $additionalDescription;
$this->addElement('text', 'parent_host', [
'label' => $this->translate('Parent Host'),
'description' => $this->translate(
'The parent host. You might want to refer Host Custom Variables'
. ' via $host.vars.varname$'
),
'class' => "autosubmit director-suggest",
'label' => $this->translate('Parent Host'),
'description' => $parentHostDescription,
'class' => "autosubmit director-suggest",
'data-suggestion-context' => 'hostnames',
'order' => 10,
'required' => $this->isObject(),
'value' => $parentHost
'order' => 10,
'required' => $this->isObject(),
'value' => $parentHost,
'validators' => [$parentHostValidator]
]);
$sentParent = $this->getSentOrObjectValue('parent_host');
if (!empty($sentParent) || $dependency->isApplyRule()) {
$parentService = $dependency->get('parent_service');
if ($parentService === null) {
$parentServiceVar = $dependency->get('parent_service_by_name');
if ($parentServiceVar) {
$parentService = '$' . $parentServiceVar . '$';
}
}
$parentServiceDescription = $this->translate(
'Optional. The parent service. If omitted this dependency'
. ' object is treated as host dependency.'
);
$parentServiceDescription .= ' ' . $additionalDescription;
$parentServiceValidator = clone $parentHostValidator;
$parentServiceValidator->setMessage(
$this->translate('The parent service cannot be a service custom variable for a host dependency'),
Zend_Validate_Callback::INVALID_VALUE
);
$this->addElement('text', 'parent_service', [
'label' => $this->translate('Parent Service'),
'description' => $this->translate(
'Optional. The parent service. If omitted this dependency'
. ' object is treated as host dependency.'
),
'class' => "autosubmit director-suggest",
'data-suggestion-context' => 'servicenames',
'data-suggestion-for-host' => $sentParent,
'order' => 20,
'value' => $parentService
]);
'label' => $this->translate('Parent Service'),
'description' => $parentServiceDescription,
'class' => "autosubmit director-suggest",
'data-suggestion-context' => 'servicenames',
'data-suggestion-for-host' => $sentParent,
'order' => 20,
'value' => $parentService,
'validators' => [$parentServiceValidator]
]);
}
// If configuring Object, allow selection of child host and/or service,
@ -290,11 +336,22 @@ class IcingaDependencyForm extends DirectorObjectForm
protected function handleProperties(DbObject $object, &$values)
{
if ($this->hasBeenSent()) {
if (isset($values['parent_host'])
&& $this->isCustomVar($values['parent_host'])
) {
$values['parent_host_var'] = \trim($values['parent_host'], '$');
$values['parent_host'] = '';
if (isset($values['parent_host'])) {
if ($this->isCustomVar($values['parent_host'])) {
$values['parent_host_var'] = \trim($values['parent_host'], '$');
$values['parent_host'] = '';
} else {
$values['parent_host_var'] = '';
}
}
if (isset($values['parent_service'])) {
if ($this->isCustomVar($values['parent_service'])) {
$values['parent_service_by_name'] = trim($values['parent_service'], '$');
$values['parent_service'] = '';
} else {
$values['parent_service_by_name'] = '';
}
}
}
@ -303,7 +360,6 @@ class IcingaDependencyForm extends DirectorObjectForm
protected function isCustomVar($string)
{
return \preg_match('/^\$(?:host)\.vars\..+\$$/', $string);
// Eventually: return \preg_match('/^\$(?:host|service)\.vars\..+\$$/', $string);
return preg_match('/^\$(?:host|service)\.vars\..+\$$/', $string);
}
}

View File

@ -2,7 +2,10 @@
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;
@ -81,7 +84,13 @@ class IcingaHostForm extends DirectorObjectForm
'class' => 'autosubmit',
]);
if ($this->getSentOrResolvedObjectValue('has_agent') === 'y') {
try {
$hasAgent = $this->getSentOrResolvedObjectValue('has_agent') === 'y';
} catch (Exception $e) {
$hasAgent = false;
}
if ($hasAgent) {
$this->addBoolean('master_should_connect', [
'label' => $this->translate('Establish connection'),
'description' => $this->translate(
@ -97,6 +106,17 @@ 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', [
@ -123,6 +143,7 @@ class IcingaHostForm extends DirectorObjectForm
'master_should_connect',
'accept_config',
'command_endpoint_id',
'custom_endpoint_name',
'api_key',
];
$this->addDisplayGroup($elements, 'clustering', [
@ -150,7 +171,7 @@ class IcingaHostForm extends DirectorObjectForm
if ($this->hasBeenSent()) {
$this->addError($this->translate('No Host template has been chosen'));
} else {
if ($this->hasPermission('director/admin')) {
if ($this->hasPermission(Permission::ADMIN)) {
$html = sprintf(
$this->translate('Please define a %s first'),
Link::create(
@ -195,8 +216,9 @@ class IcingaHostForm extends DirectorObjectForm
*/
protected function addGroupsElement()
{
if ($this->hasHostGroupRestriction()
&& ! $this->getAuth()->hasPermission('director/groups-for-restricted-hosts')
if (
$this->hasHostGroupRestriction()
&& ! $this->getAuth()->hasPermission(Permission::GROUPS_FOR_RESTRICTED_HOSTS)
) {
return $this;
}
@ -230,12 +252,14 @@ class IcingaHostForm extends DirectorObjectForm
$links->addAttributes(['class' => 'strike-links']);
/** @var BaseHtmlElement $link */
foreach ($links->getContent() as $link) {
$link->addAttributes([
'title' => $this->translate(
'Group has been inherited, but will be overridden'
. ' by locally assigned group(s)'
)
]);
if ($link instanceof BaseHtmlElement) {
$link->addAttributes([
'title' => $this->translate(
'Group has been inherited, but will be overridden'
. ' by locally assigned group(s)'
)
]);
}
}
}
$this->addElement('simpleNote', 'inherited_groups', [
@ -248,15 +272,6 @@ class IcingaHostForm extends DirectorObjectForm
return $this;
}
protected function strikeGroupLinks(BaseHtmlElement $links)
{
/** @var BaseHtmlElement $link */
foreach ($links->getContent() as $link) {
$link->getAttributes()->add('style', 'text-decoration: strike');
}
$links->add('aha');
}
protected function getInheritedGroups()
{
if ($this->hasObject()) {
@ -281,9 +296,7 @@ class IcingaHostForm extends DirectorObjectForm
);
}
return Html::tag('span', [
'style' => 'line-height: 2.5em; padding-left: 0.5em'
], $links);
return Html::tag('span', ['class' => 'host-group-links'], $links);
}
protected function getAppliedGroups()
@ -297,7 +310,7 @@ class IcingaHostForm extends DirectorObjectForm
protected function hasHostGroupRestriction()
{
return $this->getAuth()->getRestrictions('director/filter/hostgroups');
return $this->getAuth()->getRestrictions(Restriction::FILTER_HOSTGROUPS);
}
/**

View File

@ -21,6 +21,9 @@ 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;
@ -48,6 +51,7 @@ 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) {
@ -68,8 +72,7 @@ class IcingaMultiEditForm extends DirectorObjectForm
/** @var \Zend_Form_Element $el */
foreach ($this->getElements() as $el) {
$name = $el->getName();
if (substr($name, 0, 4) === 'var_') {
if ($this->isCustomVar($el->getName())) {
$this->makeVariants($el);
}
}
@ -137,8 +140,8 @@ class IcingaMultiEditForm extends DirectorObjectForm
continue;
}
if (substr($property, 0, 4) === 'var_') {
$property = 'vars.' . substr($property, 4);
if ($this->isCustomVar($property)) {
$property = 'vars.' . $this->varNameMap[$property];
}
foreach ($this->getObjects($objects) as $object) {
@ -147,13 +150,26 @@ 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++;
$object->store();
$store->store($object);
}
}
@ -221,6 +237,7 @@ class IcingaMultiEditForm extends DirectorObjectForm
$key = $element->getName();
$this->removeElement($key);
$label = $element->getLabel();
$group = $this->getDisplayGroupForElement($element);
$description = $element->getDescription();
@ -240,11 +257,13 @@ class IcingaMultiEditForm extends DirectorObjectForm
}
}
protected function getVariants($key)
{
$variants = array();
if (substr($key, 0, 4) === 'var_') {
$key = 'vars.' . substr($key, 4);
if ($this->isCustomVar($key)) {
$key = 'vars.' . $this->varNameMap[$key];
}
foreach ($this->objects as $name => $object) {
@ -309,8 +328,9 @@ class IcingaMultiEditForm extends DirectorObjectForm
$this->translate($this->object->getShortTableName())
);
$store = $this->getDbObjectStore();
foreach ($this->objects as $object) {
$object->delete();
$store->delete($object);
}
if ($this->listUrl) {

View File

@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Forms;
use Icinga\Module\Director\DataType\DataTypeDirectorObject;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
class IcingaNotificationForm extends DirectorObjectForm
@ -121,20 +122,32 @@ class IcingaNotificationForm extends DirectorObjectForm
{
$users = $this->enumUsers();
if (empty($users)) {
return $this;
}
$this->addElement(
'extensibleSet',
'users',
array(
$this->addElement('select', 'users', [
'label' => $this->translate('Users'),
'description' => $this->translate('No User object has been created yet'),
'multiOptions' => $this->optionalEnum([]),
]);
} else {
$this->addElement('extensibleSet', 'users', [
'label' => $this->translate('Users'),
'description' => $this->translate(
'Users that should be notified by this notifications'
),
'multiOptions' => $this->optionalEnum($users)
]);
}
$this->addElement('select', 'users_var', [
'label' => $this->translate('Users Custom Variable'),
'multiOptions' => $this->enumDirectorObjectFields('user'),
'description' => $this->translate(
'If defined, Users from this Custom Variable will be combined with single users chosen below. '
. ' e.g.: when set to notification_contacts, this notification will pick Users from the Array'
. ' service.vars.notification_contacts and fall back to host.vars.notification_contacts, in'
. ' case the former one does not exist.'
. ' Only Array type DirectorObject Fields for User objects are eligible for this feature.'
)
);
]);
return $this;
}
@ -146,24 +159,59 @@ class IcingaNotificationForm extends DirectorObjectForm
{
$groups = $this->enumUsergroups();
if (empty($groups)) {
return $this;
}
$this->addElement(
'extensibleSet',
'user_groups',
array(
$this->addElement('select', 'user_groups', [
'label' => $this->translate('Users'),
'description' => $this->translate('No UserGroup object has been created yet'),
'multiOptions' => $this->optionalEnum([]),
]);
} else {
$this->addElement('extensibleSet', 'user_groups', [
'label' => $this->translate('User groups'),
'description' => $this->translate(
'User groups that should be notified by this notifications'
),
'multiOptions' => $this->optionalEnum($groups)
]);
}
$this->addElement('select', 'user_groups_var', [
'label' => $this->translate('User Groups Custom Variable'),
'multiOptions' => $this->enumDirectorObjectFields('usergroup'),
'description' => $this->translate(
'If defined, User Groups from this Custom Variable will be combined with single Groups chosen below. '
. ' e.g.: when set to notification_groups, this notification will pick User Groups from the Array'
. ' service.vars.notification_groups and fall back to host.vars.notification_groups, in'
. ' case the former one does not exist.'
. ' Only Array type DirectorObject Fields for User objects are eligible for this feature.'
)
);
]);
return $this;
}
protected function enumDirectorObjectFields($objectType, $dataType = 'array')
{
$db = $this->db->getDbAdapter();
$query = $db->select()
->from(['df' => 'director_datafield'], ['k' => 'df.varname', 'v' => 'df.varname'])
->join(
['dfs' => 'director_datafield_setting'],
$db->quoteInto('df.id = dfs.datafield_id AND dfs.setting_name = ?', 'icinga_object_type'),
[]
)
->join(
['dft' => 'director_datafield_setting'],
$db->quoteInto('df.id = dft.datafield_id AND dft.setting_name = ?', 'data_type'),
[]
)
->where('df.datatype = ?', DataTypeDirectorObject::class)
->where('dfs.setting_value = ?', $objectType)
->where('dft.setting_value = ?', $dataType)
->order('df.varname');
return $this->optionalEnum($db->fetchPairs($query));
}
/**
* @return self
*/
@ -196,7 +244,7 @@ class IcingaNotificationForm extends DirectorObjectForm
array(
'label' => $this->translate('First notification delay'),
'description' => $this->translate(
'Delay unless the first notification should be sent'
'Delay until the first notification should be sent'
) . '. ' . $this->getTimeValueInfo()
)
);

View File

@ -2,6 +2,9 @@
namespace Icinga\Module\Director\Forms;
use Icinga\Module\Director\DataType\DataTypeBoolean;
use Icinga\Module\Director\DataType\DataTypeString;
use Icinga\Module\Director\Field\FormFieldSuggestion;
use Icinga\Module\Director\Objects\IcingaCommand;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Objects\IcingaObject;
@ -15,6 +18,9 @@ class IcingaObjectFieldForm extends DirectorObjectForm
/** @var IcingaObject Please note that $object would conflict with logic in parent class */
protected $icingaObject;
/** @var FormFieldSuggestion */
protected $fieldSuggestion;
public function setIcingaObject($object)
{
$this->icingaObject = $object;
@ -36,22 +42,9 @@ class IcingaObjectFieldForm extends DirectorObjectForm
. ' a specific set, shown as a dropdown.'
);
// TODO: remove assigned ones!
$existingFields = $this->db->enumDatafields();
$blacklistedVars = array();
$suggestedFields = array();
foreach ($existingFields as $id => $field) {
if (preg_match('/ \(([^\)]+)\)$/', $field, $m)) {
$blacklistedVars['$' . $m[1] . '$'] = $id;
}
}
// TODO: think about imported existing vars without fields
// TODO: extract vars from command line (-> dummy)
// TODO: do not suggest chosen ones
$argumentVars = array();
$argumentVarDescriptions = array();
if ($object instanceof IcingaCommand) {
$command = $object;
} elseif ($object->hasProperty('check_command_id')) {
@ -60,56 +53,16 @@ class IcingaObjectFieldForm extends DirectorObjectForm
$command = null;
}
if ($command) {
foreach ($command->arguments() as $arg) {
if ($arg->argument_format === 'string') {
$val = $arg->argument_value;
// TODO: create var::extractMacros or so
$suggestions = $this->fieldSuggestion = new FormFieldSuggestion($command, $this->db->enumDatafields());
$fields = $suggestions->getCommandFields();
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(
$this->addElement('select', 'datafield_id', [
'label' => 'Field',
'required' => true,
'description' => 'Field to assign',
'class' => 'autosubmit',
'multiOptions' => $this->optionalEnum($fields)
));
]);
if (empty($fields)) {
// TODO: show message depending on permissions
@ -121,67 +74,58 @@ class IcingaObjectFieldForm extends DirectorObjectForm
}
if (($id = $this->getSentValue('datafield_id')) && ! ctype_digit($id)) {
$this->addElement('text', 'caption', array(
$this->addElement('text', 'caption', [
'label' => $this->translate('Caption'),
'required' => true,
'ignore' => true,
'value' => trim($id, '$'),
'description' => $this->translate('The caption which should be displayed')
));
'description' => $this->translate(
'The caption which should be displayed to your users when this field'
. ' is shown'
)
]);
$this->addElement('textarea', 'description', array(
$this->addElement('textarea', 'description', [
'label' => $this->translate('Description'),
'description' => $this->translate('A description about the field'),
'description' => $this->translate(
'An extended description for this field. Will be shown as soon as a'
. ' user puts the focus on this field'
),
'ignore' => true,
'value' => array_key_exists($id, $argumentVarDescriptions) ? $argumentVarDescriptions[$id] : null,
'value' => $command ? $suggestions->getDescription($id) : null,
'rows' => '3',
));
]);
}
$this->addElement('select', 'is_required', array(
$this->addElement('select', 'is_required', [
'label' => $this->translate('Mandatory'),
'description' => $this->translate('Whether this field should be mandatory'),
'required' => true,
'multiOptions' => array(
'multiOptions' => [
'n' => $this->translate('Optional'),
'y' => $this->translate('Mandatory'),
)
));
]
]);
$filterFields = array();
$prefix = null;
if ($object instanceof IcingaHost) {
$prefix = 'host.vars.';
} elseif ($object instanceof IcingaService) {
$prefix = 'service.vars.';
}
if ($prefix) {
$loader = new IcingaObjectFieldLoader($object);
$fields = $loader->getFields();
foreach ($fields as $varName => $field) {
$filterFields[$prefix . $field->varname] = $field->caption;
}
$this->addFilterElement('var_filter', array(
if ($filterFields = $this->getFilterFields($object)) {
$this->addFilterElement('var_filter', [
'description' => $this->translate(
'You might want to show this field only when certain conditions are met.'
. ' Otherwise it will not be available and values eventually set before'
. ' will be cleared once stored'
),
'columns' => $filterFields,
));
]);
$this->addDisplayGroup(array($this->getElement('var_filter')), 'field_filter', array(
'decorators' => array(
$this->addDisplayGroup([$this->getElement('var_filter')], 'field_filter', [
'decorators' => [
'FormElements',
array('HtmlTag', array('tag' => 'dl')),
['HtmlTag', ['tag' => 'dl']],
'Fieldset',
),
],
'order' => 30,
'legend' => $this->translate('Show based on filter')
));
]);
}
$this->setButtons();
@ -202,18 +146,42 @@ class IcingaObjectFieldForm extends DirectorObjectForm
$fieldId = $this->getValue('datafield_id');
if (! ctype_digit($fieldId)) {
$field = DirectorDatafield::create(array(
$field = DirectorDatafield::create([
'varname' => trim($fieldId, '$'),
'caption' => $this->getValue('caption'),
'description' => $this->getValue('description'),
'datatype' => 'Icinga\Module\Director\DataType\DataTypeString',
));
'datatype' => $this->fieldSuggestion && $this->fieldSuggestion->isBoolean($fieldId)
? DataTypeBoolean::class
: DataTypeString::class
]);
$field->store($this->getDb());
$this->setElementValue('datafield_id', $field->get('id'));
$this->object()->set('datafield_id', $field->get('id'));
}
$this->object()->set('var_filter', $this->getValue('var_filter'));
return parent::onSuccess();
parent::onSuccess();
}
protected static function getFilterFields(IcingaObject $object): array
{
$filterFields = [];
$prefix = null;
if ($object instanceof IcingaHost) {
$prefix = 'host.vars.';
} elseif ($object instanceof IcingaService) {
$prefix = 'service.vars.';
}
if ($prefix) {
$loader = new IcingaObjectFieldLoader($object);
$fields = $loader->getFields();
foreach ($fields as $varName => $field) {
$filterFields[$prefix . $field->get('varname')] = $field->get('caption');
}
}
return $filterFields;
}
}

View File

@ -22,6 +22,10 @@ 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'),

View File

@ -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, 2016-01-28 - have a look at the documentation for more examples'
'Might be monday, tuesday or 2016-01-28 - have a look at the documentation for more examples'
),
]);

View File

@ -0,0 +1,54 @@
<?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;
}
}

View File

@ -6,12 +6,15 @@ 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;
@ -127,6 +130,8 @@ class IcingaServiceForm extends DirectorObjectForm
if (! $this->providesOverrides()) {
return;
}
$hasDeleteButton = false;
$isBranch = $this->branch && $this->branch->isBranch();
if ($this->hasBeenBlacklisted()) {
$this->addHtml(
@ -134,11 +139,22 @@ class IcingaServiceForm extends DirectorObjectForm
['name' => 'HINT_blacklisted']
);
$group = null;
$this->addDeleteButton($this->translate('Reactivate'));
if (! $isBranch) {
$this->addDeleteButton($this->translate('Reactivate'));
$hasDeleteButton = true;
}
$this->setSubmitLabel(false);
} else {
$this->addOverrideHint();
$group = $this->getDisplayGroup('custom_fields');
if (! $group) {
foreach ($this->getDisplayGroups() as $groupName => $eventualGroup) {
if (preg_match('/^custom_fields:/', $groupName)) {
$group = $eventualGroup;
break;
}
}
}
if ($group) {
$elements = $group->getElements();
$group->setElements([$this->getElement('inheritance_hint')]);
@ -155,10 +171,13 @@ class IcingaServiceForm extends DirectorObjectForm
$this->setSubmitLabel(false);
}
$this->addDeleteButton($this->translate('Deactivate'));
if (! $isBranch) {
$this->addDeleteButton($this->translate('Deactivate'));
$hasDeleteButton = true;
}
}
if (! $this->hasSubmitButton()) {
if (! $this->hasSubmitButton() && $hasDeleteButton) {
$this->addDisplayGroup([$this->deleteButtonName], 'buttons', [
'decorators' => [
'FormElements',
@ -179,14 +198,16 @@ class IcingaServiceForm extends DirectorObjectForm
}
/**
* @param IcingaService $service
* @return IcingaService
* Hint: could be moved elsewhere
*
* @param IcingaService $object
* @return IcingaObject|IcingaService|IcingaServiceSet
* @throws \Icinga\Exception\NotFoundError
*/
protected function getFirstParent(IcingaService $service)
protected static function getFirstParent(IcingaObject $object)
{
/** @var IcingaService[] $objects */
$objects = $service->imports()->getObjects();
/** @var IcingaObject[] $objects */
$objects = $object->imports()->getObjects();
if (empty($objects)) {
throw new RuntimeException('Something went wrong, got no parent');
}
@ -207,13 +228,19 @@ 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 = ?', $host->get('id'))
->where('service_id = ?', $service->get('id'))
->where('host_id = ?', $hostId)
->where('service_id = ?', $serviceId)
);
} else {
$this->blacklisted = false;
@ -255,10 +282,12 @@ 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(),
@ -277,7 +306,7 @@ class IcingaServiceForm extends DirectorObjectForm
if ($this->set) {
return $this->object;
} else {
return $this->getFirstParent($this->object);
return self::getFirstParent($this->object);
}
}
@ -325,14 +354,14 @@ class IcingaServiceForm extends DirectorObjectForm
protected function setupServiceElements()
{
if ($this->object) {
$objectType = $this->object->object_type;
$objectType = $this->object->get('object_type');
} elseif ($this->preferredObjectType) {
$objectType = $this->preferredObjectType;
} else {
$objectType = 'template';
}
$this->addHidden('object_type', $objectType);
$forceCommandElements = $this->hasPermission('director/admin');
$forceCommandElements = $this->hasPermission(Permission::ADMIN);
$this->addNameElement()
->addHostObjectElement()
@ -414,10 +443,6 @@ class IcingaServiceForm extends DirectorObjectForm
$this->addHtmlHint($hint, ['name' => 'inheritance_hint']);
}
/**
* @throws IcingaException
* @throws ProgrammingError
*/
protected function setupOnHostForSet()
{
$msg = $this->translate(
@ -470,7 +495,7 @@ class IcingaServiceForm extends DirectorObjectForm
*/
protected function setupHostRelatedElements()
{
$this->addHidden('host_id', $this->host->id);
$this->addHidden('host', $this->host->getObjectName());
$this->addHidden('object_type', 'object');
$this->addImportsElement();
$imports = $this->getSentOrObjectValue('imports');
@ -493,13 +518,7 @@ class IcingaServiceForm extends DirectorObjectForm
->addExtraInfoElements()
->setButtons();
if ($this->hasBeenSent()) {
$name = $this->getSentOrObjectValue('object_name');
if (!strlen($name)) {
$this->setElementValue('object_name', end($imports));
$this->object->object_name = end($imports);
}
}
$this->setDefaultNameFromTemplate($imports);
}
/**
@ -517,7 +536,7 @@ class IcingaServiceForm extends DirectorObjectForm
*/
protected function setupSetRelatedElements()
{
$this->addHidden('service_set_id', $this->set->id);
$this->addHidden('service_set', $this->set->getObjectName());
$this->addHidden('object_type', 'apply');
$this->addImportsElement();
$this->setButtons();
@ -537,19 +556,13 @@ class IcingaServiceForm extends DirectorObjectForm
->addGroupsElement()
->groupMainProperties();
if ($this->hasPermission('director/admin')) {
if ($this->hasPermission(Permission::ADMIN)) {
$this->addCheckCommandElements(true)
->addCheckExecutionElements(true)
->addExtraInfoElements();
}
if ($this->hasBeenSent()) {
$name = $this->getSentOrObjectValue('object_name');
if (!strlen($name)) {
$this->setElementValue('object_name', end($imports));
$this->object->object_name = end($imports);
}
}
$this->setDefaultNameFromTemplate($imports);
}
public function setServiceSet(IcingaServiceSet $set)
@ -586,14 +599,14 @@ class IcingaServiceForm extends DirectorObjectForm
protected function addHostObjectElement()
{
if ($this->isObject()) {
$this->addElement('select', 'host_id', array(
$this->addElement('select', 'host', [
'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;
@ -695,10 +708,35 @@ class IcingaServiceForm extends DirectorObjectForm
protected function enumHostsAndTemplates()
{
return array(
$this->translate('Templates') => $this->db->enumHostTemplates(),
$this->translate('Hosts') => $this->db->enumHosts(),
);
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;
}
protected function enumServicegroups()
@ -715,10 +753,6 @@ class IcingaServiceForm extends DirectorObjectForm
return $db->fetchPairs($select);
}
/**
* @throws IcingaException
* @throws ProgrammingError
*/
protected function succeedForOverrides()
{
$vars = array();
@ -739,7 +773,7 @@ class IcingaServiceForm extends DirectorObjectForm
$this->translate($host->getObjectName())
);
$host->store();
$this->getDbObjectStore()->store($host);
} else {
if ($this->isApiRequest()) {
$this->setHttpResponseCode(304);
@ -751,16 +785,27 @@ class IcingaServiceForm extends DirectorObjectForm
$this->redirectOnSuccess($msg);
}
/**
* @throws IcingaException
* @throws ProgrammingError
*/
public function onSuccess()
{
if ($this->providesOverrides()) {
return $this->succeedForOverrides();
$this->succeedForOverrides();
return;
}
return parent::onSuccess();
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));
}
}
}
}

View File

@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Forms;
use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Objects\IcingaHost;
use Icinga\Module\Director\Web\Form\DirectorObjectForm;
@ -69,7 +70,8 @@ class IcingaServiceSetForm extends DirectorObjectForm
}
$this->addHidden('object_type', 'object');
$this->addHidden('host_id', $this->host->id);
$this->addHidden('host', $this->host->getObjectName());
$this->groupMainProperties();
}
public function setHost(IcingaHost $host)
@ -77,6 +79,7 @@ class IcingaServiceSetForm extends DirectorObjectForm
$this->host = $host;
return $this;
}
protected function addSingleImportsElement()
{
$enum = $this->enumAllowedTemplates();
@ -111,7 +114,7 @@ class IcingaServiceSetForm extends DirectorObjectForm
protected function addAssignmentElements()
{
if (! $this->hasPermission('director/service_set/apply')) {
if (! $this->hasPermission(Permission::SERVICE_SET_APPLY)) {
return $this;
}

View File

@ -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,6 +91,15 @@ 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();
}
@ -124,7 +133,7 @@ class IcingaTemplateChoiceForm extends DirectorObjectForm
/** @var IcingaTemplateChoice $object */
$object = $this->object();
$this->setSuccessUrl(
'director/templatechoice/' . $object->getObjectshortTableName(),
'director/templatechoice/' . $object->getObjectShortTableName(),
$object->getUrlParams()
);
}

View File

@ -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, 2016-01-28 - have a look at the documentation for more examples'
'Might be monday, tuesday or 2016-01-28 - have a look at the documentation for more examples'
),
));

View File

@ -64,6 +64,41 @@ class ImportRowModifierForm extends DirectorObjectForm
$error = $e->getMessage();
$mods = $this->optionalEnum([]);
}
$this->addElement('YesNo', 'use_filter', [
'label' => $this->translate('Set based on filter'),
'ignore' => true,
'class' => 'autosubmit',
'required' => true,
]);
if ($this->hasBeenSent()) {
$useFilter = $this->getSentValue('use_filter');
if ($useFilter === null) {
$this->setElementValue('use_filter', $useFilter = 'n');
}
} elseif ($object = $this->getObject()) {
$expression = $object->get('filter_expression');
$useFilter = ($expression === null || strlen($expression) === 0) ? 'n' : 'y';
$this->setElementValue('use_filter', $useFilter);
} else {
$this->setElementValue('use_filter', $useFilter = 'n');
}
if ($useFilter === 'y') {
$this->addElement('text', 'filter_expression', [
'label' => $this->translate('Filter Expression'),
'description' => $this->translate(
'This allows to filter for specific parts within the given source expression.'
. ' You are allowed to refer all imported columns. Examples: host=www* would'
. ' set this property only for rows imported with a host property starting'
. ' with "www". Complex example: host=www*&!(address=127.*|address6=::1).'
. ' Please note, that CIDR notation based matches are also supported: '
. ' address=192.0.2.128/25| address=2001:db8::/32| address=::ffff:192.0.2.0/96'
),
'required' => true,
// TODO: validate filter
]);
}
$this->addElement('select', 'provider_class', [
'label' => $this->translate('Modifier'),
@ -163,10 +198,10 @@ class ImportRowModifierForm extends DirectorObjectForm
if ($class !== null) {
if (! class_exists($class)) {
throw new RuntimeException(
throw new RuntimeException(sprintf(
'The hooked class "%s" for this property modifier does no longer exist',
$class
);
));
}
$class::addSettingsFormFields($this);
@ -179,4 +214,13 @@ class ImportRowModifierForm extends DirectorObjectForm
return $this;
}
public function onSuccess()
{
if ($this->getValue('use_filter') === 'n') {
$this->getObject()->set('filter_expression', null);
}
parent::onSuccess();
}
}

View File

@ -41,12 +41,18 @@ 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'
@ -71,7 +77,7 @@ class KickstartForm extends DirectorForm
$hint = Html::sprintf(
$this->translate('Your database looks good, you are ready to %s'),
Link::create(
'start working with the Icinga Director',
$this->translate('start working with the Icinga Director'),
'director',
null,
['data-base-target' => '_main']
@ -194,35 +200,8 @@ 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');
}
}
$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'));
}
}
$this->tryDbConnection();
}
/**
@ -343,7 +322,7 @@ class KickstartForm extends DirectorForm
)
);
$this->addHtmlHint(
Html::tag('pre', null, $config),
Html::tag('pre', null, (string) $config),
array('name' => 'HINT_config_store')
);
@ -376,8 +355,10 @@ 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();
}
@ -466,4 +447,41 @@ 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;
}
}

View File

@ -17,10 +17,7 @@ class RemoveLinkForm extends DirectorForm
{
// Required to detect the right instance
$this->formName = 'RemoveSet' . sha1(json_encode($params));
parent::__construct([
'style' => 'float: right',
'data-base-target' => '_self'
]);
parent::__construct(['data-base-target' => '_self']);
$this->label = $label;
$this->title = $title;
foreach ($params as $name => $value) {
@ -38,7 +35,7 @@ class RemoveLinkForm extends DirectorForm
public function setup()
{
$this->setAttrib('class', 'inline');
$this->addAttribs(['class' => ['inline', 'remove-link-form']]);
$this->addHtml(Icon::create('cancel'));
$this->addSubmitButton($this->label, [
'class' => 'link-button',

View File

@ -105,6 +105,18 @@ 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(

View File

@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Forms;
use Icinga\Module\Director\Objects\DirectorActivityLog;
use Icinga\Module\Director\Objects\SyncRule;
use Icinga\Module\Director\Web\Form\DirectorForm;
@ -31,16 +32,20 @@ class SyncCheckForm extends DirectorForm
$this->notifySuccess(
$this->translate(('This Sync Rule would apply new changes'))
);
$sum = array('create' => 0, 'modify' => 0, 'delete' => 0);
$sum = [
DirectorActivityLog::ACTION_CREATE => 0,
DirectorActivityLog::ACTION_MODIFY => 0,
DirectorActivityLog::ACTION_DELETE => 0
];
// TODO: Preview them? Like "hosta, hostb and 4 more would be...
foreach ($this->rule->getExpectedModifications() as $object) {
if ($object->shouldBeRemoved()) {
$sum['delete']++;
$sum[DirectorActivityLog::ACTION_DELETE]++;
} elseif (! $object->hasBeenLoadedFromDb()) {
$sum['create']++;
$sum[DirectorActivityLog::ACTION_CREATE]++;
} elseif ($object->hasBeenModified()) {
$sum['modify']++;
$sum[DirectorActivityLog::ACTION_MODIFY]++;
}
}
@ -50,7 +55,7 @@ class SyncCheckForm extends DirectorForm
} elseif ($sum['modify'] > 1) {
}
*/
$html = '<pre>' . print_r($sum, 1) . '</pre>';
$html = '<pre>' . print_r($sum, true) . '</pre>';
$this->addHtml($html);
} elseif ($this->rule->get('sync_state') === 'in-sync') {

View File

@ -25,7 +25,7 @@ class SyncPropertyForm extends DirectorObjectForm
private $dummyObject;
const EXPRESSION = '__EXPRESSION__';
public const EXPRESSION = '__EXPRESSION__';
/**
* @throws \Zend_Form_Exception
@ -93,7 +93,8 @@ class SyncPropertyForm extends DirectorObjectForm
$this->setElementValue('use_filter', $useFilter = 'n');
}
} else {
$useFilter = strlen($this->getObject()->filter_expression) ? 'y' : 'n';
$expression = $this->getObject()->filter_expression;
$useFilter = ($expression === null || strlen($expression) === 0) ? 'n' : 'y';
$this->setElementValue('use_filter', $useFilter);
}

View File

@ -74,9 +74,23 @@ 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'),
'description' => sprintf(

View File

@ -2,44 +2,66 @@
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 DirectorForm
class SyncRunForm extends Form
{
use TranslationHelper;
protected $defaultDecoratorClass = null;
/** @var ?string */
protected $successMessage = null;
/** @var SyncRule */
protected $rule;
public function setSyncRule(SyncRule $rule)
/** @var DbObjectStore */
protected $store;
public function __construct(SyncRule $rule, DbObjectStore $store)
{
$this->rule = $rule;
return $this;
$this->store = $store;
}
public function setup()
public function assemble()
{
$this->submitLabel = false;
$this->addElement('submit', 'submit', array(
'label' => $this->translate('Trigger this Sync'),
'decorators' => array('ViewHelper')
));
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;
}
public function onSuccess()
{
$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')
);
$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');
}
} else {
$this->addError($this->translate('Synchronization failed'));
// Used to be $rule->get('sync_state') === 'in-sync', $changed = $rule->applyChanges();
$this->successMessage = $this->translate('Nothing to do, rule is in sync');
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1839,7 +1839,7 @@ msgstr ""
"essere basate sui gruppi."
#: application/forms/IcingaNotificationForm.php:199
msgid "Delay unless the first notification should be sent"
msgid "Delay until the first notification should be sent"
msgstr "Ritarda prima di spedire la prima notifica"
#: application/forms/IcingaObjectFieldForm.php:193
@ -1979,7 +1979,7 @@ msgid "Disable Checks"
msgstr "Disattivare i Checks"
#: application/forms/IcingaDependencyForm.php:167
msgid "Disable Notificiations"
msgid "Disable Notifications"
msgstr "Disattivare le notifiche"
#: application/forms/SettingsForm.php:54
@ -3429,7 +3429,7 @@ msgstr "Regole su Unisci"
#: application/forms/IcingaScheduledDowntimeRangeForm.php:24
#, fuzzy
msgid ""
"Might be, monday, tuesday, 2016-01-28 - have a look at the documentation for "
"Might be monday, tuesday or 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"

View File

@ -1665,7 +1665,7 @@ msgstr "サービスグループを定義すると、より構造がわかりま
"最適です。 通知と許可はグループに基づいている場合があります。"
#: ../../../../modules/director/application/forms/IcingaNotificationForm.php:196
msgid "Delay unless the first notification should be sent"
msgid "Delay until the first notification should be sent"
msgstr "最初の通知時間"
#: ../../../../modules/director/application/forms/IcingaObjectFieldForm.php:185
@ -1791,7 +1791,7 @@ msgstr "監視を無効化"
# smori
#: ../../../../modules/director/application/forms/IcingaDependencyForm.php:164
msgid "Disable Notificiations"
msgid "Disable Notifications"
msgstr "通知を無効化"
#: ../../../../modules/director/application/forms/SettingsForm.php:54
@ -3058,7 +3058,7 @@ msgstr "マージポリシー"
#: ../../../../modules/director/application/forms/IcingaTimePeriodRangeForm.php:23
msgid ""
"Might be, monday, tuesday, 2016-01-28 - have a look at the documentation for "
"Might be monday, tuesday or 2016-01-28 - have a look at the documentation for "
"more examples"
msgstr "monday, tuesday, 2016-01-28といった書式で指定します。"
"より多くの例についてはドキュメントを見てください"

View File

@ -44,14 +44,16 @@ class Zend_View_Helper_FormDataFilter extends Zend_View_Helper_FormElement
{
$info = $this->_getInfo($name, $value, $attribs);
extract($info); // id, name, value, attribs, options, listsep, disable
if (array_key_exists('columns', $attribs)) {
$this->setColumns($attribs['columns']);
unset($attribs['columns']);
}
if ($attribs) {
if (array_key_exists('columns', $attribs)) {
$this->setColumns($attribs['columns']);
unset($attribs['columns']);
}
if (array_key_exists('suggestionContext', $attribs)) {
$this->setSuggestionContext($attribs['suggestionContext']);
unset($attribs['suggestionContext']);
if (array_key_exists('suggestionContext', $attribs)) {
$this->setSuggestionContext($attribs['suggestionContext']);
unset($attribs['suggestionContext']);
}
}
// TODO: check for columns in attribs, preserve & remove them from the
@ -217,7 +219,7 @@ class Zend_View_Helper_FormDataFilter extends Zend_View_Helper_FormElement
} elseif (substr($col, $prefixLen, 5) === 'vars.') {
$var = substr($col, $prefixLen + 5);
return $this->text($filter, "DataListValues!${var}");
return $this->text($filter, "DataListValues!{$var}");
}
}
@ -236,7 +238,7 @@ class Zend_View_Helper_FormDataFilter extends Zend_View_Helper_FormElement
$filter->getExpression(),
[
'class' => 'director-suggest',
'data-suggestion-context' => "${type}groupnames",
'data-suggestion-context' => "{$type}groupnames",
]
);
}

View File

@ -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 (\strlen($sentValue)) {
if ($sentValue !== null && \strlen($sentValue)) {
$el->getAttributes()->set('value', $sentValue);
} elseif (\strlen($value) > 0) {
} elseif ($value !== null && \strlen($value) > 0) {
$el->getAttributes()->set('value', '__UNCHANGED_VALUE__');
}

View File

@ -1,4 +1,5 @@
<?php
// Avoid complaints about missing namespace and invalid class name
// @codingStandardsIgnoreStart

View File

@ -1,8 +1,3 @@
<?php
use Icinga\Application\Modules\Manager;
?>
<div class="controls">
<?= $this->tabs ?>
<h1><?= $this->escape($this->title) ?></h1>
@ -10,62 +5,5 @@ use Icinga\Application\Modules\Manager;
<div class="content">
<p class="legacy-error"><?= $this->escape($this->message) ?></p>
<table class="common-table table-row-selectable">
<thead>
<tr>
<th><?= $this->translate('Module name') ?></th>
<th><?= $this->translate('Required') ?></th>
<th><?= $this->translate('Installed') ?></th>
</tr>
</thead>
<tbody data-base-target="_next">
<?php
foreach ($this->dependencies as $module => $required) {
/** @var Manager $this->modules */
if ($modules->hasEnabled($module)) {
$installed = $modules->getModule($module, false)->getVersion();
$installed = \ltrim($installed, 'v'); // v0.6.0 VS 0.6.0
if (\preg_match('/^([<>=]+)\s*v?(\d+\.\d+\.\d+)$/', $required, $match)) {
$operator = $match[1];
$vRequired = $match[2];
if (\version_compare($installed, $vRequired, $operator)) {
$icon = 'ok';
} else {
$icon = 'cancel';
}
} else {
$icon = 'cancel';
}
$link = $this->qlink(
$module,
'config/module',
['name' => $module],
['class' => "icon-$icon"]
);
} elseif ($modules->hasInstalled($module)) {
$installed = $this->translate('disabled');
$link = $this->qlink($module, 'config/module', ['name' => $module], ['class' => 'icon-cancel']);
} else {
$installed = $this->translate('missing');
$link = sprintf(
'<a href="#" class="icon-cancel">%s</a> (<a href="https://github.com/Icinga/icingaweb2-module-%s"'
. ' target="_blank" rel="noreferrer">%s</a>)',
$this->escape($module),
$this->escape($module),
$this->translate('more')
);
}
\printf(
'<tr><td>%s</a></td><td>%s</td><td>%s</td></tr>',
$link,
$this->escape($required),
$this->escape($installed)
);
}
?>
</tbody>
</table>
<?= $this->table ?>
</div>

View File

@ -1,72 +1,99 @@
<?php
use Icinga\Application\Icinga;
use Icinga\Application\Modules\Module;
use Icinga\Module\Director\Auth\Permission;
use Icinga\Module\Director\Auth\Restriction;
use Icinga\Web\Window;
/** @var 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'));
$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')
);
$monitoringExists = Module::exists('monitoring');
$icingadbExists = Module::exists('icingadb');
$this->provideRestriction(
'director/service/apply/filter-by-name',
$this->translate(
'Filter available service apply rules'
)
);
$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/notification/apply/filter-by-name',
$this->translate(
'Filter available notification 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/service_set/filter-by-name',
$this->translate(
'Filter available service set templates. Use asterisks (*) as wildcards,'
. ' like in DB* or *net*'
)
);
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->provideSearchUrl($this->translate('Host configs'), 'director/hosts?limit=10', 60);
@ -83,10 +110,10 @@ $this->provideRestriction(
);
*/
$this->provideConfigTab('config', array(
$this->provideConfigTab('config', [
'title' => 'Configuration',
'url' => 'settings'
));
]);
$mainTitle = N_('Icinga Director');
try {
@ -113,41 +140,38 @@ try {
$mainTitle .= ' (?!)';
}
$section = $this->menuSection(
$mainTitle
)->setUrl('director')->setPriority(60)->setIcon(
'cubes'
)->setRenderer(array(
'SummaryNavigationItemRenderer',
'state' => 'critical'
));
// Hint: director/admin and director/deployments are intentionally
$section = $this->menuSection($mainTitle)
->setUrl('director')
->setPriority(60)
->setIcon('cubes')
->setRenderer(['SummaryNavigationItemRenderer', 'state' => 'critical']);
$section->add(N_('Hosts'))
->setUrl('director/dashboard?name=hosts')
->setPermission('director/hosts')
->setPermission(Permission::HOSTS)
->setPriority(30);
$section->add(N_('Services'))
->setUrl('director/dashboard?name=services')
->setPermission('director/services')
->setPermission(Permission::SERVICES)
->setPriority(40);
$section->add(N_('Commands'))
->setUrl('director/dashboard?name=commands')
->setPermission('director/admin')
->setPermission(Permission::ADMIN)
->setPriority(50);
$section->add(N_('Notifications'))
->setUrl('director/dashboard?name=notifications')
->setPermission('director/notifications')
->setPermission(Permission::NOTIFICATIONS)
->setPriority(70);
$section->add(N_('Automation'))
->setUrl('director/importsources')
->setPermission('director/admin')
->setPermission(Permission::ADMIN)
->setPriority(901);
$section->add(N_('Activity log'))
->setUrl('director/config/activities')
->setPriority(902)
->setPermission('director/audit')
->setPermission(Permission::AUDIT)
->setRenderer('ConfigHealthItemRenderer');
$section->add(N_('Deployments'))
->setUrl('director/config/deployments')
->setPriority(902)
->setPermission('director/deployments');
->setPermission(Permission::DEPLOYMENTS);

View File

@ -1,147 +1,75 @@
<a id="Installation"></a>Installation
=====================================
<!-- {% if index %} -->
# Installing Icinga Director
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 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.
Requirements
------------
The following steps will guide you through installing and setting up Icinga Director.
* Icinga 2 (&gt;= 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 (&gt;= 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.5.0)
* [reactbundle](https://github.com/Icinga/icingaweb2-module-reactbundle) (>=0.7.0)
* A database, MySQL (&gt;= 5.1) or PostgreSQL (&gt;= 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)
To upgrade an existing Icinga Director installation to a newer version,
see the [upgrading](05-Upgrading.md) documentation for the necessary steps.
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
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.
Database
--------
## Optional Requirements
### Create an empty Icinga Director 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:
HINT: You should replace `some-password` with a secure custom password.
* 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 %} -->
#### MySQL (or MariaDB)
## Installing Icinga Director Package
mysql -e "CREATE DATABASE director CHARACTER SET 'utf8';
CREATE USER director@localhost IDENTIFIED BY 'some-password';
GRANT ALL ON director.* TO director@localhost;"
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 %} -->
In case your MySQL root user is password-protected, please add `-p` to this
command.
## Setting up the Database
#### PostgreSQL
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.
### Setting up a MySQL or MariaDB Database
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;"
> **Warning**
> Make sure to replace `CHANGEME` with a secure password.
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.
```
mysql -e "CREATE DATABASE director CHARACTER SET 'utf8';
CREATE USER director@localhost IDENTIFIED BY 'CHANGEME';
GRANT ALL ON director.* TO director@localhost;"
```
Web-based Configuration
-----------------------
### Setting up a PostgreSQL Database
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).
> **Warning**
> Make sure to replace `CHANGEME` with a secure password.
### Create a Database resource
```
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;"
```
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.
## Configuring Icinga Director
Log in to your running Icinga Web setup with a privileged user
and follow the steps below to configure Icinga Director:
### 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.0"
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.0"
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. 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 #} -->

View File

@ -0,0 +1,83 @@
# 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" %} -->

View File

@ -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,6 +15,9 @@ 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)
@ -39,6 +42,31 @@ 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
-------------------------------------------------

View File

@ -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
* manifactured by Cisco
* manufactured by Cisco
* with SNMP credentials, regardless of which version
...might then look as follows:

View File

@ -75,6 +75,12 @@ 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
@ -126,17 +132,18 @@ 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 |
| 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 |
#### Examples
@ -184,16 +191,16 @@ in JSON format.
#### Options
| 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 |
| 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 |
### Clone an existing object
@ -281,7 +288,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 |
@ -456,7 +463,22 @@ Config with checksum b330febd0820493fb12921ad8f5ea42102a5c871 already exists
### Config deployment
You do not need to explicitely render your config before deploying it to your
#### 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
Icinga 2 master node. Just trigger a deployment, it will re-render the current
config:
@ -490,6 +512,13 @@ 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:

View File

@ -39,12 +39,15 @@ 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
@ -113,23 +116,37 @@ 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 `resolve` parameter to your URL, all inherited object
In case you add the `resolved` 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 all properties
TODO: adjust the code to fix this, current implementation has `withNull`
#### Retrieve default (null) properties also
Per default properties with `null` value are skipped when shipping a result.
You can influence this behavior with the properties parameter. Just append
`properties=ALL` to your URL:
You can influence this behavior with the `properties` parameter. Just append
`&withNull` to your URL:
director/host?name=hostname.example.com&properties=all
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
#### Retrieve only specific properties
@ -141,6 +158,23 @@ 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
@ -223,7 +257,7 @@ You can of course also use the API to trigger specific actions. Deploying the co
More
----
Currently we do not handle Last-Modified und ETag headers. This would involve some work, but could be a cool feature. Let us know your ideas!
Currently, we do not handle Last-Modified und ETag headers. This would involve some work, but could be a cool feature. Let us know your ideas!
Sample scenario
@ -526,8 +560,8 @@ Another possibility is to pass a list of checksums to fetch the status of
specific deployments and (activity log) activities.
Following, you can see an example of how to do it:
GET director/config/deployment-status?config_checksums=617b9cbad9e141cfc3f4cb636ec684bd60073be2,
617b9cbad9e141cfc3f4cb636ec684bd60073be1&activity_log_checksums=617b9cbad9e141cfc3f4cb636ec684bd60073be1,
GET director/config/deployment-status?configs=617b9cbad9e141cfc3f4cb636ec684bd60073be2,
617b9cbad9e141cfc3f4cb636ec684bd60073be1&activitiess=617b9cbad9e141cfc3f4cb636ec684bd60073be1,
028b3a19ca7457f5fc9dbb5e4ea527eaf61616a2
```json

View File

@ -4,6 +4,528 @@
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))
### 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.
![Notification User Vars](screenshot/director/82_changelog/v1.11.0/82-1.11.0-05-notification_user-var.png)
Behind the scenes, some Icinga DSL assures that Icinga behaves as expected:
![Notification User Vars rendered](screenshot/director/82_changelog/v1.11.0/82-1.11.0-06-notification_user-var_rendered.png)
The IcingaDB module is now supported. This release also ships a fallback template
for Icinga for Windows 1.11 (and Icinga 2.14). To improve security for those
relying on default settings, all Host templates are per default rendered to all
non-global zones in a redundant way, instead of being rendered to the main global
zone.
For those who want to store Secrets in their Host template definitions, this now
hinders them from reaching your Agent Endpoints. In addition to this, with this
release you now have more control over target Zones for services belonging to
Service Sets. Also, some issues related to permissions and restrictions have been
addressed.
Various little Import and Sync issues have been addressed, automated Service
Template import has been fixed. In addition to some minor Property modifier
improvements, they can now be applied in a conditional way. Such filter rules
also support CIDR notation. Most prominent use-case: as vSphereDB now ships ALL
guest IP addresses, you can pick specific addresses for specific use-cases /
host properties based on their network range:
![CIDR-based filters](screenshot/director/82_changelog/v1.11.0/82-1.11.0-01-cidr_based_filters.png)
This release now officially supports PHP 8.2, addresses issues when integrating
with the IcingaDB web module, and some dark-mode glitches. Search functionality
has been improved, Preview Diff shows more details, editing multiple single
Services with the very same name has been fixed, and the interactive Startup log
renderer now wraps log lines in a nice way:
![Wrap Startup Log lines](screenshot/director/82_changelog/v1.11.0/82-1.11.0-02-wrap_startup_log_lines.png)
Performance has greatly been improved for those, who trigger a lot of single API
requests, instead of relying on Import/Sync mechanism. Our template usage overview
now also summarizes and links objects used in Services belonging to Service Sets:
![Template Usage overview](screenshot/director/82_changelog/v1.11.0/82-1.11.0-03-template_usage.png)
Commands can now be cloned with their field definitions, and custom variables
from set_if flags make now part of the "suggested fields" list.
In addition to major refactoring and technical improvements related to our
configuration baskets, it's now also possible to upload additional snapshots for
existing baskets:
![Basket Snapshot upload](screenshot/director/82_changelog/v1.11.0/82-1.11.0-04-upload_basket_snapshot.png)
Speaking of baskets, they have been reworked in a way giving especially Icinga
Partners and Plugin authors more control over related objects. As UUIDs are now
supported in Baskets too, it is for example possible to rename an object with a
new Basket Snapshot.
### Breaking Changes
* Module and system dependencies have been raised, [Upgrading](05-Upgrading.md)
and [Installation](02-Installation.md) documentations contain related details
### UI
* FEATURE: allow to clone commands with fields (#2264)
* FEATURE: Data Fields are now sorted in a case-insensitive way (#2358)
* FEATURE: Data Field search is now case-insensitive (#2359)
* FEATURE: Deployment Log now breaks lines (#2677)
* FEATURE: Sort Template trees by name (#2691)
* FEATURE: Branch and Sync diff/preview now shows related host for services (#2736)
* FEATURE: Show more details for assign filter parsing errors (#2667)
* FEATURE: Fields from set_if are now being proposed (#514)
* FEATURE: Template usage table now shows Set members (#2378)
* FIX: do not fail for (some) Service Dependencies (#2669, #1142)
* FIX: Service Sets can now be searched by Service name in branches too (#2738)
* FIX: Template usage table had no header (#2780)
* FIX: Strikethrough for deactivated services in applied Service Set (#2746, #2766)
* FIX: editing multi-selected services with the same name has been fixed (#2798, 2801, #2599)
* FIX: Service Sets table with PostgreSQL (#2799)
* FIX: Dark mode for some clone forms (#2670)
### Icinga Configuration
* FEATURE: render fallback template for IfW 1.11 for Icinga &lt; 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 &amp; 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:
![Sync Preview - List](https://user-images.githubusercontent.com/553008/191472888-33849b3e-9d96-4113-b960-92708769e90d.png)
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:
![Sync Preview - Details](https://user-images.githubusercontent.com/553008/191472900-1968691e-a758-4c99-99ce-059bc3689356.png)
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
-----
### Fixed issues
* You can find issues and feature requests related to this release on our
[roadmap](https://github.com/Icinga/icingaweb2-module-director/milestone/24?closed=1)
### User Interface
* FIX: show Override button when all Fields belong to Field Categories (#2303)
* FIX: don't fail when showing a Host overriding multiple inherited groups (#2253)
* FIX: deal with inherited values which are invalid for a select box (#2288)
* FIX: Service Set preview inline Service Template links (#2334)
* FIX: show Services applied with Rules involving applied Hostgroups (#2313)
* FIX: show "deactivated" services as such also for read-only users (#2344)
* FIX: Overrides for Services belonging to Sets on root Host Templates (#2333)
* FIX: show no header tabs for search result in web 2.8+ (#2141)
* FIX: show and link dependencies for web 2.9+ (#2354)
### Icinga Configuration
* FIX: rare race condition, where generated config might miss some files (#2351)
### Icinga API
* FIX: use Icinga 2's generate-ticket API, required for v2.13.0 (#2348)
### Import and Sync
* FIX: Purge didn't remove more than 1000 services at once (#2339)
### Automation, User Interface
* FIX: error message wording on failing related (or parent) object ref (#2224)
### REST API
* FIX: creating scheduled downtime via api failed (#1879)
1.8.0
-----
@ -87,6 +609,7 @@ before switching to a new version.
### Icinga Agent handling
* FIX: Linux Agent installer now fails when unable to retrieve a certificate
* FEATURE: Linux Agent installer now supports Alpine Linux (#2216)
* FEATURE: Icinga for Windows support (#2147)
### REST API
* FEATURE: Self Service API ignores empty/missing properties (e.g. no address)

View File

@ -12,16 +12,12 @@ there is probably already someone running them from time to time. So, just
lean back with full trust in our development toolchain and spend your time
elsewhere ;-) Cheers!
### Tests on Travis-CI
### Tests on GitHub
When pushing to [GitHub](https://github.com/Icinga/icingaweb2-module-director/)
or sending pull requests, Unit-Tests are automatically triggered on
[Travis-CI](https://travis-ci.org/Icinga/icingaweb2-module-director):
or sending pull requests, Unit-Tests are automatically triggered.
[![Build Status](https://travis-ci.org/Icinga/icingaweb2-module-director.svg?branch=master)](https://travis-ci.org/Icinga/icingaweb2-module-director)
We run our tests against MySQL and PostgreSQL, with PHP versions ranging from
5.3 to 7.1, including nightly builds.
![Build Status](https://github.com/Icinga/icingaweb2-module-director/workflows/PHP%20Tests/badge.svg?branch=master)
### Tests for supported Platforms

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@ -56,7 +56,7 @@ class Acl
public function listRoleNames()
{
return array_map(
array($this, 'getNameForRole'),
[$this, 'getNameForRole'],
$this->getUser()->getRoles()
);
}

View File

@ -0,0 +1,113 @@
<?php
namespace Icinga\Module\Director\Application;
class Dependency
{
/** @var string */
protected $name;
/** @var string|null */
protected $installedVersion;
/** @var bool|null */
protected $enabled;
/** @var string */
protected $operator;
/** @var string */
protected $requiredVersion;
/** @var string */
protected $requirement;
/**
* Dependency constructor.
* @param string $name Usually a module name
* @param string $requirement e.g. >=1.7.0
* @param string $installedVersion
* @param bool $enabled
*/
public function __construct($name, $requirement, $installedVersion = null, $enabled = null)
{
$this->name = $name;
$this->setRequirement($requirement);
if ($installedVersion !== null) {
$this->setInstalledVersion($installedVersion);
}
if ($enabled !== null) {
$this->setEnabled($enabled);
}
}
public function setRequirement($requirement)
{
if (preg_match('/^([<>=]+)\s*v?(\d+\.\d+\.\d+)$/', $requirement, $match)) {
$this->operator = $match[1];
$this->requiredVersion = $match[2];
$this->requirement = $requirement;
} else {
throw new \InvalidArgumentException("'$requirement' is not a valid version constraint");
}
}
/**
* @return bool
*/
public function isInstalled()
{
return $this->installedVersion !== null;
}
/**
* @return string|null
*/
public function getInstalledVersion()
{
return $this->installedVersion;
}
/**
* @param string $version
*/
public function setInstalledVersion($version)
{
$this->installedVersion = ltrim($version, 'v'); // v0.6.0 VS 0.6.0
}
/**
* @return bool
*/
public function isEnabled()
{
return $this->enabled === true;
}
/**
* @param bool $enabled
*/
public function setEnabled($enabled = true)
{
$this->enabled = $enabled;
}
public function isSatisfied()
{
if (! $this->isInstalled() || ! $this->isEnabled()) {
return false;
}
return version_compare($this->installedVersion, $this->requiredVersion, $this->operator);
}
public function getName()
{
return $this->name;
}
public function getRequirement()
{
return $this->requirement;
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace Icinga\Module\Director\Application;
use Icinga\Application\ApplicationBootstrap;
use Icinga\Application\Modules\Module;
use Icinga\Application\Version;
class DependencyChecker
{
/** @var ApplicationBootstrap */
protected $app;
/** @var \Icinga\Application\Modules\Manager */
protected $modules;
public function __construct(ApplicationBootstrap $app)
{
$this->app = $app;
$this->modules = $app->getModuleManager();
}
/**
* @param Module $module
* @return Dependency[]
*/
public function getDependencies(Module $module)
{
$dependencies = [];
$isV290 = version_compare(Version::VERSION, '2.9.0', '>=');
foreach ($module->getDependencies() as $moduleName => $required) {
if ($isV290 && in_array($moduleName, ['ipl', 'reactbundle'], true)) {
continue;
}
$dependency = new Dependency($moduleName, $required);
$dependency->setEnabled($this->modules->hasEnabled($moduleName));
if ($this->modules->hasInstalled($moduleName)) {
$dependency->setInstalledVersion($this->modules->getModule($moduleName, false)->getVersion());
}
$dependencies[] = $dependency;
}
if ($isV290) {
$libs = $this->app->getLibraries();
foreach ($module->getRequiredLibraries() as $libraryName => $required) {
$dependency = new Dependency($libraryName, $required);
if ($libs->has($libraryName)) {
$dependency->setInstalledVersion($libs->get($libraryName)->getVersion());
$dependency->setEnabled();
}
$dependencies[] = $dependency;
}
}
return $dependencies;
}
// if (version_compare(Version::VERSION, '2.9.0', 'ge')) {
// }
/**
* @param Module $module
* @return bool
*/
public function satisfiesDependencies(Module $module)
{
foreach ($this->getDependencies($module) as $dependency) {
if (! $dependency->isSatisfied()) {
return false;
}
}
return true;
}
}

View File

@ -35,19 +35,20 @@ class MemoryLimit
$val = trim($string);
if (preg_match('/^(\d+)([KMG])$/', $val, $m)) {
$val = $m[1];
$val = (int) $m[1];
switch ($m[2]) {
case 'G':
$val *= 1024;
// Intentional fall-through
// no break
case 'M':
$val *= 1024;
// Intentional fall-through
// no break
case 'K':
$val *= 1024;
}
}
return intval($val);
return (int) $val;
}
}

View File

@ -0,0 +1,36 @@
<?php
namespace Icinga\Module\Director\Auth;
use Icinga\Authentication\Auth;
use Icinga\Data\Filter\Filter;
class MonitoringRestriction
{
public static function getObjectsFilter(Auth $auth): Filter
{
$restriction = Filter::matchAny();
$restriction->setAllowedFilterColumns([
'host_name',
'hostgroup_name',
'instance_name',
'service_description',
'servicegroup_name',
function ($c) {
return preg_match('/^_(?:host|service)_/i', $c);
}
]);
foreach ($auth->getRestrictions(Restriction::MONITORING_RW_OBJECT_FILTER) as $filter) {
if ($filter === '*') {
return Filter::matchAll();
}
$restriction->addFilter(Filter::fromQueryString($filter));
}
if ($restriction->isEmpty()) {
return Filter::matchAll();
}
return $restriction;
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Icinga\Module\Director\Auth;
class Permission
{
public const ALL_PERMISSIONS = 'director/*';
public const ADMIN = 'director/admin'; // internal, assign ALL_PERMISSONS
public const API = 'director/api';
public const AUDIT = 'director/audit';
public const DEPLOY = 'director/deploy';
public const DEPLOYMENTS = 'director/deployments'; // internal, assign ALL_PERMISSONS
public const GROUPS_FOR_RESTRICTED_HOSTS = 'director/groups-for-restricted-hosts';
public const HOSTS = 'director/hosts';
public const HOST_GROUPS = 'director/hostgroups'; // internal, assign ALL_PERMISSIONS
public const INSPECT = 'director/inspect';
public const MONITORING_SERVICES_RO = 'director/monitoring/services-ro';
public const MONITORING_SERVICES = 'director/monitoring/services';
public const MONITORING_HOSTS = 'director/monitoring/hosts';
public const ICINGADB_SERVICES_RO = 'director/icingadb/services-ro';
public const ICINGADB_SERVICES = 'director/icingadb/services';
public const ICINGADB_HOSTS = 'director/icingadb/hosts';
public const NOTIFICATIONS = 'director/notifications';
public const SCHEDULED_DOWNTIMES = 'director/scheduled-downtimes';
public const SERVICES = 'director/services';
public const SERVICE_SETS = 'director/servicesets';
public const SERVICE_SET_APPLY = 'director/service_set/apply';
public const SHOW_CONFIG = 'director/showconfig';
public const SHOW_SQL = 'director/showsql';
public const USERS = 'director/users';
}

View File

@ -0,0 +1,17 @@
<?php
namespace Icinga\Module\Director\Auth;
class Restriction
{
public const MONITORING_RW_OBJECT_FILTER = 'director/monitoring/rw-object-filter';
public const ICINGADB_RW_OBJECT_FILTER = 'director/icingadb/rw-object-filter';
public const FILTER_HOSTGROUPS = 'director/filter/hostgroups';
// Hint: by-name-Filters are being fetched with variable names, like "director/$type/apply/filter-by-name"
public const NOTIFICATION_APPLY_FILTER_BY_NAME = 'director/notification/apply/filter-by-name';
public const SCHEDULED_DOWNTIME_APPLY_FILTER_BY_NAME = 'director/scheduled-downtime/apply/filter-by-name';
public const SERVICE_APPLY_FILTER_BY_NAME = 'director/service/apply/filter-by-name';
public const SERVICE_SET_FILTER_BY_NAME = 'director/service_set/filter-by-name';
public const DB_RESOURCE = 'director/db_resource';
}

View File

@ -2,11 +2,12 @@
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;
@ -21,7 +22,7 @@ class Command extends CliCommand
protected function renderJson($object, $pretty = true)
{
return json_encode($object, $pretty ? JSON_PRETTY_PRINT : null) . "\n";
return JsonString::encode($object, $pretty ? JSON_PRETTY_PRINT : null) . "\n";
}
/**
@ -30,15 +31,17 @@ class Command extends CliCommand
*/
protected function parseJson($json)
{
$res = json_decode($json);
if ($res === null) {
$this->fail('Invalid JSON: %s', $this->getLastJsonError());
try {
return JsonString::decode($json);
} catch (JsonDecodeException $e) {
$this->fail('Invalid JSON: %s', $e->getMessage());
}
return $res;
}
/**
* @param string $msg
* @return never-return
*/
public function fail($msg)
{
$args = func_get_args();
@ -46,16 +49,8 @@ class Command extends CliCommand
if (count($args)) {
$msg = vsprintf($msg, $args);
}
throw new RuntimeException($msg);
}
/**
* @return string
*/
protected function getLastJsonError()
{
return JsonException::getJsonErrorMessage(json_last_error());
echo $this->screen->colorize("ERROR", 'red') . ": $msg\n";
exit(1);
}
/**
@ -87,9 +82,9 @@ class Command extends CliCommand
{
MemoryLimit::raiseTo('1024M');
ini_set('max_execution_time', 0);
ini_set('max_execution_time', '0');
if (version_compare(PHP_VERSION, '7.0.0') < 0) {
ini_set('zend.enable_gc', 0);
ini_set('zend.enable_gc', '0');
}
return $this;

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