cmdbsyncer 4.2.4__tar.gz → 4.2.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cmdbsyncer-4.2.4/cmdbsyncer.egg-info → cmdbsyncer-4.2.6}/PKG-INFO +1 -1
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/__init__.py +6 -0
- cmdbsyncer-4.2.6/application/buildinfo.txt +1 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v4.2.md +34 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/host.py +6 -0
- cmdbsyncer-4.2.6/application/models/project.py +34 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/plugin.py +29 -14
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/rule/rule.py +50 -9
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/rule/views.py +32 -7
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/__init__.py +12 -8
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/admin_views.py +0 -11
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/cmk_rules.py +4 -4
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/downtimes.py +52 -19
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/helpers.py +20 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/inits.py +21 -11
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/models.py +2 -21
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/syncer.py +33 -1
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_cmk_rules.py +59 -8
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_downtimes.py +53 -17
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_syncer.py +25 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/views.py +9 -286
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/export.py +8 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/maintenance/__init__.py +30 -0
- cmdbsyncer-4.2.6/application/templates/admin/assign_project_form.html +33 -0
- cmdbsyncer-4.2.4/application/templates/admin/checkmk_rule_project_edit.html → cmdbsyncer-4.2.6/application/templates/admin/project_edit.html +1 -1
- cmdbsyncer-4.2.4/application/templates/admin/checkmk_rule_project_import.html → cmdbsyncer-4.2.6/application/templates/admin/project_import.html +2 -2
- cmdbsyncer-4.2.4/application/templates/admin/checkmk_rule_project_list.html → cmdbsyncer-4.2.6/application/templates/admin/project_list.html +2 -2
- cmdbsyncer-4.2.4/application/templates/admin/checkmk_rule_project_overview.html → cmdbsyncer-4.2.6/application/templates/admin/project_overview.html +1 -1
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/_form_sections.py +21 -8
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/host.py +76 -1
- cmdbsyncer-4.2.6/application/views/project.py +355 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6/cmdbsyncer.egg-info}/PKG-INFO +1 -1
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/cmdbsyncer.egg-info/SOURCES.txt +8 -5
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/pyproject.toml +1 -1
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_api.py +5 -2
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_plugin.py +39 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_rule.py +47 -0
- cmdbsyncer-4.2.4/application/buildinfo.txt +0 -1
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/LICENSE +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/README.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/_version.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/api/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/api/inventory.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/api/objects.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/api/rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/api/syncer.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/api/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/auth/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/.pages +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v3.10.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v3.11.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v3.12.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v3.5.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v3.7.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v3.8.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v3.9.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v4.0.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/changelog/v4.1.md +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/cli.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/config.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/docu_links.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/enterprise.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/audit.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/cron.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/get_account.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/inventory.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/local_config_file.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/local_config_presets.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/mongo_keys.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/notification_channels.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/notification_dispatch.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/plugins.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/sates.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/sql.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/syncer_jinja.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/tablib_formater.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/tests/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/helpers/tests/test_sql.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/mcp_server.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/account.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/config.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/cron.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/field_approval.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/forms.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/host_inventory_tree.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/notification_channel.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/notification_rule.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/notification_state.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/saved_search.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/states.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/models/user.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/custom_attributes/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/custom_attributes/rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/custom_attributes/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/debug.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/email.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/inventory/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/log/log.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/log/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/log/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/rule/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/rule/filter.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/rule/match.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/rule/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/rule/rewrite.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/search_parser.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/modules/statefile.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/notices/strict_certificate_verification.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/admin_views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/inventory.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/playbook_rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/runner.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/seed.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/site_syncer.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ansible/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/bmc_remedy/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/bmc_remedy/bmc_remedy.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/bmc_remedy/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/bi.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/cmk2.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/dcd.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/groups.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/import_v1.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/import_v2.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/inventorize.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/notification_rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/passwords.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/poolfolder.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/rule_passwords.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/sites.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tags.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_bi.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_cmk2.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_dcd.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_groups.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_helpers.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_import_v1.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_import_v2.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_inventorize.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_notification_rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_passwords.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_poolfolder.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_rule_passwords.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_sites.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_tags.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/tests/test_users.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/checkmk/users.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/cisco_dna/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/cisco_dna/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/cisco_dna/syncer.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/cron.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/csv/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/csv/csv.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/csv/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/file_requests.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/idoit/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/idoit/admin_views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/idoit/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/idoit/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/idoit/rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/idoit/syncer.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/idoit/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jdisc/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jdisc/applications.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jdisc/devices.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jdisc/executables.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jdisc/jdisc.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jdisc/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira/jira.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/admin_views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/jira_cloud.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/schema_sync.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/jira_cloud/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/json/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/json/json.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/json/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ldap/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ldap/ldap.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/ldap/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/maintenance/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/mssql/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/mssql/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/mysql/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/mysql/mysql.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/mysql/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/admin_views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/cluster.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/contacts.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/dataflow.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/devices.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/interfaces.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/ips.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/netbox.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/networks.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/prefixes.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/tests/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/tests/test_import_filter.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/utils.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/netbox/virtualmachines.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/prtg/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/prtg/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/prtg/prtg.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/pyodbc/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/pyodbc/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/pyodbc/pyodbc.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rest/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rest/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rest/rest.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rules/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rules/admin_views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rules/autorules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rules/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rules/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rules/rule_definitions.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rules/rule_import_export.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/rules/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/syncer_shell.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/vmware/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/vmware/admin_views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/vmware/custom_attributes.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/vmware/models.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/vmware/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/vmware/rules.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/vmware/views.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/vmware/vmware.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/yml/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/yml/plugin.json +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins/yml/yml.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/plugins_cli.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/static/cmdbsyncer_mark.png +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/static/css/cmdbsyncer.css +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/static/favicon.png +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/static/js/main.js +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/static/logo_white.png +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/_brand.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/_theme.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/_host_tabs.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/account_pick_type.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/ansible_playbook_run.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/ansible_project_detail.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/ansible_rule_list.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/ansible_run_details.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/bulk_label_form.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/changelog_archive.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/checkmk_rule_mngmt_list.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/checkmk_settings_list.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/checkmk_test_folder_scope.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/copy_as_new_form.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/data_quality.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/file/list.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/file/modals/form.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/host_details.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/host_edit.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/host_inventory_tree.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/host_list.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/host_relations_graph.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/host_timeline.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/index.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/local_config_editor.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/master.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/model/clone_confirm.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/model/inline_list_base.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/object_list.html +0 -0
- /cmdbsyncer-4.2.4/application/templates/admin/checkmk_rule_project_import_cmk.html → /cmdbsyncer-4.2.6/application/templates/admin/project_import_cmk.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/set_cmk_version_form.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/admin/set_template_form.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/base.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/change_password.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/debug.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/debug_host.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/email/newuser.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/email/notification.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/email/resetpassword.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/formular.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/license_info.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/login.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/logout_confirm.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/request_password.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/set_2fa.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/templates/set_theme.html +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/themes/dracula.css +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/themes/gruvbox-dark.css +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/themes/gruvbox-light.css +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/themes/nord.css +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/themes_registry.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/_form_fields.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/account.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/config.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/cron.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/data_quality.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/default.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/field_approval.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/fileadmin.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/host_filters.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/host_renderers.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/host_widgets.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/license.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/notification_channel.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/notification_rule.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/saved_search.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/application/views/user.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/cmdbsyncer.egg-info/dependency_links.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/cmdbsyncer.egg-info/entry_points.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/cmdbsyncer.egg-info/requires.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/cmdbsyncer.egg-info/top_level.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/requirements-ansible-windows.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/requirements-ansible.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/requirements-extras.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/requirements.txt +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/setup.cfg +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/syncerapi/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/syncerapi/v1/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/syncerapi/v1/core/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/syncerapi/v1/inventory/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/syncerapi/v1/rest/__init__.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_account_macro.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_api_csrf_invariant.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_default_view.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_mongo_keys.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_plugin_ssti.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_plugins_cli.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_rule_filename_detect.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_rule_match.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_search_parser.py +0 -0
- {cmdbsyncer-4.2.4 → cmdbsyncer-4.2.6}/tests/test_webhook_token_hash.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmdbsyncer
|
|
3
|
-
Version: 4.2.
|
|
3
|
+
Version: 4.2.6
|
|
4
4
|
Summary: Rule-based modular synchronizer for Checkmk, Netbox, Ansible, I-DOIT, Jira CMDB and 15+ other CMDB/monitoring systems
|
|
5
5
|
Author-email: Kuhn & Ruess GmbH <info@kuhn-ruess.de>
|
|
6
6
|
Maintainer-email: Bastian Kuhn <mail@bastian-kuhn.de>
|
|
@@ -522,6 +522,12 @@ def _register_web_layer(): # pylint: disable=too-many-locals,too-many-statement
|
|
|
522
522
|
category="Modules",
|
|
523
523
|
menu_icon_type='fa', menu_icon_value='fa-cog'))
|
|
524
524
|
#.
|
|
525
|
+
# .-- Projects
|
|
526
|
+
from application.models.project import Project
|
|
527
|
+
from application.views.project import ProjectView
|
|
528
|
+
admin.add_view(ProjectView(Project, name="Projects",
|
|
529
|
+
menu_icon_type='fa', menu_icon_value='fa-cubes'))
|
|
530
|
+
#.
|
|
525
531
|
|
|
526
532
|
_register_all_plugin_admin_views(admin)
|
|
527
533
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
BUILD_DATE=2026-07-16T14:47:35Z
|
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Version 4.2
|
|
2
2
|
|
|
3
|
+
## Version 4.2.6
|
|
4
|
+
|
|
5
|
+
### Projects
|
|
6
|
+
- FEAT: Projects have their own top-level menu entry next to Modules; run `./cmdbsyncer sys self_configure` once after the update so existing projects appear there
|
|
7
|
+
- FEAT: Projects can exclude accounts — the project's members are never exported to the listed accounts, and the exclusion wins over "Exported to Accounts"
|
|
8
|
+
- FEAT: Hosts can be assigned to a Project (host edit form or "Assign Project" bulk action in the host list) — the Checkmk host export then only pushes them to the accounts the project's account filter allows; the assignment never converts an imported host into a CMDB object
|
|
9
|
+
|
|
10
|
+
### Checkmk
|
|
11
|
+
- FIX: Checkmk Setup/DCD rule exports cache rule results per account, so project rules are no longer served from another account's cached outcomes — previously the first exporting account decided which project rules everyone else got
|
|
12
|
+
- FIX: Opening the host debug page no longer overwrites the cached rule results used by the Checkmk rule export, and its Setup Rules table now shows on every visit instead of only the first
|
|
13
|
+
- FIX: Editing, renaming or deleting a Checkmk Rule Project takes effect on the next export — renames keep the assigned rules attached, and filter changes clear the hosts' cached rule results
|
|
14
|
+
- FIX: Importing a Rule Project from JSON keeps its account filter — imported projects no longer silently export to all accounts
|
|
15
|
+
|
|
16
|
+
### Interface
|
|
17
|
+
- FIX: The section cards of the modern rule edit forms (e.g. DCD rules: header bars and nested outcome/condition cards) follow the active theme instead of showing hardcoded light backgrounds on the dark themes
|
|
18
|
+
|
|
19
|
+
### Rules
|
|
20
|
+
- FIX: Editing or deleting a rule now clears the hosts' cached rule results, so exports pick up rule changes immediately instead of using outcomes cached before the edit
|
|
21
|
+
- FIX: `--debug-rules` shows the rule evaluation on every run — an existing rule cache no longer silences the output
|
|
22
|
+
- FEAT: `--debug-rules` shows the deciding condition per rule — which condition failed on a miss, which one matched on a hit
|
|
23
|
+
- FIX: Rule list views no longer crash when a condition was created without negate flags (e.g. programmatically or via JSON import)
|
|
24
|
+
|
|
25
|
+
## Version 4.2.5
|
|
26
|
+
|
|
27
|
+
### Setup
|
|
28
|
+
- FEAT: An account can override the global HTTP request timeout with a `request_timeout` custom field (value in seconds) — useful for slow target systems such as large distributed Checkmk setups, where downtime operations can take longer than the default 30 seconds
|
|
29
|
+
|
|
30
|
+
### Checkmk
|
|
31
|
+
- FIX: Downtime export is much faster on large inventories — it now reads all existing Checkmk downtimes in a single query instead of one per host, so runs that previously appeared to hang for minutes (one livestatus round-trip per matching host) finish quickly
|
|
32
|
+
- FEAT: Downtime export ends with a status line showing how many downtimes were created, how many already existed in Checkmk and how many failed — a run where everything already exists no longer ends silently; the counts are also recorded in the run's log entry
|
|
33
|
+
|
|
3
34
|
## Version 4.2.4
|
|
4
35
|
|
|
5
36
|
### Checkmk
|
|
@@ -14,6 +45,9 @@
|
|
|
14
45
|
### Netbox
|
|
15
46
|
- FEAT: Netbox can now import interfaces of devices and virtual machines (analogous to the device and VM import) — each host's Netbox interfaces, including their assigned IP addresses, are stored on the host's inventory; with the account option `import_as_hosts` every interface is instead imported as its own host so it can be exported again
|
|
16
47
|
|
|
48
|
+
### Jira
|
|
49
|
+
- FEAT: `jira export_cloud --debug` now prints, per object, which fields it changes and their old and new value — so an object that keeps updating on every run (even with `--dry-run`) can be traced to the exact field responsible
|
|
50
|
+
|
|
17
51
|
### Interface
|
|
18
52
|
- FIX: Rule forms render fully theme-aware on the dark themes (Gruvbox, Dracula, Nord) — the nested outcome/condition field groups and their "Add …" buttons no longer show a hard-coded white/light background; nested cards, `bg-light`/`bg-white` utilities and the inline "Add" buttons now follow the active theme's surface colours everywhere
|
|
19
53
|
|
|
@@ -142,6 +142,12 @@ class Host(db.Document):
|
|
|
142
142
|
|
|
143
143
|
folder = db.StringField() # Is just Checkmk related, better solution needed
|
|
144
144
|
|
|
145
|
+
# Name of the Project this host belongs to (optional). Exports that
|
|
146
|
+
# honour projects (currently the Checkmk host export) only push the
|
|
147
|
+
# host to accounts the project's account filter allows — same scope
|
|
148
|
+
# as the project's rules.
|
|
149
|
+
project = db.StringField()
|
|
150
|
+
|
|
145
151
|
log = db.ListField(field=db.StringField())
|
|
146
152
|
|
|
147
153
|
cache = db.DictField()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project
|
|
3
|
+
"""
|
|
4
|
+
# pylint: disable=too-few-public-methods
|
|
5
|
+
from application import db
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Project(db.Document):
|
|
9
|
+
"""
|
|
10
|
+
Groups syncer objects (currently Checkmk Setup Rules, DCD rules and
|
|
11
|
+
hosts — more may follow) and limits which accounts they are exported
|
|
12
|
+
to. ``limit_by_accounts`` restricts the project's members to the
|
|
13
|
+
listed accounts; an empty list means no restriction.
|
|
14
|
+
``deny_by_accounts`` excludes accounts and wins over the allow list.
|
|
15
|
+
|
|
16
|
+
The account-scope decision itself lives with the consumers (see
|
|
17
|
+
``application.plugins.checkmk.helpers.project_allows_account``) —
|
|
18
|
+
this document only carries the data.
|
|
19
|
+
"""
|
|
20
|
+
name = db.StringField(required=True, unique=True)
|
|
21
|
+
documentation = db.StringField()
|
|
22
|
+
|
|
23
|
+
# Names of the accounts this project's members may be exported to.
|
|
24
|
+
# Empty = no restriction (all accounts). Stored by name to survive
|
|
25
|
+
# JSON im-/export between separate syncer instances.
|
|
26
|
+
limit_by_accounts = db.ListField(field=db.StringField())
|
|
27
|
+
|
|
28
|
+
# Names of the accounts this project's members are never exported to.
|
|
29
|
+
# The deny list wins over ``limit_by_accounts``.
|
|
30
|
+
deny_by_accounts = db.ListField(field=db.StringField())
|
|
31
|
+
|
|
32
|
+
meta = {
|
|
33
|
+
'strict': False,
|
|
34
|
+
}
|
|
@@ -305,9 +305,22 @@ class Plugin():
|
|
|
305
305
|
logger.debug(f"Request ({method.upper()}) to {url}")
|
|
306
306
|
|
|
307
307
|
method = method.lower()
|
|
308
|
+
timeout = app.config['HTTP_REQUEST_TIMEOUT']
|
|
309
|
+
# Per-account override: a `request_timeout` custom field on the
|
|
310
|
+
# account wins over the global HTTP_REQUEST_TIMEOUT. Slow target
|
|
311
|
+
# systems (e.g. large distributed Checkmk setups, where every
|
|
312
|
+
# downtime read/write fans out to all sites) need more than the
|
|
313
|
+
# default 30 seconds without raising it deployment-wide.
|
|
314
|
+
if account_timeout := self.config.get('request_timeout'):
|
|
315
|
+
try:
|
|
316
|
+
timeout = float(account_timeout)
|
|
317
|
+
except (TypeError, ValueError):
|
|
318
|
+
logger.warning(
|
|
319
|
+
f"Ignoring invalid request_timeout {account_timeout!r} "
|
|
320
|
+
f"on account {self.config.get('name')!r}")
|
|
308
321
|
payload = {
|
|
309
322
|
'verify': self.verify,
|
|
310
|
-
'timeout':
|
|
323
|
+
'timeout': timeout,
|
|
311
324
|
}
|
|
312
325
|
|
|
313
326
|
if headers:
|
|
@@ -524,21 +537,21 @@ class Plugin():
|
|
|
524
537
|
return self.actions.get_outcomes(db_host, attributes)
|
|
525
538
|
#.
|
|
526
539
|
|
|
527
|
-
def debug_rules(self, hostname,
|
|
540
|
+
def debug_rules(self, hostname, _model=None):
|
|
528
541
|
"""
|
|
529
542
|
Debug mode for inspecting rule outcomes on a specific host.
|
|
530
|
-
|
|
543
|
+
|
|
531
544
|
This method is used with the --debug-rules command line switch to
|
|
532
|
-
analyze how rules are applied to a specific host. It clears
|
|
533
|
-
|
|
534
|
-
|
|
545
|
+
analyze how rules are applied to a specific host. It clears the
|
|
546
|
+
host's cache and shows detailed rule processing information.
|
|
547
|
+
|
|
535
548
|
Args:
|
|
536
549
|
hostname (str): Hostname to debug
|
|
537
|
-
|
|
538
|
-
|
|
550
|
+
_model (str): Unused, kept for caller compatibility
|
|
551
|
+
|
|
539
552
|
Returns:
|
|
540
553
|
None: Prints debug information to console
|
|
541
|
-
|
|
554
|
+
|
|
542
555
|
Note:
|
|
543
556
|
This method prints directly to console and is intended for
|
|
544
557
|
interactive debugging sessions.
|
|
@@ -551,11 +564,13 @@ class Plugin():
|
|
|
551
564
|
}
|
|
552
565
|
try:
|
|
553
566
|
db_host = Host.objects.get(hostname=hostname)
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
567
|
+
# Clear the host's whole cache. Outcome caches use heterogeneous
|
|
568
|
+
# keys (e.g. 'ExportDowntimes', qualname-based keys), so the old
|
|
569
|
+
# model-prefix filter missed them (and compared a lowercased key
|
|
570
|
+
# against a capitalized prefix). get_outcomes() then returned the
|
|
571
|
+
# cached result before any debug table was rendered — the debug
|
|
572
|
+
# run silently printed nothing.
|
|
573
|
+
db_host.cache = {}
|
|
559
574
|
db_host.save()
|
|
560
575
|
except DoesNotExist:
|
|
561
576
|
print(f"{cc.FAIL}Host not Found{cc.ENDC}")
|
|
@@ -23,6 +23,25 @@ _RULE_DESCRIPTIONS = {
|
|
|
23
23
|
'anyway': "ALWAYS match",
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
|
|
27
|
+
def format_condition(condition):
|
|
28
|
+
"""
|
|
29
|
+
Compact one-line rendering of a FullCondition dict for debug output,
|
|
30
|
+
so the deciding condition of a rule match/miss is readable in a table.
|
|
31
|
+
"""
|
|
32
|
+
if not condition:
|
|
33
|
+
return ''
|
|
34
|
+
if condition.get('match_type') == 'tag':
|
|
35
|
+
tag_negate = ' negated' if condition.get('tag_match_negate') else ''
|
|
36
|
+
value_negate = ' negated' if condition.get('value_match_negate') else ''
|
|
37
|
+
return (f"tag {condition.get('tag_match')}{tag_negate} "
|
|
38
|
+
f"'{condition.get('tag')}', "
|
|
39
|
+
f"value {condition.get('value_match')}{value_negate} "
|
|
40
|
+
f"'{condition.get('value', '')}'")
|
|
41
|
+
hostname_negate = ' negated' if condition.get('hostname_match_negate') else ''
|
|
42
|
+
return (f"hostname {condition.get('hostname_match')}{hostname_negate} "
|
|
43
|
+
f"'{condition.get('hostname', '')}'")
|
|
44
|
+
|
|
26
45
|
class Rule():
|
|
27
46
|
"""
|
|
28
47
|
Base Rule Class
|
|
@@ -233,12 +252,13 @@ class Rule():
|
|
|
233
252
|
|
|
234
253
|
table = Table(title=title, box=box.ASCII_DOUBLE_HEAD,\
|
|
235
254
|
header_style="bold blue", title_style="yellow", \
|
|
236
|
-
title_justify="left", width=
|
|
255
|
+
title_justify="left", width=130)
|
|
237
256
|
table.add_column("Hit")
|
|
238
257
|
table.add_column("Description")
|
|
239
258
|
table.add_column("Rule Name")
|
|
240
259
|
table.add_column("Rule ID")
|
|
241
260
|
table.add_column("Last Match")
|
|
261
|
+
table.add_column("Deciding Condition")
|
|
242
262
|
|
|
243
263
|
outcomes = {}
|
|
244
264
|
rule_objs, prepared_rules = self._iter_rule_docs()
|
|
@@ -293,8 +313,20 @@ class Rule():
|
|
|
293
313
|
"last_match": str(rule['last_match']),
|
|
294
314
|
}
|
|
295
315
|
self.debug_lines.append(debug_data)
|
|
316
|
+
# Show WHY the rule hit or missed: for 'all' rules the first
|
|
317
|
+
# failing condition, for 'any' rules the matching one (on a
|
|
318
|
+
# miss, the last condition checked — all of them failed).
|
|
319
|
+
if rule_hit:
|
|
320
|
+
deciding = format_condition(match_reason)
|
|
321
|
+
if deciding:
|
|
322
|
+
deciding = f"matched: {deciding}"
|
|
323
|
+
else:
|
|
324
|
+
deciding = format_condition(no_match_reason)
|
|
325
|
+
if deciding:
|
|
326
|
+
deciding = f"failed: {deciding}"
|
|
296
327
|
table.add_row(str(rule_hit), _RULE_DESCRIPTIONS[condition_typ],\
|
|
297
|
-
rule['name'][:30], str(rule['_id']), str(rule['last_match'])
|
|
328
|
+
rule['name'][:30], str(rule['_id']), str(rule['last_match']),
|
|
329
|
+
deciding)
|
|
298
330
|
if rule_hit:
|
|
299
331
|
# outcomes were pre-converted to plain dicts in
|
|
300
332
|
# _iter_rule_docs so we don't rebuild them per host.
|
|
@@ -408,12 +440,20 @@ class Rule():
|
|
|
408
440
|
return self.check_rules(db_host.hostname)
|
|
409
441
|
|
|
410
442
|
|
|
411
|
-
def get_outcomes(self, db_host, attributes, persist_cache=True
|
|
443
|
+
def get_outcomes(self, db_host, attributes, persist_cache=True,
|
|
444
|
+
use_cache=True):
|
|
412
445
|
"""
|
|
413
446
|
Handle Return of outcomes.
|
|
447
|
+
|
|
448
|
+
``use_cache=False`` bypasses the per-host outcome cache entirely
|
|
449
|
+
(neither read nor written). Debug evaluations need this: they run
|
|
450
|
+
with a different rule set than the exports (e.g. all Setup Rules
|
|
451
|
+
instead of the account's project scope) and must not poison the
|
|
452
|
+
export's cache slot — nor return a stale cached result instead of
|
|
453
|
+
producing debug lines.
|
|
414
454
|
"""
|
|
415
455
|
cache = self.cache_name or self._default_cache_key
|
|
416
|
-
if cache in db_host.cache:
|
|
456
|
+
if use_cache and cache in db_host.cache:
|
|
417
457
|
logger.debug("Using Rule Cache for %s", db_host.hostname)
|
|
418
458
|
return db_host.cache[cache]
|
|
419
459
|
|
|
@@ -421,9 +461,10 @@ class Rule():
|
|
|
421
461
|
self.hostname = db_host.hostname
|
|
422
462
|
self.db_host = db_host
|
|
423
463
|
rules = self.check_rule_match(db_host)
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
464
|
+
if use_cache:
|
|
465
|
+
db_host.cache[cache] = rules
|
|
466
|
+
if persist_cache:
|
|
467
|
+
db_host.save()
|
|
468
|
+
else:
|
|
469
|
+
setattr(db_host, '_cache_dirty', True)
|
|
429
470
|
return rules
|
|
@@ -18,6 +18,7 @@ from application.views.default import DefaultModelView
|
|
|
18
18
|
from application.modules.rule.models import filter_actions, rule_types, condition_types
|
|
19
19
|
from application.docu_links import docu_links
|
|
20
20
|
from application.helpers.sates import add_changes
|
|
21
|
+
from application.models.host import Host
|
|
21
22
|
from flask_admin.contrib.mongoengine.filters import BooleanEqualFilter, FilterLike
|
|
22
23
|
|
|
23
24
|
|
|
@@ -258,10 +259,28 @@ def _render_attribute_outcomes(_view, _context, model, _name):
|
|
|
258
259
|
return Markup(html)
|
|
259
260
|
|
|
260
261
|
|
|
262
|
+
def invalidate_host_rule_caches():
|
|
263
|
+
"""
|
|
264
|
+
Drop the per-host rule outcome caches after a rule was changed.
|
|
265
|
+
|
|
266
|
+
``db_host.cache`` is only reset when the host's own labels or inventory
|
|
267
|
+
change — a rule edit alone never touches it. Exports would keep using
|
|
268
|
+
the outcomes cached before the edit until every host happens to be
|
|
269
|
+
re-imported (reported from the field: a corrected downtime rule
|
|
270
|
+
exported nothing for most hosts). Outcome cache keys are heterogeneous
|
|
271
|
+
(e.g. 'ExportDowntimes', qualname-based keys), so a prefix-scoped clear
|
|
272
|
+
is not possible — drop the whole cache, the next run recomputes it.
|
|
273
|
+
"""
|
|
274
|
+
Host.objects(cache__ne={}).update(set__cache={})
|
|
275
|
+
|
|
276
|
+
|
|
261
277
|
def _render_full_conditions(_view, _context, model, _name):
|
|
262
278
|
"""
|
|
263
279
|
Render full condition set which contains host or labels
|
|
264
280
|
"""
|
|
281
|
+
# Rules created programmatically or via JSON import may carry None in
|
|
282
|
+
# the negate booleans or match-type fields — render them like their
|
|
283
|
+
# defaults instead of raising a KeyError that breaks the whole list view.
|
|
265
284
|
negate = {
|
|
266
285
|
True: 'not ',
|
|
267
286
|
False: ' ',
|
|
@@ -275,9 +294,9 @@ def _render_full_conditions(_view, _context, model, _name):
|
|
|
275
294
|
<h6 class="card-subtitle mb-2 text-muted">Hostname</h6>
|
|
276
295
|
<p class="card-text">
|
|
277
296
|
<span class="badge badge-primary">
|
|
278
|
-
{escape(negate[entry.hostname_match_negate])}
|
|
279
|
-
{escape(condition_types
|
|
280
|
-
<span class="badge badge-info">{escape(entry.hostname)}</span>
|
|
297
|
+
{escape(negate[bool(entry.hostname_match_negate)])}
|
|
298
|
+
{escape(condition_types.get(entry.hostname_match, ''))}</span>
|
|
299
|
+
<span class="badge badge-info">{escape(entry.hostname or '')}</span>
|
|
281
300
|
</p>
|
|
282
301
|
</div>
|
|
283
302
|
</div>
|
|
@@ -289,16 +308,18 @@ def _render_full_conditions(_view, _context, model, _name):
|
|
|
289
308
|
<h6 class="card-subtitle mb-2 text-muted">Key</h6>
|
|
290
309
|
<p class="card-text">
|
|
291
310
|
<span class="badge badge-primary">
|
|
292
|
-
{escape(negate[entry.tag_match_negate])}{escape(
|
|
311
|
+
{escape(negate[bool(entry.tag_match_negate)])}{escape(
|
|
312
|
+
condition_types.get(entry.tag_match, ''))}
|
|
293
313
|
</span>
|
|
294
|
-
<span class="badge badge-info">{escape(entry.tag)}</span>
|
|
314
|
+
<span class="badge badge-info">{escape(entry.tag or '')}</span>
|
|
295
315
|
</p>
|
|
296
316
|
<h6 class="card-subtitle mb-2 text-muted">Value</h6>
|
|
297
317
|
<p class="card-text">
|
|
298
318
|
<span class="badge badge-primary">
|
|
299
|
-
{escape(negate[entry.value_match_negate])} {escape(
|
|
319
|
+
{escape(negate[bool(entry.value_match_negate)])} {escape(
|
|
320
|
+
condition_types.get(entry.value_match, ''))}
|
|
300
321
|
</span>
|
|
301
|
-
<span class="badge badge-info">{escape(entry.value)}</span>
|
|
322
|
+
<span class="badge badge-info">{escape(entry.value or '')}</span>
|
|
302
323
|
</p>
|
|
303
324
|
</div>
|
|
304
325
|
</div>
|
|
@@ -448,6 +469,7 @@ class RuleModelView(DefaultModelView):
|
|
|
448
469
|
Overwrite Actions on Model Change
|
|
449
470
|
"""
|
|
450
471
|
add_changes()
|
|
472
|
+
invalidate_host_rule_caches()
|
|
451
473
|
|
|
452
474
|
try:
|
|
453
475
|
super().on_model_change(form, model, is_created)
|
|
@@ -460,6 +482,7 @@ class RuleModelView(DefaultModelView):
|
|
|
460
482
|
Overwrite Actions on Model Delete
|
|
461
483
|
"""
|
|
462
484
|
add_changes()
|
|
485
|
+
invalidate_host_rule_caches()
|
|
463
486
|
|
|
464
487
|
return super().on_model_delete(model)
|
|
465
488
|
|
|
@@ -586,6 +609,7 @@ class FiltereModelView(DefaultModelView):
|
|
|
586
609
|
Overwrite Actions on Model Change
|
|
587
610
|
"""
|
|
588
611
|
add_changes()
|
|
612
|
+
invalidate_host_rule_caches()
|
|
589
613
|
|
|
590
614
|
try:
|
|
591
615
|
super().on_model_change(form, model, is_created)
|
|
@@ -598,6 +622,7 @@ class FiltereModelView(DefaultModelView):
|
|
|
598
622
|
Overwrite Actions on Model Delete
|
|
599
623
|
"""
|
|
600
624
|
add_changes()
|
|
625
|
+
invalidate_host_rule_caches()
|
|
601
626
|
|
|
602
627
|
return super().on_model_delete(model)
|
|
603
628
|
|
|
@@ -209,11 +209,11 @@ def get_host_debug_data(hostname):
|
|
|
209
209
|
|
|
210
210
|
try:
|
|
211
211
|
db_host = Host.objects.get(hostname=hostname)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
# Clear the host's whole cache: outcome caches use heterogeneous
|
|
213
|
+
# keys (e.g. 'ExportDowntimes', 'cmk_tags_tag_choices', qualname
|
|
214
|
+
# based keys), so the old 'checkmk' prefix filter missed them and
|
|
215
|
+
# the debug run showed stale cached results for those engines.
|
|
216
|
+
db_host.cache = {}
|
|
217
217
|
db_host.save()
|
|
218
218
|
except DoesNotExist:
|
|
219
219
|
print(f"{ColorCodes.FAIL}Host not Found{ColorCodes.ENDC}")
|
|
@@ -248,7 +248,11 @@ def get_host_debug_data(hostname):
|
|
|
248
248
|
setup_rules = CheckmkRulesetRule()
|
|
249
249
|
setup_rules.debug = True
|
|
250
250
|
setup_rules.rules = CheckmkRuleMngmt.objects(enabled=True).order_by('sort_field')
|
|
251
|
-
|
|
251
|
+
# use_cache=False: the debug run evaluates all Setup Rules
|
|
252
|
+
# instead of the account's project scope and must neither
|
|
253
|
+
# poison the export's cache slot nor short-circuit on a
|
|
254
|
+
# cached result (which would leave the debug table empty).
|
|
255
|
+
setup_rules.get_outcomes(db_host, attributes['all'], use_cache=False)
|
|
252
256
|
rule_logs['Setup Rules'] = setup_rules.debug_lines
|
|
253
257
|
except Exception as exp: # pylint: disable=broad-exception-caught
|
|
254
258
|
rule_logs['Setup Rules'] = [{
|
|
@@ -432,13 +436,13 @@ def cli_export_rules(account, debug):
|
|
|
432
436
|
@click.option("--debug", is_flag=True)
|
|
433
437
|
def cli_import_project_rules(project, account, folder, recursive, debug):
|
|
434
438
|
"""
|
|
435
|
-
Import all Checkmk Setup Rules of a folder into a
|
|
439
|
+
Import all Checkmk Setup Rules of a folder into a Project
|
|
436
440
|
|
|
437
441
|
### Example
|
|
438
442
|
_./cmdbsyncer checkmk import_project_rules MYPROJECT SITEACCOUNT /server_
|
|
439
443
|
|
|
440
444
|
Args:
|
|
441
|
-
project (string): Name of the target
|
|
445
|
+
project (string): Name of the target Project
|
|
442
446
|
account (string): Checkmk account to read the rules from
|
|
443
447
|
folder (string): Checkmk folder to import rules from
|
|
444
448
|
"""
|
|
@@ -21,7 +21,6 @@ from .models import (
|
|
|
21
21
|
CheckmkRewriteAttributeRule,
|
|
22
22
|
CheckmkRule,
|
|
23
23
|
CheckmkRuleMngmt,
|
|
24
|
-
CheckmkRuleProject,
|
|
25
24
|
CheckmkSettings,
|
|
26
25
|
CheckmkSite,
|
|
27
26
|
CheckmkTagMngmt,
|
|
@@ -37,7 +36,6 @@ from .views import (
|
|
|
37
36
|
CheckmkFolderPoolView,
|
|
38
37
|
CheckmkInventorizeAttributesView,
|
|
39
38
|
CheckmkMngmtRuleView,
|
|
40
|
-
CheckmkRuleProjectView,
|
|
41
39
|
CheckmkNotificationRuleView,
|
|
42
40
|
CheckmkPasswordView,
|
|
43
41
|
CheckmkRuleView,
|
|
@@ -108,15 +106,6 @@ def register_admin_views(admin):
|
|
|
108
106
|
menu_icon_value='fa-cogs',
|
|
109
107
|
)
|
|
110
108
|
)
|
|
111
|
-
admin.add_view(
|
|
112
|
-
CheckmkRuleProjectView(
|
|
113
|
-
CheckmkRuleProject,
|
|
114
|
-
name="Setup Rule Projects",
|
|
115
|
-
category="Checkmk",
|
|
116
|
-
menu_icon_type='fa',
|
|
117
|
-
menu_icon_value='fa-cubes',
|
|
118
|
-
)
|
|
119
|
-
)
|
|
120
109
|
admin.add_view(
|
|
121
110
|
CheckmkTagMngmtView(
|
|
122
111
|
CheckmkTagMngmt,
|
|
@@ -627,10 +627,10 @@ class CheckmkRuleSync(CMK2):
|
|
|
627
627
|
# Host-independent rules, wired in by inits.export_rules. Evaluated
|
|
628
628
|
# once in calculate_static_rules instead of per host.
|
|
629
629
|
self.static_rules = []
|
|
630
|
-
#
|
|
631
|
-
#
|
|
632
|
-
#
|
|
633
|
-
#
|
|
630
|
+
# Optional Project name scoping the ``rule_marker``.
|
|
631
|
+
# The current export runs are account-wide (all allowed projects in
|
|
632
|
+
# one pass), so this stays None there — it is kept for callers that
|
|
633
|
+
# manage a single project's rules in isolation.
|
|
634
634
|
self.project = None
|
|
635
635
|
|
|
636
636
|
@property
|
|
@@ -18,6 +18,13 @@ class CheckmkDowntimeSync(CMK2):
|
|
|
18
18
|
# Reset Log Details
|
|
19
19
|
#log_details = []
|
|
20
20
|
|
|
21
|
+
def __init__(self, account=False):
|
|
22
|
+
super().__init__(account)
|
|
23
|
+
# Run statistics for the final status line: without it a run where
|
|
24
|
+
# every configured downtime already exists in Checkmk ends silently
|
|
25
|
+
# and looks broken to the operator.
|
|
26
|
+
self.dt_stats = {'created': 0, 'existing': 0, 'failed': 0}
|
|
27
|
+
|
|
21
28
|
|
|
22
29
|
def ahead_days(self, offset):
|
|
23
30
|
"""
|
|
@@ -216,16 +223,20 @@ class CheckmkDowntimeSync(CMK2):
|
|
|
216
223
|
data['duration'] = int(downtime['duration'])
|
|
217
224
|
try:
|
|
218
225
|
self.request(url, method="POST", data=data)
|
|
226
|
+
self.dt_stats['created'] += 1
|
|
219
227
|
print(f"\n{cc.OKGREEN} *{cc.ENDC} Set Downtime for "\
|
|
220
228
|
f"{data['start_time']} ({data['comment']})")
|
|
221
229
|
except CmkException as error:
|
|
230
|
+
self.dt_stats['failed'] += 1
|
|
222
231
|
self.log_details.append(("error", f"Downtime failed {error}"))
|
|
223
232
|
print(f"\n{cc.WARNING} *{cc.ENDC} Downtime failed: "\
|
|
224
233
|
f"{error}")
|
|
225
234
|
|
|
226
|
-
def do_hosts_downtimes(self, hostname, host_actions, attributes):
|
|
235
|
+
def do_hosts_downtimes(self, hostname, host_actions, attributes, current_downtimes):
|
|
227
236
|
"""
|
|
228
|
-
|
|
237
|
+
Set the configured downtimes for one host that are not already
|
|
238
|
+
present in Checkmk. ``current_downtimes`` is this host's slice of the
|
|
239
|
+
downtimes ``run()`` read once up front in a single bulk query.
|
|
229
240
|
"""
|
|
230
241
|
try:
|
|
231
242
|
configured_downtimes = []
|
|
@@ -234,12 +245,11 @@ class CheckmkDowntimeSync(CMK2):
|
|
|
234
245
|
configured_downtimes += \
|
|
235
246
|
list(self.calculate_configured_downtimes(rule, attributes['all']))
|
|
236
247
|
|
|
237
|
-
current_downtimes = list(
|
|
238
|
-
self.get_current_cmk_downtimes(hostname)
|
|
239
|
-
)
|
|
240
248
|
for downtime in configured_downtimes:
|
|
241
249
|
if downtime not in current_downtimes:
|
|
242
250
|
self.set_downtime(hostname, downtime)
|
|
251
|
+
else:
|
|
252
|
+
self.dt_stats['existing'] += 1
|
|
243
253
|
except Exception as exp: # pylint: disable=broad-exception-caught
|
|
244
254
|
self.log_details.append(('error', f'Exception {exp}'))
|
|
245
255
|
print(f"Exception: {exp}")
|
|
@@ -248,6 +258,13 @@ class CheckmkDowntimeSync(CMK2):
|
|
|
248
258
|
"""
|
|
249
259
|
Export Downtimes
|
|
250
260
|
"""
|
|
261
|
+
# Read every current host downtime in a single bulk query up front
|
|
262
|
+
# instead of one query per host inside the loop. On large inventories
|
|
263
|
+
# that turns hundreds of serial livestatus round-trips (one per host
|
|
264
|
+
# matching a downtime rule) into a single call — the previous
|
|
265
|
+
# per-host reads were what made the export appear to hang.
|
|
266
|
+
current_by_host = self.get_all_cmk_downtimes()
|
|
267
|
+
|
|
251
268
|
# Collect Rules
|
|
252
269
|
total = Host.active_non_template().count()
|
|
253
270
|
with Progress(SpinnerColumn(),
|
|
@@ -270,9 +287,18 @@ class CheckmkDowntimeSync(CMK2):
|
|
|
270
287
|
if not host_actions:
|
|
271
288
|
progress.advance(task1)
|
|
272
289
|
continue
|
|
273
|
-
self.do_hosts_downtimes(hostname, host_actions, attributes
|
|
290
|
+
self.do_hosts_downtimes(hostname, host_actions, attributes,
|
|
291
|
+
current_by_host.get(hostname, []))
|
|
274
292
|
progress.advance(task1)
|
|
275
293
|
|
|
294
|
+
# Final status line: a fully deduplicated run creates nothing and
|
|
295
|
+
# would otherwise end without any output, which reads like a failure.
|
|
296
|
+
print(f"{cc.OKGREEN} -- {cc.ENDC}Downtimes: {self.dt_stats['created']} created, "
|
|
297
|
+
f"{self.dt_stats['existing']} already present in Checkmk, "
|
|
298
|
+
f"{self.dt_stats['failed']} failed")
|
|
299
|
+
for key, value in self.dt_stats.items():
|
|
300
|
+
self.log_details.append((f'downtimes_{key}', value))
|
|
301
|
+
|
|
276
302
|
def run_async(self):
|
|
277
303
|
"""
|
|
278
304
|
Export Downtimes
|
|
@@ -308,25 +334,32 @@ class CheckmkDowntimeSync(CMK2):
|
|
|
308
334
|
# pool.close()
|
|
309
335
|
# pool.join()
|
|
310
336
|
|
|
311
|
-
def
|
|
312
|
-
"""
|
|
313
|
-
Read Downtimes from Checkmk
|
|
337
|
+
def get_all_cmk_downtimes(self):
|
|
314
338
|
"""
|
|
339
|
+
Read all host downtimes from Checkmk in one query, grouped by
|
|
340
|
+
hostname (``{hostname: [downtime, ...]}``).
|
|
315
341
|
|
|
316
|
-
|
|
317
|
-
|
|
342
|
+
Used by ``run()`` so the whole export does a single downtime read
|
|
343
|
+
instead of one per host — the per-host reads were the reason the
|
|
344
|
+
export appeared to hang on large inventories.
|
|
345
|
+
"""
|
|
346
|
+
url = "domain-types/downtime/collections/all?downtime_type=host"
|
|
318
347
|
response = self.request(url, method="GET")
|
|
319
348
|
# request() returns an empty ``{}`` body on error responses
|
|
320
349
|
# (404, non-200, no content). Guard the lookup so a failed
|
|
321
350
|
# downtime read yields "no current downtimes" instead of a bare
|
|
322
351
|
# KeyError that would escape as a detail-less run failure.
|
|
323
352
|
downtimes = response[0].get('value', []) if response[0] else []
|
|
353
|
+
by_host = {}
|
|
324
354
|
for downtime in downtimes:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
"
|
|
331
|
-
"
|
|
332
|
-
|
|
355
|
+
extensions = downtime.get('extensions', {})
|
|
356
|
+
hostname = extensions.get('host_name')
|
|
357
|
+
if not hostname:
|
|
358
|
+
continue
|
|
359
|
+
by_host.setdefault(hostname, []).append({
|
|
360
|
+
"start": datetime.datetime.fromisoformat(extensions["start_time"]),
|
|
361
|
+
"end": datetime.datetime.fromisoformat(extensions["end_time"]),
|
|
362
|
+
"comment": extensions["comment"],
|
|
363
|
+
"duration": extensions.get("duration", False),
|
|
364
|
+
})
|
|
365
|
+
return by_host
|
|
@@ -32,3 +32,23 @@ def cmk_cleanup_hostname(input_str):
|
|
|
32
32
|
for needle, replacer in app.config['REPLACERS']:
|
|
33
33
|
input_str = input_str.replace(needle, replacer)
|
|
34
34
|
return re.sub('[^a-zA-Z0-9_-]', '_', input_str.strip()).lower()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def project_allows_account(project, account_name):
|
|
38
|
+
"""
|
|
39
|
+
True when a Project's rules (and assigned hosts) may be
|
|
40
|
+
exported to ``account_name``: not on the project's ``deny_by_accounts``
|
|
41
|
+
list, and either no ``limit_by_accounts`` allow list is set or the
|
|
42
|
+
account is on it. The deny list wins over the allow list.
|
|
43
|
+
|
|
44
|
+
Lives here (not on the model) so the account-scope decision is shared
|
|
45
|
+
by the rule exports, the host export and the model without importing
|
|
46
|
+
MongoEngine documents.
|
|
47
|
+
"""
|
|
48
|
+
denied = [name for name in (getattr(project, 'deny_by_accounts', None) or [])
|
|
49
|
+
if name]
|
|
50
|
+
if account_name in denied:
|
|
51
|
+
return False
|
|
52
|
+
allowed = [name for name in (getattr(project, 'limit_by_accounts', None) or [])
|
|
53
|
+
if name]
|
|
54
|
+
return not allowed or account_name in allowed
|