infrahub-server 1.6.3__py3-none-any.whl → 1.7.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 (250) hide show
  1. infrahub/actions/tasks.py +4 -2
  2. infrahub/api/exceptions.py +2 -2
  3. infrahub/api/schema.py +3 -1
  4. infrahub/artifacts/tasks.py +1 -0
  5. infrahub/auth.py +2 -2
  6. infrahub/cli/db.py +54 -28
  7. infrahub/computed_attribute/gather.py +3 -4
  8. infrahub/computed_attribute/tasks.py +23 -6
  9. infrahub/config.py +8 -0
  10. infrahub/constants/enums.py +12 -0
  11. infrahub/core/account.py +4 -4
  12. infrahub/core/attribute.py +106 -108
  13. infrahub/core/branch/models.py +44 -71
  14. infrahub/core/branch/tasks.py +5 -3
  15. infrahub/core/changelog/diff.py +1 -20
  16. infrahub/core/changelog/models.py +0 -7
  17. infrahub/core/constants/__init__.py +17 -0
  18. infrahub/core/constants/database.py +0 -1
  19. infrahub/core/constants/schema.py +0 -1
  20. infrahub/core/convert_object_type/repository_conversion.py +3 -4
  21. infrahub/core/diff/branch_differ.py +1 -1
  22. infrahub/core/diff/conflict_transferer.py +1 -1
  23. infrahub/core/diff/data_check_synchronizer.py +4 -3
  24. infrahub/core/diff/enricher/cardinality_one.py +2 -2
  25. infrahub/core/diff/enricher/hierarchy.py +1 -1
  26. infrahub/core/diff/enricher/labels.py +1 -1
  27. infrahub/core/diff/merger/merger.py +28 -2
  28. infrahub/core/diff/merger/serializer.py +3 -10
  29. infrahub/core/diff/model/diff.py +1 -1
  30. infrahub/core/diff/query/merge.py +376 -135
  31. infrahub/core/diff/repository/repository.py +3 -1
  32. infrahub/core/graph/__init__.py +1 -1
  33. infrahub/core/graph/constraints.py +3 -3
  34. infrahub/core/graph/schema.py +2 -12
  35. infrahub/core/ipam/reconciler.py +8 -6
  36. infrahub/core/ipam/utilization.py +8 -15
  37. infrahub/core/manager.py +133 -152
  38. infrahub/core/merge.py +1 -1
  39. infrahub/core/metadata/__init__.py +0 -0
  40. infrahub/core/metadata/interface.py +37 -0
  41. infrahub/core/metadata/model.py +31 -0
  42. infrahub/core/metadata/query/__init__.py +0 -0
  43. infrahub/core/metadata/query/node_metadata.py +301 -0
  44. infrahub/core/migrations/graph/__init__.py +4 -0
  45. infrahub/core/migrations/graph/m012_convert_account_generic.py +12 -12
  46. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +7 -12
  47. infrahub/core/migrations/graph/m017_add_core_profile.py +5 -2
  48. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -1
  49. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +0 -10
  50. infrahub/core/migrations/graph/m020_duplicate_edges.py +0 -8
  51. infrahub/core/migrations/graph/m025_uniqueness_nulls.py +2 -1
  52. infrahub/core/migrations/graph/m026_0000_prefix_fix.py +2 -1
  53. infrahub/core/migrations/graph/m029_duplicates_cleanup.py +0 -1
  54. infrahub/core/migrations/graph/m031_check_number_attributes.py +2 -2
  55. infrahub/core/migrations/graph/m038_redo_0000_prefix_fix.py +2 -1
  56. infrahub/core/migrations/graph/m041_deleted_dup_edges.py +1 -1
  57. infrahub/core/migrations/graph/m049_remove_is_visible_relationship.py +53 -0
  58. infrahub/core/migrations/graph/m050_backfill_vertex_metadata.py +168 -0
  59. infrahub/core/migrations/query/__init__.py +2 -2
  60. infrahub/core/migrations/query/attribute_add.py +17 -6
  61. infrahub/core/migrations/query/attribute_remove.py +19 -5
  62. infrahub/core/migrations/query/attribute_rename.py +21 -5
  63. infrahub/core/migrations/query/node_duplicate.py +19 -4
  64. infrahub/core/migrations/query/schema_attribute_update.py +1 -1
  65. infrahub/core/migrations/schema/attribute_kind_update.py +21 -2
  66. infrahub/core/migrations/schema/attribute_name_update.py +1 -1
  67. infrahub/core/migrations/schema/attribute_supports_profile.py +5 -3
  68. infrahub/core/migrations/schema/models.py +3 -0
  69. infrahub/core/migrations/schema/node_attribute_add.py +5 -2
  70. infrahub/core/migrations/schema/node_attribute_remove.py +1 -1
  71. infrahub/core/migrations/schema/node_kind_update.py +1 -1
  72. infrahub/core/migrations/schema/node_remove.py +24 -2
  73. infrahub/core/migrations/schema/tasks.py +4 -1
  74. infrahub/core/migrations/shared.py +13 -6
  75. infrahub/core/models.py +6 -6
  76. infrahub/core/node/__init__.py +157 -58
  77. infrahub/core/node/base.py +9 -5
  78. infrahub/core/node/create.py +7 -3
  79. infrahub/core/node/delete_validator.py +1 -1
  80. infrahub/core/node/standard.py +100 -14
  81. infrahub/core/order.py +30 -0
  82. infrahub/core/property.py +0 -1
  83. infrahub/core/protocols.py +1 -0
  84. infrahub/core/protocols_base.py +10 -2
  85. infrahub/core/query/__init__.py +5 -3
  86. infrahub/core/query/attribute.py +164 -49
  87. infrahub/core/query/branch.py +58 -70
  88. infrahub/core/query/delete.py +1 -1
  89. infrahub/core/query/diff.py +7 -7
  90. infrahub/core/query/ipam.py +104 -43
  91. infrahub/core/query/node.py +1072 -281
  92. infrahub/core/query/relationship.py +531 -325
  93. infrahub/core/query/resource_manager.py +107 -18
  94. infrahub/core/query/standard_node.py +25 -5
  95. infrahub/core/query/utils.py +2 -4
  96. infrahub/core/relationship/constraints/count.py +1 -1
  97. infrahub/core/relationship/constraints/peer_kind.py +1 -1
  98. infrahub/core/relationship/constraints/peer_parent.py +1 -1
  99. infrahub/core/relationship/constraints/peer_relatives.py +1 -1
  100. infrahub/core/relationship/constraints/profiles_kind.py +1 -1
  101. infrahub/core/relationship/constraints/profiles_removal.py +168 -0
  102. infrahub/core/relationship/model.py +293 -139
  103. infrahub/core/schema/attribute_schema.py +2 -2
  104. infrahub/core/schema/basenode_schema.py +3 -0
  105. infrahub/core/schema/definitions/core/__init__.py +8 -2
  106. infrahub/core/schema/definitions/core/account.py +10 -10
  107. infrahub/core/schema/definitions/core/artifact.py +14 -8
  108. infrahub/core/schema/definitions/core/check.py +10 -4
  109. infrahub/core/schema/definitions/core/generator.py +26 -6
  110. infrahub/core/schema/definitions/core/graphql_query.py +1 -1
  111. infrahub/core/schema/definitions/core/group.py +9 -2
  112. infrahub/core/schema/definitions/core/ipam.py +80 -10
  113. infrahub/core/schema/definitions/core/menu.py +41 -7
  114. infrahub/core/schema/definitions/core/permission.py +16 -2
  115. infrahub/core/schema/definitions/core/profile.py +16 -2
  116. infrahub/core/schema/definitions/core/propose_change.py +24 -4
  117. infrahub/core/schema/definitions/core/propose_change_comment.py +23 -11
  118. infrahub/core/schema/definitions/core/propose_change_validator.py +50 -21
  119. infrahub/core/schema/definitions/core/repository.py +10 -0
  120. infrahub/core/schema/definitions/core/resource_pool.py +8 -1
  121. infrahub/core/schema/definitions/core/template.py +19 -2
  122. infrahub/core/schema/definitions/core/transform.py +11 -5
  123. infrahub/core/schema/definitions/core/webhook.py +27 -9
  124. infrahub/core/schema/manager.py +63 -43
  125. infrahub/core/schema/relationship_schema.py +6 -2
  126. infrahub/core/schema/schema_branch.py +48 -10
  127. infrahub/core/task/task.py +4 -2
  128. infrahub/core/utils.py +3 -25
  129. infrahub/core/validators/aggregated_checker.py +1 -1
  130. infrahub/core/validators/attribute/choices.py +1 -1
  131. infrahub/core/validators/attribute/enum.py +1 -1
  132. infrahub/core/validators/attribute/kind.py +1 -1
  133. infrahub/core/validators/attribute/length.py +1 -1
  134. infrahub/core/validators/attribute/min_max.py +1 -1
  135. infrahub/core/validators/attribute/number_pool.py +1 -1
  136. infrahub/core/validators/attribute/optional.py +1 -1
  137. infrahub/core/validators/attribute/regex.py +1 -1
  138. infrahub/core/validators/determiner.py +3 -3
  139. infrahub/core/validators/node/attribute.py +1 -1
  140. infrahub/core/validators/node/relationship.py +1 -1
  141. infrahub/core/validators/relationship/peer.py +1 -1
  142. infrahub/database/__init__.py +4 -4
  143. infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
  144. infrahub/dependencies/builder/constraint/relationship_manager/profiles_removal.py +8 -0
  145. infrahub/dependencies/registry.py +2 -0
  146. infrahub/display_labels/tasks.py +12 -3
  147. infrahub/git/integrator.py +18 -18
  148. infrahub/git/tasks.py +1 -1
  149. infrahub/git/utils.py +1 -1
  150. infrahub/graphql/constants.py +3 -0
  151. infrahub/graphql/context.py +1 -1
  152. infrahub/graphql/field_extractor.py +1 -1
  153. infrahub/graphql/initialization.py +11 -0
  154. infrahub/graphql/loaders/account.py +134 -0
  155. infrahub/graphql/loaders/node.py +5 -12
  156. infrahub/graphql/loaders/peers.py +5 -7
  157. infrahub/graphql/manager.py +175 -21
  158. infrahub/graphql/metadata.py +91 -0
  159. infrahub/graphql/mutations/account.py +6 -6
  160. infrahub/graphql/mutations/attribute.py +0 -2
  161. infrahub/graphql/mutations/branch.py +9 -5
  162. infrahub/graphql/mutations/computed_attribute.py +1 -1
  163. infrahub/graphql/mutations/display_label.py +1 -1
  164. infrahub/graphql/mutations/hfid.py +1 -1
  165. infrahub/graphql/mutations/ipam.py +4 -6
  166. infrahub/graphql/mutations/main.py +9 -4
  167. infrahub/graphql/mutations/profile.py +16 -22
  168. infrahub/graphql/mutations/proposed_change.py +4 -4
  169. infrahub/graphql/mutations/relationship.py +40 -10
  170. infrahub/graphql/mutations/repository.py +14 -12
  171. infrahub/graphql/mutations/schema.py +2 -2
  172. infrahub/graphql/order.py +14 -0
  173. infrahub/graphql/queries/branch.py +62 -6
  174. infrahub/graphql/queries/resource_manager.py +25 -24
  175. infrahub/graphql/resolvers/account_metadata.py +84 -0
  176. infrahub/graphql/resolvers/ipam.py +6 -8
  177. infrahub/graphql/resolvers/many_relationship.py +77 -35
  178. infrahub/graphql/resolvers/resolver.py +59 -14
  179. infrahub/graphql/resolvers/single_relationship.py +87 -23
  180. infrahub/graphql/subscription/graphql_query.py +2 -0
  181. infrahub/graphql/types/__init__.py +0 -1
  182. infrahub/graphql/types/attribute.py +10 -5
  183. infrahub/graphql/types/branch.py +40 -53
  184. infrahub/graphql/types/enums.py +3 -0
  185. infrahub/graphql/types/metadata.py +28 -0
  186. infrahub/graphql/types/node.py +22 -2
  187. infrahub/graphql/types/relationship.py +10 -2
  188. infrahub/graphql/types/standard_node.py +12 -7
  189. infrahub/hfid/tasks.py +12 -3
  190. infrahub/lock.py +7 -0
  191. infrahub/menu/repository.py +1 -1
  192. infrahub/patch/queries/base.py +1 -1
  193. infrahub/pools/number.py +1 -8
  194. infrahub/profiles/gather.py +56 -0
  195. infrahub/profiles/mandatory_fields_checker.py +116 -0
  196. infrahub/profiles/models.py +66 -0
  197. infrahub/profiles/node_applier.py +154 -13
  198. infrahub/profiles/queries/get_profile_data.py +143 -31
  199. infrahub/profiles/tasks.py +79 -27
  200. infrahub/profiles/triggers.py +22 -0
  201. infrahub/proposed_change/action_checker.py +1 -1
  202. infrahub/proposed_change/tasks.py +4 -1
  203. infrahub/services/__init__.py +1 -1
  204. infrahub/services/adapters/cache/nats.py +1 -1
  205. infrahub/services/adapters/cache/redis.py +7 -0
  206. infrahub/tasks/artifact.py +1 -0
  207. infrahub/transformations/tasks.py +2 -2
  208. infrahub/trigger/catalogue.py +2 -0
  209. infrahub/trigger/models.py +1 -0
  210. infrahub/trigger/setup.py +3 -3
  211. infrahub/trigger/tasks.py +3 -0
  212. infrahub/validators/tasks.py +1 -0
  213. infrahub/webhook/gather.py +1 -1
  214. infrahub/webhook/models.py +1 -1
  215. infrahub/webhook/tasks.py +23 -7
  216. infrahub/workers/dependencies.py +9 -3
  217. infrahub/workers/infrahub_async.py +13 -4
  218. infrahub/workflows/catalogue.py +19 -0
  219. infrahub_sdk/analyzer.py +2 -2
  220. infrahub_sdk/branch.py +12 -39
  221. infrahub_sdk/checks.py +4 -4
  222. infrahub_sdk/client.py +36 -0
  223. infrahub_sdk/ctl/cli_commands.py +2 -1
  224. infrahub_sdk/ctl/graphql.py +15 -4
  225. infrahub_sdk/ctl/utils.py +2 -2
  226. infrahub_sdk/enums.py +6 -0
  227. infrahub_sdk/graphql/renderers.py +21 -0
  228. infrahub_sdk/graphql/utils.py +85 -0
  229. infrahub_sdk/node/attribute.py +12 -2
  230. infrahub_sdk/node/constants.py +12 -0
  231. infrahub_sdk/node/metadata.py +69 -0
  232. infrahub_sdk/node/node.py +65 -14
  233. infrahub_sdk/node/property.py +3 -0
  234. infrahub_sdk/node/related_node.py +37 -5
  235. infrahub_sdk/node/relationship.py +18 -1
  236. infrahub_sdk/operation.py +2 -2
  237. infrahub_sdk/schema/repository.py +1 -2
  238. infrahub_sdk/transforms.py +2 -2
  239. infrahub_sdk/types.py +18 -2
  240. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/METADATA +17 -16
  241. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/RECORD +249 -228
  242. infrahub_testcontainers/container.py +3 -3
  243. infrahub_testcontainers/docker-compose-cluster.test.yml +7 -7
  244. infrahub_testcontainers/docker-compose.test.yml +13 -5
  245. infrahub_testcontainers/models.py +3 -3
  246. infrahub_testcontainers/performance_test.py +1 -1
  247. infrahub/graphql/models.py +0 -6
  248. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/WHEEL +0 -0
  249. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/entry_points.txt +0 -0
  250. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0.dist-info}/licenses/LICENSE.txt +0 -0
@@ -14,7 +14,7 @@ class AttributeNameUpdateMigrationQuery01(AttributeMigrationQuery, AttributeRena
14
14
  self,
15
15
  migration: AttributeSchemaMigration,
16
16
  **kwargs: Any,
17
- ):
17
+ ) -> None:
18
18
  new_attr = AttributeInfo(
19
19
  name=migration.new_attribute_schema.name,
20
20
  node_kind=migration.new_schema.kind,
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING, Any, Sequence
4
4
 
5
+ from infrahub.core.constants import SYSTEM_USER_ID
5
6
  from infrahub.core.migrations.query.attribute_remove import AttributeRemoveQuery
6
7
  from infrahub.core.schema.generic_schema import GenericSchema
7
8
  from infrahub.core.schema.node_schema import NodeSchema
@@ -33,7 +34,7 @@ class ProfilesAttributeAddMigrationQuery(AttributeMigrationQuery, AttributeAddQu
33
34
  self,
34
35
  migration: AttributeSchemaMigration,
35
36
  **kwargs: Any,
36
- ):
37
+ ) -> None:
37
38
  node_kinds = _get_node_kinds(migration.new_schema)
38
39
  super().__init__(
39
40
  migration=migration,
@@ -53,7 +54,7 @@ class ProfilesAttributeRemoveMigrationQuery(AttributeMigrationQuery, AttributeRe
53
54
  self,
54
55
  migration: AttributeSchemaMigration,
55
56
  **kwargs: Any,
56
- ):
57
+ ) -> None:
57
58
  node_kinds = _get_node_kinds(migration.new_schema)
58
59
  super().__init__(
59
60
  migration=migration,
@@ -73,6 +74,7 @@ class AttributeSupportsProfileUpdateMigration(AttributeSchemaMigration):
73
74
  branch: Branch,
74
75
  at: Timestamp | str | None = None,
75
76
  queries: Sequence[type[MigrationBaseQuery]] | None = None, # noqa: ARG002
77
+ user_id: str = SYSTEM_USER_ID,
76
78
  ) -> MigrationResult:
77
79
  if (
78
80
  # no change in whether the attribute should be used on profiles
@@ -87,4 +89,4 @@ class AttributeSupportsProfileUpdateMigration(AttributeSchemaMigration):
87
89
  if not self.new_attribute_schema.support_profiles:
88
90
  profiles_queries.append(ProfilesAttributeRemoveMigrationQuery)
89
91
 
90
- return await super().execute(db=db, branch=branch, at=at, queries=profiles_queries)
92
+ return await super().execute(db=db, branch=branch, at=at, queries=profiles_queries, user_id=user_id)
@@ -3,6 +3,7 @@ from typing import Any
3
3
  from pydantic import BaseModel, ConfigDict, Field, field_validator, model_serializer
4
4
 
5
5
  from infrahub.core.branch import Branch
6
+ from infrahub.core.constants import SYSTEM_USER_ID
6
7
  from infrahub.core.models import SchemaUpdateMigrationInfo
7
8
  from infrahub.core.path import SchemaPath
8
9
  from infrahub.core.schema.schema_branch import SchemaBranch
@@ -15,6 +16,7 @@ class SchemaApplyMigrationData(BaseModel):
15
16
  new_schema: SchemaBranch
16
17
  previous_schema: SchemaBranch
17
18
  migrations: list[SchemaUpdateMigrationInfo]
19
+ user_id: str = SYSTEM_USER_ID
18
20
 
19
21
  @model_serializer()
20
22
  def serialize_model(self) -> dict[str, Any]:
@@ -23,6 +25,7 @@ class SchemaApplyMigrationData(BaseModel):
23
25
  "previous_schema": self.previous_schema.to_dict_schema_object(),
24
26
  "new_schema": self.new_schema.to_dict_schema_object(),
25
27
  "migrations": [migration.model_dump() for migration in self.migrations],
28
+ "user_id": self.user_id,
26
29
  }
27
30
 
28
31
  @field_validator("new_schema", "previous_schema", mode="before")
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING, Any, Sequence
4
4
 
5
5
  from infrahub.core import registry
6
+ from infrahub.core.constants import SYSTEM_USER_ID
6
7
  from infrahub.core.node import Node
7
8
  from infrahub.core.schema.generic_schema import GenericSchema
8
9
  from infrahub.core.schema.node_schema import NodeSchema
@@ -40,7 +41,7 @@ class NodeAttributeAddMigrationQuery01(AttributeMigrationQuery, AttributeAddQuer
40
41
  self,
41
42
  migration: AttributeSchemaMigration,
42
43
  **kwargs: Any,
43
- ):
44
+ ) -> None:
44
45
  node_kinds = self._get_node_kinds(
45
46
  schema=migration.new_schema, new_attribute_schema=migration.new_attribute_schema
46
47
  )
@@ -65,10 +66,11 @@ class NodeAttributeAddMigration(AttributeSchemaMigration):
65
66
  branch: Branch,
66
67
  at: Timestamp | str | None = None,
67
68
  queries: Sequence[type[MigrationBaseQuery]] | None = None,
69
+ user_id: str = SYSTEM_USER_ID,
68
70
  ) -> MigrationResult:
69
71
  if self.new_attribute_schema.inherited is True:
70
72
  return MigrationResult()
71
- return await super().execute(db=db, branch=branch, at=at, queries=queries)
73
+ return await super().execute(db=db, branch=branch, at=at, queries=queries, user_id=user_id)
72
74
 
73
75
  async def execute_post_queries(
74
76
  self,
@@ -76,6 +78,7 @@ class NodeAttributeAddMigration(AttributeSchemaMigration):
76
78
  result: MigrationResult,
77
79
  branch: Branch,
78
80
  at: Timestamp, # noqa: ARG002
81
+ user_id: str, # noqa: ARG002
79
82
  ) -> MigrationResult:
80
83
  if self.new_attribute_schema.kind != "NumberPool":
81
84
  return result
@@ -15,7 +15,7 @@ class NodeAttributeRemoveMigrationQuery01(AttributeMigrationQuery, AttributeRemo
15
15
  self,
16
16
  migration: AttributeSchemaMigration,
17
17
  **kwargs: Any,
18
- ):
18
+ ) -> None:
19
19
  super().__init__(
20
20
  migration=migration,
21
21
  attribute_name=migration.previous_attribute_schema.name,
@@ -14,7 +14,7 @@ class NodeKindUpdateMigrationQuery01(MigrationQuery, NodeDuplicateQuery):
14
14
  self,
15
15
  migration: SchemaMigration,
16
16
  **kwargs: Any,
17
- ):
17
+ ) -> None:
18
18
  new_node = SchemaNodeInfo(
19
19
  name=migration.new_schema.name,
20
20
  namespace=migration.new_schema.namespace,
@@ -51,12 +51,17 @@ class NodeRemoveMigrationBaseQuery(MigrationQuery):
51
51
  self.params["branch_name"] = self.branch.name
52
52
  self.params["branch"] = self.branch.name
53
53
  self.params["branch_level"] = self.branch.hierarchy_level
54
+ self.params["user_id"] = self.user_id
54
55
 
55
56
  self.params["rel_props"] = {
56
57
  "status": RelationshipStatus.DELETED.value,
57
58
  "from": self.at.to_string(),
59
+ "from_user_id": self.user_id,
58
60
  }
59
61
 
62
+ # Set metadata for vertex properties on default/global branch
63
+ self.params["set_metadata"] = self.branch.is_default or self.branch.is_global
64
+
60
65
  node_remove_query = self.render_node_remove_query(branch_filter=branch_filter)
61
66
 
62
67
  query = """
@@ -72,6 +77,13 @@ class NodeRemoveMigrationBaseQuery(MigrationQuery):
72
77
  WITH n1 as active_node, r1 as rb
73
78
  WHERE rb.status = "active"
74
79
  %(node_remove_query)s
80
+ WITH active_node
81
+ // Set metadata on Node vertex if on default/global branch
82
+ CALL (active_node) {
83
+ WITH active_node
84
+ WHERE $set_metadata
85
+ SET active_node.updated_at = $current_time, active_node.updated_by = $user_id
86
+ }
75
87
  RETURN DISTINCT active_node
76
88
  """ % {
77
89
  "branch_filter": branch_filter,
@@ -103,12 +115,17 @@ class NodeRemoveMigrationQueryIn(NodeRemoveMigrationBaseQuery):
103
115
  }
104
116
  WITH n1 as active_node, rel_inband1 as rel_inband, p1 as peer_node
105
117
  WHERE rel_inband.status = "active"
118
+ CALL (peer_node) {
119
+ WITH peer_node
120
+ WHERE $set_metadata
121
+ SET peer_node.updated_at = $current_time, peer_node.updated_by = $user_id
122
+ }
106
123
  CALL (%(sub_query_args)s) {
107
124
  %(sub_query)s
108
125
  }
109
126
  WITH p2 as peer_node, rel_inband, active_node
110
127
  FOREACH (i in CASE WHEN rel_inband.branch IN ["-global-", $branch] THEN [1] ELSE [] END |
111
- SET rel_inband.to = $current_time
128
+ SET rel_inband.to = $current_time, rel_inband.to_user_id = $user_id
112
129
  )
113
130
  """ % {"sub_query": sub_query, "sub_query_args": sub_query_args, "branch_filter": branch_filter}
114
131
  return query
@@ -150,11 +167,16 @@ class NodeRemoveMigrationQueryOut(NodeRemoveMigrationBaseQuery):
150
167
  }
151
168
  WITH n1 as active_node, rel_outband1 as rel_outband, p1 as peer_node
152
169
  WHERE rel_outband.status = "active"
170
+ CALL (peer_node) {
171
+ WITH peer_node
172
+ WHERE $set_metadata
173
+ SET peer_node.updated_at = $current_time, peer_node.updated_by = $user_id
174
+ }
153
175
  CALL (%(sub_query_args)s) {
154
176
  %(sub_query)s
155
177
  }
156
178
  FOREACH (i in CASE WHEN rel_outband.branch IN ["-global-", $branch] THEN [1] ELSE [] END |
157
- SET rel_outband.to = $current_time
179
+ SET rel_outband.to = $current_time, rel_outband.to_user_id = $user_id
158
180
  )
159
181
  """ % {"sub_query": sub_query, "sub_query_args": sub_query_args, "branch_filter": branch_filter}
160
182
 
@@ -8,6 +8,7 @@ from prefect.cache_policies import NONE
8
8
  from prefect.logging import get_run_logger
9
9
 
10
10
  from infrahub.core.branch import Branch # noqa: TC001
11
+ from infrahub.core.constants import SYSTEM_USER_ID
11
12
  from infrahub.core.migrations import MIGRATION_MAP
12
13
  from infrahub.core.path import SchemaPath # noqa: TC001
13
14
  from infrahub.workers.dependencies import get_database
@@ -57,6 +58,7 @@ async def schema_apply_migrations(message: SchemaApplyMigrationData) -> list[str
57
58
  previous_node_schema=previous_node_schema,
58
59
  schema_path=migration.path,
59
60
  database=await get_database(),
61
+ user_id=message.user_id,
60
62
  )
61
63
 
62
64
  async for _, result in batch.execute():
@@ -79,6 +81,7 @@ async def schema_path_migrate(
79
81
  database: InfrahubDatabase,
80
82
  new_node_schema: MainSchemaTypes | None = None,
81
83
  previous_node_schema: MainSchemaTypes | None = None,
84
+ user_id: str = SYSTEM_USER_ID,
82
85
  ) -> SchemaMigrationPathResponseData:
83
86
  log = get_run_logger()
84
87
 
@@ -101,7 +104,7 @@ async def schema_path_migrate(
101
104
  previous_node_schema=previous_node_schema, # type: ignore[arg-type]
102
105
  schema_path=schema_path,
103
106
  )
104
- execution_result = await migration.execute(db=db, branch=branch)
107
+ execution_result = await migration.execute(db=db, branch=branch, user_id=user_id)
105
108
 
106
109
  log.info(f"Migration completed for {migration_name}")
107
110
  log.debug(f"execution_result {execution_result}")
@@ -7,6 +7,7 @@ from rich.console import Console
7
7
  from typing_extensions import Self
8
8
 
9
9
  from infrahub.core import registry
10
+ from infrahub.core.constants import SYSTEM_USER_ID
10
11
  from infrahub.core.path import SchemaPath # noqa: TC001
11
12
  from infrahub.core.query import Query # noqa: TC001
12
13
  from infrahub.core.schema import AttributeSchema, MainSchemaTypes, RelationshipSchema, SchemaRoot, internal_schema
@@ -62,6 +63,7 @@ class SchemaMigration(BaseModel):
62
63
  result: MigrationResult,
63
64
  branch: Branch, # noqa: ARG002
64
65
  at: Timestamp, # noqa: ARG002
66
+ user_id: str, # noqa: ARG002
65
67
  ) -> MigrationResult:
66
68
  return result
67
69
 
@@ -71,6 +73,7 @@ class SchemaMigration(BaseModel):
71
73
  result: MigrationResult,
72
74
  branch: Branch, # noqa: ARG002
73
75
  at: Timestamp, # noqa: ARG002
76
+ user_id: str, # noqa: ARG002
74
77
  ) -> MigrationResult:
75
78
  return result
76
79
 
@@ -81,10 +84,11 @@ class SchemaMigration(BaseModel):
81
84
  branch: Branch,
82
85
  at: Timestamp,
83
86
  queries: Sequence[type[MigrationBaseQuery]],
87
+ user_id: str,
84
88
  ) -> MigrationResult:
85
89
  for migration_query in queries:
86
90
  try:
87
- query = await migration_query.init(db=db, branch=branch, at=at, migration=self)
91
+ query = await migration_query.init(db=db, branch=branch, at=at, migration=self, user_id=user_id)
88
92
  await query.execute(db=db)
89
93
  result.nbr_migrations_executed += query.get_nbr_migrations_executed()
90
94
  except Exception as exc:
@@ -99,15 +103,18 @@ class SchemaMigration(BaseModel):
99
103
  branch: Branch,
100
104
  at: Timestamp | str | None = None,
101
105
  queries: Sequence[type[MigrationBaseQuery]] | None = None,
106
+ user_id: str = SYSTEM_USER_ID,
102
107
  ) -> MigrationResult:
103
108
  async with db.start_transaction() as ts:
104
109
  result = MigrationResult()
105
110
  at = Timestamp(at)
106
111
 
107
- await self.execute_pre_queries(db=ts, result=result, branch=branch, at=at)
112
+ await self.execute_pre_queries(db=ts, result=result, branch=branch, at=at, user_id=user_id)
108
113
  queries_to_execute = queries or self.queries
109
- await self.execute_queries(db=ts, result=result, branch=branch, at=at, queries=queries_to_execute)
110
- await self.execute_post_queries(db=ts, result=result, branch=branch, at=at)
114
+ await self.execute_queries(
115
+ db=ts, result=result, branch=branch, at=at, queries=queries_to_execute, user_id=user_id
116
+ )
117
+ await self.execute_post_queries(db=ts, result=result, branch=branch, at=at, user_id=user_id)
111
118
 
112
119
  return result
113
120
 
@@ -209,14 +216,14 @@ class InternalSchemaMigration(BaseModel):
209
216
  async def validate_migration(self, db: InfrahubDatabase) -> MigrationResult:
210
217
  raise NotImplementedError
211
218
 
212
- async def execute(self, db: InfrahubDatabase) -> MigrationResult:
219
+ async def execute(self, db: InfrahubDatabase, user_id: str = SYSTEM_USER_ID) -> MigrationResult:
213
220
  result = MigrationResult()
214
221
 
215
222
  default_branch = registry.get_branch_from_registry()
216
223
 
217
224
  for migration in self.migrations:
218
225
  try:
219
- execution_result = await migration.execute(db=db, branch=default_branch)
226
+ execution_result = await migration.execute(db=db, branch=default_branch, user_id=user_id)
220
227
  result.errors.extend(execution_result.errors)
221
228
  except Exception as exc:
222
229
  result.errors.append(str(exc))
infrahub/core/models.py CHANGED
@@ -267,7 +267,7 @@ class SchemaUpdateValidationResult(BaseModel):
267
267
  if prop_name in PROPERTY_NAMES_TO_IGNORE:
268
268
  continue
269
269
 
270
- field_info = field.model_fields[prop_name]
270
+ field_info = field.__class__.model_fields[prop_name]
271
271
  field_update = str(field_info.json_schema_extra.get("update")) # type: ignore[union-attr]
272
272
 
273
273
  if isinstance(prop_diff, HashableModelDiff):
@@ -275,7 +275,7 @@ class SchemaUpdateValidationResult(BaseModel):
275
275
  # override field_update if this field has its own json_schema_extra.update
276
276
  try:
277
277
  prop_field = getattr(field, prop_name)
278
- param_field_info = prop_field.model_fields[param_field_name]
278
+ param_field_info = prop_field.__class__.model_fields[param_field_name]
279
279
  param_field_update = str(param_field_info.json_schema_extra.get("update"))
280
280
  except (AttributeError, KeyError):
281
281
  param_field_update = None
@@ -306,7 +306,7 @@ class SchemaUpdateValidationResult(BaseModel):
306
306
  )
307
307
 
308
308
  def _process_node_attributes(self, schema: MainSchemaTypes, node_field_name: str) -> None:
309
- field_info = schema.model_fields[node_field_name]
309
+ field_info = schema.__class__.model_fields[node_field_name]
310
310
  field_update = str(field_info.json_schema_extra.get("update")) # type: ignore[union-attr]
311
311
 
312
312
  # No need to execute a migration for generic nodes attributes because they are not stored in the database
@@ -424,7 +424,7 @@ class HashableModel(BaseModel):
424
424
 
425
425
  values = []
426
426
  md5hash = hashlib.md5(usedforsecurity=False)
427
- for field_name in sorted(self.model_fields.keys()):
427
+ for field_name in sorted(self.__class__.model_fields.keys()):
428
428
  if field_name.startswith("_") or field_name in self._exclude_from_hash:
429
429
  continue
430
430
 
@@ -577,7 +577,7 @@ class HashableModel(BaseModel):
577
577
  TODO Implement other fields type like dict
578
578
  """
579
579
 
580
- for field_name in other.model_fields.keys():
580
+ for field_name in other.__class__.model_fields.keys():
581
581
  if not hasattr(self, field_name):
582
582
  with contextlib.suppress(ValueError):
583
583
  # handles the case where self and other are different types and other has fields that self does not
@@ -613,7 +613,7 @@ class HashableModel(BaseModel):
613
613
  return attr_other
614
614
 
615
615
  def _get_field_names_for_diff(self) -> list[str]:
616
- return list(self.model_fields.keys())
616
+ return list(self.__class__.model_fields.keys())
617
617
 
618
618
  def diff(self, other: Self) -> HashableModelDiff:
619
619
  in_both, local_only, other_only = compare_lists(