infrahub-server 1.1.6__py3-none-any.whl → 1.2.0b1__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 (407) hide show
  1. infrahub/api/artifact.py +16 -4
  2. infrahub/api/dependencies.py +8 -0
  3. infrahub/api/oauth2.py +0 -1
  4. infrahub/api/oidc.py +0 -1
  5. infrahub/api/query.py +18 -7
  6. infrahub/api/schema.py +32 -6
  7. infrahub/api/transformation.py +12 -5
  8. infrahub/{message_bus/messages/check_artifact_create.py → artifacts/models.py} +5 -3
  9. infrahub/{message_bus/operations/check/artifact.py → artifacts/tasks.py} +26 -25
  10. infrahub/cli/__init__.py +0 -2
  11. infrahub/cli/db.py +6 -7
  12. infrahub/cli/events.py +8 -3
  13. infrahub/cli/git_agent.py +9 -7
  14. infrahub/cli/tasks.py +4 -6
  15. infrahub/computed_attribute/models.py +1 -1
  16. infrahub/computed_attribute/tasks.py +64 -17
  17. infrahub/computed_attribute/triggers.py +90 -0
  18. infrahub/config.py +1 -1
  19. infrahub/context.py +39 -0
  20. infrahub/core/account.py +5 -8
  21. infrahub/core/attribute.py +54 -22
  22. infrahub/core/branch/models.py +4 -4
  23. infrahub/core/branch/tasks.py +137 -129
  24. infrahub/core/changelog/__init__.py +0 -0
  25. infrahub/core/changelog/diff.py +283 -0
  26. infrahub/core/changelog/models.py +499 -0
  27. infrahub/core/constants/__init__.py +43 -2
  28. infrahub/core/constants/infrahubkind.py +1 -0
  29. infrahub/core/constants/schema.py +2 -0
  30. infrahub/core/diff/combiner.py +12 -8
  31. infrahub/core/diff/coordinator.py +49 -70
  32. infrahub/core/diff/data_check_synchronizer.py +86 -7
  33. infrahub/core/diff/enricher/aggregated.py +3 -3
  34. infrahub/core/diff/enricher/cardinality_one.py +7 -7
  35. infrahub/core/diff/enricher/hierarchy.py +22 -7
  36. infrahub/core/diff/enricher/labels.py +19 -4
  37. infrahub/core/diff/enricher/path_identifier.py +7 -9
  38. infrahub/core/diff/enricher/summary_counts.py +3 -1
  39. infrahub/core/diff/merger/merger.py +8 -4
  40. infrahub/core/diff/model/path.py +76 -35
  41. infrahub/core/diff/parent_node_adder.py +78 -0
  42. infrahub/core/diff/payload_builder.py +13 -2
  43. infrahub/core/diff/query/all_conflicts.py +6 -3
  44. infrahub/core/diff/query/artifact.py +1 -1
  45. infrahub/core/diff/query/delete_query.py +1 -1
  46. infrahub/core/diff/query/diff_get.py +3 -2
  47. infrahub/core/diff/query/diff_summary.py +1 -1
  48. infrahub/core/diff/query/field_specifiers.py +3 -1
  49. infrahub/core/diff/query/field_summary.py +3 -2
  50. infrahub/core/diff/query/filters.py +14 -3
  51. infrahub/core/diff/query/get_conflict_query.py +1 -1
  52. infrahub/core/diff/query/has_conflicts_query.py +6 -3
  53. infrahub/core/diff/query/merge.py +3 -3
  54. infrahub/core/diff/query/{drop_tracking_id.py → merge_tracking_id.py} +4 -4
  55. infrahub/core/diff/query/roots_metadata.py +9 -2
  56. infrahub/core/diff/query/save.py +233 -142
  57. infrahub/core/diff/query/summary_counts_enricher.py +267 -0
  58. infrahub/core/diff/query/time_range_query.py +3 -2
  59. infrahub/core/diff/query/update_conflict_query.py +1 -1
  60. infrahub/core/diff/query_parser.py +49 -24
  61. infrahub/core/diff/repository/deserializer.py +32 -28
  62. infrahub/core/diff/repository/repository.py +215 -41
  63. infrahub/core/diff/tasks.py +13 -12
  64. infrahub/core/enums.py +1 -1
  65. infrahub/core/graph/__init__.py +1 -1
  66. infrahub/core/graph/index.py +3 -0
  67. infrahub/core/integrity/object_conflict/conflict_recorder.py +1 -1
  68. infrahub/core/ipam/reconciler.py +1 -1
  69. infrahub/core/ipam/tasks.py +2 -3
  70. infrahub/core/manager.py +20 -15
  71. infrahub/core/merge.py +5 -2
  72. infrahub/core/migrations/graph/__init__.py +4 -0
  73. infrahub/core/migrations/graph/m001_add_version_to_graph.py +1 -1
  74. infrahub/core/migrations/graph/m002_attribute_is_default.py +2 -2
  75. infrahub/core/migrations/graph/m003_relationship_parent_optional.py +2 -2
  76. infrahub/core/migrations/graph/m004_add_attr_documentation.py +1 -1
  77. infrahub/core/migrations/graph/m005_add_rel_read_only.py +1 -1
  78. infrahub/core/migrations/graph/m006_add_rel_on_delete.py +1 -1
  79. infrahub/core/migrations/graph/m007_add_rel_allow_override.py +1 -1
  80. infrahub/core/migrations/graph/m008_add_human_friendly_id.py +1 -1
  81. infrahub/core/migrations/graph/m009_add_generate_profile_attr.py +1 -1
  82. infrahub/core/migrations/graph/m010_add_generate_profile_attr_generic.py +1 -1
  83. infrahub/core/migrations/graph/m011_remove_profile_relationship_schema.py +2 -2
  84. infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -23
  85. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -11
  86. infrahub/core/migrations/graph/m014_remove_index_attr_value.py +2 -2
  87. infrahub/core/migrations/graph/m015_diff_format_update.py +1 -1
  88. infrahub/core/migrations/graph/m016_diff_delete_bug_fix.py +1 -1
  89. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -1
  90. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -2
  91. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  92. infrahub/core/migrations/graph/m020_add_generate_template_attr.py +48 -0
  93. infrahub/core/migrations/query/attribute_add.py +1 -1
  94. infrahub/core/migrations/query/attribute_rename.py +1 -1
  95. infrahub/core/migrations/query/delete_element_in_schema.py +1 -1
  96. infrahub/core/migrations/query/node_duplicate.py +39 -19
  97. infrahub/core/migrations/query/relationship_duplicate.py +1 -1
  98. infrahub/core/migrations/query/schema_attribute_update.py +1 -1
  99. infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
  100. infrahub/core/migrations/schema/node_remove.py +27 -13
  101. infrahub/core/migrations/schema/tasks.py +5 -5
  102. infrahub/core/migrations/shared.py +4 -4
  103. infrahub/core/models.py +7 -8
  104. infrahub/core/node/__init__.py +170 -46
  105. infrahub/core/node/base.py +1 -1
  106. infrahub/core/node/constraints/grouped_uniqueness.py +9 -2
  107. infrahub/core/node/delete_validator.py +4 -4
  108. infrahub/core/node/ipam.py +13 -8
  109. infrahub/core/node/permissions.py +4 -0
  110. infrahub/core/node/resource_manager/ip_prefix_pool.py +8 -5
  111. infrahub/core/node/standard.py +3 -5
  112. infrahub/core/property.py +1 -1
  113. infrahub/core/protocols.py +6 -0
  114. infrahub/core/protocols_base.py +4 -2
  115. infrahub/core/query/__init__.py +2 -5
  116. infrahub/core/query/attribute.py +9 -9
  117. infrahub/core/query/branch.py +5 -5
  118. infrahub/core/query/delete.py +1 -1
  119. infrahub/core/query/diff.py +45 -7
  120. infrahub/core/query/ipam.py +4 -4
  121. infrahub/core/query/node.py +19 -14
  122. infrahub/core/query/relationship.py +213 -26
  123. infrahub/core/query/resource_manager.py +13 -11
  124. infrahub/core/query/standard_node.py +6 -6
  125. infrahub/core/query/task.py +3 -3
  126. infrahub/core/query/task_log.py +1 -1
  127. infrahub/core/query/utils.py +5 -5
  128. infrahub/core/registry.py +0 -2
  129. infrahub/core/relationship/constraints/count.py +1 -1
  130. infrahub/core/relationship/constraints/peer_kind.py +1 -1
  131. infrahub/core/relationship/model.py +76 -38
  132. infrahub/core/schema/__init__.py +6 -4
  133. infrahub/core/schema/attribute_schema.py +8 -0
  134. infrahub/core/schema/basenode_schema.py +13 -3
  135. infrahub/core/schema/definitions/core/__init__.py +153 -0
  136. infrahub/core/schema/definitions/core/account.py +168 -0
  137. infrahub/core/schema/definitions/core/artifact.py +127 -0
  138. infrahub/core/schema/definitions/core/builtin.py +21 -0
  139. infrahub/core/schema/definitions/core/check.py +60 -0
  140. infrahub/core/schema/definitions/core/generator.py +96 -0
  141. infrahub/core/schema/definitions/core/graphql_query.py +77 -0
  142. infrahub/core/schema/definitions/core/group.py +105 -0
  143. infrahub/core/schema/definitions/core/ipam.py +252 -0
  144. infrahub/core/schema/definitions/core/lineage.py +17 -0
  145. infrahub/core/schema/definitions/core/menu.py +46 -0
  146. infrahub/core/schema/definitions/core/permission.py +161 -0
  147. infrahub/core/schema/definitions/core/profile.py +29 -0
  148. infrahub/core/schema/definitions/core/propose_change.py +88 -0
  149. infrahub/core/schema/definitions/core/propose_change_comment.py +188 -0
  150. infrahub/core/schema/definitions/core/propose_change_validator.py +326 -0
  151. infrahub/core/schema/definitions/core/repository.py +280 -0
  152. infrahub/core/schema/definitions/core/resource_pool.py +180 -0
  153. infrahub/core/schema/definitions/core/template.py +12 -0
  154. infrahub/core/schema/definitions/core/transform.py +87 -0
  155. infrahub/core/schema/definitions/core/webhook.py +108 -0
  156. infrahub/core/schema/definitions/internal.py +16 -0
  157. infrahub/core/schema/generated/genericnode_schema.py +5 -0
  158. infrahub/core/schema/generated/node_schema.py +5 -0
  159. infrahub/core/schema/generic_schema.py +5 -1
  160. infrahub/core/schema/manager.py +45 -42
  161. infrahub/core/schema/node_schema.py +4 -0
  162. infrahub/core/schema/profile_schema.py +4 -0
  163. infrahub/core/schema/relationship_schema.py +10 -2
  164. infrahub/core/schema/schema_branch.py +260 -16
  165. infrahub/core/schema/template_schema.py +36 -0
  166. infrahub/core/task/user_task.py +7 -5
  167. infrahub/core/timestamp.py +3 -3
  168. infrahub/core/utils.py +3 -2
  169. infrahub/core/validators/attribute/choices.py +1 -1
  170. infrahub/core/validators/attribute/enum.py +1 -1
  171. infrahub/core/validators/attribute/kind.py +1 -1
  172. infrahub/core/validators/attribute/length.py +1 -1
  173. infrahub/core/validators/attribute/optional.py +1 -1
  174. infrahub/core/validators/attribute/regex.py +1 -1
  175. infrahub/core/validators/attribute/unique.py +1 -1
  176. infrahub/core/validators/checks_runner.py +37 -0
  177. infrahub/core/validators/node/generate_profile.py +1 -1
  178. infrahub/core/validators/node/hierarchy.py +1 -1
  179. infrahub/core/validators/query.py +1 -1
  180. infrahub/core/validators/relationship/count.py +1 -1
  181. infrahub/core/validators/relationship/optional.py +1 -1
  182. infrahub/core/validators/relationship/peer.py +1 -1
  183. infrahub/core/validators/tasks.py +8 -6
  184. infrahub/core/validators/uniqueness/query.py +20 -17
  185. infrahub/database/__init__.py +16 -2
  186. infrahub/database/memgraph.py +1 -1
  187. infrahub/dependencies/builder/constraint/grouped/node_runner.py +0 -2
  188. infrahub/dependencies/builder/diff/combiner.py +1 -1
  189. infrahub/dependencies/builder/diff/conflicts_enricher.py +1 -1
  190. infrahub/dependencies/builder/diff/coordinator.py +0 -2
  191. infrahub/dependencies/builder/diff/deserializer.py +4 -2
  192. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  193. infrahub/dependencies/builder/diff/enricher/summary_counts.py +1 -1
  194. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  195. infrahub/events/artifact_action.py +76 -0
  196. infrahub/events/branch_action.py +50 -21
  197. infrahub/events/group_action.py +117 -0
  198. infrahub/events/models.py +164 -51
  199. infrahub/events/node_action.py +70 -8
  200. infrahub/events/repository_action.py +8 -8
  201. infrahub/events/schema_action.py +21 -8
  202. infrahub/exceptions.py +9 -0
  203. infrahub/generators/models.py +1 -0
  204. infrahub/generators/tasks.py +34 -15
  205. infrahub/git/base.py +3 -5
  206. infrahub/git/constants.py +0 -1
  207. infrahub/git/integrator.py +60 -36
  208. infrahub/git/models.py +80 -1
  209. infrahub/git/repository.py +7 -8
  210. infrahub/git/tasks.py +432 -112
  211. infrahub/git_credential/helper.py +2 -3
  212. infrahub/graphql/analyzer.py +572 -11
  213. infrahub/graphql/app.py +34 -26
  214. infrahub/graphql/auth/query_permission_checker/anonymous_checker.py +5 -5
  215. infrahub/graphql/auth/query_permission_checker/default_branch_checker.py +4 -4
  216. infrahub/graphql/auth/query_permission_checker/merge_operation_checker.py +4 -4
  217. infrahub/graphql/auth/query_permission_checker/object_permission_checker.py +28 -35
  218. infrahub/graphql/auth/query_permission_checker/super_admin_checker.py +5 -5
  219. infrahub/graphql/context.py +33 -0
  220. infrahub/graphql/enums.py +1 -1
  221. infrahub/graphql/initialization.py +5 -1
  222. infrahub/graphql/loaders/node.py +2 -2
  223. infrahub/graphql/manager.py +63 -63
  224. infrahub/graphql/mutations/account.py +20 -13
  225. infrahub/graphql/mutations/artifact_definition.py +16 -12
  226. infrahub/graphql/mutations/branch.py +86 -40
  227. infrahub/graphql/mutations/computed_attribute.py +24 -13
  228. infrahub/graphql/mutations/diff.py +54 -14
  229. infrahub/graphql/mutations/diff_conflict.py +14 -8
  230. infrahub/graphql/mutations/generator.py +83 -0
  231. infrahub/graphql/mutations/graphql_query.py +19 -11
  232. infrahub/graphql/mutations/ipam.py +25 -23
  233. infrahub/graphql/mutations/main.py +243 -50
  234. infrahub/graphql/mutations/menu.py +10 -10
  235. infrahub/graphql/mutations/proposed_change.py +36 -28
  236. infrahub/graphql/mutations/relationship.py +343 -104
  237. infrahub/graphql/mutations/repository.py +41 -35
  238. infrahub/graphql/mutations/resource_manager.py +26 -26
  239. infrahub/graphql/mutations/schema.py +66 -33
  240. infrahub/graphql/mutations/tasks.py +16 -10
  241. infrahub/graphql/parser.py +1 -1
  242. infrahub/graphql/permissions.py +3 -10
  243. infrahub/graphql/queries/account.py +22 -18
  244. infrahub/graphql/queries/branch.py +6 -4
  245. infrahub/graphql/queries/diff/tree.py +63 -52
  246. infrahub/graphql/queries/event.py +115 -0
  247. infrahub/graphql/queries/internal.py +3 -3
  248. infrahub/graphql/queries/ipam.py +23 -18
  249. infrahub/graphql/queries/relationship.py +11 -10
  250. infrahub/graphql/queries/resource_manager.py +43 -27
  251. infrahub/graphql/queries/search.py +9 -8
  252. infrahub/graphql/queries/status.py +12 -9
  253. infrahub/graphql/queries/task.py +11 -9
  254. infrahub/graphql/resolvers/resolver.py +69 -43
  255. infrahub/graphql/resolvers/single_relationship.py +16 -10
  256. infrahub/graphql/schema.py +4 -0
  257. infrahub/graphql/subscription/__init__.py +1 -1
  258. infrahub/graphql/subscription/events.py +1 -1
  259. infrahub/graphql/subscription/graphql_query.py +8 -8
  260. infrahub/graphql/types/branch.py +2 -2
  261. infrahub/graphql/types/common.py +6 -1
  262. infrahub/graphql/types/context.py +12 -0
  263. infrahub/graphql/types/enums.py +2 -0
  264. infrahub/graphql/types/event.py +158 -0
  265. infrahub/graphql/types/interface.py +2 -2
  266. infrahub/graphql/types/node.py +3 -3
  267. infrahub/graphql/types/permission.py +2 -2
  268. infrahub/graphql/types/relationship.py +3 -3
  269. infrahub/graphql/types/standard_node.py +9 -11
  270. infrahub/graphql/utils.py +28 -182
  271. infrahub/groups/tasks.py +2 -3
  272. infrahub/lock.py +21 -21
  273. infrahub/menu/generator.py +0 -1
  274. infrahub/menu/menu.py +116 -138
  275. infrahub/menu/models.py +4 -4
  276. infrahub/message_bus/__init__.py +11 -13
  277. infrahub/message_bus/messages/__init__.py +0 -14
  278. infrahub/message_bus/messages/check_generator_run.py +1 -3
  279. infrahub/message_bus/messages/event_branch_merge.py +3 -0
  280. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  281. infrahub/message_bus/messages/request_proposedchange_pipeline.py +2 -0
  282. infrahub/message_bus/messages/send_echo_request.py +1 -1
  283. infrahub/message_bus/operations/__init__.py +4 -13
  284. infrahub/message_bus/operations/check/__init__.py +2 -2
  285. infrahub/message_bus/operations/check/generator.py +1 -3
  286. infrahub/message_bus/operations/event/branch.py +7 -3
  287. infrahub/message_bus/operations/event/schema.py +1 -1
  288. infrahub/message_bus/operations/event/worker.py +0 -3
  289. infrahub/message_bus/operations/finalize/validator.py +1 -1
  290. infrahub/message_bus/operations/git/file.py +2 -2
  291. infrahub/message_bus/operations/git/repository.py +1 -1
  292. infrahub/message_bus/operations/requests/__init__.py +0 -4
  293. infrahub/message_bus/operations/requests/generator_definition.py +2 -4
  294. infrahub/message_bus/operations/requests/proposed_change.py +37 -20
  295. infrahub/message_bus/operations/send/echo.py +1 -1
  296. infrahub/message_bus/types.py +1 -1
  297. infrahub/permissions/__init__.py +2 -1
  298. infrahub/permissions/globals.py +15 -0
  299. infrahub/permissions/types.py +26 -0
  300. infrahub/pools/prefix.py +29 -165
  301. infrahub/prefect_server/__init__.py +0 -0
  302. infrahub/prefect_server/app.py +18 -0
  303. infrahub/prefect_server/database.py +20 -0
  304. infrahub/prefect_server/events.py +28 -0
  305. infrahub/prefect_server/models.py +46 -0
  306. infrahub/proposed_change/models.py +18 -1
  307. infrahub/proposed_change/tasks.py +195 -53
  308. infrahub/pytest_plugin.py +4 -4
  309. infrahub/server.py +13 -12
  310. infrahub/services/__init__.py +148 -63
  311. infrahub/services/adapters/cache/__init__.py +11 -11
  312. infrahub/services/adapters/cache/nats.py +42 -25
  313. infrahub/services/adapters/cache/redis.py +3 -11
  314. infrahub/services/adapters/event/__init__.py +10 -18
  315. infrahub/services/adapters/http/__init__.py +0 -5
  316. infrahub/services/adapters/http/httpx.py +22 -15
  317. infrahub/services/adapters/message_bus/__init__.py +25 -8
  318. infrahub/services/adapters/message_bus/local.py +9 -7
  319. infrahub/services/adapters/message_bus/nats.py +14 -8
  320. infrahub/services/adapters/message_bus/rabbitmq.py +23 -10
  321. infrahub/services/adapters/workflow/__init__.py +11 -8
  322. infrahub/services/adapters/workflow/local.py +27 -6
  323. infrahub/services/adapters/workflow/worker.py +23 -7
  324. infrahub/services/component.py +43 -40
  325. infrahub/services/protocols.py +7 -7
  326. infrahub/services/scheduler.py +30 -29
  327. infrahub/storage.py +2 -4
  328. infrahub/task_manager/constants.py +1 -1
  329. infrahub/task_manager/event.py +261 -0
  330. infrahub/task_manager/models.py +147 -3
  331. infrahub/task_manager/task.py +1 -1
  332. infrahub/tasks/artifact.py +19 -18
  333. infrahub/tasks/registry.py +1 -1
  334. infrahub/tasks/telemetry.py +13 -14
  335. infrahub/transformations/tasks.py +3 -5
  336. infrahub/trigger/__init__.py +0 -0
  337. infrahub/trigger/catalogue.py +16 -0
  338. infrahub/trigger/constants.py +9 -0
  339. infrahub/trigger/models.py +105 -0
  340. infrahub/trigger/tasks.py +91 -0
  341. infrahub/types.py +1 -1
  342. infrahub/utils.py +1 -1
  343. infrahub/webhook/constants.py +0 -2
  344. infrahub/webhook/models.py +161 -40
  345. infrahub/webhook/tasks.py +123 -202
  346. infrahub/webhook/triggers.py +27 -0
  347. infrahub/workers/infrahub_async.py +36 -25
  348. infrahub/workers/utils.py +63 -0
  349. infrahub/workflows/catalogue.py +71 -52
  350. infrahub/workflows/initialization.py +14 -8
  351. infrahub/workflows/models.py +28 -4
  352. infrahub/workflows/utils.py +1 -1
  353. infrahub_sdk/client.py +8 -0
  354. infrahub_sdk/ctl/branch.py +3 -2
  355. infrahub_sdk/ctl/check.py +3 -3
  356. infrahub_sdk/ctl/cli_commands.py +16 -11
  357. infrahub_sdk/ctl/exceptions.py +0 -6
  358. infrahub_sdk/ctl/exporter.py +1 -1
  359. infrahub_sdk/ctl/generator.py +5 -5
  360. infrahub_sdk/ctl/importer.py +3 -2
  361. infrahub_sdk/ctl/menu.py +1 -1
  362. infrahub_sdk/ctl/object.py +1 -1
  363. infrahub_sdk/ctl/repository.py +23 -15
  364. infrahub_sdk/ctl/schema.py +2 -2
  365. infrahub_sdk/ctl/utils.py +4 -19
  366. infrahub_sdk/ctl/validate.py +2 -1
  367. infrahub_sdk/exceptions.py +12 -0
  368. infrahub_sdk/generator.py +3 -0
  369. infrahub_sdk/node.py +4 -4
  370. infrahub_sdk/protocols.py +21 -8
  371. infrahub_sdk/schema/__init__.py +14 -2
  372. infrahub_sdk/schema/main.py +7 -0
  373. infrahub_sdk/task/__init__.py +1 -0
  374. infrahub_sdk/task/constants.py +3 -0
  375. infrahub_sdk/task/exceptions.py +25 -0
  376. infrahub_sdk/task/manager.py +545 -0
  377. infrahub_sdk/task/models.py +74 -0
  378. infrahub_sdk/timestamp.py +134 -33
  379. infrahub_sdk/utils.py +39 -1
  380. infrahub_sdk/yaml.py +2 -3
  381. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/METADATA +47 -12
  382. infrahub_server-1.2.0b1.dist-info/RECORD +725 -0
  383. infrahub_testcontainers/container.py +14 -6
  384. infrahub_testcontainers/docker-compose.test.yml +24 -5
  385. infrahub_testcontainers/haproxy.cfg +43 -0
  386. infrahub_testcontainers/helpers.py +85 -1
  387. infrahub/core/branch/constants.py +0 -2
  388. infrahub/core/schema/definitions/core.py +0 -2274
  389. infrahub/graphql/query.py +0 -52
  390. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  391. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  392. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  393. infrahub/message_bus/messages/request_artifactdefinition_check.py +0 -17
  394. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  395. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  396. infrahub/message_bus/operations/check/repository.py +0 -293
  397. infrahub/message_bus/operations/requests/artifact_definition.py +0 -148
  398. infrahub/message_bus/operations/requests/repository.py +0 -133
  399. infrahub/schema/constants.py +0 -1
  400. infrahub/schema/tasks.py +0 -76
  401. infrahub/services/adapters/database/__init__.py +0 -9
  402. infrahub_sdk/ctl/_file.py +0 -13
  403. infrahub_server-1.1.6.dist-info/RECORD +0 -681
  404. /infrahub/{schema → artifacts}/__init__.py +0 -0
  405. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/LICENSE.txt +0 -0
  406. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/WHEEL +0 -0
  407. {infrahub_server-1.1.6.dist-info → infrahub_server-1.2.0b1.dist-info}/entry_points.txt +0 -0
@@ -12,6 +12,7 @@ from typing_extensions import Self
12
12
 
13
13
  from infrahub.computed_attribute.constants import VALID_KINDS as VALID_COMPUTED_ATTRIBUTE_KINDS
14
14
  from infrahub.core.constants import (
15
+ OBJECT_TEMPLATE_NAME_ATTR,
15
16
  RESERVED_ATTR_GEN_NAMES,
16
17
  RESERVED_ATTR_REL_NAMES,
17
18
  RESTRICTED_NAMESPACES,
@@ -43,6 +44,7 @@ from infrahub.core.schema import (
43
44
  RelationshipSchema,
44
45
  SchemaAttributePath,
45
46
  SchemaRoot,
47
+ TemplateSchema,
46
48
  )
47
49
  from infrahub.core.schema.definitions.core import core_profile_schema_definition
48
50
  from infrahub.core.validators import CONSTRAINT_VALIDATOR_MAP
@@ -53,6 +55,7 @@ from infrahub.types import ATTRIBUTE_TYPES
53
55
  from infrahub.utils import format_label
54
56
  from infrahub.visuals import select_color
55
57
 
58
+ from ..constants.schema import PARENT_CHILD_IDENTIFIER
56
59
  from .constants import INTERNAL_SCHEMA_NODE_KINDS, SchemaNamespace
57
60
  from .schema_branch_computed import ComputedAttributes
58
61
 
@@ -62,9 +65,6 @@ if TYPE_CHECKING:
62
65
  from pydantic import ValidationInfo
63
66
 
64
67
 
65
- # pylint: disable=redefined-builtin,too-many-public-methods,too-many-lines
66
-
67
-
68
68
  class SchemaBranch:
69
69
  def __init__(
70
70
  self,
@@ -78,19 +78,21 @@ class SchemaBranch:
78
78
  self.nodes: dict[str, str] = {}
79
79
  self.generics: dict[str, str] = {}
80
80
  self.profiles: dict[str, str] = {}
81
+ self.templates: dict[str, str] = {}
81
82
  self.computed_attributes = computed_attributes or ComputedAttributes()
82
83
 
83
84
  if data:
84
85
  self.nodes = data.get("nodes", {})
85
86
  self.generics = data.get("generics", {})
86
87
  self.profiles = data.get("profiles", {})
88
+ self.templates = data.get("templates", {})
87
89
 
88
90
  @classmethod
89
91
  def __get_validators__(cls) -> Iterator[Callable[..., Any]]: # noqa: PLW3201
90
92
  yield cls.validate
91
93
 
92
94
  @classmethod
93
- def validate(cls, v: Any, info: ValidationInfo) -> Self: # pylint: disable=unused-argument
95
+ def validate(cls, v: Any, info: ValidationInfo) -> Self: # noqa: ARG003
94
96
  if isinstance(v, cls):
95
97
  return v
96
98
  if isinstance(v, dict):
@@ -109,6 +111,10 @@ class SchemaBranch:
109
111
  def profile_names(self) -> list[str]:
110
112
  return list(self.profiles.keys())
111
113
 
114
+ @property
115
+ def template_names(self) -> list[str]:
116
+ return list(self.templates.keys())
117
+
112
118
  def get_all_kind_id_map(self, exclude_profiles: bool = False) -> dict[str, str]:
113
119
  kind_id_map = {}
114
120
  if exclude_profiles:
@@ -124,7 +130,7 @@ class SchemaBranch:
124
130
 
125
131
  @property
126
132
  def all_names(self) -> list[str]:
127
- return self.node_names + self.generic_names + self.profile_names
133
+ return self.node_names + self.generic_names + self.profile_names + self.template_names
128
134
 
129
135
  def get_hash(self) -> str:
130
136
  """Calculate the hash for this objects based on the content of nodes and generics.
@@ -142,13 +148,14 @@ class SchemaBranch:
142
148
  return SchemaBranchHash(main=self.get_hash(), nodes=self.nodes, generics=self.generics)
143
149
 
144
150
  def to_dict(self) -> dict[str, Any]:
145
- return {"nodes": self.nodes, "generics": self.generics, "profiles": self.profiles}
151
+ return {"nodes": self.nodes, "generics": self.generics, "profiles": self.profiles, "templates": self.templates}
146
152
 
147
153
  def to_dict_schema_object(self, duplicate: bool = False) -> dict[str, dict[str, MainSchemaTypes]]:
148
154
  return {
149
155
  "nodes": {name: self.get(name, duplicate=duplicate) for name in self.nodes},
150
156
  "profiles": {name: self.get(name, duplicate=duplicate) for name in self.profiles},
151
157
  "generics": {name: self.get(name, duplicate=duplicate) for name in self.generics},
158
+ "templates": {name: self.get(name, duplicate=duplicate) for name in self.templates},
152
159
  }
153
160
 
154
161
  @classmethod
@@ -157,10 +164,11 @@ class SchemaBranch:
157
164
  "nodes": NodeSchema,
158
165
  "generics": GenericSchema,
159
166
  "profiles": ProfileSchema,
167
+ "templates": TemplateSchema,
160
168
  }
161
169
 
162
170
  cache: dict[str, MainSchemaTypes] = {}
163
- nodes: dict[str, dict[str, str]] = {"nodes": {}, "generics": {}, "profiles": {}}
171
+ nodes: dict[str, dict[str, str]] = {"nodes": {}, "generics": {}, "profiles": {}, "templates": {}}
164
172
 
165
173
  for node_type, node_class in type_mapping.items():
166
174
  for node_name, node_data in data[node_type].items():
@@ -281,6 +289,8 @@ class SchemaBranch:
281
289
  self.generics[name] = schema_hash
282
290
  elif "Profile" in schema.__class__.__name__:
283
291
  self.profiles[name] = schema_hash
292
+ elif "Template" in schema.__class__.__name__:
293
+ self.templates[name] = schema_hash
284
294
 
285
295
  return schema_hash
286
296
 
@@ -292,6 +302,7 @@ class SchemaBranch:
292
302
 
293
303
  If duplicate is set to false, the real object will be returned.
294
304
  """
305
+
295
306
  key = None
296
307
  if name in self.nodes:
297
308
  key = self.nodes[name]
@@ -299,6 +310,8 @@ class SchemaBranch:
299
310
  key = self.generics[name]
300
311
  elif name in self.profiles:
301
312
  key = self.profiles[name]
313
+ elif name in self.templates:
314
+ key = self.templates[name]
302
315
 
303
316
  if key and duplicate:
304
317
  return self._cache[key].duplicate()
@@ -330,6 +343,13 @@ class SchemaBranch:
330
343
  raise ValueError(f"{name!r} is not of type ProfileSchema")
331
344
  return item
332
345
 
346
+ def get_template(self, name: str, duplicate: bool = True) -> TemplateSchema:
347
+ """Access a specific TemplateSchema, defined by its kind."""
348
+ item = self.get(name=name, duplicate=duplicate)
349
+ if not isinstance(item, TemplateSchema):
350
+ raise ValueError(f"{name!r} is not of type TemplateSchema")
351
+ return item
352
+
333
353
  def delete(self, name: str) -> None:
334
354
  if name in self.nodes:
335
355
  del self.nodes[name]
@@ -337,6 +357,8 @@ class SchemaBranch:
337
357
  del self.generics[name]
338
358
  elif name in self.profiles:
339
359
  del self.profiles[name]
360
+ elif name in self.templates:
361
+ del self.templates[name]
340
362
  else:
341
363
  raise SchemaNotFoundError(
342
364
  branch_name=self.name, identifier=name, message=f"Unable to find the schema {name!r} in the registry"
@@ -431,7 +453,7 @@ class SchemaBranch:
431
453
 
432
454
  def generate_fields_for_display_label(self, name: str) -> Optional[dict]:
433
455
  node = self.get(name=name, duplicate=False)
434
- if isinstance(node, (NodeSchema, ProfileSchema)):
456
+ if isinstance(node, NodeSchema | ProfileSchema | TemplateSchema):
435
457
  return node.generate_fields_for_display_label()
436
458
 
437
459
  fields: dict[str, Union[str, None, dict[str, None]]] = {}
@@ -490,6 +512,8 @@ class SchemaBranch:
490
512
  self.process_inheritance()
491
513
  self.process_hierarchy()
492
514
  self.process_branch_support()
515
+ self.manage_object_template_schemas()
516
+ self.manage_object_template_relationships()
493
517
  self.manage_profile_schemas()
494
518
  self.manage_profile_relationships()
495
519
  self.add_hierarchy_generic()
@@ -520,6 +544,9 @@ class SchemaBranch:
520
544
  self.process_relationships()
521
545
  self.process_human_friendly_id()
522
546
 
547
+ def _generate_identifier_string(self, node_kind: str, peer_kind: str) -> str:
548
+ return "__".join(sorted([node_kind, peer_kind])).lower()
549
+
523
550
  def generate_identifiers(self) -> None:
524
551
  """Generate the identifier for all relationships if it's not already present."""
525
552
  for name in self.all_names:
@@ -532,7 +559,7 @@ class SchemaBranch:
532
559
  for rel in node.relationships:
533
560
  if rel.identifier:
534
561
  continue
535
- rel.identifier = str("__".join(sorted([node.kind, rel.peer]))).lower()
562
+ rel.identifier = self._generate_identifier_string(node.kind, rel.peer)
536
563
  self.set(name=name, schema=node)
537
564
 
538
565
  def validate_identifiers(self) -> None:
@@ -1267,7 +1294,6 @@ class SchemaBranch:
1267
1294
 
1268
1295
  if either node on a relationship support branch, the relationship must be branch aware.
1269
1296
  """
1270
- # pylint: disable=too-many-branches
1271
1297
 
1272
1298
  for name in self.all_names:
1273
1299
  node = self.get(name=name, duplicate=False)
@@ -1329,7 +1355,6 @@ class SchemaBranch:
1329
1355
 
1330
1356
  def process_cardinality_counts(self) -> None:
1331
1357
  """Ensure that all relationships with a cardinality of ONE have a min_count and max_count of 1."""
1332
- # pylint: disable=too-many-branches
1333
1358
 
1334
1359
  for name in self.all_names:
1335
1360
  node = self.get(name=name, duplicate=False)
@@ -1416,7 +1441,6 @@ class SchemaBranch:
1416
1441
  self.set(name=name, schema=node)
1417
1442
 
1418
1443
  def cleanup_inherited_elements(self) -> None:
1419
- # pylint: disable=too-many-branches
1420
1444
  for name in self.node_names:
1421
1445
  node = self.get_node(name=name, duplicate=False)
1422
1446
 
@@ -1512,7 +1536,7 @@ class SchemaBranch:
1512
1536
  def _get_hierarchy_child_rel(self, peer: str, hierarchical: str | None, read_only: bool) -> RelationshipSchema:
1513
1537
  return RelationshipSchema(
1514
1538
  name="children",
1515
- identifier="parent__child",
1539
+ identifier=PARENT_CHILD_IDENTIFIER,
1516
1540
  peer=peer,
1517
1541
  kind=RelationshipKind.HIERARCHY,
1518
1542
  cardinality=RelationshipCardinality.MANY,
@@ -1527,7 +1551,7 @@ class SchemaBranch:
1527
1551
  ) -> RelationshipSchema:
1528
1552
  return RelationshipSchema(
1529
1553
  name="parent",
1530
- identifier="parent__child",
1554
+ identifier=PARENT_CHILD_IDENTIFIER,
1531
1555
  peer=peer,
1532
1556
  kind=RelationshipKind.HIERARCHY,
1533
1557
  cardinality=RelationshipCardinality.ONE,
@@ -1642,7 +1666,7 @@ class SchemaBranch:
1642
1666
 
1643
1667
  if new_used_by_profile:
1644
1668
  core_profile_schema = self.get(name=InfrahubKind.PROFILE, duplicate=True)
1645
- core_profile_schema.used_by = sorted(list(profile_schema_kinds))
1669
+ core_profile_schema.used_by = sorted(profile_schema_kinds)
1646
1670
  self.set(name=InfrahubKind.PROFILE, schema=core_profile_schema)
1647
1671
 
1648
1672
  if self.has(name=InfrahubKind.NODE):
@@ -1653,7 +1677,7 @@ class SchemaBranch:
1653
1677
  if new_used_by_node:
1654
1678
  core_node_schema = self.get(name=InfrahubKind.NODE, duplicate=True)
1655
1679
  updated_used_by_node = set(chain(profile_schema_kinds, set(core_node_schema.used_by)))
1656
- core_node_schema.used_by = sorted(list(updated_used_by_node))
1680
+ core_node_schema.used_by = sorted(updated_used_by_node)
1657
1681
  self.set(name=InfrahubKind.NODE, schema=core_node_schema)
1658
1682
 
1659
1683
  def manage_profile_relationships(self) -> None:
@@ -1746,3 +1770,223 @@ class SchemaBranch:
1746
1770
  profile.attributes.append(attr)
1747
1771
 
1748
1772
  return profile
1773
+
1774
+ def _get_object_template_kind(self, node_kind: str) -> str:
1775
+ return f"Template{node_kind}"
1776
+
1777
+ def manage_object_template_relationships(self) -> None:
1778
+ """Add an `object_template` relationship to all nodes that can be created from object templates.
1779
+
1780
+ This relationship allows to record from which template an object has been created.
1781
+ """
1782
+ for node_name in self.node_names + self.generic_names:
1783
+ node = self.get(name=node_name, duplicate=False)
1784
+
1785
+ if (
1786
+ node.namespace in RESTRICTED_NAMESPACES
1787
+ or not node.generate_template
1788
+ or node.state == HashableModelState.ABSENT
1789
+ ):
1790
+ continue
1791
+
1792
+ template_rel_settings: dict[str, Any] = {
1793
+ "name": "object_template",
1794
+ "identifier": "node__objecttemplate",
1795
+ "peer": self._get_object_template_kind(node.kind),
1796
+ "kind": RelationshipKind.TEMPLATE,
1797
+ "cardinality": RelationshipCardinality.ONE,
1798
+ "branch": BranchSupportType.AWARE,
1799
+ "order_weight": 1,
1800
+ }
1801
+
1802
+ # Add relationship between node and template
1803
+ if "object_template" not in node.relationship_names:
1804
+ node_schema = self.get(name=node_name, duplicate=True)
1805
+
1806
+ node_schema.relationships.append(RelationshipSchema(**template_rel_settings))
1807
+ self.set(name=node_name, schema=node_schema)
1808
+ else:
1809
+ has_changes: bool = False
1810
+ rel_template = node.get_relationship(name="object_template")
1811
+ for name, value in template_rel_settings.items():
1812
+ if getattr(rel_template, name) != value:
1813
+ has_changes = True
1814
+
1815
+ if not has_changes:
1816
+ continue
1817
+
1818
+ node_schema = self.get(name=node_name, duplicate=True)
1819
+ rel_template = node_schema.get_relationship(name="object_template")
1820
+ for name, value in template_rel_settings.items():
1821
+ if getattr(rel_template, name) != value:
1822
+ setattr(rel_template, name, value)
1823
+
1824
+ self.set(name=node_name, schema=node_schema)
1825
+
1826
+ def add_relationships_to_template(self, node: NodeSchema) -> None:
1827
+ template_schema = self.get(name=self._get_object_template_kind(node_kind=node.kind), duplicate=False)
1828
+ # Remove previous relationships to account for new ones
1829
+ template_schema.relationships = [
1830
+ r for r in template_schema.relationships if r.kind == RelationshipKind.TEMPLATE
1831
+ ]
1832
+
1833
+ for relationship in node.relationships:
1834
+ if relationship.peer in [
1835
+ InfrahubKind.GENERICGROUP,
1836
+ InfrahubKind.PROFILE,
1837
+ ] or relationship.kind not in [
1838
+ RelationshipKind.COMPONENT,
1839
+ RelationshipKind.PARENT,
1840
+ RelationshipKind.ATTRIBUTE,
1841
+ RelationshipKind.GENERIC,
1842
+ ]:
1843
+ continue
1844
+
1845
+ rel_template_peer = (
1846
+ self._get_object_template_kind(node_kind=relationship.peer)
1847
+ if relationship.kind not in [RelationshipKind.ATTRIBUTE, RelationshipKind.GENERIC]
1848
+ else relationship.peer
1849
+ )
1850
+ template_schema.relationships.append(
1851
+ RelationshipSchema(
1852
+ name=relationship.name,
1853
+ peer=rel_template_peer,
1854
+ kind=relationship.kind,
1855
+ optional=relationship.kind
1856
+ in [RelationshipKind.COMPONENT, RelationshipKind.ATTRIBUTE, RelationshipKind.GENERIC],
1857
+ cardinality=relationship.cardinality,
1858
+ branch=relationship.branch,
1859
+ identifier=self._generate_identifier_string(template_schema.kind, rel_template_peer),
1860
+ min_count=relationship.min_count,
1861
+ max_count=relationship.max_count,
1862
+ label=f"{relationship.name} template".title()
1863
+ if relationship.kind in [RelationshipKind.COMPONENT, RelationshipKind.PARENT]
1864
+ else relationship.name.title(),
1865
+ )
1866
+ )
1867
+
1868
+ def generate_object_template_from_node(self, node: NodeSchema) -> TemplateSchema:
1869
+ core_template_schema = self.get(name=InfrahubKind.OBJECTTEMPLATE, duplicate=False)
1870
+ core_name_attr = core_template_schema.get_attribute(name=OBJECT_TEMPLATE_NAME_ATTR)
1871
+ template_name_attr = AttributeSchema(
1872
+ **core_name_attr.model_dump(exclude=["id", "inherited"]),
1873
+ )
1874
+ template_name_attr.branch = node.branch
1875
+
1876
+ template = TemplateSchema(
1877
+ name=node.kind,
1878
+ namespace="Template",
1879
+ label=f"Object template {node.label}",
1880
+ description=f"Object template for {node.kind}",
1881
+ branch=node.branch,
1882
+ include_in_menu=False,
1883
+ display_labels=["template_name__value"],
1884
+ inherit_from=[InfrahubKind.LINEAGESOURCE, InfrahubKind.OBJECTTEMPLATE, InfrahubKind.NODE],
1885
+ human_friendly_id=["template_name__value"],
1886
+ default_filter="template_name__value",
1887
+ attributes=[template_name_attr],
1888
+ relationships=[
1889
+ RelationshipSchema(
1890
+ name="related_nodes",
1891
+ identifier="node__objecttemplate",
1892
+ peer=node.kind,
1893
+ kind=RelationshipKind.TEMPLATE,
1894
+ cardinality=RelationshipCardinality.MANY,
1895
+ branch=BranchSupportType.AWARE,
1896
+ )
1897
+ ],
1898
+ )
1899
+
1900
+ for node_attr in node.attributes:
1901
+ if node_attr.unique:
1902
+ continue
1903
+
1904
+ attr = AttributeSchema(
1905
+ optional=True, **node_attr.model_dump(exclude=["id", "unique", "optional", "read_only", "inherited"])
1906
+ )
1907
+ template.attributes.append(attr)
1908
+
1909
+ return template
1910
+
1911
+ def identify_required_object_templates(
1912
+ self, node_schema: NodeSchema | GenericSchema, identified: set[NodeSchema | GenericSchema]
1913
+ ) -> set[NodeSchema]:
1914
+ """Identify all templates required to turn a given node into a template."""
1915
+ if node_schema in identified:
1916
+ return identified
1917
+
1918
+ identified.add(node_schema)
1919
+
1920
+ for relationship in node_schema.relationships:
1921
+ if relationship.peer in [
1922
+ InfrahubKind.GENERICGROUP,
1923
+ InfrahubKind.PROFILE,
1924
+ ] or relationship.kind not in [RelationshipKind.COMPONENT, RelationshipKind.PARENT]:
1925
+ continue
1926
+
1927
+ peer_schema = self.get(name=relationship.peer, duplicate=False)
1928
+ if not isinstance(peer_schema, NodeSchema | GenericSchema) or peer_schema in identified:
1929
+ continue
1930
+
1931
+ identified |= self.identify_required_object_templates(node_schema=peer_schema, identified=identified)
1932
+
1933
+ return identified
1934
+
1935
+ def manage_object_template_schemas(self) -> None:
1936
+ need_templates: set[NodeSchema | GenericSchema] = set()
1937
+ template_schema_kinds: set[str] = set()
1938
+
1939
+ for node_name in self.node_names + self.generic_names:
1940
+ node = self.get(name=node_name, duplicate=False)
1941
+
1942
+ # Delete old object templates if schemas were removed
1943
+ if (
1944
+ node.namespace in RESTRICTED_NAMESPACES
1945
+ or not node.generate_template
1946
+ or node.state == HashableModelState.ABSENT
1947
+ ):
1948
+ try:
1949
+ self.delete(name=self._get_object_template_kind(node_kind=node.kind))
1950
+ except SchemaNotFoundError:
1951
+ ...
1952
+ continue
1953
+
1954
+ need_templates |= self.identify_required_object_templates(node_schema=node, identified=need_templates)
1955
+
1956
+ # Generate templates with their attributes
1957
+ for node in need_templates:
1958
+ template = self.generate_object_template_from_node(node=node)
1959
+ self.set(name=template.kind, schema=template)
1960
+ template_schema_kinds.add(template.kind)
1961
+
1962
+ # Go back on templates and add relationships to them
1963
+ for node in need_templates:
1964
+ self.add_relationships_to_template(node=node)
1965
+
1966
+ for previous_template in list(self.templates.keys()):
1967
+ # Ensure that we remove previous object template schemas if a node has been renamed
1968
+ if previous_template not in template_schema_kinds:
1969
+ self.delete(name=previous_template)
1970
+
1971
+ if not template_schema_kinds:
1972
+ return
1973
+
1974
+ core_template_schema = self.get(name=InfrahubKind.OBJECTTEMPLATE, duplicate=False)
1975
+ current_used_by_template = set(core_template_schema.used_by)
1976
+ new_used_by_template = template_schema_kinds - current_used_by_template
1977
+
1978
+ if new_used_by_template:
1979
+ core_template_schema = self.get(name=InfrahubKind.OBJECTTEMPLATE, duplicate=True)
1980
+ core_template_schema.used_by = sorted(template_schema_kinds)
1981
+ self.set(name=InfrahubKind.OBJECTTEMPLATE, schema=core_template_schema)
1982
+
1983
+ if self.has(name=InfrahubKind.NODE):
1984
+ core_node_schema = self.get(name=InfrahubKind.NODE, duplicate=False)
1985
+ current_used_by_node = set(core_node_schema.used_by)
1986
+ new_used_by_node = template_schema_kinds - current_used_by_node
1987
+
1988
+ if new_used_by_node:
1989
+ core_node_schema = self.get(name=InfrahubKind.NODE, duplicate=True)
1990
+ updated_used_by_node = set(chain(template_schema_kinds, set(core_node_schema.used_by)))
1991
+ core_node_schema.used_by = sorted(updated_used_by_node)
1992
+ self.set(name=InfrahubKind.NODE, schema=core_node_schema)
@@ -0,0 +1,36 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import Field
4
+
5
+ from infrahub.core.constants import InfrahubKind
6
+ from infrahub.core.schema.basenode_schema import BaseNodeSchema
7
+
8
+
9
+ class TemplateSchema(BaseNodeSchema):
10
+ inherit_from: list[str] = Field(
11
+ default_factory=list, description="List of Generic Kind that this template is inheriting from"
12
+ )
13
+
14
+ @property
15
+ def is_node_schema(self) -> bool:
16
+ return False
17
+
18
+ @property
19
+ def is_generic_schema(self) -> bool:
20
+ return False
21
+
22
+ @property
23
+ def is_profile_schema(self) -> bool:
24
+ return False
25
+
26
+ @property
27
+ def is_template_schema(self) -> bool:
28
+ return True
29
+
30
+ def get_labels(self) -> list[str]:
31
+ """Return the labels for this object, composed of the kind and the list of Generic this object is inheriting from."""
32
+
33
+ labels: list[str] = [self.kind] + self.inherit_from
34
+ if self.namespace not in ["Schema", "Internal"] and InfrahubKind.GENERICGROUP not in self.inherit_from:
35
+ labels.append(InfrahubKind.OBJECTTEMPLATE)
36
+ return labels
@@ -80,14 +80,16 @@ class UserTask:
80
80
 
81
81
  @classmethod
82
82
  def from_graphql_context(
83
- cls, title: str, context: GraphqlContext, logger: Optional[Union[BoundLogger, InfrahubLogger]] = None
83
+ cls, title: str, graphql_context: GraphqlContext, logger: Optional[Union[BoundLogger, InfrahubLogger]] = None
84
84
  ) -> Self:
85
- if not context.db or not context.account_session:
85
+ if not graphql_context.db or not graphql_context.account_session:
86
86
  raise ValueError("db and account_session must be provided to initialize a GraphQLTaskReport")
87
87
 
88
- if not logger and context.service and context.service.log:
89
- logger = context.service.log
90
- return cls(title=title, account_id=context.account_session.account_id, db=context.db, logger=logger)
88
+ if not logger and graphql_context.service and graphql_context.service.log:
89
+ logger = graphql_context.service.log
90
+ return cls(
91
+ title=title, account_id=graphql_context.account_session.account_id, db=graphql_context.db, logger=logger
92
+ )
91
93
 
92
94
  async def __aenter__(self) -> Self:
93
95
  await self.create_task()
@@ -5,12 +5,12 @@ from typing import TYPE_CHECKING, Any
5
5
  from infrahub_sdk.timestamp import Timestamp as BaseTimestamp
6
6
 
7
7
  if TYPE_CHECKING:
8
- from pendulum.datetime import DateTime
8
+ from datetime import datetime
9
9
 
10
10
 
11
11
  class Timestamp(BaseTimestamp):
12
- async def to_graphql(self, *args: Any, **kwargs: Any) -> DateTime: # pylint: disable=unused-argument
13
- return self.obj
12
+ async def to_graphql(self, *args: Any, **kwargs: Any) -> datetime: # noqa: ARG002
13
+ return self.to_datetime()
14
14
 
15
15
  def get_query_filter_path(self, rel_name: str = "r") -> tuple[str, dict]:
16
16
  """
infrahub/core/utils.py CHANGED
@@ -72,6 +72,7 @@ async def update_relationships_to(ids: list[str], db: InfrahubDatabase, to: Time
72
72
  query = """
73
73
  MATCH ()-[r]->()
74
74
  WHERE %(id_func)s(r) IN $ids
75
+ AND r.to IS NULL
75
76
  SET r.to = $to
76
77
  RETURN %(id_func)s(r)
77
78
  """ % {"id_func": db.get_id_function_name()}
@@ -184,7 +185,7 @@ def parse_node_kind(kind: str) -> NodeKind:
184
185
  def convert_ip_to_binary_str(
185
186
  obj: Union[ipaddress.IPv6Network, ipaddress.IPv4Network, ipaddress.IPv4Interface, ipaddress.IPv6Interface],
186
187
  ) -> str:
187
- if isinstance(obj, (ipaddress.IPv6Network, ipaddress.IPv4Network)):
188
+ if isinstance(obj, ipaddress.IPv6Network | ipaddress.IPv4Network):
188
189
  prefix_bin = f"{int(obj.network_address):b}"
189
190
  return prefix_bin.zfill(obj.max_prefixlen)
190
191
 
@@ -204,7 +205,7 @@ def build_regex_attr(value: str | int | bool) -> str:
204
205
  """
205
206
  if isinstance(value, str):
206
207
  return f'"{value}"'
207
- if isinstance(value, (bool, int)):
208
+ if isinstance(value, bool | int):
208
209
  value_str = str(value).lower()
209
210
  return rf'(?<=[^\w"\d]){value_str}(?=[^\w"\d])'
210
211
 
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
18
18
  class AttributeChoicesUpdateValidatorQuery(AttributeSchemaValidatorQuery):
19
19
  name: str = "attribute_constraints_choices_validator"
20
20
 
21
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
21
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
22
22
  if self.attribute_schema.choices is None:
23
23
  return
24
24
 
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
18
18
  class AttributeEnumUpdateValidatorQuery(AttributeSchemaValidatorQuery):
19
19
  name: str = "attribute_constraints_enum_validator"
20
20
 
21
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
21
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
22
22
  if self.attribute_schema.enum is None:
23
23
  return
24
24
 
@@ -28,7 +28,7 @@ class NodeAttributeValue:
28
28
  class AttributeKindUpdateValidatorQuery(AttributeSchemaValidatorQuery):
29
29
  name: str = "attribute_constraints_kind_validator"
30
30
 
31
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
31
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
32
32
  branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
33
33
  self.params.update(branch_params)
34
34
 
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
18
18
  class AttributeLengthUpdateValidatorQuery(AttributeSchemaValidatorQuery):
19
19
  name: str = "attribute_constraints_length_validator"
20
20
 
21
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
21
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
22
22
  branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
23
23
  self.params.update(branch_params)
24
24
 
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
18
18
  class AttributeOptionalUpdateValidatorQuery(AttributeSchemaValidatorQuery):
19
19
  name: str = "attribute_constraints_optional_validator"
20
20
 
21
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
21
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
22
22
  branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
23
23
  self.params.update(branch_params)
24
24
 
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
18
18
  class AttributeRegexUpdateValidatorQuery(AttributeSchemaValidatorQuery):
19
19
  name: str = "attribute_constraints_regex_validator"
20
20
 
21
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
21
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
22
22
  branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string())
23
23
  self.params.update(branch_params)
24
24
 
@@ -18,7 +18,7 @@ if TYPE_CHECKING:
18
18
  class AttributeUniqueUpdateValidatorQuery(AttributeSchemaValidatorQuery):
19
19
  name: str = "attribute_constraints_unique_validator"
20
20
 
21
- async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None:
21
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
22
22
  branch_filter, branch_params = self.branch.get_query_filter_path(at=self.at.to_string(), is_isolated=False)
23
23
  self.params.update(branch_params)
24
24