infrahub-server 1.2.0rc0__py3-none-any.whl → 1.2.1__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 (365) hide show
  1. infrahub/api/dependencies.py +6 -6
  2. infrahub/api/diff/validation_models.py +7 -7
  3. infrahub/api/schema.py +1 -1
  4. infrahub/artifacts/models.py +5 -3
  5. infrahub/artifacts/tasks.py +3 -5
  6. infrahub/cli/__init__.py +13 -9
  7. infrahub/cli/constants.py +3 -0
  8. infrahub/cli/db.py +165 -183
  9. infrahub/cli/upgrade.py +146 -0
  10. infrahub/computed_attribute/gather.py +185 -0
  11. infrahub/computed_attribute/models.py +240 -12
  12. infrahub/computed_attribute/tasks.py +77 -441
  13. infrahub/computed_attribute/triggers.py +13 -47
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +58 -58
  18. infrahub/core/branch/tasks.py +74 -22
  19. infrahub/core/changelog/diff.py +95 -36
  20. infrahub/core/changelog/models.py +217 -43
  21. infrahub/core/constants/__init__.py +28 -0
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constants/schema.py +2 -0
  24. infrahub/core/constraint/node/runner.py +9 -8
  25. infrahub/core/diff/branch_differ.py +10 -10
  26. infrahub/core/diff/enricher/cardinality_one.py +5 -0
  27. infrahub/core/diff/enricher/hierarchy.py +17 -4
  28. infrahub/core/diff/enricher/labels.py +5 -0
  29. infrahub/core/diff/enricher/path_identifier.py +4 -0
  30. infrahub/core/diff/ipam_diff_parser.py +4 -5
  31. infrahub/core/diff/model/diff.py +27 -27
  32. infrahub/core/diff/model/path.py +32 -9
  33. infrahub/core/diff/parent_node_adder.py +78 -0
  34. infrahub/core/diff/payload_builder.py +13 -2
  35. infrahub/core/diff/query/filters.py +2 -2
  36. infrahub/core/diff/query/merge.py +20 -17
  37. infrahub/core/diff/query/save.py +188 -182
  38. infrahub/core/diff/query/summary_counts_enricher.py +51 -4
  39. infrahub/core/diff/query_parser.py +4 -4
  40. infrahub/core/diff/repository/deserializer.py +8 -3
  41. infrahub/core/diff/repository/repository.py +156 -38
  42. infrahub/core/diff/tasks.py +4 -4
  43. infrahub/core/graph/__init__.py +1 -1
  44. infrahub/core/graph/index.py +3 -0
  45. infrahub/core/initialization.py +1 -10
  46. infrahub/core/ipam/constants.py +3 -4
  47. infrahub/core/ipam/reconciler.py +12 -12
  48. infrahub/core/ipam/utilization.py +10 -13
  49. infrahub/core/manager.py +36 -36
  50. infrahub/core/merge.py +7 -7
  51. infrahub/core/migrations/__init__.py +2 -3
  52. infrahub/core/migrations/graph/__init__.py +12 -3
  53. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  54. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  55. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  56. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  57. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  58. infrahub/core/migrations/graph/m022_add_generate_template_attr.py +48 -0
  59. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  60. infrahub/core/migrations/query/attribute_add.py +2 -2
  61. infrahub/core/migrations/query/node_duplicate.py +43 -26
  62. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  63. infrahub/core/migrations/schema/models.py +19 -4
  64. infrahub/core/migrations/schema/node_remove.py +26 -12
  65. infrahub/core/migrations/schema/tasks.py +2 -2
  66. infrahub/core/migrations/shared.py +16 -16
  67. infrahub/core/models.py +15 -6
  68. infrahub/core/node/__init__.py +43 -39
  69. infrahub/core/node/base.py +2 -4
  70. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  71. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  72. infrahub/core/node/constraints/interface.py +1 -2
  73. infrahub/core/node/delete_validator.py +3 -5
  74. infrahub/core/node/ipam.py +4 -4
  75. infrahub/core/node/permissions.py +7 -7
  76. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  77. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  78. infrahub/core/node/resource_manager/number_pool.py +3 -3
  79. infrahub/core/path.py +12 -12
  80. infrahub/core/property.py +11 -11
  81. infrahub/core/protocols.py +7 -0
  82. infrahub/core/protocols_base.py +21 -21
  83. infrahub/core/query/__init__.py +33 -33
  84. infrahub/core/query/attribute.py +6 -4
  85. infrahub/core/query/diff.py +3 -3
  86. infrahub/core/query/node.py +82 -32
  87. infrahub/core/query/relationship.py +228 -40
  88. infrahub/core/query/resource_manager.py +2 -0
  89. infrahub/core/query/standard_node.py +3 -3
  90. infrahub/core/query/subquery.py +9 -9
  91. infrahub/core/registry.py +13 -15
  92. infrahub/core/relationship/constraints/count.py +3 -4
  93. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  94. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  95. infrahub/core/relationship/model.py +51 -59
  96. infrahub/core/schema/attribute_schema.py +16 -8
  97. infrahub/core/schema/basenode_schema.py +105 -44
  98. infrahub/core/schema/computed_attribute.py +3 -3
  99. infrahub/core/schema/definitions/core/__init__.py +147 -0
  100. infrahub/core/schema/definitions/core/account.py +171 -0
  101. infrahub/core/schema/definitions/core/artifact.py +136 -0
  102. infrahub/core/schema/definitions/core/builtin.py +24 -0
  103. infrahub/core/schema/definitions/core/check.py +68 -0
  104. infrahub/core/schema/definitions/core/core.py +17 -0
  105. infrahub/core/schema/definitions/core/generator.py +100 -0
  106. infrahub/core/schema/definitions/core/graphql_query.py +79 -0
  107. infrahub/core/schema/definitions/core/group.py +108 -0
  108. infrahub/core/schema/definitions/core/ipam.py +193 -0
  109. infrahub/core/schema/definitions/core/lineage.py +19 -0
  110. infrahub/core/schema/definitions/core/menu.py +48 -0
  111. infrahub/core/schema/definitions/core/permission.py +163 -0
  112. infrahub/core/schema/definitions/core/profile.py +18 -0
  113. infrahub/core/schema/definitions/core/propose_change.py +97 -0
  114. infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
  115. infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
  116. infrahub/core/schema/definitions/core/repository.py +286 -0
  117. infrahub/core/schema/definitions/core/resource_pool.py +170 -0
  118. infrahub/core/schema/definitions/core/template.py +27 -0
  119. infrahub/core/schema/definitions/core/transform.py +96 -0
  120. infrahub/core/schema/definitions/core/webhook.py +134 -0
  121. infrahub/core/schema/definitions/internal.py +16 -16
  122. infrahub/core/schema/dropdown.py +3 -4
  123. infrahub/core/schema/generated/attribute_schema.py +15 -18
  124. infrahub/core/schema/generated/base_node_schema.py +12 -14
  125. infrahub/core/schema/generated/node_schema.py +3 -5
  126. infrahub/core/schema/generated/relationship_schema.py +9 -11
  127. infrahub/core/schema/generic_schema.py +2 -2
  128. infrahub/core/schema/manager.py +20 -9
  129. infrahub/core/schema/node_schema.py +4 -2
  130. infrahub/core/schema/relationship_schema.py +14 -6
  131. infrahub/core/schema/schema_branch.py +292 -144
  132. infrahub/core/schema/schema_branch_computed.py +41 -4
  133. infrahub/core/task/task.py +3 -3
  134. infrahub/core/task/user_task.py +15 -15
  135. infrahub/core/timestamp.py +3 -3
  136. infrahub/core/utils.py +20 -18
  137. infrahub/core/validators/__init__.py +1 -3
  138. infrahub/core/validators/aggregated_checker.py +2 -2
  139. infrahub/core/validators/attribute/choices.py +2 -2
  140. infrahub/core/validators/attribute/enum.py +2 -2
  141. infrahub/core/validators/attribute/kind.py +2 -2
  142. infrahub/core/validators/attribute/length.py +2 -2
  143. infrahub/core/validators/attribute/optional.py +2 -2
  144. infrahub/core/validators/attribute/regex.py +2 -2
  145. infrahub/core/validators/attribute/unique.py +2 -2
  146. infrahub/core/validators/checks_runner.py +25 -2
  147. infrahub/core/validators/determiner.py +1 -3
  148. infrahub/core/validators/interface.py +6 -2
  149. infrahub/core/validators/model.py +22 -3
  150. infrahub/core/validators/models/validate_migration.py +17 -4
  151. infrahub/core/validators/node/attribute.py +2 -2
  152. infrahub/core/validators/node/generate_profile.py +2 -2
  153. infrahub/core/validators/node/hierarchy.py +3 -5
  154. infrahub/core/validators/node/inherit_from.py +27 -5
  155. infrahub/core/validators/node/relationship.py +2 -2
  156. infrahub/core/validators/relationship/count.py +4 -4
  157. infrahub/core/validators/relationship/optional.py +2 -2
  158. infrahub/core/validators/relationship/peer.py +2 -2
  159. infrahub/core/validators/shared.py +2 -2
  160. infrahub/core/validators/tasks.py +8 -0
  161. infrahub/core/validators/uniqueness/checker.py +22 -21
  162. infrahub/core/validators/uniqueness/index.py +2 -2
  163. infrahub/core/validators/uniqueness/model.py +11 -11
  164. infrahub/database/__init__.py +27 -22
  165. infrahub/database/metrics.py +7 -1
  166. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  167. infrahub/dependencies/builder/diff/deserializer.py +3 -1
  168. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  169. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  170. infrahub/dependencies/component/registry.py +2 -2
  171. infrahub/events/__init__.py +25 -2
  172. infrahub/events/artifact_action.py +64 -0
  173. infrahub/events/branch_action.py +33 -22
  174. infrahub/events/generator.py +71 -0
  175. infrahub/events/group_action.py +51 -21
  176. infrahub/events/models.py +18 -19
  177. infrahub/events/node_action.py +88 -37
  178. infrahub/events/repository_action.py +5 -18
  179. infrahub/events/schema_action.py +4 -9
  180. infrahub/events/utils.py +16 -0
  181. infrahub/events/validator_action.py +55 -0
  182. infrahub/exceptions.py +32 -24
  183. infrahub/generators/models.py +2 -3
  184. infrahub/generators/tasks.py +24 -4
  185. infrahub/git/base.py +7 -7
  186. infrahub/git/integrator.py +48 -24
  187. infrahub/git/models.py +101 -9
  188. infrahub/git/repository.py +3 -3
  189. infrahub/git/tasks.py +408 -6
  190. infrahub/git/utils.py +48 -0
  191. infrahub/git/worktree.py +1 -2
  192. infrahub/git_credential/askpass.py +1 -2
  193. infrahub/graphql/analyzer.py +12 -0
  194. infrahub/graphql/app.py +13 -15
  195. infrahub/graphql/context.py +39 -0
  196. infrahub/graphql/initialization.py +3 -0
  197. infrahub/graphql/loaders/node.py +2 -12
  198. infrahub/graphql/loaders/peers.py +77 -0
  199. infrahub/graphql/loaders/shared.py +13 -0
  200. infrahub/graphql/manager.py +17 -19
  201. infrahub/graphql/mutations/artifact_definition.py +5 -5
  202. infrahub/graphql/mutations/branch.py +26 -1
  203. infrahub/graphql/mutations/computed_attribute.py +9 -5
  204. infrahub/graphql/mutations/diff.py +23 -11
  205. infrahub/graphql/mutations/diff_conflict.py +5 -0
  206. infrahub/graphql/mutations/generator.py +83 -0
  207. infrahub/graphql/mutations/graphql_query.py +5 -5
  208. infrahub/graphql/mutations/ipam.py +54 -74
  209. infrahub/graphql/mutations/main.py +195 -132
  210. infrahub/graphql/mutations/menu.py +7 -7
  211. infrahub/graphql/mutations/models.py +2 -4
  212. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  213. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  214. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  215. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  216. infrahub/graphql/mutations/proposed_change.py +7 -7
  217. infrahub/graphql/mutations/relationship.py +93 -19
  218. infrahub/graphql/mutations/repository.py +8 -8
  219. infrahub/graphql/mutations/resource_manager.py +3 -3
  220. infrahub/graphql/mutations/schema.py +19 -4
  221. infrahub/graphql/mutations/webhook.py +137 -0
  222. infrahub/graphql/parser.py +4 -4
  223. infrahub/graphql/permissions.py +1 -10
  224. infrahub/graphql/queries/diff/tree.py +19 -14
  225. infrahub/graphql/queries/event.py +5 -2
  226. infrahub/graphql/queries/ipam.py +2 -2
  227. infrahub/graphql/queries/relationship.py +2 -2
  228. infrahub/graphql/queries/search.py +2 -2
  229. infrahub/graphql/resolvers/many_relationship.py +264 -0
  230. infrahub/graphql/resolvers/resolver.py +13 -110
  231. infrahub/graphql/schema.py +2 -0
  232. infrahub/graphql/subscription/graphql_query.py +2 -0
  233. infrahub/graphql/types/context.py +12 -0
  234. infrahub/graphql/types/event.py +84 -17
  235. infrahub/graphql/types/node.py +2 -2
  236. infrahub/graphql/utils.py +2 -2
  237. infrahub/groups/ancestors.py +29 -0
  238. infrahub/groups/parsers.py +107 -0
  239. infrahub/lock.py +20 -20
  240. infrahub/menu/constants.py +0 -1
  241. infrahub/menu/generator.py +9 -21
  242. infrahub/menu/menu.py +17 -38
  243. infrahub/menu/models.py +117 -16
  244. infrahub/menu/repository.py +111 -0
  245. infrahub/menu/utils.py +5 -8
  246. infrahub/message_bus/__init__.py +11 -13
  247. infrahub/message_bus/messages/__init__.py +1 -21
  248. infrahub/message_bus/messages/check_generator_run.py +3 -3
  249. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  250. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  251. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  252. infrahub/message_bus/messages/send_echo_request.py +1 -1
  253. infrahub/message_bus/operations/__init__.py +1 -10
  254. infrahub/message_bus/operations/check/__init__.py +2 -2
  255. infrahub/message_bus/operations/check/generator.py +1 -0
  256. infrahub/message_bus/operations/event/__init__.py +2 -2
  257. infrahub/message_bus/operations/event/worker.py +0 -3
  258. infrahub/message_bus/operations/finalize/validator.py +51 -1
  259. infrahub/message_bus/operations/requests/__init__.py +0 -2
  260. infrahub/message_bus/operations/requests/generator_definition.py +21 -23
  261. infrahub/message_bus/operations/requests/proposed_change.py +14 -10
  262. infrahub/permissions/globals.py +15 -0
  263. infrahub/pools/number.py +2 -4
  264. infrahub/proposed_change/models.py +3 -0
  265. infrahub/proposed_change/tasks.py +58 -45
  266. infrahub/pytest_plugin.py +13 -10
  267. infrahub/server.py +2 -3
  268. infrahub/services/__init__.py +2 -2
  269. infrahub/services/adapters/cache/__init__.py +4 -6
  270. infrahub/services/adapters/cache/nats.py +4 -5
  271. infrahub/services/adapters/cache/redis.py +3 -7
  272. infrahub/services/adapters/event/__init__.py +1 -1
  273. infrahub/services/adapters/message_bus/__init__.py +3 -3
  274. infrahub/services/adapters/message_bus/local.py +2 -2
  275. infrahub/services/adapters/message_bus/nats.py +4 -4
  276. infrahub/services/adapters/message_bus/rabbitmq.py +4 -4
  277. infrahub/services/adapters/workflow/local.py +2 -2
  278. infrahub/services/component.py +5 -5
  279. infrahub/services/protocols.py +7 -7
  280. infrahub/services/scheduler.py +1 -3
  281. infrahub/task_manager/event.py +102 -9
  282. infrahub/task_manager/models.py +27 -7
  283. infrahub/tasks/artifact.py +7 -6
  284. infrahub/telemetry/__init__.py +0 -0
  285. infrahub/telemetry/constants.py +9 -0
  286. infrahub/telemetry/database.py +86 -0
  287. infrahub/telemetry/models.py +65 -0
  288. infrahub/telemetry/task_manager.py +77 -0
  289. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  290. infrahub/telemetry/utils.py +11 -0
  291. infrahub/trace.py +4 -4
  292. infrahub/transformations/tasks.py +2 -2
  293. infrahub/trigger/catalogue.py +4 -6
  294. infrahub/trigger/constants.py +0 -8
  295. infrahub/trigger/models.py +54 -5
  296. infrahub/trigger/setup.py +90 -0
  297. infrahub/trigger/tasks.py +35 -84
  298. infrahub/utils.py +11 -1
  299. infrahub/validators/__init__.py +0 -0
  300. infrahub/validators/events.py +42 -0
  301. infrahub/validators/tasks.py +41 -0
  302. infrahub/webhook/gather.py +17 -0
  303. infrahub/webhook/models.py +176 -44
  304. infrahub/webhook/tasks.py +154 -155
  305. infrahub/webhook/triggers.py +31 -7
  306. infrahub/workers/infrahub_async.py +2 -2
  307. infrahub/workers/utils.py +2 -2
  308. infrahub/workflows/catalogue.py +86 -35
  309. infrahub/workflows/initialization.py +8 -2
  310. infrahub/workflows/models.py +27 -1
  311. infrahub/workflows/utils.py +10 -1
  312. infrahub_sdk/client.py +35 -8
  313. infrahub_sdk/config.py +3 -0
  314. infrahub_sdk/context.py +13 -0
  315. infrahub_sdk/ctl/branch.py +3 -2
  316. infrahub_sdk/ctl/cli_commands.py +5 -1
  317. infrahub_sdk/ctl/utils.py +0 -16
  318. infrahub_sdk/exceptions.py +12 -0
  319. infrahub_sdk/generator.py +4 -1
  320. infrahub_sdk/graphql.py +45 -13
  321. infrahub_sdk/node.py +71 -22
  322. infrahub_sdk/protocols.py +21 -8
  323. infrahub_sdk/protocols_base.py +32 -11
  324. infrahub_sdk/query_groups.py +6 -35
  325. infrahub_sdk/schema/__init__.py +55 -26
  326. infrahub_sdk/schema/main.py +8 -0
  327. infrahub_sdk/task/__init__.py +11 -0
  328. infrahub_sdk/task/constants.py +3 -0
  329. infrahub_sdk/task/exceptions.py +25 -0
  330. infrahub_sdk/task/manager.py +551 -0
  331. infrahub_sdk/task/models.py +74 -0
  332. infrahub_sdk/testing/schemas/animal.py +9 -0
  333. infrahub_sdk/timestamp.py +142 -33
  334. infrahub_sdk/utils.py +29 -1
  335. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +8 -6
  336. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +349 -293
  337. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
  338. infrahub_testcontainers/constants.py +2 -0
  339. infrahub_testcontainers/container.py +157 -12
  340. infrahub_testcontainers/docker-compose.test.yml +31 -6
  341. infrahub_testcontainers/helpers.py +18 -73
  342. infrahub_testcontainers/host.py +41 -0
  343. infrahub_testcontainers/measurements.py +93 -0
  344. infrahub_testcontainers/models.py +38 -0
  345. infrahub_testcontainers/performance_test.py +166 -0
  346. infrahub_testcontainers/plugin.py +136 -0
  347. infrahub_testcontainers/prometheus.yml +30 -0
  348. infrahub/core/schema/definitions/core.py +0 -2286
  349. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  350. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  351. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  352. infrahub/message_bus/messages/event_branch_create.py +0 -11
  353. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  354. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  355. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  356. infrahub/message_bus/messages/event_schema_update.py +0 -9
  357. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  358. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  359. infrahub/message_bus/operations/check/repository.py +0 -293
  360. infrahub/message_bus/operations/event/node.py +0 -20
  361. infrahub/message_bus/operations/event/schema.py +0 -17
  362. infrahub/message_bus/operations/requests/repository.py +0 -133
  363. infrahub/webhook/constants.py +0 -1
  364. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
  365. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
infrahub/trace.py CHANGED
@@ -9,7 +9,7 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
9
9
  )
10
10
  from opentelemetry.sdk.resources import Resource
11
11
  from opentelemetry.sdk.trace import TracerProvider
12
- from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
12
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter, SpanExporter
13
13
  from opentelemetry.trace import StatusCode
14
14
 
15
15
  from infrahub.worker import WORKER_IDENTITY
@@ -19,7 +19,7 @@ def get_current_span_with_context() -> trace.Span:
19
19
  return trace.get_current_span()
20
20
 
21
21
 
22
- def get_traceid() -> str:
22
+ def get_traceid() -> str | None:
23
23
  current_span = get_current_span_with_context()
24
24
  trace_id = current_span.get_span_context().trace_id
25
25
  if trace_id == 0:
@@ -63,7 +63,7 @@ def create_tracer_provider(
63
63
  ) -> TracerProvider:
64
64
  # Create a BatchSpanProcessor exporter based on the type
65
65
  if exporter_type == "console":
66
- exporter = ConsoleSpanExporter()
66
+ exporter: SpanExporter = ConsoleSpanExporter()
67
67
  elif exporter_type == "otlp":
68
68
  if not exporter_endpoint:
69
69
  raise ValueError("Exporter type is set to otlp but endpoint is not set")
@@ -76,7 +76,7 @@ def create_tracer_provider(
76
76
 
77
77
  extra_attributes = {}
78
78
  if os.getenv("OTEL_RESOURCE_ATTRIBUTES"):
79
- extra_attributes = dict(attr.split("=") for attr in os.getenv("OTEL_RESOURCE_ATTRIBUTES").split(","))
79
+ extra_attributes = dict(attr.split("=") for attr in os.getenv("OTEL_RESOURCE_ATTRIBUTES", "").split(","))
80
80
 
81
81
  # Resource can be required for some backends, e.g. Jaeger
82
82
  resource = Resource(
@@ -30,7 +30,7 @@ async def transform_python(message: TransformPythonData, service: InfrahubServic
30
30
  location=message.transform_location,
31
31
  data=message.data,
32
32
  client=service.client,
33
- )
33
+ ) # type: ignore[misc]
34
34
 
35
35
  return transformed_data
36
36
 
@@ -49,6 +49,6 @@ async def transform_render_jinja2_template(message: TransformJinjaTemplateData,
49
49
 
50
50
  rendered_template = await repo.render_jinja2_template.with_options(timeout_seconds=message.timeout)(
51
51
  commit=message.commit, location=message.template_location, data={"data": message.data}
52
- )
52
+ ) # type: ignore[misc]
53
53
 
54
54
  return rendered_template
@@ -1,15 +1,13 @@
1
1
  from infrahub.computed_attribute.triggers import (
2
2
  TRIGGER_COMPUTED_ATTRIBUTE_ALL_SCHEMA,
3
- TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_CLEAN_BRANCH,
4
- TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_SETUP_BRANCH,
5
3
  TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_SETUP_COMMIT,
6
4
  )
7
- from infrahub.webhook.triggers import TRIGGER_WEBHOOK_SETUP_UPDATE
5
+ from infrahub.trigger.models import TriggerDefinition
6
+ from infrahub.webhook.triggers import TRIGGER_WEBHOOK_DELETE, TRIGGER_WEBHOOK_SETUP_UPDATE
8
7
 
9
- triggers = [
8
+ builtin_triggers: list[TriggerDefinition] = [
10
9
  TRIGGER_COMPUTED_ATTRIBUTE_ALL_SCHEMA,
11
- TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_CLEAN_BRANCH,
12
- TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_SETUP_BRANCH,
13
10
  TRIGGER_COMPUTED_ATTRIBUTE_PYTHON_SETUP_COMMIT,
11
+ TRIGGER_WEBHOOK_DELETE,
14
12
  TRIGGER_WEBHOOK_SETUP_UPDATE,
15
13
  ]
@@ -1,9 +1 @@
1
- DEPRECATED_STATIC_TRIGGER_NAMES = [
2
- "Trigger-branch-create-events", # used in 1.1.x
3
- "Trigger-branch-remove-events", # used in 1.1.x
4
- "Trigger-webhook-update-configuration", # used in 1.1.x
5
- "Trigger-repository-commit-update-event", # used in 1.1.x
6
- "Trigger-schema-update-event", # used in 1.1.x
7
- ]
8
-
9
1
  NAME_SEPARATOR = "::"
@@ -1,7 +1,8 @@
1
+ from __future__ import annotations
2
+
1
3
  from datetime import timedelta
2
4
  from enum import Enum
3
- from typing import Any
4
- from uuid import UUID
5
+ from typing import TYPE_CHECKING, Any
5
6
 
6
7
  from prefect.events.actions import RunDeployment
7
8
  from prefect.events.schemas.automations import EventTrigger as PrefectEventTrigger
@@ -9,13 +10,22 @@ from prefect.events.schemas.automations import Posture
9
10
  from prefect.events.schemas.events import ResourceSpecification
10
11
  from pydantic import BaseModel, Field
11
12
 
13
+ from infrahub import __version__
14
+ from infrahub.workflows.models import WorkflowDefinition # noqa: TC001
15
+
12
16
  from .constants import NAME_SEPARATOR
13
17
 
18
+ if TYPE_CHECKING:
19
+ from uuid import UUID
20
+
14
21
 
15
22
  class TriggerType(str, Enum):
16
23
  BUILTIN = "builtin"
24
+ WEBHOOK = "webhook"
25
+ COMPUTED_ATTR_JINJA2 = "computed_attr_jinja2"
26
+ COMPUTED_ATTR_PYTHON = "computed_attr_python"
27
+ COMPUTED_ATTR_PYTHON_QUERY = "computed_attr_python_query"
17
28
  # OBJECT = "object"
18
- # COMPUTED_ATTR = "computed_attr"
19
29
 
20
30
 
21
31
  class EventTrigger(BaseModel):
@@ -35,19 +45,44 @@ class EventTrigger(BaseModel):
35
45
 
36
46
 
37
47
  class ExecuteWorkflow(BaseModel):
38
- name: str
48
+ workflow: WorkflowDefinition
39
49
  parameters: dict[str, Any] = Field(default_factory=dict)
40
50
 
51
+ @property
52
+ def name(self) -> str:
53
+ return self.workflow.name
54
+
41
55
  def get_prefect(self, mapping: dict[str, UUID]) -> RunDeployment:
42
56
  deployment_id = mapping[self.name]
57
+ return self.get(deployment_id)
43
58
 
59
+ def get(self, id: UUID) -> RunDeployment:
44
60
  return RunDeployment(
45
61
  source="selected",
46
- deployment_id=deployment_id,
62
+ deployment_id=id,
47
63
  parameters=self.parameters,
48
64
  job_variables={},
49
65
  )
50
66
 
67
+ def validate_parameters(self) -> None:
68
+ if not self.parameters:
69
+ return
70
+
71
+ workflow_params = self.workflow.get_parameters()
72
+ workflow_required_params = [p.name for p in workflow_params.values() if p.required]
73
+ trigger_params = list(self.parameters.keys())
74
+
75
+ missing_required_params = set(workflow_required_params) - set(trigger_params)
76
+ wrong_params = set(trigger_params) - set(workflow_params)
77
+
78
+ if missing_required_params:
79
+ raise ValueError(
80
+ f"Missing required parameters: {missing_required_params} for workflow {self.workflow.name}"
81
+ )
82
+
83
+ if wrong_params:
84
+ raise ValueError(f"Workflow {self.workflow.name} doesn't support parameters: {wrong_params}")
85
+
51
86
 
52
87
  class TriggerDefinition(BaseModel):
53
88
  name: str
@@ -61,9 +96,23 @@ class TriggerDefinition(BaseModel):
61
96
  """Return the name of all deployments used by this trigger"""
62
97
  return [action.name for action in self.actions]
63
98
 
99
+ def get_description(self) -> str:
100
+ return f"Automation for Trigger {self.name} of type {self.type.value} (v{__version__})"
101
+
64
102
  def generate_name(self) -> str:
65
103
  return f"{self.type.value}{NAME_SEPARATOR}{self.name}"
66
104
 
105
+ def validate_actions(self) -> None:
106
+ for action in self.actions:
107
+ action.validate_parameters()
108
+
109
+
110
+ class TriggerBranchDefinition(TriggerDefinition):
111
+ branch: str
112
+
113
+ def generate_name(self) -> str:
114
+ return f"{self.type.value}{NAME_SEPARATOR}{self.branch}{NAME_SEPARATOR}{self.name}"
115
+
67
116
 
68
117
  class BuiltinTriggerDefinition(TriggerDefinition):
69
118
  type: TriggerType = TriggerType.BUILTIN
@@ -0,0 +1,90 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from prefect import get_run_logger, task
4
+ from prefect.automations import AutomationCore
5
+ from prefect.cache_policies import NONE
6
+ from prefect.client.orchestration import PrefectClient
7
+ from prefect.client.schemas.filters import DeploymentFilter, DeploymentFilterName
8
+
9
+ from infrahub.trigger.models import TriggerDefinition
10
+
11
+ from .models import TriggerType
12
+
13
+ if TYPE_CHECKING:
14
+ from uuid import UUID
15
+
16
+
17
+ @task(name="trigger-setup", task_run_name="Setup triggers", cache_policy=NONE) # type: ignore[arg-type]
18
+ async def setup_triggers(
19
+ client: PrefectClient,
20
+ triggers: list[TriggerDefinition],
21
+ trigger_type: TriggerType | None = None,
22
+ ) -> None:
23
+ log = get_run_logger()
24
+
25
+ if trigger_type:
26
+ log.info(f"Setting up triggers of type {trigger_type.value}")
27
+ else:
28
+ log.info("Setting up all triggers")
29
+
30
+ # -------------------------------------------------------------
31
+ # Retrieve existing Deployments and Automation from the server
32
+ # -------------------------------------------------------------
33
+ deployment_names = list({name for trigger in triggers for name in trigger.get_deployment_names()})
34
+ deployments = {
35
+ item.name: item
36
+ for item in await client.read_deployments(
37
+ deployment_filter=DeploymentFilter(name=DeploymentFilterName(any_=deployment_names))
38
+ )
39
+ }
40
+ deployments_mapping: dict[str, UUID] = {name: item.id for name, item in deployments.items()}
41
+ existing_automations = {item.name: item for item in await client.read_automations()}
42
+
43
+ # If a trigger type is provided, narrow down the list of existing triggers to know which one to delete
44
+ if trigger_type:
45
+ trigger_automations = [
46
+ item.name for item in await client.read_automations() if item.name.startswith(trigger_type.value)
47
+ ]
48
+ else:
49
+ trigger_automations = [item.name for item in await client.read_automations()]
50
+
51
+ trigger_names = [trigger.generate_name() for trigger in triggers]
52
+
53
+ log.debug(f"{len(trigger_automations)} existing triggers ({trigger_automations})")
54
+ log.debug(f"{len(trigger_names)} triggers to configure ({trigger_names})")
55
+
56
+ to_delete = set(trigger_automations) - set(trigger_names)
57
+ log.debug(f"{len(trigger_names)} triggers to delete ({to_delete})")
58
+
59
+ # -------------------------------------------------------------
60
+ # Create or Update all triggers
61
+ # -------------------------------------------------------------
62
+ for trigger in triggers:
63
+ automation = AutomationCore(
64
+ name=trigger.generate_name(),
65
+ description=trigger.get_description(),
66
+ enabled=True,
67
+ trigger=trigger.trigger.get_prefect(),
68
+ actions=[action.get_prefect(mapping=deployments_mapping) for action in trigger.actions],
69
+ )
70
+
71
+ existing_automation = existing_automations.get(trigger.generate_name(), None)
72
+
73
+ if existing_automation:
74
+ await client.update_automation(automation_id=existing_automation.id, automation=automation)
75
+ log.info(f"{trigger.generate_name()} Updated")
76
+ else:
77
+ await client.create_automation(automation=automation)
78
+ log.info(f"{trigger.generate_name()} Created")
79
+
80
+ # -------------------------------------------------------------
81
+ # Delete Triggers that shouldn't be there
82
+ # -------------------------------------------------------------
83
+ for item_to_delete in to_delete:
84
+ existing_automation = existing_automations.get(item_to_delete)
85
+
86
+ if not existing_automation:
87
+ continue
88
+
89
+ await client.delete_automation(automation_id=existing_automation.id)
90
+ log.info(f"{item_to_delete} Deleted")
infrahub/trigger/tasks.py CHANGED
@@ -1,85 +1,36 @@
1
- from typing import TYPE_CHECKING
2
-
3
- from infrahub_sdk.utils import compare_lists
4
- from prefect import get_run_logger, task
5
- from prefect.automations import AutomationCore
6
- from prefect.cache_policies import NONE
7
- from prefect.client.orchestration import PrefectClient
8
- from prefect.client.schemas.filters import DeploymentFilter, DeploymentFilterName
9
-
10
- from .catalogue import triggers
11
- from .constants import DEPRECATED_STATIC_TRIGGER_NAMES
12
- from .models import TriggerType
13
-
14
- if TYPE_CHECKING:
15
- from uuid import UUID
16
-
17
-
18
- @task(name="trigger-setup", task_run_name="Setup triggers in task-manager", cache_policy=NONE) # type: ignore[arg-type]
19
- async def setup_triggers(client: PrefectClient) -> None:
20
- log = get_run_logger()
21
-
22
- # -------------------------------------------------------------
23
- # Retrieve existing Deployments and Automation from the server
24
- # -------------------------------------------------------------
25
- deployment_names = list({name for trigger in triggers for name in trigger.get_deployment_names()})
26
- deployments = {
27
- item.name: item
28
- for item in await client.read_deployments(
29
- deployment_filter=DeploymentFilter(name=DeploymentFilterName(any_=deployment_names))
30
- )
31
- }
32
- deployments_mapping: dict[str, UUID] = {name: item.id for name, item in deployments.items()}
33
- existing_automations = {item.name: item for item in await client.read_automations()}
34
-
35
- builtin_automations = [
36
- item.name for item in await client.read_automations() if item.name.startswith(TriggerType.BUILTIN.value)
37
- ]
38
- trigger_names = [trigger.generate_name() for trigger in triggers]
39
-
40
- _, to_delete, _ = compare_lists(list1=builtin_automations, list2=trigger_names)
41
-
42
- # -------------------------------------------------------------
43
- # Create or Update all builtin triggers
44
- # -------------------------------------------------------------
45
- for trigger in triggers:
46
- automation = AutomationCore(
47
- name=trigger.generate_name(),
48
- description=trigger.description,
49
- enabled=True,
50
- trigger=trigger.trigger.get_prefect(),
51
- actions=[action.get_prefect(mapping=deployments_mapping) for action in trigger.actions],
1
+ from prefect import flow
2
+ from prefect.client.orchestration import get_client
3
+
4
+ from infrahub.computed_attribute.gather import (
5
+ gather_trigger_computed_attribute_jinja2,
6
+ gather_trigger_computed_attribute_python,
7
+ )
8
+ from infrahub.services import InfrahubServices # noqa: TC001 needed for prefect flow
9
+ from infrahub.trigger.catalogue import builtin_triggers
10
+ from infrahub.webhook.gather import gather_trigger_webhook
11
+
12
+ from .setup import setup_triggers
13
+
14
+
15
+ @flow(name="trigger-configure-all", flow_run_name="Configure all triggers")
16
+ async def trigger_configure_all(service: InfrahubServices) -> None:
17
+ webhook_trigger = await gather_trigger_webhook(db=service.database)
18
+ computed_attribute_j2_triggers = await gather_trigger_computed_attribute_jinja2()
19
+ (
20
+ computed_attribute_python_triggers,
21
+ computed_attribute_python_query_triggers,
22
+ ) = await gather_trigger_computed_attribute_python(db=service.database)
23
+
24
+ triggers = (
25
+ computed_attribute_j2_triggers
26
+ + computed_attribute_python_triggers
27
+ + computed_attribute_python_query_triggers
28
+ + builtin_triggers
29
+ + webhook_trigger
30
+ )
31
+
32
+ async with get_client(sync_client=False) as prefect_client:
33
+ await setup_triggers(
34
+ client=prefect_client,
35
+ triggers=triggers,
52
36
  )
53
-
54
- existing_automation = existing_automations.get(trigger.name, None)
55
-
56
- if existing_automation:
57
- await client.update_automation(automation_id=existing_automation.id, automation=automation)
58
- log.info(f"{trigger.name} Updated")
59
- else:
60
- await client.create_automation(automation=automation)
61
- log.info(f"{trigger.name} Created")
62
-
63
- # -------------------------------------------------------------
64
- # Delete Builtin Triggers that shouldn't be there
65
- # -------------------------------------------------------------
66
- for item_to_delete in to_delete:
67
- existing_automation = existing_automations.get(item_to_delete)
68
-
69
- if not existing_automation:
70
- continue
71
-
72
- await client.delete_automation(automation_id=existing_automation.id)
73
- log.info(f"{item_to_delete} Deleted")
74
-
75
- # -------------------------------------------------------------
76
- # Delete Deprecated triggers
77
- # -------------------------------------------------------------
78
- for trigger_name in DEPRECATED_STATIC_TRIGGER_NAMES:
79
- existing_automation = existing_automations.get(trigger_name)
80
-
81
- if not existing_automation:
82
- continue
83
-
84
- await client.delete_automation(automation_id=existing_automation.id)
85
- log.info(f"{trigger_name} Deleted")
infrahub/utils.py CHANGED
@@ -2,9 +2,10 @@ import hashlib
2
2
  from enum import Enum, EnumMeta
3
3
  from pathlib import Path
4
4
  from re import finditer
5
- from typing import Any
5
+ from typing import Any, TypeVar
6
6
 
7
7
  KWARGS_TO_DROP = ["session"]
8
+ AnyClass = TypeVar("AnyClass", bound=type)
8
9
 
9
10
 
10
11
  def get_fixtures_dir() -> Path:
@@ -73,3 +74,12 @@ def get_nested_dict(nested_dict: dict[str, Any], keys: list[str]) -> dict[str, A
73
74
  else:
74
75
  return {}
75
76
  return current_level if isinstance(current_level, dict) else {}
77
+
78
+
79
+ def get_all_subclasses(cls: AnyClass) -> list[AnyClass]:
80
+ """Recursively get all subclasses of the given class."""
81
+ subclasses: list[AnyClass] = []
82
+ for subclass in cls.__subclasses__():
83
+ subclasses.append(subclass)
84
+ subclasses.extend(get_all_subclasses(subclass))
85
+ return subclasses
File without changes
@@ -0,0 +1,42 @@
1
+ from infrahub_sdk.protocols import CoreValidator
2
+
3
+ from infrahub.context import InfrahubContext
4
+ from infrahub.events.models import EventMeta
5
+ from infrahub.events.validator_action import ValidatorFailedEvent, ValidatorPassedEvent, ValidatorStartedEvent
6
+ from infrahub.services import InfrahubServices
7
+
8
+
9
+ async def send_failed_validator(
10
+ service: InfrahubServices, validator: CoreValidator, proposed_change_id: str, context: InfrahubContext
11
+ ) -> None:
12
+ event = ValidatorFailedEvent(
13
+ node_id=validator.id,
14
+ kind=validator.get_kind(),
15
+ proposed_change_id=proposed_change_id,
16
+ meta=EventMeta.from_context(context=context),
17
+ )
18
+ await service.event.send(event=event)
19
+
20
+
21
+ async def send_passed_validator(
22
+ service: InfrahubServices, validator: CoreValidator, proposed_change_id: str, context: InfrahubContext
23
+ ) -> None:
24
+ event = ValidatorPassedEvent(
25
+ node_id=validator.id,
26
+ kind=validator.get_kind(),
27
+ proposed_change_id=proposed_change_id,
28
+ meta=EventMeta.from_context(context=context),
29
+ )
30
+ await service.event.send(event=event)
31
+
32
+
33
+ async def send_start_validator(
34
+ service: InfrahubServices, validator: CoreValidator, proposed_change_id: str, context: InfrahubContext
35
+ ) -> None:
36
+ event = ValidatorStartedEvent(
37
+ node_id=validator.id,
38
+ kind=validator.get_kind(),
39
+ proposed_change_id=proposed_change_id,
40
+ meta=EventMeta.from_context(context=context),
41
+ )
42
+ await service.event.send(event=event)
@@ -0,0 +1,41 @@
1
+ from typing import Any, TypeVar, cast
2
+
3
+ from infrahub_sdk.protocols import CoreValidator
4
+
5
+ from infrahub.context import InfrahubContext
6
+ from infrahub.core.constants import ValidatorConclusion, ValidatorState
7
+ from infrahub.services import InfrahubServices
8
+
9
+ from .events import send_start_validator
10
+
11
+ ValidatorType = TypeVar("ValidatorType", bound=CoreValidator)
12
+
13
+
14
+ async def start_validator(
15
+ service: InfrahubServices,
16
+ validator: CoreValidator | None,
17
+ validator_type: type[ValidatorType],
18
+ proposed_change: str,
19
+ context: InfrahubContext,
20
+ data: dict[str, Any],
21
+ ) -> ValidatorType:
22
+ if validator:
23
+ validator.conclusion.value = ValidatorConclusion.UNKNOWN.value
24
+ validator.state.value = ValidatorState.QUEUED.value
25
+ validator.started_at.value = ""
26
+ validator.completed_at.value = ""
27
+ await validator.save()
28
+ validator = cast(ValidatorType, validator)
29
+ else:
30
+ data["proposed_change"] = proposed_change
31
+ validator = await service.client.create(
32
+ kind=validator_type,
33
+ data=data,
34
+ )
35
+ await validator.save()
36
+
37
+ await send_start_validator(
38
+ service=service, validator=validator, proposed_change_id=proposed_change, context=context
39
+ )
40
+
41
+ return validator
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ from prefect import task
4
+ from prefect.cache_policies import NONE
5
+
6
+ from infrahub.core.manager import NodeManager
7
+ from infrahub.core.protocols import CoreWebhook
8
+ from infrahub.database import InfrahubDatabase # noqa: TC001 needed for prefect flow
9
+
10
+ from .models import WebhookTriggerDefinition
11
+
12
+
13
+ @task(name="gather-trigger-webhook", task_run_name="Gather webhook triggers", cache_policy=NONE)
14
+ async def gather_trigger_webhook(db: InfrahubDatabase) -> list[WebhookTriggerDefinition]:
15
+ webhooks = await NodeManager.query(db=db, schema=CoreWebhook)
16
+ triggers = [WebhookTriggerDefinition.from_object(webhook) for webhook in webhooks]
17
+ return triggers