cmdbsyncer 4.4.1__tar.gz → 4.4.2__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 (506) hide show
  1. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/PKG-INFO +1 -1
  2. cmdbsyncer-4.4.2/application/buildinfo.txt +1 -0
  3. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v4.4.md +10 -0
  4. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/get_account.py +13 -8
  5. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/account.py +16 -9
  6. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/runner.py +14 -4
  7. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/tests/test_runner_ssh_env.py +37 -1
  8. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/cmk_rules.py +24 -15
  9. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/dcd.py +5 -1
  10. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/syncer.py +3 -1
  11. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_cmk_rules.py +56 -0
  12. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_dcd.py +8 -0
  13. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_syncer.py +4 -3
  14. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/cron.py +33 -3
  15. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/dataflow.py +2 -1
  16. cmdbsyncer-4.4.2/application/plugins/netbox/tests/test_same_host_url.py +29 -0
  17. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/utils.py +13 -0
  18. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/cmdbsyncer.egg-info/PKG-INFO +1 -1
  19. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/cmdbsyncer.egg-info/SOURCES.txt +3 -0
  20. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/pyproject.toml +1 -1
  21. cmdbsyncer-4.4.2/tests/test_account_master_cache_smoke.py +50 -0
  22. cmdbsyncer-4.4.2/tests/test_cron_stale_lock_smoke.py +57 -0
  23. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_security_fixes.py +23 -0
  24. cmdbsyncer-4.4.1/application/buildinfo.txt +0 -1
  25. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/LICENSE +0 -0
  26. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/README.md +0 -0
  27. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/__init__.py +0 -0
  28. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/_version.py +0 -0
  29. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/api/__init__.py +0 -0
  30. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/api/inventory.py +0 -0
  31. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/api/objects.py +0 -0
  32. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/api/rules.py +0 -0
  33. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/api/syncer.py +0 -0
  34. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/api/views.py +0 -0
  35. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/auth/views.py +0 -0
  36. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/.pages +0 -0
  37. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v3.10.md +0 -0
  38. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v3.11.md +0 -0
  39. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v3.12.md +0 -0
  40. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v3.5.md +0 -0
  41. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v3.7.md +0 -0
  42. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v3.8.md +0 -0
  43. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v3.9.md +0 -0
  44. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v4.0.md +0 -0
  45. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v4.1.md +0 -0
  46. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v4.2.md +0 -0
  47. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/changelog/v4.3.md +0 -0
  48. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/cli.py +0 -0
  49. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/config.py +0 -0
  50. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/docu_links.py +0 -0
  51. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/enterprise.py +0 -0
  52. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/__init__.py +0 -0
  53. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/audit.py +0 -0
  54. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/cron.py +0 -0
  55. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/db_analysis.py +0 -0
  56. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/host_maintenance.py +0 -0
  57. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/import_hostnames.py +0 -0
  58. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/inventory.py +0 -0
  59. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/label_hash.py +0 -0
  60. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/label_history.py +0 -0
  61. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/local_config_file.py +0 -0
  62. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/local_config_presets.py +0 -0
  63. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/mongo_keys.py +0 -0
  64. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/notification_channels.py +0 -0
  65. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/notification_dispatch.py +0 -0
  66. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/plugins.py +0 -0
  67. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/retention.py +0 -0
  68. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/sates.py +0 -0
  69. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/sql.py +0 -0
  70. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/stale_indexes.py +0 -0
  71. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/syncer_jinja.py +0 -0
  72. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/tablib_formater.py +0 -0
  73. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/tests/__init__.py +0 -0
  74. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/tests/test_sql.py +0 -0
  75. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/helpers/timezone.py +0 -0
  76. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/mcp_server.py +0 -0
  77. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/__init__.py +0 -0
  78. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/config.py +0 -0
  79. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/cron.py +0 -0
  80. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/field_approval.py +0 -0
  81. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/forms.py +0 -0
  82. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/host.py +0 -0
  83. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/host_cleanup.py +0 -0
  84. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/host_create_time.py +0 -0
  85. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/host_inventory_tree.py +0 -0
  86. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/host_label_event.py +0 -0
  87. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/host_labels.py +0 -0
  88. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/host_templates.py +0 -0
  89. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/notification_channel.py +0 -0
  90. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/notification_rule.py +0 -0
  91. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/notification_state.py +0 -0
  92. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/project.py +0 -0
  93. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/saved_search.py +0 -0
  94. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/states.py +0 -0
  95. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/models/user.py +0 -0
  96. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/module_registry.py +0 -0
  97. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/__init__.py +0 -0
  98. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/custom_attributes/models.py +0 -0
  99. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/custom_attributes/rules.py +0 -0
  100. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/custom_attributes/views.py +0 -0
  101. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/debug.py +0 -0
  102. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/email.py +0 -0
  103. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/inventory/__init__.py +0 -0
  104. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/log/command_output.py +0 -0
  105. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/log/log.py +0 -0
  106. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/log/models.py +0 -0
  107. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/log/views.py +0 -0
  108. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/plugin.py +0 -0
  109. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/__init__.py +0 -0
  110. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/filter.py +0 -0
  111. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/list_source.py +0 -0
  112. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/list_source_views.py +0 -0
  113. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/match.py +0 -0
  114. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/models.py +0 -0
  115. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/rewrite.py +0 -0
  116. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/rule.py +0 -0
  117. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/rule/views.py +0 -0
  118. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/search_parser.py +0 -0
  119. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/modules/statefile.py +0 -0
  120. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/notices/strict_certificate_verification.txt +0 -0
  121. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/__init__.py +0 -0
  122. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/__init__.py +0 -0
  123. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/admin_views.py +0 -0
  124. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/inventory.py +0 -0
  125. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/models.py +0 -0
  126. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/playbook_rules.py +0 -0
  127. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/plugin.json +0 -0
  128. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/rules.py +0 -0
  129. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/seed.py +0 -0
  130. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/site_syncer.py +0 -0
  131. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/tests/__init__.py +0 -0
  132. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ansible/views.py +0 -0
  133. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/bmc_remedy/__init__.py +0 -0
  134. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/bmc_remedy/bmc_remedy.py +0 -0
  135. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/bmc_remedy/plugin.json +0 -0
  136. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/__init__.py +0 -0
  137. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/admin_views.py +0 -0
  138. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/bi.py +0 -0
  139. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/cmk2.py +0 -0
  140. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/data/ruleset_examples.json +0 -0
  141. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/data/rulesets_2.4.json +0 -0
  142. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/data/rulesets_2.5.json +0 -0
  143. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/data_quality.py +0 -0
  144. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/downtimes.py +0 -0
  145. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/folder_attributes.py +0 -0
  146. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/groups.py +0 -0
  147. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/helpers.py +0 -0
  148. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/import_v1.py +0 -0
  149. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/import_v2.py +0 -0
  150. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/inits.py +0 -0
  151. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/inventorize.py +0 -0
  152. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/list_source.py +0 -0
  153. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/models.py +0 -0
  154. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/notification_rules.py +0 -0
  155. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/passwords.py +0 -0
  156. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/plugin.json +0 -0
  157. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/poolfolder.py +0 -0
  158. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/rule_analysis_runner.py +0 -0
  159. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/rule_passwords.py +0 -0
  160. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/rules.py +0 -0
  161. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/rulesets_catalog.py +0 -0
  162. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/sitepool.py +0 -0
  163. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/sites.py +0 -0
  164. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tags.py +0 -0
  165. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/__init__.py +0 -0
  166. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_assign_template.py +0 -0
  167. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_bi.py +0 -0
  168. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_cmk2.py +0 -0
  169. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_cmk_conditions.py +0 -0
  170. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_data_quality.py +0 -0
  171. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_downtimes.py +0 -0
  172. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_groups.py +0 -0
  173. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_helpers.py +0 -0
  174. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_import_v1.py +0 -0
  175. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_import_v2.py +0 -0
  176. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_inventorize.py +0 -0
  177. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_list_source.py +0 -0
  178. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_notification_rules.py +0 -0
  179. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_passwords.py +0 -0
  180. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_poolfolder.py +0 -0
  181. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_rule_analysis_runner.py +0 -0
  182. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_rule_passwords.py +0 -0
  183. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_rules.py +0 -0
  184. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_sitepool.py +0 -0
  185. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_sites.py +0 -0
  186. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_tags.py +0 -0
  187. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_user_generation.py +0 -0
  188. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/tests/test_users.py +0 -0
  189. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/user_generation.py +0 -0
  190. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/user_models.py +0 -0
  191. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/users.py +0 -0
  192. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/checkmk/views.py +0 -0
  193. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/cisco_dna/__init__.py +0 -0
  194. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/cisco_dna/plugin.json +0 -0
  195. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/cisco_dna/syncer.py +0 -0
  196. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/csv/__init__.py +0 -0
  197. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/csv/csv.py +0 -0
  198. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/csv/plugin.json +0 -0
  199. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/__init__.py +0 -0
  200. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/admin_views.py +0 -0
  201. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/models.py +0 -0
  202. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/plugin.json +0 -0
  203. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/repeats.py +0 -0
  204. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/rules.py +0 -0
  205. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/sender.py +0 -0
  206. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/tests/__init__.py +0 -0
  207. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/tests/test_eda.py +0 -0
  208. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/tests/test_repeats.py +0 -0
  209. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/eda/views.py +0 -0
  210. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/file_requests.py +0 -0
  211. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/idoit/__init__.py +0 -0
  212. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/idoit/admin_views.py +0 -0
  213. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/idoit/models.py +0 -0
  214. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/idoit/plugin.json +0 -0
  215. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/idoit/rules.py +0 -0
  216. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/idoit/syncer.py +0 -0
  217. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/idoit/views.py +0 -0
  218. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jdisc/__init__.py +0 -0
  219. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jdisc/applications.py +0 -0
  220. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jdisc/devices.py +0 -0
  221. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jdisc/executables.py +0 -0
  222. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jdisc/jdisc.py +0 -0
  223. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jdisc/plugin.json +0 -0
  224. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira/__init__.py +0 -0
  225. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira/jira.py +0 -0
  226. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira/plugin.json +0 -0
  227. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/__init__.py +0 -0
  228. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/admin_views.py +0 -0
  229. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/export.py +0 -0
  230. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/jira_cloud.py +0 -0
  231. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/models.py +0 -0
  232. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/plugin.json +0 -0
  233. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/rules.py +0 -0
  234. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/schema_sync.py +0 -0
  235. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/tests/__init__.py +0 -0
  236. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/tests/test_attribute_value.py +0 -0
  237. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/jira_cloud/views.py +0 -0
  238. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/json/__init__.py +0 -0
  239. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/json/json.py +0 -0
  240. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/json/plugin.json +0 -0
  241. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ldap/__init__.py +0 -0
  242. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ldap/admin_views.py +0 -0
  243. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ldap/ldap.py +0 -0
  244. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ldap/plugin.json +0 -0
  245. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/ldap/views.py +0 -0
  246. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/maintenance/__init__.py +0 -0
  247. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/maintenance/db_commands.py +0 -0
  248. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/maintenance/plugin.json +0 -0
  249. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/maintenance/tests/__init__.py +0 -0
  250. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/maintenance/tests/test_delete_all_hosts.py +0 -0
  251. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/maintenance/tests/test_delete_inventory.py +0 -0
  252. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/mssql/__init__.py +0 -0
  253. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/mssql/plugin.json +0 -0
  254. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/mysql/__init__.py +0 -0
  255. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/mysql/mysql.py +0 -0
  256. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/mysql/plugin.json +0 -0
  257. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/__init__.py +0 -0
  258. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/admin_views.py +0 -0
  259. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/cluster.py +0 -0
  260. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/contacts.py +0 -0
  261. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/devices.py +0 -0
  262. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/interfaces.py +0 -0
  263. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/ips.py +0 -0
  264. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/models.py +0 -0
  265. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/netbox.py +0 -0
  266. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/networks.py +0 -0
  267. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/plugin.json +0 -0
  268. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/prefixes.py +0 -0
  269. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/rules.py +0 -0
  270. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/tests/__init__.py +0 -0
  271. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/tests/test_import_filter.py +0 -0
  272. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/views.py +0 -0
  273. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/netbox/virtualmachines.py +0 -0
  274. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/prtg/__init__.py +0 -0
  275. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/prtg/plugin.json +0 -0
  276. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/prtg/prtg.py +0 -0
  277. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/pyodbc/__init__.py +0 -0
  278. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/pyodbc/plugin.json +0 -0
  279. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/pyodbc/pyodbc.py +0 -0
  280. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rest/__init__.py +0 -0
  281. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rest/plugin.json +0 -0
  282. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rest/rest.py +0 -0
  283. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rules/__init__.py +0 -0
  284. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rules/admin_views.py +0 -0
  285. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rules/autorules.py +0 -0
  286. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rules/models.py +0 -0
  287. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rules/plugin.json +0 -0
  288. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rules/rule_definitions.py +0 -0
  289. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rules/rule_import_export.py +0 -0
  290. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/rules/views.py +0 -0
  291. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/servicenow/__init__.py +0 -0
  292. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/servicenow/admin_views.py +0 -0
  293. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/servicenow/plugin.json +0 -0
  294. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/servicenow/syncer.py +0 -0
  295. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/servicenow/tests/__init__.py +0 -0
  296. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/servicenow/tests/test_table_request.py +0 -0
  297. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/servicenow/views.py +0 -0
  298. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/syncer_shell.py +0 -0
  299. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/vmware/__init__.py +0 -0
  300. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/vmware/admin_views.py +0 -0
  301. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/vmware/custom_attributes.py +0 -0
  302. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/vmware/models.py +0 -0
  303. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/vmware/plugin.json +0 -0
  304. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/vmware/rules.py +0 -0
  305. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/vmware/views.py +0 -0
  306. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/vmware/vmware.py +0 -0
  307. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/yml/__init__.py +0 -0
  308. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/yml/plugin.json +0 -0
  309. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins/yml/yml.py +0 -0
  310. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/plugins_cli.py +0 -0
  311. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/cmdbsyncer_mark.png +0 -0
  312. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/css/cmdbsyncer.css +0 -0
  313. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/favicon.png +0 -0
  314. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/js/Sortable.min.js +0 -0
  315. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/js/main.js +0 -0
  316. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/logo_white.png +0 -0
  317. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/vendor/README.md +0 -0
  318. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/vendor/ansible.svg +0 -0
  319. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/vendor/checkmk.svg +0 -0
  320. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/vendor/idoit.svg +0 -0
  321. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/vendor/jira.svg +0 -0
  322. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/vendor/netbox.svg +0 -0
  323. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/static/vendor/vmware.svg +0 -0
  324. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/_brand.html +0 -0
  325. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/_theme.html +0 -0
  326. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/_timezone.html +0 -0
  327. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/_host_tabs.html +0 -0
  328. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/account_create.html +0 -0
  329. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/account_edit.html +0 -0
  330. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/account_field_help.html +0 -0
  331. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/account_pick_type.html +0 -0
  332. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/ansible_playbook_run.html +0 -0
  333. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/ansible_project_detail.html +0 -0
  334. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/ansible_rule_list.html +0 -0
  335. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/ansible_run_details.html +0 -0
  336. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/assign_project_form.html +0 -0
  337. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/bulk_label_form.html +0 -0
  338. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/changelog_archive.html +0 -0
  339. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/checkmk_data_quality.html +0 -0
  340. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/checkmk_list_rule_debug.html +0 -0
  341. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/checkmk_rule_mngmt_list.html +0 -0
  342. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/checkmk_rule_optimization.html +0 -0
  343. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/checkmk_settings_list.html +0 -0
  344. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/checkmk_test_folder_scope.html +0 -0
  345. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/checkmk_user_generation_preview.html +0 -0
  346. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/checkmk_user_generation_rule_list.html +0 -0
  347. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/copy_as_new_form.html +0 -0
  348. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/data_quality.html +0 -0
  349. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/data_quality_lowercase_preview.html +0 -0
  350. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/file/list.html +0 -0
  351. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/file/modals/form.html +0 -0
  352. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/first_steps.html +0 -0
  353. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/host_csv_import_preview.html +0 -0
  354. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/host_details.html +0 -0
  355. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/host_edit.html +0 -0
  356. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/host_inventory_tree.html +0 -0
  357. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/host_list.html +0 -0
  358. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/host_relations_graph.html +0 -0
  359. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/host_timeline.html +0 -0
  360. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/index.html +0 -0
  361. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/ldap_search.html +0 -0
  362. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/local_config_editor.html +0 -0
  363. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/master.html +0 -0
  364. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/_action_picker.html +0 -0
  365. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/_folder_builder.html +0 -0
  366. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/_list_source_preview.html +0 -0
  367. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/_notification_plugin_picker.html +0 -0
  368. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/_ruleset_autocomplete.html +0 -0
  369. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/checkmk_notification_rule_create.html +0 -0
  370. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/checkmk_notification_rule_edit.html +0 -0
  371. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/checkmk_rule_create.html +0 -0
  372. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/checkmk_rule_edit.html +0 -0
  373. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/checkmk_rule_mngmt_create.html +0 -0
  374. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/checkmk_rule_mngmt_edit.html +0 -0
  375. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/clone_confirm.html +0 -0
  376. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/inline_list_base.html +0 -0
  377. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/list_source_create.html +0 -0
  378. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/model/list_source_edit.html +0 -0
  379. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/module_overview.html +0 -0
  380. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/object_list.html +0 -0
  381. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/project_edit.html +0 -0
  382. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/project_import.html +0 -0
  383. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/project_import_cmk.html +0 -0
  384. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/project_list.html +0 -0
  385. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/project_overview.html +0 -0
  386. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/servicenow_query.html +0 -0
  387. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/set_account_form.html +0 -0
  388. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/set_cmk_version_form.html +0 -0
  389. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/admin/set_template_form.html +0 -0
  390. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/api_tokens.html +0 -0
  391. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/base.html +0 -0
  392. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/change_password.html +0 -0
  393. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/csrf_error.html +0 -0
  394. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/debug.html +0 -0
  395. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/debug_host.html +0 -0
  396. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/email/newuser.html +0 -0
  397. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/email/notification.html +0 -0
  398. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/email/resetpassword.html +0 -0
  399. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/formular.html +0 -0
  400. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/license_info.html +0 -0
  401. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/login.html +0 -0
  402. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/logout_confirm.html +0 -0
  403. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/request_password.html +0 -0
  404. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/set_2fa.html +0 -0
  405. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/templates/set_theme.html +0 -0
  406. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/themes/dracula.css +0 -0
  407. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/themes/gruvbox-dark.css +0 -0
  408. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/themes/gruvbox-light.css +0 -0
  409. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/themes/nord.css +0 -0
  410. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/themes_registry.py +0 -0
  411. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/_form_fields.py +0 -0
  412. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/_form_sections.py +0 -0
  413. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/account.py +0 -0
  414. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/account_select.py +0 -0
  415. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/config.py +0 -0
  416. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/cron.py +0 -0
  417. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/data_quality.py +0 -0
  418. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/default.py +0 -0
  419. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/field_approval.py +0 -0
  420. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/fileadmin.py +0 -0
  421. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/first_steps.py +0 -0
  422. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/host.py +0 -0
  423. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/host_filters.py +0 -0
  424. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/host_inventory_grid.py +0 -0
  425. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/host_renderers.py +0 -0
  426. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/host_widgets.py +0 -0
  427. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/license.py +0 -0
  428. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/menu_links.py +0 -0
  429. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/module_overview.py +0 -0
  430. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/notification_channel.py +0 -0
  431. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/notification_rule.py +0 -0
  432. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/project.py +0 -0
  433. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/saved_search.py +0 -0
  434. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/template_select.py +0 -0
  435. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/application/views/user.py +0 -0
  436. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/cmdbsyncer.egg-info/dependency_links.txt +0 -0
  437. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/cmdbsyncer.egg-info/entry_points.txt +0 -0
  438. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/cmdbsyncer.egg-info/requires.txt +0 -0
  439. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/cmdbsyncer.egg-info/top_level.txt +0 -0
  440. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/requirements-ansible-windows.txt +0 -0
  441. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/requirements-ansible.txt +0 -0
  442. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/requirements-extras.txt +0 -0
  443. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/requirements.txt +0 -0
  444. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/setup.cfg +0 -0
  445. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/syncerapi/__init__.py +0 -0
  446. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/syncerapi/v1/__init__.py +0 -0
  447. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/syncerapi/v1/core/__init__.py +0 -0
  448. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/syncerapi/v1/inventory/__init__.py +0 -0
  449. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/syncerapi/v1/rest/__init__.py +0 -0
  450. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_account_macro.py +0 -0
  451. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_active_templates.py +0 -0
  452. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_ansible_cmk_roles.py +0 -0
  453. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_ansible_inventory.py +0 -0
  454. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_api.py +0 -0
  455. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_api_csrf_invariant.py +0 -0
  456. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_config_dir.py +0 -0
  457. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_cron_missing_account.py +0 -0
  458. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_csrf_config.py +0 -0
  459. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_data_quality_duplicates.py +0 -0
  460. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_default_view.py +0 -0
  461. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_disabled_row_style.py +0 -0
  462. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_eda_web_smoke.py +0 -0
  463. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_enterprise_quiet.py +0 -0
  464. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_folder_builder_js.py +0 -0
  465. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_global_account_presets.py +0 -0
  466. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_host_cleanup.py +0 -0
  467. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_host_create_time.py +0 -0
  468. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_host_label_edit.py +0 -0
  469. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_host_roundtrip_smoke.py +0 -0
  470. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_host_template_filter.py +0 -0
  471. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_host_template_resync.py +0 -0
  472. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_import_hostnames.py +0 -0
  473. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_jinja_get_list.py +0 -0
  474. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_jinja_hash.py +0 -0
  475. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_label_history.py +0 -0
  476. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_ldap_search_filter.py +0 -0
  477. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_local_config_presets.py +0 -0
  478. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_logging_config.py +0 -0
  479. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_model_indexes.py +0 -0
  480. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_mongo_keys.py +0 -0
  481. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_plugin.py +0 -0
  482. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_plugin_ssti.py +0 -0
  483. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_plugins_cli.py +0 -0
  484. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_regex_condition_limits.py +0 -0
  485. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_rule.py +0 -0
  486. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_rule_export_templates.py +0 -0
  487. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_rule_filename_detect.py +0 -0
  488. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_rule_import_override.py +0 -0
  489. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_rule_list_rows.py +0 -0
  490. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_rule_list_source.py +0 -0
  491. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_rule_match.py +0 -0
  492. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_rule_registry_complete.py +0 -0
  493. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_search_parser.py +0 -0
  494. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_stale_indexes.py +0 -0
  495. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_template_merge_fields.py +0 -0
  496. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_timezone.py +0 -0
  497. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_user_scope_smoke.py +0 -0
  498. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_view_permission_flags.py +0 -0
  499. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_web_account_password_chars.py +0 -0
  500. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_web_account_password_deferred_save.py +0 -0
  501. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_web_ansible_account_inventory.py +0 -0
  502. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_web_boot_smoke.py +0 -0
  503. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_web_debug_pages.py +0 -0
  504. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_web_list_source.py +0 -0
  505. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/tests/test_web_requests_smoke.py +0 -0
  506. {cmdbsyncer-4.4.1 → cmdbsyncer-4.4.2}/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.4.1
3
+ Version: 4.4.2
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-11-10T09:35:59Z
@@ -1,5 +1,15 @@
1
1
  # Version 4.4
2
2
 
3
+ ## Version 4.4.2
4
+ - SEC: Netbox Dataflow: the API token only goes to the address of the account; a page link of the answer pointing to another host no longer gets it
5
+ - FIX: Cron Groups: after a restart of the container a group no longer stays marked as running, when another process got the number of its old run
6
+ - FIX: Accounts: a change, like the master flag, reaches every process of the web interface and REST API within a minute; before, some kept the old account until a restart
7
+ - FIX: Checkmk: a host export with --limit creates a host that a rule turns into a cluster right away; before, the host was deleted and only came back as cluster with the next full run
8
+ - FIX: Checkmk DCD Rules: Restrict Source Hosts renders Jinja like the other fields, e.g. {{ HOSTNAME }}; a line that renders empty is left out
9
+ - FIX: Checkmk: rule export: a rule with a stored password, for example Kubernetes on Checkmk 2.5, is no longer updated on every run
10
+ - FIX: Ansible: playbooks started from the web interface find ansible-playbook in the Syncer's venv, also when the web server runs under systemd without the venv on its PATH
11
+ - FIX: Checkmk: Manage OMD Server creates a missing site again, including the initial cmkadmin password, instead of failing on the update step
12
+
3
13
  ## Version 4.4.1
4
14
  - FIX: REST import: entries without the hostname field are skipped instead of aborting the whole import
5
15
  - FIX: Checkmk users: an empty row under Roles or Contact Groups is no longer sent to Checkmk, which rejected the user because of it
@@ -2,6 +2,7 @@
2
2
  Helper to get Account
3
3
  """
4
4
  import copy
5
+ import time
5
6
  from contextlib import contextmanager
6
7
  from contextvars import ContextVar
7
8
 
@@ -67,11 +68,13 @@ _CHILD_OWNED_FIELDS = ('typ', 'username', 'password', 'address', 'object_type')
67
68
  # Internal serialisation artefacts that never leave this layer.
68
69
  _INTERNAL_FIELDS = ('custom_fields', 'password_crypted', 'plugin_settings')
69
70
 
70
- # In-process cache: ``{(lookup_key, is_id): account_dict}``. Sync runs read
71
- # the same handful of accounts for every host/rule, so caching keeps Mongo
72
- # and the secrets-manager hook off the hot path. Invalidated on Account
73
- # save/delete via mongoengine signals so the web app picks up edits
74
- # without a process restart.
71
+ # In-process cache: ``{(lookup_key, is_id): (loaded_at, account_dict)}``.
72
+ # Sync runs read the same handful of accounts for every host/rule, so
73
+ # caching keeps Mongo and the secrets-manager hook off the hot path.
74
+ # Account save/delete clears it through mongoengine signals, but only in
75
+ # the process that saved; the other web workers read the account again
76
+ # after ACCOUNT_CACHE_SECONDS.
77
+ ACCOUNT_CACHE_SECONDS = 60
75
78
  _account_cache = {}
76
79
 
77
80
 
@@ -177,10 +180,12 @@ def get_account_by_name(name, is_id=False):
177
180
  Get Account by Name or Return False
178
181
  """
179
182
  cache_key = (str(name), is_id)
180
- cached = _account_cache.get(cache_key)
181
- if cached is None:
183
+ entry = _account_cache.get(cache_key)
184
+ if entry and time.monotonic() - entry[0] < ACCOUNT_CACHE_SECONDS:
185
+ cached = entry[1]
186
+ else:
182
187
  cached = _build_account_dict(name, is_id)
183
- _account_cache[cache_key] = cached
188
+ _account_cache[cache_key] = (time.monotonic(), cached)
184
189
  # Defensive copy — callers must not mutate the cached entry.
185
190
  return copy.deepcopy(cached)
186
191
 
@@ -1,6 +1,8 @@
1
1
  """
2
2
  Account
3
3
  """
4
+ import time
5
+
4
6
  from bson.errors import InvalidId
5
7
  from mongoengine import DENY
6
8
  from mongoengine.errors import ValidationError
@@ -230,6 +232,7 @@ class Account(db.Document):
230
232
  return f"{self.name} ({self.typ})"
231
233
 
232
234
 
235
+ IS_MASTER_CACHE_SECONDS = 60
233
236
  _IS_MASTER_CACHE = {}
234
237
 
235
238
  # Hosts an import had to leave alone because a master account owns them.
@@ -273,13 +276,17 @@ def account_is_master(account_id):
273
276
  Whether the account with *account_id* is flagged as master.
274
277
 
275
278
  An import asks this once per host it does not own, so the answer is
276
- cached for the lifetime of the process. Unknown or malformed ids
277
- (legacy data) count as "not master".
279
+ cached for IS_MASTER_CACHE_SECONDS; a change of the flag reaches a
280
+ running process (web workers) within that time. Unknown or malformed
281
+ ids (legacy data) count as "not master".
278
282
  """
279
- if account_id not in _IS_MASTER_CACHE:
280
- try:
281
- account = Account.objects(id=account_id).only('is_master').first()
282
- except (ValidationError, InvalidId):
283
- account = None
284
- _IS_MASTER_CACHE[account_id] = bool(account and account.is_master)
285
- return _IS_MASTER_CACHE[account_id]
283
+ entry = _IS_MASTER_CACHE.get(account_id)
284
+ if entry and time.monotonic() - entry[0] < IS_MASTER_CACHE_SECONDS:
285
+ return entry[1]
286
+ try:
287
+ account = Account.objects(id=account_id).only('is_master').first()
288
+ except (ValidationError, InvalidId):
289
+ account = None
290
+ is_master = bool(account and account.is_master)
291
+ _IS_MASTER_CACHE[account_id] = (time.monotonic(), is_master)
292
+ return is_master
@@ -57,10 +57,20 @@ def _ansible_dir() -> Path:
57
57
 
58
58
 
59
59
  def _ansible_binary() -> str:
60
- """Path to `ansible-playbook` (default: rely on $PATH)."""
61
- return app.config.get('ANSIBLE_PLAYBOOK_BIN') \
62
- or os.environ.get('CMDBSYNCER_ANSIBLE_PLAYBOOK_BIN') \
63
- or 'ansible-playbook'
60
+ """
61
+ Path to `ansible-playbook`: explicit config / env override, then the one
62
+ in the running interpreter's venv, then $PATH. The venv comes first for
63
+ the same reason as in `_cmdbsyncer_bin` — a gunicorn worker under
64
+ systemd runs with a PATH that omits the venv's bin dir.
65
+ """
66
+ override = app.config.get('ANSIBLE_PLAYBOOK_BIN') \
67
+ or os.environ.get('CMDBSYNCER_ANSIBLE_PLAYBOOK_BIN')
68
+ if override:
69
+ return override
70
+ venv_bin = Path(sys.prefix) / 'bin' / 'ansible-playbook'
71
+ if venv_bin.is_file():
72
+ return str(venv_bin)
73
+ return 'ansible-playbook'
64
74
 
65
75
 
66
76
  def _inventory_plugin_dir() -> str | None:
@@ -3,10 +3,12 @@ The playbook runner has to work under a web user without a writable home.
3
3
  """
4
4
  # pylint: disable=missing-function-docstring,missing-class-docstring,protected-access
5
5
  import os
6
+ import shutil
6
7
  import sys
8
+ import tempfile
7
9
  import unittest
8
10
  from types import ModuleType
9
- from unittest.mock import MagicMock
11
+ from unittest.mock import MagicMock, patch
10
12
 
11
13
  from tests import _load_real_module
12
14
 
@@ -56,6 +58,40 @@ class SshEnvTest(unittest.TestCase):
56
58
  args.index('/tmp/run-2/known_hosts'))
57
59
 
58
60
 
61
+ class AnsibleBinaryTest(unittest.TestCase):
62
+ """
63
+ Under systemd the venv's bin dir is not on PATH, so the runner has to
64
+ find ansible-playbook next to the running interpreter.
65
+ """
66
+
67
+ @classmethod
68
+ def setUpClass(cls):
69
+ cls.runner = _load_runner()
70
+
71
+ def setUp(self):
72
+ self.prefix = tempfile.mkdtemp()
73
+ self.addCleanup(shutil.rmtree, self.prefix)
74
+ patcher = patch.object(self.runner.sys, 'prefix', self.prefix)
75
+ patcher.start()
76
+ self.addCleanup(patcher.stop)
77
+ self.runner.app.config.pop('ANSIBLE_PLAYBOOK_BIN', None)
78
+
79
+ def test_the_venv_binary_is_used(self):
80
+ os.mkdir(os.path.join(self.prefix, 'bin'))
81
+ binary = os.path.join(self.prefix, 'bin', 'ansible-playbook')
82
+ with open(binary, 'w', encoding='utf-8'):
83
+ pass
84
+ self.assertEqual(self.runner._ansible_binary(), binary)
85
+
86
+ def test_without_venv_binary_path_decides(self):
87
+ self.assertEqual(self.runner._ansible_binary(), 'ansible-playbook')
88
+
89
+ def test_the_config_wins(self):
90
+ self.runner.app.config['ANSIBLE_PLAYBOOK_BIN'] = '/usr/bin/ansible-playbook'
91
+ self.addCleanup(self.runner.app.config.pop, 'ANSIBLE_PLAYBOOK_BIN', None)
92
+ self.assertEqual(self.runner._ansible_binary(), '/usr/bin/ansible-playbook')
93
+
94
+
59
95
  class ConnectionHintTest(unittest.TestCase):
60
96
  """
61
97
  sshpass calls a non-writable home a wrong password. The log must not
@@ -36,6 +36,9 @@ KEEP_VALUE_HINT = "Value managed manually in Checkmk - Syncer will not overwrite
36
36
  KEEP_VALUE_MARK = "(Value editable)"
37
37
  # Checkmk returns every explicit password of a rule value masked like this.
38
38
  MASKED_PASSWORD = "'******'"
39
+ # Checkmk 2.5 masks the second part of a stored password reference too. It
40
+ # holds no secret: the rule works with it left empty.
41
+ MASKED_STORED_PASSWORD = re.compile(r"('stored_password', \('[^']*', )'\*{6}'")
39
42
 
40
43
  # Longest Setup Rule name written into the Checkmk rule description. Long
41
44
  # enough for real rule names, short enough to keep the rule list readable.
@@ -843,7 +846,7 @@ def preview_list_rule(rule):
843
846
 
844
847
  def clean_postproccessed(data):
845
848
  """
846
- Normalize Checkmk's explicit_password tuples before rule comparison.
849
+ Normalize Checkmk's password tuples, at any depth, before rule comparison.
847
850
  """
848
851
  # Intentional: Checkmk re-encrypts the stored explicit_password tuple
849
852
  # (id, password) on every GET, so the ciphertext differs across reads
@@ -852,16 +855,20 @@ def clean_postproccessed(data):
852
855
  # on every sync. The trade-off — that a real password change is not
853
856
  # detected here — is accepted; password rotation is managed by the
854
857
  # Checkmk password store, not by rule diffs.
855
- output = {}
856
- for key, value in data.items():
857
- if isinstance(value, tuple):
858
- if value[0] == 'cmk_postprocessed' and \
859
- value[1] == 'explicit_password':
860
- new_tuple = (None, None)
861
- new_value = (value[0], value[1], new_tuple)
862
- value = new_value
863
- output[key] = value
864
- return output
858
+ # A stored_password only references the store: Checkmk 2.5 returns its
859
+ # second part masked, so only the ident is compared.
860
+ if isinstance(data, dict):
861
+ return {key: clean_postproccessed(value) for key, value in data.items()}
862
+ if isinstance(data, list):
863
+ return [clean_postproccessed(value) for value in data]
864
+ if not isinstance(data, tuple):
865
+ return data
866
+ if len(data) == 3 and data[0] == 'cmk_postprocessed':
867
+ if data[1] == 'explicit_password':
868
+ return (data[0], data[1], (None, None))
869
+ if data[1] == 'stored_password':
870
+ return (data[0], data[1], (data[2][0], ''))
871
+ return tuple(clean_postproccessed(value) for value in data)
865
872
 
866
873
  def deep_compare(ours, stored, strict=False):
867
874
  """
@@ -883,9 +890,9 @@ def deep_compare(ours, stored, strict=False):
883
890
  Nested dicts inside lists are still compared structurally via each
884
891
  element's ``==``.
885
892
  """
893
+ ours = clean_postproccessed(ours)
894
+ stored = clean_postproccessed(stored)
886
895
  if isinstance(ours, dict) and isinstance(stored, dict):
887
- ours = clean_postproccessed(ours)
888
- stored = clean_postproccessed(stored)
889
896
  if strict:
890
897
  if set(ours.keys()) != set(stored.keys()):
891
898
  return False
@@ -2694,7 +2701,9 @@ class CheckmkRuleSync(CMK2): # pylint: disable=too-many-instance-attributes
2694
2701
  current = properties.get('description', '')
2695
2702
  if current == wanted:
2696
2703
  return
2697
- if MASKED_PASSWORD in cmk_rule['extensions']['value_raw']:
2704
+ value_raw = MASKED_STORED_PASSWORD.sub(
2705
+ r"\1''", cmk_rule['extensions']['value_raw'])
2706
+ if MASKED_PASSWORD in value_raw:
2698
2707
  # The value as read holds the password masked. Sending it back
2699
2708
  # would replace the real password with the mask, so the
2700
2709
  # description stays as it is.
@@ -2704,7 +2713,7 @@ class CheckmkRuleSync(CMK2): # pylint: disable=too-many-instance-attributes
2704
2713
  payload = {
2705
2714
  "properties": properties,
2706
2715
  "conditions": cmk_rule['extensions']['conditions'],
2707
- "value_raw": cmk_rule['extensions']['value_raw'],
2716
+ "value_raw": value_raw,
2708
2717
  }
2709
2718
  if self.dry_run:
2710
2719
  self._plan('UPDATE', f"{ruleset_name} {rule_id}",
@@ -128,7 +128,11 @@ class CheckmkDCDRuleSync(CMK2):
128
128
  Return Payload as Dict
129
129
  """
130
130
  try:
131
- restricted_hosts = rule['restricted_source_hosts']
131
+ # A line rendering empty (an attribute the host lacks) is left out.
132
+ restricted_hosts = [
133
+ host for host in (render_jinja(entry, mode='raise', **attributes).strip()
134
+ for entry in rule['restricted_source_hosts'])
135
+ if host]
132
136
  creation_rules = self.build_creation_rules(rule, attributes)
133
137
  exclude_time_ranges = self.build_timeranges(rule)
134
138
 
@@ -1201,6 +1201,9 @@ class SyncCMK2(CMK2):
1201
1201
  # skipping it left every already-existing folder unchanged whenever a
1202
1202
  # run was limited to single hosts (the usual way to test folder rules).
1203
1203
  self.handle_folders()
1204
+ # Clusters only hold hosts of this run. A host that turned into a
1205
+ # cluster was already deleted above and has to come back now.
1206
+ self.handle_clusters()
1204
1207
 
1205
1208
  if self.limit:
1206
1209
  log.log(f"Finished Sync to Checkmk Account: {self.account_name} because LIMIT",
@@ -1208,7 +1211,6 @@ class SyncCMK2(CMK2):
1208
1211
  print(f"\n{CC.OKCYAN} -- {CC.ENDC}Stop processing in limit mode")
1209
1212
  return
1210
1213
 
1211
- self.handle_clusters()
1212
1214
  self.cleanup_hosts()
1213
1215
 
1214
1216
 
@@ -75,6 +75,11 @@ class TestCleanPostprocessed(unittest.TestCase):
75
75
  }
76
76
  self.assertEqual(result, expected)
77
77
 
78
+ def test_stored_password_keeps_ident_only(self):
79
+ data = {'token': ('cmk_postprocessed', 'stored_password', ('id', '******'))}
80
+ expected = {'token': ('cmk_postprocessed', 'stored_password', ('id', ''))}
81
+ self.assertEqual(clean_postproccessed(data), expected)
82
+
78
83
  def test_non_password_tuple_unchanged(self):
79
84
  data = {'other': ('something', 'else', 'data')}
80
85
  result = clean_postproccessed(data)
@@ -152,6 +157,31 @@ class TestDeepCompare(unittest.TestCase):
152
157
  b = {'password': ('cmk_postprocessed', 'explicit_password', ('id2', 'pw2'))}
153
158
  self.assertTrue(deep_compare(a, b))
154
159
 
160
+ def test_masked_stored_password_is_no_drift(self):
161
+ # Sent with an empty second part, Checkmk 2.5 returns it masked.
162
+ ours = {'token': ('cmk_postprocessed', 'stored_password', ('pw1', ''))}
163
+ stored = {'token': ('cmk_postprocessed', 'stored_password', ('pw1', '******'))}
164
+ self.assertTrue(deep_compare(ours, stored))
165
+ self.assertTrue(deep_compare(ours, stored, strict=True))
166
+
167
+ def test_other_stored_password_is_drift(self):
168
+ ours = {'token': ('cmk_postprocessed', 'stored_password', ('pw1', ''))}
169
+ stored = {'token': ('cmk_postprocessed', 'stored_password', ('pw2', '******'))}
170
+ self.assertFalse(deep_compare(ours, stored))
171
+
172
+ def test_nested_stored_password_is_no_drift(self):
173
+ def value(secret):
174
+ password = ('cmk_postprocessed', 'stored_password', ('pw1', secret))
175
+ return {'auth': ('user_auth', {'password': password}),
176
+ 'endpoints': [{'password': password}]}
177
+ self.assertTrue(deep_compare(value(''), value('******')))
178
+
179
+ def test_nested_explicit_password_is_no_drift(self):
180
+ def value(ident):
181
+ password = ('cmk_postprocessed', 'explicit_password', (ident, '******'))
182
+ return {'auth': ('user_auth', {'password': password})}
183
+ self.assertTrue(deep_compare(value('a'), value('b')))
184
+
155
185
 
156
186
  class TestAnalyzeValueDifferences(unittest.TestCase):
157
187
  """Tests for analyze_value_differences"""
@@ -3296,6 +3326,32 @@ class TestSyncDescription(unittest.TestCase):
3296
3326
  self.assertEqual(data['value_raw'], "{'levels': (99, 99)}")
3297
3327
  self.assertEqual(data['properties']['comment'], 'c')
3298
3328
 
3329
+ def test_stale_description_with_stored_password_is_rewritten(self):
3330
+ puts = self._wire()
3331
+ cmk_rule = self._cmk_rule('cmdbsyncer_test_account')
3332
+ cmk_rule['extensions']['value_raw'] = (
3333
+ "{'token': ('cmk_postprocessed', 'stored_password', ('pw1', '******'))}")
3334
+ local = {'description': 'cmdbsyncer_test_account - Kube'}
3335
+
3336
+ self.sync._sync_description(cmk_rule, local, 'a_ruleset')
3337
+
3338
+ self.assertEqual(len(puts), 1)
3339
+ self.assertEqual(
3340
+ puts[0][2]['value_raw'],
3341
+ "{'token': ('cmk_postprocessed', 'stored_password', ('pw1', ''))}")
3342
+
3343
+ def test_stale_description_with_explicit_password_writes_nothing(self):
3344
+ puts = self._wire()
3345
+ cmk_rule = self._cmk_rule('cmdbsyncer_test_account')
3346
+ cmk_rule['extensions']['value_raw'] = (
3347
+ "{'stored': ('cmk_postprocessed', 'stored_password', ('pw1', '******')), "
3348
+ "'token': ('cmk_postprocessed', 'explicit_password', ('id', '******'))}")
3349
+ local = {'description': 'cmdbsyncer_test_account - Kube'}
3350
+
3351
+ self.sync._sync_description(cmk_rule, local, 'a_ruleset')
3352
+
3353
+ self.assertEqual(puts, [])
3354
+
3299
3355
  def test_matching_description_writes_nothing(self):
3300
3356
  puts = self._wire()
3301
3357
  cmk_rule = self._cmk_rule('cmdbsyncer_test_account - Disk Levels')
@@ -380,6 +380,14 @@ class TestDCDListRule(unittest.TestCase):
380
380
  self.assertTrue(any('dc1 not created' in str(detail)
381
381
  for detail in self.sync.log_details))
382
382
 
383
+ def test_restrict_source_hosts_are_rendered(self, _render):
384
+ self.sync.static_rules = [_dcd_rule(
385
+ "id;host\ndc1;srv01\n",
386
+ restricted_source_hosts=['{{ host }}', '{{ missing | default("") }}'])]
387
+ self.sync.calculate_static_rules({'cmk_site': 'site_a', 'account': {}})
388
+ self.assertEqual(
389
+ self.sync.all_rules[0]['connector']['restrict_source_hosts'], ['srv01'])
390
+
383
391
 
384
392
  if __name__ == '__main__':
385
393
  unittest.main(verbosity=2)
@@ -963,10 +963,11 @@ class TestSyncCMK2(unittest.TestCase):
963
963
 
964
964
  self.syncer.run()
965
965
 
966
- # Folders applied for the processed hosts ...
966
+ # Folders and clusters applied for the processed hosts, a host
967
+ # turned cluster was deleted and has to come back ...
967
968
  mock_folders.assert_called_once()
968
- # ... but cluster/cleanup passes are skipped in limit mode.
969
- mock_clusters.assert_not_called()
969
+ mock_clusters.assert_called_once()
970
+ # ... but the cleanup is skipped in limit mode.
970
971
  mock_cleanup.assert_not_called()
971
972
 
972
973
 
@@ -35,20 +35,50 @@ def _pid_alive(pid):
35
35
  return True
36
36
 
37
37
 
38
+ def _process_start(pid):
39
+ """
40
+ Local start time of the process ``pid``, from /proc. None where /proc
41
+ is missing (not Linux) or the process is gone.
42
+ """
43
+ try:
44
+ with open(f"/proc/{int(pid)}/stat", encoding="ascii") as handle:
45
+ # The name in brackets may hold spaces, the fields after it don't
46
+ ticks = int(handle.read().rsplit(")", 1)[1].split()[19])
47
+ with open("/proc/stat", encoding="ascii") as handle:
48
+ boot = next(int(line.split()[1]) for line in handle
49
+ if line.startswith("btime "))
50
+ return datetime.fromtimestamp(boot + ticks / os.sysconf("SC_CLK_TCK"))
51
+ except (OSError, ValueError, IndexError, StopIteration):
52
+ return None
53
+
54
+
55
+ def _pid_reused(stats):
56
+ """
57
+ Whether the PID of the lock now belongs to a process that started after
58
+ the run, as after a container restart, where PIDs count up from 1 again.
59
+ The runner itself starts before it writes last_start.
60
+ """
61
+ if not stats.last_start:
62
+ return False
63
+ started = _process_start(stats.pid)
64
+ return started is not None and started > stats.last_start + timedelta(seconds=2)
65
+
66
+
38
67
  def _reset_stale_lock(stats):
39
68
  """
40
69
  A previous run crashed (OOM, kill -9, container restart) before it could
41
70
  release `is_running`. Reset the lock when the recorded PID no longer
42
- exists on this host (the runner is always local).
71
+ exists on this host (the runner is always local), or belongs to a
72
+ process started after the run.
43
73
  """
44
74
  if not stats.is_running:
45
75
  return
46
- if _pid_alive(stats.pid):
76
+ if _pid_alive(stats.pid) and not _pid_reused(stats):
47
77
  return
48
78
  stats.is_running = False
49
79
  stats.failure = True
50
80
  message = (f"{datetime.now()}: Stale lock cleared "
51
- f"(pid {stats.pid} no longer running)")
81
+ f"(pid {stats.pid} no longer running the group)")
52
82
  stats.last_message = message
53
83
  stats.all_messages = f"{stats.all_messages or ''}{message}\n"
54
84
  stats.last_ended = datetime.now()
@@ -9,6 +9,7 @@ from application.models.host import Host
9
9
 
10
10
  from .netbox import SyncNetbox
11
11
  from .models import NetboxDataflowModels
12
+ from .utils import same_host_url
12
13
 
13
14
 
14
15
  class DictObj: # pylint: disable=too-few-public-methods
@@ -160,7 +161,7 @@ class SyncDataFlow(SyncNetbox):
160
161
  resp_data = resp.json()
161
162
  result_collection += resp_data['results']
162
163
  while resp_data.get('next'):
163
- next_url = resp_data['next']
164
+ next_url = same_host_url(resp_data['next'], self.config['address'])
164
165
  resp = self.inner_request("GET", next_url, headers=self.headers)
165
166
  resp_data = resp.json()
166
167
  result_collection += resp_data['results']
@@ -0,0 +1,29 @@
1
+ """
2
+ The page link of a Netbox answer carries the token on the next request,
3
+ so it is pinned to the host of the account.
4
+ """
5
+ # pylint: disable=missing-function-docstring
6
+ import unittest
7
+
8
+ from application.plugins.netbox.utils import same_host_url
9
+
10
+
11
+ class TestSameHostUrl(unittest.TestCase):
12
+ """Page links of the Dataflow sync."""
13
+
14
+ def test_link_to_another_host_stays_on_the_account(self):
15
+ self.assertEqual(
16
+ same_host_url('https://evil.example/api/plugins/data-flows/x/?limit=50&offset=50',
17
+ 'https://netbox.example.com'),
18
+ 'https://netbox.example.com/api/plugins/data-flows/x/?limit=50&offset=50')
19
+
20
+ def test_link_of_the_own_host_is_kept(self):
21
+ url = 'https://netbox.example.com:8443/api/plugins/data-flows/x/?offset=50'
22
+ self.assertEqual(same_host_url(url, 'https://netbox.example.com:8443'), url)
23
+
24
+ def test_scheme_follows_the_account(self):
25
+ # Behind a TLS proxy Netbox may answer with http links
26
+ self.assertEqual(
27
+ same_host_url('http://netbox.example.com/api/x/?offset=50',
28
+ 'https://netbox.example.com'),
29
+ 'https://netbox.example.com/api/x/?offset=50')
@@ -2,6 +2,8 @@
2
2
  Shared helpers for the Netbox plugin.
3
3
  """
4
4
  from collections import defaultdict
5
+ from urllib.parse import urlsplit, urlunsplit
6
+
5
7
  from rich.progress import Progress, SpinnerColumn, TimeElapsedColumn, MofNCompleteColumn
6
8
 
7
9
 
@@ -29,3 +31,14 @@ def parse_import_filter(import_filter):
29
31
  parsed_filter[key].append(value)
30
32
  return {key: values if len(values) > 1 else values[0]
31
33
  for key, values in parsed_filter.items()}
34
+
35
+
36
+ def same_host_url(url, address):
37
+ """
38
+ The page link of an answer, with scheme and host of the account.
39
+ The link comes from the server and carries the token on the next
40
+ request, so it must not lead to another host.
41
+ """
42
+ page = urlsplit(url)
43
+ base = urlsplit(address)
44
+ return urlunsplit((base.scheme, base.netloc, page.path, page.query, ''))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cmdbsyncer
3
- Version: 4.4.1
3
+ Version: 4.4.2
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>
@@ -270,6 +270,7 @@ application/plugins/netbox/views.py
270
270
  application/plugins/netbox/virtualmachines.py
271
271
  application/plugins/netbox/tests/__init__.py
272
272
  application/plugins/netbox/tests/test_import_filter.py
273
+ application/plugins/netbox/tests/test_same_host_url.py
273
274
  application/plugins/prtg/__init__.py
274
275
  application/plugins/prtg/plugin.json
275
276
  application/plugins/prtg/prtg.py
@@ -441,6 +442,7 @@ syncerapi/v1/core/__init__.py
441
442
  syncerapi/v1/inventory/__init__.py
442
443
  syncerapi/v1/rest/__init__.py
443
444
  tests/test_account_macro.py
445
+ tests/test_account_master_cache_smoke.py
444
446
  tests/test_active_templates.py
445
447
  tests/test_ansible_cmk_roles.py
446
448
  tests/test_ansible_inventory.py
@@ -448,6 +450,7 @@ tests/test_api.py
448
450
  tests/test_api_csrf_invariant.py
449
451
  tests/test_config_dir.py
450
452
  tests/test_cron_missing_account.py
453
+ tests/test_cron_stale_lock_smoke.py
451
454
  tests/test_csrf_config.py
452
455
  tests/test_data_quality_duplicates.py
453
456
  tests/test_default_view.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cmdbsyncer"
7
- version = "4.4.1"
7
+ version = "4.4.2"
8
8
  description = "Rule-based modular synchronizer for Checkmk, Netbox, Ansible, I-DOIT, Jira CMDB and 15+ other CMDB/monitoring systems"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -0,0 +1,50 @@
1
+ """
2
+ A change of the master flag reaches a running process within the cache time.
3
+
4
+ The save signal only clears the caches of the process that saved, the
5
+ other web workers learn about it when their entry runs out. Saving in
6
+ another process is simulated by a direct database update, which sends no
7
+ signal. See ``tests/web_smoke_helpers.py`` for why this needs a subprocess.
8
+ """
9
+
10
+ import unittest
11
+
12
+ from tests.web_smoke_helpers import HAVE_MONGOMOCK, SKIP_REASON, run_against_app
13
+
14
+
15
+ SNIPPET = '''
16
+ from unittest.mock import patch
17
+
18
+ from application.models import account as account_module
19
+ from application.models.account import Account, account_is_master
20
+
21
+ now = [1000.0]
22
+ clock = patch.object(account_module.time, 'monotonic', side_effect=lambda: now[0])
23
+ clock.start()
24
+
25
+ account = Account(name='src', type='csv', address='', enabled=True)
26
+ account.save()
27
+ eq(account_is_master(str(account.id)), False, 'before the change')
28
+
29
+ Account.objects(id=account.id).update(set__is_master=True)
30
+ now[0] += account_module.IS_MASTER_CACHE_SECONDS - 1
31
+ eq(account_is_master(str(account.id)), False, 'within the cache time')
32
+
33
+ now[0] += 2
34
+ eq(account_is_master(str(account.id)), True, 'after the cache time')
35
+
36
+ clock.stop()
37
+ print('MASTER_CACHE_OK')
38
+ '''
39
+
40
+
41
+ @unittest.skipUnless(HAVE_MONGOMOCK, SKIP_REASON)
42
+ class AccountMasterCacheTests(unittest.TestCase):
43
+ """Runs the snippet against the booted app."""
44
+
45
+ def test_master_flag_reaches_a_running_process(self):
46
+ """Cached within the cache time, read again after it."""
47
+ result = run_against_app(SNIPPET, False)
48
+ self.assertEqual(result.returncode, 0,
49
+ f"{result.stdout[-1500:]}\n{result.stderr[-1500:]}")
50
+ self.assertIn('MASTER_CACHE_OK', result.stdout)