cmdbsyncer 4.2.2__tar.gz → 4.2.4__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.2/cmdbsyncer.egg-info → cmdbsyncer-4.2.4}/PKG-INFO +1 -1
- cmdbsyncer-4.2.4/application/buildinfo.txt +1 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v4.2.md +26 -13
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/cmk2.py +15 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/cmk_rules.py +31 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/dcd.py +67 -9
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/downtimes.py +5 -1
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/inits.py +22 -3
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/models.py +14 -1
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/syncer.py +3 -20
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tags.py +22 -9
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_cmk_rules.py +85 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_dcd.py +56 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_rule_passwords.py +48 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_tags.py +41 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/views.py +112 -20
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/__init__.py +40 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/devices.py +2 -20
- cmdbsyncer-4.2.4/application/plugins/netbox/interfaces.py +263 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/tests/test_import_filter.py +8 -8
- cmdbsyncer-4.2.4/application/plugins/netbox/utils.py +31 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_import.html +4 -3
- cmdbsyncer-4.2.4/application/templates/admin/checkmk_rule_project_list.html +25 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_overview.html +72 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/model/inline_list_base.html +2 -2
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/themes/dracula.css +8 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/themes/gruvbox-dark.css +8 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/themes/gruvbox-light.css +9 -1
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/themes/nord.css +8 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/_form_sections.py +3 -2
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4/cmdbsyncer.egg-info}/PKG-INFO +1 -1
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/SOURCES.txt +2 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/pyproject.toml +1 -1
- cmdbsyncer-4.2.2/application/buildinfo.txt +0 -1
- cmdbsyncer-4.2.2/application/plugins/netbox/interfaces.py +0 -124
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/LICENSE +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/README.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/_version.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/api/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/api/inventory.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/api/objects.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/api/rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/api/syncer.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/api/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/auth/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/.pages +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v3.10.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v3.11.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v3.12.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v3.5.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v3.7.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v3.8.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v3.9.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v4.0.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/changelog/v4.1.md +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/cli.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/config.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/docu_links.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/enterprise.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/audit.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/cron.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/get_account.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/inventory.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/local_config_file.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/local_config_presets.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/mongo_keys.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/notification_channels.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/notification_dispatch.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/plugins.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/sates.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/sql.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/syncer_jinja.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/tablib_formater.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/tests/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/helpers/tests/test_sql.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/mcp_server.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/account.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/config.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/cron.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/field_approval.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/forms.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/host.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/host_inventory_tree.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/notification_channel.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/notification_rule.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/notification_state.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/saved_search.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/states.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/models/user.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/custom_attributes/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/custom_attributes/rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/custom_attributes/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/debug.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/email.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/inventory/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/log/log.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/log/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/log/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/plugin.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/rule/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/rule/filter.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/rule/match.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/rule/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/rule/rewrite.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/rule/rule.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/rule/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/search_parser.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/modules/statefile.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/notices/strict_certificate_verification.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/admin_views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/inventory.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/playbook_rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/runner.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/seed.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/site_syncer.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ansible/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/bmc_remedy/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/bmc_remedy/bmc_remedy.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/bmc_remedy/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/admin_views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/bi.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/groups.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/helpers.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/import_v1.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/import_v2.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/inventorize.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/notification_rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/passwords.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/poolfolder.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/rule_passwords.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/sites.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_bi.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_cmk2.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_downtimes.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_groups.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_helpers.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_import_v1.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_import_v2.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_inventorize.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_notification_rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_passwords.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_poolfolder.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_sites.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_syncer.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_users.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/checkmk/users.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/cisco_dna/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/cisco_dna/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/cisco_dna/syncer.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/cron.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/csv/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/csv/csv.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/csv/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/file_requests.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/idoit/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/idoit/admin_views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/idoit/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/idoit/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/idoit/rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/idoit/syncer.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/idoit/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jdisc/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jdisc/applications.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jdisc/devices.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jdisc/executables.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jdisc/jdisc.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jdisc/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira/jira.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/admin_views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/export.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/jira_cloud.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/schema_sync.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/json/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/json/json.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/json/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ldap/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ldap/ldap.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/ldap/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/maintenance/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/maintenance/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/mssql/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/mssql/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/mysql/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/mysql/mysql.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/mysql/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/admin_views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/cluster.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/contacts.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/dataflow.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/ips.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/netbox.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/networks.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/prefixes.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/tests/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/netbox/virtualmachines.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/prtg/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/prtg/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/prtg/prtg.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/pyodbc/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/pyodbc/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/pyodbc/pyodbc.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rest/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rest/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rest/rest.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rules/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rules/admin_views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rules/autorules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rules/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rules/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rules/rule_definitions.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rules/rule_import_export.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/rules/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/syncer_shell.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/vmware/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/vmware/admin_views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/vmware/custom_attributes.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/vmware/models.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/vmware/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/vmware/rules.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/vmware/views.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/vmware/vmware.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/yml/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/yml/plugin.json +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins/yml/yml.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/plugins_cli.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/static/cmdbsyncer_mark.png +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/static/css/cmdbsyncer.css +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/static/favicon.png +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/static/js/main.js +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/static/logo_white.png +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/_brand.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/_theme.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/_host_tabs.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/account_pick_type.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/ansible_playbook_run.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/ansible_project_detail.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/ansible_rule_list.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/ansible_run_details.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/bulk_label_form.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/changelog_archive.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_mngmt_list.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_edit.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_import_cmk.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_settings_list.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_test_folder_scope.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/copy_as_new_form.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/data_quality.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/file/list.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/file/modals/form.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/host_details.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/host_edit.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/host_inventory_tree.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/host_list.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/host_relations_graph.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/host_timeline.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/index.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/local_config_editor.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/master.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/model/clone_confirm.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/object_list.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/set_cmk_version_form.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/admin/set_template_form.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/base.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/change_password.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/debug.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/debug_host.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/email/newuser.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/email/notification.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/email/resetpassword.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/formular.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/license_info.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/login.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/logout_confirm.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/request_password.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/set_2fa.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/templates/set_theme.html +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/themes_registry.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/_form_fields.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/account.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/config.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/cron.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/data_quality.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/default.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/field_approval.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/fileadmin.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/host.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/host_filters.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/host_renderers.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/host_widgets.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/license.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/notification_channel.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/notification_rule.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/saved_search.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/application/views/user.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/dependency_links.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/entry_points.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/requires.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/top_level.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/requirements-ansible-windows.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/requirements-ansible.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/requirements-extras.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/requirements.txt +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/setup.cfg +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/syncerapi/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/syncerapi/v1/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/syncerapi/v1/core/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/syncerapi/v1/inventory/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/syncerapi/v1/rest/__init__.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_account_macro.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_api.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_api_csrf_invariant.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_default_view.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_mongo_keys.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_plugin.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_plugin_ssti.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_plugins_cli.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_rule.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_rule_filename_detect.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_rule_match.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/tests/test_search_parser.py +0 -0
- {cmdbsyncer-4.2.2 → cmdbsyncer-4.2.4}/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.4
|
|
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>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
BUILD_DATE=2026-07-15T17:59:01Z
|
|
@@ -1,35 +1,48 @@
|
|
|
1
1
|
# Version 4.2
|
|
2
2
|
|
|
3
|
-
## Version 4.2.
|
|
3
|
+
## Version 4.2.4
|
|
4
|
+
|
|
5
|
+
### Checkmk
|
|
6
|
+
- FIX: Downtime export now reports the real error — a Checkmk/livestatus timeout or connection problem while reading current downtimes is surfaced (and re-raised with `--debug`) instead of ending in a generic "Checkmk: Export Downtimes" failure with no detail; reading downtimes for a host that returns no data no longer aborts the run
|
|
7
|
+
- FIX: Host export no longer logs "Created Host" when the host creation actually failed — the success line is now only printed when Checkmk accepted the host, so a failed single-host create is reported as an error instead of a false success
|
|
8
|
+
- FIX: Exporting host tags to Checkmk 2.5 no longer fails with "Unknown field" — the tag group id field (renamed from `ident` to `id` in Checkmk 2.4) is now selected per Checkmk version, so 2.3 and older keep working too
|
|
9
|
+
- FEAT: DCD rules can be flagged "static" — a host-independent DCD rule is rendered once and always created instead of being recalculated for every host, which speeds up the DCD export on large inventories (like the Setup rule static flag)
|
|
10
|
+
- FIX: Exporting DCD rules works again on Checkmk 2.4 and 2.5 — the connector settings are now sent nested under a `connector` object as the REST API requires; before, the export failed with many "Unknown field" errors. Checkmk 2.3 keeps its two extra connector fields
|
|
11
|
+
- FEAT: A DCD rule's site can be set to `{{ cmk_site }}`, which resolves to the exporting account's Checkmk site — so one rule targets the right site on a test and a prod instance with different site names; the field now shows this as a placeholder hint
|
|
12
|
+
- FEAT: DCD rules can use `{{ account.<field> }}` to insert any (non-secret) attribute of the exporting Checkmk account — including per-account custom fields — so one rule adapts its values per account (e.g. test vs prod); passwords are never exposed
|
|
13
|
+
|
|
14
|
+
### Netbox
|
|
15
|
+
- 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
|
+
|
|
17
|
+
### Interface
|
|
18
|
+
- 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
|
+
|
|
20
|
+
## Version 4.2.3
|
|
4
21
|
|
|
5
22
|
### Ansible
|
|
6
23
|
- FIX: Playbook tasks delegated to localhost (`delegate_to: localhost`) no longer abort with "Failed to create temporary directory" under the web server — the local connection's temp dir now points at a writable per-run path instead of the web user's home
|
|
7
24
|
- FEAT: Checkmk Settings gain an "installation staging path" — the Checkmk server-management playbook stages the downloaded installer there instead of `/tmp`; leave it empty to keep using `/tmp`. Use it when the executing user can't reliably use `/tmp` (permission or private-tmp isolation)
|
|
8
25
|
- FIX: The Checkmk site-update playbook no longer fails the "set downtime" step with "401 Unauthorized" when no Checkmk API user/secret is configured — the downtime is skipped instead
|
|
26
|
+
- FIX: Running a playbook from the UI no longer aborts with "cmdbsyncer binary not found" — the local-mode inventory now resolves the `cmdbsyncer` CLI from the venv even when the web server's PATH omits it
|
|
27
|
+
|
|
28
|
+
### Setup
|
|
29
|
+
- FIX: A fresh `docker compose up` from git now starts — the bundled compose stack was told to reach MongoDB on `127.0.0.1` (the app container itself) instead of the `mongo` service, so the API aborted on boot with `Connection refused` (gh #124)
|
|
9
30
|
|
|
10
31
|
### Checkmk
|
|
32
|
+
- FIX: Importing Setup Rules from a Checkmk folder now surfaces the real Checkmk error (e.g. wrong credentials) instead of silently reporting "0 rules imported"
|
|
33
|
+
- FEAT: The Checkmk group export now honors an account's (or child account's) object filter for "Checkmk: Export Groups" — set it to include CMDB objects/shadow hosts in the group calculation; without a filter the export stays host-only as before
|
|
11
34
|
- FEAT: The Checkmk module menu is tidier — "Setup Rule Projects" now sits next to "Manage Checkmk Setup Rules", "Limit Host Export to Folders" moved under the host filters, and the separate "Export Scoping" submenu is gone
|
|
12
35
|
- FIX: "Limit Host Export to Folders" now lists rule folders in lowercase to match Checkmk's folder names, so the scope reliably matches the folders hosts are exported to
|
|
13
36
|
- FEAT: "Limit Host Export to Folders" is easier to use — clicking a rule folder or typing one adds it to a list of selected folders you can remove individually, instead of editing a comma-separated text field
|
|
14
37
|
- FEAT: Importing Setup Rules from a Checkmk folder into a project now shows a progress bar and status message while it runs, so you can see it is working
|
|
15
38
|
- FEAT: Checkmk Setup Rules can reference a syncer Checkmk Password with `{{ cmk_password("name") }}`, which resolves to that entry's Checkmk password-store ident on export — run the password export so the entry exists in the target Checkmk
|
|
16
39
|
- FEAT: Importing rules from a Checkmk folder now rewrites inline rule passwords (which Checkmk masks as `******` on read) into such password-store references, so imported rules deploy from a test to a production Checkmk without exposing or overwriting the secret — create a Checkmk Password with the reported name and export it
|
|
40
|
+
- FEAT: The Checkmk rule export now respects an account's folder scope ("Limit Host Export to Folders") — a scoped account only receives Setup rules whose target folder is in scope, just like the host export
|
|
41
|
+
- FEAT: DCD rules can be assigned to a Rule Project — they show on the project overview, follow the project's account filter on export (only exported to the accounts the project allows), and are included in the project's JSON export/import; the project list gains an "Import project from JSON" button
|
|
17
42
|
|
|
18
43
|
### Interface
|
|
19
44
|
- FIX: Card-style admin form pages (e.g. the "New Account" plugin-type picker) render with consistent padding and a theme-aware header in all four themes, instead of a header hanging off the edge of a flat card
|
|
20
45
|
|
|
21
|
-
## Version 4.2.1
|
|
22
|
-
|
|
23
|
-
### Ansible
|
|
24
|
-
- FIX: Running a playbook from the UI no longer aborts with "cmdbsyncer binary not found" — the local-mode inventory now resolves the `cmdbsyncer` CLI from the venv even when the web server's PATH omits it
|
|
25
|
-
|
|
26
|
-
### Setup
|
|
27
|
-
- FIX: A fresh `docker compose up` from git now starts — the bundled compose stack was told to reach MongoDB on `127.0.0.1` (the app container itself) instead of the `mongo` service, so the API aborted on boot with `Connection refused` (gh #124)
|
|
28
|
-
|
|
29
|
-
### Checkmk
|
|
30
|
-
- FIX: Importing Setup Rules from a Checkmk folder now surfaces the real Checkmk error (e.g. wrong credentials) instead of silently reporting "0 rules imported"
|
|
31
|
-
- FEAT: The Checkmk group export now honors an account's (or child account's) object filter for "Checkmk: Export Groups" — set it to include CMDB objects/shadow hosts in the group calculation; without a filter the export stays host-only as before
|
|
32
|
-
|
|
33
46
|
## Version 4.2.0
|
|
34
47
|
|
|
35
48
|
### Hosts
|
|
@@ -69,6 +69,21 @@ class CMK2(Plugin):
|
|
|
69
69
|
self._init_complete = True
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
def version_at_least(self, major, minor):
|
|
73
|
+
"""
|
|
74
|
+
True when the probed Checkmk version is at least ``major.minor``.
|
|
75
|
+
|
|
76
|
+
Central helper for version switches in the export code (the Checkmk REST
|
|
77
|
+
API changes field shapes between releases). ``checkmk_version`` looks
|
|
78
|
+
like ``2.4.0p19.cee`` or ``2.5.0.pro``; an unreadable value is treated
|
|
79
|
+
as the newest release so new installs get the current behaviour.
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
release = tuple(int(p) for p in str(self.checkmk_version).split('.')[:2])
|
|
83
|
+
except (AttributeError, ValueError, TypeError):
|
|
84
|
+
return True
|
|
85
|
+
return release >= (major, minor)
|
|
86
|
+
|
|
72
87
|
def _probe_checkmk_version(self):
|
|
73
88
|
"""
|
|
74
89
|
Ask Checkmk for its version and return the bare version string.
|
|
@@ -83,6 +83,31 @@ def folder_in_scope(rule_folder, target_folder, recursive=False):
|
|
|
83
83
|
return rule_folder.startswith(target_folder + '/')
|
|
84
84
|
|
|
85
85
|
|
|
86
|
+
def folder_within_scope(folder, limits):
|
|
87
|
+
"""
|
|
88
|
+
True when ``folder`` falls within an account's ``limit_by_folders`` scope.
|
|
89
|
+
|
|
90
|
+
``limits`` is the raw comma-separated ``limit_by_folders`` value off the
|
|
91
|
+
account. An empty or missing scope means no restriction (always True).
|
|
92
|
+
Folders typed without a leading slash are tolerated, and the match is
|
|
93
|
+
recursive so selecting ``/test`` also covers ``/test/linux``. Shared by the
|
|
94
|
+
host export (which folder a host lands in) and the rule export (which folder
|
|
95
|
+
a Setup rule is placed in) so both honour the same scope.
|
|
96
|
+
"""
|
|
97
|
+
allowed = []
|
|
98
|
+
for entry in (limits or '').split(','):
|
|
99
|
+
entry = entry.strip()
|
|
100
|
+
if not entry:
|
|
101
|
+
continue
|
|
102
|
+
if not entry.startswith('/'):
|
|
103
|
+
entry = '/' + entry
|
|
104
|
+
allowed.append(entry)
|
|
105
|
+
if not allowed:
|
|
106
|
+
return True
|
|
107
|
+
folder = folder or '/'
|
|
108
|
+
return any(folder_in_scope(folder, scope, recursive=True) for scope in allowed)
|
|
109
|
+
|
|
110
|
+
|
|
86
111
|
def iter_rule_folders():
|
|
87
112
|
"""
|
|
88
113
|
Collect the literal folders that the configured rules can place objects
|
|
@@ -758,6 +783,12 @@ class CheckmkRuleSync(CMK2):
|
|
|
758
783
|
value = render_jinja(rule_params['value_template'], **context)
|
|
759
784
|
rule_params['folder'] = normalize_folder(
|
|
760
785
|
render_jinja(rule_params['folder'], **context))
|
|
786
|
+
# Respect the account's folder scope (limit_by_folders): a scoped
|
|
787
|
+
# account only receives rules whose target folder is in scope, just
|
|
788
|
+
# like the host export only pushes hosts of those folders.
|
|
789
|
+
if not folder_within_scope(
|
|
790
|
+
rule_params['folder'], self.config.get('limit_by_folders')):
|
|
791
|
+
return None
|
|
761
792
|
rule_params['value'] = value
|
|
762
793
|
del rule_params['value_template']
|
|
763
794
|
rule_params['optimize'] = False
|
|
@@ -17,6 +17,10 @@ class CheckmkDCDRuleSync(CMK2):
|
|
|
17
17
|
"""
|
|
18
18
|
console = None
|
|
19
19
|
|
|
20
|
+
# Host-independent DCD rules, rendered once instead of per host. Injected
|
|
21
|
+
# by inits.export_dcd_rules; defaults to empty so other callers still work.
|
|
22
|
+
static_rules = []
|
|
23
|
+
|
|
20
24
|
def __init__(self, account=False):
|
|
21
25
|
super().__init__(account)
|
|
22
26
|
# Per-instance run state. Class-level defaults would accumulate
|
|
@@ -24,6 +28,33 @@ class CheckmkDCDRuleSync(CMK2):
|
|
|
24
28
|
# into later exports.
|
|
25
29
|
self.all_rules = []
|
|
26
30
|
|
|
31
|
+
# Account config keys withheld from the rule template context — secrets and
|
|
32
|
+
# internal ids that must never end up in a rendered rule.
|
|
33
|
+
_ACCOUNT_HIDDEN_KEYS = frozenset({
|
|
34
|
+
'password', 'bakery_passphrase', 'ca_cert_chain', 'ca_root_cert',
|
|
35
|
+
'_id', 'id', 'ref',
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
def _account_site(self):
|
|
39
|
+
"""
|
|
40
|
+
Checkmk site name of the exporting account — the last path segment of
|
|
41
|
+
its address (which ends in ``/<site>``). Exposed to DCD rules as
|
|
42
|
+
``{{ cmk_site }}`` so one rule can target the correct site on each
|
|
43
|
+
Checkmk (e.g. a test and a prod instance with different site names).
|
|
44
|
+
"""
|
|
45
|
+
address = (self.config.get('address') or '').rstrip('/')
|
|
46
|
+
return address.rsplit('/', 1)[-1] if '/' in address else ''
|
|
47
|
+
|
|
48
|
+
def _account_context(self):
|
|
49
|
+
"""
|
|
50
|
+
The exporting account's attributes exposed to DCD rules as
|
|
51
|
+
``{{ account.<field> }}`` — its standard fields plus any per-account
|
|
52
|
+
custom field (flattened into the account config). Lets one rule use a
|
|
53
|
+
value configured per account (test vs prod). Secrets are withheld.
|
|
54
|
+
"""
|
|
55
|
+
return {key: value for key, value in (self.config or {}).items()
|
|
56
|
+
if key not in self._ACCOUNT_HIDDEN_KEYS}
|
|
57
|
+
|
|
27
58
|
def does_rule_exist(self, rule_id):
|
|
28
59
|
"""
|
|
29
60
|
Check if Rule is existing
|
|
@@ -97,25 +128,34 @@ class CheckmkDCDRuleSync(CMK2):
|
|
|
97
128
|
exclude_time_ranges = self.build_timeranges(rule)
|
|
98
129
|
|
|
99
130
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
"site": render_jinja(rule['site'], mode='raise',**attributes),
|
|
131
|
+
# Checkmk's DCD REST API nests the connector settings under a
|
|
132
|
+
# "connector" object (all three supported versions). Checkmk 2.4
|
|
133
|
+
# dropped the "activate_changes_interval" and "exclude_time_ranges"
|
|
134
|
+
# connector fields — only 2.3 and older still accept them.
|
|
135
|
+
connector = {
|
|
106
136
|
"connector_type": render_jinja(rule['connector_type'], mode='raise',**attributes),
|
|
107
137
|
"restrict_source_hosts": restricted_hosts,
|
|
108
138
|
"interval": render_jinja(rule['interval'], mode='raise', **attributes),
|
|
109
139
|
"creation_rules": creation_rules,
|
|
110
|
-
"activate_changes_interval": render_jinja(rule['activate_changes_interval'], \
|
|
111
|
-
**attributes),
|
|
112
140
|
"discover_on_creation": rule['discover_on_creation'],
|
|
113
|
-
"exclude_time_ranges": exclude_time_ranges,
|
|
114
141
|
"no_deletion_time_after_init": render_jinja(rule['no_deletion_time_after_init'],\
|
|
115
142
|
**attributes),
|
|
116
143
|
"max_cache_age": render_jinja(rule['max_cache_age'], **attributes),
|
|
117
144
|
"validity_period": render_jinja(rule['validity_period'], **attributes),
|
|
118
145
|
}
|
|
146
|
+
if not self.version_at_least(2, 4):
|
|
147
|
+
connector["activate_changes_interval"] = \
|
|
148
|
+
render_jinja(rule['activate_changes_interval'], **attributes)
|
|
149
|
+
connector["exclude_time_ranges"] = exclude_time_ranges
|
|
150
|
+
|
|
151
|
+
payload = {
|
|
152
|
+
"dcd_id": render_jinja(rule['dcd_id'], mode='raise', **attributes),
|
|
153
|
+
"title": render_jinja(rule['title'], mode='raise', **attributes),
|
|
154
|
+
"comment": render_jinja(rule['comment'], mode='raise',**attributes),
|
|
155
|
+
"disabled": rule['disabled'],
|
|
156
|
+
"site": render_jinja(rule['site'], mode='raise',**attributes),
|
|
157
|
+
"connector": connector,
|
|
158
|
+
}
|
|
119
159
|
if rule['documentation_url']:
|
|
120
160
|
payload['documentation_url']= rule['documentation_url']
|
|
121
161
|
logger.debug(payload)
|
|
@@ -151,6 +191,11 @@ class CheckmkDCDRuleSync(CMK2):
|
|
|
151
191
|
Export DCD Rules
|
|
152
192
|
"""
|
|
153
193
|
|
|
194
|
+
# Exposed to every DCD rule: {{ cmk_site }} = the account's Checkmk site,
|
|
195
|
+
# and {{ account.<field> }} = any (non-secret) account attribute, so one
|
|
196
|
+
# rule can use values configured per account (test vs prod).
|
|
197
|
+
site = self._account_site()
|
|
198
|
+
account_ctx = self._account_context()
|
|
154
199
|
db_objects = Host.active_non_template()
|
|
155
200
|
total = db_objects.count()
|
|
156
201
|
with Progress(SpinnerColumn(),
|
|
@@ -168,12 +213,25 @@ class CheckmkDCDRuleSync(CMK2):
|
|
|
168
213
|
logger.debug(' -- Skiped no attributes')
|
|
169
214
|
progress.advance(task1)
|
|
170
215
|
continue
|
|
216
|
+
attributes['all']['cmk_site'] = site
|
|
217
|
+
attributes['all']['account'] = account_ctx
|
|
171
218
|
# pylint: disable-next=no-member
|
|
172
219
|
host_actions = self.actions.get_outcomes(db_host, attributes['all'])
|
|
173
220
|
if host_actions:
|
|
174
221
|
logger.debug(' -- Got Actions')
|
|
175
222
|
self.calculate_rules_of_host(db_host.hostname, host_actions, attributes['all'])
|
|
176
223
|
progress.advance(task1)
|
|
224
|
+
|
|
225
|
+
# Static rules carry no host data: render each once against an empty
|
|
226
|
+
# host context instead of per host (their match conditions are
|
|
227
|
+
# ignored — a static rule is always emitted).
|
|
228
|
+
for rule in self.static_rules:
|
|
229
|
+
host_actions = {'dcd': [dict(outcome.to_mongo())
|
|
230
|
+
for outcome in rule.outcomes]}
|
|
231
|
+
self.calculate_rules_of_host(
|
|
232
|
+
f"static:{rule.name}", host_actions,
|
|
233
|
+
{'cmk_site': site, 'account': account_ctx})
|
|
234
|
+
|
|
177
235
|
task2 = progress.add_task("Send Rules to Checkmk", total=len(self.all_rules))
|
|
178
236
|
count_new = 0
|
|
179
237
|
count_existing = 0
|
|
@@ -316,7 +316,11 @@ class CheckmkDowntimeSync(CMK2):
|
|
|
316
316
|
url = f"domain-types/downtime/collections/all?"\
|
|
317
317
|
f"host_name={hostname}&downtime_type=host"
|
|
318
318
|
response = self.request(url, method="GET")
|
|
319
|
-
|
|
319
|
+
# request() returns an empty ``{}`` body on error responses
|
|
320
|
+
# (404, non-200, no content). Guard the lookup so a failed
|
|
321
|
+
# downtime read yields "no current downtimes" instead of a bare
|
|
322
|
+
# KeyError that would escape as a detail-less run failure.
|
|
323
|
+
downtimes = response[0].get('value', []) if response[0] else []
|
|
320
324
|
for downtime in downtimes:
|
|
321
325
|
yield {
|
|
322
326
|
"start" : datetime.datetime.fromisoformat(
|
|
@@ -516,10 +516,16 @@ def export_downtimes(account, debug=False, debug_rules=False):
|
|
|
516
516
|
syncer.actions = actions
|
|
517
517
|
syncer.debug_rules(debug_rules, "Checkmk")
|
|
518
518
|
|
|
519
|
-
except
|
|
519
|
+
except Exception as error_obj: # pylint: disable=broad-exception-caught
|
|
520
|
+
# Catch every error, not just CmkException: the downtime export
|
|
521
|
+
# talks to Checkmk's livestatus (e.g. reading current downtimes),
|
|
522
|
+
# which can raise a plain requests timeout/connection error. With
|
|
523
|
+
# the old CmkException-only catch those escaped uncaught, so the
|
|
524
|
+
# run left only a detail-less "Checkmk: Export Downtimes" log entry
|
|
525
|
+
# and `--debug` never surfaced the real cause.
|
|
520
526
|
if debug:
|
|
521
527
|
raise
|
|
522
|
-
print(f'
|
|
528
|
+
print(f'{ColorCodes.FAIL}Error: {error_obj} {ColorCodes.ENDC}')
|
|
523
529
|
if syncer is not None:
|
|
524
530
|
syncer.record_exception(error_obj)
|
|
525
531
|
else:
|
|
@@ -540,12 +546,24 @@ def export_dcd_rules(account, debug=False, debug_rules=False):
|
|
|
540
546
|
Name overwrite
|
|
541
547
|
"""
|
|
542
548
|
actions = ExportDCD(account)
|
|
543
|
-
|
|
549
|
+
# Honour each project's account filter (limit_by_accounts): a DCD rule
|
|
550
|
+
# assigned to a project is only exported to the accounts that project
|
|
551
|
+
# allows. Rules without a project stay global (exported everywhere),
|
|
552
|
+
# matching the Setup-rule export.
|
|
553
|
+
allowed_projects = [None, ''] + projects_for_account(account)
|
|
554
|
+
# Static rules carry no host data — they are rendered once (see
|
|
555
|
+
# CheckmkDCDRuleSync.export_rules) instead of per host, so they are kept
|
|
556
|
+
# out of the per-host engine here.
|
|
557
|
+
actions.rules = CheckmkDCDRule.objects(
|
|
558
|
+
enabled=True, static_rule__ne=True, project__in=allowed_projects)
|
|
559
|
+
static_rules = CheckmkDCDRule.objects(
|
|
560
|
+
enabled=True, static_rule=True, project__in=allowed_projects)
|
|
544
561
|
|
|
545
562
|
if not debug_rules:
|
|
546
563
|
syncer = CheckmkDCDRuleSync(account)
|
|
547
564
|
syncer.debug = debug
|
|
548
565
|
syncer.actions = actions
|
|
566
|
+
syncer.static_rules = static_rules
|
|
549
567
|
syncer.rewrite = rules['rewrite']
|
|
550
568
|
syncer.filter = rules['filter']
|
|
551
569
|
syncer.name = 'Checkmk: Export DCD Rules'
|
|
@@ -554,6 +572,7 @@ def export_dcd_rules(account, debug=False, debug_rules=False):
|
|
|
554
572
|
else:
|
|
555
573
|
syncer = CheckmkDCDRuleSync(False)
|
|
556
574
|
syncer.actions = actions
|
|
575
|
+
syncer.static_rules = static_rules
|
|
557
576
|
syncer.rewrite = rules['rewrite']
|
|
558
577
|
syncer.filter = rules['filter']
|
|
559
578
|
syncer.debug_rules(debug_rules, "Checkmk")
|
|
@@ -690,12 +690,25 @@ class CheckmkDCDRule(db.Document):
|
|
|
690
690
|
render_cmk_dcd_rule = db.StringField()
|
|
691
691
|
last_match = db.BooleanField(default=False)
|
|
692
692
|
|
|
693
|
+
# Host-independent DCD rule: a DCD connection rarely depends on host data, so
|
|
694
|
+
# a static rule is rendered once (against an empty host context, ignoring the
|
|
695
|
+
# match conditions) instead of once per host and de-duplicated — the same
|
|
696
|
+
# optimisation CheckmkRuleMngmt.static_rule provides for Setup rules.
|
|
697
|
+
static_rule = db.BooleanField(default=False)
|
|
698
|
+
|
|
699
|
+
# Name of the CheckmkRuleProject this DCD rule belongs to (or empty).
|
|
700
|
+
# Referenced by name to match CheckmkRuleMngmt.project. A DCD rule assigned
|
|
701
|
+
# to a project follows that project's account filter (limit_by_accounts) on
|
|
702
|
+
# export, just like a Setup rule — it is only exported to the accounts the
|
|
703
|
+
# project allows. A rule without a project stays global.
|
|
704
|
+
project = db.StringField()
|
|
693
705
|
|
|
694
706
|
enabled = db.BooleanField()
|
|
695
707
|
sort_field = db.IntField(default=0)
|
|
696
708
|
|
|
697
709
|
meta = {
|
|
698
|
-
'strict': False
|
|
710
|
+
'strict': False,
|
|
711
|
+
'indexes': ['project'],
|
|
699
712
|
}
|
|
700
713
|
|
|
701
714
|
#.
|
|
@@ -9,7 +9,7 @@ from rich.progress import Progress, SpinnerColumn, TimeElapsedColumn, MofNComple
|
|
|
9
9
|
from application import app, logger, log, init_db
|
|
10
10
|
from application.models.host import Host
|
|
11
11
|
from application.plugins.checkmk.cmk2 import CMK2, CmkException
|
|
12
|
-
from application.plugins.checkmk.cmk_rules import
|
|
12
|
+
from application.plugins.checkmk.cmk_rules import folder_within_scope
|
|
13
13
|
from application.modules.debug import ColorCodes as CC
|
|
14
14
|
|
|
15
15
|
|
|
@@ -349,25 +349,8 @@ class SyncCMK2(CMK2):
|
|
|
349
349
|
Returns:
|
|
350
350
|
bool: True if the host should be exported to this account.
|
|
351
351
|
"""
|
|
352
|
-
limits = self.config.get('limit_by_folders')
|
|
353
|
-
if not limits:
|
|
354
|
-
return True
|
|
355
|
-
# A folder entered without a leading slash (e.g. "test/linux" instead of
|
|
356
|
-
# "/test/linux") would otherwise never match the slash-prefixed folder a
|
|
357
|
-
# rule produces — normalise it so the scope works regardless of how it
|
|
358
|
-
# was typed, on this page or directly in the account's custom fields.
|
|
359
|
-
allowed = []
|
|
360
|
-
for entry in limits.split(','):
|
|
361
|
-
entry = entry.strip()
|
|
362
|
-
if not entry:
|
|
363
|
-
continue
|
|
364
|
-
if not entry.startswith('/'):
|
|
365
|
-
entry = '/' + entry
|
|
366
|
-
allowed.append(entry)
|
|
367
|
-
if not allowed:
|
|
368
|
-
return True
|
|
369
352
|
folder = next_actions.get('move_folder') or '/'
|
|
370
|
-
return
|
|
353
|
+
return folder_within_scope(folder, self.config.get('limit_by_folders'))
|
|
371
354
|
|
|
372
355
|
def handle_clusters(self):
|
|
373
356
|
"""
|
|
@@ -1039,10 +1022,10 @@ class SyncCMK2(CMK2):
|
|
|
1039
1022
|
try:
|
|
1040
1023
|
self.request(url, method="POST", data=body)
|
|
1041
1024
|
self.num_created += 1
|
|
1025
|
+
self.console(f" * Created Host {hostname}")
|
|
1042
1026
|
except CmkException as error:
|
|
1043
1027
|
self.log_details.append(('error', f"Host Create Error: {error}"))
|
|
1044
1028
|
self.console(f" * CMK API ERROR {error}")
|
|
1045
|
-
self.console(f" * Created Host {hostname}")
|
|
1046
1029
|
|
|
1047
1030
|
|
|
1048
1031
|
|
|
@@ -310,6 +310,7 @@ class CheckmkTagSync(CMK2):
|
|
|
310
310
|
config_tags.sort(key=lambda tup: tup[1])
|
|
311
311
|
if len(config_tags) > 1:
|
|
312
312
|
config_tags.insert(0, (None, "Not set"))
|
|
313
|
+
id_field = self._tag_id_field()
|
|
313
314
|
found_ids = []
|
|
314
315
|
tags = []
|
|
315
316
|
for x, y in config_tags:
|
|
@@ -319,7 +320,7 @@ class CheckmkTagSync(CMK2):
|
|
|
319
320
|
if not y:
|
|
320
321
|
continue
|
|
321
322
|
if x not in found_ids:
|
|
322
|
-
tags.append({
|
|
323
|
+
tags.append({id_field: x, 'title': y})
|
|
323
324
|
found_ids.append(x)
|
|
324
325
|
|
|
325
326
|
if not tags or len(tags) == 0:
|
|
@@ -327,6 +328,14 @@ class CheckmkTagSync(CMK2):
|
|
|
327
328
|
return False
|
|
328
329
|
return tags
|
|
329
330
|
|
|
331
|
+
def _tag_id_field(self):
|
|
332
|
+
"""
|
|
333
|
+
Field name for a host tag group id and its tag choices. Checkmk renamed
|
|
334
|
+
it from ``ident`` to ``id`` in 2.4, so 2.4+ use ``id`` and 2.3 and older
|
|
335
|
+
use ``ident`` (verified against 2.3.0p48, 2.4.0p19 and 2.5.0p8).
|
|
336
|
+
"""
|
|
337
|
+
return 'id' if self.version_at_least(2, 4) else 'ident'
|
|
338
|
+
|
|
330
339
|
def sync_to_checkmk(self, groups, tag_group_list):
|
|
331
340
|
"""
|
|
332
341
|
Use generated configuration to Sync
|
|
@@ -341,12 +350,17 @@ class CheckmkTagSync(CMK2):
|
|
|
341
350
|
*Progress.get_default_columns(),
|
|
342
351
|
TimeElapsedColumn()) as progress:
|
|
343
352
|
task1 = progress.add_task("Sending to Checkmk", total=len(groups))
|
|
353
|
+
# Checkmk renamed the tag group id field 'ident' -> 'id' in 2.4.
|
|
354
|
+
id_field = self._tag_id_field()
|
|
344
355
|
for syncer_group_id, syncer_group_data in groups.items():
|
|
345
356
|
payload = syncer_group_data.copy()
|
|
346
357
|
for what in ['object_filter', 'rw_id', 'is_template',
|
|
347
358
|
'rw_title', 'multiply_list']:
|
|
348
359
|
if what in payload:
|
|
349
360
|
del payload[what]
|
|
361
|
+
# The group is built with an 'ident' key internally; send it
|
|
362
|
+
# under the field name this Checkmk version expects.
|
|
363
|
+
payload[id_field] = payload.pop('ident')
|
|
350
364
|
|
|
351
365
|
tag_list = [(x[1], x[2]) for x in tag_group_list if x[0] == syncer_group_id]
|
|
352
366
|
if tags := self.prepare_tags_for_checkmk(tag_list):
|
|
@@ -362,7 +376,7 @@ class CheckmkTagSync(CMK2):
|
|
|
362
376
|
# Check if we need to update it
|
|
363
377
|
checkmk_tags = checkmk_ids[syncer_group_id]
|
|
364
378
|
checkmk_tags_flat = \
|
|
365
|
-
[{
|
|
379
|
+
[{id_field: x['id'], 'title': x['title']} \
|
|
366
380
|
for x in checkmk_tags if x['title'].strip()]
|
|
367
381
|
|
|
368
382
|
if app.config['CMK_DONT_DELETE_TAGS']:
|
|
@@ -370,10 +384,10 @@ class CheckmkTagSync(CMK2):
|
|
|
370
384
|
found = set()
|
|
371
385
|
new_tags = []
|
|
372
386
|
for tag in payload['tags'] + checkmk_tags_flat:
|
|
373
|
-
if tag[
|
|
374
|
-
found.add(tag[
|
|
387
|
+
if tag[id_field] not in found:
|
|
388
|
+
found.add(tag[id_field])
|
|
375
389
|
new_tags.append(tag)
|
|
376
|
-
payload['tags'] = sorted(new_tags, key=lambda x: str(x[
|
|
390
|
+
payload['tags'] = sorted(new_tags, key=lambda x: str(x[id_field]))
|
|
377
391
|
checkmk_tags_frozen = {frozenset(d.items()) for d in checkmk_tags_flat}
|
|
378
392
|
syncer_tags_frozen = {frozenset(d.items()) for d in payload['tags']}
|
|
379
393
|
if checkmk_tags_frozen == syncer_tags_frozen:
|
|
@@ -386,12 +400,11 @@ class CheckmkTagSync(CMK2):
|
|
|
386
400
|
update_headers = {
|
|
387
401
|
'if-match': etag
|
|
388
402
|
}
|
|
389
|
-
del payload[
|
|
403
|
+
del payload[id_field]
|
|
390
404
|
payload['repair'] = False
|
|
391
405
|
try:
|
|
392
|
-
self.request(
|
|
393
|
-
method="PUT",
|
|
394
|
-
data=payload,
|
|
406
|
+
self.request(
|
|
407
|
+
url, method="PUT", data=payload,
|
|
395
408
|
additional_header=update_headers)
|
|
396
409
|
except Exception as error:
|
|
397
410
|
progress.console.print(f" ! Group {syncer_group_id} can't be updated.")
|
|
@@ -16,6 +16,7 @@ from application.plugins.checkmk.cmk_rules import (
|
|
|
16
16
|
render_jinja_in_value,
|
|
17
17
|
normalize_cmk_folder,
|
|
18
18
|
folder_in_scope,
|
|
19
|
+
folder_within_scope,
|
|
19
20
|
cmk_conditions_to_outcome,
|
|
20
21
|
cmk_rule_to_outcome,
|
|
21
22
|
CheckmkRuleSync,
|
|
@@ -210,6 +211,43 @@ class TestCheckmkRuleSync(unittest.TestCase):
|
|
|
210
211
|
self.assertIn('host_label_groups', result['condition'])
|
|
211
212
|
self.assertNotIn('service_labels', result['condition'])
|
|
212
213
|
|
|
214
|
+
@patch('application.plugins.checkmk.cmk_rules.render_jinja')
|
|
215
|
+
def test_folder_scope_skips_out_of_scope_rule(self, mock_render):
|
|
216
|
+
# A scoped account (limit_by_folders) drops a rule whose folder is not
|
|
217
|
+
# in scope — build returns None so the caller skips it.
|
|
218
|
+
mock_render.side_effect = lambda tpl, **kw: tpl
|
|
219
|
+
self.sync.config = {'limit_by_folders': '/test'}
|
|
220
|
+
rule_params = {
|
|
221
|
+
'value_template': "{'k': 'v'}", 'folder': '/prod', 'comment': 'c',
|
|
222
|
+
}
|
|
223
|
+
result = self.sync.build_condition_and_update_rule_params(
|
|
224
|
+
rule_params, {'all': {'HOSTNAME': 'h'}})
|
|
225
|
+
self.assertIsNone(result)
|
|
226
|
+
|
|
227
|
+
@patch('application.plugins.checkmk.cmk_rules.render_jinja')
|
|
228
|
+
def test_folder_scope_keeps_in_scope_rule(self, mock_render):
|
|
229
|
+
mock_render.side_effect = lambda tpl, **kw: tpl
|
|
230
|
+
self.sync.config = {'limit_by_folders': '/test'}
|
|
231
|
+
rule_params = {
|
|
232
|
+
'value_template': "{'k': 'v'}", 'folder': '/test/linux',
|
|
233
|
+
'comment': 'c',
|
|
234
|
+
}
|
|
235
|
+
result = self.sync.build_condition_and_update_rule_params(
|
|
236
|
+
rule_params, {'all': {'HOSTNAME': 'h'}})
|
|
237
|
+
self.assertIsNotNone(result)
|
|
238
|
+
self.assertEqual(result['folder'], '/test/linux')
|
|
239
|
+
|
|
240
|
+
@patch('application.plugins.checkmk.cmk_rules.render_jinja')
|
|
241
|
+
def test_no_folder_scope_keeps_rule(self, mock_render):
|
|
242
|
+
mock_render.side_effect = lambda tpl, **kw: tpl
|
|
243
|
+
# config without limit_by_folders (the setUp default) — no restriction.
|
|
244
|
+
rule_params = {
|
|
245
|
+
'value_template': "{'k': 'v'}", 'folder': '/prod', 'comment': 'c',
|
|
246
|
+
}
|
|
247
|
+
result = self.sync.build_condition_and_update_rule_params(
|
|
248
|
+
rule_params, {'all': {'HOSTNAME': 'h'}})
|
|
249
|
+
self.assertIsNotNone(result)
|
|
250
|
+
|
|
213
251
|
@patch('application.plugins.checkmk.cmk_rules.render_jinja')
|
|
214
252
|
def test_build_condition_v22(self, mock_render):
|
|
215
253
|
mock_render.side_effect = lambda tpl, **kw: tpl
|
|
@@ -624,6 +662,19 @@ class TestCmkFolderHelpers(unittest.TestCase):
|
|
|
624
662
|
self.assertFalse(
|
|
625
663
|
folder_in_scope('/server-old', '/server', recursive=True))
|
|
626
664
|
|
|
665
|
+
def test_within_scope_no_limit_allows_all(self):
|
|
666
|
+
self.assertTrue(folder_within_scope('/anything', ''))
|
|
667
|
+
self.assertTrue(folder_within_scope('/anything', None))
|
|
668
|
+
|
|
669
|
+
def test_within_scope_recursive_and_leading_slash_tolerant(self):
|
|
670
|
+
# scope typed without a leading slash still matches, recursively.
|
|
671
|
+
self.assertTrue(folder_within_scope('/test/linux', 'test'))
|
|
672
|
+
self.assertTrue(folder_within_scope('/test', '/test,/other'))
|
|
673
|
+
|
|
674
|
+
def test_within_scope_out_of_scope_folder(self):
|
|
675
|
+
self.assertFalse(folder_within_scope('/prod', '/test'))
|
|
676
|
+
self.assertFalse(folder_within_scope('/', '/test'))
|
|
677
|
+
|
|
627
678
|
|
|
628
679
|
class TestCmkConditionReverse(unittest.TestCase):
|
|
629
680
|
"""cmk_conditions_to_outcome + cmk_rule_to_outcome (reverse of export)."""
|
|
@@ -898,5 +949,39 @@ class TestProjectsForAccount(unittest.TestCase):
|
|
|
898
949
|
self.assertEqual(for_b, ['all', 'a_and_b', 'only_b'])
|
|
899
950
|
|
|
900
951
|
|
|
952
|
+
class TestExportDcdRulesProjectFilter(unittest.TestCase):
|
|
953
|
+
"""export_dcd_rules restricts DCD rules by their project's account filter."""
|
|
954
|
+
|
|
955
|
+
def test_dcd_export_filters_by_project(self):
|
|
956
|
+
# DefaultRule stand-in (must be subclassable)
|
|
957
|
+
class _StubRule: # pylint: disable=too-few-public-methods
|
|
958
|
+
def __init__(self, account=None):
|
|
959
|
+
self.rules = None
|
|
960
|
+
|
|
961
|
+
# CheckmkDCDRuleSync stand-in
|
|
962
|
+
class _StubSync: # pylint: disable=too-few-public-methods
|
|
963
|
+
def __init__(self, account=False):
|
|
964
|
+
pass
|
|
965
|
+
|
|
966
|
+
def export_rules(self):
|
|
967
|
+
pass
|
|
968
|
+
|
|
969
|
+
with patch.object(inits, '_load_rules',
|
|
970
|
+
return_value={'rewrite': [], 'filter': []}), \
|
|
971
|
+
patch.object(inits, 'projects_for_account',
|
|
972
|
+
return_value=['proj_a']), \
|
|
973
|
+
patch.object(inits, 'DefaultRule', _StubRule), \
|
|
974
|
+
patch.object(inits, 'CheckmkDCDRuleSync', _StubSync), \
|
|
975
|
+
patch.object(inits, 'CheckmkDCDRule') as mock_dcd:
|
|
976
|
+
mock_dcd.objects.return_value = ['rule']
|
|
977
|
+
inits.export_dcd_rules('acc_a')
|
|
978
|
+
# Global (no project) rules plus the projects this account is allowed,
|
|
979
|
+
# split into the per-host (non-static) and static-rule querysets.
|
|
980
|
+
mock_dcd.objects.assert_any_call(
|
|
981
|
+
enabled=True, static_rule__ne=True, project__in=[None, '', 'proj_a'])
|
|
982
|
+
mock_dcd.objects.assert_any_call(
|
|
983
|
+
enabled=True, static_rule=True, project__in=[None, '', 'proj_a'])
|
|
984
|
+
|
|
985
|
+
|
|
901
986
|
if __name__ == '__main__':
|
|
902
987
|
unittest.main(verbosity=2)
|