infrahub-server 1.1.9__py3-none-any.whl → 1.2.0__py3-none-any.whl

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 (467) hide show
  1. infrahub/api/artifact.py +16 -4
  2. infrahub/api/dependencies.py +14 -6
  3. infrahub/api/diff/validation_models.py +7 -7
  4. infrahub/api/oauth2.py +0 -1
  5. infrahub/api/oidc.py +0 -1
  6. infrahub/api/query.py +18 -7
  7. infrahub/api/schema.py +33 -7
  8. infrahub/api/transformation.py +12 -5
  9. infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +6 -6
  10. infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +27 -28
  11. infrahub/cli/__init__.py +12 -10
  12. infrahub/cli/constants.py +3 -0
  13. infrahub/cli/db.py +166 -185
  14. infrahub/cli/events.py +8 -3
  15. infrahub/cli/git_agent.py +9 -7
  16. infrahub/cli/tasks.py +4 -6
  17. infrahub/cli/upgrade.py +146 -0
  18. infrahub/computed_attribute/gather.py +174 -0
  19. infrahub/computed_attribute/models.py +202 -11
  20. infrahub/computed_attribute/tasks.py +103 -421
  21. infrahub/computed_attribute/triggers.py +56 -0
  22. infrahub/config.py +33 -33
  23. infrahub/context.py +53 -0
  24. infrahub/core/account.py +9 -12
  25. infrahub/core/attribute.py +104 -75
  26. infrahub/core/branch/models.py +4 -4
  27. infrahub/core/branch/tasks.py +133 -125
  28. infrahub/core/changelog/__init__.py +0 -0
  29. infrahub/core/changelog/diff.py +291 -0
  30. infrahub/core/changelog/models.py +662 -0
  31. infrahub/core/constants/__init__.py +47 -2
  32. infrahub/core/constants/infrahubkind.py +3 -0
  33. infrahub/core/constants/schema.py +2 -0
  34. infrahub/core/constraint/node/runner.py +2 -2
  35. infrahub/core/diff/branch_differ.py +10 -10
  36. infrahub/core/diff/combiner.py +1 -1
  37. infrahub/core/diff/enricher/cardinality_one.py +1 -1
  38. infrahub/core/diff/enricher/hierarchy.py +5 -3
  39. infrahub/core/diff/enricher/labels.py +1 -1
  40. infrahub/core/diff/enricher/path_identifier.py +1 -2
  41. infrahub/core/diff/enricher/summary_counts.py +107 -0
  42. infrahub/core/diff/ipam_diff_parser.py +4 -5
  43. infrahub/core/diff/merger/merger.py +3 -1
  44. infrahub/core/diff/model/diff.py +27 -27
  45. infrahub/core/diff/model/path.py +13 -13
  46. infrahub/core/diff/query/all_conflicts.py +1 -1
  47. infrahub/core/diff/query/artifact.py +1 -1
  48. infrahub/core/diff/query/delete_query.py +1 -1
  49. infrahub/core/diff/query/diff_get.py +1 -1
  50. infrahub/core/diff/query/diff_summary.py +1 -1
  51. infrahub/core/diff/query/field_specifiers.py +1 -1
  52. infrahub/core/diff/query/field_summary.py +1 -1
  53. infrahub/core/diff/query/filters.py +2 -2
  54. infrahub/core/diff/query/get_conflict_query.py +1 -1
  55. infrahub/core/diff/query/has_conflicts_query.py +1 -1
  56. infrahub/core/diff/query/merge.py +3 -3
  57. infrahub/core/diff/query/merge_tracking_id.py +1 -1
  58. infrahub/core/diff/query/roots_metadata.py +1 -1
  59. infrahub/core/diff/query/save.py +3 -3
  60. infrahub/core/diff/query/summary_counts_enricher.py +2 -2
  61. infrahub/core/diff/query/time_range_query.py +1 -1
  62. infrahub/core/diff/query/update_conflict_query.py +1 -1
  63. infrahub/core/diff/query_parser.py +4 -4
  64. infrahub/core/diff/repository/deserializer.py +1 -1
  65. infrahub/core/diff/tasks.py +9 -8
  66. infrahub/core/enums.py +1 -1
  67. infrahub/core/initialization.py +1 -10
  68. infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
  69. infrahub/core/ipam/constants.py +3 -4
  70. infrahub/core/ipam/reconciler.py +13 -13
  71. infrahub/core/ipam/tasks.py +2 -3
  72. infrahub/core/ipam/utilization.py +10 -13
  73. infrahub/core/manager.py +52 -47
  74. infrahub/core/merge.py +12 -9
  75. infrahub/core/migrations/__init__.py +1 -3
  76. infrahub/core/migrations/graph/__init__.py +5 -3
  77. infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
  78. infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
  79. infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
  80. infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
  81. infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
  82. infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
  83. infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
  84. infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
  85. infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
  86. infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
  87. infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
  88. infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
  89. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
  90. infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
  91. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
  92. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
  93. infrahub/core/migrations/graph/m017_add_core_profile.py +2 -6
  94. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +3 -3
  95. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +4 -4
  96. infrahub/core/migrations/graph/m020_duplicate_edges.py +3 -3
  97. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +2 -2
  98. infrahub/core/migrations/graph/m022_add_generate_template_attr.py +48 -0
  99. infrahub/core/migrations/query/attribute_add.py +3 -3
  100. infrahub/core/migrations/query/attribute_rename.py +1 -1
  101. infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
  102. infrahub/core/migrations/query/node_duplicate.py +1 -1
  103. infrahub/core/migrations/query/relationship_duplicate.py +1 -1
  104. infrahub/core/migrations/query/schema_attribute_update.py +3 -3
  105. infrahub/core/migrations/schema/models.py +19 -4
  106. infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
  107. infrahub/core/migrations/schema/node_remove.py +1 -1
  108. infrahub/core/migrations/schema/tasks.py +7 -7
  109. infrahub/core/migrations/shared.py +10 -12
  110. infrahub/core/models.py +13 -14
  111. infrahub/core/node/__init__.py +172 -57
  112. infrahub/core/node/base.py +3 -5
  113. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  114. infrahub/core/node/constraints/grouped_uniqueness.py +5 -5
  115. infrahub/core/node/constraints/interface.py +1 -2
  116. infrahub/core/node/delete_validator.py +7 -9
  117. infrahub/core/node/ipam.py +10 -10
  118. infrahub/core/node/permissions.py +7 -7
  119. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  120. infrahub/core/node/resource_manager/ip_prefix_pool.py +14 -11
  121. infrahub/core/node/resource_manager/number_pool.py +3 -3
  122. infrahub/core/node/standard.py +3 -5
  123. infrahub/core/path.py +12 -12
  124. infrahub/core/property.py +12 -12
  125. infrahub/core/protocols.py +11 -0
  126. infrahub/core/protocols_base.py +25 -23
  127. infrahub/core/query/__init__.py +35 -38
  128. infrahub/core/query/attribute.py +13 -13
  129. infrahub/core/query/branch.py +5 -5
  130. infrahub/core/query/delete.py +1 -1
  131. infrahub/core/query/diff.py +7 -7
  132. infrahub/core/query/ipam.py +4 -4
  133. infrahub/core/query/node.py +23 -24
  134. infrahub/core/query/relationship.py +143 -46
  135. infrahub/core/query/resource_manager.py +10 -10
  136. infrahub/core/query/standard_node.py +9 -9
  137. infrahub/core/query/subquery.py +9 -9
  138. infrahub/core/query/task.py +3 -3
  139. infrahub/core/query/task_log.py +1 -1
  140. infrahub/core/query/utils.py +5 -5
  141. infrahub/core/registry.py +13 -17
  142. infrahub/core/relationship/constraints/count.py +4 -5
  143. infrahub/core/relationship/constraints/peer_kind.py +4 -5
  144. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  145. infrahub/core/relationship/model.py +103 -67
  146. infrahub/core/schema/__init__.py +6 -4
  147. infrahub/core/schema/attribute_schema.py +16 -8
  148. infrahub/core/schema/basenode_schema.py +38 -26
  149. infrahub/core/schema/computed_attribute.py +3 -3
  150. infrahub/core/schema/definitions/core/__init__.py +147 -0
  151. infrahub/core/schema/definitions/core/account.py +171 -0
  152. infrahub/core/schema/definitions/core/artifact.py +136 -0
  153. infrahub/core/schema/definitions/core/builtin.py +24 -0
  154. infrahub/core/schema/definitions/core/check.py +68 -0
  155. infrahub/core/schema/definitions/core/core.py +17 -0
  156. infrahub/core/schema/definitions/core/generator.py +100 -0
  157. infrahub/core/schema/definitions/core/graphql_query.py +79 -0
  158. infrahub/core/schema/definitions/core/group.py +108 -0
  159. infrahub/core/schema/definitions/core/ipam.py +193 -0
  160. infrahub/core/schema/definitions/core/lineage.py +19 -0
  161. infrahub/core/schema/definitions/core/menu.py +48 -0
  162. infrahub/core/schema/definitions/core/permission.py +163 -0
  163. infrahub/core/schema/definitions/core/profile.py +18 -0
  164. infrahub/core/schema/definitions/core/propose_change.py +97 -0
  165. infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
  166. infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
  167. infrahub/core/schema/definitions/core/repository.py +286 -0
  168. infrahub/core/schema/definitions/core/resource_pool.py +170 -0
  169. infrahub/core/schema/definitions/core/template.py +27 -0
  170. infrahub/core/schema/definitions/core/transform.py +96 -0
  171. infrahub/core/schema/definitions/core/webhook.py +134 -0
  172. infrahub/core/schema/definitions/internal.py +32 -16
  173. infrahub/core/schema/dropdown.py +3 -4
  174. infrahub/core/schema/generated/attribute_schema.py +15 -18
  175. infrahub/core/schema/generated/base_node_schema.py +12 -14
  176. infrahub/core/schema/generated/genericnode_schema.py +5 -0
  177. infrahub/core/schema/generated/node_schema.py +8 -5
  178. infrahub/core/schema/generated/relationship_schema.py +9 -11
  179. infrahub/core/schema/generic_schema.py +6 -2
  180. infrahub/core/schema/manager.py +46 -43
  181. infrahub/core/schema/node_schema.py +6 -2
  182. infrahub/core/schema/profile_schema.py +4 -0
  183. infrahub/core/schema/relationship_schema.py +15 -7
  184. infrahub/core/schema/schema_branch.py +423 -89
  185. infrahub/core/schema/schema_branch_computed.py +41 -4
  186. infrahub/core/schema/template_schema.py +36 -0
  187. infrahub/core/task/task.py +3 -3
  188. infrahub/core/task/user_task.py +21 -19
  189. infrahub/core/timestamp.py +3 -3
  190. infrahub/core/utils.py +12 -12
  191. infrahub/core/validators/__init__.py +1 -3
  192. infrahub/core/validators/aggregated_checker.py +2 -2
  193. infrahub/core/validators/attribute/choices.py +3 -3
  194. infrahub/core/validators/attribute/enum.py +3 -3
  195. infrahub/core/validators/attribute/kind.py +3 -3
  196. infrahub/core/validators/attribute/length.py +3 -3
  197. infrahub/core/validators/attribute/optional.py +3 -3
  198. infrahub/core/validators/attribute/regex.py +3 -3
  199. infrahub/core/validators/attribute/unique.py +3 -3
  200. infrahub/core/validators/checks_runner.py +60 -0
  201. infrahub/core/validators/determiner.py +1 -3
  202. infrahub/core/validators/model.py +1 -3
  203. infrahub/core/validators/models/validate_migration.py +17 -4
  204. infrahub/core/validators/node/attribute.py +2 -2
  205. infrahub/core/validators/node/generate_profile.py +3 -3
  206. infrahub/core/validators/node/hierarchy.py +3 -3
  207. infrahub/core/validators/node/inherit_from.py +2 -2
  208. infrahub/core/validators/node/relationship.py +2 -2
  209. infrahub/core/validators/query.py +1 -1
  210. infrahub/core/validators/relationship/count.py +5 -5
  211. infrahub/core/validators/relationship/optional.py +3 -3
  212. infrahub/core/validators/relationship/peer.py +3 -3
  213. infrahub/core/validators/shared.py +2 -2
  214. infrahub/core/validators/tasks.py +8 -6
  215. infrahub/core/validators/uniqueness/checker.py +5 -6
  216. infrahub/core/validators/uniqueness/index.py +2 -2
  217. infrahub/core/validators/uniqueness/model.py +11 -11
  218. infrahub/core/validators/uniqueness/query.py +1 -1
  219. infrahub/database/__init__.py +19 -23
  220. infrahub/database/memgraph.py +1 -1
  221. infrahub/dependencies/builder/diff/combiner.py +1 -1
  222. infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
  223. infrahub/dependencies/builder/diff/deserializer.py +1 -1
  224. infrahub/dependencies/builder/diff/enricher/summary_counts.py +8 -0
  225. infrahub/dependencies/builder/diff/parent_node_adder.py +1 -1
  226. infrahub/dependencies/component/registry.py +2 -2
  227. infrahub/events/__init__.py +25 -2
  228. infrahub/events/artifact_action.py +64 -0
  229. infrahub/events/branch_action.py +57 -20
  230. infrahub/events/generator.py +71 -0
  231. infrahub/events/group_action.py +103 -0
  232. infrahub/events/models.py +160 -53
  233. infrahub/events/node_action.py +140 -23
  234. infrahub/events/repository_action.py +7 -20
  235. infrahub/events/schema_action.py +18 -10
  236. infrahub/events/utils.py +16 -0
  237. infrahub/events/validator_action.py +55 -0
  238. infrahub/exceptions.py +12 -3
  239. infrahub/generators/models.py +2 -3
  240. infrahub/generators/tasks.py +34 -15
  241. infrahub/git/base.py +10 -12
  242. infrahub/git/constants.py +0 -1
  243. infrahub/git/integrator.py +82 -57
  244. infrahub/git/models.py +101 -9
  245. infrahub/git/repository.py +9 -10
  246. infrahub/git/tasks.py +450 -112
  247. infrahub/git/utils.py +48 -0
  248. infrahub/git/worktree.py +1 -2
  249. infrahub/git_credential/askpass.py +1 -2
  250. infrahub/git_credential/helper.py +2 -3
  251. infrahub/graphql/analyzer.py +572 -11
  252. infrahub/graphql/app.py +47 -41
  253. infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
  254. infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
  255. infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
  256. infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
  257. infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
  258. infrahub/graphql/context.py +39 -0
  259. infrahub/graphql/enums.py +1 -1
  260. infrahub/graphql/initialization.py +5 -1
  261. infrahub/graphql/loaders/node.py +1 -1
  262. infrahub/graphql/loaders/shared.py +1 -1
  263. infrahub/graphql/manager.py +75 -72
  264. infrahub/graphql/mutations/account.py +20 -13
  265. infrahub/graphql/mutations/artifact_definition.py +18 -14
  266. infrahub/graphql/mutations/branch.py +86 -40
  267. infrahub/graphql/mutations/computed_attribute.py +26 -18
  268. infrahub/graphql/mutations/diff.py +17 -8
  269. infrahub/graphql/mutations/diff_conflict.py +14 -8
  270. infrahub/graphql/mutations/generator.py +83 -0
  271. infrahub/graphql/mutations/graphql_query.py +21 -13
  272. infrahub/graphql/mutations/ipam.py +41 -39
  273. infrahub/graphql/mutations/main.py +226 -66
  274. infrahub/graphql/mutations/menu.py +12 -12
  275. infrahub/graphql/mutations/models.py +2 -4
  276. infrahub/graphql/mutations/node_getter/by_default_filter.py +1 -3
  277. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  278. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  279. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  280. infrahub/graphql/mutations/proposed_change.py +39 -31
  281. infrahub/graphql/mutations/relationship.py +372 -129
  282. infrahub/graphql/mutations/repository.py +46 -40
  283. infrahub/graphql/mutations/resource_manager.py +26 -26
  284. infrahub/graphql/mutations/schema.py +70 -37
  285. infrahub/graphql/mutations/tasks.py +10 -7
  286. infrahub/graphql/mutations/webhook.py +137 -0
  287. infrahub/graphql/parser.py +5 -5
  288. infrahub/graphql/permissions.py +3 -10
  289. infrahub/graphql/queries/account.py +22 -18
  290. infrahub/graphql/queries/branch.py +6 -4
  291. infrahub/graphql/queries/diff/tree.py +67 -56
  292. infrahub/graphql/queries/event.py +115 -0
  293. infrahub/graphql/queries/internal.py +3 -3
  294. infrahub/graphql/queries/ipam.py +25 -20
  295. infrahub/graphql/queries/relationship.py +13 -12
  296. infrahub/graphql/queries/resource_manager.py +37 -25
  297. infrahub/graphql/queries/search.py +11 -10
  298. infrahub/graphql/queries/status.py +12 -9
  299. infrahub/graphql/queries/task.py +11 -9
  300. infrahub/graphql/resolvers/many_relationship.py +15 -15
  301. infrahub/graphql/resolvers/resolver.py +58 -37
  302. infrahub/graphql/resolvers/single_relationship.py +16 -10
  303. infrahub/graphql/schema.py +4 -0
  304. infrahub/graphql/subscription/__init__.py +1 -1
  305. infrahub/graphql/subscription/events.py +1 -1
  306. infrahub/graphql/subscription/graphql_query.py +8 -8
  307. infrahub/graphql/types/branch.py +2 -2
  308. infrahub/graphql/types/common.py +6 -1
  309. infrahub/graphql/types/context.py +12 -0
  310. infrahub/graphql/types/enums.py +2 -0
  311. infrahub/graphql/types/event.py +167 -0
  312. infrahub/graphql/types/interface.py +2 -2
  313. infrahub/graphql/types/node.py +5 -5
  314. infrahub/graphql/types/permission.py +2 -2
  315. infrahub/graphql/types/relationship.py +3 -3
  316. infrahub/graphql/types/standard_node.py +9 -11
  317. infrahub/graphql/utils.py +30 -184
  318. infrahub/groups/ancestors.py +29 -0
  319. infrahub/groups/parsers.py +107 -0
  320. infrahub/groups/tasks.py +2 -3
  321. infrahub/lock.py +21 -21
  322. infrahub/menu/generator.py +7 -8
  323. infrahub/menu/menu.py +107 -139
  324. infrahub/menu/models.py +121 -20
  325. infrahub/menu/repository.py +111 -0
  326. infrahub/menu/utils.py +5 -8
  327. infrahub/message_bus/__init__.py +11 -13
  328. infrahub/message_bus/messages/__init__.py +1 -25
  329. infrahub/message_bus/messages/check_generator_run.py +3 -3
  330. infrahub/message_bus/messages/event_branch_merge.py +3 -0
  331. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  332. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  333. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  334. infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
  335. infrahub/message_bus/messages/send_echo_request.py +1 -1
  336. infrahub/message_bus/operations/__init__.py +4 -15
  337. infrahub/message_bus/operations/check/__init__.py +2 -2
  338. infrahub/message_bus/operations/check/generator.py +2 -3
  339. infrahub/message_bus/operations/event/__init__.py +2 -2
  340. infrahub/message_bus/operations/event/branch.py +7 -3
  341. infrahub/message_bus/operations/event/worker.py +0 -3
  342. infrahub/message_bus/operations/finalize/validator.py +52 -2
  343. infrahub/message_bus/operations/git/file.py +2 -2
  344. infrahub/message_bus/operations/git/repository.py +1 -1
  345. infrahub/message_bus/operations/requests/__init__.py +0 -4
  346. infrahub/message_bus/operations/requests/generator_definition.py +22 -24
  347. infrahub/message_bus/operations/requests/proposed_change.py +39 -20
  348. infrahub/message_bus/operations/send/echo.py +1 -1
  349. infrahub/message_bus/types.py +1 -1
  350. infrahub/permissions/globals.py +15 -0
  351. infrahub/pools/number.py +2 -4
  352. infrahub/pools/prefix.py +29 -165
  353. infrahub/prefect_server/__init__.py +0 -0
  354. infrahub/prefect_server/app.py +18 -0
  355. infrahub/prefect_server/database.py +20 -0
  356. infrahub/prefect_server/events.py +28 -0
  357. infrahub/prefect_server/models.py +46 -0
  358. infrahub/proposed_change/models.py +18 -1
  359. infrahub/proposed_change/tasks.py +204 -53
  360. infrahub/pytest_plugin.py +13 -10
  361. infrahub/server.py +13 -12
  362. infrahub/services/__init__.py +148 -63
  363. infrahub/services/adapters/cache/__init__.py +11 -11
  364. infrahub/services/adapters/cache/nats.py +42 -25
  365. infrahub/services/adapters/cache/redis.py +3 -11
  366. infrahub/services/adapters/event/__init__.py +11 -19
  367. infrahub/services/adapters/http/__init__.py +0 -5
  368. infrahub/services/adapters/http/httpx.py +22 -15
  369. infrahub/services/adapters/message_bus/__init__.py +25 -8
  370. infrahub/services/adapters/message_bus/local.py +9 -7
  371. infrahub/services/adapters/message_bus/nats.py +14 -8
  372. infrahub/services/adapters/message_bus/rabbitmq.py +23 -10
  373. infrahub/services/adapters/workflow/__init__.py +11 -8
  374. infrahub/services/adapters/workflow/local.py +27 -6
  375. infrahub/services/adapters/workflow/worker.py +23 -7
  376. infrahub/services/component.py +43 -40
  377. infrahub/services/protocols.py +7 -7
  378. infrahub/services/scheduler.py +30 -29
  379. infrahub/storage.py +2 -4
  380. infrahub/task_manager/constants.py +1 -1
  381. infrahub/task_manager/event.py +275 -0
  382. infrahub/task_manager/models.py +147 -3
  383. infrahub/task_manager/task.py +1 -1
  384. infrahub/tasks/artifact.py +20 -21
  385. infrahub/tasks/registry.py +1 -1
  386. infrahub/telemetry/__init__.py +0 -0
  387. infrahub/telemetry/constants.py +9 -0
  388. infrahub/telemetry/database.py +86 -0
  389. infrahub/telemetry/models.py +65 -0
  390. infrahub/telemetry/task_manager.py +77 -0
  391. infrahub/telemetry/tasks.py +119 -0
  392. infrahub/telemetry/utils.py +11 -0
  393. infrahub/transformations/tasks.py +5 -7
  394. infrahub/trigger/__init__.py +0 -0
  395. infrahub/trigger/catalogue.py +13 -0
  396. infrahub/trigger/constants.py +1 -0
  397. infrahub/trigger/models.py +118 -0
  398. infrahub/trigger/setup.py +90 -0
  399. infrahub/trigger/tasks.py +36 -0
  400. infrahub/types.py +1 -1
  401. infrahub/utils.py +12 -2
  402. infrahub/validators/__init__.py +0 -0
  403. infrahub/validators/events.py +42 -0
  404. infrahub/validators/tasks.py +41 -0
  405. infrahub/webhook/gather.py +17 -0
  406. infrahub/webhook/models.py +180 -42
  407. infrahub/webhook/tasks.py +149 -203
  408. infrahub/webhook/triggers.py +44 -0
  409. infrahub/workers/infrahub_async.py +38 -27
  410. infrahub/workers/utils.py +63 -0
  411. infrahub/workflows/catalogue.py +98 -71
  412. infrahub/workflows/initialization.py +12 -8
  413. infrahub/workflows/models.py +29 -5
  414. infrahub/workflows/utils.py +11 -2
  415. infrahub_sdk/client.py +19 -0
  416. infrahub_sdk/context.py +13 -0
  417. infrahub_sdk/ctl/branch.py +3 -2
  418. infrahub_sdk/ctl/utils.py +0 -16
  419. infrahub_sdk/exceptions.py +6 -0
  420. infrahub_sdk/generator.py +3 -0
  421. infrahub_sdk/graphql.py +45 -13
  422. infrahub_sdk/node.py +66 -20
  423. infrahub_sdk/protocols.py +21 -8
  424. infrahub_sdk/protocols_base.py +32 -11
  425. infrahub_sdk/schema/__init__.py +14 -2
  426. infrahub_sdk/schema/main.py +7 -0
  427. infrahub_sdk/task/__init__.py +11 -0
  428. infrahub_sdk/task/constants.py +3 -0
  429. infrahub_sdk/task/exceptions.py +25 -0
  430. infrahub_sdk/task/manager.py +551 -0
  431. infrahub_sdk/task/models.py +74 -0
  432. infrahub_sdk/timestamp.py +142 -33
  433. infrahub_sdk/utils.py +29 -1
  434. {infrahub_server-1.1.9.dist-info → infrahub_server-1.2.0.dist-info}/METADATA +8 -6
  435. infrahub_server-1.2.0.dist-info/RECORD +746 -0
  436. infrahub_testcontainers/container.py +5 -6
  437. infrahub_testcontainers/docker-compose.test.yml +2 -2
  438. infrahub_testcontainers/helpers.py +5 -1
  439. infrahub/core/branch/constants.py +0 -2
  440. infrahub/core/schema/definitions/core.py +0 -2275
  441. infrahub/graphql/query.py +0 -52
  442. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  443. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  444. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  445. infrahub/message_bus/messages/event_branch_create.py +0 -11
  446. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  447. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  448. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  449. infrahub/message_bus/messages/event_schema_update.py +0 -9
  450. infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
  451. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  452. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  453. infrahub/message_bus/operations/check/repository.py +0 -293
  454. infrahub/message_bus/operations/event/node.py +0 -20
  455. infrahub/message_bus/operations/event/schema.py +0 -17
  456. infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
  457. infrahub/message_bus/operations/requests/repository.py +0 -133
  458. infrahub/schema/constants.py +0 -1
  459. infrahub/schema/tasks.py +0 -76
  460. infrahub/services/adapters/database/__init__.py +0 -9
  461. infrahub/tasks/telemetry.py +0 -127
  462. infrahub/webhook/constants.py +0 -3
  463. infrahub_server-1.1.9.dist-info/RECORD +0 -688
  464. /infrahub/{schema → artifacts}/__init__.py +0 -0
  465. {infrahub_server-1.1.9.dist-info → infrahub_server-1.2.0.dist-info}/LICENSE.txt +0 -0
  466. {infrahub_server-1.1.9.dist-info → infrahub_server-1.2.0.dist-info}/WHEEL +0 -0
  467. {infrahub_server-1.1.9.dist-info → infrahub_server-1.2.0.dist-info}/entry_points.txt +0 -0
@@ -1,14 +1,14 @@
1
- from typing import Optional
2
-
1
+ from infrahub_sdk.protocols import CoreGeneratorValidator
3
2
  from infrahub_sdk.uuidt import UUIDT
4
3
  from prefect import flow
5
4
  from prefect.logging import get_run_logger
6
5
 
7
- from infrahub.core.constants import InfrahubKind, ValidatorConclusion, ValidatorState
6
+ from infrahub.core.constants import InfrahubKind
8
7
  from infrahub.core.timestamp import Timestamp
9
8
  from infrahub.message_bus import InfrahubMessage, Meta, messages
10
9
  from infrahub.message_bus.types import KVTTL
11
10
  from infrahub.services import InfrahubServices
11
+ from infrahub.validators.tasks import start_validator
12
12
  from infrahub.workflows.utils import add_tags
13
13
 
14
14
 
@@ -29,31 +29,26 @@ async def check(message: messages.RequestGeneratorDefinitionCheck, service: Infr
29
29
 
30
30
  await proposed_change.validations.fetch()
31
31
 
32
- validator = None
32
+ previous_validator: CoreGeneratorValidator | None = None
33
33
  for relationship in proposed_change.validations.peers:
34
34
  existing_validator = relationship.peer
35
35
  if (
36
36
  existing_validator.typename == InfrahubKind.GENERATORVALIDATOR
37
37
  and existing_validator.definition.id == message.generator_definition.definition_id
38
38
  ):
39
- validator = existing_validator
40
-
41
- if validator:
42
- validator.conclusion.value = ValidatorConclusion.UNKNOWN.value
43
- validator.state.value = ValidatorState.QUEUED.value
44
- validator.started_at.value = ""
45
- validator.completed_at.value = ""
46
- await validator.save()
47
- else:
48
- validator = await service.client.create(
49
- kind=InfrahubKind.GENERATORVALIDATOR,
50
- data={
51
- "label": validator_name,
52
- "proposed_change": message.proposed_change,
53
- "definition": message.generator_definition.definition_id,
54
- },
55
- )
56
- await validator.save()
39
+ previous_validator = existing_validator
40
+
41
+ validator = await start_validator(
42
+ service=service,
43
+ validator=previous_validator,
44
+ validator_type=CoreGeneratorValidator,
45
+ proposed_change=message.proposed_change,
46
+ data={
47
+ "label": validator_name,
48
+ "definition": message.generator_definition.definition_id,
49
+ },
50
+ context=message.context,
51
+ )
57
52
 
58
53
  group = await service.client.get(
59
54
  kind=InfrahubKind.GENERICGROUP,
@@ -92,6 +87,7 @@ async def check(message: messages.RequestGeneratorDefinitionCheck, service: Infr
92
87
  log.info(f"Trigger execution of {message.generator_definition.definition_name} for {member.display_label}")
93
88
  events.append(
94
89
  messages.CheckGeneratorRun(
90
+ context=message.context,
95
91
  generator_definition=message.generator_definition,
96
92
  generator_instance=generator_instance,
97
93
  commit=repository.source_commit,
@@ -121,14 +117,16 @@ async def check(message: messages.RequestGeneratorDefinitionCheck, service: Infr
121
117
  validator_id=validator.id,
122
118
  validator_execution_id=validator_execution_id,
123
119
  validator_type=InfrahubKind.GENERATORVALIDATOR,
120
+ context=message.context,
121
+ proposed_change=message.proposed_change,
124
122
  )
125
123
  )
126
124
  for event in events:
127
125
  event.assign_meta(parent=message)
128
- await service.send(message=event)
126
+ await service.message_bus.send(message=event)
129
127
 
130
128
 
131
- def _run_generator(instance_id: Optional[str], managed_branch: bool, impacted_instances: list[str]) -> bool:
129
+ def _run_generator(instance_id: str | None, managed_branch: bool, impacted_instances: list[str]) -> bool:
132
130
  """Returns a boolean to indicate if a generator instance needs to be executed
133
131
  Will return true if:
134
132
  * The instance_id wasn't set which could be that it's a new object that doesn't have a previous generator instance
@@ -11,6 +11,7 @@ from infrahub.core.constants import CheckType, InfrahubKind, RepositoryInternalS
11
11
  from infrahub.core.diff.coordinator import DiffCoordinator
12
12
  from infrahub.core.registry import registry
13
13
  from infrahub.dependencies.registry import get_component_registry
14
+ from infrahub.git.models import TriggerRepositoryInternalChecks
14
15
  from infrahub.git.repository import InfrahubRepository
15
16
  from infrahub.message_bus import InfrahubMessage, messages
16
17
  from infrahub.message_bus.types import (
@@ -20,6 +21,7 @@ from infrahub.message_bus.types import (
20
21
  ProposedChangeSubscriber,
21
22
  )
22
23
  from infrahub.proposed_change.models import (
24
+ RequestArtifactDefinitionCheck,
23
25
  RequestProposedChangeDataIntegrity,
24
26
  RequestProposedChangeRepositoryChecks,
25
27
  RequestProposedChangeRunGenerators,
@@ -28,6 +30,8 @@ from infrahub.proposed_change.models import (
28
30
  )
29
31
  from infrahub.services import InfrahubServices # noqa: TC001
30
32
  from infrahub.workflows.catalogue import (
33
+ GIT_REPOSITORY_INTERNAL_CHECKS_TRIGGER,
34
+ REQUEST_ARTIFACT_DEFINITION_CHECK,
31
35
  REQUEST_PROPOSED_CHANGE_DATA_INTEGRITY,
32
36
  REQUEST_PROPOSED_CHANGE_REPOSITORY_CHECKS,
33
37
  REQUEST_PROPOSED_CHANGE_RUN_GENERATORS,
@@ -74,17 +78,17 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
74
78
  ):
75
79
  for repo in repositories:
76
80
  if not repo.read_only and repo.internal_status == RepositoryInternalStatus.ACTIVE.value:
77
- events.append(
78
- messages.RequestRepositoryChecks(
79
- proposed_change=message.proposed_change,
80
- repository=repo.repository_id,
81
- source_branch=repo.source_branch,
82
- target_branch=repo.destination_branch,
83
- )
81
+ model = TriggerRepositoryInternalChecks(
82
+ proposed_change=message.proposed_change,
83
+ repository=repo.repository_id,
84
+ source_branch=repo.source_branch,
85
+ target_branch=repo.destination_branch,
86
+ )
87
+ await service.workflow.submit_workflow(
88
+ workflow=GIT_REPOSITORY_INTERNAL_CHECKS_TRIGGER,
89
+ context=message.context,
90
+ parameters={"model": model},
84
91
  )
85
- for event in events:
86
- event.assign_meta(parent=message)
87
- await service.send(message=event)
88
92
  return
89
93
 
90
94
  await _gather_repository_repository_diffs(repositories=repositories, service=service)
@@ -103,6 +107,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
103
107
  if message.check_type is CheckType.ARTIFACT:
104
108
  events.append(
105
109
  messages.RequestProposedChangeRefreshArtifacts(
110
+ context=message.context,
106
111
  proposed_change=message.proposed_change,
107
112
  source_branch=message.source_branch,
108
113
  source_branch_sync_with_git=message.source_branch_sync_with_git,
@@ -122,7 +127,9 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
122
127
  do_repository_checks=message.check_type is CheckType.ALL,
123
128
  )
124
129
  await service.workflow.submit_workflow(
125
- workflow=REQUEST_PROPOSED_CHANGE_RUN_GENERATORS, parameters={"model": model_proposed_change_run_generator}
130
+ workflow=REQUEST_PROPOSED_CHANGE_RUN_GENERATORS,
131
+ context=message.context,
132
+ parameters={"model": model_proposed_change_run_generator},
126
133
  )
127
134
 
128
135
  if message.check_type in [CheckType.ALL, CheckType.DATA] and branch_diff.has_node_changes(
@@ -136,7 +143,9 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
136
143
  branch_diff=branch_diff,
137
144
  )
138
145
  await service.workflow.submit_workflow(
139
- workflow=REQUEST_PROPOSED_CHANGE_DATA_INTEGRITY, parameters={"model": model_proposed_change_data_integrity}
146
+ workflow=REQUEST_PROPOSED_CHANGE_DATA_INTEGRITY,
147
+ context=message.context,
148
+ parameters={"model": model_proposed_change_data_integrity},
140
149
  )
141
150
 
142
151
  if message.check_type in [CheckType.REPOSITORY, CheckType.USER]:
@@ -148,7 +157,9 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
148
157
  branch_diff=branch_diff,
149
158
  )
150
159
  await service.workflow.submit_workflow(
151
- workflow=REQUEST_PROPOSED_CHANGE_REPOSITORY_CHECKS, parameters={"model": model_proposed_change_repo_checks}
160
+ workflow=REQUEST_PROPOSED_CHANGE_REPOSITORY_CHECKS,
161
+ context=message.context,
162
+ parameters={"model": model_proposed_change_repo_checks},
152
163
  )
153
164
 
154
165
  if message.check_type in [CheckType.ALL, CheckType.SCHEMA] and branch_diff.has_data_changes(
@@ -156,6 +167,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
156
167
  ):
157
168
  await service.workflow.submit_workflow(
158
169
  workflow=REQUEST_PROPOSED_CHANGE_SCHEMA_INTEGRITY,
170
+ context=message.context,
159
171
  parameters={
160
172
  "model": RequestProposedChangeSchemaIntegrity(
161
173
  proposed_change=message.proposed_change,
@@ -170,6 +182,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
170
182
  if message.check_type in [CheckType.ALL, CheckType.TEST]:
171
183
  await service.workflow.submit_workflow(
172
184
  workflow=REQUEST_PROPOSED_CHANGE_USER_TESTS,
185
+ context=message.context,
173
186
  parameters={
174
187
  "model": RequestProposedChangeUserTests(
175
188
  proposed_change=message.proposed_change,
@@ -183,7 +196,7 @@ async def pipeline(message: messages.RequestProposedChangePipeline, service: Inf
183
196
 
184
197
  for event in events:
185
198
  event.assign_meta(parent=message)
186
- await service.send(message=event)
199
+ await service.message_bus.send(message=event)
187
200
 
188
201
 
189
202
  @flow(
@@ -232,7 +245,8 @@ async def refresh_artifacts(message: messages.RequestProposedChangeRefreshArtifa
232
245
 
233
246
  if select:
234
247
  log.info(f"Trigger processing of {artifact_definition.definition_name}")
235
- msg = messages.RequestArtifactDefinitionCheck(
248
+ model = RequestArtifactDefinitionCheck(
249
+ context=message.context,
236
250
  artifact_definition=artifact_definition,
237
251
  branch_diff=message.branch_diff,
238
252
  proposed_change=message.proposed_change,
@@ -241,8 +255,7 @@ async def refresh_artifacts(message: messages.RequestProposedChangeRefreshArtifa
241
255
  destination_branch=message.destination_branch,
242
256
  )
243
257
 
244
- msg.assign_meta(parent=message)
245
- await service.send(message=msg)
258
+ await service.workflow.submit_workflow(REQUEST_ARTIFACT_DEFINITION_CHECK, parameters={"model": model})
246
259
 
247
260
 
248
261
  GATHER_ARTIFACT_DEFINITIONS = """
@@ -520,7 +533,7 @@ async def _get_proposed_change_repositories(
520
533
  return _parse_proposed_change_repositories(message=message, source=source_all, destination=destination_all)
521
534
 
522
535
 
523
- @task(name="proposed-change-validate-repository-conflicts", task_run_name="Validate conflicts on repository")
536
+ @task(name="proposed-change-validate-repository-conflicts", task_run_name="Validate conflicts on repository") # type: ignore[arg-type]
524
537
  async def _validate_repository_merge_conflicts(
525
538
  repositories: list[ProposedChangeRepository], service: InfrahubServices
526
539
  ) -> bool:
@@ -529,7 +542,10 @@ async def _validate_repository_merge_conflicts(
529
542
  for repo in repositories:
530
543
  if repo.has_diff and not repo.is_staging:
531
544
  git_repo = await InfrahubRepository.init(
532
- id=repo.repository_id, name=repo.repository_name, client=service.client
545
+ id=repo.repository_id,
546
+ name=repo.repository_name,
547
+ client=service.client,
548
+ service=service,
533
549
  )
534
550
  async with lock.registry.get(name=repo.repository_name, namespace="repository"):
535
551
  repo.conflicts = await git_repo.get_conflicts(
@@ -551,7 +567,10 @@ async def _gather_repository_repository_diffs(
551
567
  if repo.has_diff and repo.source_commit and repo.destination_commit:
552
568
  # TODO we need to find a way to return all files in the repo if the repo is new
553
569
  git_repo = await InfrahubRepository.init(
554
- id=repo.repository_id, name=repo.repository_name, client=service.client
570
+ id=repo.repository_id,
571
+ name=repo.repository_name,
572
+ client=service.client,
573
+ service=service,
555
574
  )
556
575
 
557
576
  files_changed: list[str] = []
@@ -10,4 +10,4 @@ async def request(message: messages.SendEchoRequest, service: InfrahubServices)
10
10
  service.log.info(f"Received message: {message.message}")
11
11
  if message.reply_requested:
12
12
  response = SendEchoRequestResponse(data=SendEchoRequestResponseData(response=f"Reply to: {message.message}"))
13
- await service.reply(message=response, initiator=message)
13
+ await service.message_bus.reply_if_initiator_meta(message=response, initiator=message)
@@ -9,7 +9,7 @@ from pydantic import BaseModel, Field
9
9
  from infrahub.core.constants import InfrahubKind, RepositoryInternalStatus
10
10
  from infrahub.exceptions import NodeNotFoundError
11
11
 
12
- SCHEMA_CHANGE = re.compile("^Schema[A-Z]")
12
+ SCHEMA_CHANGE = re.compile(r"^Schema[A-Z]")
13
13
 
14
14
 
15
15
  class MessageTTL(int, Enum):
@@ -0,0 +1,15 @@
1
+ from infrahub.core.account import GlobalPermission
2
+ from infrahub.core.constants import GLOBAL_BRANCH_NAME, GlobalPermissions, PermissionDecision
3
+ from infrahub.core.registry import registry
4
+
5
+
6
+ def define_global_permission_from_branch(permission: GlobalPermissions, branch_name: str) -> GlobalPermission:
7
+ if branch_name in (GLOBAL_BRANCH_NAME, registry.default_branch):
8
+ decision = PermissionDecision.ALLOW_DEFAULT
9
+ else:
10
+ decision = PermissionDecision.ALLOW_OTHER
11
+
12
+ return GlobalPermission(
13
+ action=permission.value,
14
+ decision=decision.value,
15
+ )
infrahub/pools/number.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Optional, Union
4
+ from typing import TYPE_CHECKING
5
5
 
6
6
  from infrahub.core.query.resource_manager import NumberPoolGetAllocated
7
7
  from infrahub.core.registry import registry
@@ -20,9 +20,7 @@ class UsedNumber:
20
20
 
21
21
 
22
22
  class NumberUtilizationGetter:
23
- def __init__(
24
- self, db: InfrahubDatabase, pool: CoreNode, branch: Branch, at: Optional[Union[Timestamp, str]] = None
25
- ) -> None:
23
+ def __init__(self, db: InfrahubDatabase, pool: CoreNode, branch: Branch, at: Timestamp | str | None = None) -> None:
26
24
  self.db = db
27
25
  self.at = at
28
26
  self.pool = pool
infrahub/pools/prefix.py CHANGED
@@ -1,174 +1,38 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import ipaddress
4
- from collections import OrderedDict, defaultdict
5
- from ipaddress import IPv4Network, IPv6Network
6
- from typing import Optional, Union
4
+ from typing import TYPE_CHECKING, Literal
7
5
 
6
+ from netaddr import IPSet
8
7
 
9
- class PrefixPool:
10
- """
11
- Class to automatically manage Prefixes and help to carve out sub-prefixes
12
- """
13
-
14
- def __init__(self, network: str) -> None:
15
- self.network = ipaddress.ip_network(network)
16
-
17
- # Define biggest and smallest possible masks
18
- self.mask_biggest = self.network.prefixlen + 1
19
- if self.network.version == 4:
20
- self.mask_smallest = 32
21
- else:
22
- self.mask_smallest = 128
23
-
24
- self.available_subnets = defaultdict(list)
25
- self.sub_by_key: dict[str, Optional[str]] = OrderedDict()
26
- self.sub_by_id: dict[str, str] = OrderedDict()
27
-
28
- # Save the top level available subnet
29
- for subnet in list(self.network.subnets(new_prefix=self.mask_biggest)):
30
- self.available_subnets[self.mask_biggest].append(str(subnet))
31
-
32
- def reserve(self, subnet: str, identifier: Optional[str] = None) -> bool:
33
- """
34
- Indicate that a specific subnet is already reserved/used
35
- """
36
-
37
- # TODO Add check to make sure the subnet provided has the right size
38
- sub = ipaddress.ip_network(subnet)
39
-
40
- if int(sub.prefixlen) <= int(self.network.prefixlen):
41
- raise ValueError(f"{subnet} do not have the right size ({sub.prefixlen},{self.network.prefixlen})")
42
-
43
- if sub.supernet(new_prefix=self.network.prefixlen) != self.network:
44
- raise ValueError(f"{subnet} is not part of this network")
45
-
46
- # Check first if this ID as already done a reservation
47
- if identifier and identifier in self.sub_by_id.keys():
48
- if self.sub_by_id[identifier] == str(sub):
49
- return True
50
- raise ValueError(
51
- f"this identifier ({identifier}) is already used but for a different resource ({self.sub_by_id[identifier]})"
52
- )
53
-
54
- if identifier and str(sub) in self.sub_by_key.keys():
55
- raise ValueError(f"this subnet is already reserved but not with this identifier ({identifier})")
56
-
57
- if str(sub) in self.sub_by_key.keys():
58
- self.remove_subnet_from_available_list(sub)
59
- return True
60
-
61
- # Check if the subnet itself is available
62
- # if available reserve and return
63
- if subnet in self.available_subnets[sub.prefixlen]:
64
- if identifier:
65
- self.sub_by_id[identifier] = subnet
66
- self.sub_by_key[subnet] = identifier
67
- else:
68
- self.sub_by_key[subnet] = None
69
-
70
- self.remove_subnet_from_available_list(sub)
71
- return True
72
-
73
- # If not reserved already, check if the subnet is available
74
- # start at sublen and check all available subnet
75
- # increase 1 by 1 until we find the closer supernet available
76
- # break it down and keep track of the other available subnets
8
+ if TYPE_CHECKING:
9
+ from infrahub.core.ipam.constants import IPNetworkType
77
10
 
78
- for sublen in range(sub.prefixlen - 1, self.network.prefixlen, -1):
79
- supernet = sub.supernet(new_prefix=sublen)
80
- if str(supernet) in self.available_subnets[sublen]:
81
- self.split_supernet(supernet=supernet, subnet=sub)
82
- return self.reserve(subnet=subnet, identifier=identifier)
83
11
 
84
- return False
12
+ def get_next_available_prefix(pool: IPSet, prefix_length: int, prefix_ver: Literal[4, 6] = 4) -> IPNetworkType:
13
+ """Get the next available prefix of a given prefix length from an IPSet.
85
14
 
86
- def get(self, prefixlen: int, identifier: Optional[str] = None) -> Union[IPv4Network, IPv6Network]:
87
- """Return the next available Subnet."""
15
+ Args:
16
+ pool: netaddr IPSet object with available subnets
17
+ prefix_length: length of the desired prefix
18
+ prefix_ver: IPSet can contain a mix of IPv4 and IPv6 subnets. This parameter specifies the IP version of prefix to acquire.
88
19
 
89
- clean_prefixlen = int(prefixlen)
90
-
91
- if identifier and identifier in self.sub_by_id.keys():
92
- net = ipaddress.ip_network(self.sub_by_id[identifier])
93
- if net.prefixlen == clean_prefixlen:
94
- return net
95
- raise ValueError()
96
-
97
- if len(self.available_subnets[clean_prefixlen]) != 0:
98
- sub = self.available_subnets[clean_prefixlen][0]
99
- self.reserve(subnet=sub, identifier=identifier)
100
- return ipaddress.ip_network(sub)
101
-
102
- # if a subnet of this size is not available
103
- # we need to find the closest subnet available and split it
104
- for i in range(clean_prefixlen - 1, self.mask_biggest - 1, -1):
105
- if len(self.available_subnets[i]) != 0:
106
- supernet = ipaddress.ip_network(self.available_subnets[i][0])
107
- # supernet available, will split it
108
- subs = supernet.subnets(new_prefix=clean_prefixlen)
109
- next_sub: Union[IPv4Network, IPv6Network] = next(subs) # type: ignore[assignment]
110
- self.split_supernet(supernet=supernet, subnet=next_sub)
111
- self.reserve(subnet=str(next_sub), identifier=identifier)
112
- return next_sub
113
-
114
- raise IndexError("No More subnet available")
115
-
116
- def get_nbr_available_subnets(self) -> dict[int, int]:
117
- tmp = {}
118
- for i in range(self.mask_biggest, self.mask_smallest + 1):
119
- tmp[i] = len(self.available_subnets[i])
120
-
121
- return tmp
122
-
123
- def check_if_already_allocated(self, identifier: str) -> bool:
124
- """
125
- Check if a subnet has already been allocated based on an identifier
126
-
127
- Need to add the same capability based on Network address
128
- If both identifier and subnet are provided, identifier take precedence
129
- """
130
- if identifier in self.sub_by_id.keys():
131
- return True
132
- return False
133
-
134
- def split_supernet(
135
- self, supernet: Union[IPv4Network, IPv6Network], subnet: Union[IPv4Network, IPv6Network]
136
- ) -> None:
137
- """Split a supernet into smaller networks"""
138
-
139
- # TODO ensure subnet is small than supernet
140
- # TODO ensure that subnet is part of supernet
141
- parent_net = supernet
142
- for i in range(supernet.prefixlen + 1, subnet.prefixlen + 1):
143
- tmp_net: list[Union[IPv4Network, IPv6Network]] = list(parent_net.subnets(new_prefix=i))
144
-
145
- if i == subnet.prefixlen:
146
- for net in tmp_net:
147
- self.available_subnets[i].append(str(net))
148
- else:
149
- if subnet.subnet_of(other=tmp_net[0]): # type: ignore[arg-type]
150
- parent = 0
151
- other = 1
152
- else:
153
- parent = 1
154
- other = 0
155
-
156
- parent_net = tmp_net[parent]
157
- self.available_subnets[i].append(str(tmp_net[other]))
158
-
159
- self.remove_subnet_from_available_list(supernet)
160
-
161
- def remove_subnet_from_available_list(self, subnet: Union[IPv4Network, IPv6Network]) -> None:
162
- """Remove a subnet from the list of available Subnet."""
163
- try:
164
- idx = self.available_subnets[subnet.prefixlen].index(str(subnet))
165
- del self.available_subnets[subnet.prefixlen][idx]
166
- except ValueError:
167
- # Already removed
168
- pass
169
-
170
- # if idx:
171
- # return True
172
- # except:
173
- # log.warn("Unable to remove %s from list of available subnets" % str(subnet))
174
- # return False
20
+ Raises:
21
+ ValueError: If there are no available subnets in the pool
22
+ """
23
+ prefix_ver_map = {
24
+ 4: ipaddress.IPv4Network,
25
+ 6: ipaddress.IPv6Network,
26
+ }
27
+
28
+ filtered_pool = IPSet([])
29
+ for subnet in pool.iter_cidrs():
30
+ if isinstance(ipaddress.ip_network(str(subnet)), prefix_ver_map[prefix_ver]):
31
+ filtered_pool.add(subnet)
32
+
33
+ for cidr in filtered_pool.iter_cidrs():
34
+ if cidr.prefixlen <= prefix_length:
35
+ next_available = ipaddress.ip_network(f"{cidr.network}/{prefix_length}")
36
+ return next_available
37
+
38
+ raise ValueError("No available subnets in pool")
File without changes
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from fastapi import APIRouter, FastAPI
4
+ from prefect.server.api.server import create_app
5
+
6
+ from . import events
7
+
8
+ router = APIRouter(prefix="/infrahub")
9
+
10
+ router.include_router(events.router)
11
+
12
+
13
+ def create_infrahub_prefect() -> FastAPI:
14
+ app = create_app()
15
+ api_app: FastAPI = app.__dict__["api_app"]
16
+ api_app.include_router(router=router)
17
+
18
+ return app
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from prefect.server.events.schemas.events import ReceivedEvent
6
+ from prefect.server.events.storage import INTERACTIVE_PAGE_SIZE
7
+ from prefect.server.events.storage.database import raw_count_events, read_events
8
+
9
+ if TYPE_CHECKING:
10
+ from prefect.server.events.filters import EventFilter
11
+ from sqlalchemy.ext.asyncio import AsyncSession
12
+
13
+
14
+ async def query_events(
15
+ session: AsyncSession, filter: EventFilter, page_size: int = INTERACTIVE_PAGE_SIZE, offset: int | None = None
16
+ ) -> tuple[list[ReceivedEvent], int]:
17
+ count = await raw_count_events(session, filter) # type: ignore[attr-defined]
18
+ page = await read_events(session, filter, limit=page_size, offset=offset) # type: ignore[attr-defined]
19
+ events = [ReceivedEvent.model_validate(e, from_attributes=True) for e in page]
20
+ return events, count
@@ -0,0 +1,28 @@
1
+ from fastapi import APIRouter
2
+ from fastapi.param_functions import Depends
3
+ from prefect.server.database import PrefectDBInterface, provide_database_interface
4
+
5
+ from .database import query_events
6
+ from .models import InfrahubEventfilterInput, InfrahubEventPage
7
+
8
+ router = APIRouter(prefix="/events", tags=["Infrahub"])
9
+
10
+
11
+ @router.post(
12
+ "/filter",
13
+ )
14
+ async def read_events(
15
+ event_filter: InfrahubEventfilterInput,
16
+ db: PrefectDBInterface = Depends(provide_database_interface), # noqa: B008
17
+ ) -> InfrahubEventPage:
18
+ event_filter.filter.set_prefix()
19
+
20
+ async with db.session_context() as session:
21
+ events, total = await query_events(
22
+ session=session, filter=event_filter.filter, page_size=event_filter.limit, offset=event_filter.offset
23
+ )
24
+
25
+ return InfrahubEventPage(
26
+ events=events,
27
+ total=total,
28
+ )
@@ -0,0 +1,46 @@
1
+ from typing import TYPE_CHECKING, Sequence, cast
2
+
3
+ from prefect.server.database import PrefectDBInterface, db_injector
4
+ from prefect.server.events.filters import EventFilter, EventNameFilter, EventOrder, EventRelatedFilter
5
+ from prefect.server.events.schemas.events import ReceivedEvent
6
+ from prefect.server.utilities.schemas import PrefectBaseModel
7
+ from pydantic import BaseModel, Field
8
+
9
+ if TYPE_CHECKING:
10
+ from sqlalchemy.sql.expression import ColumnExpressionArgument
11
+
12
+
13
+ class InfrahubEventFilter(EventFilter):
14
+ matching_related: list[EventRelatedFilter] = Field(default_factory=list)
15
+
16
+ def set_prefix(self) -> None:
17
+ if self.event:
18
+ if self.event.prefix is not None and "infrahub." not in self.event.prefix:
19
+ self.event.prefix.append("infrahub.")
20
+ else:
21
+ self.event = EventNameFilter(prefix=["infrahub."], name=[], exclude_prefix=None, exclude_name=None)
22
+
23
+ @db_injector
24
+ def build_where_clauses(self, db: PrefectDBInterface) -> Sequence["ColumnExpressionArgument[bool]"]:
25
+ result = cast(list["ColumnExpressionArgument[bool]"], super().build_where_clauses())
26
+ top_level_filter = self._scoped_event_resources(db)
27
+ for matching_related in self.matching_related:
28
+ matching_related._top_level_filter = top_level_filter
29
+ result.extend(matching_related.build_where_clauses())
30
+
31
+ return result
32
+
33
+ @classmethod
34
+ def default(cls) -> "InfrahubEventFilter":
35
+ return cls(event=None, any_resource=None, resource=None, related=None, order=EventOrder.DESC)
36
+
37
+
38
+ class InfrahubEventPage(PrefectBaseModel):
39
+ events: list[ReceivedEvent] = Field(..., description="The Events matching the query")
40
+ total: int = Field(..., description="The total number of matching Events")
41
+
42
+
43
+ class InfrahubEventfilterInput(BaseModel):
44
+ limit: int = Field(default=50)
45
+ filter: InfrahubEventFilter = Field(default_factory=InfrahubEventFilter.default)
46
+ offset: int | None = Field(default=None)
@@ -1,6 +1,8 @@
1
- from pydantic import Field
1
+ from pydantic import BaseModel, ConfigDict, Field
2
2
 
3
+ from infrahub.context import InfrahubContext
3
4
  from infrahub.message_bus.messages.proposed_change.base_with_diff import BaseProposedChangeWithDiffMessage
5
+ from infrahub.message_bus.types import ProposedChangeArtifactDefinition, ProposedChangeBranchDiff
4
6
 
5
7
 
6
8
  class RequestProposedChangeDataIntegrity(BaseProposedChangeWithDiffMessage):
@@ -26,3 +28,18 @@ class RequestProposedChangeSchemaIntegrity(BaseProposedChangeWithDiffMessage):
26
28
 
27
29
  class RequestProposedChangeUserTests(BaseProposedChangeWithDiffMessage):
28
30
  """Sent trigger to run tests (smoke, units, integrations) for a proposed change."""
31
+
32
+
33
+ class RequestArtifactDefinitionCheck(BaseModel):
34
+ """Sent to validate the generation of artifacts in relation to a proposed change."""
35
+
36
+ model_config = ConfigDict(arbitrary_types_allowed=True)
37
+
38
+ artifact_definition: ProposedChangeArtifactDefinition = Field(..., description="The Artifact Definition")
39
+ branch_diff: ProposedChangeBranchDiff = Field(..., description="The calculated diff between the two branches")
40
+ proposed_change: str = Field(..., description="The unique ID of the Proposed Change")
41
+ source_branch: str = Field(..., description="The source branch")
42
+ source_branch_sync_with_git: bool = Field(..., description="Indicates if the source branch should sync with git")
43
+ destination_branch: str = Field(..., description="The target branch")
44
+
45
+ context: InfrahubContext = Field(..., description="The context of the task")