cmdbsyncer 4.2.3__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.
Files changed (346) hide show
  1. {cmdbsyncer-4.2.3/cmdbsyncer.egg-info → cmdbsyncer-4.2.4}/PKG-INFO +1 -1
  2. cmdbsyncer-4.2.4/application/buildinfo.txt +1 -0
  3. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v4.2.md +23 -16
  4. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/cmk2.py +15 -0
  5. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/dcd.py +67 -9
  6. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/downtimes.py +5 -1
  7. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/inits.py +16 -3
  8. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/models.py +6 -0
  9. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/syncer.py +1 -1
  10. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tags.py +22 -9
  11. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_cmk_rules.py +6 -3
  12. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_dcd.py +56 -0
  13. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_tags.py +41 -0
  14. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/views.py +25 -1
  15. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/__init__.py +40 -0
  16. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/devices.py +2 -20
  17. cmdbsyncer-4.2.4/application/plugins/netbox/interfaces.py +263 -0
  18. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/tests/test_import_filter.py +8 -8
  19. cmdbsyncer-4.2.4/application/plugins/netbox/utils.py +31 -0
  20. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_overview.html +3 -0
  21. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/model/inline_list_base.html +2 -2
  22. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/themes/dracula.css +8 -0
  23. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/themes/gruvbox-dark.css +8 -0
  24. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/themes/gruvbox-light.css +9 -1
  25. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/themes/nord.css +8 -0
  26. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/_form_sections.py +3 -2
  27. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4/cmdbsyncer.egg-info}/PKG-INFO +1 -1
  28. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/SOURCES.txt +1 -0
  29. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/pyproject.toml +1 -1
  30. cmdbsyncer-4.2.3/application/buildinfo.txt +0 -1
  31. cmdbsyncer-4.2.3/application/plugins/netbox/interfaces.py +0 -124
  32. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/LICENSE +0 -0
  33. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/README.md +0 -0
  34. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/__init__.py +0 -0
  35. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/_version.py +0 -0
  36. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/api/__init__.py +0 -0
  37. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/api/inventory.py +0 -0
  38. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/api/objects.py +0 -0
  39. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/api/rules.py +0 -0
  40. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/api/syncer.py +0 -0
  41. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/api/views.py +0 -0
  42. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/auth/views.py +0 -0
  43. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/.pages +0 -0
  44. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v3.10.md +0 -0
  45. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v3.11.md +0 -0
  46. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v3.12.md +0 -0
  47. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v3.5.md +0 -0
  48. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v3.7.md +0 -0
  49. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v3.8.md +0 -0
  50. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v3.9.md +0 -0
  51. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v4.0.md +0 -0
  52. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/changelog/v4.1.md +0 -0
  53. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/cli.py +0 -0
  54. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/config.py +0 -0
  55. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/docu_links.py +0 -0
  56. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/enterprise.py +0 -0
  57. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/__init__.py +0 -0
  58. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/audit.py +0 -0
  59. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/cron.py +0 -0
  60. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/get_account.py +0 -0
  61. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/inventory.py +0 -0
  62. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/local_config_file.py +0 -0
  63. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/local_config_presets.py +0 -0
  64. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/mongo_keys.py +0 -0
  65. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/notification_channels.py +0 -0
  66. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/notification_dispatch.py +0 -0
  67. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/plugins.py +0 -0
  68. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/sates.py +0 -0
  69. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/sql.py +0 -0
  70. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/syncer_jinja.py +0 -0
  71. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/tablib_formater.py +0 -0
  72. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/tests/__init__.py +0 -0
  73. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/helpers/tests/test_sql.py +0 -0
  74. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/mcp_server.py +0 -0
  75. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/__init__.py +0 -0
  76. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/account.py +0 -0
  77. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/config.py +0 -0
  78. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/cron.py +0 -0
  79. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/field_approval.py +0 -0
  80. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/forms.py +0 -0
  81. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/host.py +0 -0
  82. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/host_inventory_tree.py +0 -0
  83. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/notification_channel.py +0 -0
  84. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/notification_rule.py +0 -0
  85. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/notification_state.py +0 -0
  86. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/saved_search.py +0 -0
  87. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/states.py +0 -0
  88. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/models/user.py +0 -0
  89. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/__init__.py +0 -0
  90. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/custom_attributes/models.py +0 -0
  91. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/custom_attributes/rules.py +0 -0
  92. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/custom_attributes/views.py +0 -0
  93. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/debug.py +0 -0
  94. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/email.py +0 -0
  95. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/inventory/__init__.py +0 -0
  96. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/log/log.py +0 -0
  97. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/log/models.py +0 -0
  98. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/log/views.py +0 -0
  99. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/plugin.py +0 -0
  100. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/rule/__init__.py +0 -0
  101. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/rule/filter.py +0 -0
  102. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/rule/match.py +0 -0
  103. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/rule/models.py +0 -0
  104. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/rule/rewrite.py +0 -0
  105. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/rule/rule.py +0 -0
  106. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/rule/views.py +0 -0
  107. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/search_parser.py +0 -0
  108. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/modules/statefile.py +0 -0
  109. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/notices/strict_certificate_verification.txt +0 -0
  110. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/__init__.py +0 -0
  111. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/__init__.py +0 -0
  112. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/admin_views.py +0 -0
  113. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/inventory.py +0 -0
  114. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/models.py +0 -0
  115. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/playbook_rules.py +0 -0
  116. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/plugin.json +0 -0
  117. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/rules.py +0 -0
  118. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/runner.py +0 -0
  119. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/seed.py +0 -0
  120. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/site_syncer.py +0 -0
  121. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ansible/views.py +0 -0
  122. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/bmc_remedy/__init__.py +0 -0
  123. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/bmc_remedy/bmc_remedy.py +0 -0
  124. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/bmc_remedy/plugin.json +0 -0
  125. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/__init__.py +0 -0
  126. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/admin_views.py +0 -0
  127. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/bi.py +0 -0
  128. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/cmk_rules.py +0 -0
  129. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/groups.py +0 -0
  130. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/helpers.py +0 -0
  131. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/import_v1.py +0 -0
  132. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/import_v2.py +0 -0
  133. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/inventorize.py +0 -0
  134. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/notification_rules.py +0 -0
  135. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/passwords.py +0 -0
  136. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/plugin.json +0 -0
  137. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/poolfolder.py +0 -0
  138. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/rule_passwords.py +0 -0
  139. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/rules.py +0 -0
  140. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/sites.py +0 -0
  141. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/__init__.py +0 -0
  142. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_bi.py +0 -0
  143. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_cmk2.py +0 -0
  144. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_downtimes.py +0 -0
  145. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_groups.py +0 -0
  146. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_helpers.py +0 -0
  147. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_import_v1.py +0 -0
  148. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_import_v2.py +0 -0
  149. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_inventorize.py +0 -0
  150. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_notification_rules.py +0 -0
  151. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_passwords.py +0 -0
  152. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_poolfolder.py +0 -0
  153. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_rule_passwords.py +0 -0
  154. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_rules.py +0 -0
  155. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_sites.py +0 -0
  156. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_syncer.py +0 -0
  157. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/tests/test_users.py +0 -0
  158. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/checkmk/users.py +0 -0
  159. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/cisco_dna/__init__.py +0 -0
  160. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/cisco_dna/plugin.json +0 -0
  161. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/cisco_dna/syncer.py +0 -0
  162. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/cron.py +0 -0
  163. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/csv/__init__.py +0 -0
  164. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/csv/csv.py +0 -0
  165. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/csv/plugin.json +0 -0
  166. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/file_requests.py +0 -0
  167. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/idoit/__init__.py +0 -0
  168. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/idoit/admin_views.py +0 -0
  169. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/idoit/models.py +0 -0
  170. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/idoit/plugin.json +0 -0
  171. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/idoit/rules.py +0 -0
  172. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/idoit/syncer.py +0 -0
  173. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/idoit/views.py +0 -0
  174. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jdisc/__init__.py +0 -0
  175. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jdisc/applications.py +0 -0
  176. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jdisc/devices.py +0 -0
  177. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jdisc/executables.py +0 -0
  178. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jdisc/jdisc.py +0 -0
  179. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jdisc/plugin.json +0 -0
  180. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira/__init__.py +0 -0
  181. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira/jira.py +0 -0
  182. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira/plugin.json +0 -0
  183. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/__init__.py +0 -0
  184. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/admin_views.py +0 -0
  185. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/export.py +0 -0
  186. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/jira_cloud.py +0 -0
  187. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/models.py +0 -0
  188. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/plugin.json +0 -0
  189. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/rules.py +0 -0
  190. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/schema_sync.py +0 -0
  191. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/jira_cloud/views.py +0 -0
  192. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/json/__init__.py +0 -0
  193. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/json/json.py +0 -0
  194. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/json/plugin.json +0 -0
  195. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ldap/__init__.py +0 -0
  196. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ldap/ldap.py +0 -0
  197. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/ldap/plugin.json +0 -0
  198. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/maintenance/__init__.py +0 -0
  199. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/maintenance/plugin.json +0 -0
  200. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/mssql/__init__.py +0 -0
  201. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/mssql/plugin.json +0 -0
  202. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/mysql/__init__.py +0 -0
  203. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/mysql/mysql.py +0 -0
  204. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/mysql/plugin.json +0 -0
  205. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/admin_views.py +0 -0
  206. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/cluster.py +0 -0
  207. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/contacts.py +0 -0
  208. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/dataflow.py +0 -0
  209. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/ips.py +0 -0
  210. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/models.py +0 -0
  211. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/netbox.py +0 -0
  212. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/networks.py +0 -0
  213. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/plugin.json +0 -0
  214. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/prefixes.py +0 -0
  215. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/rules.py +0 -0
  216. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/tests/__init__.py +0 -0
  217. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/views.py +0 -0
  218. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/netbox/virtualmachines.py +0 -0
  219. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/prtg/__init__.py +0 -0
  220. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/prtg/plugin.json +0 -0
  221. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/prtg/prtg.py +0 -0
  222. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/pyodbc/__init__.py +0 -0
  223. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/pyodbc/plugin.json +0 -0
  224. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/pyodbc/pyodbc.py +0 -0
  225. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rest/__init__.py +0 -0
  226. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rest/plugin.json +0 -0
  227. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rest/rest.py +0 -0
  228. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rules/__init__.py +0 -0
  229. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rules/admin_views.py +0 -0
  230. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rules/autorules.py +0 -0
  231. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rules/models.py +0 -0
  232. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rules/plugin.json +0 -0
  233. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rules/rule_definitions.py +0 -0
  234. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rules/rule_import_export.py +0 -0
  235. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/rules/views.py +0 -0
  236. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/syncer_shell.py +0 -0
  237. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/vmware/__init__.py +0 -0
  238. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/vmware/admin_views.py +0 -0
  239. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/vmware/custom_attributes.py +0 -0
  240. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/vmware/models.py +0 -0
  241. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/vmware/plugin.json +0 -0
  242. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/vmware/rules.py +0 -0
  243. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/vmware/views.py +0 -0
  244. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/vmware/vmware.py +0 -0
  245. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/yml/__init__.py +0 -0
  246. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/yml/plugin.json +0 -0
  247. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins/yml/yml.py +0 -0
  248. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/plugins_cli.py +0 -0
  249. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/static/cmdbsyncer_mark.png +0 -0
  250. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/static/css/cmdbsyncer.css +0 -0
  251. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/static/favicon.png +0 -0
  252. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/static/js/main.js +0 -0
  253. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/static/logo_white.png +0 -0
  254. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/_brand.html +0 -0
  255. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/_theme.html +0 -0
  256. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/_host_tabs.html +0 -0
  257. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/account_pick_type.html +0 -0
  258. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/ansible_playbook_run.html +0 -0
  259. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/ansible_project_detail.html +0 -0
  260. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/ansible_rule_list.html +0 -0
  261. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/ansible_run_details.html +0 -0
  262. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/bulk_label_form.html +0 -0
  263. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/changelog_archive.html +0 -0
  264. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_mngmt_list.html +0 -0
  265. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_edit.html +0 -0
  266. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_import.html +0 -0
  267. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_import_cmk.html +0 -0
  268. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_rule_project_list.html +0 -0
  269. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_settings_list.html +0 -0
  270. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/checkmk_test_folder_scope.html +0 -0
  271. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/copy_as_new_form.html +0 -0
  272. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/data_quality.html +0 -0
  273. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/file/list.html +0 -0
  274. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/file/modals/form.html +0 -0
  275. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/host_details.html +0 -0
  276. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/host_edit.html +0 -0
  277. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/host_inventory_tree.html +0 -0
  278. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/host_list.html +0 -0
  279. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/host_relations_graph.html +0 -0
  280. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/host_timeline.html +0 -0
  281. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/index.html +0 -0
  282. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/local_config_editor.html +0 -0
  283. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/master.html +0 -0
  284. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/model/clone_confirm.html +0 -0
  285. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/object_list.html +0 -0
  286. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/set_cmk_version_form.html +0 -0
  287. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/admin/set_template_form.html +0 -0
  288. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/base.html +0 -0
  289. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/change_password.html +0 -0
  290. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/debug.html +0 -0
  291. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/debug_host.html +0 -0
  292. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/email/newuser.html +0 -0
  293. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/email/notification.html +0 -0
  294. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/email/resetpassword.html +0 -0
  295. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/formular.html +0 -0
  296. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/license_info.html +0 -0
  297. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/login.html +0 -0
  298. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/logout_confirm.html +0 -0
  299. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/request_password.html +0 -0
  300. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/set_2fa.html +0 -0
  301. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/templates/set_theme.html +0 -0
  302. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/themes_registry.py +0 -0
  303. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/_form_fields.py +0 -0
  304. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/account.py +0 -0
  305. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/config.py +0 -0
  306. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/cron.py +0 -0
  307. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/data_quality.py +0 -0
  308. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/default.py +0 -0
  309. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/field_approval.py +0 -0
  310. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/fileadmin.py +0 -0
  311. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/host.py +0 -0
  312. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/host_filters.py +0 -0
  313. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/host_renderers.py +0 -0
  314. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/host_widgets.py +0 -0
  315. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/license.py +0 -0
  316. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/notification_channel.py +0 -0
  317. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/notification_rule.py +0 -0
  318. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/saved_search.py +0 -0
  319. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/application/views/user.py +0 -0
  320. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/dependency_links.txt +0 -0
  321. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/entry_points.txt +0 -0
  322. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/requires.txt +0 -0
  323. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/cmdbsyncer.egg-info/top_level.txt +0 -0
  324. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/requirements-ansible-windows.txt +0 -0
  325. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/requirements-ansible.txt +0 -0
  326. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/requirements-extras.txt +0 -0
  327. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/requirements.txt +0 -0
  328. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/setup.cfg +0 -0
  329. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/syncerapi/__init__.py +0 -0
  330. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/syncerapi/v1/__init__.py +0 -0
  331. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/syncerapi/v1/core/__init__.py +0 -0
  332. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/syncerapi/v1/inventory/__init__.py +0 -0
  333. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/syncerapi/v1/rest/__init__.py +0 -0
  334. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_account_macro.py +0 -0
  335. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_api.py +0 -0
  336. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_api_csrf_invariant.py +0 -0
  337. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_default_view.py +0 -0
  338. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_mongo_keys.py +0 -0
  339. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_plugin.py +0 -0
  340. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_plugin_ssti.py +0 -0
  341. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_plugins_cli.py +0 -0
  342. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_rule.py +0 -0
  343. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_rule_filename_detect.py +0 -0
  344. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_rule_match.py +0 -0
  345. {cmdbsyncer-4.2.3 → cmdbsyncer-4.2.4}/tests/test_search_parser.py +0 -0
  346. {cmdbsyncer-4.2.3 → 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
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,41 +1,48 @@
1
1
  # Version 4.2
2
2
 
3
- ## Version 4.2.3
3
+ ## Version 4.2.4
4
4
 
5
5
  ### Checkmk
6
- - 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
7
- - 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
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
8
19
 
9
- ## Version 4.2.2
20
+ ## Version 4.2.3
10
21
 
11
22
  ### Ansible
12
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
13
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)
14
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)
15
30
 
16
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
17
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
18
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
19
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
20
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
21
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
22
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
23
42
 
24
43
  ### Interface
25
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
26
45
 
27
- ## Version 4.2.1
28
-
29
- ### Ansible
30
- - 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
31
-
32
- ### Setup
33
- - 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)
34
-
35
- ### Checkmk
36
- - 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"
37
- - 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
38
-
39
46
  ## Version 4.2.0
40
47
 
41
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.
@@ -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
- payload = {
101
- "dcd_id": render_jinja(rule['dcd_id'], mode='raise', **attributes),
102
- "title": render_jinja(rule['title'], mode='raise', **attributes),
103
- "comment": render_jinja(rule['comment'], mode='raise',**attributes),
104
- "disabled": rule['disabled'],
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
- downtimes = response[0]['value']
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 CmkException as error_obj:
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'C{ColorCodes.FAIL}MK Connection Error: {error_obj} {ColorCodes.ENDC}')
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:
@@ -545,13 +551,19 @@ def export_dcd_rules(account, debug=False, debug_rules=False):
545
551
  # allows. Rules without a project stay global (exported everywhere),
546
552
  # matching the Setup-rule export.
547
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.
548
557
  actions.rules = CheckmkDCDRule.objects(
549
- enabled=True, project__in=allowed_projects)
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)
550
561
 
551
562
  if not debug_rules:
552
563
  syncer = CheckmkDCDRuleSync(account)
553
564
  syncer.debug = debug
554
565
  syncer.actions = actions
566
+ syncer.static_rules = static_rules
555
567
  syncer.rewrite = rules['rewrite']
556
568
  syncer.filter = rules['filter']
557
569
  syncer.name = 'Checkmk: Export DCD Rules'
@@ -560,6 +572,7 @@ def export_dcd_rules(account, debug=False, debug_rules=False):
560
572
  else:
561
573
  syncer = CheckmkDCDRuleSync(False)
562
574
  syncer.actions = actions
575
+ syncer.static_rules = static_rules
563
576
  syncer.rewrite = rules['rewrite']
564
577
  syncer.filter = rules['filter']
565
578
  syncer.debug_rules(debug_rules, "Checkmk")
@@ -690,6 +690,12 @@ 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
+
693
699
  # Name of the CheckmkRuleProject this DCD rule belongs to (or empty).
694
700
  # Referenced by name to match CheckmkRuleMngmt.project. A DCD rule assigned
695
701
  # to a project follows that project's account filter (limit_by_accounts) on
@@ -1022,10 +1022,10 @@ class SyncCMK2(CMK2):
1022
1022
  try:
1023
1023
  self.request(url, method="POST", data=body)
1024
1024
  self.num_created += 1
1025
+ self.console(f" * Created Host {hostname}")
1025
1026
  except CmkException as error:
1026
1027
  self.log_details.append(('error', f"Host Create Error: {error}"))
1027
1028
  self.console(f" * CMK API ERROR {error}")
1028
- self.console(f" * Created Host {hostname}")
1029
1029
 
1030
1030
 
1031
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({'ident':x, 'title': y})
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
- [{'ident': x['id'], 'title': x['title']} \
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['ident'] not in found:
374
- found.add(tag['ident'])
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['ident']))
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['ident']
403
+ del payload[id_field]
390
404
  payload['repair'] = False
391
405
  try:
392
- self.request(url,
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.")
@@ -975,9 +975,12 @@ class TestExportDcdRulesProjectFilter(unittest.TestCase):
975
975
  patch.object(inits, 'CheckmkDCDRule') as mock_dcd:
976
976
  mock_dcd.objects.return_value = ['rule']
977
977
  inits.export_dcd_rules('acc_a')
978
- # Global (no project) rules plus the projects this account is allowed.
979
- mock_dcd.objects.assert_called_once_with(
980
- enabled=True, project__in=[None, '', 'proj_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'])
981
984
 
982
985
 
983
986
  if __name__ == '__main__':
@@ -171,6 +171,62 @@ class TestCheckmkDCDRuleSync(unittest.TestCase):
171
171
  result = self.sync.build_rule_payload(rule, {})
172
172
  self.assertEqual(result, {})
173
173
 
174
+ def _payload_rule(self):
175
+ return {
176
+ 'dcd_id': 'dcd1', 'title': 'T', 'comment': '', 'disabled': False,
177
+ 'site': 'site1', 'connector_type': 'piggyback',
178
+ 'restricted_source_hosts': [], 'interval': '60',
179
+ 'creation_rules': [], 'activate_changes_interval': '300',
180
+ 'discover_on_creation': True, 'exclude_time_ranges': [],
181
+ 'no_deletion_time_after_init': '120', 'max_cache_age': '3600',
182
+ 'validity_period': '60', 'documentation_url': '',
183
+ }
184
+
185
+ @patch('application.plugins.checkmk.dcd.render_jinja')
186
+ def test_payload_nests_connector_on_24plus(self, mock_render):
187
+ # Checkmk 2.4+ wants the connector settings nested under "connector"
188
+ # and no longer accepts the two 2.3-only fields.
189
+ mock_render.side_effect = lambda tpl, **kw: tpl
190
+ self.sync.checkmk_version = '2.4.0p19.cee'
191
+ result = self.sync.build_rule_payload(self._payload_rule(), {})
192
+ self.assertIn('connector', result)
193
+ self.assertNotIn('connector_type', result) # not at top level
194
+ conn = result['connector']
195
+ self.assertEqual(conn['connector_type'], 'piggyback')
196
+ self.assertIn('interval', conn)
197
+ self.assertNotIn('activate_changes_interval', conn)
198
+ self.assertNotIn('exclude_time_ranges', conn)
199
+
200
+ @patch('application.plugins.checkmk.dcd.render_jinja')
201
+ def test_payload_connector_keeps_23_fields(self, mock_render):
202
+ mock_render.side_effect = lambda tpl, **kw: tpl
203
+ self.sync.checkmk_version = '2.3.0p48.cce'
204
+ conn = self.sync.build_rule_payload(self._payload_rule(), {})['connector']
205
+ self.assertIn('activate_changes_interval', conn)
206
+ self.assertIn('exclude_time_ranges', conn)
207
+
208
+ def test_account_site(self):
209
+ self.sync.config = {'address': 'http://host:8080/cmk/'}
210
+ self.assertEqual(self.sync._account_site(), 'cmk')
211
+ self.sync.config = {'address': 'https://mon.example.com/prod'}
212
+ self.assertEqual(self.sync._account_site(), 'prod')
213
+ self.sync.config = {'address': ''}
214
+ self.assertEqual(self.sync._account_site(), '')
215
+
216
+ def test_account_context_exposes_fields_without_secrets(self):
217
+ self.sync.config = {
218
+ 'name': 'prod', 'address': 'http://h/cmk', 'username': 'auto',
219
+ 'my_field': 'x', 'password': 'secret',
220
+ 'bakery_passphrase': 'p', '_id': 1,
221
+ }
222
+ ctx = self.sync._account_context()
223
+ # custom + standard fields are exposed
224
+ self.assertEqual(ctx['name'], 'prod')
225
+ self.assertEqual(ctx['my_field'], 'x')
226
+ # secrets / internal ids are withheld
227
+ for hidden in ('password', 'bakery_passphrase', '_id'):
228
+ self.assertNotIn(hidden, ctx)
229
+
174
230
  def test_create_rule_in_cmk(self):
175
231
  with patch.object(self.sync, 'request') as mock_req:
176
232
  mock_req.return_value = (None, {})
@@ -236,5 +236,46 @@ class TestCheckmkTagSync(unittest.TestCase):
236
236
  self.assertEqual(result['grp1'], ('pre_id', 'Pre Title'))
237
237
 
238
238
 
239
+ class TestTagIdFieldSwitch(unittest.TestCase):
240
+ """The host tag group id field switch (ident vs id) by Checkmk version."""
241
+
242
+ def setUp(self):
243
+ def mock_init(self_param, account=False):
244
+ base_mock_init(self_param, groups={})
245
+
246
+ self.init_patcher = patch(
247
+ 'application.plugins.checkmk.tags.CMK2.__init__', mock_init)
248
+ self.init_patcher.start()
249
+ self.sync = CheckmkTagSync()
250
+
251
+ def tearDown(self):
252
+ self.init_patcher.stop()
253
+
254
+ def test_tag_id_field_by_version(self):
255
+ cases = {
256
+ '2.2.0p1': 'ident',
257
+ '2.3.0p48.cre': 'ident',
258
+ '2.4.0p19.cee': 'id',
259
+ '2.5.0p8.pro': 'id',
260
+ '3.0.0': 'id',
261
+ '': 'id', # unknown -> assume modern
262
+ 'garbage': 'id',
263
+ }
264
+ for version, expected in cases.items():
265
+ self.sync.checkmk_version = version
266
+ self.assertEqual(self.sync._tag_id_field(), expected,
267
+ f"version {version!r}")
268
+
269
+ def test_prepare_tags_uses_ident_on_23(self):
270
+ self.sync.checkmk_version = '2.3.0p48.cre'
271
+ tags = self.sync.prepare_tags_for_checkmk([('v1', 'Val1')])
272
+ self.assertEqual(tags, [{'ident': 'v1', 'title': 'Val1'}])
273
+
274
+ def test_prepare_tags_uses_id_on_24plus(self):
275
+ self.sync.checkmk_version = '2.4.0p19.cee'
276
+ tags = self.sync.prepare_tags_for_checkmk([('v1', 'Val1')])
277
+ self.assertEqual(tags, [{'id': 'v1', 'title': 'Val1'}])
278
+
279
+
239
280
  if __name__ == '__main__':
240
281
  unittest.main(verbosity=2)
@@ -1854,7 +1854,7 @@ class CheckmkDCDView(RuleModelView):
1854
1854
  rules.Field('documentation'),
1855
1855
  rules.Field('project'),
1856
1856
  div_open,
1857
- rules.NestedRule(('enabled', 'last_match')),
1857
+ rules.NestedRule(('enabled', 'last_match', 'static_rule')),
1858
1858
  div_close,
1859
1859
  rules.Field('sort_field'),
1860
1860
  ],
@@ -1888,6 +1888,30 @@ class CheckmkDCDView(RuleModelView):
1888
1888
  "rule is exported only to the accounts the project allows (a "
1889
1889
  "project without an account filter still exports everywhere)."
1890
1890
  )
1891
+ self.form_descriptions['static_rule'] = (
1892
+ "Host-independent rule: render it once and always create it, "
1893
+ "ignoring the match conditions. A DCD connection rarely depends on "
1894
+ "host data, so this skips the per-host calculation and is much "
1895
+ "faster on large inventories. Use only when the outcome templates "
1896
+ "reference no host attributes."
1897
+ )
1898
+
1899
+ # Hint the {{ cmk_site }} macro in the outcome's Site field so users see
1900
+ # they can target the exporting account's own Checkmk site (test/prod).
1901
+ base_subdocs = dict(getattr(self, 'form_subdocuments', None) or {})
1902
+ base_subdocs['outcomes'] = {
1903
+ 'form_subdocuments': {
1904
+ '': {
1905
+ 'form_widget_args': {
1906
+ 'site': {
1907
+ 'placeholder':
1908
+ '{{ cmk_site }} — the exporting account\'s site',
1909
+ },
1910
+ },
1911
+ },
1912
+ },
1913
+ }
1914
+ self.form_subdocuments = base_subdocs
1891
1915
 
1892
1916
  super().__init__(model, **kwargs)
1893
1917
 
@@ -277,6 +277,46 @@ def cli_netbox_vm_import(account, debug=False):
277
277
  netbox_vm_import(account, debug)
278
278
  register_cronjob("Netbox: Import VMs", netbox_vm_import)
279
279
  #.
280
+ # .-- Command: Import DCIM Interfaces
281
+ def netbox_interface_import(account, debug=False):
282
+ """Import DCIM Interfaces from Netbox"""
283
+ try:
284
+ syncer = SyncInterfaces(account)
285
+ syncer.debug = debug
286
+ syncer.import_interfaces()
287
+ except Exception as error_obj: # pylint: disable=broad-exception-caught
288
+ if debug:
289
+ raise
290
+ print(f'{cc.FAIL}Connection Error: {error_obj} {cc.ENDC}')
291
+
292
+ @cli_netbox.command('import_dcim_interfaces')
293
+ @click.argument("account")
294
+ @click.option("--debug", is_flag=True)
295
+ def cli_netbox_interface_import(account, debug=False):
296
+ """Import Interfaces of Devices from Netbox"""
297
+ netbox_interface_import(account, debug)
298
+ register_cronjob("Netbox: Import DCIM Interfaces", netbox_interface_import)
299
+ #.
300
+ # .-- Command: Import Virtualization Interfaces
301
+ def netbox_virt_interface_import(account, debug=False):
302
+ """Import Virtualization Interfaces from Netbox"""
303
+ try:
304
+ syncer = SyncVirtInterfaces(account)
305
+ syncer.debug = debug
306
+ syncer.import_interfaces(mode='virtualization')
307
+ except Exception as error_obj: # pylint: disable=broad-exception-caught
308
+ if debug:
309
+ raise
310
+ print(f'{cc.FAIL}Connection Error: {error_obj} {cc.ENDC}')
311
+
312
+ @cli_netbox.command('import_virt_interfaces')
313
+ @click.argument("account")
314
+ @click.option("--debug", is_flag=True)
315
+ def cli_netbox_virt_interface_import(account, debug=False):
316
+ """Import Interfaces of Virtual Machines from Netbox"""
317
+ netbox_virt_interface_import(account, debug)
318
+ register_cronjob("Netbox: Import Virtualization Interfaces", netbox_virt_interface_import)
319
+ #.
280
320
  # .-- Command: Export IPs
281
321
  def netbox_ip_sync(account, debug=False, debug_rules=False):
282
322
  """Import Devices from Netbox"""